GML Dynamic Camera code explanation

P

pixelRaid

Guest
I've been following Shaun Spalding's tutorials. One of his videos mentioned a code for something he called a dynamic camera.
The code was following:

var xTo, yTo;

move_towards_point(mouse_x, mouse_y, 0);
xTo = obj_player.x + lengthdir_x(min(256, distance_to_point(mouse_x, mouse_y)), direction);
yTo = obj_player.y + lengthdir_y(min(256, distance_to_point(mouse_x, mouse_y)), direction);

x += (xTo-x)/25;
y += (yTo-y)/25;

view_xview[0] = -(view_wview/2) + x;
view_yview[0] = -(view_hview/2) + y;

view_xview = clamp(view_xview, 0, room_width - view_wview);
view_yview = clamp(view_yview, 0, room_height - view_hview);


It basically creates a lead room in the direction of the mouse pointer. I tried to follow him as much as possible, went through the video multiple times. But failed to understand the code. I even went through the documentations. The code works fine with my game, but I'm not able to get what's exactly happening here. I would be using it in the future and I don't want to simply copy-paste the code everywhere. I would like to know exactly what's happening in the code and also, why is lengthdir needed?

P.S. I'm new here, so I might be wrong about where to ask this question. I apologize for any inconvenience.
 

TheouAegis

Member
var xTo, yTo;
Declare the variables xTo and yTo local to this code

move_towards_point(mouse_x, mouse_y, 0);

This just sets the direction toward the mouse. It would be better to just use direction=point_direction(x,y,mouse_x,mouse_y) I'd expect
xTo = obj_player.x + lengthdir_x(min(256, distance_to_point(mouse_x, mouse_y)), direction);
yTo = obj_player.y + lengthdir_y(min(256, distance_to_point(mouse_x, mouse_y)), direction);

This sets the two variables to be how far the camera needs to move from the player toward the mouse, up to 256 pixels

x += (xTo-x)/25;
y += (yTo-y)/25;

This moves the camera object 1/25th of the way toward the mouse

view_xview[0] = -(view_wview/2) + x;
view_yview[0] = -(view_hview/2) + y;

This repositions the view to follow the mouse

view_xview = clamp(view_xview, 0, room_width - view_wview);
view_yview = clamp(view_yview, 0, room_height - view_hview);

The view can go outside the room using the previous code, so this keeps it inside the room (optional)

The last part is optional because the dimensions of the room aren't that important. You can put things outside the room as much as you want. Just think of the room as a type of invisible border which you can ignore like Mexicans.
 
P

pixelRaid

Guest
Thanks for the explanation. But I have a few more questions. What exactly is lengthdir and how is it helping? I know lengthdir is a component of displacement to a point and and the direction. But what does it actually mean? And why was -(view_wview/2) + x not written like x - (view_wview/2)?
 
T

trebor777

Guest
About LengthDir
It's because you want to move in the direction of the mouse cursor, we need to know how much for each axis in order to move correctly in the direction of the vector drawn between the cursor and the character.
LengthDir_x/y returns the proper value for a distance (our radius) in a specific direction. Basically behind the curtains it translates to determining the angle between an axis (y or x) and our direction, and playing with trigonometry to get the correct X and Y for a specific distance in that direction.
https://en.wikipedia.org/wiki/Trigonometric_functions
http://www.afralisp.net/archive/lisp/bulge.htm

It's similar to knowing the hypothenus of a right triangle, and looking to know the length of the other sides. because computers only understand X and Y. :)
Hope it helps.

Let's decompose it:
min(256, distance_to_point(mouse_x, mouse_y)

-> Distance_to_point(mouse_x, mouse_y) this gives you a distance between two points: the current object position (implicitely), and the given point as argument, here the mouse cursor.
->min( a , b) returns the lowest value comparing a to b.

So our line gives us either 256 or the distance to the mouse cursor, whichever is the smallest. We do this because we don't really want to move exactly to the mouse cursor as it might be quite far from the player, but only toward its' direction. So having a max distance (or radius) is good :)

then get the X and Y component of that vector and add those to the obj_player position. This gives us a target to reach for our camera. ' I want to go there! '

But we don't want it to move instantly. We want to move smoothly, so that it takes a certain amount of time to reach that target for the camera. So we split the distance (xTo-x) between our current camera position and our target, by an arbitrary value ( / 25) and move by that amount for that frame. (x += ... )

Same thing for y.

Next frame we recompute all over again. our distance should be shorter, the split distance too, so the increment to move is smaller, etc.. etc.. this move less and less each frame. giving the illusion of a smooth movement.


About the -(...) + x , rather than the x - (...)
No particular reason. Both works. the math is the same in the end. Just a personal coding style preference for Shaun... ^^' I guess?
Maybe it's easier for him to understand it like that.



I hope it clarified things for you.
 
P

pixelRaid

Guest
Thanks for the replies, I've gotten a hang of it. I guess some more practice will embed the concepts.
 
Top