【问题标题】:How can I offset a Bounding Circle based on a rotation?如何根据旋转偏移边界圆?
【发布时间】:2021-10-26 18:44:11
【问题描述】:

我正在创建一个子弹射弹并给它一个绑定圈。我试图将圆圈设置在子弹的前面,这样当它撞击它时就会发生碰撞。下面是项目符号和显示边界圆位置的蓝色圆圈。

右下角的例子是我想要做的,但有任何旋转。关于如何动态偏移圆的任何想法?

HitBox.java(这是蓝色圆圈)

package com.icyrelic.game.object;

import com.icyrelic.game.object.entity.Entity;
import com.jogamp.opengl.math.VectorUtil;
import lombok.Getter;
import lombok.Setter;


public class HitBox {

    @Getter
    private GameObject object;
    @Getter @Setter
    private float width = 0, height = 0, xOffset = 0f, yOffset = 0f, radius = 0;


    public HitBox(GameObject object, float width, float height) {
        this.object = object;
        this.width = width;
        this.height = height;
    }

    public HitBox(GameObject entity, float radius) {
        this.object = object;
        this.radius = radius;
    }


    public boolean intersects(HitBox b) {
        boolean collisionX = getMinX() <= b.getMaxX() && getMaxX() >= b.getMinX();
        boolean collisionY = getMinY() <= b.getMaxY() && getMaxY() >= b.getMinY();

        return collisionX && collisionY;
    }

    public boolean willCollide(HitBox b, float x, float y) {
        //Circle vs Circle
        if(radius != 0 && b.getRadius() != 0)
            return circleCollide(x, y, b.getRadius(), b.getXOffset(), b.getYOffset());

        //Circle vs AABB
        if((radius != 0 && b.getRadius() == 0) || (radius == 0 && b.getRadius() != 0))
            return circleAABBCollusion(b, x, y);

        //AABB vs AABB
        boolean collisionX = getMinX() <= x+b.getWidth()/2 && getMaxX() >= x-b.getWidth()/2;
        boolean collisionY = getMinY() <= y+b.getHeight()/2 && getMaxY() >= y-b.getHeight()/2;

        return collisionX && collisionY;
    }

    private boolean circleCollide(float x2, float y2, float radius2, float xOffset2, float yOffset2) {
        double xDif = (object.getLocation().getX() + xOffset) - (x2 + xOffset2);
        double yDif = (object.getLocation().getY() + yOffset) - (y2 + yOffset2);
        double distanceSquared = xDif * xDif + yDif * yDif;

       return distanceSquared < (radius + radius2) * (radius + radius2);
    }

    private boolean circleAABBCollusion(HitBox b, float x, float y) {
        HitBox circle = radius == 0 ? b : this;
        HitBox aabb = radius == 0 ? this : b;

        float[] circleCenter = radius == 0 ? new float[] {x, y} : new float[] {object.getLocation().getX(), object.getLocation().getY()};
        float[] aabbCenter = radius == 0 ? new float[] {object.getLocation().getX(), object.getLocation().getY()} : new float[] {x, y};

        float closestX = circleCenter[0] + circle.getXOffset();
        float closestY = circleCenter[1] + circle.getYOffset();

        if(closestX < aabb.getMinX(aabbCenter[0])) closestX = aabb.getMinX(aabbCenter[0]);
        else if (closestX > aabb.getMaxX(aabbCenter[0])) closestX = aabb.getMaxX(aabbCenter[0]);

        if(closestY < aabb.getMinY(aabbCenter[1])) closestY = aabb.getMinY(aabbCenter[1]);
        else if (closestY > aabb.getMaxY(aabbCenter[1])) closestY = aabb.getMaxY(aabbCenter[1]);

        float dist = VectorUtil.distSquareVec3(new float[]{circleCenter[0]+circle.getXOffset(), circleCenter[1]+circle.getYOffset(), 1}, new float[]{closestX, closestY, 1});

        return dist <= circle.getRadius() * circle.getRadius();
    }

    private float getMinX() { return object.getLocation().getX()+xOffset - width/2; }
    private float getMaxX() { return object.getLocation().getX()+xOffset + width/2; }
    private float getMinY() { return object.getLocation().getY()+yOffset - height/2; }
    private float getMaxY() { return object.getLocation().getY()+yOffset + height/2;}

    private float getMinX(float x) { return x+xOffset - width/2; }
    private float getMaxX(float x) { return x+xOffset + width/2; }
    private float getMinY(float y) { return y+yOffset - height/2; }
    private float getMaxY(float y) { return y+yOffset + height/2;}

    public void setSize(float width, float height) { this.width = width; this.height = height; }
    public void setOffset(float x, float y) { this.xOffset = x; this.yOffset = y; }
}


Bullet.java

package com.icyrelic.game.object.projectile.type;

import com.icyrelic.game.Graphics.Animation;
import com.icyrelic.game.Graphics.ImageResource;
import com.icyrelic.game.object.projectile.Projectile;


public class Bullet extends Projectile {

    public Bullet(float x, float y, float width, float height, float rotation, float rotationOffset) {
        super(x,y,width, height, rotation, rotationOffset);
        hitBox.setRadius(0.03f);
        hitBox.setYOffset(-0.12f);
        location.setRotationOffset(-0f);



        animations = new Animation[1];
        ImageResource[] a = new ImageResource[1];
        a[0] = new ImageResource("/Projectile/Bullet.png");

        animations[0] = new Animation(a, 1);
    }

    @Override
    public void update() {
        //location.setRotation(0);
    }



}

Projectile.java

package com.icyrelic.game.object.projectile;

import com.icyrelic.game.Graphics.Graphics;
import com.icyrelic.game.object.GameObject;
import com.icyrelic.game.object.HitBox;
import lombok.Getter;


@Getter
public abstract class Projectile extends GameObject {

    protected float speed = 1.0f;
    protected HitBox hitBox;

    public Projectile(float x, float y, float width, float height, float rotation, float rotationOffset) {
        super(x, y, width, height, rotation, rotationOffset);
        this.hitBox = new HitBox(this, width, height);
    }

    @Override
    public void render() {
        super.render();
        Graphics.setColor(0,0, 1, 1);

        if(hitBox.getRadius() == 0) {
            Graphics.drawRect(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset(), hitBox.getWidth(), hitBox.getHeight(), false);
        } else {
            Graphics.drawHollowCircle(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset(), hitBox.getRadius());
        }
        Graphics.setColor(1,0, 0, 1);
        //Graphics.drawRect(location.getX(), location.getY(), width/2, height/2, false);
        Graphics.setColor(1,1, 1, 1);

        Graphics.setColor(1,1, 1, 1);
    }
}

GameObject.java

package com.icyrelic.game.object;

import com.icyrelic.game.Graphics.Animation;
import com.icyrelic.game.Graphics.Graphics;
import com.icyrelic.game.world.Location;
import lombok.Getter;



@Getter
public abstract class GameObject {


    protected Location location;

    protected float width = 1, height = 1;
    protected float xImageOffset = 0, yImageOffset = 0;

    protected Animation[] animations;
    protected int currentAnimation = 0;


    public GameObject(float x, float y, float width, float height, float rotation, float rotationOffset) {
        this.location = new Location(x, y, rotation, rotationOffset);
        this.width = width;
        this.height = height;


    }

    public void render () {
        animations[currentAnimation].play();

        Graphics.setRotation(location.getRotation() + location.getRotationOffset());
        Graphics.drawImage(animations[currentAnimation].getImage(), location.getX(), location.getY(), xImageOffset, yImageOffset, width, height);
        Graphics.setRotation(0);

        //Graphics.setRotation(-rotation);





    }

    public abstract void update ();
}

尝试翻译 Alberto 提供的信息后,我得到以下结果。它在正确的方向上有点接近,但仍然不是 100%

        hitBox.setXOffset(((float) Math.sin(location.getRotationRadians()) ));
        hitBox.setYOffset(((float) Math.cos(location.getRotationRadians()) ));

【问题讨论】:

  • 可能是分享您的代码的一个很好的起点?
  • 我添加了 Hitbox 和 Bullet 代码。不确定该问题究竟要分享什么,所以我希望我分享的内容就足够了。
  • 可能还需要Projectile
  • 添加,还添加了继承自弹丸的GameObject.java
  • 你在哪里画蓝色圆圈?

标签: java collision-detection bounding-box


【解决方案1】:

自从

Graphics.drawHollowCircle(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset(), hitBox.getRadius());

总是在底部画,这个

Graphics.drawHollowCircle(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset() / 2, hitBox.getRadius());

应该在中心画圆...然后使用一些三角函数来获得圆的中心,您必须执行以下操作:

float offsetX = Math.sin(location.getRotation()) * (hitBox.getYOffset() / 2);
float offsetY = Math.cos(location.getRotation()) * (hitBox.getYOffset() / 2);

Graphics.drawHollowCircle(location.getX() + offsetX, location.getY()  + offsetY, hitBox.getRadius());

假设location.getRotation() 将返回辐射点进行旋转

【讨论】:

  • 所以 hitbox.getxoffset 和 getyoffset 默认为 0。 location.getX 和 location.getY 已经知道圆的中心,所以使用它只是辐射旋转的 sin/cos?
  • 我添加了一张图片,其中包含我目前使用旋转的 cos 和 sin 得到的图像
  • @IcyRelic 返回什么location.getRotation()?我对Graphics.drawHollowCircle(location.getX() + hitBox.getXOffset(), location.getY() + hitBox.getYOffset() / 2, hitBox.getRadius());的目标是让蓝色圆圈画在图像的中心,你能确认一下吗?但是,坐标系统会根据渲染系统进行更改,因此这可能无法按预期工作,因此请确认使用该线(并且没有 sin/cos)蓝色圆圈位于所有图像的中心
  • 如果我移除 yOffset 以在底部绘制它,它已经在中心绘制。 x 和 y 是蓝色圆圈的中心。因此,您提供的偏移量只会撤消我放置的偏移量。我能够将圆置于几乎正确的位置,将 x 上的旋转罪数乘以 0.12f,y 上的旋转 cos 乘以 -0.12,其中一些取决于旋转,正好在它们应该在的位置和其他旋转有点偏离。
  • @IcyRelic 请立即尝试...如果不起作用,请使用Graphics.drawHollowCircle(location.getX(), location.getY(), hitBox.getRadius());发布图片
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 2014-11-18
  • 1970-01-01
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
相关资源
最近更新 更多