• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

[SOLVED] Compass Pointing Towards Exit

Hey everyone! So I have yet another question. I'm prepping for a game jam by trying to figure out how to do things before actually making the game. I'm trying to implement a compass item that points towards the level exit.
When you pick up the item, it draws the compass in the GUI. The compass sprite has multiple frames, each pointing in a different direction, so I figured setting the image_speed to 0 and the image_index to whatever frame has the direction I want it to point, but that doesn't seem to work...

Here's the code for one of the inventory slots filled with a compass:

Code:
if (room != rm_win || room != rm_start) && (slotfull1 = true) && (compass1 = true) {
    draw_set_halign(fa_center);
    draw_set_valign(fa_bottom);
    draw_sprite(spr_compass_inventory, 600, 590, 950);
    if (obj_hero.x > instance_nearest(x, y, obj_exit_1).x) && (obj_hero.y < instance_nearest(x, y, obj_exit_1).y) {
        image_index = 3;
        image_speed = 0;
    }
    if (obj_hero.x < instance_nearest(x, y, obj_exit_1).x) && (obj_hero.y < instance_nearest(x, y, obj_exit_1).y) {
        image_index = 2;
        image_speed = 0;
    }
    if (obj_hero.x > instance_nearest(x, y, obj_exit_1).x) && (obj_hero.y > instance_nearest(x, y, obj_exit_1).y) {
        image_index = 0;
        image_speed = 0;
    }
    if (obj_hero.x < instance_nearest(x, y, obj_exit_1).x) && (obj_hero.y > instance_nearest(x, y, obj_exit_1).y) {
        image_index = 0;
        image_speed = 0;
    }
    if (obj_hero.x = instance_nearest(x, y, obj_exit_1).x) && (obj_hero.y > instance_nearest(x, y, obj_exit_1).y) {
        image_index = 0;
        image_speed = 0;
    }
    if (obj_hero.x = instance_nearest(x, y, obj_exit_1).x) && (obj_hero.y < instance_nearest(x, y, obj_exit_1).y) {
        image_index = 1;
        image_speed = 0;
    }
}
The inventory system works just fine, but I have no idea how to make the compass look like it's pointing towards the exit.
 
I

Insanebrio

Guest
The second argument of your draw sprite has 600 and not image_index, thats why it keeps the same image all the time. Also i would draw that sprite AFTER calculating which image index to use.
 
Another question. @Insanebrio I think it only calculates which image_index to use upon picking up the item, instead of how I want to use it where it updates every second or so to show the closest exit. How should I do that?
 

obscene

Member
Two severly important optimization tips. Your code is terribly inefficient (CPU-wise) and overly-complicated which makes it harder for you / us to edit.

First...

12 times you run the exact same code instance_nearest(x, y, obj_exit_1). That is a very heavy function. It takes GM a long time to do that 12 times. Your game will slow down if you do things like this.

You can do that ONE time and save the results to a variable...

var inst=instance_nearest(x, y, obj_exit_1);

And then from there you can do all the if y > inst.y and x < inst.x ... etc without having to repeat that calculation.


Second...

Even though you have saved a TON of resources now, it's still very expensive to refer to another instance's variable such as inst.x or inst.y. You don't want to do that over and over and over like you are doing because you are causing GM to have to look at that instance and get it's x and y, over and over. So again, look them up once and save those to variables.

var xx=inst.x;
var yy=inst.y;

And now make your comparisons to xx and yy instead.




Third...

Any time you are running muliple IF statements in a row, ask yourself if only ONE of the statements can be true or if multiple ones can.

Example:

if the sky is blue // yes it is
if the sky is green // If we already know the sky is blue, why are we asking it again???

That second IF is a waste, because we already knew the sky was blue.

So you do this instead....

if the sky is blue // yes it is
else if the sky is green // this line is skipped by GM



Fourth...

In every IF statement you run, image_speed is set to 0. So why not just set it to 0 to begin with and remove all those extra lines which make your code too messy and hard to follow.



There are more optimizations but that's enough for one post.

Sorry for the long post but hopefully you'll implement all these measures as it helps you make a smooth running game and it helps people on the forum understand your code and help you fix problems in it.
 

KhMaIBQ

Member
This compass problem can actually be solved using the functions point_direction and draw_sprite_ext.

point_direction(x1, y1, x2, y2)
draw_sprite_ext( sprite, subimg, x, y, xscale, yscale, rot, colour, alpha )

The compass object will use one sprite that is pointing to the right because rotation angle 0 starts to the right and rotates counter-clockwise as the angle increases. The function point_direction gets the angle between two points. In this case, one point is the player and the other point is the exit. We use draw_sprite_ext to draw the compass at a rotation angle. This allows you to point it in the direction you want without having to have a large load of sprites for the compass.

Assuming the following...
objPlayer = the player
objExit = the exit
sprCompassArrow = the sprite for the compass arrow

We can do the following...

Code:
// In the draw event for the compass or whatever is handling the compass
var tmpAngle = point_direction( objPlayer.x, objPlayer.y, objExit.x, objExit.y );
draw_sprite_ext( sprCompassArrow, 0, x, y, 1.0, 1.0, tmpAngle, c_white, 1.0 );
 
@KhMaIBQ unfortunately my compass isn't an arrow. It's a picture of a circular compass with multiple images that change the direction of the arrow withing the compass. Changing the angle would just turn the circular compass around, making it sideways and whatnot. So I need to change the image_index, not the angle
 
How many different directions can your compass point in? Also, I'm assuming the first sub image points directly to the right, and successive sub-images go counter-clockwise.
 
{UPDATE}

Okay, so I cleaned up the code a bit, though it's not perfect. @obscene thank you for the advice :)

@flyingsaucerinvasion It goes from north, south, east, and west. Clockwise probably would've been more logical, but it's easy for me to remember the directions in that order.

Okay so I set up an alarm, though I'm not sure I'm doing it correctly cause it doesn't seem to work yet.

Here's the code that's relevant:

Code:
compass1 = false;
compass2 = false;
compass3 = false;
compassdir1 = false;
compassdir2 = false;
compassdir3 = false;
compassdir4 = false;
compassdir5 = false;
compassdir6 = false;
alarm[0] = 30;

Code:
var inst = instance_nearest(x, y, obj_exit_1);

if (obj_hero.x > inst.x) && (obj_hero.y < inst.y) {
    compassdir1 = true;
    }
    else {
        if (obj_hero.x < inst.x) && (obj_hero.y < inst.y) {
            compassdir2 = true;
        }
        else {
            if (obj_hero.x > inst.x) && (obj_hero.y > inst.y) {
                compassdir3 = true;
            }
            else {
                    if (obj_hero.x < inst.x) && (obj_hero.y > inst.y) {
                    compassdir4 = true;
                }
                else {
                    if (obj_hero.x = inst.x) && (obj_hero.y > inst.y) {
                        compassdir5 = true;
                    }
                        else {
                            if (obj_hero.x = inst.x) && (obj_hero.y < inst.y) {
                                compassdir6 = true;
                    }
                }
            }
        }
    }
}

Code:
    if (room != rm_win || room != rm_start) && (slotfull1 = true) && (compass1 = true) {
        draw_set_halign(fa_center);
        draw_set_valign(fa_bottom);
        image_speed = 0;
        if compassdir1 = true {
            draw_sprite(spr_compass_inventory, image_index, 590, 950);
            image_index = 3;
        }
        else {
            if compassdir2 = true {
                draw_sprite(spr_compass_inventory, image_index, 590, 950);
                image_index = 2;
            }
            else {
                if compassdir3 = true {
                draw_sprite(spr_compass_inventory, image_index, 590, 950);
                image_index = 0;
            }
                else {
                    if compassdir4 = true {
                    draw_sprite(spr_compass_inventory, image_index, 590, 950);
                    image_index = 0;
                }
                    else {
                        if compassdir5 = true {
                        draw_sprite(spr_compass_inventory, image_index, 590, 950);
                        image_index = 0;
                    }
                        else {
                            if compassdir6 = true {
                            draw_sprite(spr_compass_inventory, image_index, 590, 950);
                            image_index = 1;
                        }

                        }
                    }
                }
            }
        }
    }

I decided to put the draw_sprite under each one since it seemed like the sprite was drawn and then the image_index couldn't be changed, but I don't know
 
If your compass can point in 4 different directions, and your sub-images are arranged in this order right = 0, up = 1, left = 2, down = 3. Then the entire code for selecting the compass sub-image can be condensed to just two lines.
Code:
    var _e = instance_nearest(obj_hero.x,obj_hero.y,obj_exit_1);
    if instance_exists(_e) {  image_index = round(point_direction(obj_hero.x,obj_hero.y,_e.x,_e.y) / 90) mod 4;  }
the first line gets the nearest exit to the hero object. (better make sure the hero object exists before running this code).
Then if a nearest exit exists, the compass sub-image is selected according the the direction from the hero object to the exit.
Note: the sub-images in the compass sprite must be arranged right, up, left, down, in that order.
instance_exists will protect you from a crash in case no instance of obj_exit could be found.
 
Top