• 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!

GML Issue with Bullet Origin

D

Daniel Hall

Guest
Hi,

Im new to gamemaker, and followed the tutorial for making an asteroids clone in GML (From yoygames youtube channel).

Thats all fine, but I am now trying to edit it so that instead of a single bullet from the center of the spaceship, i want two bullets, one from each side (i created a sprite with two little guns). Ive tried figuring it out, and searching for solutions (I tried to just offset the 1 gun to start with). The below code does offset it, but the offset switches sides when rotating the ship.

The code I have for the bullet spawn (as a step event on the ship obj) is:

var _yy = y + lengthdir_y(20, image_angle);
var _xx = x - lengthdir_x(8, image_angle);
bullet1 = instance_create_layer(_xx, _yy, "Instances", obj_bullet)
bullet1.direction = image_angle;

Can anyone advise?

The example from the GML reference pages made it sound like it would work "This will create a bullet instance at (_xx, _yy), which will be 64 pixels from the parent instance in the direction of the image angle."

Im sure im just missing something stupid, enjoying my time with it though
 

CloseRange

Member
lengthdir_x and lengthdir_y when used together should generally use the exact same peramaters.
By that I mean not 20 in one and 8 in the other. And also don't add on one side and subtract on the other.

This code will do as you want when done correctly. Choose a direction and choose a distance from that direction.
in your case image_angle will make it move forward from the ship, so you want image_angle+90 to make it move right of the ship.
20 will make it 20 pixels to the right:
Code:
var _yy = y + lengthdir_y(20, image_angle+90);
var _xx = x + lengthdir_x(20, image_angle+90);
bullet1 = instance_create_layer(_xx, _yy, "Instances", obj_bullet)
bullet1.direction = image_angle;
 
Use of lengthdir is throwing all newbies off. I wish yoyo would never have included those functions.

My opinion is that this is far more straightforward:

Code:
    bullet_x = ship_x +  c * offset_x + s * offset_y
    bullet_y = ship_y + -s * offset_x + c * offset_y
c and s are the cosine and sine of the ship's angle. Use dcos and dsin, which take the angle argument in degrees.

offset_x and offset_y are the position of the gun relative to the ship's origin, (measured as if the ship was at zero rotation, and located at the world origin (0,0)).

If you have multiple guns, you can use an array to contain a number of offset positions, thus allowing you to fit the bullet creating code for all guns neatly within a loop. By the way, in that case, you can precalculate cosine and sine before the loop, saving you the extra cost of doing the function calls inside the loop.
 

CloseRange

Member
I actually don't agree with that. I started Game Maker when I was 10 and lengthdir was an amazing function for me as I didn't even know what a graph was.
Code:
    bullet_x = ship_x +  c * offset_x + s * offset_y
    bullet_y = ship_y + -s * offset_x + c * offset_y
that would have confused me beyond belief back then and lengthdir is a great way for people who arn't math savy to still be able to achieve angled offsets. Assuming they use it properly
 
D

Daniel Hall

Guest
Thanks guys, I managed to get it looking sort of ok with

Code:
    var _yy1 = y + lengthdir_y(8, image_angle+90);
    var _xx1 = x + lengthdir_x(8, image_angle+90);
    var _yy2 = y - lengthdir_y(8, image_angle+90);
    var _xx2 = x - lengthdir_x(8, image_angle+90);
    bullet1 = instance_create_layer(_xx1, _yy1, "Instances", obj_bullet)
    bullet1.direction = image_angle-1;
    bullet2 = instance_create_layer(_xx2, _yy2, "Instances", obj_bullet)
    bullet2.direction = image_angle+1;
Bullets now appear from the wing turrets, and look good even when rotating the ship :)
 
I actually don't agree with that. I started Game Maker when I was 10 and lengthdir was an amazing function for me as I didn't even know what a graph was.
Code:
    bullet_x = ship_x +  c * offset_x + s * offset_y
    bullet_y = ship_y + -s * offset_x + c * offset_y
that would have confused me beyond belief back then and lengthdir is a great way for people who arn't math savy to still be able to achieve angled offsets. Assuming they use it properly
New users never use lengthdir correctly to rotate a point, which makes it seem totally redundant to me.

Let me try at a concise explanation of what I posted. There are two vectors, (c,-s), which points in the direction of the (rotated) instance's x axis, and (s,c) which points in the direction of it's y axis. offset_x and offset_y are the coordinates of the gun as measured along the instnace's x and y axes. All that has to be done is to scale (c,-s) and (s,c) by offset_x and offset_y, respectively, and to add the results to the instance's world position. Once you memorize that, there's no reason that I can see to use lenthdir ever again, and you don't have to precalculate the distance and direction between sets of points. Well, those are my thoughts on the subject.
 
D

Daniel Hall

Guest
Thank you both,

I have gotten it working with both methods now, valuable learning experience for me.

The code for the cos,sin method I used was (in case anyone has the same question)

Code:
if(keyboard_check_pressed(vk_space)){
    audio_play_sound(pewpew, 1, false)

    c = dcos(image_angle);
    s = dsin(image_angle);
    offset_x = -1;
    offset_y = 15;
    offset_y2 = -15;
    bullet_x = obj_ship.x +  c * offset_x + s * offset_y
    bullet_y = obj_ship.y + -s * offset_x + c * offset_y
    bullet_x2 = obj_ship.x +  c * offset_x + s * offset_y2
    bullet_y2 = obj_ship.y + -s * offset_x + c * offset_y2
    bullet1 = instance_create_layer(bullet_x, bullet_y, "Instances", obj_bullet)
    bullet1.direction = image_angle-1;
    if global.pwruplvl >=1{
        bullet1.sprite_index = spr_bulletx   
    }
    bullet2 = instance_create_layer(bullet_x2, bullet_y2, "Instances", obj_bullet)
    bullet2.direction = image_angle+1;
    if global.pwruplvl >=1{
        //bullet2.sprite_index = spr_bulletx   
    }
}
 

Yal

šŸ§ *penguin noises*
GMC Elder
lengthdir_x / lengthdir_y are self-explanatory and abstracts away GM's inverted Y axis (which messes up a number of trig identities, especially when you start thinking about rotational matrices). I never use the normal trig functions, not even the dcos / dsin versions.
 
Top