Final Report (Building a Backbone for Building)

From EQUIS Lab Wiki

Jump to: navigation, search

Contents

Building a Backbone for Building

Summary

Most project goals were completed during the course of the term, with the concept of a village centre falling by the wayside, along with enforcing legal building placement. Project integration added a few additional requirements, and issues with the exercise bike as input called for a few more changes. Overall, the main advancements in the code were the addition of the building selection menu, the overhaul of the system that reads building information, and full integration with the quest system.

Project Approach

The beginning stages of the project focussed on exploring the provided body of code. It was felt that any changes to the code should both respect the architecture in place, and be consistent with style conventions and approach used in other code. Without a clear understanding of the structure of LIAV, it would have been impossible to implement any change while respecting the current purposes of each class in the existing structure. After spending 2 or 3 weeks to achieve a level of comfort, work on the changes associated with this project began.

A building system was already implemented in LIAV, though it did not actual work. That architecture is shown in figure 1. When the insert building button was pressed, the game would swing the camera to a top-down view, draw a new building on the screen, and then allow the user to cycle through a pre-defined set of buildings to insert. The building could be moved around on the terrain, as well as rotated. Eventually, the user could insert the building, which would permanently place the building and return the camera (and game state) back to normal. While functional, the system had several shortcomings:

File:Old building UML.JPG

Figure 1: Original Building System Architecture


1) Communication – Very little information was communicated to the user during the building process. If a building could not be built due to lack of resources, this was not communicated until the user actually clicked the final insert button. The user had no idea that a problem existed until the last stage of the process, and even then wasn’t informed how many resources were required but simply told that resources were insufficient.

2) Building Placement – No checks were made to ensure legal building placement. It was possible to insert a building on top of a tree, villager, other building, etc.

3) Architectural Issues – Almost all code to insert a building was placed into the InsertBuildingInGameState. This was problematic, in that the game states should be concise listings of a number of commands that need to be executed when the game is in a current state. By comparison, the other game states typically had very little code, and simply called other methods as needed to run the game at that state. In addition, the building code is very specific. A more generalized version could be abstracted out, allowing it to be used for other game functionalities outside of the scope of this project.

4) Loading of Building Data – When the first request to create a building (e.g. ‘log_cabin’) was made, the BuildingManager class would look for a file with that same name (e.g. ‘log_cabin.building’). If the file was not present, the game would crash (in fact, this was the error that caused LIAV as provided to fail when the insert building command was made). In addition, this approach forced the developer to always work with a known name; it was not possible to perform functions on the list of buildings.

These issues, once clearly outlined, added a few additional goals to the project as compared to the original proposal. The midterm list of project goals was as follows:

• Allow the player to insert buildings into the game.

• Provide a view that is useful for placing buildings in legal positions.

• Tie the building system into the resource system.

• Provide a useful menu that allows the player to easily select building types

• Enable the player to build ‘special’ buildings when certain conditions are met (for instance, as a reward for completing a quest). This goal was approached during integration and is now considered a sub-goal of the later integration tasks.

• Add construction-in-progress. Buildings start out as a construction site, and progress through a series of models. For example, this could progress by showing a bare construction site, a basic frame, a frame with a roof, a mostly finished building, and an occupied building.

• Enforce the concept of a village. Only allow buildings to be placed within a certain distance of your village centre. Allow the player to initially choose the village centre by placing a permanent marker.

• (NEW) Rewrite the load building data sections of code. Change it so that all building data is loaded from a single source in a single pass

• (NEW) Move some insert building functionality from the GameState class to a more appropriate location.

Integration and the final demonstration added a new set of issues that had not been previously considered, even at the time of the midterm progress report. The quest group had two requirements from the building code, relating to collectible items and quest rewards. Secondly, there were some issues related to the input of the game that caused problems with the menu, especially when the exercise bike was used. This two new issues are listed here:

• (NEW) Provide methods and building data tags to satisfy the needs of the quest group for integration. While one of the goals is indicated in the already existing goal of providing quest rewards, the actual integration included several other needs as well. Thus, the previous goal is subsumed by this goal.

• (NEW) Review and modify the input for the entire building process so that it functions properly regardless of the input type.

The remainder of this report will go through each of these goals in detail, discussing how the changes will affect the UI of the game, the art requirements of each change, the related milestones, and the implementation details.

Loading Building Data

When a building is first created, the system must go to an external .xml file and load the building data. If a building has not been used, the game is unaware of it. This prevents any other part of the game from generating a list of buildings for any operation. In addition, each building was described in its own .xml file, which is not consistent with other resources such as the concept.overlay file. The solution to this is quite straightforward – place all the building data in a single file and load that when the BuildingManager is created. When the BuildingManager is instantiated, the constructor calls a new method called loadBuildingData(). This goes to the new .xml file called buildings.liav that contains the building data for all buildings. In one pass, the data for each building is read from that file and loaded into a corresponding buildingData object. All of the data is now present within the game and can be used to create buildings or generate special lists of buildings. Figure 2 shows an excerpt of the building data file. Lastly, the code to read information from some tags was sometimes inconsistent and poorly laid-out. This was corrected.


File:Building file excerpt.JPG

Figure 2: Excerpt from building.liav


To make a new building available to the game, a developer simply defines a new <building> entry in the buildings.liav file. On the next execution of the game, the new building will be present. Each new building created by the arts students was added to the building file in this manner.

This change will be invisible to the user. While there was no direct involvement from the arts students, this provided the vehicle through which their new models were incorporated. This was the first change made to the game as part of this project and is fully implemented and tested

Building Selection Menu

A main proposal in this project was the creation of a menu that allows the user to select the building to be inserted. Based on difficulty, there was a question as to whether or not the building would be a simple 2d menu that merely listed allowed buildings, or a 3d menu that would list buildings and show the model for the building that is currently selected. Figure 3 shows an artist’s conception of how the change should appear to the user.

“Figure 3: Artist's Conception of New Menu”

While attaching the Crazy Eddie GUI library was considered, it turns out that OGRE overlays are sophisticated enough to allow 3d elements to be attached. Thus, it was determined that this project could create the envisioned 3d menu without using CEGUI.

The first issue in implementing this change was the creation of the list of buildings that could be inserted. The idea was to create a method to identify if a building could be built by a user. In response, a new tag “buildable” was created that indicates if the building should be buildable by the user in the game A tree, for instance, should not buildable by a user, while a town hall should be. To implement this, all “<building>” entries in the “building.liav” file were given a buildable flag. The “loadBuildingData()” method was changed to read in this tag, and the building data object was modified to store the tag value. A new public method, called getBuildableList(), was added to the BuildingManager() class. It goes through the pre-loaded building data and returns an array that lists the name of all the buildings that are buildable.

The 3d element also had to be incorporated. Since OGRE shares resources for nodes and meshes in the world, the node had to be created as a ‘rogue scene node’ that reads the mesh file directly and does not create a world object. The material for the mesh also had to be altered in several ways. These changes were needed so that ogre would render the 3d element as part of the overlay and, most importantly, on top of everything else. Changes include setting the render order to the overlay buffer, setting the z-value of the rendered object, disabling lighting effects on the object, and others. If the node was created normally, many of the changes to the material would have appeared in other scene nodes using the same material, severely disrupting the display.

A new class was created to manage the new overlay: CAX3dDialog. This new class is essentially a wrapper for an OGRE Overlay that provides several methods to interact with this 3dDialog. It provides functionality to set the 3d element, set the list of data to display, scroll through the list, and output the user’s selection. Creating a separate class allows the dialog to be used for other purposes as well, such as integrating with the Quest group. An overlay was added to the concepts.overlay file to act as the basis for the 3d overlay. Several elements were added to it, including a title bar, lines of data, and several informational displays at the bottom (which will be discussed in more detail later)

When the overlay is created, it queries the buildingManager for the list of buildable buildings. It shows the list of buildings available to be built and highlights the current selection in red text. One significant issue was the number of buildings. The dialog could accomodate seven lines for displaying the menu. With the buildings added by the arts students, the number of possible buildings was in the low twenties. Thus, a paging functionality was added to the menu. If more than 6 buildings were given to the menu through the getBuildableList() method, only the first six would be displayed. The seventh line would show “More…” and could be selected to page the menu. Any later pages would also have “More…”, ensuring the user could cycle through all menu pages as necessary.

While the change has clear visual implications for the user, no new graphics are necessary. Thus, arts student did not need to be involved in the creation of the menu. Figure 4 shows an in-game screen shot of the actual change. This is updated since the midterm progress report.

File:Building insert menu2.JPG

Figure 4: Updated Screenshot of Building Select Menu

Location of Insert Building Code

Currently, much of the insert building code and all of the camera-swinging code is located directly within the game state class. This is inappropriate, as game states are most easily understood as a concise set of actions to take when a game is in a certain states, along with a new control mapping that applies to that state. Computations for specific processes that happen to occur in a game state do not rightly belong there.

Since the code in question is all related to building insertion, it makes sense to move as much of this code as possible to the BuildingManager class. As well, much of the current code can be entirely eliminated due to existence of the building selection dialog. While desired, this change does not affect the functionality of the game, and is more cosmetic. This aspect of the change was sacrificed in lieu of integration and input tasks. Other changes were made and are outlined below.

The new building selection code (that calls and operates the new 3d dialog) must be located somewhere. The solution is to add a new game state, called CAXBuildingSelectGameState which inherits from InGameState. The old and new game state diagrams are show in figure 5. The new UML for the game state is shown in figure 6.


Figure 5: Game State Diagram


Figure 6: UML diagram showing game states and CAX3dDialog


CAXBuildingSelectGameState manages the 3d dialog. It creates and destroys it as necessary, assigns the 3d element, sends it the list of options, and changes the selection as necessary. Once a building has been selected, the state is moved to the building insert game state.

It should also be noted that a pause state has been added. While this is not relevant to the project, it was done originally as a quick test of the game state code. However, it worked correctly and has a clear usefulness, so it was left in. When using the bike as input, it allows the user to take a quick break for water, for instance. Due to an issue with integration, this state was removed from the final program. However, the code is still present and could easily be activated.

The work for the new game states is now complete. This is entirely architecture based, and thus has no appearance to the user. However, it does control the fact that the menu exists on screen, and also checks for specific user input to operate the menu. No art is necessary.

Allowing Building Insertion in Legal Positions

As a feature that was previously implemented, much of the work is already done here. However, there are many smaller things that should be done to ensure this feature will operate correctly with other changes. First, the current system does some building selection, which is now redundant with the 3d menu. Secondly, it must now accept a building as input, that is, the building placement must accept the output of the building selection menu as input. Both of these changes are fairly small, and result in no changes to the in-game appearance. Also, no art student interaction is required for this aspect of the project. Previously, a new building was created by the Insert Building code, and various buildings could be cycled through by repeatedly pressing the insert building button. Since the new menu selects the building to insert, the ability to cycle through buildings at this stage was removed. The building built at when the Insert Building game state is entered is now supplied by the building selection game state. No other changes were necessary.

However, there is one additional change that should be made that will be visible to the player. Currently, a building may be placed anywhere, including on top of other existing structures. Since choosing building placement is done by the user in the insert building game state, it is also the part of the process where a check should made so that an overlapping building cannot be placed. If it is, the proposed building could be drawn in red to indicate that the current location is illegal. Otherwise, the building should appear normally. This should be achievable by creating a red ambient light on the object. Unfortunately, no work was done on this requirement. However, the approach seems sound and could be implemented in the future.

Tying together Buildings and Resources

All buildings have a resource cost. The idea is that when a structure is built, the resource cost will be deducted from the player’s current resources. If the player lacks adequate resources, the building will not be built. While this is loosely enforced in the existing system, it is not adequate – resources are never actually deducted.

To both enforce the system and provide feedback to the user, the following system will be implemented. When the building selection menu is created, all buildable buildings will appear, regardless of resource requirements. If, however, a given building cannot be built due to inadequate resources, the menu listing will appear in an easily distinguishable grey colour. When that building is selected, the menu will short an information message that notifies the user of insufficient resources. The user will not be able to select that menu option. In other words, any building that is selected will be guaranteed to have sufficient resources. When the building is actually inserted, the resources will be deducted.

No new art elements are necessary to implement this feature. This feature was implemented successfully. All buildings that are buildable, regardless of resources, appear in the menu. If the user has not collected enough resources to construct the building currently selected in the menu, the user cannot select that building. In addition, the last line of the 3dDialog menu states the required resources. The resource that is insufficient will be shown in red text. Figure 4 above shows this line in the dialog.

Special Buildings as Quest Rewards

At midterm, it was believed that the current system now supported this change trivially. The idea was that, by default, any quest reward item can be set by default to buildable=false. It would then never appear on the building selection menu. Once a quest was completed, the flag can be toggled such that the building was then buildable and would appear on the building selection menu. Depending on the building and the purpose of the quest reward, the flag could be toggled back to false after building so that only one could be built. However, when integration took place, it was found that there were several other requirements that needed to be met. This simple solution would not be adequate. The solution to this problem will be discussed under the integration heading below.

Construction-In-Progress

This change presented a ready opportunity for art students. John worked on the creation of several intermediate models representing stages of building construction (construction pit, frame, frame with roof, etc). The planned solution was as follows. Place the building, and then temporarily overridden the default building mesh with the appropriate construction stage model. Using a Timer-Trigger, update the model through its intermediate stages. Once the stages have been completed, the final timer trigger needed to return the building to its default model. The work for this was planned to be done in the BuildingManager class. When a building is created, it will call a method in the BuildingManager class to initiate the sequence of trigger-update, trigger-update, etc.

The plan was to undertake this work only if the intermediate models were created. They were in fact created, and the change was implemented. Each building was given several additional tags – BuildStages, BuildStage1, BuildStage2, and BuildStage3. BuildStages would default to 0 if it was not entered into the building data file. When a building was placed, if buildStages was equal to zero, the building would be placed normally. If buildStages was given a value (between 1 and 3), a new method “buildingConstructCycle()” was called. This would set the mesh of the node to the mesh specified in BuildStage1. A timer trigger would then be started that would call another new method – “buildingCycleCallback()”. This method would continue the cycle. Once :buildingConstructCycle()” figured out that the building was at its last stage, it would set the mesh to the proper mesh for the building and break the cycle.

For the sake of completeness, there are several known bugs with this feature. If multiple stages have the same mesh name, unpredictable results may occur. If the number of stages is greater than the number of named buildStages, the program will fail. Also, only a maximum of 3 stages may be used. Lastly, if multiple buildings are built in a very short period of time, the construction cycles may interfere with each other. Unfortunately, implementing this change, even with the bugs, was quite time consuming.

The change appears as expected to the user. After the user places a building, the camera returns to the normal follow-cam perspective. Once the camera move is complete, the building jumps to its first build stage. Every 10 seconds, the building advances through the cycle. This goal happened specifically because of the involvement of the arts students through their creating of building stages.

Village Concept

The idea of a village in the scope of this project is essentially ‘a group of buildings'. In order to enforce this, an additional check must be introduced that forces the user to build structures within ‘village-limits’. What are the village limits, and how is the village centre first established? To do this, a tag for village centre-ness was added to the building data file. If a building is a village centre, other buildings can be built within a defined distance of it.

This creates a potential problem - if you must build near a village centre, and there are no village centres already built, then nothing can ever be built. To solve this, either new village centres could ignore that check, or the concept of an ‘outpost’ can be added. If a building is flagged as an outpost, then it can be built anywhere. Since the outpost concept is less limiting, this route should be taken.

Implementing this feature involves creating and reading in two new tags from the buildings.liav file, and then adding a check at the appropriate point in the building process. While there isn’t yet a final decision on the most appropriate location, it will most likely be in the same area where the ‘legal position’ is checked in the building insert phase of the building process.

As indicated in the mid-term progress report, this feature was first in line to be removed if other features demanded priority. Due to time spent on integration and other goals, it was left uncompleted. However, the tags for village centre and outpost were added to the buildable file and are read into LIAV. Thus, the code could be implemented in the future.

There was cooperation with the arts students on this feature. Jen had been making various objects, such as arches and water fountains that will act as interesting and attractive village centres. Luckily, these models also fit quite naturally into the quest system. Despite the lack of village centres, all models were included in the final game.

Interaction with other groups

Integration was done over the last 2 weeks of the term. The sound group and the environmental effects group both modified sections of code that were disjoint from the sections modified in this code. Integration with those groups was a simple matter of copying over the code that was modified by the respective projects.

The integration with the quest group was much more involved. There were 3 primary tasks that needed to be done for the integration:

1) The 3dDialog: The 3dDialog was recommended to the quest group as a tool to receive dialog and quests from villagers. A copy of the code was provided to the quest group at the time of midterm presentations. The hope was that the code could be used for both groups. However, this was not communicated clearly, and it in fact became a fork of the code. A new class called QuestDialog was created from the code-fork. This is unfortunate, as the 3dDialog class had faculties within it to differentiate between different uses. When a 3dDialog is instantiated, it takes a string as a parameter that is used to define the type of 3dDialog to display. Thus, it would have been possible to simply call the same method to create a 3dDialog while specifying ‘quest’ as the type. Changes could have been made within the 3dDialog class to add new functionality for a dialog of type quest, but this was not done.

2) Automatic Quest Generation: It was the intent of the quest group to automatically generate quests. Since every object in the game (outside of weather, villagers, the avatar, and the terrain) is handled within the building manager, information to generate these quests needed to come from the building manager. The type of quest that would use this new information was the collection quest. In this quest, a small random number of a collectible item gets scattered across the terrain. They are collected as the user steers the avatar over these items. Once all items are collected, the user returns to the quest giver to receive a reward and a new quest.

There needed to be a way for the quest group to get a list of collectible items. The solution was very similar to the solution for generating a list of buildable items. A new tag was added to the building data file – collectible. If an item can act as a randomly generated quest collectible, then this tag should be flagged true. As building data is read into the system, any buildings that are flagged as collectible get added to a collectibleList vector. The method “getCollectibleList()” was created to return this vector to the quest creation module.

3) Quest Rewards: Upon quest completion, some kind of reward was to be given to the user. It was decided that the reward would be the ability to build specialty buildings, such as a fountain, arch, or other interesting building. The user would be assigned the ability to build one or two of a specific building. This created two needs – one, the ability to randomly determine a building that would be given as a quest reward, and two, some way to reckon with only sometimes being able to build a building and some way to track the buildable number.

To complete both of these tasks, a new integer tag was added to the building data file, named buildableQuantity. It was given a default value of -1, which means the building in question can be built an unlimited number of times. This was the value assigned to standard buildings such as the town hall or lumber mill. If a building was to act as a quest reward, it was given a value of 0. In addition, the method to fetch the list of buildable buildings was changed to reflect this addition. If the buildable quantity was -1, the building would always appear in the building selection menu. If the building quantity was greater than 0, it does not appear, while a quantity greater than 0 indicates that the building will appear. Also, the quantity also appeared at the bottom of the building menu, thereby notifying the player. By default, no quest reward was buildable, but upon completing a quest, the quest reward would then show up in the building menu. Of course, when the building was built, if the buildableQuantity was greater than 0, it was decremented.

This value was also used to return the list of potential quest rewards to the quest generator. An iterative search through the loaded building data for buildable buildings with buildingQuantity greater than -1 would return only those buildings that could be quest rewards. Thus, a list could be provided to the quest group that would return a list of quest rewards.

Input Mapping

The building menu was designed to use the move forward and break inputs to cycle up and down through the menu. Selecting a menu item was done with the action button. There was a problem with this basic approach, however. Since the game would run with a very high FPS, even the shortest key-presses were often acted upon multiple times. A brief touch of the down key would result in several moves down in the menu. Pressing the action button on the more key would often result in the inadvertent selection of the first item on the next menu page. Even worse, the move forward key was tied into the gear system and was amplified. So, a brief touch on the move forward key resulted in a long period of forward presses, causing the menu to cycle repeatedly through all of its options. When the bike was attached, this forward problem was amplified. Pedalling the bike needed to break some kind of threshold before moving forward occurred. Once motion began, the bike would continue moving from its own momentum. This would continue sending move forward commands to the game, even for a few seconds after pedalling ceased. In other words, it was difficult to get the menu to move, and once it moved, it would cycle through all the menu options for a few seconds in an uncontrollable manner. Clearly, this needed to be changed.

The answer involved two things. First, two input keys were defined: menuIncrement and menuDecrement. By separating these from the move forward command, the influence of the bike was removed. These keys were set to be the rear trigger buttons on the game-pad, and the up and down buttons on the keyboard, though they can be remapped in the input.cfg file.

The second step was eliminating multiple key presses. While a few different methods were tried, the solution settled upon was to lock out the menu for a short time after a key press was made. Each input response in the menu would be triggered based on two things – pressing the input key, and the liveness of the menu. By default, the menu would be active. A key-press would cause the corresponding action to take place, and then the menu would become inactive. A timer trigger would also be started. When the timer trigger fired (0.4 seconds later) the menu would reactivate. This solved the multiple key-press problems. A small change was put in to ensure that only the key last pressed would be locked out. For instance, if the user scrolled down once then quickly pressed enter, both of these inputs should be acted upon. This was done successfully.

Conclusions

All things considered, this was an enjoyable and successful project. The majority of project goals were implemented, the architecture of LIAV was respected and followed, and integration was successful. The user experience was improved, and the game is more full featured. Figure 7 below shows an example of the construction of several new buildings, improving the look and feel of the game for the user. Additionally, the game is easier to operate and is more communicative, making game play more satisfying for the user.

File:Village.JPG

Figure 7: A screenshot showing several buildings that been constructed