我的平台游戏中有一套方法正在检测和解决实体与tilemap之间的冲突,但是它们的工作做得不好。
底部方法是被调用的方法,如下所示:
player.velocity = player.velocity.add(getFinalCollisionVector());
其中player.velocity是Vec2D。
private List<Rectangle2D> getCollidingTiles(){
List<Rectangle2D> collidingTiles = new ArrayList<Rectangle2D>();
for(int x = (int) (this.getX()/Tile.SIZE); x <= (int) (this.getX()/Tile.SIZE) + this.getRect2D().getWidth()/Tile.SIZE; x++){
for(int y = (int) (this.getX()/Tile.SIZE); y <= (int) (this.getX()/Tile.SIZE) + this.getRect2D().getHeight()/Tile.SIZE; y++){
if(map.getTileAt(x, y).getAttribute(Attribute.SOLID))
if(map.getCollisionBoxAt(x,y).isColliding(this.collisionBox))
collidingTiles.add(new Rectangle2D.Double(x, y, Tile.SIZE, Tile.SIZE));
}
}
return collidingTiles;
}
private List<Vec2D> getAllTileCollisionVectors(){
List<Rectangle2D> collidingTiles = getCollidingTiles();
List<Vec2D> collisionVectors = new ArrayList<Vec2D>();
for(Rectangle2D rec : collidingTiles){
collisionVectors.add(getCorrectionVector(rec));
}
return collisionVectors;
}
private Vec2D getCorrectionVector(Rectangle2D target)
{
Vec2D ret = new Vec2D();
double x1 = (this.getX() + this.getSize().x) - target.getX();
double x2 = this.getX() - (target.getX() + target.getWidth());
double y1 = (this.getY() + this.getSize().y) - target.getY();
double y2 = this.getY() - (target.getY() + target.getHeight());
// calculate displacement along X-axis
if (x1 < x2)
{
ret.x = x1;
}
else if (x1 > x2)
{
ret.x = x2;
}
// calculate displacement along Y-axis
if (y1 < y2)
{
ret.y = y1;
}
else if (y1 > y2)
{
ret.y = y2;
}
return ret;
}
protected Vec2D getFinalCollisionVector(){
List<Vec2D> collisionVectors = getAllTileCollisionVectors();
if(collisionVectors.size() < 1)
return new Vec2D(0,0);
Vec2D finalVector = new Vec2D();
for(Vec2D vec : collisionVectors){
finalVector = finalVector.add(vec);
}
return finalVector;
}
我的代码中出错了什么?这是玩家显示的行为,在那里(由于重力)落到那一点,然后他冻结。
答案 0 :(得分:0)
OP在这里: 由于没有其他答案,我已经发布了自己的答案。
我已经放弃了旧的实施,从头开始,它现在有效。这是新的实现:
public Corners getCornersAreSolid(double x, double y) {
int leftTile = (int)(x / Tile.SIZE);
int rightTile = (int)((x + moveData.collisionBox.getWidth()) / Tile.SIZE);
int topTile = (int)(y / Tile.SIZE);
int bottomTile = (int)((y + moveData.collisionBox.getHeight()) / Tile.SIZE);
boolean topLeft = hasAttribute(map, Attribute.SOLID, topTile, leftTile);
boolean topRight = hasAttribute(map, Attribute.SOLID, topTile, rightTile);
boolean bottomLeft = hasAttribute(map, Attribute.SOLID, bottomTile, leftTile);
boolean bottomRight = hasAttribute(map, Attribute.SOLID, bottomTile, rightTile);
Corners solidCorners = new Corners();
solidCorners.topLeft = topLeft;
solidCorners.topRight = topRight;
solidCorners.bottomRight = bottomRight;
solidCorners.bottomLeft = bottomLeft;
return solidCorners;
}
private boolean hasAttribute(GameMap map, Attribute attribute, int tileY, int tileX) {
boolean result = false;
if (tileX >= 0 && tileX < map.getWidthInTiles() && tileY >= 0 && tileY < map.getHeightInTiles()) {
result = map.getTileAt(tileX, tileY).getAttribute(attribute);
}
return result;
}
public Vec2D getNextPosition() {
int currCol = (int) (getX() / Tile.SIZE);
int currRow = (int) (getY() / Tile.SIZE);
double destX = getX() + moveData.velocity.x;
double destY = getY() + moveData.velocity.y;
double tempX = getX();
double tempY = getY();
Corners solidCorners = getCornersAreSolid(getX(), destY);
boolean topLeft = solidCorners.topLeft;
boolean topRight = solidCorners.topRight;
boolean bottomLeft = solidCorners.bottomLeft;
boolean bottomRight = solidCorners.bottomRight;
this.framesSinceLastCollision += 1;
if(moveData.velocity.y < 0) {
if(topLeft || topRight) {
moveData.velocity.y = 0;
tempY = currRow * Tile.SIZE;
this.framesSinceLastCollision = 0;
}
else {
tempY += moveData.velocity.y;
}
}
else if(moveData.velocity.y > 0) {
if(bottomLeft || bottomRight) {
moveData.velocity.y = 0;
tempY = (currRow + 1) * Tile.SIZE - moveData.collisionBox.getHeight() % Tile.SIZE - 1 ;
this.framesSinceLastCollision = 0;
}
else {
tempY += moveData.velocity.y;
}
}
solidCorners = getCornersAreSolid(destX, getY());
topLeft = solidCorners.topLeft;
topRight = solidCorners.topRight;
bottomLeft = solidCorners.bottomLeft;
bottomRight = solidCorners.bottomRight;
if(moveData.velocity.x < 0) {
if(topLeft || bottomLeft) {
moveData.velocity.x = 0;
tempX = currCol * Tile.SIZE;
this.framesSinceLastCollision = 0;
}
else {
tempX += moveData.velocity.x;
}
}
if(moveData.velocity.x > 0) {
if(topRight || bottomRight) {
moveData.velocity.x = 0;
tempX = (currCol + 1) * Tile.SIZE - moveData.collisionBox.getWidth() % Tile.SIZE -1 ;
this.framesSinceLastCollision = 0;
}
else {
tempX += moveData.velocity.x;
}
}
return new Vec2D(tempX, tempY);
}
private static class Corners{
public boolean topLeft, topRight;
public boolean bottomLeft, bottomRight;
public Corners(){
topLeft = false;
topRight = false;
bottomLeft = false;
bottomRight = false;
}
}