GMS 2 [solved] Aiming (camera)

trentallain

Member
In my game I want it so if I am holding right click on a mouse or L2 (gp_shoulderlb) on a controller, it will slowly move the camera towards a point (which will be the camera's view width or height/2 past the camera's target object, with an angle up to 360 degrees). And if I release right click or L2, then it will slowly go back to the normal target object.
Code:
if obj_control.controller_connected == true
{
    if gamepad_axis_value(gp_type,gp_axisrh) != 0 and gamepad_axis_value(gp_type,gp_axisrv) != 0
    {
       var gp_h_axis_dir = sign(gamepad_axis_value(gp_type,gp_axisrh))
       var gp_v_axis_dir = sign(gamepad_axis_value(gp_type,gp_axisrv))
       right_axis_direction = floor(point_direction(0,0,gp_h_axis_dir,gp_v_axis_dir))
    }
    camera_aim_direction = right_axis_direction
}
else
{
    camera_aim_direction = floor(point_direction(0,0,mouse_x,mouse_y))
}

if obj_control.inventory_open == 0 && obj_control.menu_open == 0
{
    if mouse_check_button(mb_right) || (obj_control.controller_connected == true && gamepad_button_check(obj_control.gp_type,gp_shoulderlb))
    {
        if !keyboard_check(ord("1")) && !keyboard_check(ord("2")) && !keyboard_check(ord("3"))
        {
            //Aiming
            view_target_x = floor(x - camera_get_view_width(obj_control.camera)/2 - (x-mouse_x)/4)
            view_target_y = floor(y - camera_get_view_height(obj_control.camera)/2 - (y-mouse_y)/4)     
            camera_set_view_pos(obj_control.camera,view_target_x,view_target_y)
        }
    }
    else
    {       
        camera_set_view_pos(obj_control.camera,x-camera_get_view_width(obj_control.camera)/2,y-camera_get_view_height(obj_control.camera)/2)
    }
}
The above code kind of works for the right click atm (but snaps to positions)

So my questions are:
How do I get it to work with camera_aim_direction and not snap to positions?
 

TheouAegis

Member
When the camera is centered, it's at player's x-view_width/2 and y-view_height/2, correct?

You said distance should be half the view's size, presumably to keep the player in view. You will likely want this hard-coded so the game doesn't have to calculate it every time. The formula is
sqrt(view_width*view_height)/2
But if you want the player to stay in view, it needs to be a shorter distance like
sqrt((view_width - sprite_width)*(view_height - sprite_height))/2
Let's call those values scope_length.

So zoomed out, the camera is at
x + lengthdir_x(scope_length, camera_aim_direction)
y + lengthdir_y(scope_length, camera_aim_direction)

But we need the length to be variable. For that, we should use another variable. Let's call it camera_aim_distance.
x + lengthdir_x(scope_length+camera_aim_distance, camera_aim_direction)
y + lengthdir_x(scope_length+camera_aim_distance, camera_aim_direction)

Now all you need to do is set camera_aim_distance to lerp(camera_aim_distance, scope_length * button_is_pressed, 0.2 - 0.1*!button_is_pressed)

I used button_is_pressed since your code is using mouse and gamepad. You should consider doing that too. All of those I/O checks add up and slow down your game.
 

trentallain

Member
When the camera is centered, it's at player's x-view_width/2 and y-view_height/2, correct?

You said distance should be half the view's size, presumably to keep the player in view. You will likely want this hard-coded so the game doesn't have to calculate it every time. The formula is
sqrt(view_width*view_height)/2
But if you want the player to stay in view, it needs to be a shorter distance like
sqrt((view_width - sprite_width)*(view_height - sprite_height))/2
Let's call those values scope_length.

So zoomed out, the camera is at
x + lengthdir_x(scope_length, camera_aim_direction)
y + lengthdir_y(scope_length, camera_aim_direction)

But we need the length to be variable. For that, we should use another variable. Let's call it camera_aim_distance.
x + lengthdir_x(scope_length+camera_aim_distance, camera_aim_direction)
y + lengthdir_x(scope_length+camera_aim_distance, camera_aim_direction)

Now all you need to do is set camera_aim_distance to lerp(camera_aim_distance, scope_length * button_is_pressed, 0.2 - 0.1*!button_is_pressed)

I used button_is_pressed since your code is using mouse and gamepad. You should consider doing that too. All of those I/O checks add up and slow down your game.
Thanks so much!
But when you said "Now all you need to do is set camera_aim_distance to lerp(camera_aim_distance, scope_length * button_is_pressed, 0.2 - 0.1*!button_is_pressed)" did u mean that or camera_set_view_pos?
 

TheouAegis

Member
camera_aim_distance

Oh, i was going somewhere with this and got derailed. The formula should be

x +lengthdir_x(camera_aim_distance, camera_aim_direction) -view_width/2
y +lengthdir_x(camera_aim_distance, camera_aim_direction) -view_height/2

I didnt use the right variables, so it will take some editing.
 

trentallain

Member
camera_aim_distance

Oh, i was going somewhere with this and got derailed. The formula should be

x +lengthdir_x(camera_aim_distance, camera_aim_direction) -view_width/2
y +lengthdir_x(camera_aim_distance, camera_aim_direction) -view_height/2

I didnt use the right variables, so it will take some editing.
Code:
//View tracking
view_width = camera_get_view_width(obj_control.camera)
view_height = camera_get_view_height(obj_control.camera)
scope_length = sqrt((view_width - sprite_width)*(view_height - sprite_height))/2
camera_aim_distance = 0
camera_aim_direction = 0
right_axis_direction = 0
Code:
if obj_control.controller_connected == true
{
    if gamepad_axis_value(gp_type,gp_axisrh) != 0 and gamepad_axis_value(obj_control.gp_type,gp_axisrv) != 0
    {
       var gp_h_axis_dir = sign(gamepad_axis_value(obj_control.gp_type,gp_axisrh))
       var gp_v_axis_dir = sign(gamepad_axis_value(obj_control.gp_type,gp_axisrv))
       right_axis_direction = floor(point_direction(0,0,gp_h_axis_dir,gp_v_axis_dir))
    }
    camera_aim_direction = right_axis_direction
}
else
{
    camera_aim_direction = floor(point_direction(0,0,mouse_x,mouse_y))
}

if obj_control.inventory_open == 0 && obj_control.menu_open == 0
{
    if mouse_check_button(mb_right) || (obj_control.controller_connected == true && gamepad_button_check(obj_control.gp_type,gp_shoulderlb))
    {
        if !keyboard_check(ord("1")) && !keyboard_check(ord("2")) && !keyboard_check(ord("3"))
        {
            //Aiming
            camera_aim_distance = lerp(camera_aim_distance, scope_length, 0.2)
            camera_set_view_pos(obj_control.camera,x+lengthdir_x(camera_aim_distance, camera_aim_direction)-view_width/2,y+lengthdir_x(camera_aim_distance, camera_aim_direction)-view_height/2)
        }
    }
    else
    {       
        camera_set_view_pos(obj_control.camera,x-camera_get_view_width(obj_control.camera)/2,y-camera_get_view_height(obj_control.camera)/2)
    }
}
I think I must have written it in wrong. The camera only moves to the bottom right?
 

trentallain

Member
camera_aim_distance

Oh, i was going somewhere with this and got derailed. The formula should be

x +lengthdir_x(camera_aim_distance, camera_aim_direction) -view_width/2
y +lengthdir_x(camera_aim_distance, camera_aim_direction) -view_height/2

I didnt use the right variables, so it will take some editing.
I don't think it works? Also for x and y, are you supposed to be using lengthdir_x for both? (I've tried changing it but still the same issue)
 

TheouAegis

Member
Oh one is supposed to be lengthdir_y. That was a typo, sorry.

I think the issue may be here:

camera_aim_direction = floor(point_direction(0,0,mouse_x,mouse_y))

Replace 0,0 with x,y or player.x,player.y


And you can replace this:

camera_set_view_pos(obj_control.camera,x-camera_get_view_width(obj_control.camera)/2,y-camera_get_view_height(obj_control.camera)/2)

with

camera_set_view_pos(obj_control.camera,x-view_width/2,y-view_height/2)
 

trentallain

Member
Oh one is supposed to be lengthdir_y. That was a typo, sorry.

I think the issue may be here:

camera_aim_direction = floor(point_direction(0,0,mouse_x,mouse_y))

Replace 0,0 with x,y or player.x,player.y


And you can replace this:

camera_set_view_pos(obj_control.camera,x-camera_get_view_width(obj_control.camera)/2,y-camera_get_view_height(obj_control.camera)/2)

with

camera_set_view_pos(obj_control.camera,x-view_width/2,y-view_height/2)
Thanks it works perfectly! 10/10
Code:
///Create
//View tracking
view_width = camera_get_view_width(obj_control.camera)
view_height = camera_get_view_height(obj_control.camera)
scope_length = (sqrt((view_width - sprite_width)*(view_height - sprite_height))/2)/2/2
camera_aim_distance = 0
camera_aim_direction = 0
right_axis_direction = 0

///Step
if obj_control.controller_connected == true
{
    if gamepad_axis_value(gp_type,gp_axisrh) != 0 and gamepad_axis_value(obj_control.gp_type,gp_axisrv) != 0
    {
       var gp_h_axis_dir = sign(gamepad_axis_value(obj_control.gp_type,gp_axisrh))
       var gp_v_axis_dir = sign(gamepad_axis_value(obj_control.gp_type,gp_axisrv))
       right_axis_direction = floor(point_direction(x,y,gp_h_axis_dir,gp_v_axis_dir))
    }
    camera_aim_direction = right_axis_direction
}
else
{
    camera_aim_direction = floor(point_direction(x,y,mouse_x,mouse_y))
}

if obj_control.inventory_open == 0 && obj_control.menu_open == 0
{
    if mouse_check_button(mb_right) || (obj_control.controller_connected == true && gamepad_button_check(obj_control.gp_type,gp_shoulderlb))
    {
        if !keyboard_check(ord("1")) && !keyboard_check(ord("2")) && !keyboard_check(ord("3"))
        {
            //Aiming           
            camera_set_view_pos(obj_control.camera,x + lengthdir_x(scope_length+camera_aim_distance, camera_aim_direction)-view_width/2,y + lengthdir_y(scope_length+camera_aim_distance, camera_aim_direction)-view_height/2)
            camera_aim_distance = lerp(camera_aim_distance, scope_length, 0.2)
        }
    }
    else
    {       
        camera_aim_distance = 0
        camera_set_view_pos(obj_control.camera,x-view_width/2,y-view_height/2)
    }
}
 
Last edited:

trentallain

Member
Oh one is supposed to be lengthdir_y. That was a typo, sorry.

I think the issue may be here:

camera_aim_direction = floor(point_direction(0,0,mouse_x,mouse_y))

Replace 0,0 with x,y or player.x,player.y


And you can replace this:

camera_set_view_pos(obj_control.camera,x-camera_get_view_width(obj_control.camera)/2,y-camera_get_view_height(obj_control.camera)/2)

with

camera_set_view_pos(obj_control.camera,x-view_width/2,y-view_height/2)
As a side note, my code doesn't work for the right analog stick?
Code:
if obj_control.controller_connected == true
{
    if sign(gamepad_axis_value(obj_control.gp_type,gp_axisrh)) != 0 and sign(gamepad_axis_value(obj_control.gp_type,gp_axisrv)) != 0
    {
       var gp_h_axis_dir = gamepad_axis_value(obj_control.gp_type,gp_axisrh)
       var gp_v_axis_dir = gamepad_axis_value(obj_control.gp_type,gp_axisrv)
       right_axis_direction = floor(point_direction(0,0,gp_h_axis_dir,gp_v_axis_dir))
    }
    camera_aim_direction = right_axis_direction
}
else
{
    camera_aim_direction = floor(point_direction(x,y,mouse_x,mouse_y))
}
 

trentallain

Member
To be honest, I am not sure why it doesn't work. Are you sure the code is even picking up the correct gamepad?
Yeah because I tested if gamepad_button_check_pressed(obj_control.gp_type,gp_dpadu) { whatever } and it worked. I'm so confused as to why it won't work too
 
Top