Off-screen Enemy Indication

An arrow or indicator that shows the location of off-screen enemies which is around the edge of the camera.
I would like this to not be drawn, because I'd like to use an object for the indicator.

I have an object for this enemy, and there is only 1, but I think maybe solving the problem for multiple objects would help future people visiting this post. :)

All of the videos and forum posts I've seen are outdated.
If you need more info I'll be glad to provide!
 
Lets say your camera resolution is 480x270.

First, set the oIndicator x,y to the targeted enemy's x,y
GML:
oIndicator.x = oEnemy.x;
oIndicator.y = oEnemy.y;
Then you want to:
GML:
oIndicator.x = clamp(oIndicator.x, oPlayer.x-480/2, oPlayer.x+480/2);
oIndicator.y = clamp(oIndicator.y, oPlayer.y-270/2, oPlayer.y+270/2);
So you make sure the indicator is always inside the camera bounds. But you may also need to calculate the indicator margin so its not like half visible.

Rest is just pointing the image towards the enemy or how you'd like to do that part. If its just a simple arrow, then:
GML:
oIndicator.image_angle = point_direction(oPlayer.x, oPlayer.y, oTargetedEnemy.x, oTargetedEnemy.y);
Should do the trick. Make sure your arrow is pointing right (0 degree) on the sprite always.
 

chamaeleon

Member
Just using clamp individually on x and y can lead to a misleading directional indicator position. The cut-off need to be along the line towards the target, otherwise the visual marker will shift relative the actual direction, to an extent that depends on the amount that is clamped off for each axis.
 
No major issues arose, but sometimes the tracker would move off the enemy if the player was moving.

GML:
x = obj_enemy.x;
y = obj_enemy.y;

x = clamp(obj_enemy.x, obj_player.x-683/2, obj_player.x+683/2);
y = clamp(obj_enemy.y, obj_player.y-384/2, obj_player.y+384/2);

image_angle = point_direction(obj_player.x, obj_player.y, obj_enemy.x, obj_enemy.y);
638 is the x camera resolution and 384 is the y.

I found 2 improvements that could be made.
_________________________________________________
Simple: Is there a function that grabs the camera res so I could set it to a variable and not have to update this code every time I change camera resolution?
???: Up until the middle of the pointer object shows onscreen, the other half is hidden. Is there a way to fix this?
 

chamaeleon

Member
Assume for a moment that both x and y of the target are less than obj_player.x-683/2 and obj_player.y-683/2 respectively. The clamp() operation will make x be obj_player.x-683/2 and y be obj_player.y-683/2 regardless of what the target coordinates are as long as the condition I mentioned at the beginning is true.

For any position the target has (of which there are many for which my stated example constraint holds true, since it's an infinite area to the top-left of that corner point of your boundary), and how the visual indicator should be positioned to show in which direction it is, its position will remain the same because you clamp x and y to two specific values that does not depend on the target at all.

As long as the target in this case sticks in that area, the indicator will be stuck in the same corner position without moving, when it really should be moving along the sides of the imaginary boundary box for it, in the vicinity of the corner.
 
@chamaeleon I understand now. I am incorrect in saying that if there is a function to get the camera border x and y positions I could set a variable to that function and then use the clamp() function with that variable. Does such a function exist? What would that code look like?
 

FrostyCat

Redemption Seeker
The camera's borders can be found with the following:
The right edge can be found by adding x+width, and the bottom edge can be found by adding y+height.

Since you mentioned finding outdated resources, here is a correspondence table between legacy and current view region properties:
Pre-2.xPost-2.x
view_xview[N]camera_get_view_x(view_camera[N])
view_yview[N]camera_get_view_y(view_camera[N])
view_wview[N]camera_get_view_width(view_camera[N])
view_hview[N]camera_get_view_height(view_camera[N])
 
The camera's borders can be found with the following:
The right edge can be found by adding x+width, and the bottom edge can be found by adding y+height.

Since you mentioned finding outdated resources, here is a correspondence table between legacy and current view region properties:
Pre-2.xPost-2.x
view_xview[N]camera_get_view_x(view_camera[N])
view_yview[N]camera_get_view_y(view_camera[N])
view_wview[N]camera_get_view_width(view_camera[N])
view_hview[N]camera_get_view_height(view_camera[N])
Thanks this is exactly the function I needed! While it doesn't solve the problem, it expands my understanding, so thanks! :)
 

Slyddar

Member
This is outdated.
Like many older resources, you just need to convert it to GMS2.3 by placing it in a function wrapper. I use @YellowAfterlife 's script, and it does exactly what you are describing. Basically just create a pointer object and run this in the step event.
GML:
function point_to_edge(_sx, _sy, _tx, _ty, _inner, _pad) {
   
    //gets coordinates for drawing an arrow on the edge of the screen, pointing to a destination
    //https://yal.cc/gamemaker-pointing-to-an-off-screen-object/
   
    ///@sx        real    source x
    ///@sy        real    source y
    ///@tx        real    target x
    ///@ty        real    target y
    ///@inner    real    distance to goal under which the pointing object should start to fade out
    ///@pad        real    distance between pointing object and edge
   
    var _dx, _dy, _vx, _vy, _vl;
    //_sx = src.x; _sy = src.y // source position
    //_tx = dst.x; _ty = dst.y // destination position
    _dx = _tx - _sx; _dy = _ty - _sy // difference
    _vl = sqrt(_dx * _dx + _dy * _dy) // distance
    if (_vl != 0) {
        _vx = _dx / _vl; _vy = _dy / _vl
    } else {
        _vx = 0; _vy = 0;
    }
    if (_vl > _inner * 2) {
        _vl -= _inner
        image_alpha = 1
    } else {
        image_alpha = max(0, (_vl - _inner) / _inner)
        _vl /= 2
    }
    image_angle = point_direction(_sx, _sy, _tx, _ty)
    if (_vy < 0) {
        _vl = min(_vl, ((global.cy + _pad) - _sy) / _vy)
    } else if (_vy > 0) {
        _vl = min(_vl, ((global.cy + global.ch - _pad) - _sy) / _vy)
    }
    if (_vx < 0) {
        _vl = min(_vl, ((global.cx + _pad) - _sx) / _vx)
    } else if (_vx > 0) {
        _vl = min(_vl, ((global.cx + global.cw - _pad) - _sx) / _vx)
    }
    x = _sx + _vx * _vl
    y = _sy + _vy * _vl   
}
 
Last edited:
Top