Ludus ante Portas

About the game

Ludus ante Portas was a game that could be played on the famous landmark of the city of Trier, the ‚Porta Nigra‘. The game was developed as part of the ‚Design und Kulturtage Trier‘. A maximum of 10 players were able to play the game at the same time and the players were divided equally into two teams.

The players in the team of the Romans tried to protect the Porta Nigra by holding up their shields and repairing broken pillars. The players in the Germanic team tried to destroy the Porta Nigra with their catapults. If they managed to destroy a certain number of pillars, they won. The team of the Romans won through surviving the night of the attack.

My tasks

This project was the first time I got to work with the Unity3D engine. Thanks to many online tutorials I was able to learn the basics quickly. At the beginning of the project I had the tasks to implement effects and animations. Some of the effects I implemented were for example the rustling of bushes or the flickering of a candle flame.

I implemented the rustling effect of the bushes by using a particle system with leaves as particles. The particle system was then activated by hitting the bush with a projectile. Fortunately the engine provides a function that is automatically triggered by a collision event with a trigger collider. Within this function I tested whether a projectile has hit the collider or not. If a projectile hit the collider, the particle system was activated. After a certain amount of time, using a coroutine, the particle system was then turned back off again.

Show code
void OnTriggerEnter(Collider other){
   if (!hit && other.tag != "Projectile"){
      hit = true;
      ...
      else if (other.tag == "bush"){
         other.GetComponent().hasBeenHit();
         aSource.volume = 0.30f;
         aSource.PlayOneShot(hitPillar);
      }
      ...
}



The flickering of the candle flames was implemented in the same way. In addition, the flame was scaled up and down permanently to create a burning animation.

Due to the indisposition of many group members, I took on a variety of other tasks. These included organization of the group, bug fixing, implementation of the player controls and creating the animation tree for the main characters.

The organization of the 38 people group turned out to be a huge challenge. First I decided to use the organsization tool called ‚Trello‚. I hoped that this tool would help to provide a structured working flow throughout the project. Just using Trello as tool for organization turned out to be insufficient. As a solution, I arranged weekly meetings and prototype tests. Having some kind of weekly schedule helped the team a lot the accomplish milestones faster.

In retrospect

Looking back I would do the following things differently:

  • Team size
    With 38 people, the group was too big for a project of this size. Due to the high number of people many people had no tasks or worked on the same parts. A group size of 3 programmers and 4-5 designers would be far more adequate to realise this project.
  • Team Leader
    My assignment as team leader was very late in the project. In order to realise the project smoothly, a team leader should be deployed faster.
  • Animations
    As already mentioned, I implemented an animation via script. Unity provides an animation system which is suited better for this task.


    Diese Diashow benötigt JavaScript.

Werbeanzeigen

Ork Commander

About the game

‚Ork Commander‘ was a recreational project where the player had to build a base and equip his units with the appropriate equipment. Whether the army of the player was effective against the attackers or not depended on the provided equipment. The goal of the game was to destroy the enemy base. The project was realised in the Unity3D engine.

My tasks

My tasks were the implementation of a rasterized construction system associated with an user interface as well as a direction-controlled road system. We decided that the construction area of the player should be predetermined to a limited area. That’s why I decided to initialize every point in the grid of the construction area as a gameobject. In addition to this object a sprite was created which was then used to visualize collisions with other objects.

Show code
for (int x = 0; x < m_FieldLength; x++)
   for(int z = 0; z < m_FieldWidth; z++){
      m_TileGrid[x, z] = Instantiate(m_1x1Tile, new Vector3(0.5f + x, 0.0f, 0.5f + z), m_TilesAndSpriteRotation) as GameObject;
      m_TileGrid[x, z].layer = 14;
      m_TileGrid[x, z].tag = "ConstructionTile";
      m_TileGrid[x, z].name = "Tile ID: " + x + ";" + z;
      m_TileGrid[x, z].transform.SetParent(tmp_THolder.transform);
      ...
      m_SpriteGrid[x, z] = Instantiate(m_SpriteObject, new Vector3(0.5f + x, m_Höhe, 0.5f + z), m_TilesAndSpriteRotation) as GameObject;
      m_SpriteGrid[x, z].transform.SetParent(tmp_SHolder.transform);
      m_SpriteGrid[x, z].name = "CollisionSprite ID: " + x + ";" + z;
      ...
   }



In case of a collision between a point in the grid and an object in the world, the associated sprite was marked as non-buildable and a corresponding entry was placed in the logic of the building area.

Show code
if(Physics.CheckSphere(spherePos, 0.40f)){
   m_PlacementLogic[x, z] = (int)m_TileTypes.building;
   m_SpriteGrid[x, z].GetComponent().sprite = m_CollisionSprite;
}
m_SpriteGrid[x, z].SetActive(false);



Building a structure was controlled via raycasts. The raycast was used to determine at which point of the grid the placement was attempted.

 if Physics.Raycast(m_MouseRay, out m_MouseObject, Mathf.Infinity, m_MouseDetectingLayers))



In an area around this point was then checked whether the placement of the building was possible or not. The size of the area depended on the size of the building.

The directional road system was a much heavier task compared to the construction system. In addition to the requirement of the directional control it was also necessary to move the units correctly on the roads, that the units were routed into buildings and that streets were adapted to neighboring streets.

I implemented the direction control in a way that a road was marked with a special type in each direction. This type was either a wall, an entrance or an exit. The adjacent streets were then adapted to the newly placed street depending on its types.

Show code
switch (p_Direction){
   case 0:
      if (script.GetNorthWay() == m_DoorTypes.wall)
         script.SetNorthWay(m_DoorTypes.exit);
      if (script.GetSouthWay() == m_DoorTypes.wall)
         script.SetSouthWay(m_DoorTypes.entrance);
   break;
   case 1:
      if (script.GetEastWay() == m_DoorTypes.wall)
         script.SetEastWay(m_DoorTypes.exit);
      if(script.GetWestWay() == m_DoorTypes.wall)
         script.SetWestWay(m_DoorTypes.entrance);
   break;
   ...
   default:
      Debug.Log("INVALID DIRECTION");
      break;
}


The correct routing of the units was controlled by the road system. Each unit polled the system for information about the next road. The unit moved forwards after the system returned a positive message.

Show code
public bool IsThereAWayForward(Vector3 p_Position){
   int x = (int)p_Position.x, z = (int)p_Position.z;
   Doorways_Script Script = m_Doorways[x, z];
   if (z + 1 < m_MainConstructor.m_FieldWidth && Script.GetNorthWay() == m_DoorTypes.exit &&
   m_Doorways[x, z + 1].GetOccupationStatus() == false &&
   m_Doorways[x, z + 1].GetSouthWay() == m_DoorTypes.entrance)
      return true;
   ...
   return false;
}



Proper forwarding to buildings was controlled by triggers. If a unit moves into the trigger of a building the building checks for available capacities. If capacities were available the unit was directed into the building.

Show code
void OnTriggerEnter(Collider other){
   if (other.tag == "Unit" && !other.GetComponent().m_AlreadyEquipped){
      if (selectedBody!=null || selectedLeftHand!=null ||
      selectedRightHand!=null)
         StartCoroutine(startEquip(other.gameObject));
   }
}



Working on this project was one of the most difficult and nerve-wracking experiences I had in my studies. Nevertheless, the result motivated me a lot. In retrospect, I would research for more information about systems and not develop them „from the gut“.

Diese Diashow benötigt JavaScript.

Chaos God

About the game

The game ‚Chaos God‘ was born during my first Global Game Jam. The goal of the game was to bring as much harm as possible to the world. The player got to the god of chaos. This god could perform various rituals in order to spread chaos in the world. Our team choosed a 2.5D look which was strongly inspired by the survival game ‚Don’t Starve‘. The project was realised in the Unity3D engine.

My tasks

Beside game design my tasks included to implement the logical representation and execution of the available rituals as well as their presentation in an user interface. I did not have any experiences in the area of user interfaces and therefore selected these tasks on purpose.

The rituals could be performed by combining three different items out of the players inventory. I decided to use a XML document to represent the rituals. Using a XML document should make it easier to add rituals to the game while providing a good overview over their structure.

Ritual XML Document
Chaos God – Ritual XML Document

After the game was started all rituals were loaded from the XML document, saved and processed in order for the player to use them while playing.

Show code
private void LoadRituals(){
   XmlDocument xmlDoc = new XmlDocument();
   xmlDoc.LoadXml(GameAsset.text);
   XmlNodeList ritualsList = xmlDoc.GetElementsByTagName("Ritual");    foreach (XmlNode ritualInfo in ritualsList){
      XmlNodeList ritualcontent = ritualInfo.ChildNodes;
      obj = new Dictionary();
      foreach (XmlNode ritualItems in ritualcontent){
         if (ritualItems.Name == "name"){
            obj.Add("name", ritualItems.InnerText);
         }
         if (ritualItems.Name == "object"){
            switch (ritualItems.Attributes["name"].Value){
               case "Item1": obj.Add("Item1", ritualItems.InnerText); 
               break;
               ...
            }
         }
      }
      rituals.Add(obj);
   }
}



Another task of mine was to make sure that objects reacted to casted rituals. I created scripts which could be applied easily to an object. Within these scripts the needed behaviour had to be implemented via code. Our team decided to use sprite swapping in most cases.

The next task of mine was to create a user interface where the player could easily access and cast the different rituals. I decided to display the individual objects in a grid, as this was a typical representation of inventories in rollplaying games.

Inventory

Chaos God – Inventory

When selecting an item, its image and description were displayed in an additional information window. Using an item made it appear in the ritual circle on front of the player character.

Casting a Ritual

Chaos God – Casting a Ritual

In retrospect

In retrospect, I would implement my duties differently. The usage of an XML document and the associated effort to read this document could easily be circumvented by implementing it as a class or struct. My argument was that rituals could be added and be displayed in a simple way. In such a small game an approach like that was not necessary and a waste of time.

In addition, I would implement the user interface in different way. I would no longer manually create and place each item in the inventory but create them at runtime and then position them using vertical and horizontal layout groups. And finally, I would no longer work with string comparisons. These are costly and can have a negative impact on the performance of the game when used heavily.

Ultimately, I can say that this weekend was a lot of fun. Everyone shared my enthusiasm for games and their development. We helped each other and talked shop together. I hope to later work in an company with the same kind of atmosphere.

Diese Diashow benötigt JavaScript.