【发布时间】: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