Я хочу сделать модульную 2D игру на космическом корабле. Пользователь может использовать строительные блоки для создания корабля. Блоки могут быть квадратами, а также другими фигурами, которые не помещаются в сетку. Чтобы вычислить, какие двигатели должны запускаться с пользовательским вводом, я использую ojAlgo для решения задачи линейного программирования. Пользовательский ввод будет выглядеть примерно так: [x: 1, y: 0, z 0], где a 1 - максимальная тяга, которая может быть дана в направлении, и -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 двигателями это может быть выходом: </p>
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);
Не будет ограничивать уравнение соотношением x: y 1: 1, но найду наиболее выгодное решение. Я не могу использовать уровень здесь, потому что я не знаю максимальную тягу для обоих.
Что было бы лучшим способом ограничить 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: перенесено из 'Game Development', потому что реализация более общая, чем сценарий использования.