我正在尝试制作一个 java 2d 游戏,总体来说效果似乎不错。唯一的问题是,我不知道如何放置我的“增量”时间,以使 Action 在 30 FPS 和 1000 FPS 上移动相同。
这是我的实体类代码:
import java.awt.Rectangle;
import map.Tile;
import graphics.Sprite;
public class Entity {
private String name;
private float positionx, positiony; // Current coordinate
private int targetx,targety; // Target coordinate
private double vx, vy; // Current vector
private double lx, ly; // Last vector
private float speed;
private Sprite sprite;
public Entity(String name, int x, int y, Sprite sprite){
this.name = name;
this.speed = 1f;
this.positionx = x;
this.positiony = y;
this.sprite = sprite;
main.Main.e.addEntity(this); // These kind of calls are ugly, and should be fixed.
}
public void remove(){
main.Main.e.removeEntity(this);
sprite.remove();
}
public void setVector(double vx, double vy){
this.vx = vx;
this.vy = vy;
}
public void update(long delta){
//Multiply modifier to make it act the same on 30 fps as 1000 fps.
vx = vx*delta;
vy = vy*delta;
// Calculate vector
double distance = Math.sqrt((vx * vx) + (vy * vy));
if(distance > 0){ // Have we reached the target yet?
vx = ((vx / distance));
vy = ((vy / distance));
}else{
vx = 0;
vy = 0;
}
//Check collision with objects:
Rectangle rx = new Rectangle((int) (vx+positionx), (int)positiony, 32, 32);
Rectangle ry = new Rectangle((int) positionx, (int)(vy+positiony), 32, 32);
for(Entity e : main.Main.e.getEntities()){
if(this != e){
if(isIntersecting(rx, e.getBounds())){
vx = 0; // Disallow x direction.
}
if(isIntersecting(ry, e.getBounds())){
vy = 0; // Disallow y direction.
}
}
}
//Check tiles:
for(Tile t : main.Main.m.getNeighbours(positionx,positiony)){
if(t.isBlocking()){
if(isIntersecting(rx, t.getBounds())){
vx = 0;
}
if(isIntersecting(ry, t.getBounds())){
vy = 0;
}
}
}
//Update the position:
positionx += vx*speed;
positiony += vy*speed;
//Animate:
animate(vx, vy);
}
public boolean isIntersecting(Rectangle r1, Rectangle r2){
return r1.intersects(r2);
}
public Rectangle getBounds(){
return new Rectangle((int) positionx,(int) positiony,32,32);
}
public void setMoveTo(int x, int y){
this.targetx = x;
this.targety = y;
}
//This function is used by the bots, and not on players (they are setting the vector and use update directly):
public void moveTo(long delta){
setVector((targetx-positionx),(targety-positiony));
update(delta);
}
public void animate(double dx, double dy){
sprite.setPosition((int)positionx, (int)positiony);
if(dx > 0){
sprite.setAnimation(0, 7, 100); // Walk right.
}else if(dx < 0){
sprite.setAnimation(1, 7, 100); // Walk left.
}else{
if(lx > 0){
sprite.setAnimation(2, 3, 200); // Stand right.
}else if(lx < 0){
sprite.setAnimation(3, 3, 200); // Stand left.
}
}
lx = dx;
ly = dy;
}
}
我经常遇到的两个问题:
1# 游戏在 60FPS 和 500FPS 上的运行方式不同。
2# 游戏在 60FPS 和 500FPS 下的运行速度相同,但我的碰撞发生了问题,而且我无法移动到距离其他物体超过 15px 的地方。我想我需要实现类似的东西:如果我不能靠近10px,那么将其移动10px,但我不知道如何实现它。
如何正确实现?这会有很大帮助!
最佳答案
最简单的方法是考虑,如果您想要恒定速度下的恒定位移,您可以相对于 30 FPS 的增量缩放所有增量,如下所示:
因此,如果您以 60 FPS 运行,但想要与 30 FPS alpha 相同的位移,则为 (1/30)/(1/60) = 2
所以
删除vx = vx*delta;
vy = vy*delta;
并将您的位置更新更改为
alpha = (1.0/30)*delta;
positionx += alpha*vx*speed;
positiony += alpha*vy*speed;
这只是一个粗略的解决方案,让我知道它是如何工作的,我稍后会更新以获得更正确的解决方案(考虑到由于渲染和计算需要一些时间,增量并不总是 1/FPS) .
编辑:变量增量稍后会出现。但一些优化:
- 您不需要在 Y 和 X 上构造一个矩形来进行碰撞检测,请尝试绘制两个矩形,如果它们相交,它们就会在两个轴上相交。只需从
vx + posx, vy+posy
创建一个矩形并检查与此的交集。 以上应该可以让你的碰撞检查减半。为了进一步优化,请考虑使用
QuadTree
可以找到一个实现 here .针对“ block 状”碰撞测试的问题(您从阻挡对象处停止 X 像素)。您可以用伪代码执行以下操作:
if(new position will make this colide) while(this.position is more than one pixel away from blocking object) keep moving one pixel
这将使您在距目标 1 像素处停止。
关于Java 2d 游戏 - 增量时间和碰撞问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18147880/