wxWidgets for a Blob Game Editor

A blob game is something like Loco Roco or Gish where there are characters and objects in the game that can compress and squeeze and roll around. Using the physics system I have been working on this semester I wanted to replicate that and create a game with the following in mind:

  • Must contain a character that can roll around
  • Must contain a level editor for placing composite objects
  • Must display features of a mass aggregate system

For me, creating the game would not be hard, but I wanted to be able to pay special attention to the editor I was going to make for the game. I wanted to create my level editor so that it was styled similar to that of Grey: The Lost Technology, and by that I mean a separate control panel so that I do not have to create a rendering loop for the active, drawable game space within a window. I knew that you could use Windows Forms with C++ so I tried setting that up. The problem with this idea is that the C++ implementation of Windows Forms is managed. This immediately created problems because my current game implementation is written in unmanaged code. After some fiddling around with Windows Forms, I eventually gave up. The primary reason I wanted to use was that I could use the visual designer, so it was primarily the speed of quickly mocking up a UI that I wanted.

I started looking at other C++ UI libraries and I found a few, such as Qt and wxWidgets. Both are really powerful UI libraries that offer all the functionality that Windows Forms offers, but cross-platform. I had done my research and found that Qt is easier to use, but wxWidgets was meant to be the most natural looking for the given system it runs on. It’s meant to look as close to system dialogs as possible. I had also looked at wxWidgets before and had already read their documentation because I saw that a company that I like was using it for their tools development. The decision was made… already having some prior knowledge of the library, I chose wxWidgets.

wxWidgets turned out to be a really easy platform to implement into my existing codebase. I usually have a lot of trouble linking a new library into my existing code, but not with this. The documentation is very clear, and I didn’t even have to compile my own version of the source code! The setup instructions for getting wx into your Visual Studio can be found here. After that, you can grab any of the “Hello World” scripts or samples from the wx documentation page.

 Code

Here is my minor implementation of a small control panel for my editor:

//CompositeCPanel.h
#pragma once

#include <wx/wx.h>
#include "CompositeEditor.h"

class CompositeCPanel : public wxFrame
{
public:
	CompositeCPanel(const wxString& title, CompositeEditor* editor);
	
	void OnUpdate(wxCommandEvent & event);
	void OnSave(wxCommandEvent & event);
	void OnComboBoxSelected(wxCommandEvent & event);

	wxTextCtrl * entryX;
	wxTextCtrl * entryY;
	wxTextCtrl * entryZ;
	wxTextCtrl * radius;

private:
	wxTextCtrl* mName;
	wxComboBox* mCombo;

	CompositeEditor* mEditor;
};

//CompositeCPanel.cpp
#include "CompositeCPanel.h"

CompositeCPanel::CompositeCPanel(const wxString& title, CompositeEditor* editor)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 350))
	, mEditor(editor)
{
	wxPanel *panel = new wxPanel(this, wxID_ANY);

	wxStaticText* xText = new wxStaticText(panel, wxID_ANY, "X:", wxPoint(5, 20), wxDefaultSize, 0L, wxStaticTextNameStr);
	entryX = new wxTextCtrl(panel, wxID_ANY, "", wxPoint(20, 20), wxDefaultSize, 0L, wxDefaultValidator, wxTextCtrlNameStr);
	wxStaticText* yText = new wxStaticText(panel, wxID_ANY, "Y:", wxPoint(5, 45), wxDefaultSize, 0L, wxStaticTextNameStr);
	entryY = new wxTextCtrl(panel, wxID_ANY, "", wxPoint(20, 45), wxDefaultSize, 0L, wxDefaultValidator, wxTextCtrlNameStr);
	wxStaticText* zText = new wxStaticText(panel, wxID_ANY, "Z:", wxPoint(5, 70), wxDefaultSize, 0L, wxStaticTextNameStr);
	entryZ = new wxTextCtrl(panel, wxID_ANY, "", wxPoint(20, 70), wxDefaultSize, 0L, wxDefaultValidator, wxTextCtrlNameStr);

	wxStaticText* radiusText = new wxStaticText(panel, wxID_ANY, "Radius:", wxPoint(5, 95), wxDefaultSize, 0L, wxStaticTextNameStr);
	radius = new wxTextCtrl(panel, wxID_ANY, "", wxPoint(50, 95), wxDefaultSize, 0L, wxDefaultValidator, wxTextCtrlNameStr);

	wxButton *button = new wxButton(panel, wxID_EXIT, wxT("Update"), wxPoint(20, 120));
	Connect(wxID_EXIT, wxEVT_COMMAND_BUTTON_CLICKED, 
		wxCommandEventHandler(CompositeCPanel::OnUpdate));

	wxStaticText* nameText = new wxStaticText(panel, wxID_ANY, "Name:", wxPoint(5, 195), wxDefaultSize, 0L, wxStaticTextNameStr);
	mName = new wxTextCtrl(panel, wxID_ANY, "", wxPoint(50, 195), wxDefaultSize, 0L, wxDefaultValidator, wxTextCtrlNameStr);

	wxButton *buttonSave = new wxButton(panel, wxID_SAVE, wxT("Save"), wxPoint(20, 220));
	Connect(wxID_SAVE, wxEVT_COMMAND_BUTTON_CLICKED, 
		wxCommandEventHandler(CompositeCPanel::OnSave));

	wxString items[] = {"rod", "spring"};

	wxStaticText* typeT = new wxStaticText(panel, wxID_ANY, "Link Type: ", wxPoint(5, 170), wxDefaultSize, 0L, wxStaticTextNameStr);
	mCombo = new wxComboBox(panel, wxID_OK, wxEmptyString, wxPoint(70, 170), wxDefaultSize, WXSIZEOF(items), items);
	Connect(wxID_OK, wxEVT_COMMAND_COMBOBOX_SELECTED, 
		wxCommandEventHandler(CompositeCPanel::OnComboBoxSelected));
	mCombo->SetSelection(0);
	mEditor->NotifySelectedItem(mCombo->GetValue().ToStdString());

	button->SetFocus();

	mEditor->mFrame = this;
}

void CompositeCPanel::OnComboBoxSelected(wxCommandEvent & event)
{
	mEditor->NotifySelectedItem(mCombo->GetValue().ToStdString());
}

void CompositeCPanel::OnUpdate(wxCommandEvent & WXUNUSED(event))
{
	// update the game.
	mEditor->ReceiveStrings(
		entryX->GetValue().ToStdString(),
		entryY->GetValue().ToStdString(), 
		entryZ->GetValue().ToStdString(),
		radius->GetValue().ToStdString());
}

void CompositeCPanel::OnSave( wxCommandEvent & event )
{
	mEditor->SaveObject(mName->GetValue().ToStdString());
}

One of the problems I faced with using wxWidgets was that I did not fully understand how their event system worked and thus I was not able to take full advantage of their feature set. To achieve the goal that I wanted, I passed a reference to the class that this Dialog was linked to. While it’s probably not the best solution, it is a solution, and until I find out a better way this will be the way it stays for now.

Videos

Grey: The Lost Technology

About the Game

Grey: The Lost Technology is the first project for Team Aurora, the independent game studio a few friends and I co-founded. Grey was successfully Kick-started in May of 2012. We were able to travel to PAX East and meet with a lot of fellow developers and met some really cool people. The game is an action RPG that explores the possibility of an overpopulated Earth and the humans who leave to find a new planet to call home.

Development

The game is programmed in C# using the XNA Framework. The game does not use external libraries, and instead uses the game engine we have programmed called “Aurora2D”.

Game

The game is primarily Quest/Narrative driven. What this means is that you need to speak to someone, who will give you a quest. Once this quest is completed you will be awarded with another quest, or you will tasked to talk to a person who will give you quest. The dialogue system is something that I spent some time working on to make sure it functioned just right. Imagine the dialogue mechanic like any RPG, or text-based action game: The text shows up in a box and then continues to show up in chunks until a response is required. Each response can link to certain objects in the game. Talking to someone can give you:

  • Quests
  • Money
  • Health
  • Experience
  • Items

Alternatively, it can direct you to more dialog. Implementing this is primarily about a good structure and design of the dialogue objects themselves. A Talker, when spoken to, evaluates each dialogue that is tied to them. They accept commands and react accordingly.

Another large contribution of mine is the design and implementation of the map system. A map is designed like so:

  • Map
    • Levels (Can be viewed as subsections of a map)
      • Layers
        • Tiles
      • Group Objects
      • Spawners
      • In-location markers
      • Characters

A map is broken down into levels (read: sections), then a level is broken down to handle each component that is drawable from the tabs in the editor (See below). So the structure is simple, each type of object has their own list, and when the maps are saved, they are serialized in an overridden XmlWrite that structures each object list as a group. However the most revolutionary part about the serialization is about saving the tiles. When serializing the tiles, there is a dictionary that holds a dictionary, kind of like this: Dictionary<int, Dictionary<int, Tile>>. This can be seen as [x][y] = tile. You might be thinking that it should be stored as an array, but when saving an array it saves all the empty positions, and we don’t want that. So I wrote a loop that writes out each tile within an <X> element and a <Y> element. The <Y> element holds the tile position in the texture, and then also holds an index to a texture that it uses. The ending result looks kind of like this:

<Level>
  <ScreenWidth>20</ScreenWidth>
  <ScreenHeight>12</ScreenHeight>
  <Position>0,0</Position>
  <Textures>Content/Textures/Tiles/Sand_01.png</Textures>
  <Layer>
    <Name>Sand</Name>
    <Priority>-15</Priority>
    <CollisionType>0</CollisionType>
    <X0>
      <Y1>0,1</Y1>
      <Y2>0,2</Y2>
      <Y3>0,3</Y3>
      <Y4>0,4</Y4>
      <Y0>0,0</Y0>
      <Y5>0,0</Y5>
      <Y6>0,1</Y6>
      <Y7>0,2</Y7>
      <Y8>0,3</Y8>
      <Y9>0,4</Y9>
      <Y10>0,0</Y10>
      <Y11>0,1</Y11>
    </X0>
  <Layer>
<Level>

This saves us a tremendous amount of space and is a lifesaver in terms of distribution of the final product (because there are less files to transfer, it’s much easier to share). To read more about my theory and logic behind this serialization concept, check it out here: Problems of Storing Maps

Editor

Since we created the game with a framework, and did not use an existing game engine, we needed to create a game editor. The game editor is something of my own creation with the exception of the Navigation Mesh Editor written by our other programmer, Jacob Jackson. The editor is an XNA project that is supplemented by Windows Forms. When the game launches is creates the Control Panel that the designers will be using to manage game assets and map textures.

Control Panel

Grey Editor: Control Panel
Grey Editor: Control Panel

The control panel offers all the flexibility and options that a game designer needs to fill in a level and create everything that is going to be in the level. On the surface you can see that you have the ability to manage:

  • Texture Placement/Selection
    • Animated
    • Static
  • Objects
    • Map Links
    • Characters
    • Enemy Spawners
    • Location Marker/Zones
  • Particles
  • In-Game Items

By adjusting the Edit Mode, you will have access to different functionality offered by the editor. For example switching from TILE (which allows you to place all of the items offered in the tabs) to PATROL_EDITOR, you will be able to draw patrol path lists that and have the ability to customize them. There is also an Edit Mode for drawing the Navigation Mesh on a map. Lastly, there is another edit mode for drawing world-space collision geometry.

The Draw Mode combo box allows a designer to change between:

  • Drawing – Draw an object in the scene
  • Deleting – Delete an object in the scene
  • Editing – If drawing collision, use to add vertices to a shape
  • Transforming – If drawing collision, use to grab and move vertices of a shape

Tools

Collision Editor

animationeditorSome of the coolest parts of the editor are in the Tools Menu. The tools menu provide a designer with the ability to add collision geometry to each and every character model/animation that exists in the game. Using the Collision editor is simple. A list is populated with all the animations from the spritesheets and then the selected spritesheet is drawn and all that is required is to click and drag to draw a collision box. Rotating the collision box is done by holding space after you dragged the box out to it’s appropriate size.

Data Editor

The Data Editor gets into the nitty gritty of the actual game itself and allows the designer to

  • Create all items in the game
  • Create all the quests of the game
  • Create magic effects
  • Alter “New Game” configuration options

questeditorThe quest creation system is a portion of the editor that I had a lot of fun working with and was able to really break down a solid questing architecture.  The quest system is broken down like so:

  • Quest
    • Quest Steps
      • Continue Requirements
      • Failure Conditions
      • Rewards
      • Items to Remove
    • Rewards
    • Items to Remove

A quest must have steps to be completable. Think of a game like The Elder Scrolls: Skyrim where a quest often times has a few parts that must be completed to complete the overall goal. To evaluate each of the Continue Requirements, I hook events for each running quest and then when anything in the game happens and fires an event, each quest you are completing will be updated concurrently. This event driven implementation is the core of the quest system. As a supplement, I created what I like to call an action list. The action list is a rolling list of every action that our hero, Oren, performs in the game, whether it’s killing an enemy, clearing a spawner, or changing maps, it all gets recorded as separate actions. This implementation solves the problem of a player exploring the map and killing a boss or character that spawns once in a game, then getting the quest tells you to defeat him, and not being able to complete it. A quest checks the action list in parallel to the events that it handles.

createitemThe Item Editor is also really cool because to complete this I implemented a class parser using C# reflection to handle populating the editor. There is a main recursive function that handles the population aspect. This function takes the object and uses reflection to evaluate each public property and generate a component that best fits the type of property it’s evaluating.

Engine

The engine is a set of utility classes and objects that offer a full suite of functionality and easily pluggable into different situations. Some of the tools offered include:

  • Texture Parsing for Animations
    • Texture Atlases
    • Grouped Textures
    • Single sprite sheets
  • XML Serialization
  • Quad Trees
  • Separating Axis Theorem (SAT) Collision Detection
  • Baseline Menu Creation
    • Including Buttons and Sliders
  • Lots of Extensions for Primitive Classes
  • Input Management
  • Resolution Management
  • Event Management

The library is fully featured and provides us with a very solid base to build Grey with.