Java игра-как остановить игрока от хождения по препятствиям
Я создал очень простой класс 2D Java-игр, состоящий из общих методов 2D-игр, таких как render и update, я настроил все свои операторы if так, чтобы игрок перемещался по карте с помощью ввода стрелок клавиатуры. Я сейчас пытаюсь настроить то, что я прочитал, это обнаружение столкновений, я знаю основы того, что мне нужно сделать, потому что я много читал, прежде чем я действительно пришел сюда, чтобы задать вопрос, из того, что я прочитал, это звучит примерно так:
Сделать 2 прямоугольники
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 разных направлениях (вверх, вниз, влево, вправо). Было бы намного проще, если бы он был просто 1-мерным, потому что я мог бы просто изменить направление на противоположное тому, что он был, но его два измерения, так что он это немного сбивает с толку.
Дополнительная информация:
Представление, в которое играет моя игра, похоже на следующее: http://www.2dplay.com/awesome-tanks/awesome-tanks-play.htm
Правка 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;
}
}
2 ответа:
В качестве предварительного условия ваш класс игроков (или один из его суперклассов) должен иметь несколько полей, описывающих их скорость (пара полей для x-speed и y-speed работает очень хорошо, хотя вам понадобится триггер, чтобы настроить игрока в заданном направлении). Вот пример простого класса игроков с полями 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
, Вы можете использовать методintersection()
, почти все классы прямоугольников имеют нечто подобное) и определить, является ли х-скорость, у-скорость, или оба должны быть установлены в ноль. Например, если перекресток шире, чем он высок (больше по оси x, чем по оси y), вы, вероятно, должны установить скорость y в ноль, но не затрагивать скорость X. Если вы хотите, чтобы игрок развернулся (на 180 градусов), просто переверните знак x-скорости и y-скорости. Если вы хотите, чтобы игрок "отскочил" вместо остановки, проанализируйте пересечение точно так же, как в предыдущем случае, но измените скорость, а не установите ее на ноль. Вот несколько примеров кода (вероятно, не будет работать точно так, как написано, потому что я не знаю, как настраиваются ваши классы):Обратите внимание, что независимо от того, что вы решите делать, столкновения, как правило, очень трудно заставить работать гладко. Я бы счел все эти варианты хорошими отправными точками, на которых всегда можно было бы построить . Надеюсь, это поможет.//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; } }