Slick2D矩形碰撞检测

时间:2014-07-15 09:52:18

标签: java collision-detection intersection slick2d rectangles

我有一个问题,显示一个矩形与另一个矩形相撞。所以我的问题是,如何让交叉方法检查碰撞?或者在这种情况下还有其他方法来处理碰撞吗?

我创造了一个回合制战斗游戏(类似于最终幻想或龙骑传奇),其中玩家的角色位于屏幕右侧,敌人位于左侧。玩家和敌人各自轮流攻击。所以当玩家攻击时,精灵动画会从右到左移动到屏幕上,直到它停在敌人面前,攻击并返回到它的起始坐标。玩家和敌人都有一个围绕它们绘制的矩形来表示每个角色的界限。

当玩家向前移动时,他会穿过敌人的矩形并停在其中。此时应该向控制台输出" INTERSECT!"表明两个矩形之间存在碰撞,但不幸的是没有。

请注意,我在课程中省略了不必要的代码段,并尝试提供与我的问题相关的代码。

这是我的切入点,GameClass:

public class GameClass extends BasicGame{
//other variable declarations

public void init(GameContainer container) throws SlickException {
player = new Player();
enemy = new Enemy();
skeleton = new Skeleton();
enemy = skeleton;
playX = player.getStartX(); //700
playY = player.getStartY(); //140
playW = player.rect.getWidth(); //40
playH = player.rect.getHeight(); //70
enemyX = enemy.getStartX(); //100
enemyY = enemy.getStartY(); //140
enemyWidth = enemy.getWidth(); //50
enemyHeight = enemy.getHeight(); //55

SpriteSheet sheet = new SpriteSheet("data/homeranim.png", 36, 65);
    anim = new Animation();
    for (int i=0;i<8;i++) {
        anim.addFrame(sheet.getSprite(i,0), 150);
    }
}

public void render(GameContainer container, Graphics g)
        throws SlickException {
anim.draw(playX,playY); // draws player animation
skeletonAnim.draw(enemyX, enemyY); // draws enemy
g.draw(player.rect); //draws player bounds
g.draw(enemy.rect); //draws enemy bounds
}

public void update(GameContainer container, int delta)
        throws SlickException {
playerUpdate(delta);
if (player.rect.intersects(enemy.rect)) {
             System.out.println("INTERSECT!");

         System.out.println("Player minX: " + player.rect.getMinX());
         System.out.println("Player maxX: " + player.rect.getMaxX());
         System.out.println("Enemy minX: " + enemy.rect.getMinX());
         System.out.println("Enemy maxX: " + enemy.rect.getMaxX());
         }
      }

public void playerUpdate(int delta) {
    if (playerForward == true){
       playX -= delta * 0.4f;
       if (playX <= 140) {
             playX = 140;
             playerForward = false;
             playerBackward = true;}
  }

   if (playerBackward == true) {
         playX += delta * 0.4f;
         if (playX >= 700) {
             playX = 700;
             playerBackward = false;
             delay = 1250;
  }

public void keyReleased(int key, char c) {
       if (key == Input.KEY_ENTER){
          playerForward = true;}
}
}

这是我的Player类的一瞥:

public class Player {

private int startX = 700;
private int startY = 140;
public Shape rect = new Rectangle(startX, startY, 40, 70);
//plus getters and setters
}

我的整个敌人课程:

public class Enemy {

private int startX, startY, width, height;
public Shape rect = new Rectangle(startX, startY, width, height);
// plus getters and setters
   }

我的骷髅课扩展了敌人:

public class Skeleton extends Enemy {

public Skeleton() {
    // TODO Auto-generated constructor stub
    setMaxHealth(120);
    setStartX(100);
    setStartY(140);
    setWidth(50);
    setHeight(55);
}

}

注意:由于我已将g.drawRect()切换为g.draw(),因此不会绘制敌方矩形。

起点处的矩形边界:http://i.imgur.com/QDDk858.png

应该在碰撞的地方绑定:http://i.imgur.com/pOANfvN.png

我希望我已经提供了足够的代码来向您展示我的问题所在。我已经在互联网上翻了好几个小时而没有运气。如果我需要提供任何其他代码,请不要犹豫。非常感谢您的帮助和支持!

1 个答案:

答案 0 :(得分:1)

您不是自己更新hitbox位置。

你正在画这个:

g.drawRect(playX, playY, playW, playH); //draws player bounds
g.drawRect(enemyX, enemyY, enemyW, enemyH); //draws enemy bounds

但这不是真正的击球手,它只是玩家/敌人的位置,这里绘制的矩形将位于正确的位置,而击球手本身则不是。

我建议你做以下事情:

public void update(GameContainer container, int delta)
{
    playerUpdate(delta);

    player.rect.setLocation(playX, playY);
    enemy.rect.setLocation(enemyX, enemyY); // update the hitboxes to the new positions

    if (player.rect.intersects(enemy.rect))
    {
        System.out.println("INTERSECT!");
    }
}

public void playerUpdate(int delta)
{
    if (playerForward == true)
    {
       playX -= delta * 0.4f;

       if (playX <= 140) 
       {
             playX = 140;
             playerForward = false;
             playerBackward = true;
       }
    }

    if (playerBackward == true) 
    {
         playX += delta * 0.4f;

         if (playX >= 700) 
         {
             playX = 700;
             playerBackward = false;
             delay = 1250;
         }
    }
}

public void keyReleased(int key, char c) 
{
   if (key == Input.KEY_ENTER)
   {
      playerForward = true;
   }
}

此外,由于您似乎对Java中的游戏开发不熟悉,所以有一些提示:

  • 正确格式化代码

总是在if,else,switch,while,for等之后放置{...};正确的行缩进,。

  • 想想OO(面向对象)

这个非常重要。你的敌人和玩家类都应该扩展某种实体类,因为他们都非常希望获得类似的行为(避免代码重复!)。总结类似于超类的行为,用一些可调参数简化要控制的行为等等。

例如,您将敌人和玩家的位置存储为主类中的静态整数。这不是OO。将位置移动到实体类,您可以以任何方式实现它。

  • 不要无缘无故地抛出异常

您的update(...)方法会抛出SlickException,即使它从不需要。

  • 小心封装

这是许多初学者所做的事情:只需获取一些参数,将它们作为私有(或者甚至是公共)放入类中,并为它们生成getter和setter。这是封装。这几乎与首先公开它们一样糟糕。

但为什么我们不公开一切?

我们不希望任何人(甚至我们自己)依赖恰好在那里的某些参数,因为我们可能希望稍后更改某些特定的实现。不要只是将所有可能的值放在那里进行更改,封装的意义与我们最终使用的实现类型无关,并通过保护可以设置/更改的内容来保护代码的可用性。

  • 效果很重要

对于任何类型的软件而言,这是您应该注意的方面之一,但您通常可以最彻底地看到游戏中的后果。表现很重要!而且,我并不是说你必须注意每一个细节,而是要记住如何改进和加强你的代码,特别是对于经常调用的方法,如update(..)和在Slick2D中渲染(..)。

<强>更新

作为评论中讨论的另一个问题的解决方案:

public class Enemy {

    private int startX, startY, width, height;
    public Shape rect = new Rectangle(startX, startY, width, height);
    // plus getters and setters
}

宽度和高度只能为0,因为它们永远不会被赋值为整数,默认值为0,因此敌方矩形hitbox确实有0宽度并且永远不会触发。

尝试类似:

 public class Enemy {

    private int startX, startY, width = 50, height = 70;
    public Shape rect = new Rectangle(startX, startY, width, height);
    // plus getters and setters
 }

这应该可行,但您应该将所有这些属性移动到敌人类并将它们放在构造函数中。