Final Project Report: Google Summer of Code


Github Repositories:
Light And Shadow: https://github.com/Terasology/LightAndShadow -- The main module for the GSoC project
Light And Shadow Resources: https://github.com/Terasology/LightAndShadowResources -- Art resources for Light and Shadow

Project Overview:
This project builds upon the existing Terasology game engine, creating a Minimum Viable Product (MVP) for a Capture the Flag game mode in Terasology's Light and Shadow module. While the module already had some work done on it, including much discussion about the module's implementation, aesthetic, and some art completed in Light And Shadow's art and assets module.

I looked at the existing module and how to add a Capture the Flag game mode that fit with the aesthetic of the world as well as one that was fun and functional. To that end I created a new world generator that created a simple world for the Capture the Flag game mode with two bases, flags, and let players steal flags from one another and score.

Completed Work:
World Generation:
To begin, I created a simple world generator that would hold the Capture the Flag bases and flags. The module had a previously created platform that players would spawn at, so I included this in the new world generator for players to spawn into the world.

The world consists of a flat plane with two bases (colored red for the red team's base and black for the black team's base at some distance apart, with a flag that appears on each base. For the floating platform that the player spawns at, I created two teleporters (red and black) that the player could use to choose their team and teleport down into the world.

The player's spawn platform, with a talking NPC and red and black team teleporters

The basic idea in world generation and item placement is to define the region in which specific blocks should be placed, and then to place blocks in that region with a rasterizer.

For instance, BaseProvider (part of the system used to create the bases in the world) defines a specific region for the base:

with BASE_EXTENT being a set value for how many tiles wide the base is from the center. Then the BaseRasterizer fills in these regions with blocks in the world generation for the red and black bases:



Red and black bases placed into the world

Pull requests:
Simple World Generator and Base / Flag Generation: https://github.com/Terasology/LightAndShadow/issues/64
Changes base blocks to be red/black depending on base instead of gray stone: https://github.com/Terasology/LightAndShadowResources/pull/30

Teams and Attack Mechanics:
Next I focused on one of the core aspects of the game--being put on a team and being able to steal the flag.

Teams are handled through a component added to the player at game start called LASTeamComponent. This component holds information about the team the player is on, in this case a String with the team of the player (ex. "red", "black", "white"). By default, the player begins on the platform as the white (or neutral) team, which is added to the player on game start through a delta of the player.prefab which defines the String "team" of the LASTeamComponent:
"LASTeam" : {
"team" : "white"
}

When the player chooses a team and teleports into the world, the team field of the component is changed to the relevant team:


On teleporting down to the world, the player is also given a weapon with which to attack other players, and the player model is reskinned to match their team selection (from a white pawn to a red/black pawn). For the weapon, I created a magic wand item for players to tag one another. If the opposing player is holding a flag, the flag is dropped between the attacking player and the target player (removed from the target player's inventory and placed into the world). The first player to touch the flag picks it up. If a player from the same team as the flag being picked up takes the flag, it is sent back to the team's home base.

Being able to pick up the flag from the base is handled through a component on the flag (TakeBlockOnActivate). The TakeBlockOnActivationSystem checks when a player activates the flag (pressing E) to see whether the team of the flag is different from the team of the player, If so, it removes the flag from the world and places it in the player's inventory:

The flag is set as indestructible so that the players can't just attack the flag while it is on the base to take it.

The attack mechanic in the game happens similarly. The magic wand has a RaycastOnActivateComponent used to determine whether a weapon for attacking other players is held or not. The players themselves have a FlagDropOnActivateComponent on them to detect when they are activated by another player holding a magic staff. If they are attacked, the game searches through the target player's inventory to see if they are holding a flag:


The code also adds a particle effect on the players when they pick up a flag that is removed when the player drops the flag. The particle effects are either red hearts or black spades depending on whether the player is holding a red or black flag. This indicator can be seen by allies and enemy team members so that players can see who is currently holding a flag.

Player holding flag has particle effects placed on them

Pull requests:
Adds faction component to player, changes flag pickup logic, and starts player on platform: https://github.com/Terasology/LightAndShadow/pull/65
Adding flag prefab and code for activation: https://github.com/Terasology/LightAndShadowResources/pull/23
Player vs Player Combat Mechanics: https://github.com/Terasology/LightAndShadow/pull/68
Improvements to Capture the Flag attack system: https://github.com/Terasology/LightAndShadow/pull/69
Adds particle effects and textures for when flag is held: https://github.com/Terasology/LightAndShadowResources/pull/29


Scoring and UI:
To complete the gameplay loop, I worked on allowing players to score and added UI to indicate the player's score. Scoring works similarly to the code for attacking another player--when the player presses the activate button on a base block (detected through a component on the block), the game searches through the player's inventory to see if they have a flag. If they do, the score of that team increases, and the block is removed from the player's inventory and placed back at its home base. This score is kept track of using integer fields in the ScoreSystem.

To display the score to players, I created a HUD element where the values for the black score and red score are bound to the ScoreSystem's fields for the red and black scores. When a player scores, this sends an event to all clients that updates their HUD with the current score, so that score is properly synced and displayed across multiplayer:




Left: A view from the black team's player running with the flag
Right: A player watching the black team's player run towards the black team's base

Pull requests:
Adding beginning elements of score system and UI: https://github.com/Terasology/LightAndShadow/pull/67
Adding Client HUD and Score System: https://github.com/Terasology/LightAndShadow/pull/70
Fix for flag stealing and scoring not working in headless server + client setup: https://github.com/Terasology/LightAndShadow/pull/71

Conclusion:
The work for Google Summer of Code provides a working Capture the Flag game mode with support for multiplayer gameplay that features team-based collaboration, flag stealing, and scoring. Some features from the initial proposal did not make it into this summer's GSoC work (ex. weapon cooldowns) and other features not initially part of the MVP did make it into the game (ex. player skinning).

I do have several recommendations for future work, both for the MVP and for larger improvements beyond, which I detail below. The game is available to test and play as well, with more information about how to do so at the end of this post.



Future Work:

Partially Completed:

Some improvements to gameplay are partially completed, but still have some work to be done. One improvement is changing the symbols on the health HUD based on the team the player is on. This lets the player know which team they are on, and adds some flavor to the game. The player should start off with white circles on their health HUD, which change to red hearts or black spades depending on the team selected.

I also started work on improving player skinning, which makes the player's avatar no longer visible to them, and does not leave the model in the world when the player disconnects from the server.

Both of these work on singleplayer but do not currently sync correctly in multiplayer, so need more work before being merged.

Pull requests:

[WIP] Update to how player skinning on team selection is handled: https://github.com/Terasology/LightAndShadow/pull/72

[WIP] HUD now reskins with red hearts/black spades on team selection: https://github.com/Terasology/LightAndShadow/pull/73


Recommended Minimum Viable Product Improvements:

There are several features that I'd recommend adding to the MVP. The first is handling level reset for when one team reaches the set number of points to win. There should be some indication that a team has won (ex. UI popup screen), and the level should be reset with the world being regenerated and players moved back to the spawn platform.

There should also be improved terrain features, such as a maze, added to the world to create more variety and challenge in the Capture the Flag game mode. This would add more replayability to the game as well.

Possible future directions:

There are many possible long-term improvements to the game, including changing the way the start of the game is handled (team selection and round start), providing more player skins, and adding more weapons and abilities for players. They are listed in more detail in the Outbox section of the project board: https://github.com/orgs/Terasology/projects/11



Testing and Playing:

The game mode is available to play. Download Terasology, fetch the Light and Shadow module, and run the game in singleplayer or multiplayer, selecting the Light & Shadow gameplay template and the Light and Shadow (Simple) world generator.