Bonjour and a warm welcome to the FlashPunk Tutorial 03!
Here I’m going to show how to implement some camera movement. It’s a short one, so you shouldn’t have to spend too much time on it. It’s the logical continuation of the previous tutorial. As always, you can get the source code for the previous tutorial here, and the final code of this tutorial here. Without further ado, let’s just get started, shall we?
So as you remember, we created a map of dimensions 1248×768 pixels, while our flash player window was just 624×480. Clearly, there’s area in the map that we haven’t seen in the game, because the camera won’t move along.
Our avatar is free to roam outside the screen boundaries, but we’d like to follow him right?
Screen scrolling is pretty simple, and there are many different techniques, as well as concepts such as parallax
scrolling. We are just going to do very basic stuff – we’re going to move the camera in the direction in which the player moves, if the player moves close enough towards one of the 4 screen boundaries.
Heck, I’ll just throw the new Game world in your face! 😛
We added 2 new variables to the Game world. The first two are map related, they store the width and height of our map. The next 2 are camera related. cameraOffset contains the pixel distance (or padding, if you will) from the screen edge that is the closest the avatar must be able to get to the screen edge. Only if the camera is already on the map’s boundaries can the avatar move withing the offset without the camera moving along. I hope this makes some sense. The other variable is the camera speed, which is the speed the camera is to follow the player. It is logically related to the player’s movement speed. For example, if the camera’s speed is lower than the player’s movement speed, then it means the player can outrun the camera, but if the player’s movement speed was lower, then the camera could potentially lose focus of the player by going too far (not with the offset though).
Anyways, in the constructor class we’re initializing the cameraOffset to be 200 pixels, and the cameraSpeed to 2 pixels, which, as you’ll remember, is the speed of the player. Next are some changes in the loadMap() function. When we get the xml instance of the map, we read the values of the width and height tags and store them in the mapWidth and mapHeight variables respectively.
After doing all that, we can actually start understanding the new function, followPlayer(). We check on the horizontal
and vertical axis separately if the player has moved into the camera offset. For example, in order to determine this for
the left screen boundary, we take the player’s x coordinate (which is actually the coordinate of the player sprite’s left edge) and the camera’s (the part of the screen that we can view through the flash player window) x coordinte. We substract it from the player’s x coordinate and we get the distance between the player left edge and the screen’s left edge. If this distance is less than the cameraOffset, we need to move the camera (FP.camera.x) horizontally by 2 pixels (cameraSpeed). But before we can do that, we need to check if the camera already reached it’s most left position, in other words, we need to see if the camera already hit the map’s left boundary, which is 0. If that isn’t the case, we can go ahead and decrease the camera’s x coordinate.
We do the same thing for the other direction, but this time we need to add the width of the screen’s view portion and the player’s sprite (actually the hitbox). We again also need to check whether the camera hit the map’s boundary. Try the demo now, enjoy as your avatar roams the forgotten lands :D. But wait, what happens if we place our avatar to a position that on the other side of the map? Try it, by changing the values of the player’s position from 10,10 to something like 900,500.
Hmm… the camera seems to start at 0,0 no matter what, and then it only slowly (namely by the speed you set – 2 pixels per frame) moves towards the player. This is an issue, and it must be addressed. We simply need a new function that we can call after loadMap() that sets the FP.camera’s starting position by evaluating the player’s position. It should again first check on the horizontal axis, then on the vertical axis. In most cases, it should position the camera so that the player ends up in the center area of the screen’s view port. So for the x axis for example, we’d like something like FP.camera.x = (player.x + player.width/2) – FP.width / 2, and the same idea goes for the y axis. Now of course, there’s the issue with the screen boundaries, so we’ll need to check the new FP.camera.x and FP.camera.y values if they exceed the map boundaries. This is done by some simple if conditionals, nothing very fancy there.
The code of the new function is here:
And then just set a function call right after calling loadMap()
You could stop now and go out, have a cig/tea/coffee/party if you like, but there’s still something I’m not really happy with in this code. The whole camera thing is really not that integral to the Game world class, is it? Let’s exercise some modularization (is that even a word?). Create a new folder called “utility” inside the “src” folder of your project. In there, create a new class called Camera.as. You’ll pretty much copy and past most of the code, but there are some additional things to add of course. Here it is:
The whole class should be a no-brainer now. We set parameters in the function definitions, because we want to get those values at run time, and the offset and speed are set when first instanciating the class. In the Game world we are going to delete the two camera functions and the cameraOffset and cameraSpeed variables as well. Instead, we’ll create a new camera object as a class property, and instantiate it in the constructor, and call the adjustToPlayer() function right after loadMap() and followPlayer() in the update function. Here is the new Game world:
Aaand we’re done. You can get the entire code here. See you soon with a bigger tutorial next time on transitioning between maps, and creating a world map to show the current position of the player.