GML Is this logic sound?

NeilC

Member
Hey guys,

I'm new to GameMaker and game logic so having to take a guess on best practices without knowing what commands might solve my problem. This technically works but I'd be grateful if any of you could tell me if this is the wrong way of doing things - it would help me greatly in validating my progress.

So, I want my player to appear where I touch the screen (or in this test, click the LMB) and while I continue to hold the LMB, the player follows the cursor and fires bullets. My logic is that I'll only enable ship collision when the ship is visible.

Is this approach acceptable or should I be only creating the ship on LMB? If this alpha 'hack' is a bad practice, could anyone point out which command(s) I should be using to enable/disable the ship on LMB? I just can't find/see/figure out an alternative.

Thanks in advance!
Neil

This is in the Create event:
Code:
fireTimer = 0

fireRate = room_speed/10
This is the the Step event:
Code:
fireTimer += 1

// Draw the player at the mouse coordinate when they click the mouse
image_alpha = 0;

if (mouse_check_button(mb_left)) {
    x = mouse_x;
    y = mouse_y;
    image_alpha = 1;
};


// Fire a bullet if the mouse button is pressed but only at a predetermined firing rate
if (mouse_check_button(mb_left)) and (fireTimer mod fireRate == 0) {
    var inst = instance_create_layer(x,y, "Instances", obj_bullet);
    inst.direction = 90;
    audio_play_sound(snd_zap, 1, false);
};
 

Binsk

Member
If you're new to programming then you will quickly learn:
The only 'wrong ways' that exist are ones that don't work.

If it works then it's a right way to do it. The only difference between various functional methods of doing something is the efficiency which, in your case, is a non issue. So no, your method is perfectly fine.
 

devKathy

Member
For the sake of argument, let's say you have two algorithms that do the same job. One will take x^n operations to do it, and the other will take n^2 operations, where n is the number of items of data (or inputs) to be operated on and/or read.

Let's also say that the slower (x^n) algorithm will be faster for a person to code and get working.

If you know n isn't gonna get that big, maybe it's okay to use the slow one, provided you have fast enough hardware. If n could get really big, so big that your hardware can't make up for its bigness, then yeah, it's a bad idea to just use whatever algorithms "work" for smaller cases.

Other instances of things working but not necessarily being the best approach include - using a global variable that more than one object can modify, leading to race conditions.

I wouldn't say there's anything wrong with this approach; in fact, to use the alpha variable in this situation potentially eliminates having to use a flag (Boolean variable), or something like that later on. However, I'm glad you're asking about best practices. Continuing to investigate what these are with respect to GM will be a valuable time saver for you.

We'll wait to see if anyone has a better approach, which I'm not ruling out.
 

NeilC

Member
Thank you both for your replies. It's great to hear that I've not done anything stupid. I guess I'm at a point in my development where bad habits can stick and I'd like to avoid that where I can.
 

FrostyCat

Member
There is actually a quite serious problem with the logic behind the code if you extrapolate to other configurations.

Look what happens if you change fireRate to something like room_speed/7 or any other fractional value that won't arrive perfectly on an integer when added repeatedly. Expecting numeric perfection in "crossing-the-line" behaviours is a common rookie habit that needs to be weeded out early, and I've written about this before in posts like this and this.

When implementing boundary line conditions, always check an entire side of the line, never just the line itself.
Code:
if (fireTimer >= fireRate && mouse_check_button(mb_left))  {
  fireTimer -= fireRate;
  with (instance_create_layer(x,y, "Instances", obj_bullet)) {
    direction = 90;
  }
  audio_play_sound(snd_zap, 1, false);
}
 

NeilC

Member
Thanks for your insight @FrostyCat. I understand that the 'crossing the line check' is critical for creating robust collisions but I'm afraid I don't understand the benefit in this particular example, where you wouldn't intentionally divide the room_speed by anything other than a divisible number. I did try to run the code as written but it doesn't draw anything - all I get is the sound (which sounds like it's playing every frame).

What have I missed?
 

devKathy

Member
D'oh! I missed that double equals sign.

Anyway, I have an idea of what he means. If you aren't using an integer as the base for your modulo operator, that's going to be an issue. Shouldn't compile if I'm reading the manual right:

https://docs2.yoyogames.com/index.html?page=source/_build/index.html

In other words, you've gotta ensure that you aren't doing things that could cause sudden and difficult to find errors. If a function or operator needs an integer, you should try to make sure the thing you're giving it is an integer. Same for strings, floats, etc. Cleaner that way. Easy to forget when I primarily use languages that enforce this.

EDIT: Not sure if my answer is clear. If you use the result of a division as the base of a modulo, it is conceivable that eventually you could have a float in that base, which is undesirable.

Like 4/7 is not a pretty number.
 
Last edited:

NeilC

Member
Thanks @devKathy - I totally get that. From what I've read, I'm using the modulo to check if the result of the timer is even - because I don't want to be firing a bullet every frame. This seemed to be better than using an alarm.

If I do get a 'weird' number, the only negative is the firing pattern up the screen isn't evenly spaced. I've set the number specifically to give me the firing pattern I want (which also looks nice and regular).

I suspect that when the game drops frames, I'll see the undesirable irregular pattern but then again, the entire game will suffer equally badly when this happens.

Anyway, I'm now using <=.

Thanks again everyone - the conversation is really useful to me! :)
 
Top