Slick2D矩形碰撞检测 [英] Slick2D Rectangle Collision Detection

查看:172
本文介绍了Slick2D矩形碰撞检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm having an issue showing that one rectangle has collided with another. So my question is, how can I get the intersect method to check for collision? Or are there any other ways to handle collision in this situation?

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

I'm creating a turn-based combat game (similar to Final Fantasy or Legend of Dragoon) where the player's character is on the right side of the screen and the enemy is on the left side. The player and enemy each take turns attacking. So when the player attacks, the sprite animation moves across the screen from right to left until it stops in front of the enemy, attacks, and returns to it's starting coordinates. Both the player and enemy have a rectangle drawn around them to represent the bounds of each character.

当玩家向前移动时,他会穿过敌人的矩形并在其中停留。此时应该输出到控制台说INTERSECT!显示两个矩形之间存在碰撞,但遗憾的是没有。

When the player moves forward, he passes through the Enemy's rectangle and stops within it. At this point there should be output to the console saying "INTERSECT!" to show that there was a collision between the two rectangles, but unfortunately there isn't.

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

Please note that I have omitted the unnecessary pieces of code within my classes and tried to provide the code that pertains to my problem.

这是我的入口点,GameClass:

This is my entry point, 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类的一瞥:

This is a glimpse at my Player class:

public class Player {

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

我的整个Enemy课程:

And my entire Enemy class:

public class Enemy {

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

我的Skeleton类扩展了Enemy:

My Skeleton class extends Enemy:

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(),没有绘制敌方矩形。

Note: Since I've switched g.drawRect() to g.draw(), enemy rectangle isn't being drawn.

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

Rect bound碰撞应该是: http://i.imgur.com/pOANfvN.png

Rect bound where collision should be: http://i.imgur.com/pOANfvN.png

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

I hope I've provided enough code to show you what my problem is. I've rummaged through the internet for hours with no luck. If there is any other code I need to provide, please do not hesitate to ask. Thank you very much for your help and support!

推荐答案

您没有自己更新hitbox职位。

You are not updating the hitbox positions themselves.

您正在绘制此:

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

但这不是实际的命中箱,只是玩家的位置/敌人和这里绘制的矩形将位于正确的位置,而命中箱本身则不是。

But this isn't the actual hitbox, it's just the position of the player/enemy and the rectangles drawn here will be on the correct position while the hitboxes themselves aren't.

我建议您执行以下操作:

I suggest you do the following:

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中,为您提供一些提示:

Furthermore, as you seem to be new to game development in Java, some tips for you:


  • 正确格式化代码

  • Format your code properly

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

Always place full {...} after if, else, switch, while, for, etc.; proper line indentation, .


  • 想想OO(面向对象)

  • Think OO (Object-Oriented)

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

This one is pretty important. Your enemy and player class should both extend some kind of entity class because they both will pretty much want to obtain similar behavior (avoid code duplication!). Sum up similar behavior to a super class, simplify the behavior to be controlled with a few adjustable parameters and so on.

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

For example, you store the positions of your enemy and player as a static integer in your main class. This is not OO. Move the positions to the entity class where you can implement it in whatever manner you wish.


  • 不要抛出异常无缘无故

  • Don't just throw an exception for no reason

您的更新(...)方法会抛出SlickException,即使它永远不需要。

Your update(...) method throws a SlickException even though it's never needed.


  • 小心封装

  • Be careful about encapsulation

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

This is something a lot of beginners do: Just grab some parameters, put them in a class as private (or maybe even public) and generate getters- and setters for them. This is not encapsulation. This is almost as bad as making them public in the first place.

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

But why don't we just make everything public?

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

We don't want anyone (or even ourselves) to rely on some parameters that just happen to be there because of some very specific implementation of something we might want to change later. Don't just put all possible values out there to be changed, the sense of encapsulation is to be independent from what kind of implementation we end up using and to protect the usability of our code by guarding what can be set/changed.


  • 表现确实重要

  • Performance does matter

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

This is one of the aspects you should watch out for, for any kind of software, but you can often most drastically see the consequences in games. Performance is important! And by that, I don't mean that you have to watch out for every single detail, but just keep an overview in mind on how to improve and fasten up your code, especially with frequently called methods such as update(..) and render(..) in Slick2D.

更新

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

As a solution to another problem discussed in the comments:

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,永远不会触发。

width and height can only be 0 as they are never assigned an integers have the value 0 per default, so the enemy rectangle hitbox does have 0 width and will never trigger.

尝试类似:

 public class Enemy {

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

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

This should work, but you should probably move all these attributes to the enemy class and put them in the constructor.

这篇关于Slick2D矩形碰撞检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆