我正在制作我的第一个2D游戏,当我向上移动并与瓷砖相撞时,它会停止,我仍然可以左右移动,但很难穿过门口。
下图显示了玩家被卡住的地方,他们不能向右或向下移动,也不能向上移动,但这是有意的
抱歉,如果我遗漏了一些重要的事情,这是我第一次发帖。
为了澄清,我的碰撞框设置得比我的玩家小一点,这样玩家将与墙砖重叠一点,因此当试图穿过右侧的门口时,如果玩家碰撞框的顶部与墙砖碰撞框的底部发生碰撞,它确实会阻止玩家向上移动,但如果玩家试图继续向右移动,玩家将被阻止
玩家被卡在哪里的图像
package game.handlers;
import game.GamePanel;
import game.entities.Entity;
import game.items.Item;
import game.items.objects.*;
import game.items.misc.*;
public class CollisionHandler
{
GamePanel gp;
public CollisionHandler(GamePanel gp)
{
this.gp = gp;
}
public void checkTile(Entity entity)
{
int entityLeftWorldX = entity.worldX + entity.collisionBox.x;
int entityRightWorldX = entity.worldX + entity.collisionBox.x + entity.collisionBox.width;
int entityTopWorldY = entity.worldY + entity.collisionBox.y;
int entityBottemWorldY = entity.worldY + entity.collisionBox.y + entity.collisionBox.height;
int entityLeftCol = entityLeftWorldX / gp.tileSize;
int entityRightCol = entityRightWorldX / gp.tileSize;
int entityTopRow = entityTopWorldY / gp.tileSize;
int entityBottemRow = entityBottemWorldY / gp.tileSize;
int tileNum1, tileNum2;
switch(entity.direction)
{
case "up":
entityTopRow = (entityTopWorldY - entity.speed) / gp.tileSize;
tileNum1 = gp.tm.mapTileNum[entityLeftCol] [entityTopRow];
tileNum2 = gp.tm.mapTileNum[entityRightCol] [entityBottemRow];
if(gp.tm.tile[tileNum1].hasCollision || gp.tm.tile[tileNum2].hasCollision)
{
entity.collisionOn = true;
}
break;
case "down":
entityBottemRow = (entityBottemWorldY + entity.speed) / gp.tileSize;
tileNum1 = gp.tm.mapTileNum[entityLeftCol] [entityTopRow];
tileNum2 = gp.tm.mapTileNum[entityRightCol] [entityBottemRow];
if(gp.tm.tile[tileNum1].hasCollision || gp.tm.tile[tileNum2].hasCollision)
{
entity.collisionOn = true;
}
break;
case "left":
entityLeftCol = (entityLeftWorldX - entity.speed) / gp.tileSize;
tileNum1 = gp.tm.mapTileNum[entityLeftCol] [entityTopRow];
tileNum2 = gp.tm.mapTileNum[entityRightCol] [entityBottemRow];
if(gp.tm.tile[tileNum1].hasCollision || gp.tm.tile[tileNum2].hasCollision)
{
entity.collisionOn = true;
}
break;
case "right":
entityRightCol = (entityRightWorldX + entity.speed) / gp.tileSize;
tileNum1 = gp.tm.mapTileNum[entityLeftCol] [entityTopRow];
tileNum2 = gp.tm.mapTileNum[entityRightCol] [entityBottemRow];
if(gp.tm.tile[tileNum1].hasCollision || gp.tm.tile[tileNum2].hasCollision)
{
entity.collisionOn = true;
}
break;
default:
break;
}
}
public int checkItem(Entity entity, boolean player)
{
int index = 999;
for(Item item: gp.items)
{
if(item != null)
{
entity.collisionBox.x = entity.worldX + entity.collisionBox.x;
entity.collisionBox.y = entity.worldY + entity.collisionBox.y;
item.collisionBox.x = item.worldX + item.collisionBox.x;
item.collisionBox.y = item.worldY + item.collisionBox.y;
switch(entity.direction)
{
case "up":
entity.collisionBox.y -= entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
break;
case "down":
entity.collisionBox.y += entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
break;
case "left":
entity.collisionBox.x -= entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
break;
case "right":
entity.collisionBox.x += entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
break;
}
/*switch(entity.direction)
{
case "up":
entity.collisionBox.y -= entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item instanceof SObject)
{
SObject object = (SObject)item;
object.interact(gp);
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
else
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
}
break;
case "down":
entity.collisionBox.y += entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item instanceof SObject)
{
SObject object = (SObject)item;
object.interact(gp);
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
else
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
}
break;
case "left":
entity.collisionBox.x -= entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item instanceof SObject)
{
SObject object = (SObject)item;
object.interact(gp);
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
else
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
}
break;
case "right":
entity.collisionBox.x += entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item instanceof SObject)
{
SObject object = (SObject)item;
object.interact(gp);
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
else
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
if(player)
{
index = gp.items.indexOf(item);
}
}
}
break;
}*/
entity.collisionBox.x = entity.defaultCollisionBoxX;
entity.collisionBox.y = entity.defaultCollisionBoxY;
item.collisionBox.x = item.defaultCollisionBoxX;
item.collisionBox.y = item.defaultCollisionBoxY;
}
}
return index;
}
public void interact(Entity entity, int index)
{
Item item = gp.items.get(index);
if(item != null)
{
entity.collisionBox.x = entity.worldX + entity.collisionBox.x;
entity.collisionBox.y = entity.worldY + entity.collisionBox.y;
item.collisionBox.x = item.worldX + item.collisionBox.x;
item.collisionBox.y = item.worldY + item.collisionBox.y;
switch(entity.direction)
{
case "up":
entity.collisionBox.y -= entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
}
break;
case "down":
entity.collisionBox.y += entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
}
break;
case "left":
entity.collisionBox.x -= entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
}
break;
case "right":
entity.collisionBox.x += entity.speed;
if(entity.collisionBox.intersects(item.collisionBox))
{
if(item.hasCollision)
{
entity.collisionOn = true;
}
}
break;
}
entity.collisionBox.x = entity.defaultCollisionBoxX;
entity.collisionBox.y = entity.defaultCollisionBoxY;
item.collisionBox.x = item.defaultCollisionBoxX;
item.collisionBox.y = item.defaultCollisionBoxY;
}
}
}
package game.entities;
import game.util.Inventory;
import game.items.Item;
import java.awt.image.*;
import java.awt.Rectangle;
import java.util.ArrayList;
public abstract class Entity
{
public int health;
public int maxHealth;
public int worldX, worldY;
public int speed;
public BufferedImage up1, up2, down1, down2, left1, left2, right1, right2;
public String direction;
public int spriteCounter = 0;
public int spriteNumber = 1;
public Rectangle collisionBox;
public int defaultCollisionBoxX, defaultCollisionBoxY;
public boolean collisionOn = false;
public Inventory inv = new Inventory(this);
public Item equiped;
public ArrayList<String> diialogues = new ArrayList<String>();
public void heal(int amountToHeal)
{
health += amountToHeal;
if(health > maxHealth)
{
health = maxHealth;
}
}
public void damage(int amountToDamage)
{
health -= amountToDamage;
if(health < 0)
{
health = 0;
}
}
}
package game.entities;
import game.handlers.KeyHandler;
import game.items.Item;
import game.items.objects.SObject;
import game.GamePanel;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;
public class Player extends Entity
{
GamePanel gp;
KeyHandler kh;
public final int screenX;
public final int screenY;
public Player(GamePanel gp, KeyHandler kh)
{
this.gp = gp;
this.kh = kh;
screenX = gp.screenWidth/2 - (gp.tileSize/2);
screenY = gp.screenHeight/2 - (gp.tileSize/2);
collisionBox = new Rectangle(8, 16, 32, 32);
defaultCollisionBoxX = collisionBox.x;
defaultCollisionBoxY = collisionBox.y;
worldX = gp.tileSize * 22;
worldY = gp.tileSize * 46; //46
speed = 4;
direction = "down";
health = 50;
maxHealth = 100;
getPlayerImage();
}
public void getPlayerImage()
{
try
{
up1 = ImageIO.read(getClass().getResourceAsStream("/Resources/Entities/Player/boy_up_1.png"));
up2 = ImageIO.read(getClass().getResourceAsStream("/Resources/Entities/Player/boy_up_2.png"));
down1 = ImageIO.read(getClass().getResourceAsStream("/Resources/Entities/Player/boy_down_1.png"));
down2 = ImageIO.read(getClass().getResourceAsStream("/Resources/Entities/Player/boy_down_2.png"));
left1 = ImageIO.read(getClass().getResourceAsStream("/Resources/Entities/Player/boy_left_1.png"));
left2 = ImageIO.read(getClass().getResourceAsStream("/Resources/Entities/Player/boy_left_2.png"));
right1 = ImageIO.read(getClass().getResourceAsStream("/Resources/Entities/Player/boy_right_1.png"));
right2 = ImageIO.read(getClass().getResourceAsStream("/Resources/Entities/Player/boy_right_2.png"));
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void interactObject(int index)
{
if(gp.kh.ePressed)
{
if(index != 999)
{
SObject object = (SObject)gp.items.get(index);
object.interact(gp);
}
}
}
public void pickUpItem(int index)
{
if(index != 999)
{
if(gp.items.get(index) instanceof SObject)
{
}
else
{
//inv.items.add(gp.items.get(index));
gp.items.set(index, null);
}
}
}
public void interactNPC(int index)
{}
public void update()
{
if(kh.downPressed || kh.upPressed || kh.leftPressed || kh.rightPressed)
{
if(kh.upPressed)
{
direction = "up";
}
if(kh.downPressed)
{
direction = "down";
}
if(kh.leftPressed)
{
direction = "left";
}
if(kh.rightPressed)
{
direction = "right";
}
collisionOn = false;
gp.ch.checkTile(this);
int itemIndex = gp.ch.checkItem(this, true);
pickUpItem(itemIndex);
if(!collisionOn)
{
switch(direction)
{
case "up":
worldY -= speed;
break;
case "down":
worldY += speed;
break;
case "left":
worldX -= speed;
break;
case "right":
worldX += speed;
break;
}
}
//int objectIndex = gp.ch.checkItem(this, true);
//interactObject(objectIndex);
gp.kh.ePressed = false;
spriteCounter++;
if(spriteCounter > 12)
{
if(spriteNumber == 1)
{
spriteNumber = 2;
}
else if(spriteNumber == 2)
{
spriteNumber = 1;
}
spriteCounter = 0;
}
}
}
public void draw(Graphics2D g2d)
{
BufferedImage image = null;
switch(direction)
{
case "up":
if(spriteNumber == 1)
{
image = up1;
}
else if(spriteNumber == 2)
{
image = up2;
}
break;
case "down":
if(spriteNumber == 1)
{
image = down1;
}
else if(spriteNumber == 2)
{
image = down2;
}
break;
case "left":
if(spriteNumber == 1)
{
image = left1;
}
else if(spriteNumber == 2)
{
image = left2;
}
break;
case "right":
if(spriteNumber == 1)
{
image = right1;
}
else if(spriteNumber == 2)
{
image = right2;
}
break;
default:
break;
}
int x = screenX;
int y = screenY;
if(screenX > worldX)
{
x = worldX;
}
if(screenY > worldY)
{
y = worldY;
}
int rightOffset = gp.screenWidth - gp.player.screenX;
if(rightOffset > gp.worldWidth - gp.player.worldX)
{
x = gp.screenWidth - (gp.worldWidth - worldX);
}
int bottemOffset = gp.screenHeight - gp.player.screenY;
if(bottemOffset > gp.worldHeight - gp.player.worldY)
{
y = gp.screenHeight -(gp.worldHeight - worldY);
}
g2d.drawImage(image, x, y, gp.tileSize, gp.tileSize, null);
}
}
package game.handlers;
import game.GamePanel;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
public class KeyHandler implements KeyListener
{
GamePanel gp;
public boolean upPressed, leftPressed, downPressed, rightPressed;
public boolean ePressed, enterPressed;
private boolean u, u2, d, d2, l, r, l2, r2;
public KeyHandler(GamePanel gp)
{
this.gp = gp;
}
@Override
public void keyTyped(KeyEvent e)
{}
@Override
public void keyPressed(KeyEvent e)
{
int input = e.getKeyCode();
if(gp.gameState == gp.playState)
{
if(input == KeyEvent.VK_W)
{
upPressed = true;
}
if(input == KeyEvent.VK_A)
{
leftPressed = true;
}
if(input == KeyEvent.VK_S)
{
downPressed = true;
}
if(input == KeyEvent.VK_D)
{
rightPressed = true;
}
//interact key
if(input == KeyEvent.VK_E)
{
ePressed = true;
}
//Dev mode
if(input == KeyEvent.VK_UP)
{
if(!u)
{
u = true;
}
else if(u)
{
u2 = true;
}
if(u && u2)
{
if(!gp.devMode)
{
gp.devMode = true;
}
else if(gp.devMode)
{
gp.devMode = false;
}
}
}
if(gp.devMode)
{
if(input == KeyEvent.VK_T)
{
gp.player.heal(5);
}
if(input == KeyEvent.VK_Y)
{
gp.player.damage(5);
}
}
}
if(gp.gameState == gp.playState || gp.gameState == gp.pauseState)
{
//Toggle Pause Menu
if(input == KeyEvent.VK_P)
{
if(gp.gameState == gp.playState)
{
gp.gameState = gp.pauseState;
}
else if(gp.gameState == gp.pauseState)
{
gp.gameState = gp.playState;
}
}
}
if(gp.gameState == gp.textState)
{
if(input == KeyEvent.VK_ENTER)
{
enterPressed = true;
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
int input = e.getKeyCode();
if(input == KeyEvent.VK_W)
{
upPressed = false;
}
if(input == KeyEvent.VK_A)
{
leftPressed = false;
}
if(input == KeyEvent.VK_S)
{
downPressed = false;
}
if(input == KeyEvent.VK_D)
{
rightPressed = false;
}
}
}
我将非常感谢任何可以提供的帮助以及任何建议
回答你关于重构的问题:在很多地方,你的代码可以变得更干净、更高效。例如,考虑KeyHandler中的这一部分。爪哇:
if(!u)
{
u = true;
}
else if(u)
{
u2 = true;
}
if(u && u2)
{
if(!gp.devMode)
{
gp.devMode = true;
}
else if(gp.devMode)
{
gp.devMode = false;
}
}
看看第一个if语句。如果u
为false,则输入第一个分支并将其设置为true。否则u
为true,则输入第二个分支。在这第二个分支中,您有一个测试if(u)
。但是只有当u
为true时,您才能输入这个分支!这意味着您不需要再次检查它,它可以简化为
if (!u) {
u = true;
} else {
u2 = true;
}
现在,您可以看到在执行此if语句后,u
的值将始终为真(因为它要么从一开始就为真,要么在第一个分支中设置为真)。因此,它可以更加简化:
java prettyprint-override">if (u) {
u2 = true;
}
u = true;
之后是下一个if语句。条件是if(u
if(!gp.devMode)
{
gp.devMode = true;
}
else if(gp.devMode)
{
gp.devMode = false;
}
在这里您再次使用
u
变量执行与之前相同的过度测试:不需要第二个if(gp.devMode)
检查,因为为了进入这个分支gp.devMode
必须已经为真。此if-语句的全部含义是切换gp.devMode
的值:如果为真,则将其设置为false,反之亦然。您可以通过一个简单的赋值来实现这一点:
gp.devMode = !gp.devMode;
因此,第二个if语句可以简化为
if (u2) {
gp.devMode =! gp.devMode;
}
我们开始的整个代码块被简化为
if (u) {
u2 = true;
}
u = true;
if (u2) {
gp.devMode = !gp.devMode;
}
这只是代码的简化,同时保持相同的逻辑。在许多地方,逻辑也可以简化或更改。
而且,现在的代码很容易出现简单的打字错误。例如,要指定运动方向,请使用字符串。如果在其中一个地方你不小心输入了“rigth”而不是“right”,会发生什么?程序将编译并运行,但无法正常工作,并且很难发现错误。在这种情况下,更好的解决方案是使用枚举。所以,创建一个新的文件方向。爪哇:
public enum Direction {
UP,
DOWN,
LEFT,
RIGHT
}
然后在实体类中替换声明
public String direction;
具有
public Direction direction;
当需要使用它时,可以用相应的枚举值替换字符串,例如:
switch(direction) {
case Direction.UP:
worldY -= speed;
break;
case Direction.DOWN:
worldY += speed;
break;
case Direction.LEFT:
worldX -= speed;
break;
case Direction.RIGHT:
worldX += speed;
break;
}
这样效率更高,也不容易出错。如果你打错并写下
方向。RIGTH
,则代码将无法编译。如果您忘记在switch语句中指定所有的大小写,编译器现在也可以警告您。
还有许多其他地方可以改进(例如,您始终破坏封装),但让我们回到您关于碰撞的主要问题。从您提供的信息中很难说,但我认为您的播放器的碰撞框看起来有点像下图中的红色矩形:
现在,假设玩家在门的左侧和上方,玩家想要向右移动:
在碰撞检测代码中,您有以下内容:
case "right":
entityRightCol = (entityRightWorldX + entity.speed) / gp.tileSize;
tileNum1 = gp.tm.mapTileNum[entityLeftCol] [entityTopRow];
tileNum2 = gp.tm.mapTileNum[entityRightCol] [entityBottemRow];
if(gp.tm.tile[tileNum1].hasCollision || gp.tm.tile[tileNum2].hasCollision)
{
entity.collisionOn = true;
}
break;
它说,你计算出玩家右侧偏右的位置,然后检查左上方和右下方的瓷砖,即前一张图片上绿色显示的瓷砖。你现在看到问题了吗?你应该检查右顶部和右底部的瓷砖。但是,由于您的错误,没有检测到右上角与墙的碰撞,玩家可以在墙内进一步移动。
现在你会遇到这样的情况:
假设您现在按下向下键。检查如下:
case "down":
entityBottemRow = (entityBottemWorldY + entity.speed) / gp.tileSize;
tileNum1 = gp.tm.mapTileNum[entityLeftCol] [entityTopRow];
tileNum2 = gp.tm.mapTileNum[entityRightCol] [entityBottemRow];
if(gp.tm.tile[tileNum1].hasCollision || gp.tm.tile[tileNum2].hasCollision)
{
entity.collisionOn = true;
}
break;
再次检查左上角和右下角。右下角是自由的,但左上角卡在墙上,你不能移动。除向左移动外,其他所有方向也是如此。
为了解决这一问题,您需要在每种情况下检查两块瓷砖,它们位于所需移动的方向:
case UP: check left-top and right-top;
case DOWN: check left-bottom and right-bottom;
case LEFT: check left-top and left-bottom;
case RIGHT: check right-top and right-bottom;
当我一次又一次点击播放按钮时,它会同时播放多次。我想停止多重播放。这是代码: 媒体播放器和按钮的对象 按钮单击事件监听器以播放音频 按钮单击事件侦听器以停止音频 任何帮助都将不胜感激。谢谢
我正在我的游戏中实现碰撞检测,并有一点麻烦,理解如何计算矢量,以固定我的形状重叠碰撞。 举个例子,我有两个方块。和。对于这两者,我都知道它们的、、和。但是是移动的,所以他有一个速度和一个速度。假设我每秒更新一次游戏。我已经说明了下面的情况。 现在,我需要一个公式来得到矢量来固定重叠。如果我将这个向量应用到红色方块(),它们就不会再重叠了。这就是我想要达到的目标。 谁能帮我算出计算向量的公式吗? 如
当我尝试播放我的音乐时,Discord机器人不会播放音乐。它使用ytdl核心和ffmpeg。我的代码是: 每当我尝试播放歌曲时,都会发生以下错误: (节点:5180)未处理的PromisejectionWarning:错误:找不到FFmpeg/avconv!在功能上。getInfo(C:\Users\picar\Desktop\DiscordMusicBot\node\u modules\pris
我正在尝试编程一个简单的2D平台,我想让玩家浏览一些平台。不幸的是,我的玩家无缘无故地在某些平台上绊倒: 这显然不是我想要的。我唯一能想象的是,由于某种原因,这些盒子的高度不一样。。。但如何解决这个问题呢?以下是我的一些代码: createPlatform。。。 Runner.java-act()
我已经尝试解决了平滑的玩家-墙壁碰撞的问题,这样玩家可以沿着墙壁滑动。 我尝试了以下内容: 但是如果玩家碰到了墙,他不会滑动...他只是停下来了。(我对W,A,S,D也是分开做的。) 只有当我将玩家位置设置回他正在触摸的墙壁位置时,它才有效。如下: 但是它不起作用,因为对于与另一面墙相连的墙,玩家会接触更多的边,玩家会跳到角落...所以它只适用于一面墙... 我的问题是:如何以另一种方式使玩家与墙
获取碰撞器组件 Cocos Creator 3D 目前支持两种语言进行开发,分别为JavaScript和TypeScript。 注:TypeScript具有良好的语法分析和类型提示,推荐使用。 以获取BoxCollider为例,在JavaScript中获取Collider组件: this.getComponent('BoxCollider') this.getComponent(BoxCollid