我想制作一个模块化的2D飞船游戏。用户可以使用构建块来创建飞船。块可以是正方形,也可以是不适合网格的其他形状。为了计算应使用用户输入触发的推进器,我使用ojAlgo解决了线性编程问题。用户输入将类似于:[x:1,y:0,z 0]其中a是可以在方向上给出的最大推力,而-1在另一侧是相同的。 Z在这里旋转。
我有两个问题:
首先与我分别计算x和y的方式有关:
final ExpressionsBasedModel tmpModel = new ExpressionsBasedModel();
final Expression expressionX = tmpModel.addExpression("x").weight(1); //This is the user input.
final Expression expressionY = tmpModel.addExpression("y").weight(0).level(0); //Level means lower == 0 and upper == 0
final Expression expressionZ = tmpModel.addExpression("z").weight(0).level(0);
for (int i = 0; i < size; i++) {
ThrusterBlock thrusterBlock = blockStash.thrusterList.get(i);
final Variable thrusterVar = Variable.make("th_" + i);
thrusterVar.lower(0).upper(1);
tmpModel.addVariable(thrusterVar);
expressionX.setLinearFactor(thrusterVar, thrusterBlock.displacement.x);
expressionY.setLinearFactor(thrusterVar, thrusterBlock.displacement.y);
expressionZ.setLinearFactor(thrusterVar, thrusterBlock.displacement.z);
//The thruster displacement is the calculated thrust in the given direction
}
Optimisation.Result tmpResult = tmpModel.maximise(); //To get the maximum weight (& thrust) out.
这是可行的,因为我可以将权重设置为> 0或<0,并且它将为每个推进器返回0到1之间的值。如果布局中有9个推进器,则可能是输出:
OPTIMAL 1.203 @ [1.0, 1.0, 0.0, 0.0, 0.32, 0.32, 1.0, 1.0, 1.0]
[
0th [x: 0.401, y: 0.0 , z: -0.022]
1th [x: 0.401, y: 0.0 , z: -0.022]
2th [x: -0.401, y: 0.0 , z: -0.027]
3th [x: -0.401, y: 0.0 , z: -0.027]
4th [x: 0.0, y: 0.401 , z: 0.025]
5th [x: 0.0, y: -0.401 , z: 0.025]
6th [x: 0.0, y: -0.401 , z: 0.025]
7th [x: 0.0, y: 0.401 , z: 0.025]
8th [x: 0.401, y: 0.0 , z: -0.022]
]
问题是我不能使用该系统对角移动(例如40°),因为
final Expression expressionX = tmpModel.addExpression("x").weight(1);
final Expression expressionY = tmpModel.addExpression("y").weight(1);
不会将方程式约束为1:1的x和y比率,而是找到最有益的解决方案。我在这里不能使用水平,因为我不知道两者的最大推力。 约束x和y以便使用度数的最佳方法是什么?
第二个问题:
当我想让船转弯时,它会转大约45°,然后转回去。而控制系统显示相同的推进器正在点火。我确定我计算力的方式存在问题,但是我在角度计算方面的经验很低。我认为错误可以在这里找到:
public Vector2 getForce(float power, boolean relative){
float force = maxThrust * power;
float angle = toRad(this.relativePosition.z) + (relative ? 0 : this.blockCluster.getPos().z);
//relativePosition.z is the orientation of the block in degree and this.blockCluster.getPos().z is the ship rotation in radians
temp.x = force * ((float) Math.cos(angle)) * -1;
temp.y = force * ((float) Math.sin(angle));
return temp;
}
我认为这与余弦和正弦仅返回90°有关,但我不确定。
最后,任何优化都将受到赞赏,因为它可能会连续运行多个帧。如果计算速度较慢,我将保存计算结果。
感谢您的时间!
ps:从“游戏开发”移植,因为实现比用例更通用。