Metroidvania style game - 2d playstation vita game
project Timescale: October 2013 - january 2014
Unfortunately, I do not have any screen shots or videos of this project as it was developed on a PlayStation Vita development kit and we were not given the tools to capture images from the Vita's screen. The application was written in C++ using Abertay University's own game framework. Below is the report I wrote on the project and the code files I wrote for the game.
metroidvania_code.zip | |
File Size: | 16 kb |
File Type: | zip |
Introduction
The aim of the project was to design and construct a 2-dimensional sprite based video game for the PlayStation Vita. It was required to make use of a GameObject class and have some form of collision detection.
The created application is a basic Metroidvania. The term “Metroidvania”, popularised by game critic Jeremy Parish (1996-2007), defines a videogame in the style of Nintendo’s Metroid series and Konami’s Castlevania series. Common features of the genre include 2-D side scrolling, platforming mechanics, action orientated gameplay, a large area to explore and the collecting of items that improve the player or allow them to explore new areas.
The application has all of these features implemented. There are many different areas that the player can journey through by the use of doors. Basic platforming allows the player to traverse these areas by jumping and falling. The player can fight enemies with a gun that fires projectiles or a sword that inflicts damage upon contact. Although the completed game does not have the amount of content that would be expected from a typical Metroidvania, with the framework in place, more content, such as additional areas, items and enemies, could be added with minimum difficulty.
Application Design
The program was planned to contain an application class called Game and a sprite class called GameObject.
Game would contain the main loop where all the game logic would run. This includes keeping track of the game state, rendering sprites on the screen, taking inputs from the player and updating the game objects.
The GameObject would be used for any item that would appear on screen, allowing them to be moved around the screen in different ways and collide with each other. It would also store any necessary information such as velocities or health.
The programmer intended to have three classes that would inherit from GameObject called Player, Weapon and Map, respectively.
The Player class would be used to manage the main sprite that the player controlled. It required some basic physics to allow the player to jump, more complex collision resolutions and it needed to keep track of the in-game items that the player collected.
The weapon class would be used to give the player the ability to fight off enemies. It was designed so that it could be aimed in a chosen direction, fire projectiles and damage enemies.
The Map class was planned to create different rooms for the player to explore. It would create enemies, platforms and doors, clear the room of GameObjects and change to a new room when required, store all the items that the player could collect and keep track of all the enemies, platforms and doors.
The aim of the project was to design and construct a 2-dimensional sprite based video game for the PlayStation Vita. It was required to make use of a GameObject class and have some form of collision detection.
The created application is a basic Metroidvania. The term “Metroidvania”, popularised by game critic Jeremy Parish (1996-2007), defines a videogame in the style of Nintendo’s Metroid series and Konami’s Castlevania series. Common features of the genre include 2-D side scrolling, platforming mechanics, action orientated gameplay, a large area to explore and the collecting of items that improve the player or allow them to explore new areas.
The application has all of these features implemented. There are many different areas that the player can journey through by the use of doors. Basic platforming allows the player to traverse these areas by jumping and falling. The player can fight enemies with a gun that fires projectiles or a sword that inflicts damage upon contact. Although the completed game does not have the amount of content that would be expected from a typical Metroidvania, with the framework in place, more content, such as additional areas, items and enemies, could be added with minimum difficulty.
Application Design
The program was planned to contain an application class called Game and a sprite class called GameObject.
Game would contain the main loop where all the game logic would run. This includes keeping track of the game state, rendering sprites on the screen, taking inputs from the player and updating the game objects.
The GameObject would be used for any item that would appear on screen, allowing them to be moved around the screen in different ways and collide with each other. It would also store any necessary information such as velocities or health.
The programmer intended to have three classes that would inherit from GameObject called Player, Weapon and Map, respectively.
The Player class would be used to manage the main sprite that the player controlled. It required some basic physics to allow the player to jump, more complex collision resolutions and it needed to keep track of the in-game items that the player collected.
The weapon class would be used to give the player the ability to fight off enemies. It was designed so that it could be aimed in a chosen direction, fire projectiles and damage enemies.
The Map class was planned to create different rooms for the player to explore. It would create enemies, platforms and doors, clear the room of GameObjects and change to a new room when required, store all the items that the player could collect and keep track of all the enemies, platforms and doors.
Techniques Used
The application heavily utilised GameObjects colliding with each other. This was done with bounding box collision detection. A function takes the positions, widths and heights of two GameObjects. These are used to get the x-coordinates and y-coordinates of the left, right, top and bottom sides of the boxes. It then checks that none of the sides are overlapping. If there is any overlap with the sides then the function declares that a collision has occurred.
The main feature of the application were the 2-D platforming mechanics. Set values were used for the players’ initial vertical velocity, vertical acceleration and max vertical velocity and a boolean variable was used to keep track of when the player was standing on a platform and in the air.
Every iteration of the game loop, the player’s vertical velocity is added to its y-coordinate. When the player is standing on a platform and the left analogue stick is pushed up, the initial vertical velocity is subtracted from the player’s downwards velocity. This causes the player to be propelled upwards. As long as the player is in the air, the vertical acceleration is added to the velocity. Eventually the velocity reaches zero, then keeps increasing, making the player fall. The velocity is prevented from exceeding the max vertical velocity. As long as the player is falling, the application will loop through all the platforms, checking for a collision with the player. When a collision is found, the player is moved to the top of the platform it collided with and its velocity is clamped to zero.
The weapon had three different features; aiming in the direction of the right analogue stick, firing projectiles across the screen and hitting enemies.
It gets the direction of the right analogue stick by finding the arctangent of the analogue sticks’ axis coordinates. The weapon is then rotated to face this direction. In order to get the weapon to rotate from the point where it meets the player, rather than rotate around its centre, offsets are added to its x and y coordinates. These are calculated using the sine and cosine of the direction which are multiplied by the length of the offset.
When the right analogue stick is pushed in a direction, a new GameObject is created which acts as a projectile. A value is assigned to be the weapon’s rate of fire and is used to limit the rate at which new projectiles are created. When a projectile is created it is added to a vector of projectiles. This vector gets looped through every iteration of the game loop and each projectile is moved forward in the direction of the right analogue stick. The projectile is deleted if it collides with an enemy or the edge of the screen and if it collided with an enemy, then the enemy takes damage.
When the weapon is in melee mode, it cannot fire projectiles. The game will determine if the player is using the analogue stick or the sword and change the weapon properties accordingly. The game loops through every enemy and if the weapon collides with any of them, then they are knocked back and take damage.
The game has different rooms that the player can explore. In the map class there is a function, called ChangeRoom that changes the room with the use of a switch statement. The map class has three functions to create room specific GameObjects. These GameObjects are enemies, platforms and doors. Three vectors are used to store these GameObjects. When created their properties, such as their positions and sizes, are initialised. The ChangeRoom function loops through the vectors and deletes all the previous rooms’ GameObjects. Its switch statement will then determine what the current room is and add the rooms’ enemies, platforms and doors to their respective vectors. The ChangeRoom function is called whenever the player collides with a door.
User Guide
The user starts the game by pressing the start button when prompted. The user can then pause the game at any time by pressing the start button and unpause the game by pressing the start button again. The player moves with the left analogue stick. Pushing it left moves the player left and pushing it right moves the player right. Pushing it up allows the player to jump. The weapon is controlled with the right analogue stick. It always turns to face the direction that the analogue stick is facing. When the weapon is in ranged mode and the analogue stick is pushed in a direction, the gun will fire in the same direction. When the player has picked up the stick or the sword, they can use the weapon’s melee mode by holding the right shoulder button. Whilst in melee mode the weapon will not fire but it will damage enemies and knock them back upon contact. The aim of the game is for the player to explore the rooms, collecting items as they go, and eventually reach the objective in the last room. Picking up items will output message that the user can dismiss by pressing the x button when prompted. Some rooms will require keys to open that the player can find throughout the game. When the player runs out of health, they will get a game over. Pressing the start button on the game over screen will take the user back to the start screen.
Critical Analyse
Rodrigo Monteiro (2013) detailed four major ways that a 2-D platformer could be implemented. The programmer chose to take a vectorial approach where they would resolve movement and collisions themselves. This proved to be too time consuming with the amount of features that were planned to be implemented so a very simplified version of this was done. The simplified version always moves the player to the top of a platform when it collides. Conventionally, this should only happen when the player collides with the top of the platform. Colliding with the sides or bottom of the platform should just push the player to the edge of the collision. The platforming mechanics could have been greatly improved by either using a physics engine, such as Box2D or cutting out other features in order to dedicate more time to these mechanics.
A lot of the code could have been abstracted more. In particular, a lot of the functionality of the weapon takes place in the main game loop rather than the weapon class. This includes all of the shooting mechanics, such as firing the weapon and updating the projectiles.
Rather than having the game logic in the same class as the game state control, another class could have been made to manage the game. This would leave the application class to access different states, including the game manager class as one of these states. As a result, implementing the start and game over screens would have been easier and the start screen could have easily been expanded into a menu.
The rooms should be able to vary in size like most Metroidvanias. This couldn’t be implemented though since it caused the doors to behave strangely as a result of their positions being based on the edges of the rooms. The position of the room edges would have needed to be dynamically updated with the sizes of the room or they would need to have been pre-defined for all the possible room sizes. Fixed room sizes would have still been rather limiting and to get the edges to dynamically update, the door creating function would have needed to be altered in some way.
The rooms are created by hard coding positions for every object. A much better solution would be to use some form of level loader. Then the level loader could be used in conjunction with level editing software. This would make the process of creating rooms much quicker and easier.
References
Parish, J. 1996-2007. Metroidvania. [online] Available from: http://www.gamespite.net/toastywiki/index.php/Games/Metroidvania [Accessed 4 January 2014]
Monteiro, R. 2013. The Guide to Implementing 2D Platforms. [online] Available from:
http://www.gamedev.net/page/resources/_/technical/game-programming/the-guide-to-implementing-2d-platformers-r2936 [Accessed 20 October 2013]
The application heavily utilised GameObjects colliding with each other. This was done with bounding box collision detection. A function takes the positions, widths and heights of two GameObjects. These are used to get the x-coordinates and y-coordinates of the left, right, top and bottom sides of the boxes. It then checks that none of the sides are overlapping. If there is any overlap with the sides then the function declares that a collision has occurred.
The main feature of the application were the 2-D platforming mechanics. Set values were used for the players’ initial vertical velocity, vertical acceleration and max vertical velocity and a boolean variable was used to keep track of when the player was standing on a platform and in the air.
Every iteration of the game loop, the player’s vertical velocity is added to its y-coordinate. When the player is standing on a platform and the left analogue stick is pushed up, the initial vertical velocity is subtracted from the player’s downwards velocity. This causes the player to be propelled upwards. As long as the player is in the air, the vertical acceleration is added to the velocity. Eventually the velocity reaches zero, then keeps increasing, making the player fall. The velocity is prevented from exceeding the max vertical velocity. As long as the player is falling, the application will loop through all the platforms, checking for a collision with the player. When a collision is found, the player is moved to the top of the platform it collided with and its velocity is clamped to zero.
The weapon had three different features; aiming in the direction of the right analogue stick, firing projectiles across the screen and hitting enemies.
It gets the direction of the right analogue stick by finding the arctangent of the analogue sticks’ axis coordinates. The weapon is then rotated to face this direction. In order to get the weapon to rotate from the point where it meets the player, rather than rotate around its centre, offsets are added to its x and y coordinates. These are calculated using the sine and cosine of the direction which are multiplied by the length of the offset.
When the right analogue stick is pushed in a direction, a new GameObject is created which acts as a projectile. A value is assigned to be the weapon’s rate of fire and is used to limit the rate at which new projectiles are created. When a projectile is created it is added to a vector of projectiles. This vector gets looped through every iteration of the game loop and each projectile is moved forward in the direction of the right analogue stick. The projectile is deleted if it collides with an enemy or the edge of the screen and if it collided with an enemy, then the enemy takes damage.
When the weapon is in melee mode, it cannot fire projectiles. The game will determine if the player is using the analogue stick or the sword and change the weapon properties accordingly. The game loops through every enemy and if the weapon collides with any of them, then they are knocked back and take damage.
The game has different rooms that the player can explore. In the map class there is a function, called ChangeRoom that changes the room with the use of a switch statement. The map class has three functions to create room specific GameObjects. These GameObjects are enemies, platforms and doors. Three vectors are used to store these GameObjects. When created their properties, such as their positions and sizes, are initialised. The ChangeRoom function loops through the vectors and deletes all the previous rooms’ GameObjects. Its switch statement will then determine what the current room is and add the rooms’ enemies, platforms and doors to their respective vectors. The ChangeRoom function is called whenever the player collides with a door.
User Guide
The user starts the game by pressing the start button when prompted. The user can then pause the game at any time by pressing the start button and unpause the game by pressing the start button again. The player moves with the left analogue stick. Pushing it left moves the player left and pushing it right moves the player right. Pushing it up allows the player to jump. The weapon is controlled with the right analogue stick. It always turns to face the direction that the analogue stick is facing. When the weapon is in ranged mode and the analogue stick is pushed in a direction, the gun will fire in the same direction. When the player has picked up the stick or the sword, they can use the weapon’s melee mode by holding the right shoulder button. Whilst in melee mode the weapon will not fire but it will damage enemies and knock them back upon contact. The aim of the game is for the player to explore the rooms, collecting items as they go, and eventually reach the objective in the last room. Picking up items will output message that the user can dismiss by pressing the x button when prompted. Some rooms will require keys to open that the player can find throughout the game. When the player runs out of health, they will get a game over. Pressing the start button on the game over screen will take the user back to the start screen.
Critical Analyse
Rodrigo Monteiro (2013) detailed four major ways that a 2-D platformer could be implemented. The programmer chose to take a vectorial approach where they would resolve movement and collisions themselves. This proved to be too time consuming with the amount of features that were planned to be implemented so a very simplified version of this was done. The simplified version always moves the player to the top of a platform when it collides. Conventionally, this should only happen when the player collides with the top of the platform. Colliding with the sides or bottom of the platform should just push the player to the edge of the collision. The platforming mechanics could have been greatly improved by either using a physics engine, such as Box2D or cutting out other features in order to dedicate more time to these mechanics.
A lot of the code could have been abstracted more. In particular, a lot of the functionality of the weapon takes place in the main game loop rather than the weapon class. This includes all of the shooting mechanics, such as firing the weapon and updating the projectiles.
Rather than having the game logic in the same class as the game state control, another class could have been made to manage the game. This would leave the application class to access different states, including the game manager class as one of these states. As a result, implementing the start and game over screens would have been easier and the start screen could have easily been expanded into a menu.
The rooms should be able to vary in size like most Metroidvanias. This couldn’t be implemented though since it caused the doors to behave strangely as a result of their positions being based on the edges of the rooms. The position of the room edges would have needed to be dynamically updated with the sizes of the room or they would need to have been pre-defined for all the possible room sizes. Fixed room sizes would have still been rather limiting and to get the edges to dynamically update, the door creating function would have needed to be altered in some way.
The rooms are created by hard coding positions for every object. A much better solution would be to use some form of level loader. Then the level loader could be used in conjunction with level editing software. This would make the process of creating rooms much quicker and easier.
References
Parish, J. 1996-2007. Metroidvania. [online] Available from: http://www.gamespite.net/toastywiki/index.php/Games/Metroidvania [Accessed 4 January 2014]
Monteiro, R. 2013. The Guide to Implementing 2D Platforms. [online] Available from:
http://www.gamedev.net/page/resources/_/technical/game-programming/the-guide-to-implementing-2d-platformers-r2936 [Accessed 20 October 2013]