Nebelkampf

My Role in this Project

In this project, I was responsible for building the UI system in a custom engine. UI created in Photoshop can easily be exported in the engine with a custom script I worked on. After 8 weeks we had the opportunity to make a game with our engine, and a couple of designers and artists joined the project. At that point, I mainly focussed on bug fixing and applying feedback from the UI designer and artist.

Summary of my work:

  • An UI system built in a custom engine.
  • A Photoshop script that stores the layout in a JSON file and automatically creates a texture atlas.
  • Built a system that recreates the UI layout from Photoshop in the game.
  • Close communication with the UI designer and artist for feedback, bug reports and feature requests.
  • Used a Lua script binder made by my team member to create UI functions that can be called from Lua.
  • Did Lua scripting for the functional implementation of the UI.

Details

Type
School Project
Genre
Turn-based strategy
My Role
UI/Tools Programmer
Team Size
16
Duration
4 Months
Engine
Custom Engine (HexEngine)
Language(s)
C++, Lua,
Photoshop Script

Game Description

Nebelkampf is a turn-based strategy game based around vision. Both players have access to different units that fight it out on a board covered in the fog of war. Each unit comes with its own "vision" & combat abilities.

Code Snippets

Photoshop Script

The Photoshop script will go through all layers, and stores the names and positions in a JSON file. It will also create a texture atlas automatically.
function StartExportProcess() {

    // Find the layerSet/group with the name "Export" or "export"
    // If there aren't any export layers, stop the process
    var exportLayerSet = GetExportLayerSet(app.activeDocument);
    if (!exportLayerSet) {
        alert("Failed to start export process. Make sure there is a folder with the name export.");
        return;
    }
        
    // Create the serializer for storing the layer's data inside a json file
    serializer = new Serializer(Globals.userDocument, Globals.userSettings.outputName, Globals.userSettings.outputDestination, exportLayerSet);

    // Creates a new document inside Photoshop that will be used for creating an texture atlas
    textureAtlas = new Atlas(Globals.userSettings.maxWidth, Globals.userSettings.maxHeight);
    
    // Create the smart object manager that handles storing smart object data (used for buttons)
    smartObjectManager = new SmartObjectManager(Globals.serializer, Globals.textureAtlas);
    
    // Loop through all the layers and put it in the textureAtlas and store the data
    result = StoreAllLayerData(serializer, textureAtlas, exportLayerSet, smartObjectManager);
    
    textureAtlas.Trim();
    
    // Put each layer's data in a json file and put it locally on the computer
    serializer.Serialize();
    textureAtlas.SaveAsPNG(Globals.userSettings.outputDestination, Globals.userSettings.outputName, !Globals.userSettings.keepTextureAtlasOpen);
    
    if (result == 'notfit') {
        alert("Failed to fit every layer in the atlas");
    }
}

Loading the UI created in Photoshop through Lua

In Lua the entire UI can be loaded with one function. The names of the layers can be used to reference certain UI elements.
UI.LoadUIFromJSON("textures\\prototype\\ui\\ui_ingame.json")

UI.SetUIElementVisible("yourTurnPanel", true)
UI.SetUIElementVisible("opponentTurnPanel", false)

UI.BringToFrontLayer("dialogBackground")

Loading the UI in C++

Calling the function in Lua will automatically call the correct function in C++.
bool UISystem::LoadUIFromJSONFile(string a_JsonFile)
{
	// Check if the it has a .json extension
	if (a_JsonFile.length() < 5 || a_JsonFile.substr(a_JsonFile.length() - 5) != ".json") {
		printf("[UISystem] Warning: Failed to load json file, did you forgot to add the extension .json to '%s'? \n", a_JsonFile.c_str());
		return false;
	}

	// Get the json file that contains the UI data
	resources::JSONDoc* jsonUIData = ResourceSystem::GetInstance()->LoadJSON(a_JsonFile);

	if (jsonUIData == nullptr) {
		printf("[UISystem] Warning: Couldn't load the UI because it failed to load the json file '%s'\n", (a_JsonFile).c_str());
		return false;
	}

	// Check if the json file has the correct format to create a UI from it
	if (JSONFileIsValidAsUIData(jsonUIData, a_JsonFile))
	{
		TextureAtlas* atlas = ResourceSystem::GetInstance()->LoadTextureAtlas(a_JsonFile.substr(0, a_JsonFile.length() - 5));

		try {
			return CreateGroupsFromJSONFile(jsonUIData, atlas);
		}
		catch (exception ex) {
			printf("\n  [UISystem] Warning: Something went wrong with loading the UI from a json file.\n\n");
			return false;
		}
	}

	return false;
}