我在寻找使用碰撞检测时寻找抖动源的帮助。 我已经实现了一个java游戏(使用eclipse和slick2d)并且已经松散地遵循了本指南: http://katyscode.wordpress.com/2013/01/18/2d-platform-games-collision-detection-for-dummies
但当然在必要时改变位以适应我的游戏和java而不是cpp。
从我所做的研究中,我认为我的抖动的根本原因来自四舍五入的错误。 尽管这是我的主要嫌疑人,但我仍然无法确定它的发生地点。
很抱歉,如果缩进不是很正确,那么在使用代码块识别时会遇到一些麻烦。
基本上我在课堂上创建变量。 在init()中,我设置了大部分资源。 在render()中,所有绘图都会发生。注意图形转换,以便摄像机跟随播放器。 在更新中,我当然根据用户输入,重力和摩擦来更新播放器的位置。
我也用这种方法调用碰撞检测。 碰撞检测正在研究渗透分辨率方法。
(是的,我知道我会详尽地与每个世界对象进行比较。当我将更多基本问题排除在外时,我会提高AABB的效率。就像抖动一样!)
我的方法首先计算玩家期望在每个轴上移动多少,然后对于每个世界对象,它检查与玩家边界点的交叉点(浮点值表示玩家周围的坐标)。它在每个方向上检查这个并使用结果来确定碰撞发生在哪个轴上(如果有的话),以便采取适当的措施。
很抱歉这是一堆代码,但毕竟是碰撞检测,这不是一件小事。
这是我的Play课程,其中所有更新都继续进行游戏:
package GameFiles;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;
import java.awt.Rectangle;
//import java.awt.geom.Rectangle2D;
public class Play extends BasicGameState{
static int tileSize = 32;
File levelMap;
SpriteSheet spriteSheet;
int[][] currentMap;
Image[] groundTiles = new Image[4];
//List<Rectangle2D> levelBounds = new ArrayList<Rectangle2D>();
List<Rectangle> levelBounds = new ArrayList<Rectangle>();
Player player;
float playerX, playerY;
int dir;
float acc, mov, friction, gravity;
float runSpeed;
float maxAcc;
boolean inAir, jumping, keyDown;
boolean exitFlag;
int mapHeight, mapWidth;
float mapX, mapY;
float speedX, speedY;
int worldObjectCount;
int iterations;
public Play(int state){
}
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
playerX = Game.scrWidth/2;
playerY = Game.scrHeight - tileSize - tileSize;
player = new Player(playerX, playerY);
levelMap = new File("maps/lvl1.txt");
spriteSheet = new SpriteSheet("res/tiles/tilesets/DungeonCrawlTilesetBW.png", tileSize, tileSize);
try
{
currentMap = readMap(levelMap);
}
catch (IOException e)
{
System.out.println("Array size mismatch when copying arrays.");
e.printStackTrace();
}
levelBounds.clear();
for(int x = 0; x < mapWidth; x++)
{
for(int y = 0; y < mapHeight; y++){
if(currentMap[x][y] == 1){
levelBounds.add(new Rectangle(x*tileSize, Game.scrHeight - mapHeight*tileSize + y*tileSize, tileSize, tileSize));
//levelBounds.add(new Rectangle2D.Float(x*tileSize, Game.scrHeight - mapHeight*tileSize + y*tileSize, tileSize, tileSize));
System.out.println("Added new bounding box: " + (x*tileSize) + ", " + (Game.scrHeight - mapHeight*tileSize + y*tileSize) + ", " + tileSize);
}
}
}
worldObjectCount = levelBounds.size();
System.out.println("World object count: " + worldObjectCount);
groundTiles[0] = spriteSheet.getSubImage(4, 16);
groundTiles[1] = spriteSheet.getSubImage(13, 19);
dir = 1;
acc = 0.0f;
mov = 0.0f;
friction = 4f;
gravity = 4f;
runSpeed = 0.6f;
maxAcc = -1f;
inAir = false;
jumping = false;
keyDown = false;
exitFlag = false;
speedX = 0.0f;
speedY = 0.0f;
iterations = 3;
}
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
//determine cameraX and cameraY
float cameraX, cameraY;
cameraX = player.getX() - Game.scrWidth/2;
cameraY = player.getY() - (Game.scrHeight/2 - tileSize - tileSize);
g.translate(-cameraX, -cameraY);
player.render(g);
for(int x = 0; x < mapWidth; x++)
{
for(int y = 0; y < mapHeight; y++){
if(currentMap[x][y] == 1){
groundTiles[0].draw(x*tileSize, Game.scrHeight - mapHeight*tileSize + y*tileSize);
}
}
}
g.translate(cameraX, cameraY);
}
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException{
Input input = gc.getInput();
float secondsElapsed = delta/1000.0f;
checkCollisions(secondsElapsed);
player.setX((player.getX() + speedX));
player.setY((player.getY() - speedY));
//check inputs
checkKeyEvents(input);
//slow down / friction
if(!keyDown){
if(mov < 0)
mov += friction * secondsElapsed;
else
mov -= friction * secondsElapsed;
}
speedX = mov;
if (speedX > 0 && speedX < friction * secondsElapsed) speedX = 0;
if (speedX < 0 && speedX > -friction * secondsElapsed) speedX = 0;
//jump or fall
acc -= gravity * secondsElapsed;
if (acc < maxAcc){
acc = maxAcc;
}
speedY = acc;
//exit when exitFlag true
if(exitFlag){
gc.exit();
}
}
public void checkCollisions(float secondsElapsed){
boolean contactX = true, contactYbottom = true, contactYtop = true;
// Keep iterating the contact solver until the maximum number of iterations is reached
// or no collisions are detected
for (int iteration = 0; iteration < iterations && (contactX || contactYbottom || contactYtop); iteration++)
{
float nextMoveX = speedX * secondsElapsed;
float nextMoveY = speedY * secondsElapsed;
contactX = contactYbottom = contactYtop = false;
float projectedMoveX, projectedMoveY, originalMoveX, originalMoveY;
originalMoveX = nextMoveX;
originalMoveY = nextMoveY;
for (int o = 0; o < worldObjectCount && !contactX && !contactYbottom && !contactYtop; o++)
{
for (int dir = 0; dir < 6; dir++)
{
//top, bottom, left, left, right, right.
if (dir == 0 && nextMoveY < 0) continue;
if (dir == 1 && nextMoveY > 0) continue;
if (dir == 2 && nextMoveX > 0) continue;
if (dir == 3 && nextMoveX > 0) continue;
if (dir == 4 && nextMoveX < 0) continue;
if (dir == 5 && nextMoveX < 0) continue;
projectedMoveX = (dir >= 2? nextMoveX : 0);
projectedMoveY = (dir < 2? nextMoveY : 0);
float[][] collisionPoint = player.getBounds();
Rectangle curRect = new Rectangle(levelBounds.get(o).x, levelBounds.get(o).y, levelBounds.get(o).width, levelBounds.get(o).height);
//Rectangle2D curRect = levelBounds.get(o).getBounds2D();
while (curRect.contains(collisionPoint[dir][0] + projectedMoveX, collisionPoint[dir][1] + projectedMoveY)
|| curRect.intersects(collisionPoint[dir][0] + projectedMoveX, collisionPoint[dir][1] + projectedMoveY, 1, 1))
{
if (dir == 0) projectedMoveY += 0.05f; //top collision
if (dir == 1) projectedMoveY -= 0.05f; //bottom collision
if (dir == 2) projectedMoveX += 0.05f; //left collision
if (dir == 3) projectedMoveX += 0.05f;
if (dir == 4) projectedMoveX -= 0.05f; //right collision
if (dir == 5) projectedMoveX -= 0.05f;
}
if (dir >= 2 && dir <= 5)
nextMoveX = projectedMoveX;
if (dir >= 0 && dir <= 1)
nextMoveY = projectedMoveY;
}
if (nextMoveY > originalMoveY && originalMoveY != 0)
{
contactYtop = true;
}
if (nextMoveY < originalMoveY && originalMoveY != 0)
{
contactYbottom = true;
}
if (Math.abs(nextMoveX - originalMoveX) > 0.01f)
{
contactX = true;
}
if (contactX && contactYtop && speedY > 0)
speedY = nextMoveY = 0;
}
if (contactYbottom || contactYtop)
{
player.setY(player.getY() + nextMoveY);
speedY = 0;
acc = 0;
if (contactYbottom)
jumping = false;
}
if (contactX)
{
player.setX(player.getX() + nextMoveX);
speedX = 0;
mov = 0;
}
}//end collisions
}
public int[][] readMap(File level) throws IOException, SlickException{
BufferedReader br = new BufferedReader(new FileReader(level));
mapWidth = Integer.parseInt(br.readLine());
mapHeight = Integer.parseInt(br.readLine());
int[][] map = new int[mapWidth][mapHeight];
for(int row = 0; row < mapHeight; row++)
{
String line = br.readLine();
if(line == null || line.isEmpty())
{
System.out.println("Line is empty or null");
}
else
{
String[] tileValues = line.split(",");
for(int col = 0; col < mapWidth; col++)
{
map[col][row] = Integer.parseInt(tileValues[col]);
}
}
}
br.close();
return map;
}
public void checkKeyEvents(Input input){
//key input events
if(input.isKeyPressed(Input.KEY_DOWN)){
}
if(input.isKeyPressed(Input.KEY_UP)){
if(!jumping){
acc = 1f;
}
jumping = true;
}
if(input.isKeyDown(Input.KEY_LEFT) && !input.isKeyDown(Input.KEY_RIGHT)){
keyDown = false;
mov -= 0.006f;
if (mov < -runSpeed){
mov = -runSpeed;
}
}
if(input.isKeyDown(Input.KEY_RIGHT) && !input.isKeyDown(Input.KEY_LEFT)){
keyDown = false;
mov += 0.006f;
if (mov > runSpeed){
mov = runSpeed;
}
}
if(input.isKeyPressed(Input.KEY_ESCAPE)){
exitFlag = true;
}
}
public int getID(){
return 1;
}
}
由于我无法预测潜在帮助者可能需要的更多信息,我现在就将其留在那里,但当然我可以在需要时提供更多信息。
谢谢, 学家