Вращение прямоугольника вокруг сетки для расчета игроков - PullRequest
2 голосов
/ 28 февраля 2012

У меня есть игрок, который может вращаться и перемещаться по двумерной декартовой сетке, мне нужно рассчитать, где нарисовать врагов на экране.

Игрок должен иметь определенную точку обзора, которая является размером экрана перед направлением, в котором находится игрок.(и немного позади)

Я испробовал множество способов реализовать эту путаницу с биполярными координатами и Trig, но мне не удалось решить проблему вычисления места на экране.враги должны быть нарисованы.

Проблема лучше всего представляется в виде графика, где зеленым цветом является точка обзора, представляющая собой прямоугольник, который может вращаться и перемещаться по сетке, и точками, представляющими игрока и врага.

Blue is player, Red is Enemy Green represents viewpoint

Поэтому мне нужно определить положение врагов на экране относительно поворота и положения игроков.

1 Ответ

2 голосов
/ 28 февраля 2012

Если вы собираетесь использовать Doom-подобную перспективу, вы должны представить область просмотра в виде параллелограмма, а не прямоугольника.Представьте, что за вашим персонажем стоит оператор с собственной позицией и углом.

The camera frustum

Позиция экрана противника связана с углом между камерой и противником.

//indicates where on the screen an enemy should be drawn.
//-1 represents the leftmost part of the screen, 
//and 1 is the rightmost.
//Anything larger or smaller is off the edge of the screen and should not be drawn.
float calculateXPosition(camera, enemy){
    //the camera man can see anything 30 degrees to the left or right of its line of sight. 
    //This number is arbitrary; adjust to your own tastes.
    frustumWidth = 60;

    //the angle between the enemy and the camera, in relation to the x axis.
    angle = atan2(enemy.y - camera.y, enemy.x - camera.x);

    //the angle of the enemy, in relation to the camera's line of sight. If the enemy is on-camera, this should be less than frustumWidth/2.
    objectiveAngle = camera.angle - angle;

    //scale down from [-frustumWidth/2, frustumWidth/2] to [-1, 1]
    return objectiveAngle / (frustrumWidth / 2);
}

На этих диаграммах показано, какие переменные, которые я здесь использую, представляют:

imageangle">

enter image description here

Как только вы получите«Положение X» в диапазоне [-1, 1], должно быть достаточно легко преобразовать это в пиксельные координаты.Например, если ваш экран имеет ширину 500 пикселей, вы можете сделать что-то вроде ((calculateXPosition(camera, enemy) + 1) / 2) * 500;

Edit:

Вы можете сделать что-то похожее, чтобы найти координату y точки, основываясь навысота точки и расстояние от камеры.(Я не уверен, как вы должны определить высоту противника и камеры - любое число должно быть в порядке, если оно в некоторой степени соответствует масштабу, установленному размерами x и y декартовой сетки.)

side view - camera looking at enemy

//this gives you a number between -1 and 1, just as calculateXPosition does.
//-1 is the bottom of the screen, 1 is the top.
float getYPosition(pointHeight, cameraHeight, distanceFromCamera){
    frustrumWidth = 60;
    relativeHeight = pointHeight - cameraHeight;
    angle = atan2(relativeHeight, distanceFromCamera);
    return angle / (frustrumWidth / 2);
}

enter image description here

Вы можете вызвать метод дважды, чтобы определить позицию y как верха, так и низа противника:

distanceFromCamera = sqrt((enemy.x - camera.x)^2 + (enemy.y - camera.y)^2);
topBoundary = convertToPixels(getYPosition(enemy.height, camera.height, distanceFromCamera));
bottomBoundary = convertToPixels(getYPosition(0, camera.height, distanceFromCamera));

Это должно дать вам достаточно информации, чтобы правильно масштабировать и позиционировать вражеский спрайт.

(в сторону: ширина frustrumWidth в обоих методах не обязательно должна быть одинаковой - на самом деле, они должны быть разными, если экран, на который вы рисуете, является прямоугольным. Соотношения x frustrum и y frustrumдолжно быть равно соотношению ширины и высоты экрана.)

...