While working on a new game prototype, I found some inspiration for a really cool feature from Nuclear Throne. If you are not familiar, Nuclear Throne is a top down rogue-like developed by Vlambeer where the player needs to eliminate all of the enemies in a particular stage in order to proceed.
Nuclear throne has a really unique camera system. Instead of keeping the camera centered on the player, like in other games, the camera system will follow the player’s mouse. This allows the player to see more of the level in the direction that they are aiming, helping you see around corners and making sure you don’t run into an ambush.
Another thing I like in Nuclear Throne, to save on the number of sprites that the game uses, the gun isn’t animated as part of the player, it is just a static sprite that will move around based on where the player has their mouse. The gun will also move in front of or behind the player based on where the player is currently aiming.
Building these features in GameMaker Studio 2 isn’t really all of that hard, it only requires 3 game objects to be created, a player object, a gun object and a camera controller object. I will add some wall objects just to show the camera system working, because it will be hard to see the camera’s movement on a pure black background.
We can start this project by opening up GameMaker Studio 2 and creating our 4 game objects, I named mine obj_player, obj_gun, obj_wall and obj_camera_controller. The player, wall and gun need sprites to be able to see them in the room. The player and wall sprites can be 32 * 32 and the gun can be 32 * 8. The sprite for the player should be center aligned, the gun’s sprite should be middle left aligned and the wall doesn’t really matter. Once your objects have been created and your editor looks like mine, we are ready to start writing some code.
We can begin by writing all of the code for the player. The amount of code that we need to put inside of the player object to make this work is very minimal. We only need to add 2 lines of code to the create event and a single line of code inside the step event.
Inside of the Create event we are going to be spawning a gun on the player’s x, y location, and we are going to pass through the player’s instance id over to the gun.
///@description Player Create Event
gun = instance_create_layer(x, y, "Instances", obj_gun);
gun.spawned = id;
The player’s step is only going to be updating the player’s depth based on their current y position inside of the room. This should seem very familiar if you have been using Gamemaker for a while. The depth variable is used to tell Gamemaker the order that objects should be drawn in the room. This bit of code will make objects further down the screen drawn on top of objects higher in the room
///@description Player Step Event
depth = -y;
The gun’s code is going to be in the step event of the gun object. The gun will need to update it’s location to be the same as the player’s location, which we know thanks to the player passing us it’s ID. After that we will need to determine what direction the gun should face. To do that we can use the point_direction function to find the direction between the gun’s current position and the current position of the mouse.
///@description Gun Step Event
x = spawned.x;
y = spawned.y;
var mouse_direction = point_direction(x, y, mouse_x, mouse_y);
Now that we know the direction of the mouse, it is time to actually make the gun face the mouse. The easiest way to achieve this is to update the image angle with the direction.
image_angle = mouse_direction;
When we run the game, this is what we get.
This isn’t exactly finished, the gun is always behind the player no matter where the mouse is, and we want the gun to be in front of the player when he is aiming down. The solution is that now we need to move the gun ever so slightly towards the mouse to get the desired effect.
Moving the gun isn’t very hard, first we need to create an offset variable in the gun’s create event and assign it the number of pixels we would like it to be offset by. I picked 5 pixels for this value.
///@description Gun Create
offset = 5;
Back in the step event we move the gun’s x and y positions using the lengthdir functions and giving it the direction of the mouse and our offset value. Finally we will need to update the depth of the gun so that it will be drawn over the player.
x += lengthdir_x(offset, mouse_direction);
y += lengthdir_y(offset, mouse_direction);
depth = -y;
Now we have a nice effect where the gun disappears behind the player when you aim up and it is in front of the player when you aim down.
With that feature out of the way we can now move onto having the camera follow the mouse. Put a couple walls and your camera controller object into your room (so that you can see the camera move) and set up some views. Don’t forget to make sure that the room is big enough that the camera can move through the room and you have the view set to follow the camera controller object (To make this a bit easier you can also assign a sprite to your camera controller object so that you can see the work that you are doing, but this is completely optional).
We are going to be moving our camera object directly in between the mouse and the player and updating the camera position to that location. We can find out the exact middle point between the player and mouse by taking the player’s position, the mouse’s position and averaging them. Once we have calculated the middle point between the player and mouse we can assign that value to the X and Y position of our controller in it’s step event.
///@description Camera Controller Step Event
x = (obj_player.x + mouse_x) div 2;
y = (obj_player.y + mouse_y) div 2;
And that’s all you need to do. When you run the game you should have a camera that follows along with the mouse. If you don’t, then make sure you remember to enable views, have the view follow your controller object, and make sure that the borders in the view keep your controller directly in the middle.
When you add movement to the player object the camera will move with the player as well because our controller is always going to move to the half way point between the player and the mouse.
This implementation is a little bit crude and the movement isn’t as smooth as Nuclear Throne’s, but its a very similar effect. With a bit of tweaking this could be made to work exactly like Nuclear Throne’s camera system.
Until Next Time
– Steven
Excellent writeup!