Old Project – 3D Level Editor (2010)

Today I stumbled upon some old screenshots in my backup folder and I thought maybe I should post it here to remind myself how passionate I was.

This is a 3D level editor I did for my hobby game project back in 2010. The level editor was made using Qt 4 and Irrlicht engine. Some of the screenshots below are showing the editor which uses Irrlicht’s native GUI. Irrlicht’s GUI system was quite limited in term of types of widgets and functionality, which later on led me to switching all the GUI over to Qt.

Some of the features supported by the “game engine” I did back then include:
– Basic fixed function 3D rendering
– Basic collision (box collider and trigger)
– Spawn points
– Player camera and animated camera (for in-game cinematic)
– 3D sound (using irrKlang)
– Simple path finding

I made a simple game demo using the game engine and level editor I made. Unfortunately, the game wasn’t finished and I moved on doing something else. Below is the video recording I did back in 2010 showing how the game demo look like, for a competition. Spore Motions was the name of our team back then.

Hopefully I will be back into game development very soon.

Change Unity3D Build Target Using CMD

Most people probably won’t need this, unless you encountered such scenario:

You're handling a huge project, and you somehow need to move the entire project folder from a Windows machine to a Mac for porting the project to iOS.
What will happen is when you open the project for the first time on Mac, Unity will load all the files and convert them into Windows formats because well, your project was set to run on Windows previously.
You waited for half an hour or so for all the files to be converted (it' a huge project!) and now you must change the build settings again, and wait for another half an hour for it to be converted to iOS!

If you want to avoid running the conversion twice, you can change your Unity project’s build target before opening the editor, by using the command prompt, like so:

Windows:

"C:\Program Files(x86)\Unity\Editor\Unity.exe" -buildTarget 

Mac:

/Applications/Unity/Unity.app/Contents/MacOS/Unity -buildTarget

Possible options are: win32, win64, osx, osxintel64, osxuniversal, linux, linux64, linuxuniversal, ios, android, web, webstreamed, webgl, xbox360, xboxone, ps3, ps4, psp2, wsa, wp8, bb10, tizen, samsungtv

For example:

"C:\Program Files (x86)\Unity\Editor\Unity.exe" -buildTarget ios

This way, Unity will straight away convert your project files to iOS formats and no need to convert it twice. Time saved!

Rect Error in Game Mode

If you are getting this error when running Unity Engine in game mode:

rect[2] == rt->GetGLWidth() rect[3] == rt->GetGLHeight()

It’s actually an error emitted by the editor itself, nothing to worry about. To remove this issue, go to Window → Layouts → Default to reset the editor layout. The error will then disappear.

The error is usually associated to conflicts between image effects and screen aspect ratio. It’s not really a serious issue, just follow the steps above and you’re good to go.

OGRE Hello World!

In this tutorial, I will teach you how to create an empty window with OGRE graphics engine and C/C++ language. Unlike any other tutorials that you can find on the internet, this tutorial does not rely on ExampleApplication.h and therefore you will be able to learn OGRE completely from scratch.

At the end of this tutorial, you will be able to create an empty window similar to this:

It’s actually not that complicated to code from scratch, just take a look at the full source code below and you will realize that it’s actually pretty simple to understand even for beginners.

#include <Ogre.h>
using namespace Ogre;

int main()
{
    Root *root = new Root("plugins.cfg", "mygame.cfg", "mygame.log");
    root->showConfigDialog();

    root->initialise(true, "My Game");
    RenderWindow *window = root->getAutoCreatedWindow();

    SceneManager *smgr = root->createSceneManager(ST_GENERIC, "SceneManager");

    Camera *cam = smgr->createCamera("MainCamera");

    Viewport *vp = window->addViewport(cam);
    vp->setBackgroundColour(ColourValue(0.3, 0.6, 0.9));

    root->startRendering();

    return 0;
}

Pretty simple isn’t it? I will now explain what the code does part-by-part. First of all, you have to include OGRE’s main header file “Ogre.h” into your project so that you can access its classes and functions for later use:

#include <Ogre.h>
using namespace Ogre;

You can also predefine its namespaces (but not a must) to make your code shorter. For example, instead of calling Ogre::Root *root = new Ogre::Root(), we can use Root *root = new Root() instead, which is much shorter and clean.

After that, create a Root class at the beginning of your main function, like so:

Root *root = new Root("plugins.cfg", "mygame.cfg", "mygame.log");

As you can see, Root requires 3 parameters during initialization: the first one being the config file that defines what plugins to load before starting the program; the second parameter is your game’s rendering config file that defines the resolution, aspect ratio, color depth, and so on which will also be loaded before your game is launched; and the last parameter is the name of the log file that will be generated whenever an error happens and it will tell you what problem had occurred.

After that we will be calling:

root->showConfigDialog();

which displays a config dialog before launching your game. The dialog window looks like this:

It lets the players change display settings before the game starts, which is quite handy especially for debugging purposes during development stages.

Next, we will initialize the Root class and define the window title by doing so:

root->initialise(true, "My Game");
RenderWindow *window = root->getAutoCreatedWindow();

We will then call root->getAutoCreatedWindow() to return the newly created render window and stores it to the a pointer called window. Please note that Ogre uses UK English, therefore you should use initialise instead of initialize.

Next, we will create a scene manager that manages your game’s scene graph (i.e. all the 3D objects in your scene) and save it to a pointer called smgr:

SceneManager *smgr = root->createSceneManager(ST_GENERIC, "SceneManager");

There are two parameters for creating a scene manager. The first parameter defines the type of scene graph you’re about to create. There are multiple types of scene managers you can choose from, such as:

  1. ST_GENERIC – Generic scene manager
  2. ST_EXTERIOR_CLOSE – Old terrain scene manager
  3. ST_EXTERIOR_FAR – Nature scene manager
  4. ST_EXTERIOR_REAL_FAR – Paging scene manager
  5. ST_INTERIOR – BSP scene manager

which each of them serves a very different and specific purpose. In this example, we use ST_GENERIC which is the generic type that works well in most cases. The second parameter simply lets you set a name for your scene manager, in this case, we called it “SceneManager”.

Next, we have the code below:

Camera *cam = smgr->createCamera("MainCamera");

Viewport *vp = window->addViewport(cam);
vp->setBackgroundColour(ColourValue(0.3, 0.6, 0.9));

which simply does the following, in ascending order:

  1. Create a camera and call it “MainCamera”.
  2. Ask the rendering window to link the newly created camera to its viewport.
  3. Set a background color for the viewport which will be used to flush the back buffer.

After everything has been setup correctly, we will now render the scene by calling startRendering() which is quite self-explanatory:

root->startRendering();

and viola! You have now successfully created an empty rendering window that runs on OGRE. That’s all for this tutorial, have fun!

Irrlicht Hello World!

In this tutorial, you will learn to write a simple “Hello World!” application to test whether your project has been set up correctly. At the end of this tutorial, you should be able to get this result:

Pretty cool right?

Before we start, let’s download the badass-looking beast model created by Psionic by clicking the image below:

After you’ve downloaded the zip file, extract everything to your project directory. Make sure “beast.b3d” and “beast1.jpg” are both at the same folder as your executable (.exe).

Now, let’s start writing some code!

First of all, you need to include the main Irrlicht header to your script:

#include <irrlicht.h>

After that, predefine all the irrlicht namespaces, like so:

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

If you don’t add in the codes above, you will need to call the namespaces manually everytime you use its child classes. Without predefining it, you need to call irr::scene::ISceneNode *node instead of ISceneNode *node, for example, which makes your code much longer and harder to read.

After that, define the main function:

int main(){

Note: If you don’t know what is a main function, you probably need to stop reading this tutorial, go ahead and pick up some basic C/C++ knowledge, and come back again after that.

Now, we will create an Irrlicht device and set the window caption by calling:

IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d(512,512), 32, false, false, false, 0);
device->setWindowCaption(L"Irrlicht Hello World Tutorial");

Let me explain a bit here. At the first line, we created an IrrlichtDevice pointer and named it as device. Then, we called createDevice() function to ask Irrlicht to create the rendering device based on 7 parameters which we have filled in. The parameters are explained below, in ascending order:

deviceType: Type of device. There are currently 5 options for us to choose from. As you can see, we’ve chosen OpenGL as the rendering device in this example.

  1. OpenGL – EDT_OPENGL
  2. DirectX 8 – EDT_DIRECT3D8
  3. DirectX 9 – EDT_DIRECT3D9
  4. Software – EDT_SOFTWARE
  5. Software 2 – EDT_BURNINGSVIDEO

windowSize: Size of the window. In this example, we set it as 512×512.
bits: Number of bits per pixel when running full screen mode (which will be ignored in windowed mode). It should be either 16 or 32.
fullscreen: Whether or not we enable full screen mode.
stencilbuffer: Specify if we want to use stencil buffer for drawing shadows.
vsync: Enable/disable vsync mode. Only useful when running full screen.
eventReceiver: An object which receives events. We set it as 0 because we are not going to use this parameter in this example.

Then, we will create a video driver, scene manager and GUI environment respectively by calling:

IVideoDriver *driver = device->getVideoDriver();
ISceneManager *smgr = device->getSceneManager();
IGUIEnvironment *guienv = device->getGUIEnvironment();

After that, we display a line of static text on the screen:

guienv->addStaticText(L"Hello World! You are now running Irrlicht Engine!", rect(10,10,200,22), true);

For the code above, we were calling the function addStaticText() which derives from the GUI environment class named guienv. There are 3 parameters for that particular functions: The first parameter is the text that you want to display on the screen. The second parameter is the size and location of the rectangular container where your text will be placed in. See the image below to help you understand more about text container and how you adjust the parameters. The third parameter is to specify whether we want the border line of the container to be shown.

Now, the most exciting part: We will now place the beast model into the scene!

IAnimatedMesh *mesh = smgr->getMesh("beast.b3d");
IAnimatedMeshSceneNode *node = smgr->addAnimatedMeshSceneNode(mesh);

if (node)
{
    node->setMaterialFlag(EMF_LIGHTING, false);
    ITexture *texture = driver->getTexture("beast1.png");
    node->setMaterialTexture(0, texture);
    node->setFrameLoop(1, 25);
    node->setRotation(vector3df(0, 180, 0));
}

At the first line, we loaded the mesh “beast.b3d” which you downloaded at the beginning. Please remember to place the file in the same directory as your executable binary file (.exe). Then, at the second line, we created a scene node, which stores information of your mesh, such as location, scale, attributes, materials, and so on. You can create many different individual node which uses the same mesh.

From the fourth line onwards, it means that if the animated scene node was successfully created, we will then:

  1. Disable lighting affecting the beast.
  2. Load a texture file called “beast1.png” from the directory.
  3. Apply the texture to the beast on the first UV layer. You can apply different textures on different layers, but we don’t need to do that for now.
  4. Load the animation from frame 1 to frame 25, and keep looping it.
  5. Rotate the node by 180 degree along the Y-axis.

After placing the beast, we need a camera to render the scene:

ICameraSceneNode *camera = smgr->addCameraSceneNode(0, vector3df(-100, 100, 150), vector3df(0, 5, 20));

There are 3 parameters used by the camera. The first one is the id number for that particular camera node, the second parameter is the camera location and third parameter is the viewing target of the camera.

Then, we will start running the main loop. Everything will be rendered to the screen at this point including all the objects in the scene and even the user interface.

while(device->run())
{
    driver->beginScene(true, true, SColor(255, 100, 101, 140));
    smgr->drawAll();
    guienv->drawAll();
    driver->endScene();
}
device->drop();
return 0;}

There are 3 parameters in the function beginScene(): The first one is to enable/disable back buffer, second parameter is to enable/disable z-buffer and the third parameter is the color used to clear the screen. Please remember that everything must be drawn between beginScene() and endScene() functions.

You can now build your project and that’s all for this tutorial. For those who are lazy, the whole script is shown below:

#include <irrlicht.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

int main()
{
    IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d(512,512), 32, false, false, false, 0);
    device->setWindowCaption(L"Irrlicht Hello World Tutorial");

    IVideoDriver *driver = device->getVideoDriver();
    ISceneManager *smgr = device->getScenemanager();
    IGUIEnvironment *guienv = device->getGUIEnvironment();

    guienv->addStaticText(L"Hello World! You are now running Irrlicht Engine!", rect(10,10,200,22), true);

    IAnimatedMesh *mesh = smgr->getMesh("beast.b3d");
    IAnimatedMeshSceneNode *node = smgr->addAnimatedMeshSceneNode(mesh);

    if (node)
    {
        node->setMaterialFlag(EMF_LIGHTING, false);
        ITexture *texture = driver->getTexture("beast1.png");
        node->setFrameLoop(1, 25);
        node->setMaterialTexture(0, texture);
        node->setRotation(vector3df(0, 180, 0));

    }

    ICameraSceneNode *camera = smgr->addCameraSceneNode(0, vector3df(-100, 100, 150), vector3df(0, 5, 20));

    while(device->run())
    {
        driver->beginScene(true, true, SColor(255, 100, 101, 140));
        smgr->drawAll();
        guienv->drawAll();
        driver->endScene();
    }
    device->drop();
    return 0;
}

If an error appears when you’re launching your program, it’s most probably because you didn’t copy the important irrlicht DLL file into your project directory. The DLL file needs to be placed in the same folder as your executable file (.exe).

If you want to remove the ugly console window, open up the project properties window, and change your project from console application to GUI application.

Have fun!