TIGSource Forums

Developer => Technical => Topic started by: Siegfreide on October 14, 2013, 12:22:39 PM



Title: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: Siegfreide on October 14, 2013, 12:22:39 PM
I'm trying to code "move towards point" without using the actual GML function move_towards_point.
 
I'll post my attempt below. My current code makes the enemy move DIRECTLY diagonal if the player x,y is different than the enemy x,y, then upon reaching the same x or y, follows the player along the axis which values are different.

Basically, I want the enemy to make a straight line from its position to the player's position, and then follow that line if possible, else it should find the shortest route to take via pathfinding and follow that route.
 
Also, I'm having an issue of when the enemy finally does achieve the same x or y as the player, it begins to vibrate rapidly. for example, if the player/enemy x is the same, but the y is different the enemy will vibrate along the x axis as it moves towards the player's y.

Enemy STEP Code Below
Code:
////Collisions

//Player Collision
hit = instance_place(x,y,obj_player);

if timer_contactDamage=0
{
    if (hit != noone)
    {
        hit.hitpoints-=damage;
        with instance_create(obj_player.x,obj_player.y,obj_normalDamage)damage=other.damage;
        timer_contactDamage=30;
    }
}

//Horizontal Collision
if place_meeting(x+x_speed,y,par_wall)
{
    while (!place_meeting(x+sign(x_speed),y,par_wall)) x+=sign(x_speed);
    x_speed = 0;
}

//Vertical Collision
if place_meeting(x,y+y_speed,par_wall)
{
    while (!place_meeting(x,y+sign(y_speed),par_wall)) y+=sign(y_speed);
    y_speed = 0;
    grounded = false;
}
else
{
    grounded = true;
}

Code:
////Movement

//Commit to movement
x += x_speed;
y += y_speed;

//Create Gravity
//---Not Affected By Gravity---

//If hit by Player, Enemy is enraged and gives chase
if aggro=true
{
    if timer_aggro>0
    {
        timer_aggro-=1;
    }
    if timer_aggro=0
    {
        aggro=false;
        timer_aggro=150;
    }
    if in_minRange=true
    {
        if obj_player.x = x
        {
            x_speed=0;
        }
        if obj_player.x > x
        {
            if obj_player.x < x+5
            {
                x_speed = sign(5)
            }
            else x_speed = 5;
            
        }
        if obj_player.x < x
        {
            if obj_player.x > x-5
            {
                x_speed = -sign(5)
            }
            else x_speed = -5;
            
        }
        if obj_player.y = y
        {
            y_speed=0;
        }
        if obj_player.y > y
        {
            if obj_player.y < y+5
            {
                y_speed = sign(5)
            }
            else y_speed = 5;
            
        }
        if obj_player.y < y
        {
            if obj_player.y > y-5
            {
                y_speed = -sign(5)
            }
            else y_speed = -5;
            
        }
    }
}

//If following, move towards player
if aggro=false
{
    if following=true && in_minRange=true
    {
        if obj_player.x > x
        {
            x_speed = 4;
        }
        if obj_player.x < x
        {
            x_speed = -4;
        }
        if obj_player.y > y
        {
            y_speed = 4;
        }
        if obj_player.y < y
        {
            y_speed = -4;
        }
    }
    else if following=true && in_minRange=false
    {
        x_speed=0;
        y_speed=0;
    }
    else if following=true && timer_follow=1
    {
        x_speed=0;
        y_speed=0;
    }
}

//Idle Movement
x_move = choose('left','right','stop')
y_move = choose('up','down','stop')

if in_maxRange=false && following=false
{
    if timer_idleMovement=0
    {
        if x_move = 'left'
        {
            x_speed = -(random(3));
        }
        if x_move = 'right'
        {
            x_speed = (random(3));
        }
        if x_move = 'stop'
        {
            x_speed = 0;
        }
        if y_move = 'up'
        {
            y_speed = -(random(3));
        }
        if y_move = 'down'
        {
            y_speed = (random(3));
        }
        if y_move = 'stop'
        {
            y_speed = 0;
        }
        timer_idleMovement=choose(30,45,60,75);
    }
}


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: soryy708 on October 15, 2013, 02:44:53 AM
Calculate which direction you need to take using trigonometry,
multiply the result by velocity and add to x and y co-ordinates.

About the vibration: Add a minimum radius within which the enemy won't try to follow the player.


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: bateleur on October 15, 2013, 05:00:52 AM
Calculate which direction you need to take using trigonometry

Sometimes you don't even need to do that.

I normally code it like this (pseudocode, because I don't speak GML):

Code:
dx = playerX - enemyX;
dy = playerY - enemyY;
distance = square_root(dx*dx + dy*dy);
if (distance > 0) {
 dx = dx * enemy_speed / distance;
 dy = dy * enemy_speed / distance;
}
move_enemy_by(dx,dy);


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: Siegfreide on October 15, 2013, 03:12:19 PM
I appreciate the effort put forward to help me from both of y'all, but I actually already figured it out. Just to entertain my curiosity, I tried using the method bateleur suggested, and it seems to good just fine. Thanks for the suggestions!


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: ekun on October 16, 2013, 01:20:52 AM
Calculate which direction you need to take using trigonometry

Sometimes you don't even need to do that.

I normally code it like this (pseudocode, because I don't speak GML):

Code:
dx = playerX - enemyX;
dy = playerY - enemyY;
distance = square_root(dx*dx + dy*dy);
if (distance > 0) {
 dx = dx * enemy_speed / distance;
 dy = dy * enemy_speed / distance;
}
move_enemy_by(dx,dy);

That's an interesting way to do it!

I wonder if that's less efficient than using trig though? That sqrt can be pretty expensive.

Trig pseudocode:
Code:
angle = atan2(target.y - this.y, target.x - this.x);
dx = cos(angle) * speed;
dy = sin(angle) * speed;
move(dx, dy);


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: BorisTheBrave on October 16, 2013, 11:33:41 AM
I wonder if that's less efficient than using trig though? That sqrt can be pretty expensive.
lol. Just... no.


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: ThemsAllTook on October 16, 2013, 11:45:58 AM
I wonder if that's less efficient than using trig though? That sqrt can be pretty expensive.
lol. Just... no.

To be a bit more helpful: sqrt is pretty fast on modern CPUs. Assuming GML doesn't do anything weird and uses the hardware correctly, it's not likely to be slower than any of sin(), cos(), or atan2(), so the trig solution is presumably takes at least 3 times as long. If you're not sure, profile and see which performs better. That said, unless you're doing it quite a lot of times per frame, neither is likely to be a performance bottleneck.


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: ekun on October 16, 2013, 12:44:13 PM
I wonder if that's less efficient than using trig though? That sqrt can be pretty expensive.
lol. Just... no.

???

No need to be so dismissive, Boris. I said "I wonder" because I really didn't know, I just wanted to provide the trig implementation.


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: BorisTheBrave on October 16, 2013, 01:20:07 PM
I just wanted to provide the trig implementation.
I know. I was laughing at the disingenuity of your statement when you clearly knew or had capacity to reason which was faster, you just wanted your 2 cents thrown in. Hence why I felt no explanation was really necessary.

Anyway, no offence intended, just rumpled feathers.

To repeat a spiel I have given several times in the past, the vector approach (bateleur's) is superior in pretty much every respect. It's well worth game developers times learning it, and moving on from trig, which is relatively rarely useful in comparison. Once understood, vectors are actually conceptually simpler, faster and more flexible.

This tutorial (http://docs.yoyogames.com/source/dadiospice/002_reference/maths/vector%20functions/index.html) seems to cover the basics from a GM specific direction, so might be good for you if you'd like to know more. Sadly GM doesn't treat vectors as first class objects, or else they'd be even nicer to use.



Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: ekun on October 16, 2013, 02:04:57 PM
I just wanted to provide the trig implementation.
I know. I was laughing at the disingenuity of your statement when you clearly knew or had capacity to reason which was faster, you just wanted your 2 cents thrown in. Hence why I felt no explanation was really necessary.

Anyway, no offence intended, just rumpled feathers.

To repeat a spiel I have given several times in the past, the vector approach (bateleur's) is superior in pretty much every respect. It's well worth game developers times learning it, and moving on from trig, which is relatively rarely useful in comparison. Once understood, vectors are actually conceptually simpler, faster and more flexible.

This tutorial (http://docs.yoyogames.com/source/dadiospice/002_reference/maths/vector%20functions/index.html) seems to cover the basics from a GM specific direction, so might be good for you if you'd like to know more. Sadly GM doesn't treat vectors as first class objects, or else they'd be even nicer to use.

I don't know why you think I'm being disingenuous; at the time of answering I believed the trig method was faster. After doing a bit of research now on the implementations of the functions, I realize now that I'm wrong.

Anyways, I find the trig method useful still. A lot of times, you need the angle in order to, say, rotate a sprite in the direction it's moving.



As a side note, whenever you find yourself saying "no offence intended" or "no offense", usually you'll find that you really mean the exact opposite. No offense.


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: BorisTheBrave on October 17, 2013, 02:03:13 PM
A lot of times, you need the angle in order to, say, rotate a sprite in the direction it's moving.
See, this is what is interesting. You don't need the angle to rotate a sprite. No graphics cards works with angles at all. You only see angles because some other developer has decided it would be "easier" to deal with. It's a limitation of crappy tools like GM, not a fundamental thing.


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: ekun on October 17, 2013, 05:03:47 PM
See, this is what is interesting. You don't need the angle to rotate a sprite. No graphics cards works with angles at all. You only see angles because some other developer has decided it would be "easier" to deal with. It's a limitation of crappy tools like GM, not a fundamental thing.

How would you rotate a sprite without using angles?

I don't use Game Maker, but I wouldn't go so far as to call it a crappy tool. I've seen some really cool stuff come from people who use it.


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: BorisTheBrave on October 18, 2013, 12:29:38 PM
Let's not get into the absolute value of GameMaker. There's lots of impressive stuff coming out of it.

But it is hiding how your computer handles things for an, in this case misguided, attempt at simplicity.

Essentially, there are objects called matrices that work with vectors, that very efficiently represent any linear transformation. A matrix rotation works with only multiplication and addition, which is much faster than any trigonometric functions. Vectors are used to represent position and velocity, while a single matrix can simultaneously represent offsetting a sprite, rotating it, scaling it and more.

On a lower level, e.g. your graphics card or physics engine, they underpin everything, and as such are usually made available for programmers to use as well.

Like vectors, they are not very complicated once understood - easier than learning the corresponding trig.

Not that I mean to say angles are useless, just that there is this great tool that is more often than not the better choice, locked off from all GM users by awful support.


Title: Re: Is There A Way To Manually Code "Move_Towards_Point"?
Post by: ekun on October 18, 2013, 03:12:18 PM
Let's not get into the absolute value of GameMaker. There's lots of impressive stuff coming out of it.

But it is hiding how your computer handles things for an, in this case misguided, attempt at simplicity.

Essentially, there are objects called matrices that work with vectors, that very efficiently represent any linear transformation. A matrix rotation works with only multiplication and addition, which is much faster than any trigonometric functions. Vectors are used to represent position and velocity, while a single matrix can simultaneously represent offsetting a sprite, rotating it, scaling it and more.

On a lower level, e.g. your graphics card or physics engine, they underpin everything, and as such are usually made available for programmers to use as well.

Like vectors, they are not very complicated once understood - easier than learning the corresponding trig.

Not that I mean to say angles are useless, just that there is this great tool that is more often than not the better choice, locked off from all GM users by awful support.

I see.  :)