Making the player shoot at cursor

Kyndle

Member
So I want to have the player shoot where the cursor is on the screen, I have a global mouse left down event from an online tutorial
GML:
attack_cooldown +=1;
if(attack_cooldown >=10){
    bullet = instance_create_layer(x+33,y+8, "Effect", obj_bullet);
    bullet.speed = 13;
    bullet.direction= point_direction(x+33,y+8, mouse_x, mouse_y);
    bullet.image_angle = bullet.direction;
    attack_cooldown = 0;
}
I added attack cooldown so it doesn't just keep shooting
I want to make it so the player sprites arms move with the gun thingy, and make the bullets come out of the barrel of the gun. I don't think you can just change the sprite or it would be way too tedious, so I have another armless sprite for when the mouse left click is pressed down, and I have the arms as a seperate object, it basically only has this in step event.image_angle = point_direction(x, y, mouse_x, mouse_y);.

So to spawn the arms I have
GML:
if(mouse_check_button(mb_left)){
    sprite_index = spr_player_attack;
    instance_create_layer(x+24,y+16,"Player", obj_player_arms);
}
But once the arms spawn it doesn't go away, I want them to appear when the player is attacking(holding down left mouse button) only once, and go away once the player stops holding down the button.
Also the bullets desync if the player isn't shooting straight ahead of them, they start spawning out of nowhere. Is there a better way to do this?

So the player presses left mouse click, and the character shoots where the cursor is, their arms pointing the cursor. I also want the sprite to turn around as well as the arms if the cursor is behind the player, so the arm doesn't look like it's bending backwards.
 

ophelius

Member
First, you probably don't want a million instances of your arm being created. Your code at the bottom of your post is creating 1 instance per frame. You probably can't see them because they're on top of each other.
So check if it doesn't exist first, and destroy it if the mouse isn't pressed and the arm exists:
Code:
if(mouse_check_button(mb_left)){
    //only create 1 arm if it doesn't exist
     if( !instance_exists(obj_player_arms)){
          sprite_index = spr_player_attack;
          instance_create_layer(x+24,y+16,"Player", obj_player_arms);
    }
}else{
   //if mouse not held, check if arm exists. If it does, destroy it
    if(instance_exists(obj_player_arms)
        instance_destroy(obj_player_arms)
   //reset your sprites here
}
This is untested
Try this and let me know.
 
Last edited:

Kyndle

Member
First, you probably don't want a million instances of your arm being created. Your code at the bottom of your post is creating 1 instance per frame. You probably can't see them because they're on top of each other.
So check if it doesn't exist first, and destroy it if the mouse isn't pressed and the arm exists:
Code:
if(mouse_check_button(mb_left)){
    //only create 1 arm if it doesn't exist
     if( !instance_exists(obj_player_arms)){
          sprite_index = spr_player_attack;
          instance_create_layer(x+24,y+16,"Player", obj_player_arms);
    }
}else{
   //if mouse not held, check if arm exists. If it does, destroy it
    if(instance_exists(obj_player_arms)
        instance_destroy(obj_player_arms)
   //reset your sprites here
}
This is untested
Try this and let me know.
Thanks, now it only creates 1 arm when the players shooting. But the arm stays still and doesn't move with the player when the player moves.
 

ophelius

Member
I didn't explain that part. From the looks of your code above, you seem to understand about point_direction and image_angle, which is what you'll need for your arm. So while mouse is down and arm exists, use those functions to rotate the arm based on the mouse x and y. I think you'll have to set the collision mask coordinate at the arm's shoulder position so it rotates around that point, which means you'll have to change the creation coordinates from what you already have
 

Kyndle

Member
I didn't explain that part. From the looks of your code above, you seem to understand about point_direction and image_angle, which is what you'll need for your arm. So while mouse is down and arm exists, use those functions to rotate the arm based on the mouse x and y. I think you'll have to set the collision mask coordinate at the arm's shoulder position so it rotates around that point, which means you'll have to change the creation coordinates from what you already have
No no I did do that, I meant that the arm doesn't move when the player moves, so it just floats in air when the player moves away, I put this code in arm objects step event:
GML:
x = obj_player.x+24
y = obj_player.y+16
the numbers are there to position its origin in the players shoulders, now it does move with the player
 

ophelius

Member
Ok so what's left, I noticed you also wrote that you want the player to turn around as the arm rotates?

One way is to make the player's sprite draw normally if the arm angle is between -90 and +90 degrees, and flip it horizontally is it's not(I could have those angles wrong based on how you drew your sprite).
Or:
obj_player.angle = floor(obj_player_arms.angle / 60) * 60;
would turn him only every 60 degrees the arm turns.
This is all untested
 

Kyndle

Member
Ok so what's left, I noticed you also wrote that you want the player to turn around as the arm rotates?

One way is to make the player's sprite draw normally if the arm angle is between -90 and +90 degrees, and flip it horizontally is it's not(I could have those angles wrong based on how you drew your sprite).
Or:
obj_player.angle = floor(obj_player_arms.angle / 60) * 60;
would turn him only every 60 degrees the arm turns.
This is all untested
Oh I forgot to mention the game is played in a side-scroller view, the player sprite faces right, but I want both the player sprite and the arms to face left if the player is shooting the left side of the screen. Right now the arm just rotates backwards like some sort of robot.
I tried getting the mouse x position, and set the image_xscale to -1 if the cursors x position was less than the players x position. That didn't work out, it basically did nothing. I probably implemented it wrong.
 

ophelius

Member
Are you using the draw_sprite_ext in the draw routine? It has a xscale argument, maybe create a 'flip' or 'dir' variable where your code checks to see where the mouse is, and if it's behind you set flip to -1, otherwise set it to 1. Then use that flip variable in the draw_sprite_ext function for the x_scale argument. See the manual for more details on this function
 

Kyndle

Member
Are you using the draw_sprite_ext in the draw routine? It has a xscale argument, maybe create a 'flip' or 'dir' variable where your code checks to see where the mouse is, and if it's behind you set flip to -1, otherwise set it to 1. Then use that flip variable in the draw_sprite_ext function for the x_scale argument. See the manual for more details on this function
Sorry for not replying, I am not using draw_sprite_ext I'm actually setting sprite_index image_speed image_index etc. myself. I had to redo some of the sprites and the position for arms because players origin was set to top left instead of middle center, and I changed it to middle center so when I use image_xscale it doesn't flip the sprite all the way and it looks like it's teleporting.
Anyway, I use this for the player
GML:
if(mouse_x > obj_player.x){
    image_xscale = 1;
} else{
    image_xscale = -1;
}
and this for the arms
GML:
if(mouse_x > obj_player.x){
    image_yscale = 1;
} else{
    image_yscale = -1;
}
. It works, both the player and the arms turn around.
 
Top