Both systems take in a game|test
argument:
game
builds and runs the full gametest
builds and runs tests for item serialization and potion comparison mechanics- If no arguments are supplied, the scripts default to
game
.\run [game|test]
Note that on some Windows configurations, CMake may place the game executable in the /build/Debug
folder. If the script fails, the executable is most likely there and can be run directly.
Requires freetype
to be installed. On macOS, use brew install freetype
.
chmod +x run.sh
./run.sh [game|test]
- Textured Geometry:
- All our game sprites and background environments are textured assets.
- The drawing order is implemented in
std::vector<Entity> RenderSystem::process_render_requests
, with documentation for how the different rendering layers work.The order of rendering is specified in the ENUMRENDER_LAYER
in components.hpp. - Rendering is done in render_system files, texture_paths are specified in render_system.hpp. They are also added to the ENUM
TEXTURE_ASSET_ID
, and utilized in world_init.cpp when added as a renderRequest.
- Basic 2D transformations:
- The assets in our game are scaled to a certain size, and transform, scale and rotation can be applied to entities in the game, in void RenderSystem::drawTexturedMesh(Entity entity, const mat3& projection).
- Key-frame/state interpolation:
- When entering the grotto, a fade in and out non-linear effect is played to transition.
- Fade fragment and vertex shaders are added to achieve the fading effect. From render_system.cpp, we get the current screen texture, and the darken_screen_factor which comes from our screen state. We pass in the texcoord from the vertex shader.
- Our fragment shader gets the current screen’s in_color using texture(screen_texture, texcoord). If the darken_screen_factor is 0, we keep the fade completely transparent since its background texture is black. However, when the factor begins to increase above 0, this indicates that we are changing between biomes so we use linear interpolation with the mix function to interpolate between the screen’s current color and fully opaque black.
- The alpha channel of the color returned by the shader is updated to match the darken_screen_factor to change the transparency of the fade.
- Keyboard/mouse control:
- Keyboard control is done in world_systems.cpp, on_key() function. Movement with WASD:
- If multiple keys are pressed, the player will move in the direction of the most recently pressed key. If the key corresponding to the direction that the player is currently moving is released other keys are being released, the player will move in the direction of the second most recently pressed key and work its way back until no more keys are pressed. Interaction with F:
- Item pickup: handled in world_systems.cpp, handle_player_interaction() function Enter grotto: handled in world_systems.cpp, handle_entrance_interaction
- Random/coded action:
- After an item is picked up, it respawns in 5-15 seconds at the same location.
- This is done in world_system.cpp, handle_item_respawn().
- Well-defined game-space boundaries:
- The player is unable to walk past the bounds of the forest, or into the river unless on the bridge. The player cannot leave the grotto bounds, or go into the wall of the grotto
- The positions are currently hardcoded for each biome and can be found in biome_boundaries of common.cpp which define the position and scale of the boundary lines. When the world system is initialized, it will render the boundaries based on the current biome the player is in.
- Simple collision detection & resolution (e.g. between square sprites):
- We are using AABB collision detection, with a terrain component that has fields collision_setting, width_ratio and height_ratio to draw a bounding box centered at the bottom middle of the entity. 0 Collision detection is handled in physics_system.cpp, bool collides() for each step of our physics system. Collision resolution is in WorldSystem::handle_collisions(), which prevents players from walking into entity bounding boxes
-
Test plan: Uploaded to
/doc/test-plan.docx
-
Bug report: Uploaded to
/doc/bug-report.xlsx
-
Demo video https://www.youtube.com/watch?v=Tv99njp9Pmo
Player inventory state is being persisted and reloaded in item_system.cpp
through use of the nlohmann/json
JSON library, as approved in this private Piazza post: https://piazza.com/class/m5kml0k6fxs2sz/post/203.
We are saving all Item-associated components in the player’s inventory, serializing it into the JSON format, and persisting it in build/game_state.json
before the game closes through the saveGameState
function. When the game relaunches, we read and restore entities & components to our registry based on that file from our loadGameState
function.
To observe reloadability working directly in the game, refer to the test plan. The window title header of the game also reflects persisted inventory information.
Assets are digitally-drawn with Procreate (a graphics editor app). They are added into the game as background and interactive objects (magical fruit, cocoa bean).
- The backend of our potion making system has been implemented to greatly facilitate our progress in M2.
- Recipes are defined in
common.hpp
and include a list of required ingredients, as well as a list of actions that must be followed in order to create the highest quality potion of that type. - The
potion_system.hpp
file defines several functions that can be used to update the state of cauldron entities, and fetch a potion from a cauldron if needed. - Every time a cauldron is updated, the system calculates the type and quality of the potion currently in the cauldron, updating its color and fading the cauldron’s current color towards the updated color.
- The exact method used to calculate the type and quality of a potion based on the given list of recipes is documented in the header function
PotionSystem#updatePotion
.
IMPORTANT (Kevin): If you previously ran Milestone 1, there are breaking changes to our persistence structure for Milestone 2. You will need to remove the /build/game_state.json
file for the game to run.
Both systems take in a game|test
argument:
game
builds and runs the full gametest
builds and runs tests for item serialization and potion comparison mechanics- If no arguments are supplied, the scripts default to
game
.\run [game|test]
chmod +x run.sh
./run.sh [game|test]
- Improved AI: Enemy behavior is based on a decision tree with four states: Attack, Wander, Return, and Idle. In Attack, the enemy chases when the player gets too close. If the player gets away, the enemy switches to Wander and moves around randomly for a short time, then it enters Return, heading back to its spawn point. It stays in Idle until the player comes back into range.
- Improved Sprite Animations: The player now has a walking animation, so that as you move around the WASD keys, you can see the player animation. This is handled in WorldSystem::updatePlayerWalkAndAnimation(), and the frames for the assets are hand drawn.
- Improved Gameplay and Assets: We’ve included more background assets and sprites to support our game, such as the new desert, enemies and potion making menu. Players are able to interact with the cauldron and follow a series of steps to make a potion, improving the gameplay.
- Mesh-based Collisions The bridge now uses mesh-based collision detection and resolution. The top of the bridge and the bottom of the bridge have defined mesh .obj files that are rendered onto the screen. When the player’s bounding box intersects with any triangle in the mesh, this will be detected as a collision in physics_system, using barycentric coordinates to see if a line of the box intersects with the triangle
- Gameplay Tutorial
- Uses RmlUi to display tutorial steps and updates when the player has completed the step
- Welcome message and WASD movement - complete on pressing any WASD key
- Fruit collection - complete on collecting 3 magical fruits or having 3 in inventory
- Combat and inventory selection - complete on defeating the enemy with 3 fruits
- Entering grotto - complete on interacting with grotto entrance
- Open potion making menu - complete on interacting with cauldron
- Heat knob - turn to H
- Add 5 coffee beans and 3 fruits
- Stirring - complete on picking up the ladle and successfully drawing a circle in cauldron to stir 3 times
- Pick up empty bottle and left click on cauldron to fill up a potion
- FPS Counter Displayed in the title and updates every 500ms.
- 2 minutes of non-repetitive gameplay Gameplay is illustrated by our demo video and the test plan walkthrough.
- Minimal lag Demonstrated by FPS counter in the screen title.
- Updated test plan
Uploaded to
/doc/test-plan.docx
- Updated bug list
Uploaded to
/doc/bug-report.xlsx
- Demo video https://youtu.be/Qz-uyPb_oww
We integrated RmlUi to facilitate integral game UIs such as the potion making menus, tutorials, and inventory bar. This integration will continue to remain in the game, supporting additional features like game HUDs and our inventory chest menu. RmlUi was approved by Kevin Huang in tutorial, based on our private Piazza post: https://piazza.com/class/m5kml0k6fxs2sz/post/271
RmlUi also packages FreeType for use in our game.
Relevant RmlUi code can be seen in ui_system.cpp
, ui_system.hpp
, rmlui_render_interface.cpp
, and rmlui_system_interface.cpp
.
RmlUi GitHub: https://github.com/mikke89/RmlUi
Users can now use their mouse to interact with the potion making menu. Mouse gestures include clicking on the ladle to pick it up, then dragging it into the cauldron which will update the ladle sprite. Then users can move their mouse in a circular motion to “stir” the cauldron. Users can also interact with the heat knob with their mouse by left clicking and dragging the knob. Users can also click on the empty potion bottle and drag it over the cauldron to bottle a potion.
Playability (15%):
Sustain progressive, non-repetitive gameplay for at least 5 minutes. Within this five minutes, demonstrate all of the new features (with minimal oral instructions).
- We have an updated tutorial for the new game flow and features - players are free to explore and discover how to complete the game afterwards.
During the 5 minutes, the player should be able to interact with the game and see new content for most of the time.
- While playtesting our game, we have an average playtime of ~20 minutes for the full completion of the game. Our friends who playtested took about 40 minutes to get halfway. Note: we probably won’t be adding additional gameplay elements for the final milestone since we’ve completed the game loop, just improvements.
Memory management (5%)
- Our components are consistent between biome switches. New entities are created every time a collision is detected but this was part of the provided starter code.
User Input (5%)
All user input is handled accordingly.
Realtime Performance (5%)
- We noticed the FPS would drop significantly upon longer gameplay and found the root cause to be the constant inventory UI updates. We updated the UI system so that the inventory, effects, and health bar would only be updated when its corresponding entity was modified. This brought us back to a stable FPS. We do see occasional FPS drops when we open the cauldron menu but it stabilizes after a couple of seconds.
Stability (15%):
Include fully completed and playable prior-milestone implementations.
Fix all bugs identified in prior marking sessions.
- We resolved all prior bugs except for “Adding item to cauldron removes multiple counts from player inventory” which we will mark as “Will not fix”. This is because the issue appears in an unlikely, difficult to reproduce edge-case, when sometimes adding 12 of the same item into a single potion. This bug was originally discovered during limit-testing, and is not part of our game loop. None of our potion recipes require adding more than 3 of the same item.
- The game resolution and aspect ratio are consistent across different machines/displays.
- We now support full screen as part of this milestone.
The game code should support continuing execution and graceful termination, with no crashes, glitches, or other unpredictable behaviour.
- Game execution is continuous and the game terminates with stable persistence.
- We have not identified any crashes at the time of submission.
Updated test plan uploaded to /doc/test-plan.docx
Updated bug list with open and closed bugs uploaded to /doc/bug-report.xlsx
M3 Video Submission: https://www.youtube.com/watch?v=bLyz9KP83AY
- Full screen
- Dynamic textboxes with RmlUI
- Updated tutorial for new game flow and features
- Mortar and pestle menu
- Recipe book menu
- 3 new biomes + redesigned forest
- 3 guardians
- All the potion recipes and ingredients
- Consumable potions have functionality and potions are now throwable
- Unlocking the biomes with potions + master potion pedestal
- Potion qualities and varying effects based on quality (5 stars)
- Timer in potion menu
- Sound effects and background music
- Potion effects display and health bar
- Red flash on taking damage
- Notable Bug Fixes: Adding empty inventory slot to cauldron caused crash, players can now move and slide along terrain if not all the directions are blocked
Physics Based Animation (Advanced)
- The cauldron has water fluid simulation now for stirring and heating
Audio Feedback (Basic)
- Background music (from Hollow Knight) and we created sound effects for interacting with terrain
Simple rendering effects (Basic)
- Enemies and player flash red when taking damage. Upon taking damage, the player gains immunity for one second and can’t be injured until immunity passes.