基于物理的 2D 运动:随时间改变物体的方向
Physics based 2D movement: Changing direction of an object over time
我目前正在 Java 中创建一个 2D space 游戏,你可以在 space 中控制一艘船。
游戏不使用任何外部库。
飞船应该向光标移动。但是,当移动光标时,旧势力并没有神奇地消失;随着时间的推移,这艘船改变了它的航向,最终朝着期望的方向移动。
但是,我 运行 遇到了关于船舶移动的问题。
基本上,我想要实现的是这张图片粗略地说明:
图像显示了在一个游戏刻度内飞船应该如何移动。
进一步解释:
船的最大速度用圆圈表示。
目标角度是光标当前所在的位置。
当前角度是船当前行驶的方向。
当前角度应该越来越接近目标角度,直到到达这两个角度相同的点。
船应该以最短的路线向目标角度改变方向;它可以左右转动,而不仅仅是左转或右转。
现在我已经解释了我想要实现的目标,现在我将描述我到目前为止已经实现的目标以及它是如何工作的。
基本上,"ship" 是一个位于屏幕中央的图像。当你 "move" 船时,船留在原地;移动的是游戏区的其余部分。
飞船当前"position"相对于代表游玩区域的坐标系为整数xPos和yPos
现在看一些示例代码,说明系统如何工作:
int xPos;
int yPos;
public void updateMovement() {
xPos += xSpeed;
yPos += ySpeed;
}
public void moveForward() {
double yTempSpeed = ySpeed;
double xTempSpeed = xSpeed;
yTempSpeed += 0.01 * Math.sin(Math.toRadians(targetAngle));
xTempSpeed += 0.01 * Math.cos(Math.toRadians(targetAngle));
double resultVector = Math.sqrt(xTempSpeed * xTempSpeed + yTempSpeed * yTempSpeed);
if (resultVector < 2) {
ySpeed += 0.01 * Math.sin(Math.toRadians(targetAngle));
xSpeed += 0.01 * Math.cos(Math.toRadians(targetAngle));
}
此代码成功将船舶的最大速度设置为所需值,但是,如果结果 "vector" 大于 2,即,这不起作用(船舶的航向不会改变),即当速度已经达到最大值并且 targetAngle 太接近船只当前行驶的角度时 (+- Pi / 2)。
我将如何根据此实现更改当前角度?
public void moveForward() {
ySpeed += 0.01 * Math.sin(Math.toRadians(targetAngle));
xSpeed += 0.01 * Math.cos(Math.toRadians(targetAngle));
double currentSpeed = Math.sqrt(xTempSpeed * xTempSpeed + yTempSpeed * yTempSpeed);
if (currentSpeed > maxSpeed) {
//the resulting speed is allways <= maxspeed (normed to that)
ySpeed *= maxSpeed/currentSpeed;
xSpeed *= maxSpeed/currentSpeed;
}
希望这就是您所需要的...虽然这很不现实,但航天器具有最大速度,但就 "playability" 而言,我也会这样做。
如何使船速正常化,而不是让它实际超过您的速度限制 (=2):
//it's good to put all constants out of a function in one place
//to make it easier if you ever wanted to change it
private final int MAX_SPEED = 2;
private final double ACCEL_FACTOR = 0.01;
public void moveForward() {
ySpeed += ACCEL_FACTOR * Math.sin(Math.toRadians(targetAngle));
xSpeed += ACCEL_FACTOR * Math.cos(Math.toRadians(targetAngle));
//normalize ship speed, i.e. preserve ratio of xSpeed/ySpeed
//but make sure that xSpeed^2 + ySpeed^2 <= MAX_SPEED^2
//your code goes here
//...
}
阅读有关向量归一化的内容。这样,船速的变化将正常应用(此时速度可以>=MAX_SPEED),但在归一化后它永远不会大于MAX_SPEED,所以你的 if 甚至不需要指令。
您可能会发现以下 (Swift) 代码很有用,尽管您需要自己处理飞船线性速度和 angular 速度的每帧积分:
func moveShipTowards(location: CGPoint) {
if let ship = shipNode? {
let distanceVector = CGVector(origin: ship.position, point: location)
let targetAngle = distanceVector.angle
let shipAngle = ship.zRotation
var dø = targetAngle - shipAngle
// convert to shortest arc
if dø > π {
dø -= 2.0 * π
} else if dø < -π {
dø += 2.0 * π
}
// resulting angular velocity
ship.physicsBody.angularVelocity = 12 * dø.clampedTo(π)
var velocityUnitVector = CGVector(cosf(ship.zRotation), sinf(ship.zRotation))
var magnitude = distanceVector.length.clampedTo(400)
ship.physicsBody.velocity = velocityUnitVector * magnitude
}
}
它处理让飞船在接近目标点时减速。刚才看了一下,不过似乎没有正确处理加速。
我目前正在 Java 中创建一个 2D space 游戏,你可以在 space 中控制一艘船。 游戏不使用任何外部库。
飞船应该向光标移动。但是,当移动光标时,旧势力并没有神奇地消失;随着时间的推移,这艘船改变了它的航向,最终朝着期望的方向移动。
但是,我 运行 遇到了关于船舶移动的问题。 基本上,我想要实现的是这张图片粗略地说明:
图像显示了在一个游戏刻度内飞船应该如何移动。 进一步解释:
船的最大速度用圆圈表示。
目标角度是光标当前所在的位置。
当前角度是船当前行驶的方向。
当前角度应该越来越接近目标角度,直到到达这两个角度相同的点。
船应该以最短的路线向目标角度改变方向;它可以左右转动,而不仅仅是左转或右转。
现在我已经解释了我想要实现的目标,现在我将描述我到目前为止已经实现的目标以及它是如何工作的。
基本上,"ship" 是一个位于屏幕中央的图像。当你 "move" 船时,船留在原地;移动的是游戏区的其余部分。
飞船当前"position"相对于代表游玩区域的坐标系为整数xPos和yPos
现在看一些示例代码,说明系统如何工作:
int xPos;
int yPos;
public void updateMovement() {
xPos += xSpeed;
yPos += ySpeed;
}
public void moveForward() {
double yTempSpeed = ySpeed;
double xTempSpeed = xSpeed;
yTempSpeed += 0.01 * Math.sin(Math.toRadians(targetAngle));
xTempSpeed += 0.01 * Math.cos(Math.toRadians(targetAngle));
double resultVector = Math.sqrt(xTempSpeed * xTempSpeed + yTempSpeed * yTempSpeed);
if (resultVector < 2) {
ySpeed += 0.01 * Math.sin(Math.toRadians(targetAngle));
xSpeed += 0.01 * Math.cos(Math.toRadians(targetAngle));
}
此代码成功将船舶的最大速度设置为所需值,但是,如果结果 "vector" 大于 2,即,这不起作用(船舶的航向不会改变),即当速度已经达到最大值并且 targetAngle 太接近船只当前行驶的角度时 (+- Pi / 2)。
我将如何根据此实现更改当前角度?
public void moveForward() {
ySpeed += 0.01 * Math.sin(Math.toRadians(targetAngle));
xSpeed += 0.01 * Math.cos(Math.toRadians(targetAngle));
double currentSpeed = Math.sqrt(xTempSpeed * xTempSpeed + yTempSpeed * yTempSpeed);
if (currentSpeed > maxSpeed) {
//the resulting speed is allways <= maxspeed (normed to that)
ySpeed *= maxSpeed/currentSpeed;
xSpeed *= maxSpeed/currentSpeed;
}
希望这就是您所需要的...虽然这很不现实,但航天器具有最大速度,但就 "playability" 而言,我也会这样做。
如何使船速正常化,而不是让它实际超过您的速度限制 (=2):
//it's good to put all constants out of a function in one place
//to make it easier if you ever wanted to change it
private final int MAX_SPEED = 2;
private final double ACCEL_FACTOR = 0.01;
public void moveForward() {
ySpeed += ACCEL_FACTOR * Math.sin(Math.toRadians(targetAngle));
xSpeed += ACCEL_FACTOR * Math.cos(Math.toRadians(targetAngle));
//normalize ship speed, i.e. preserve ratio of xSpeed/ySpeed
//but make sure that xSpeed^2 + ySpeed^2 <= MAX_SPEED^2
//your code goes here
//...
}
阅读有关向量归一化的内容。这样,船速的变化将正常应用(此时速度可以>=MAX_SPEED),但在归一化后它永远不会大于MAX_SPEED,所以你的 if 甚至不需要指令。
您可能会发现以下 (Swift) 代码很有用,尽管您需要自己处理飞船线性速度和 angular 速度的每帧积分:
func moveShipTowards(location: CGPoint) {
if let ship = shipNode? {
let distanceVector = CGVector(origin: ship.position, point: location)
let targetAngle = distanceVector.angle
let shipAngle = ship.zRotation
var dø = targetAngle - shipAngle
// convert to shortest arc
if dø > π {
dø -= 2.0 * π
} else if dø < -π {
dø += 2.0 * π
}
// resulting angular velocity
ship.physicsBody.angularVelocity = 12 * dø.clampedTo(π)
var velocityUnitVector = CGVector(cosf(ship.zRotation), sinf(ship.zRotation))
var magnitude = distanceVector.length.clampedTo(400)
ship.physicsBody.velocity = velocityUnitVector * magnitude
}
}
它处理让飞船在接近目标点时减速。刚才看了一下,不过似乎没有正确处理加速。