围绕网格旋转矩形以计算玩家视图

时间:2012-02-28 12:43:59

标签: math rotation trigonometry game-development cartesian

我有一个可以旋转并在2D笛卡尔网格中移动的玩家,我需要计算在屏幕上绘制敌人的位置。

玩家应具有某个视点,该视点是玩家所面向方向前的屏幕大小。 (稍微落后)

我已经尝试了很多方法来实现与Bi-Polar坐标和Trig的混乱,但是我无法解决计算屏幕上应该绘制敌人的位置的问题。

问题最好以图形的形式表示,绿色是一个可以围绕网格旋转和移动的矩形,以及代表玩家和敌人的点。

Blue is player, Red is Enemy Green represents viewpoint

所以我需要根据球员的旋转和位置计算出屏幕上敌人的位置。

1 个答案:

答案 0 :(得分:2)

如果您想要一个类似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);
}

这些图表可视化我在这里使用的变量代表什么:

depiction of <code>angle</code>

enter image description here

一旦你在[-1,1]范围内有一个“X位置”,它应该很容易将其转换为像素坐标。例如,如果您的屏幕宽度为500像素,则可以执行((calculateXPosition(camera, enemy) + 1) / 2) * 500;

之类的操作

编辑:

您可以执行类似的操作,根据点的高度和相机距离查找点的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));

这应该给你足够的信息来正确地缩放和定位敌人的精灵。

(除此之外:两种方法中的frustrumWidths不需要相同 - 实际上,如果您绘制的屏幕是矩形的,它们应该是不同的.x frustrum和y frustrum的比率应该相等到屏幕宽度和高度的比例。)