Last active
December 15, 2018 18:23
-
-
Save TheBrenny/98f8f27ad1bb53f4ee80179f43dbc64b to your computer and use it in GitHub Desktop.
Raycasting my homebrew'd way using linear functions and their x and y intercepts! The map is (theoretically) infinite in length along both axis' leading into the negative and positive. (See also: https://www.desmos.com/calculator/axjo4hkzxg)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class AngleSpeed extends Vector { | |
protected float xSpeed; | |
protected float ySpeed; | |
public AngleSpeed(AngleSpeed old) { | |
this(old.distance, old.xSpeed, old.ySpeed, old.angle.getAngle()); | |
} | |
public AngleSpeed(float speed, float xSpeed, float ySpeed, float angle) { | |
super(angle, speed); | |
this.xSpeed = xSpeed; | |
this.ySpeed = ySpeed; | |
} | |
public AngleSpeed addAngleSpeed(AngleSpeed add) { | |
this.xSpeed += add.xSpeed; | |
this.ySpeed += add.ySpeed; | |
this.distance = (float) Math.sqrt(xSpeed * xSpeed + ySpeed * ySpeed); | |
this.angle.setAngle(Angle.getAngle(0, 0, this.xSpeed, this.ySpeed)); | |
return this; | |
} | |
public float getSpeed() { | |
return this.distance; | |
} | |
public float getXSpeed() { | |
return xSpeed; | |
} | |
public float getYSpeed() { | |
return ySpeed; | |
} | |
public String toString() { | |
return StringUtil.insert("{0}[s={1}, xs={2}, ys={3}, a={4}]", getClass().getName(), this.distance, this.xSpeed, this.ySpeed, this.angle); | |
} | |
public static AngleSpeed getAngleSpeed(float angle, float speed) { | |
float xSpeed = 0.0F; | |
float ySpeed = 0.0F; | |
double sin = Math.sin(Math.toRadians(angle)); | |
double cos = Math.cos(Math.toRadians(angle)); | |
xSpeed = (float) sin * speed; | |
ySpeed = (float) -cos * speed; | |
return new AngleSpeed(speed, xSpeed, ySpeed, angle); | |
} | |
public static AngleSpeed getAngleSpeed(Vector v) { | |
return getAngleSpeed(v.angle.getAngle(), v.distance); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Vector { | |
public Angle angle; | |
public float distance; | |
public Vector(float angle, float distance) { | |
this(new Angle(angle), distance); | |
} | |
public Vector(Angle angle, float distance) { | |
this.angle = angle; | |
this.distance = distance; | |
} | |
public Angle getAngle() { | |
return this.angle; | |
} | |
public float getDistance() { | |
return this.distance; | |
} | |
public String toString() { | |
return getClass().getName() + StringUtil.insert("[angle={0},dist={1}]", angle, distance); | |
} | |
} | |
public class Ray extends Vector { | |
public Point2D location; | |
public Ray(Point2D location, Vector v) { | |
this(location, v.angle.getAngle(), v.distance); | |
} | |
public Ray(Point2D location, float angle) { | |
this(location, angle, Float.MAX_VALUE / 2); | |
} | |
public Ray(Point2D location, float angle, float distance) { | |
super(angle, distance); | |
this.location = location; | |
} | |
public Ray(Ray ray) { | |
this(new Point2D.Float((float) ray.location.getX(), (float) ray.location.getY()), ray.angle.getAngle(), ray.distance); | |
} | |
public Point2D.Float getLocation() { | |
if(!(this.location instanceof Point2D.Float)) this.location = new Point2D.Float((float) this.location.getX(), (float) this.location.getY()); | |
return (Point2D.Float) this.location; | |
} | |
public Point2D.Float getRelativeEndLoaction() { | |
AngleSpeed as = getAngleSpeed(); | |
return new Point2D.Float(as.getXSpeed(), as.getYSpeed()); | |
} | |
public Point2D.Float getEndLocation() { | |
Point2D.Float rel = getRelativeEndLoaction(); | |
return new Point2D.Float(this.getLocation().x + rel.x, this.getLocation().y + rel.y); | |
} | |
public AngleSpeed getAngleSpeed() { | |
return AngleSpeed.getAngleSpeed(this); | |
} | |
public String toString() { | |
return getClass().getName() + StringUtil.insert("[loc={0},angle={1},dist={2}]", location, angle, distance); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public Ray castRay(Ray ray, int skip) { | |
if(ray.distance == 0) return ray; | |
ray = new Ray(ray); // duplicate so we don't duck the original | |
// Start prepping vars | |
// Origin stuff | |
final Point2D.Float origin = new Point2D.Float(ray.getLocation().x, ray.getLocation().y); | |
//final Point originTile = roundTileCoords(origin.x, origin.y); | |
final Point tlTile = topLeftTile(); | |
final Point brTile = bottomRightTile(); | |
final float angle = new Angle(ray.getAngle().getAngle()).getAngle(); | |
// Moving stuff | |
Point tile = roundTileCoords(origin.x, origin.y); | |
Point grid = new Point(tile); | |
Point2D.Float mvp = new Point2D.Float(origin.x, origin.y); | |
int dirX, dirY; | |
int tileShiftX = 0, tileShiftY = 0; | |
float dist; | |
// Function stuff | |
float gradient; | |
MathUtil.LinearFunction f; | |
MathUtil.LinearFunction g; | |
// Loop stuff | |
int giveUpLoop = 100; // this is the max chickens cycles for the while loop | |
int giveUpCounter = 0; | |
boolean hit = false; | |
boolean exhausted = false; | |
// Get gradient and produce functions | |
AngleSpeed asTmp = AngleSpeed.getAngleSpeed(ray.angle.getAngle(), 1); | |
gradient = (asTmp.getYSpeed() / asTmp.getXSpeed()); | |
f = (x, m) -> m * (x - origin.x) + origin.y; | |
g = (y, m) -> (1 / m) * (y - origin.y) + origin.x; | |
if(asTmp.getXSpeed() == 0) { | |
g = (y, m) -> origin.x; // ((1/0)=0) * (y - origin.y) + origin.x; | |
f = (x, m) -> Float.POSITIVE_INFINITY; | |
} | |
// determine direction to traverse | |
dirX = angle > 0 && angle < 180 ? 1 : angle > 180 ? -1 : 0; | |
dirY = angle > 90 && angle < 270 ? 1 : angle < 90 || angle > 270 ? -1 : 0; | |
tileShiftX = dirX > 0 ? dirX : 0; | |
tileShiftY = dirY > 0 ? dirY : 0; | |
for(int i = 0; i <= skip; i++) { | |
hit = false; | |
exhausted = false; | |
giveUpCounter = 0; | |
do { | |
// move tile | |
grid.x += tileShiftX; | |
grid.y += tileShiftY; | |
// OLD: grid = roundTileCoords(mvp.x + tileShiftX, mvp.y + tileShiftY); | |
// We want to maintain the grid.x and grid.y because it should keep moving, instead of resetting it. | |
tileShiftX = tileShiftY = 0; | |
mvp.x = g.eq(grid.y, gradient); | |
mvp.y = f.eq(grid.x, gradient); | |
// find the closest of the intercepts | |
if(MathUtil.distanceSqrd(mvp.x, grid.y, origin.x, origin.y) < MathUtil.distanceSqrd(grid.x, mvp.y, origin.x, origin.y)) mvp.y = grid.y; | |
else mvp.x = grid.x; | |
// get tile coord | |
tile = roundTileCoords(mvp.x, mvp.y); | |
// check to see if we are exhausted | |
if((dist = MathUtil.distance(mvp.x, mvp.y, origin.x, origin.y)) >= ray.distance) exhausted = true; | |
else if(giveUpCounter >= giveUpLoop) exhausted = true; | |
else if(!(tile.x >= tlTile.x && tile.x <= brTile.x && tile.y >= tlTile.y && tile.y <= brTile.y)) exhausted = true; | |
if(exhausted) break; | |
// determine if hit is solid | |
if(mvp.x % 1 == 0) tileShiftX = dirX; | |
if(mvp.y % 1 == 0) tileShiftY = dirY; | |
//if(getTileRelative((int) Math.floor(mvp.x), (int) Math.floor(mvp.y)).isSolid() && !exhausted) { | |
if(getTileRelative(tile.x + (dirX < 0 ? tileShiftX : 0), tile.y + (dirY < 0 ? tileShiftY : 0)).isSolid() && !exhausted) { | |
hit = true; | |
ray.distance = dist; | |
} | |
giveUpCounter++; | |
} while(!hit && !exhausted); | |
} | |
return ray; | |
} | |
/** | |
* Rounds a tile coordinate to return the tile that contains this tile | |
* coordinate, so as to round towards negative infinity. This is done | |
* by {@code floor}ing the coordinates. | |
* | |
* @param x | |
* The x coordinate | |
* @param y | |
* The y coordinate | |
* @return The tile coordinate which "owns" the given coordinate. | |
*/ | |
public static Point roundTileCoords(float x, float y) { | |
x = (float) Math.floor(x); | |
y = (float) Math.floor(y); | |
return new Point((int) x, (int) y); | |
} | |
/** | |
* An interface to make it easy to create a linear function Lambda | |
* expression. | |
*/ | |
public static interface MathUtil.LinearFunction { | |
float eq(float n, float m); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment