Gravity Propulsion Bomb

gpbOne of the things I did this week was to program our new power up. I came up with it during last week. It’s called GPB (Gravity Propulsion Bomb). It replaces our older power up; Meteor Shower. The GPB is shot from the player’s cannon and explodes in the sky. It then becomes looks like a black hole and behves like a magnet that pulls in and sucks up all the nearby enemies. One of the alien ship types will drop the power up and you will have to click it to get the power up. This is so you can choose if you want to replace your current power up or keep the your current one. You can see the GPB in the image above.

All alien ships are effected by the GPB, but the closer the ships are to the GPB the stronger they’re pulled. To do this, the PBS iterates through all the alien ships. For each ship, the distance between the ships and the GPB are then calculated using the Pythagorean theorem (distance = ((x1 – x2)2 + (y1 – y2)2). The new position for the alien ships that frame is calculated by subtracting the position of the alien ships with the position of the GPB, then normalizing it ( {x/distance, y/distance} ), then multiply it by how far it should move that frame, which is calculated by using a large constant and subtracting that constant with the distance, and then multiply it by the delta time and a speed constant. If that all results in a number less than zero, then there’s no additional movement to be applied to the alien ships. If it was allowed to be less than zero, then far away ships would move away from the GPB. Both the pull effect and the alien ships’ usual movement are applied each frame so that they continue to do their movement patterns while being pulled.

A fade-in and fade-out is applied to the GPB sprite while active. The GPB has a countdown for how long the exists. During the first half of the countdown it does 255 – ( 255 / 2.5 ) * (countdown – 2.5) to control its transparency. It’s 255 when it’s not at all transparent, and 0 when it is. The number 2.5 is half of the countdown. To make it disappear again, the following is done: ( 255 / 2.5 ) * (countdown – 2.5).

I think the outcome seems pretty good, but it could probably be improved more if we want to. It was a bit difficult to get the numbers right for it to be really good, but I think it turned out well.

Health Meter

hpmeterThis week I’m going to talk about the health meter. I fixed it so it works correctly and is completely functional this Monday night, but I had begun working on it a bit the week before but didn’t finish it. I also added a wave effect on it on Thursday. The health meter behaves like a bowl of water. For example, when the health meter is full it’s completely round and green, but when you have only half of your health the lower half of the health meter will be a green half circle, like how it looks in the above image. The wave effect I mentioned above works by having the liquid in the ‘bowl’ constantly vary slightly in height.

The health meter consists of two layers; a green background layer which in green shows the amount of health, and a gray metal front layer that is just for nice looks. The bowl of water effect is achieved by cutting the upper half of the sprite using setTextureRect(), which is a part of SFML.

When the health changes it transitions smoothly in a fashion that makes it feel a lot like a liquid. This is achieved by using something called linear interpolation, or lerp for short. Lerp can be used with all kinds of things to get smooth transitions. My implementation of lerp looks like this: (1-t) * start + t * end. Start is what the health meter currently displays, end is the player’s actual health, and t is how fast it will move each frame; which is the game’s delta time times the transition speed.

The health meters fills up at the start of the game and decreases a bit each time you lose health. The height of the health in the health meter constantly moves a few pixels up and down to enhance the feeling of it being a liquid. This is achieved by applying sin(current_time * speed) * amount to the health height.

I’m quite happy with the result. I think the liquid effect looks really nice. We have planned in the future to have the health distributed between the four sectors of the planet, with each sector having an equal amount of health. The health meter would then only be empty when all of the sectors are destroyed. For example, if one sector is completely destroyed but all others are completely okay, then ¾ of the health meter will be filled.

Waves

Skärmklipp

Hej jag heter Linus Bjernhagen och är från grupp 17.

Spelet som vår grupp skapar heter Planet Suburbia. I spelet skjuter man på utomjordingar som vill ta sig till jorden. Man kan förflytta sig runt jorden igenom fyra olika sektorer.

På måndagen så programmerade jag så att fienderna kommer i ett antal olika ‘waves’. Det gör att alla fienderna inte kommer på en gång, och då kan spelaren ta en kort paus i spelandet så det inte blir för hektiskt. När en ny wave kommer så kommer ett meddelande upp mitt på skärmen där det står att en ny wave kommer; t.ex. ”First Wave”, ”Second Wave”, ”Third Wave”, och så vidare. Vi har inte bestämt exakt hur varje wave ska se ut, eller vilket antal. På bilden ovan ser man att den andra waven håller på att startar, och att två utomjording-skepp som har spawnat.

Spawningen av fiender i waves är uppbyggt genom att det finns en lista över ‘WaveStep’ som itereras igenom hela spelets gång. En WaveStep innehåller vilken som är den nästa typen av fiende som ska spawna, hur lång tid det är från den föregående tills den ny ska spawna, vilken vinkel runt jorden den ska spawna, och om en ny wave ska börja.

Med det här systemet är det även lätt för andra saker i koden att se vilken wave det är just nu, det är bara att kolla vilken den nuvarande WaveStep är.

Jag tyckte jag kom på ett bra sätt hur jag skulle programmera det nästan på direkten, så jag tänkte inte på några andra sätt att programmera det på. Några andra sätt som jag tänker nu i efterhand som också kunde ha fungerat är:

  • Att skriva en klass för varje gång en ny fiende dyker upp. Det här vore en väldigt dum idé eftersom det i så fall behövas hundratals klasser som alla är nästan precis likadana. Det skulle bli onödigt mycket kod, och svårare att hålla koll på.
  • Man kan ha så att fienderna spawnar slumpmässigt runt jorden och waves hanteras igenom att varje wave pågår en viss tid, och pausen emellan waves pågår en viss tid. Tiden kan vara samma i varje wave, eller variera under spelets gång.
  • Istället för att ha WaveStep eller iterera igenom en lista så kan man kalla på AlienShip::create() med parametrar om när och var den ska spawna, och kalla på den på alla fiender som ska spawna efter varandra på följd. Det här skulle fungera ungefär lika bra, men jag tycker sättet som gjorde det på är snyggare.

Introduction and Input Manager

Introduction

Hello, my name is Linus Bjernhagen and I’m going my first year of Game Design and Programming at Uppsala University – Campus Gotland. The course I have now, Game Programming I, gives 5 points towards the project we have to do for this course if we make a blog about it with at least 5 posts.

We’re supposed to make a clone of a game from a list of 12 games. The game is to be programmed in C++ and SDL. It has to have a proper game engine with things such as eg. entity hierarchy, input manager and audio manager. I’m thinking of making a Zelda I clone, but it’s still not too late to change my mind. It will ‘officially’ start on the fifth week, but I asked the teacher if it was possible to start earlier. This course is aimed at people with no previous programming experience, so I thought I would begin earlier as I wouldn’t have much to do otherwise. He said it was okay, but if I waited we would get code we could use in the game engine, eg. code for the input manager.

I began working on the project on tuesday, the second day of the course, and it’s now sunday. I think the input manager is completly done now. I finished it on thursday, so it took two and a half day to make. I’ve since then been working on the entity component system. The entities are called game objects as I feel that makes more sense. I’ve barely worked on it during the weekend though, but I feel as it’s almost done. It could have been finished much earlier if I made it differently, though I think I’ll talk more about that in my next post. Today I’m going to talk about my input manager.

Input Manager

A function called frameInputUpdate() is called each frame. Inside that function the input is polled with SDL_PollEvent(&event) and stored in a vector of events called std::vector<SDL_Event> eventList. Inside the frameInputUpdate function SDL_KEYUP, SDL_KEYDOWN, SDL_MOUSEBUTTONUP, and SDL_MOUSEBUTTONDOWN is checked. If SDL_KEYDOWN or SDL_MOUSEBUTTONDOWN is found within eventList, then that event is added to another vector of events called eventPressedList, and if SDL_KEYUP or SDL_MOUSEBUTTONUP is found within eventList, then the event in eventPressedList with the same key or mouse button is removed.

There is another way that is built-in in SDL of checking for keys pressed, but I think this way is better. You do it by checking the variable key.repeat in SDL_Event. The inteval between each time a repeat event is sent is pretty low, and there is a slight delay after you press the key until repeat begin sending. That interval and delay could apparently be set in previous versions of SDL with a function called SDL_EnableKeyRepeat. But even if I had that function I don’t think I would use key repeat, as much more events would constantly have to be handled, which could make it a bit slower. There also isn’t a way of checking for the mouse buttons being pressed built-in in SDL.

In the functions bool getKeyDown(SDL_Keycode keyCode), bool getKeyUp(SDL_Keycode keyCode) the the specified key is searched for in the varable event.key.keysum.sym in each event in eventList. It is also important to check that the event type is correct. The same thing is done in bool getKeyPressed(SDL_Keycode keyCode), but with eventPressedList instead of eventList. bool getMouseDown(Uint8 button), bool getMouseUp(Uint8 button), and bool getMousePressed(Uint8 button), but instead of checking key.keysum.sym, button.button is checked instead.

Instead of checking for keys you can also check for ‘buttons’. Button is a class I’ve made that contains a string called id and a SDL_Event* called eventP. It enables keymapping by binding keys to id’s. There is a vector called ButtonList which contains all the bindings. bool getButtonDown(std::string id), bool getButtonUp(std::string id), and bool getButtonPressed(std::string id) looks through the ButtonList after matching id’s. When a match is found the key.keysum.sym in the button’s event is checked if it is not equal to SDLK_UNKNOWN. If that’s the case then it calls getKeyDown, getKeyUp, or getKeyPressed, otherwise it checkes button.button != 0, and if that’s true it calls getMouseDown, getMouseUp, or getMousePressed. To bind a key or mouse button to an id you call the function void registerButton(std::string id, SDL_Keycode keyCode = SDLK_UNKNOWN, Uint8 mouseButton = 0). If you want to bind a key you pass a SDL_Keycode but no Uint8, and the other way around if you want to bind a mouse button. It is possible to bind several keys and mouse buttons to the same id, and it’s also possible to bind several id’s to the same key or mouse button.

You get the mouse position with Vector2* getMousePosition(). This is nothing but a simple wrapper around SDL_GetMouseState, but I thought it would be good to have my own functions for all the different input. Vector2 is a class I’ve made that has two varables; x and y. With the function Vector2* getMouseDelta() you get how much the mouse has moved since the last frame. In frameInputUpdate, getMousePosition is called and the position is stored in the variable Vector2* lastMousePosition. getMouseDelta returns lastMousePosition minus the current mouse position.

I also have a function called bool getQuit() that checks eventList for SDL_QUIT. SDL_QUIT happens when you close the window.

void destroyInputManager() clears and deletes eventList, eventPressedList, and buttonList.

That was all of my input manager. It wasn’t very hard to make, I think it was easy to figure out how to do things. In my next post I’ll most likely talk about my entity component system. I had a bit more problem with that one as I wanted to make it a certain way, but had a bit of difficulty with implementing it the way I wanted; but it seems as if I’ve got a solution to it now.

Just now while writing this I realized that I haven’t considered mouse lock and hiding the mouse, though it might be enough to just use SDL_SetRelativeMouseMode(SDL_bool enabled) for that. getMouseDelta() seems unnecessary now though as SDL_SetRelativeMouseMode does the same thing when enabled.