Created
August 9, 2017 18:00
-
-
Save Durisvk/209f25c781af4aa53a4011f522b5c2d9 to your computer and use it in GitHub Desktop.
This file contains 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
package com.iddqd.doto.gamelogic.gameobject; | |
import com.fasterxml.jackson.annotation.JsonIgnore; | |
import com.iddqd.doto.gamelogic.GameLogicConstants; | |
import com.iddqd.doto.gamelogic.astar.AStar; | |
import com.iddqd.doto.gamelogic.astar.Path; | |
import com.iddqd.doto.gamelogic.astar.Spot; | |
import com.iddqd.doto.gamelogic.gameobject.actors.heroes.AbstractHero; | |
import com.iddqd.doto.gamelogic.math.geometry.CircleCollider; | |
import com.iddqd.doto.gamelogic.math.geometry.Point; | |
import com.iddqd.doto.gamelogic.math.geometry.Vector; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.List; | |
import java.util.Objects; | |
/** | |
* Created by Ruza on 24.7.2017. | |
*/ | |
public abstract class GameBodyObject extends GameObject { | |
private int width; | |
private int height; | |
private double rotation; | |
private Point position; | |
private boolean collidable = true; | |
private boolean isStatic = false; | |
private Path aStarPath = null; | |
private Spot current = null; | |
private double currentIndex = -1; | |
public GameBodyObject() { | |
this.width = 0; | |
this.height = 0; | |
this.rotation = 0; | |
this.position = new Point(0, 0); | |
} | |
public int getWidth() { | |
return width; | |
} | |
public void setWidth(int width) { | |
this.width = width; | |
} | |
public int getHeight() { | |
return height; | |
} | |
public void setHeight(int height) { | |
this.height = height; | |
} | |
public double getRotation() { | |
return rotation; | |
} | |
public void setRotation(double rotation) { | |
this.rotation = rotation; | |
} | |
public Spot getCurrent() { | |
return current; | |
} | |
public boolean setRotationWithMaxRotation(double rotation, double maxRotation) { | |
if(Math.abs(getRotation() - rotation) < maxRotation) { | |
setRotation(rotation); | |
return true; | |
} | |
return false; | |
} | |
public Point getPosition() { | |
return position; | |
} | |
public void setPosition(Point position) { | |
this.position = position; | |
} | |
@JsonIgnore | |
public boolean isCollidable() { | |
return collidable; | |
} | |
public void setCollidable(boolean collidable) { | |
this.collidable = collidable; | |
} | |
public boolean isStatic() { | |
return isStatic; | |
} | |
public void setStatic(boolean aStatic) { | |
isStatic = aStatic; | |
} | |
public double getRadius() { | |
return Math.max(width, height) / 2; | |
} | |
public boolean checkCollision(GameBodyObject anotherObject) { | |
if(anotherObject.isStatic() && isStatic()) { | |
return false; | |
} | |
if(anotherObject instanceof AbstractHero && ((AbstractHero) anotherObject).isDead()) { | |
return false; | |
} | |
if(this instanceof AbstractHero && ((AbstractHero) this).isDead()) { | |
return false; | |
} | |
if(this.isCollidable() && anotherObject.isCollidable()) { | |
return CircleCollider.collide(getPosition(), getRadius(), anotherObject.getPosition(), anotherObject.getRadius()); | |
} | |
return false; | |
} | |
@JsonIgnore | |
private Point lastPointToMove; | |
public void setLastPointToMove(Point lastPointToMove) { | |
this.lastPointToMove = lastPointToMove; | |
} | |
/** | |
* | |
* @param p | |
* @param stepSize | |
* @param minDistance | |
* @param shouldStepInto | |
* @return if it moved | |
*/ | |
public boolean moveTowardsPoint(Point p, double stepSize, double minDistance, ArrayList<GameBodyObject> objects, boolean shouldStepInto, AStar astar) { | |
ArrayList<GameBodyObject> others = (ArrayList<GameBodyObject>) objects.clone(); | |
others.remove(this); | |
if(aStarPath == null || !aStarPath.isSuccess() || astar.interruptedPath(aStarPath.getPath(), this) || lastPointToMove == null || !lastPointToMove.isAlmostTheSame(p, 0.01)) { | |
try { | |
//astar.getGrid().unsetObstacleForObject(this); | |
aStarPath = astar.process(this, p, objects); | |
currentIndex = 0; | |
current = null; | |
//astar.getGrid().reset(); | |
} catch(Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
lastPointToMove = p.clone(); | |
double dx = p.getX() - getPosition().getX(); | |
double dy = p.getY() - getPosition().getY(); | |
Point lastPosition = getPosition().clone(); | |
boolean isClose = false; | |
double dist = Math.sqrt(dx * dx + dy * dy); | |
if (dist < Math.max(minDistance, stepSize)) { | |
isClose = true; | |
} else { | |
if (aStarPath.getPath().indexOf(current) >= aStarPath.getPath().size() - 1) { | |
if (shouldStepInto && dist <= stepSize) { | |
setPosition(p.clone()); | |
} | |
} else { | |
if (aStarPath.isHit()) { | |
moveByAStar(stepSize); | |
} else { | |
moveByPoint(dx, dy, stepSize); | |
} | |
} | |
} | |
// -- A* -- | |
// -- COLLISION AVOIDANCE -- // | |
/* double dx = p.getX() - getPosition().getX(); | |
double dy = p.getY() - getPosition().getY(); | |
boolean isClose = false; | |
Point lastPosition = getPosition().clone(); | |
if (Math.sqrt(dx * dx + dy * dy) < Math.max(minDistance, stepSize)) { | |
isClose = true; | |
} else { | |
setRotation(Math.atan2(dy, dx)); | |
// Though the sqrt is expensive operation | |
// We check first without using sqrt | |
if (shouldStepInto && Math.abs(dx) + Math.abs(dy) < stepSize) { | |
if (Math.sqrt(dx * dx + dy * dy) < stepSize) { | |
getPosition().setX(p.getX()); | |
getPosition().setY(p.getY()); | |
} | |
} else { | |
getPosition().setX(getPosition().getX() + (stepSize * Math.cos(getRotation()))); | |
getPosition().setY(getPosition().getY() + (stepSize * Math.sin(getRotation()))); | |
} | |
} | |
*/ | |
/*GameBodyObject collider = null; | |
ArrayList<Double> movements = new ArrayList<>(); | |
for (GameBodyObject obj : others) { | |
if (checkCollision(obj)) { | |
double distanceMoved = getPosition().distance(lastPosition); | |
if(!isStatic() && distanceMoved > 0.01) { | |
Vector v = new Vector(getPosition().getX() - obj.getPosition().getX(), getPosition().getY() - obj.getPosition().getY()); | |
int av = (int)(v.getAngle() * 180 / Math.PI); | |
Vector n1 = v.getNormal(stepSize, 1); | |
int an1 = (int)(n1.getAngle() * 180 / Math.PI); | |
Vector n2 = v.getNormal(stepSize, -1); | |
int an2 = (int)(n2.getAngle() * 180 / Math.PI); | |
Point p1 = lastPosition.clone(); | |
Point p2 = lastPosition.clone(); | |
p1.moveByVector(n1); | |
p2.moveByVector(n2); | |
double dist1 = p1.distance(p); | |
double dist2 = p2.distance(p); | |
if (dist1 < dist2) { | |
Double angle = getAngleIfNotColliding(n1, p1, n2, p2, others); | |
if(angle != null) { | |
movements.add(angle); | |
} | |
} else { | |
Double angle = getAngleIfNotColliding(n2, p2, n1, p1, others); | |
if(angle != null) { | |
movements.add(angle); | |
} | |
} | |
}; | |
} | |
} | |
movements.removeIf(Objects::isNull); | |
if(movements != null && !movements.isEmpty()) { | |
setPosition(lastPosition.clone()); | |
double totalAngle = 0; | |
for (double angle : movements) { | |
totalAngle += angle; | |
} | |
Vector v = Vector.createFromLengthAndAngle(stepSize, totalAngle/movements.size()); | |
Point newPos = getPosition().clone(); | |
newPos.moveByVector(v); | |
setRotationWithMaxRotation(totalAngle/movements.size(), GameLogicConstants.MAX_ROTATION_ON_COLLISION); | |
getPosition().moveByVector(v); | |
}*/ | |
return isClose; | |
} | |
public boolean moveTowardsPoint(Point p, double stepSize, double minDistance, ArrayList<GameBodyObject> objects, AStar astar) { | |
return moveTowardsPoint(p, stepSize, minDistance, objects, false, astar); | |
} | |
private boolean checkCollisionWithCircle(Point p, double radius, ArrayList<GameBodyObject> objects) { | |
for(GameBodyObject obj : objects) { | |
if(CircleCollider.collide(p, radius, obj.getPosition(), obj.getRadius())) { | |
double dx = obj.getPosition().getX() - p.getX(); | |
double dy = obj.getPosition().getY() - p.getY(); | |
return true; | |
} | |
} | |
return false; | |
} | |
private Double getAngleIfNotColliding(Vector n, Point p, Vector alternativeN, Point alternativeP, ArrayList<GameBodyObject> others) { | |
if (!checkCollisionWithCircle(p, getRadius(), others)) { | |
return n.getAngle(); | |
} else { | |
if(!checkCollisionWithCircle(alternativeP, getRadius(), others)) { | |
return alternativeN.getAngle(); | |
} else { | |
return null; | |
} | |
} | |
} | |
private void moveByAStar(double stepSize) { | |
if (aStarPath != null && aStarPath.getPath().size() > 0) { | |
if (current == null) { | |
currentIndex = 0; | |
current = aStarPath.getPath().get((int) currentIndex); | |
} | |
Spot c1 = aStarPath.getPath().get((int) currentIndex); | |
Spot c2 = aStarPath.getPath().get(Math.min((int) currentIndex + 1, aStarPath.getPath().size() - 1)); | |
double angle = new Vector(c2.getX() - c1.getX(), c2.getY() - c1.getY()).getAngle(); | |
double coef = Math.max(Math.abs(Math.cos(angle)), Math.abs(Math.sin(angle))); | |
double mss = stepSize / (current.getWidth() / coef); | |
Spot p2 = aStarPath.getPath().get(Math.min((int) Math.ceil(currentIndex + mss), aStarPath.getPath().size() - 1)); | |
Spot p1 = current; | |
if (!p1.equals(p2)) { | |
Vector v = new Vector(p2.getX() - p1.getX(), p2.getY() - p1.getY()).normalize(); | |
getPosition().moveByVector(v.mult(stepSize)); | |
setRotation(v.getAngle()); | |
} | |
currentIndex = Math.min(currentIndex + mss, aStarPath.getPath().size() - 1); | |
current = aStarPath.getPath().get((int) currentIndex); | |
} | |
} | |
private void moveByPoint(double dx, double dy, double stepSize) { | |
setRotation(Math.atan2(dy, dx)); | |
setPosition(new Point(getPosition().getX() + stepSize * Math.cos(getRotation()), getPosition().getY() + stepSize * Math.sin(getRotation()))); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment