@Override public Ray<T>[] updateRays () { T ownerPosition = owner.getPosition(); T ownerVelocity = owner.getLinearVelocity(); float velocityAngle = owner.vectorToAngle(ownerVelocity); // Update central ray rays[0].start.set(ownerPosition); rays[0].end.set(ownerVelocity).nor().scl(rayLength).add(ownerPosition); // Update left ray rays[1].start.set(ownerPosition); owner.angleToVector(rays[1].end, velocityAngle - whiskerAngle).scl(whiskerLength).add(ownerPosition); // Update right ray rays[2].start.set(ownerPosition); owner.angleToVector(rays[2].end, velocityAngle + whiskerAngle).scl(whiskerLength).add(ownerPosition); return rays; }
@Override public Ray<T>[] updateRays () { float velocityAngle = owner.vectorToAngle(owner.getLinearVelocity()); // Update ray 0 owner.angleToVector(rays[0].start, velocityAngle - HALF_PI).scl(sideOffset).add(owner.getPosition()); rays[0].end.set(owner.getLinearVelocity()).nor().scl(length); // later we'll add rays[0].start; // Update ray 1 owner.angleToVector(rays[1].start, velocityAngle + HALF_PI).scl(sideOffset).add(owner.getPosition()); rays[1].end.set(rays[0].end).add(rays[1].start); // add start position to ray 0 rays[0].end.add(rays[0].start); return rays; }
@Override public void draw () { // Draw the walls for (int i = 0; i < walls.length; i++) { renderBox(shapeRenderer, walls[i], walls_hw[i], walls_hh[i]); } if (drawDebug) { Ray<Vector2>[] rays = rayConfigurations[rayConfigurationIndex].getRays(); shapeRenderer.begin(ShapeType.Line); shapeRenderer.setColor(1, 0, 0, 1); transform.idt(); shapeRenderer.setTransformMatrix(transform); for (int i = 0; i < rays.length; i++) { Ray<Vector2> ray = rays[i]; shapeRenderer.line(ray.start, ray.end); } shapeRenderer.end(); } }
@Override public void draw () { super.draw(); if (drawDebug) { Gdx.gl.glDisable(GL20.GL_DEPTH_TEST); Ray<Vector3>[] rays = rayConfigurations[rayConfigurationIndex].getRays(); shapeRenderer.begin(ShapeType.Line); shapeRenderer.setColor(1, 1, 0, 1); shapeRenderer.setProjectionMatrix(camera.combined); for (int i = 0; i < rays.length; i++) { Ray<Vector3> ray = rays[i]; shapeRenderer.line(ray.start, ray.end); } shapeRenderer.end(); Gdx.gl.glEnable(GL20.GL_DEPTH_TEST); } }
@Override public boolean collides(Ray<Vector2> ray){ found = false; Geometry.iterateLine(0f, ray.start.x, ray.start.y, ray.end.x, ray.end.y, Vars.tilesize, (x, y)->{ if(solid(x, y)){ found = true; return; } }); return found; }
@Override public boolean findCollision(Collision<Vector2> collision, Ray<Vector2> ray){ Vector2 v = vectorCast(ray.start.x, ray.start.y, ray.end.x, ray.end.y); if(v == null) return false; collision.point = v; collision.normal = v.nor(); return true; }
@Override protected SteeringAcceleration<T> calculateRealSteering (SteeringAcceleration<T> steering) { T ownerPosition = owner.getPosition(); float minDistanceSquare = Float.POSITIVE_INFINITY; // Get the updated rays Ray<T>[] inputRays = rayConfiguration.updateRays(); // Process rays for (int i = 0; i < inputRays.length; i++) { // Find the collision with current ray boolean collided = raycastCollisionDetector.findCollision(outputCollision, inputRays[i]); if (collided) { float distanceSquare = ownerPosition.dst2(outputCollision.point); if (distanceSquare < minDistanceSquare) { minDistanceSquare = distanceSquare; // Swap collisions Collision<T> tmpCollision = outputCollision; outputCollision = minOutputCollision; minOutputCollision = tmpCollision; } } } // Return zero steering if no collision has occurred if (minDistanceSquare == Float.POSITIVE_INFINITY) return steering.setZero(); // Calculate and seek the target position steering.linear.set(minOutputCollision.point) .mulAdd(minOutputCollision.normal, owner.getBoundingRadius() + distanceFromBoundary).sub(owner.getPosition()).nor() .scl(getActualLimiter().getMaxLinearAcceleration()); // No angular acceleration steering.angular = 0; // Output steering acceleration return steering; }
/** Creates a {@code RayConfigurationBase} for the given owner and the specified number of rays. * @param owner the owner of this configuration * @param numRays the number of rays used by this configuration */ @SuppressWarnings("unchecked") public RayConfigurationBase (Steerable<T> owner, int numRays) { this.owner = owner; this.rays = new Ray[numRays]; for (int i = 0; i < numRays; i++) this.rays[i] = new Ray<T>(owner.getPosition().cpy().setZero(), owner.getPosition().cpy().setZero()); }
@Override public void draw () { // Draw the walls for (int i = 0; i < walls.length; i++) { renderBox(shapeRenderer, walls[i], walls_hw[i], walls_hh[i]); } if (drawDebug) { Ray<Vector2>[] rays = rayConfigurations[rayConfigurationIndex].getRays(); shapeRenderer.begin(ShapeType.Line); shapeRenderer.setColor(1, 0, 0, 1); transform.idt(); shapeRenderer.setTransformMatrix(transform); for (int i = 0; i < rays.length; i++) { Ray<Vector2> ray = rays[i]; tmp.set(ray.start); tmp.x = Box2dSteeringTest.metersToPixels(tmp.x); tmp.y = Box2dSteeringTest.metersToPixels(tmp.y); tmp2.set(ray.end); tmp2.x = Box2dSteeringTest.metersToPixels(tmp2.x); tmp2.y = Box2dSteeringTest.metersToPixels(tmp2.y); shapeRenderer.line(tmp, tmp2); } shapeRenderer.end(); } // Draw the character spriteBatch.begin(); character.draw(spriteBatch); spriteBatch.end(); }
@Override public boolean findCollision (Collision<Vector2> outputCollision, Ray<Vector2> inputRay) { callback.collided = false; if (!inputRay.start.epsilonEquals(inputRay.end, MathUtils.FLOAT_ROUNDING_ERROR)) { callback.outputCollision = outputCollision; world.rayCast(callback, inputRay.start, inputRay.end); } return callback.collided; }
@Override public boolean findCollision (Collision<Vector3> outputCollision, Ray<Vector3> inputRay) { // reset because we reuse the callback callback.setCollisionObject(null); world.rayTest(inputRay.start, inputRay.end, callback); if (outputCollision != null) { callback.getHitPointWorld(outputCollision.point); callback.getHitNormalWorld(outputCollision.normal); } return callback.hasHit(); }
@Override public Ray<T>[] updateRays () { rays[0].start.set(owner.getPosition()); rays[0].end.set(owner.getLinearVelocity()).nor().scl(length).add(rays[0].start); return rays; }
/** Returns the rays of this configuration. */ public Ray<T>[] getRays () { return rays; }
/** Sets the rays of this configuration. */ public void setRays (Ray<T>[] rays) { this.rays = rays; }
/** Smoothes the given path in place. * @param path the path to smooth * @return the number of nodes removed from the path. */ public int smoothPath (SmoothableGraphPath<N, V> path) { int inputPathLength = path.getCount(); // If the path is two nodes long or less, then we can't smooth it if (inputPathLength <= 2) return 0; // Make sure the ray is instantiated if (this.ray == null) { V vec = path.getNodePosition(0); this.ray = new Ray<V>(vec.cpy(), vec.cpy()); } // Keep track of where we are in the smoothed path. // We start at 1, because we must always include the start node in the smoothed path. int outputIndex = 1; // Keep track of where we are in the input path // We start at 2, because we assume two adjacent // nodes will pass the ray cast int inputIndex = 2; // Loop until we find the last item in the input while (inputIndex < inputPathLength) { // Set the ray ray.start.set(path.getNodePosition(outputIndex - 1)); ray.end.set(path.getNodePosition(inputIndex)); // Do the ray cast boolean collides = raycastCollisionDetector.collides(ray); if (collides) { // The ray test failed, swap nodes and consider the next output node path.swapNodes(outputIndex, inputIndex - 1); outputIndex++; } // Consider the next input node inputIndex++; } // Reached the last input node, always add it to the smoothed path. path.swapNodes(outputIndex, inputIndex - 1); path.truncatePath(outputIndex + 1); // Return the number of removed nodes return inputIndex - outputIndex - 1; }
/** Smoothes in place the path specified by the given request, possibly over multiple consecutive frames. * @param request the path smoothing request * @param timeToRun the time in nanoseconds that this call can use on the current frame * @return {@code true} if this operation has completed; {@code false} if more time is needed to complete. */ public boolean smoothPath (PathSmootherRequest<N, V> request, long timeToRun) { long lastTime = TimeUtils.nanoTime(); SmoothableGraphPath<N, V> path = request.path; int inputPathLength = path.getCount(); // If the path is two nodes long or less, then we can't smooth it if (inputPathLength <= 2) return true; if (request.isNew) { request.isNew = false; // Make sure the ray is instantiated if (this.ray == null) { V vec = request.path.getNodePosition(0); this.ray = new Ray<V>(vec.cpy(), vec.cpy()); } // Keep track of where we are in the smoothed path. // We start at 1, because we must always include the start node in the smoothed path. request.outputIndex = 1; // Keep track of where we are in the input path // We start at 2, because we assume two adjacent // nodes will pass the ray cast request.inputIndex = 2; } // Loop until we find the last item in the input while (request.inputIndex < inputPathLength) { // Check the available time long currentTime = TimeUtils.nanoTime(); timeToRun -= currentTime - lastTime; if (timeToRun <= PathFinderQueue.TIME_TOLERANCE) return false; // Set the ray ray.start.set(path.getNodePosition(request.outputIndex - 1)); ray.end.set(path.getNodePosition(request.inputIndex)); // Do the ray cast boolean collided = raycastCollisionDetector.collides(ray); if (collided) { // The ray test failed, swap nodes and consider the next output node path.swapNodes(request.outputIndex, request.inputIndex - 1); request.outputIndex++; } // Consider the next input node request.inputIndex++; // Store the current time lastTime = currentTime; } // Reached the last input node, always add it to the smoothed path path.swapNodes(request.outputIndex, request.inputIndex - 1); path.truncatePath(request.outputIndex + 1); // Smooth completed return true; }
public boolean findCollision (Collision<Vector2> outputCollision, Ray<Vector2> inputRay) { throw new UnsupportedOperationException(); }
@Override public boolean findCollision (Collision<Vector2> outputCollision, Ray<Vector2> inputRay) { throw new UnsupportedOperationException(); }
@Override public boolean collides (Ray<Vector2> ray) { return findCollision(null, ray); }
@Override public boolean collides (Ray<Vector3> ray) { return findCollision(null, ray); }
Ray<T>[] updateRays ();