Java 2d游戏-增量时间和碰撞问题
我正在尝试制作一个Java2D游戏,总体来说效果不错。唯一的问题是,我不知道如何放置我的“delta”时间,以使移动速度与1000 FPS相同 这是我的实体类代码:Java 2d游戏-增量时间和碰撞问题,java,collision,2d-games,timedelta,Java,Collision,2d Games,Timedelta,我正在尝试制作一个Java2D游戏,总体来说效果不错。唯一的问题是,我不知道如何放置我的“delta”时间,以使移动速度与1000 FPS相同 这是我的实体类代码: import java.awt.Rectangle; import map.Tile; import graphics.Sprite; public class Entity { private String name; private float positionx, positiony; // Current coordin
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;
}
}
导入java.awt.Rectangle;
导入地图.Tile;
导入图形。精灵;
公共类实体{
私有字符串名称;
专用浮点位置X,位置Y;//当前坐标
private int targetx,targety;//目标坐标
专用双vx,vy;//当前向量
私有双lx,ly;//最后一个向量
私人浮动速度;
私人雪碧;
公共实体(字符串名称、整数x、整数y、精灵){
this.name=名称;
这个速度=1f;
这个位置x=x;
这个位置y=y;
this.sprite=精灵;
main.main.e.addEntity(this);//这种调用很难看,应该修复。
}
公共空间删除(){
main.main.e.移动实体(this);
sprite.remove();
}
公共无效设置向量(双vx,双vy){
这是vx=vx;
this.vy=vy;
}
公共无效更新(长增量){
//“倍增”修改器使其在30 fps和1000 fps上的动作相同。
vx=vx*δ;
vy=vy*delta;
//计算向量
双距离=数学sqrt((vx*vx)+(vy*vy));
如果(距离>0){//我们达到目标了吗?
vx=((vx/距离));
vy=((vy/距离));
}否则{
vx=0;
vy=0;
}
//检查与对象的碰撞:
矩形rx=新矩形((int)(vx+positionx),(int)positiony,32,32);
矩形ry=新矩形((int)位置x,(int)(vy+positiony),32,32);
for(实体e:main.main.e.getEntities()){
如果(此!=e){
如果(isIntersecting(rx,e.getBounds())){
vx=0;//不允许x方向。
}
if(isIntersecting(ry,e.getBounds())){
vy=0;//不允许y方向。
}
}
}
//检查瓷砖:
用于(瓷砖t:main.main.m.getNeights(位置X,位置Y)){
if(t.isBlocking()){
if(isIntersecting(rx,t.getBounds())){
vx=0;
}
if(isIntersecting(ry,t.getBounds())){
vy=0;
}
}
}
//更新职位:
位置X+=vx*速度;
位置Y+=vy*速度;
//制作动画:
制作动画(vx、vy);
}
公共布尔isIntersecting(矩形r1,矩形r2){
返回r1。相交(r2);
}
公共矩形getBounds(){
返回新矩形((int)位置x,(int)位置y,32,32);
}
公共void setMoveTo(整数x,整数y){
this.targetx=x;
this.targety=y;
}
//此功能由机器人使用,而不是在玩家身上(他们正在设置向量并直接使用更新):
公共空间移动到(长三角洲){
设置向量((targetx位置x),(targety位置y));
更新(增量);
}
公共空间动画(双dx,双dy){
设置位置((内部)位置X,(内部)位置Y);
如果(dx>0){
设置动画(0,7100);//向右走。
}else if(dx<0){
设置动画(1,7100);//向左走。
}否则{
如果(lx>0){
设置动画(2,3200);//站在右边。
}else if(lx<0){
setAnimation(3,3200);//站在左边。
}
}
lx=dx;
ly=dy;
}
}
我经常遇到的两个问题:
1#游戏以60帧/秒的速度运行与以500帧/秒的速度运行不同
2#游戏以60帧/秒的速度运行,与500帧/秒的速度运行,但我的碰撞出错,并且我无法移动到距离另一个对象15像素的距离。我想我需要实现一些类似的东西:如果我不能让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;
这只是一个粗略的解决方案,让我知道它是如何工作的,我稍后会访问并更新以获得更正确的解决方案(考虑到delta并不总是1/FPS,因为渲染和计算需要一些时间)
编辑:变量delta将稍后提供。但有一些优化:
对于碰撞检测,您不需要同时在Y和X上构造矩形,可以尝试绘制两个矩形,如果它们在两个轴上相交,则在两个轴上都这样做。只需从vx+posx,vy+posy创建一个矩形
,并检查与此相交
if(new position will make this colide)
while(this.position is more than one pixel away from blocking object)
keep moving one pixel
这将使您从目标停止1px。我们需要知道如何获得长增量,是1/FPS吗?长增量是渲染最后一帧所需的时间。60FPS,delta为16.6,100FPS,delta为10。其想法是FPS越低,delta越高,实体移动的次数越多,反之亦然。这应该进行调整,使30FPS计算机和500FPS计算机的移动速度相同(当然它会滞后于30FPS)。实际上,它似乎在10FPS和1000FPS中以相同的速度运行,这很好!关于碰撞的问题仍然存在,尽管这可能是碰撞本身的问题:撞到墙上,撞到墙上时停止,但不知何故y轴也会锁定(只是有时!),并且您被卡住的唯一选项是返回,而不是向上或向下。我的理论是,由于delta,它允许一个单独的帧