我正在尝试制作一个java 2d游戏,而且它似乎总体上运作良好。唯一的问题是,我无法弄清楚如何设置我的“三角洲”时间,以使动作在30 FPS和1000 FPS上移动相同。
这是我的Entity类的代码:
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,但我不知道如何实现它。
如何正确实施?这会有很大的帮助!
答案 0 :(得分:2)
最简单的方法是考虑如果你想要一个恒定速度的恒定位移,你可以相对于30 FPS的增量来缩放所有增量,如下所示:
因此,如果您以60 FPS运行,但想要与30FPS 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;
这只是一个粗略的解决方案,让我知道它是如何工作的,我将稍后介绍并更新以获得更正确的解决方案(考虑到由于渲染和计算花费一些时间,delta并不总是1 / FPS)
编辑:变量delta将在稍后出现。但有些优化:
vx + posx, vy+posy
创建一个矩形,然后检查是否与此相交。以上应该是碰撞检查的一半。要进一步优化,请考虑使用QuadTree
可以找到here的实现。
针对“块状”碰撞测试的问题(从阻塞对象中停止X像素)。您可以使用伪代码执行以下操作:
if(new position will make this colide)
while(this.position is more than one pixel away from blocking object)
keep moving one pixel
这会让你从目标停止1px。