Hey there, actually there is a way! When you draw a vertex in 3D space, it goes through series of matrix multiplications to calculate its position on screen, and this can be replicated!
The formula is simple:
Multiply your matrix_world, matrix_view and matrix_projection matrices (= MVP matrix):
Code:
var _world = matrix_get(matrix_world);
var _view = matrix_get(matrix_view);
var _projection = matrix_get(matrix_projection);
var _mvp = matrix_multiply(matrix_multiply(_world, _view), _projection);
Multiply MVP with vector [x, y, z, w], where x,y,z is position of the enemy in 3D space and w is 1:
Code:
var _enemyX = ...;
var _enemyY = ...;
var _enemyZ = ...;
var _enemyW = 1;
var _x = _mvp[ 1]*_enemyX + _mvp[ 5]*_enemyY + _mvp[ 9]*_enemyZ + _mvp[13]*_enemyW;
var _y = _mvp[ 2]*_enemyX + _mvp[ 6]*_enemyY + _mvp[10]*_enemyZ + _mvp[14]*_enemyW;
var _z = _mvp[ 3]*_enemyX + _mvp[ 7]*_enemyY + _mvp[11]*_enemyZ + _mvp[15]*_enemyW;
var _w = _mvp[ 0]*_enemyX + _mvp[ 4]*_enemyY + _mvp[ 8]*_enemyZ + _mvp[12]*_enemyW;
Divide x, y (and z) of the resulting vector by w of the resulting vector - this is called perspective division:
Code:
_x /= _w;
_y /= _w;
// _z =/ _w; // Not necessary for our purposes
X and Y are now values in range [-1,1], you want to get them into [0, 1]:
Code:
_x = _x * 0.5 + 0.5;
_y = _y * 0.5 + 0.5;
Also the coordinates are flipped vertically, fix that with:
Now you can scale the x coordinate from [0,1] range to [0,screenWidth] and y from [0,1] range to [0, screenHeight]:
Code:
_x *= window_get_width();
_y *= window_get_height();
And now x and y are the enemy's position on screen! Seems like a lot of code, but can be squished into two scripts really (
transform,
project). I don't remember any good learning resources on this topic, but you can try googling "world view projection matrix", "perspective projection", "clip space", "NDC space" and "linear algebra" in general. Good luck!
EDIT: Wrote this without any tests, if there are some errors, please let me know!