PC Games
• Orb Tutorials
• 2D shoot 'em up Latest Updates
SDL2 Versus game tutorial
Download keys for SDL2 tutorials on itch.io
The Legend of Edgar 1.37
SDL2 Santa game tutorial 🎅
SDL2 Shooter 3 tutorial
Tags • android (3) • battle-for-the-solar-system (10) • blob-wars (10) • brexit (1) • code (6) • edgar (9) • games (43) • lasagne-monsters (1) • making-of (5) • match3 (1) • numberblocksonline (1) • orb (2) • site (1) • tanx (4) • three-guys (3) • three-guys-apocalypse (3) • tutorials (17) • water-closet (4) Books Firmware HF-Tech's chips have changed the world. Embedded into the heads of over 90% of the world's population, they have cured autism, dementia, provided intelligence boosts, and helped to ease some of the more mundane tasks in life. Daniel Blair, hacker and Workshop member, however is not convinced that everything is as rosy as it seems. But is he looking in all the wrong places..? |
— Making a 2D split screen game — Note: this tutorial assumes knowledge of C, as well as prior tutorials.
Introduction It's time to take control of our ship. Watching it spinning around is all well and good, but our game needs to be more interactive than that. In this part, we'll implement the steering and shooting, both of which are pretty easy to do. Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./versus02 to run the code. You will see a window open like the one above, with the player's ship located in the middle of the screen. Use A and D to rotate the ship anti-clockwise or clockwise. Use W to accelerate and S to brake. Hold J to fire bullets. There is no limit to how fast we can fly, but if you hit the edges of the screen, you will bounce off them, and slow down a bit. Once you're finished, close the window to exit. Inspecting the code As already stated, adding in our steering and shooting is pretty simple, even more so if you've already followed a bunch of these tutorials before. Let's jump in, starting with the updates to structs.h:
We've updated the Entity struct, to add in some new fields. `dir` is the direction the entity is moving (its velocity, if you will). `radius` is the bounding sphere of the entity (this will come into play much more later on, to help with collision detection). `data` is a pointer to the extended entity data, something we've seen before. Next, we have the Player struct:
Not much in it right now, other the `reload` field, that will control how often we can fire. Finally, we have Bullet:
Another rather standard struct. `type` is the type of bullet this is, while `position` and `dir` are the location and velocity of the bullet. `radius` is its bounding sphere. `angle` is the bullet's angle, while `model` and `owner` are used to store the model the bullet will use when rendering, and the entity that owns the bullet (in this case, just the player). Some of these fields will come into extended use later on. Moving on now, let's first look at the updates we've made to player.c, to handle our controls. First, we've updated initPlayer:
We're now mallocing a Player object (`p`) and setting it into the Entity's `data` field. We're also setting the Entity's `radius` to be 15. This value is of note, because it's actually smaller than the player's model. This means that later on you will notice that it's possible for parts of the ship to intersect the world, without a collision taking place. This is all fine, and something that is actually of advantage to us, in terms of gameplay. We'll discuss this more in a later part. For now, let's look at the update to the `tick` function:
An overhaul to the simple rotation. We're calling two new functions here, `steer` and `fire`. We're then updating the entity's `position` according to its `dir`, to make it move. Finally, we're testing if the ship has moved outside of the bounds of the screen, by checking its `radius` against the sides. If so, we're calling a function named `bounce` (we'll come to this last). So, we have a few new functions that we need to detail. We'll move on to `steer` first:
This function, as the name implies, handles our steering. We first test if A or D are pressed, and will increase or decrease the player's `angle`, to make them turn. Next, we test if W is pressed. If so, we're going to adjust the values of `dir`'s `x` and `y`, according to our current `angle` (again, using radians, and once again with the help of some trigonometry). The short version is that we will be accelerating the player in the direction their ship is facing, following the vector of their current heading. Nice and simple. Finally, we test if S is pressed, and dappen our `dir`'s `x` and `y`, causing the player to decelerate. Nothing taxing there, at all. The most complicated part is moving along our heading, and that's a very commonly available calculation. Moving over to the `fire` function now:
There's nothing difficult here, either. This function deals with firing the player's guns. We first decrease the value of the player's `reload`, then check if it's 0. If so, and J is pressed, we'll make a call to a function named firePlayerBullet (we'll see this shortly). Finally, we reset the player's `reload` to 1/12th of a second, thus allowing them to fire at a rate of 12 shots per second. The final function we want to look at is `bounce`:
As a reminder, this function is called whenever the player hits the sides of the screen. We first push the player back along the direction they have come from (effectively, returning them to the position they were in before the collision happened). With that done, we reverse the player's heading by negating their `dir`. We also dampen the velocity a bit, by quartering the result, so that we don't push the player back with the exact same force as they were originally going. As with real bouncing, some energy was lost during the impact. That's it for player.c. All those simple additions have allowed us to take control of our player's ship, and fly it along the correct heading. Great progress! Now over to bullets.c. This file is where we'll handle all our bullet-related tasks. This will be like something we've seen many, many times before, so we won't linger. To start with, we have initBullets:
We setup the bullet linked list, and also load the model for the player's bullet (as player1BulletModel). Next up, we have doBullets:
Nothing out of the ordinary - here, we're just looping through our all our bullets, updating the positions according to their direction headings, and decreasing their `health`. If a bullet goes off-screen, we'll set its health to 0, so that it is removed from our linked list. Over to drawBullet next:
Here, as with our entity rendering, we're simpling calling drawModel, and passing over all the relevant details. Now for firePlayerBullet:
This function, as we saw, is called whenever the player fires their guns. It accepts the player's entity (`e`) as a parameter. We start by creating a bullet (via spawnBullet), and setting all the relevant details. The bullet's `position` will be the same as the player's, with its direction (`dir`) inheriting from the player's own; we want the bullet to move ahead of the player, along the same vector, but at an increased speed. The bullet also inherits the player's `angle`. The `owner` is set to the player, and the bullet's `model` as player1BulletModel (for now). Finally, we come to spawnBullet:
This is just a helper function, to create a bullet for us to use. We're just about done. We just need to head over to zone.c, and tell our game loop to handle the bullets. First to initZone:
We've added in a call to initBullets. Next, to `logic`:
We're calling doBullets, to process them. Finally, we've updated `draw`:
We're calling drawBullet here. That's all there is to it! A nice, short piece, that's already added in some essential functions to our game. What would be good now is to have an arena or battle zone to fly around in. Some walls and other obstacles, that the player needs to negotiate and be constrained by. In our next part, we'll look into loading an arena, that, like most everything else in our game, will be built using triangles. Purchase The source code for all parts of this tutorial (including assets) is available for purchase, as part of the SDL2 tutorials bundle: From itch.io |