У меня есть интересная ошибка с обнаружением столкновений: скорость игрока удваивается, когда он падает, а столкновение JAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 У меня есть интересная ошибка с обнаружением столкновений: скорость игрока удваивается, когда он падает, а столкновение

Сообщение Anonymous »

Я программирую на Java 2D-игру с видом сверху и 8 направленными движениями, и во время написания своего следующего большого достижения — обнаружения столкновений — я столкнулся с серьёзной ошибкой. Как описано в вопросе, персонаж игрока (который на данный момент представляет собой коробку) удвоит свою скорость и выйдет за пределы карты, а затем игра вылетит (но не закроется), игрок застрянет на месте (см. изображение ниже).
Изображение

Кроме того, на консоль выдается ошибка выхода за пределы массива, исходящая из класса CollisionDetection, сообщающая, что он достиг границ карты, которые равны 5x5 (для целей тестирования).

Исключение в потоке «Thread-0» java.lang.ArrayIndexOutOfBoundsException: индекс 5 из 5 выходит за пределы для длины 5
в lu.embellishedduck.liminalmurmurs.engine.CollisionDetection.checkTileCollision (CollisionDetection.java:134)
...

Вот код класса CollisionDetection, отмечена строка, которая выдает ошибку. по заголовку

Код: Выделить всё

public class CollisionDetection {

//=======================
// INSTANTIATE VARIABLES
//=======================

GamePanel gamePanel;

//=============
// CONSTRUCTOR
//=============
public CollisionDetection(GamePanel gamePanel) {

this.gamePanel = gamePanel;

}//End of Constructor

//=======================================================
// METHOD TO CHECK A TILE TO SEE IF IT WILL COLLIDE WITH
// THE ENTITY PASSED IN
//=======================================================

public void checkTileCollision(Entity entity) {

//----------------------------------------------------
// FIRST UP THE ROW AND COL OF THE HIT-BOX ARE NEEDED
//----------------------------------------------------

int entityLeftWorldX = entity.getWorldX() + entity.getHitBox().x;
int entityRightWorldX = entity.getWorldX() + entity.getHitBox().x + entity.getHitBox().width;
int entityTopWorldY = entity.getWorldY() + entity.getHitBox().y;
int entityBottomWorldY = entity.getWorldY() + entity.getHitBox().y + entity.getHitBox().height;

int entityLeftCol = entityLeftWorldX / gamePanel.getTILE_SIZE();
int entityRightCol = entityRightWorldX / gamePanel.getTILE_SIZE();
int entityTopRow = entityTopWorldY / gamePanel.getTILE_SIZE();
int entityBottomRow = entityBottomWorldY / gamePanel.getTILE_SIZE();

int tileNum1, tileNum2;

//-----------------------
// SWITCH STATEMENT TIME
//-----------------------

switch (entity.getDirection()) {

case "up-left" :

entityTopRow = (entityTopWorldY - entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();

tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityLeftCol][entityTopRow];

if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision()) {

entity.setCollisionOn(true);

}//End of If Statement

break;

case "up-right" :

entityTopRow = (entityTopWorldY - entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();

tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityRightCol][entityTopRow];

if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision()) {

entity.setCollisionOn(true);

}//End of If Statement

break;

case "down-left" :

entityBottomRow = (entityBottomWorldY + entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();

tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityLeftCol][entityBottomRow];

if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision()) {

entity.setCollisionOn(true);

}//End of If Statement

break;

case "down-right" :

entityBottomRow = (entityBottomWorldY + entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();

tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityRightCol][entityBottomRow];

if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision()) {

entity.setCollisionOn(true);

}//End of If-Statement

break;

case "up" :

entityTopRow = (entityTopWorldY - entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();

//This essentially predicts where the player will be and checks for collision with the if statement
tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityLeftCol][entityTopRow];
tileNum2 = gamePanel.getTileManager().getMapTileNum()[entityRightCol][entityTopRow];

if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision() || gamePanel.getTileManager().getTiles()[tileNum2].isCollision()) {

entity.setCollisionOn(true);

}//End of If Statement

break;

case "down"  :

entityBottomRow = (entityBottomWorldY + entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();

// The line below is the erroneous one

tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityLeftCol][entityBottomRow]; // THIS LINE
tileNum2 = gamePanel.getTileManager().getMapTileNum()[entityRightCol][entityBottomRow];

if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision() || gamePanel.getTileManager().getTiles()[tileNum2].isCollision()) {

entity.setCollisionOn(true);

}//End of If Statement

break;

case "right" :

entityRightCol = (entityRightWorldX + entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();

//This essentially predicts where the player will be and checks for collision with the if statement
tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityRightCol][entityTopRow];
tileNum2 = gamePanel.getTileManager().getMapTileNum()[entityRightCol][entityBottomRow];

if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision() || gamePanel.getTileManager().getTiles()[tileNum2].isCollision()) {

entity.setCollisionOn(true);

}//End of If Statement

break;

case "left" :

entityLeftCol = (entityLeftWorldX - entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();

//This essentially predicts where the player will be and checks for collision with the if statement
tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityLeftCol][entityTopRow];
tileNum2 = gamePanel.getTileManager().getMapTileNum()[entityLeftCol][entityBottomRow];

if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision() || gamePanel.getTileManager().getTiles()[tileNum2].isCollision()) {

entity.setCollisionOn(true);

}//End of If Statement

break;

}//End of Switch-Case Statement

}//End of Method

}//End of Class
MapTileNum — это двумерный массив типа int[][], где первая часть x равна максимальному количеству столбцов фрагментов, которые может иметь карта мира. , вторая часть аналогична первой, за исключением максимального количества строк плитки. Размер каждого отображаемого фрагмента составляет 96x96 пикселей. Они были умножены на коэффициент 0,75 по сравнению с размером спрайта, равным 128. Как упоминалось ранее, максимальное количество столбцов и строк равно 5 (для карты мира размером 5x5)
Кроме того, может возникнуть проблема с обработкой движений в классе Player, как показано ниже:

Код: Выделить всё

public class Player extends Entity {

//======================
// Instantiate Variables
//======================

GamePanel gamePanel;
KeyHandler keyHandler;

//These are hardcoded values that tell the program where on the screen the player character should start when they enter the game
private final int screenX;
private final int screenY;

//=============
// CONSTRUCTOR
//=============

public Player(GamePanel gp, KeyHandler keyHandler) {

this.gamePanel = gp;
this.keyHandler = keyHandler;

//This logic makes that player always start in the middle of the screen
screenX = gp.getSCREEN_WIDTH() / 2 - (gp.getTILE_SIZE() / 2);
screenY = gp.getSCREEN_HEIGHT() / 2 - (gp.getREAL_TILE_SIZE() / 2);

setHitBox(new Rectangle());
getHitBox().x = 16;
getHitBox().y = 32;
getHitBox().width = 64;
getHitBox().height = 64;

setDefaultValues();
getPlayerImage();

}//End of Constructor

//===========================================================
// Method to set the default values for the player variables
//===========================================================

public void setDefaultValues() {

//Obviously there will be more stats here in the future but those will have to be loaded to and from a save file
setMovementSpeed(4);

//Here the player's position is set relative to tile location on the world map
//for now I'm just setting this to 100 because I haven't made any world yet.
//Also, eventually there will be a save file system which will let the player
//continue from where they left off on the map.

//Should be mainPanel.getTileSize() * row/col

setWorldX(gamePanel.getTILE_SIZE() * 1);
setWorldY(gamePanel.getTILE_SIZE() * 2);

}//End of Method

//=======================================
// Method to get the image of the player
//=======================================

public void getPlayerImage() {

//Eventually there will be image IO things in here

}//End of Class

//==============================================================
// Method which handles the updating of the player's key inputs
//==============================================================

public void update() {

//-----------------
// Local Variables
//-----------------

int diagonalSpeed = (int) Math.round(getMovementSpeed() / Math.sqrt(2));

//----------------------------------------------------
// If Statement barrage! This time handling all cases
//----------------------------------------------------

if (keyHandler.isUpPressed() || keyHandler.isLeftPressed() || keyHandler.isRightPressed() || keyHandler.isDownPressed()
|| keyHandler.isUpLeftPressed() || keyHandler.isUpRightPressed() || keyHandler.isDownLeftPressed() || keyHandler.  isDownRightPressed()) {

if (keyHandler.isUpLeftPressed()) {

setDirection("up-left");

} else if (keyHandler.isUpRightPressed()) {

setDirection("up-right");

} else if (keyHandler.isDownLeftPressed()) {

setDirection("down-left");

} else if (keyHandler.isDownRightPressed()) {

setDirection("down-right");

} else {
//Handling the primary movement
if (keyHandler.isUpPressed()) {

setDirection("up");

}
if (keyHandler.isDownPressed()) {

setDirection("down");
worldY += getMovementSpeed();
}
if (keyHandler.isRightPressed()) {

setDirection("right");

}
if (keyHandler.isLeftPressed()) {

setDirection("left");

}

}//End of Primary Movement Else Statement

//CHECK TILE COLLISION
setCollisionOn(false);
gamePanel.getCollisionDetector().checkTileCollision(this);

//IF COLLISION IS FALSE PLAYER CAN MOVE
if (!isCollisionOn()) {

//Another switch case which will deal with the player movement speed

switch (getDirection()) {

case "up-left" :

worldX -= diagonalSpeed;
worldY -= diagonalSpeed;

break;

case "up-right" :

worldX += diagonalSpeed;
worldY -= diagonalSpeed;

break;

case "down-left" :

worldX -= diagonalSpeed;
worldY += diagonalSpeed;

break;

case "down-right" :

worldX += diagonalSpeed;
worldY += diagonalSpeed;

break;

case "up" :

worldY -= getMovementSpeed();

break;

case "down" :

worldY += getMovementSpeed();

break;

case "right" :

worldX += getMovementSpeed();

break;

case "left" :

worldX -= getMovementSpeed();

break;

}//End of Switch-Case Statement

}//End of If Statement

}//End of If Statement Barrage

}//End of Method

//============================================================================
// Method which handles the drawing of the player to whichever panel calls it
//============================================================================

public void draw (Graphics2D graphics2D){

graphics2D.setColor(Color.WHITE);
graphics2D.fillRect(screenX, screenY, gamePanel.getTILE_SIZE(), gamePanel.getTILE_SIZE());

graphics2D.setColor(Color.RED);
graphics2D.fillRect(screenX + 16, screenY + 32, 64, 64);

}//End of Method

//=========
// GETTERS
//=========

public GamePanel getGamePanel() {
return gamePanel;
}
public KeyHandler getKeyHandler() {
return keyHandler;
}
public int getScreenX() {
return screenX;
}
public int getScreenY() {
return screenY;
}

//=========
// SETTERS
//=========

public void setGamePanel(GamePanel gamePanel) {
this.gamePanel = gamePanel;
}
public void setKeyHandler(KeyHandler keyHandler) {
this.keyHandler = keyHandler;
}

//=================
// toString METHOD
//=================
@Override
public String toString() {

return "Player{"  +
"gp=" + gamePanel +
", keyHandler=" + keyHandler +
", screenX=" + screenX +
", screenY=" + screenY +
'}';

}//End of toString Method

}//End of Class
Кроме того, я заметил небольшой сбой, когда ящик игрока сталкивается с хитбоксом стены при прямом направлении ввода (т. е. влево), и если игрок затем пытается двигаться по диагонали он перемещает игрока примерно на 4 пикселя в стену, и он действительно застревает между двумя воображаемыми хитбоксами. Я думаю, что это связано с основной проблемой: ошибочное столкновение.
Я пробовал настроить фактическую скорость игрока и поменять местами некоторые математические операторы в полях tileNum, но они просто сгенерировали больше ошибки, и поэтому я их удалил. Помимо этого, я обнаружил несколько недостающих операторовbreak; для случая переключателя. Я просмотрел другие источники в Интернете, но ничего не нашел.
Глюк у меня нет понятия, что может быть причиной этого.

Подробнее здесь: https://stackoverflow.com/questions/788 ... d-is-doubl
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»