Java游戏-如何阻止玩家越过障碍物
我制作了一个非常简单的2D Java游戏类,它由一般的2D游戏方法(如render和update)组成,我设置了所有的if语句,以便玩家使用键盘箭头输入在地图上移动。我现在正在尝试设置我读到的是碰撞检测,我知道我需要做的基本操作,因为我在来这里问问题之前读了很多书,从我读到的内容来看,它是这样的: 做两个长方形Java游戏-如何阻止玩家越过障碍物,java,awt,collision-detection,Java,Awt,Collision Detection,我制作了一个非常简单的2D Java游戏类,它由一般的2D游戏方法(如render和update)组成,我设置了所有的if语句,以便玩家使用键盘箭头输入在地图上移动。我现在正在尝试设置我读到的是碰撞检测,我知道我需要做的基本操作,因为我在来这里问问题之前读了很多书,从我读到的内容来看,它是这样的: 做两个长方形 Rectangle rectOne = new Rectangle(playerX, playerY, 40, 40); //keep in mind that the variabl
Rectangle rectOne = new Rectangle(playerX, playerY, 40, 40);
//keep in mind that the variables playerX and playerY are already made previously
Rectangle rectTwo = new Rectangle(50, 50, 100,100);
然后根据我的更新方法,我会说:
if(rectOne.intersects(rectTwo)){//change the player direction so that he
can go no further}
我只是不明白在我的if语句中会出现什么,我需要一些东西来阻止我的播放器在交叉点发生时继续前进,但是我如何写这个,因为播放器可以向上、下、左、右4个不同的方向移动。如果它是一维的话就简单多了,因为我可以把方向改成与它相反的方向,但是它是二维的,所以有点混乱
其他信息:
我玩游戏的视图类似于以下内容:
编辑3:
package javagame;
import java.awt.Rectangle;
IMPORTS ARE HERE
public class Play extends BasicGameState{
Animation bucky, movingUp, movingDown, movingLeft, movingRight;
Image worldMap;
boolean quit = false;//gives user to quit the game
int[] duration = {200, 200};//how long frame stays up for
int buckyPositionX = 0;
int buckyPositionY = 0;
int x = buckyPositionX + 320;//keeps user in the middle of the screem
int y = buckyPositionY + 160;//the numbers are half of the screen size
Rectangle rectOne = new Rectangle(x, y,90,90);
Rectangle rectTwo = new Rectangle(500 + buckyPositionX, 330 + buckyPositionY, 210, 150);
private int xSpeed, ySpeed;///////////////////////////CODE FOR COLLISION
public Play(int state){
}
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
worldMap = new Image("res/world.png");
Image[] walkUp = {new Image("res/b.png"), new Image("res/b.png")}; //these are the images to be used in the "walkUp" animation
Image[] walkDown = {new Image("res/f.png"), new Image("res/f.png")};
Image[] walkLeft = {new Image("res/l.png"), new Image("res/l.png")};
Image[] walkRight = {new Image("res/r.png"), new Image("res/r.png")};
movingUp = new Animation(walkUp, duration, false);
movingDown = new Animation(walkDown, duration, false);
movingLeft = new Animation(walkLeft, duration, false);
movingRight = new Animation(walkRight, duration, false);
bucky = movingDown;//facing screen initially on startup
}
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
worldMap.draw(buckyPositionX, buckyPositionY);//position 0,0
bucky.draw(x, y);//makes him appear at center of map
g.fillRect(x, y,90,90);
g.fillRect(500 + buckyPositionX, 330 + buckyPositionY, 210, 150);
if(quit==true){
g.drawString("Resume(R)", 250, 100);
g.drawString("Main(M)", 250, 150);
g.drawString("Quit Game(Q)", 250, 200);
if(quit==false){
g.clear();//wipe off everything from screen
}
}
}
public void setSpeedWithDirection(int speed, int direction)////////////CODE FOR COLLISION
{
xSpeed = (int) (Math.cos(direction) * speed);//////////////////////////CODE FOR COLLISION
ySpeed = (int) (Math.sin(direction) * speed);//////////////////////////CODE FOR COLLISION
}
public void update(GameContainer gc, StateBasedGame sbg, int delta)throws SlickException{
Input input = gc.getInput();
x += xSpeed;//////////////////////////////////////////CODE FOR COLLISION
y += ySpeed;//////////////////////////////////////////CODE FOR COLLISION
if(rectOne.intersects(rectTwo))///////////////////////CODE FOR COLLISION
{
xSpeed = 0;////////////////////////////CODE FOR COLLISION
ySpeed = 0;////////////////////////////CODE FOR COLLISION
}
//up
if(input.isKeyDown(Input.KEY_UP)){
bucky = movingUp;//changes the image to his back
buckyPositionY += 2;;//increase the Y coordinates of bucky (move him up)
if(buckyPositionY>162){//if I reach the top
buckyPositionY -= 2;//stops any further movement in that direction
}
}
//down
if(input.isKeyDown(Input.KEY_DOWN)){
bucky = movingDown;
buckyPositionY -= 2;
if(buckyPositionY<-550){
buckyPositionY += 2;//basically change the direction if + make -
}}
//left
if(input.isKeyDown(Input.KEY_LEFT)){
bucky = movingLeft;
buckyPositionX += 2;
if(buckyPositionX>324){
buckyPositionX -= 2;//delta * .1f
}}
//right
if(input.isKeyDown(Input.KEY_RIGHT)){
bucky = movingRight;
buckyPositionX -= 2;
if(buckyPositionX<-776){
buckyPositionX += 2;
}}
//escape
if(input.isKeyDown(Input.KEY_ESCAPE)){
quit=true;
}
//when the menu is up
if(quit==true){//is the menu on the screen
if(input.isKeyDown(Input.KEY_R)){
quit = false;//resumes the game, makes menu dissapear
}
if(input.isKeyDown(Input.KEY_M)){
sbg.enterState(0);//takes you to the main menu
}
if(input.isKeyDown(Input.KEY_Q)){
System.exit(0);//quits the game
}
}
}
public int getID(){
return 1;
}
}
我建议创建一个枚举方式。你应该知道他现在要走的路,然后换成相反的方式,或者你可以锁定当前的方式并选择一个随机的方式。我建议创建一个枚举方式。你应该知道他现在要走的路,然后换成相反的方式,或者,您可以锁定当前路径并选择随机路径。作为先决条件,您的玩家类或其超类应具有几个描述其速度的字段。x-speed和y-speed的一对字段工作得非常好,尽管您需要trig将玩家设置为给定方向。下面是一个具有x和y速度字段的简单玩家类示例:
public class Player
{
//coordinates of the player
private int x, y;
//horizontal and vertical components of the player's speed.
private int xSpeed, ySpeed;
//call a method similar to this one every time your player updates its position
public void updatePosition()
{
x += xSpeed;
y += ySpeed;
}
//Converts a speed and a direction (much easier to deal with)
//to an x speed and a y speed (much easier for actually moving)
//and sets the player's motion
public void setSpeedWithDirection(int speed, float direction)
{
xSpeed = Math.cos(direction) * speed;
ySpeed = Math.sin(direction) * speed;
}
}
为了实际反映玩家的速度,请在每次玩家更新时将x速度添加到玩家的x坐标,并在每次玩家更新时将y速度添加到玩家的y坐标。现在,当碰撞发生时,可能会发生很多事情。最简单的方法是通过将其x速度和y速度设置为零来停止播放器。然而,这可能看起来有问题,因为无论玩家朝哪个方向移动,他们都会停止移动。一种稍微好一点的方法是分析交叉点的形状,假设您使用的是java.awt.Rectangle。您可以使用交叉点方法,几乎所有的矩形类都有类似的内容,并确定x速度、y速度或两者都应设置为零。例如,如果交叉点在x轴上比y轴宽,那么可能应该将y轴速度设置为零,但x轴速度不受影响。如果你想让玩家旋转180度,只需翻转x-speed和y-speed的标志。如果你想让玩家弹跳而不是停止,就像前面的例子一样分析交叉点,但是反转速度而不是将其设置为零。这里有一些代码示例可能无法完全按照编写的代码工作,因为我不知道如何设置您的类:
//simple stop
if(rectOne.intersects(rectTwo))
{
player.xSpeed = 0;
player.ySpeed = 0;
}
//variable-axis stop
if(rectOne.intersects(rectTwo))
{
//depending on Rectangle implementation may need to use other method
Rectangle overlap = rectOne.intersection(rectTwo);
if (overlap.height >= overlap.width)
{
player.xSpeed = 0;
}
if (overlap.width >= overlap.height)
{
player.ySpeed = 0;
}
}
//simple turn-around (about face)
if(rectOne.intersects(rectTwo))
{
player.xSpeed *= -1;
player.ySpeed *= -1;
}
//bounce (variable-axis turn around)
if(rectOne.intersects(rectTwo))
{
Rectangle overlap = rectOne.intersection(rectTwo);
if (overlap.height >= overlap.width)
{
player.xSpeed *= -1;
}
if (overlap.width >= overlap.height)
{
player.ySpeed *= -1;
}
}
请注意,无论您选择做什么,碰撞都很难顺利进行。我会考虑所有这些选项,好的起点总是可以建立的。我希望这能有所帮助。作为一个先决条件,你的玩家类或它的超类应该有几个字段来描述它们的速度。x-speed和y-speed的一对字段工作得很好,尽管你需要trig来将玩家设置在给定的方向上。下面是一个具有x和y速度字段的简单玩家类示例:
public class Player
{
//coordinates of the player
private int x, y;
//horizontal and vertical components of the player's speed.
private int xSpeed, ySpeed;
//call a method similar to this one every time your player updates its position
public void updatePosition()
{
x += xSpeed;
y += ySpeed;
}
//Converts a speed and a direction (much easier to deal with)
//to an x speed and a y speed (much easier for actually moving)
//and sets the player's motion
public void setSpeedWithDirection(int speed, float direction)
{
xSpeed = Math.cos(direction) * speed;
ySpeed = Math.sin(direction) * speed;
}
}
为了实际反映玩家的速度,请在每次玩家更新时将x速度添加到玩家的x坐标,并在每次玩家更新时将y速度添加到玩家的y坐标。现在,当碰撞发生时,可能会发生很多事情。最简单的方法是通过将其x速度和y速度设置为零来停止播放器。然而,这可能看起来有问题,因为无论玩家朝哪个方向移动,他们都会停止移动。一种稍微好一点的方法是分析交叉点的形状,假设您使用的是java.awt.Rectangle。您可以使用交叉点方法,几乎所有的矩形类都有类似的内容,并确定x速度、y速度或两者都应设置为零。例如,如果交叉点在x轴上比y轴宽,那么可能应该将y轴速度设置为零,但x轴速度不受影响。如果你想让玩家旋转180度,只需翻转x-speed和y-speed的标志。如果你想让玩家弹跳而不是停止,就像前面的例子一样分析交叉点,但是反转速度而不是将其设置为零。这里有一些代码示例可能无法完全按照编写的代码工作,因为我不知道如何设置您的类:
//simple stop
if(rectOne.intersects(rectTwo))
{
player.xSpeed = 0;
player.ySpeed = 0;
}
//variable-axis stop
if(rectOne.intersects(rectTwo))
{
//depending on Rectangle implementation may need to use other method
Rectangle overlap = rectOne.intersection(rectTwo);
if (overlap.height >= overlap.width)
{
player.xSpeed = 0;
}
if (overlap.width >= overlap.height)
{
player.ySpeed = 0;
}
}
//simple turn-around (about face)
if(rectOne.intersects(rectTwo))
{
player.xSpeed *= -1;
player.ySpeed *= -1;
}
//bounce (variable-axis turn around)
if(rectOne.intersects(rectTwo))
{
Rectangle overlap = rectOne.intersection(rectTwo);
if (overlap.height >= overlap.width)
{
player.xSpeed *= -1;
}
if (overlap.width >= overlap.height)
{
player.ySpeed *= -1;
}
}
请注意,无论您选择做什么
幻觉往往很难顺利工作。我会考虑所有这些选项,好的起点总是可以建立的。我希望这能有所帮助。你是说玩家应该“反弹”物体吗?你可以看看基本上使用碰撞检测过程来确定物体应该从障碍物的哪个方向移动,基于它的当前移动方向。你是说玩家应该“反弹”物体吗?你可以看看它基本上使用碰撞检测过程,根据物体当前的运动方向来确定物体应该离开障碍物的方向。谢谢你花时间给我写一封详细的回复,我理解您编写的冲突代码背后的基础知识,但由于我是Java新手,我对如何设置我的xSpeed和ySpeed有点困惑,您能帮我一下吗?@RahulKhosla编辑了这样一个设置示例。感谢您给我举个例子来帮助我,我曾尝试使用您的代码在我的游戏中创建冲突,但出现错误,我将私有变量添加到我的代码中,我已使用setSpeedWidthDirection方法,并假设处于更新位置的代码和if语句可以位于我的代码中已存在的更新方法下,我用buckyPositionX和buckyPositionY替换了player,但在获得player的位置下出现以下错误。xSpeed=0;错误显示buckyPositionX没有xSpeed字段,您能帮我修复吗?我已经为您发布了我的代码,以帮助您查看我是如何设置的,您帮助我使用的代码被标记为碰撞代码。@RahulKhosla Ahh。在您的设置中,xspeed和yspeed是游戏的成员变量,而不是玩家。我建议创建一个新类来表示游戏中移动的实体,并将我的代码放在该类而不是游戏类中。或者,如果玩家是你游戏中唯一移动的东西,你可以简单地拿走玩家的,它应该会起作用。不过,请确保播放器是在x和y处绘制的。感谢您花时间给我写一个详细的回复,我理解您编写的冲突代码背后的基本原理,但由于我是Java新手,我对如何设置我的xSpeed和ySpeed有点困惑,你能帮我一下吗?@RahulKhosla编辑后加入了这样一个设置的例子。谢谢你给我一个例子来帮助我,我曾试图用你的代码在我的游戏中创建冲突,但出现了一个错误,我在代码中添加了私有变量,我使用了setSpeedWidthDirection方法,并假设处于更新位置的代码和if语句可以在我的代码中已经存在的更新方法下运行,我用我的buckyPositionX和buckyPositionY替换了player,但在获得player的位置下出现以下错误。xSpeed=0;错误显示buckyPositionX没有xSpeed字段,您能帮我修复吗?我已经为您发布了我的代码,以帮助您查看我是如何设置的,您帮助我使用的代码被标记为碰撞代码。@RahulKhosla Ahh。在您的设置中,xspeed和yspeed是游戏的成员变量,而不是玩家。我建议创建一个新类来表示游戏中移动的实体,并将我的代码放在该类而不是游戏类中。或者,如果玩家是你游戏中唯一移动的东西,你可以简单地拿走玩家的,它应该会起作用。但要确保玩家是在x和y方向绘制的。