如何根据旋转偏移边界圆?
Posted
技术标签:
【中文标题】如何根据旋转偏移边界圆?【英文标题】: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
你在哪里画蓝色圆圈?
【参考方案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());
发布图片以上是关于如何根据旋转偏移边界圆?的主要内容,如果未能解决你的问题,请参考以下文章
Python习题:给定一个字符串和一个偏移量,根据偏移量旋转字符串(从左向右旋转)。例:输入: str="abcdefg", offset = 3 输出: "efgab