Если вы собираетесь использовать Doom-подобную перспективу, вы должны представить область просмотра в виде параллелограмма, а не прямоугольника.Представьте, что за вашим персонажем стоит оператор с собственной позицией и углом.
![The camera frustum](https://i.stack.imgur.com/JmTlP.png)
Позиция экрана противника связана с углом между камерой и противником.
//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);
}
На этих диаграммах показано, какие переменные, которые я здесь использую, представляют:
angle">
![enter image description here](https://i.stack.imgur.com/NTG5I.png)
Как только вы получите«Положение X» в диапазоне [-1, 1], должно быть достаточно легко преобразовать это в пиксельные координаты.Например, если ваш экран имеет ширину 500 пикселей, вы можете сделать что-то вроде ((calculateXPosition(camera, enemy) + 1) / 2) * 500;
Edit:
Вы можете сделать что-то похожее, чтобы найти координату y точки, основываясь навысота точки и расстояние от камеры.(Я не уверен, как вы должны определить высоту противника и камеры - любое число должно быть в порядке, если оно в некоторой степени соответствует масштабу, установленному размерами x и y декартовой сетки.)
![side view - camera looking at enemy](https://i.stack.imgur.com/axzTw.png)
//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](https://i.stack.imgur.com/LQnCx.png)
Вы можете вызвать метод дважды, чтобы определить позицию 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должно быть равно соотношению ширины и высоты экрана.)