枪没有发射子弹

15

我只是为了好玩而制作了一个小游戏,但是在让子弹从枪中射出时卡住了。在下面的代码中,玩家的方向是一个名为rot的角度。

float gunOffsetX = 106, gunOffsetY = 96;
double angle = Math.toRadians(rot); // convert direction of player from degrees to radians for sin and cos
x = getX(); // player X
y = getY(); // player Y

float bulletX = (float) (x + (gunOffsetX * Math.cos(angle) - gunOffsetY * Math.sin(angle)));
float bulletY = (float) (y + (gunOffsetX * Math.sin(angle) + gunOffsetY * Math.cos(angle)));
            
Instances.fire.add(new Fire(bulletX, bulletY, rot, weapon));

还尝试过:

bulletX = (float) (x + Math.cos(angle + Math.atan2(gunOffsetX, gunOffsetY)) * Point2D.distance(0, 0, gunOffsetX, gunOffsetY));

但是结果相同

据说子弹应该在枪口处生成,但实际情况并非如此,可以在下面的gif中看到。

enter image description here

感谢任何帮助


3
你能把 10696 设为常量吗? - wake-0
1
当你不移动玩家时会发生什么? - wake-0
2
我假设你知道在Java中的坐标系统,0度面向东,180度面向西,270度面向北? - Ashwin Gupta
1
@DavidGomes 有两个问题。1)你是如何计算gunOffset变量的?(例如:0.5 * w?)2)你是否意味着在这里将gunOffsetX添加到Math.sin()中(y + (gunOffsetX * Math.sin(angle) - Ashwin Gupta
1
@DavidGomes 好的,等一下,我要尝试解决你的数学问题。但是我想非常清楚地知道:在你的坐标系中,0,0在哪里?在屏幕中心?左上角?右下角?此外,当你向南移动时,y是增加还是减少? - Ashwin Gupta
显示剩余18条评论
1个回答

13

我认为,这个游戏存在一个很大的问题,就是它如何处理形状的锚点,例如玩家。

我们可以通过在锚点位置上绘制一个小红色矩形来突出显示锚点:

g.setColor(Color.RED);
g.drawRect((int)player.getX() -5, (int)player.getY() -5, 10, 10);

这段代码出现在Draw#renderGame(Graphics2D)方法中,所以看起来像是:

private void renderGame(Graphics2D g) {
    g.rotate(Math.toRadians(player.rot), player.getX()+64, player.getY()+64);
    g.drawImage(player.getCurrentFrame(), (int)player.getX(), (int)player.getY(), player.getWidth(), player.getHeight(), null);
    g.setColor(Color.RED);
    g.drawRect((int)player.getX() -5, (int)player.getY() -5, 10, 10);
    g.rotate(-Math.toRadians(player.rot), player.getX()+64, player.getY()+64);
    //...

然后我们会发现锚点不在图像的中心:

带有锚点的图片

如您所见,锚点(旋转前的原始(0,0)点)不在图像的中心,十字准线与其相关,而非玩家视角。

这是由于玩家旋转时的移位操作导致的:

g.rotate(Math.toRadians(player.rot), player.getX()+64, player.getY()+64);
//...
g.rotate(-Math.toRadians(player.rot), player.getX()+64, player.getY()+64);

你正在使用 +64 来移动位置。我建议将其删除并在 g.drawImage 调用中添加移位,以便锚点正确位于中心(请注意,我避免了固定值 64):

g.rotate(Math.toRadians(player.rot), player.getX(), player.getY());
g.drawImage(player.getCurrentFrame(), (int)player.getX() - (player.getWidth() / 2), (int)player.getY() - (player.getHeight() / 2), player.getWidth(), player.getHeight(), null);
g.rotate(-Math.toRadians(player.rot), player.getX(), player.getY());

带有居中锚点的图像

如果你现在开枪,你会发现子弹总是从玩家的某个位置“开始”。问题在于你使用了错误的偏移量。正确的值为:

float gunOffsetX = 35, gunOffsetY = 29;

(我通过试错得到了它们,所以如果需要,您可以进一步调整它们)

现在它看起来像这样:

shot fired, still misplaced

正如您所看到的,子弹还是有点偏离目标,但这是由于子弹旋转不正确造成的(就像您对玩家形状所做的那样):

g.rotate(Math.toRadians(f.rot), f.getX()+f.getWidth()/2, f.getY()+f.getHeight()/2);
g.drawImage(f.img, (int)f.getX(), (int)f.getY(), f.getWidth(), f.getHeight(), null);
g.rotate(-Math.toRadians(f.rot), f.getX()+f.getWidth()/2, f.getY()+f.getHeight()/2);

它应该看起来像这样(没有任何XY的调整):

g.rotate(Math.toRadians(f.rot), f.getX(), f.getY());
g.drawImage(f.img, (int)f.getX(), (int)f.getY(), f.getWidth(), f.getHeight(), null);
g.rotate(-Math.toRadians(f.rot), f.getX(), f.getY());

最终结果是:

正确射击

现在玩家的准心正确对准了,子弹会落在枪口前面。


如果你想直接通过准心中心开火,你只需要微调一下玩家位置和子弹偏移量。

玩家(在Draw#renderGame(Graphics2D)中):

g.drawImage(player.getCurrentFrame(), (int)player.getX() - (player.getWidth() / 2), (int)player.getY() - (player.getHeight() / 2) - 30, player.getWidth(), player.getHeight(), null);

(请注意在 (int)player.getY() - (player.getHeight() / 2) - 30 中的 -30)

子弹:

float gunOffsetX = 35, gunOffsetY = 0;

现在子弹穿过了准心(请注意红色矩形正好在武器上方):

shot fired, bullet through crosshair

(我不太会制作合适的GIF文件,所以只能提供图片)


现在你有必要的偏移值来得到想要的结果,但你应该尝试理解为什么这些值现在是这样。之后你需要用动态值替换它们,因为不同的武器需要不同的子弹偏移量,由于玩家图像不同。拥有一些包含每种武器类型实例的类将非常有帮助,其中包含图像和武器枪管位于图像中的坐标。然后你可以使用这些坐标来正确地设置子弹图像的偏移量。


1
@DavidGomes 不用谢。别忘了读最后一段。这些常量偏移值会在你实现不同武器(计划在“Weapon”枚举中)时给你带来麻烦,所以尝试找到一种使用动态偏移而不是固定值的方法(它们与图像大小和图像中的枪管位置有关)。 - Tom
哦!你说得对!谢谢,伙计。顺便问一下,我不能只在枚举内部设置偏移量,并在每个武器构造函数中键入偏移量,然后在使用偏移量时只需使用“weapon.offsetX”吗? - David Gomes
1
@DavidKenz 是的,这也是可能的。以下是一个关于在枚举中定义用户变量的示例链接:https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html - Tom
1
是的,我知道,我也对火焰间隔做了同样的事情 :p 但还是非常感谢您的帮助! - David Gomes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接