Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

31. January 2012

 

 

As I mentioned earlier, I have recently discovered Node.JS.  Quick version, Node is a server side Javascript engine, allowing you to easily create applications on the server.  Obviously you could use SFML on both the client and the server but many people find Javascript a much faster language to work with.  The libraries bundled with Node make this task extremely easy.

 

We are going to create a very simple “High score” system, allowing users to push their score to the server as well as get a list of the current high scores.

 

 

 

You may notice Node referred to as Node, Node.js and NodeJS, which is correct?  Beats the hell out of me!  I frankly just use them all, so if you notice me switching terms, remember they are all referring to the same thing.  I am assuming you are using Windows 7 and Visual Studio for this tutorial, but there are no reasons you can’t use different OSes or IDEs.

 

 

First off, lets get Node installed, which you can download here.  Run the installer and node will be installed to your machine.  Really that’s about it.  Optionally you can add the install directory to your PATH environment variable, in my case it was C:\Program Files(X86)\nodejs, this will save you a ton of key strokes later and for the following instructions I will assume you have performed this step.

 

 

Now that you have installed node, we can create our server; you are about to see how laughably easy this is using Node.  Create a file server.js in your editor of choice, in my case I am using JetBrain WebStorm ( on a 30 day trial ) and have been impressed so far, but you can use any text editor including Notepad.  In server.js add the following code:

 

var dgram = require('dgram'); var server = dgram.createSocket('udp4'); console.log("Socket created\n"); server.on("message",function (msg,rinfo) { console.log("Received message"+ msg.toString()); }); server.bind(9000);

 

 

And… that’s it.  A perfectly functioning UDP server, not that it does much yet.  To run the code, in a command prompt, change to the directory you saved server.js to and simply type “node server.js”.  To stop node from running, press CTRL + C twice.

 

dgram is a built in Node library for creating datagram sockets.  When we create the socket with tell it to use udp4, that is to say UDP connection for IP v 4.  Then we add an on “message” handler that for now simply echos whatever data it receives.

 

 

Now lets make a C++ client to talk to our server.  If you are unfamiliar with how to configure SFML, take a look at part 1 of my C++ with SFML tutorial.  In this case we aren’t going to need to link the graphics or audio libraries, which greatly cuts down the size of our project.  If you have trouble setting up a project or simply don’t want to, you can download a pre-configured project here.  Simply open the solution and run.

 

Once you have created and configured a new project, lets add our code.  In my case I created a file called Scoreboard.cpp and added the following code.

 

#include "SFML/Network.hpp" int main(int argc, char* argv[]) { if(argc <2) return-1; sf::IPAddress ip("127.0.0.1"); sf::SocketUDP socket; sf::Packet packet; packet.Append(argv[1],strlen(argv[1])); socket.Send(packet,ip,9000); return0; }

 

 

Extremely simple code again.  The app is simply going to send a string you specify on the command line over a UDP socket, so first we check to make sure you specified a string. Then you create the IP address that represents your server’s location.  In this case you are using 127.0.0.1 which is a special reserved IP address called a loopback, which basically means “this machine”.  In an actual production environment, you would use an external IP address or DNS entry like “gameserver.mydomain.com”.

 

Next we declare our Socket and  Packet.  Think of a Packet as the “stuff” we are sending across the wire.  Next we fill that picket with the string the user passed in on the command line.  The Socket represents the connection to the remote server.  When we say socket.Send() we are saying send packet, on ip IpAddress using port 9000.  Finally we simply exit.

 

You can now run this from the command line using ScoreBoard.exe “The text you want to send”  <—The quotes are critical, or it will end up looking like multiple parameters instead of a single string.  Additionally you could specify the string in your debug settings, then you can simply press F5 to run your code.  To set this value, right click your solution and select Properties, then on the left hand side choose “Command Arguments” and specify your string (quoted again ) there, like this:

 

image

 

 

Now your primitive client and server are up and running.  Start your server first.  Open a command prompt, CD to the directory you created server.js in and type “node server.js” ( no quotes ).   Note, if you didn’t set your PATH to include the path to nodejs, this wont work and instead you will have to fully resolve the path to node.  Now run your SFML application, either using F5 if you specified a Command Argument, or from the command line.

 

Now you should see:

 

image

 

 

Congratulations!  You just created a fully function client and server!  You may have noticed we actually received two socket connections there, an empty one, then our string.  What’s going on here?  Well, SFML sends Packets in two parts, the first contains only the size, the second contains the actually data.  Why?  Beats me.  Not really a big deal, as you will soon see.

 

 

Now, in the next part we will actually make them do something!

 

 

Click here to download the pre-configured Visual Studio project.

Click here to download Server.js.

 

 

Click for part 2

Programming ,

30. January 2012

 

 

 

Alright, this one has absolutely nothing to do with game development, not even remotely, just an upfront warning!

 

I post it here because I just spent the last several hours trying to figure this out and now that I solved it, I felt like sharing in case other people are trying to add a property or attribute to a BlogEngine.Net page.  It’s not hard, once you figure it out!  Anyways, this site is run on BlogEngine and I am rather happy with it.  I have another site I am working on, however I need much more static pages with searchable attributes.  This isn’t really something Blog Engine is designed to do out of the box.  You can of course add tags to blog posts, but that doesn’t really work well for non-chronological pages.

 

So, I added it to the page object itself.  In this case I am going to add a single new entity to the Page, Published Year.  First obviously you need the BlogEngine source code,  download the source release.  Extract the project then open BlogEngine.sln inside the BlogEngine folder in Visual Studio.

 

 

First, in BlogEngine.core, locate Page.cs.

Now add the following code:

 

/// <summary> /// Added by me to support published year /// </summary> private string publishedYear; /// <summary> /// Gets or sets a value indicating Published Year /// </summary> public string PublishedYear { get { return this.publishedYear; } set { base.SetValue("PublishedYear", value, ref this.publishedYear); } }

 

 

Now you need to add a GUI for it, so you can actually set the Published Year.

 

 

Open EditPage.aspx.  First lets add the html.  I put it so it will appear in the side area of the form, above keywords.  Locate the Keywords LI ( included below for reference ) and add the following method:

 

<li> <label class="lbl" for="<%=txtPublishedYear.ClientID %>">Published Year</label> <asp:TextBox runat="server" ID="txtPublishedYear" TextMode="SingleLine" /> </li> <li> <label class="lbl" for="<%=txtKeyword.ClientID %>"><%=Resources.labels.keywords %> </label> <asp:TextBox runat="server" ID="txtKeyword" TextMode="MultiLine" Rows="5" /> </li>

 

 

Also in EditPage.aspx locate the SavePage() javascript method, and change it as follows:

var publishedYear = $("[id$='txtPublishedYear']").val(); var dto = { "id": Querystring('id'), "content": content, "title": title, "description": description, "publishedYear": publishedYear, "keywords": keywords, "slug": slug, "isFrontPage": isFrontPage, "showInList": showInList, "isPublished": isPublished, "parent": parent };

 

Order IS important here.

 

 

Now open EditPage.aspx.cs. Locate the PindPage() method and add:

this.txtPublishedYear.Text = page.PublishedYear;

 

Now locate BtnSaveClick() and modify to look like:

page.Description = this.txtDescription.Text; page.Keywords = this.txtKeyword.Text; page.PublishedYear = this.txtPublishedYear.Text; if (this.cbFrontPage.Checked)

 

 

Finally open AjaxHelper.aspx.cs in the admin folder.  Locate the SavePage() method and make the following change:

public static JsonResponse SavePage( string id, string content, string title, string description, string publishedYear, string keywords, string slug, bool isFrontPage, bool showInList, bool isPublished, string parent)

Remember when I said order was important?  These parameters need to be in the same order as the dto object created earlier.  So make sure your publishedYear setting is in the same position in both.  Now scroll down a little further in the SavePage() method and make the following change:

 

page.Description = description; page.PublishedYear = publishedYear; page.Keywords = keywords;

 

And, you are now done.  Compile and run.  Now when you go into your Page admin um, page, it should look like this:

 

image

 

 

 

Yay!  May seem a small thing, but its incredibly useful for me, and hopefully will be helpful to some of you out there!

Totally Off Topic

26. January 2012

 

 

You may remember me discussing PlayN in previous posts, it’s a Google run cross-platform, open source game library.  Previously the most missing feature was iOS support and frankly that feature is still missing, but there is light at the end of the tunnel!

 

 

PlayN developer Michael Bayne recently made a post announcing he had successfully got the Peas demo running on an iPhone4. IMG_0935Without a doubt this progress is a “very good thing”, as iOS support is easily the most important missing feature of PlayN today.

 

 

Michael’s progress:

 

I got side tracked by trying to get things working on a real device.
The simulator runs the Mono VM in JIT mode (though with various
restrictions in place to ensure that you don't do anything that's
incompatible with AOT compilation), but actually doing AOT compilation
enforces substantially more restrictions. I had to "refactor" IKVM to
contain no references whatsoever to System.Reflection.Emit even if
they were never called. I also bumped into a Mono compiler bug and
spent some time digging into the internals of IKVM and mcs (the Mono
compiler) so that I could come up with a work-around and file a
sensible bug report. It turned out to have already been fixed in trunk
(which made my investigations that much more perplexing), but since
MonoTouch is commercial software, I was necessarily working with the
latest beta release, not trunk; annoying!

Performance of the Pea Physics demo is not stellar on an iPhone 4
(it's quite reasonable, it's just not silky smooth 60 FPS with twenty
or thirty peas moving on screen). It's pretty comparable to what I've
see on actual Android devices. Depending on what Box2D's interfaces
are like, there's a possibility that it could be improved by writing
an interface-compatible implementation of Box2D directly in C#. C#
supports value types, and in a physics simulator, being able to store
your Vec2s and Matrix3s directly inline, rather than separately on the
heap, can substantially improve cache performance. That said, the
Box2D implementation, as is, is not very data-oriented. Rewriting it
to store all of the entity geometry in big flat arrays and to perform
its calculations by iterating over those arrays, rather than following
a zillion pointers through the heap, would probably help a lot on
every platform.

Now that I've got things running on an actual device, I'll go back to
finishing up the platform implementation. IOSCanvas is substantially
done. IOSStorage is done (built on Sqlite). IOSTouch (and IOSPointer)
are done. I need to implement the font and text rendering bits of
IOSGraphics/IOSCanvas. Then IOSSound, IOSNet and other niggling bits.
I'm not sure what I'll do about IOSKeyboard. I'd kind of like an
additional interface for requesting a string of text from the user,
which would allow the keyboard to pop up in "edit a line of text" mode
so that the user can use the standard copy/paste and click with
magnification text navigation. Having the app respond to key events
and attempt to implement text entry directly is a massively bad idea
(on any mobile device), IMO.

 

 

Excellent news and great work Michael! 

 

So for the people looking to see if PlayN works with iOS, the answer is no, but it’s damned close!

Programming

26. January 2012

 

 

OK, so I may just be late to the party on this CtotW, as this product is currently one of the darlings of the programming world but I ignored it completely until now.  What is it I ignored so completely and now am rather enamored of?

 

Node.js

 

 

What exactly is Node?  Well basically they ripped the V8 Engine ( yeah, it’s actually called that ) that powers the Javascript engine in Google Chrome and instead used it for creatinglogo-light server side applications, like you would traditionally make using ASP.Net or JSP.  In addition to providing a server side Javascript implementation, they have implemented a number of modules ( in C++ ) to handle many common tasks, from creating an HTTP server to cryptography.  You can of course create your own add-ons in C++.  Of course, as with all things Google, the build process is a bit convoluted and poorly documented, especially for Windows based developers.

 

 

So, why exactly have I ignored Node until now?  Frankly, I hate developing in Javascript, or at least I thought I did.  Reality is, I hate developing in Javascript for browsers!  Once you move yourself out of the browser, it becomes a much more pleasant experience!

 

 

 

What exactly makes Node so enticing?  You can make light weight, simple, scalable and asynchronous servers with absolutely no other software required.  Simple run node.exe “yourAppName” and you have a running server, no need to install Java or configure a web server.  Consider the following Hello World, a completely functional web server in just a few lines of code:

 

var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(8124, "127.0.0.1");

 

Pretty simple eh?

 

 

There are a few downsides though.  Since Node.exe runs as a single process, so will your application.  This means you are tied to a single core per instance of node.  Also, tooling support is a bit lacking.  I tried out the excellent (in concept ) Cloud9 online IDE but simply put, it didn’t work.  I really hope this changes soon, as a web based IDE sounds about perfect.  I am currently trying out WebStorm, but have formed no opinion yet.  Book support is quite limited as well, with Node Web Development and Node: Up and Running: Scalable Server-Side Code with JavaScript  being the only two published books at the moment, although a number of others are in the works.  No doubt as Node matures, so will the educational and tooling support available for it.

 

 

I am going to do a quick test of using Node.js as a simple game server for an SFML based game.  I will update here accordingly when (if) that is complete.

Cool Thing of the Week

19. January 2012

 

 

 

Our first Blender reference guide chapter has just been put online.  Think of it as a mash-up between a quick reference guide and a video tutorial.  We will cover off the most commonly performed actions in Blender with instructions on how to perform them via hotkey or using the mouse, as well as an accompanying image showing the action in, um… action.  We hope to bridge the gap between regular written instruction and video tutorial.  So for those that like moving at their own pace like you would with a written page, but with the clarity of video, hopefully this guide is perfect for you.

 

 

Obviously if you’ve been using Blender for a while, this will be of very little use to you, but if BorderSelectyou are just starting out, I hope you find it helpful.  If you have not, hopefully these will be of use.  Here for example, is the graphic illustrating the (B)order selection tool.  Click any image for a more detailed version.

 

 

We have many other pages in the work, the next one specifically covers the editing process, but any and all suggestions are welcome!  Feel we’ve glossed over an important command in a certain category, let us know!

 

 

Here is the first release though, covering selection and camera manipulation.  Consider everything to be a WIP, subject to multiple changes.  There are also some tutorials in the works, and they are going to assume you are familiar with everything in the guide.  As we bring more sections online, we will be improving the navigation of course.

Art

Tag cloud

 

The line greatly inspired by Ogre3D seems incredibly accurate to me.  On my initial explorations, that is what it most reminded me of, and that is certainly not an insult.  My nutshell description of Urho3D is:

 

A cross platform, open source, C++ based, Lua and AngelScript scripted game engine that runs on Windows, Mac and Linux and can target all those plus iOS, Android and Raspberry Pi.

 

So the question remains, what’s the developer experience like?  Well, let’s find out!

 

The Source Code

 

Being open source, Urho3D is available on Github.

image

 

I only took a quick browse through the actual code but from what I saw, it’s clean and well written in a modern C++ style.  The project is laid out intuitively, the engine and platforms nicely decoupled and things are pretty much where you would expect them to be.  The code is fairly sparsely commented, but the things that need to be commented, are.  We will touch on the documentation a bit later on.

 

Getting Started

 

Getting started is pretty simple.  Download the source code archive, extract it and use CMake to build the project files for your platform of choice.  I was up and running in a matter of minutes, however I already had all of the required development tools installed and configured.  If you’ve never used CMake before you may be in for a bit of a fight and if something goes wrong, CMake starts to feel strangely like black magic.  For me though, it mostly just worked.  A warning though, download the master branch!  The version linked of their main page is outdated to the point that the documentation doesn’t actually work.  They really should update the official release version so that it matches their getting started manual!

 

Once unzipped, Urho3D looks something like this:

image

 

Simply run the sh or bat file appropriate to your platform and you are good to go.  One thing to be aware of up front, Urho3D has samples in both AngelScript and C++, but by default the C++ projects aren’t created by cmake.  If you want them, when calling the script, add –DURHO3D_SAMPLES=1.  Additionally, Lua support isn’t added out of the box, if you want Lua support as –DURHO3D_LUA=1.

 

So for example, to get started on Windows using Visual Studio 2013, with Lua and C++ sample support, run:

cmake_vs2013.bat –DURHO3D_SAMPLES=1 –DURHO3D_LUA=1

Now if you go into the Build directory, you will see Visual Studio ( or XCode, or Makefile, whatever you chose ) projects.

 

image

 

Simply open Urho3D.sln in Visual Studio and you are done.

 

Samples Samples and More Samples

 

This is one area where Urho3D is well represented.  There are a number of included samples, written in both AngelScript and C++.  Here they are:

 

image

 

For C++, each sample is a project within your solution.  In the case of AngelScript however, each is simply a script file to be run.  Once you’ve built the Engine, you should have a tool named Urho3DPlayer ( or Urho3DPlayer_d if you built for debug ).  This is a command line utility, simply run it and pass in the path to a script to run.  The scripts are located under the Bin folder in the directory /Data/Scripts.

image

 

They are the sample examples as the C++, except of course implemented as AngelScript.

From the command line, in the bin folder, running:

Urho3DPlayer Data\Scripts\11_Physics.as

Will then load and run the script:

image

 

It’s worth noting, I also used the –w switch to run the player in Windowed mode so I could take a screen shot.  Hit ESC to exit.  Oh and Urho3D has annoying behavior of grabbing your mouse cursor, don’t worry when you lose your mouse cursor ( even Windowed ), exit with ESC or alt-tab away and you get your cursor back.  I hate really hate when windowed applications take complete control of my mouse!

 

The code in the samples is well documented, and they cover a wide variety of topics.  This is most likely going to be your primary learning source for getting up to speed quick.

 

To get an idea of a Urho3D application’s structure, let’s take a look at one of the samples, 03_Sprites.  When run, it will do this (except in motion that is):

 

image

 

Now let’s take a look at the corresponding AngelScript and C++ sources.

 

03_Sprites.as

 

// Moving sprites example.
// This sample demonstrates:
//     - Adding Sprite elements to the UI
//     - Storing custom data (sprite velocity) inside UI elements
//     - Handling frame update events in which the sprites are moved

#include "Scripts/Utilities/Sample.as"

// Number of sprites to draw
const uint NUM_SPRITES = 100;

Array<Sprite@> sprites;

void Start()
{
    // Execute the common startup for samples
    SampleStart();

    // Create the sprites to the user interface
    CreateSprites();

    // Hook up to the frame update events
    SubscribeToEvents();
}

void CreateSprites()
{
    // Get rendering window size as floats
    float width = graphics.width;
    float height = graphics.height;

    // Get the Urho3D fish texture
    Texture2D@ decalTex = cache.GetResource("Texture2D", "Textures/UrhoDecal.dds");

    for (uint i = 0; i < NUM_SPRITES; ++i)
    {
        // Create a new sprite, set it to use the texture
        Sprite@ sprite = Sprite();
        sprite.texture = decalTex;

        // The UI root element is as big as the rendering window, set random position within it
        sprite.position = Vector2(Random() * width, Random() * height);

        // Set sprite size & hotspot in its center
        sprite.size = IntVector2(128, 128);
        sprite.hotSpot = IntVector2(64, 64);

        // Set random rotation in degrees and random scale
        sprite.rotation = Random() * 360.0f;
        sprite.SetScale(Random(1.0f) + 0.5f);

        // Set random color and additive blending mode
        sprite.color = Color(Random(0.5f) + 0.5f, Random(0.5f) + 0.5f, Random(0.5f) + 0.5f);
        sprite.blendMode = BLEND_ADD;

        // Add as a child of the root UI element
        ui.root.AddChild(sprite);

        // Store sprite's velocity as a custom variable
        sprite.vars["Velocity"] = Vector2(Random(200.0f) - 100.0f, Random(200.0f) - 100.0f);

        // Store sprites to our own container for easy movement update iteration
        sprites.Push(sprite);
    }
}

void MoveSprites(float timeStep)
{
    float width = graphics.width;
    float height = graphics.height;

    // Go through all sprites
    for (uint i = 0; i < sprites.length; ++i)
    {
        Sprite@ sprite = sprites[i];

        // Rotate
        float newRot = sprite.rotation + timeStep * 30.0f;
        sprite.rotation = newRot;

        // Move, wrap around rendering window edges
        Vector2 newPos = sprite.position + sprite.vars["Velocity"].GetVector2() * timeStep;
        if (newPos.x < 0.0f)
            newPos.x += width;
        if (newPos.x >= width)
            newPos.x -= width;
        if (newPos.y < 0.0f)
            newPos.y += height;
        if (newPos.y >= height)
            newPos.y -= height;
        sprite.position = newPos;
    }
}

void SubscribeToEvents()
{
    // Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent("Update", "HandleUpdate");
}

void HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    // Take the frame time step, which is stored as a float
    float timeStep = eventData["TimeStep"].GetFloat();

    // Move sprites, scale movement with time step
    MoveSprites(timeStep);
}

// Create XML patch instructions for screen joystick layout specific to this sample app
String patchInstructions =
        "<patch>" +
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" +
        "        <attribute name=\"Is Visible\" value=\"false\" />" +
        "    </add>" +
        "</patch>";

 

And now the C++ versions:

Sprite.h

#pragma once

#include "Sample.h"

/// Moving sprites example.
/// This sample demonstrates:
///     - Adding Sprite elements to the UI
///     - Storing custom data (sprite velocity) inside UI elements
///     - Handling frame update events in which the sprites are moved
class Sprites : public Sample
{
    // Enable type information.
    OBJECT(Sprites);

public:
    /// Construct.
    Sprites(Context* context);

    /// Setup after engine initialization and before running the main loop.
    virtual void Start();

protected:
    /// Return XML patch instructions for screen joystick layout for a specific sample app, if any.
    virtual String GetScreenJoystickPatchString() const { return
        "<patch>"
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">"
        "        <attribute name=\"Is Visible\" value=\"false\" />"
        "    </add>"
        "</patch>";
    }

private:
    /// Construct the sprites.
    void CreateSprites();
    /// Move the sprites using the delta time step given.
    void MoveSprites(float timeStep);
    /// Subscribe to application-wide logic update events.
    void SubscribeToEvents();
    /// Handle the logic update event.
    void HandleUpdate(StringHash eventType, VariantMap& eventData);

    /// Vector to store the sprites for iterating through them.
    Vector<SharedPtr<Sprite> > sprites_;
};

 

Sprite.cpp

#include "CoreEvents.h"
#include "Engine.h"
#include "Graphics.h"
#include "ResourceCache.h"
#include "Sprite.h"
#include "Texture2D.h"
#include "UI.h"

#include "Sprites.h"

#include "DebugNew.h"

// Number of sprites to draw
static const unsigned NUM_SPRITES = 100;

// Custom variable identifier for storing sprite velocity within the UI element
static const StringHash VAR_VELOCITY("Velocity");

DEFINE_APPLICATION_MAIN(Sprites)

Sprites::Sprites(Context* context) :
    Sample(context)
{
}

void Sprites::Start()
{
    // Execute base class startup
    Sample::Start();

    // Create the sprites to the user interface
    CreateSprites();

    // Hook up to the frame update events
    SubscribeToEvents();
}

void Sprites::CreateSprites()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    Graphics* graphics = GetSubsystem<Graphics>();
    UI* ui = GetSubsystem<UI>();

    // Get rendering window size as floats
    float width = (float)graphics->GetWidth();
    float height = (float)graphics->GetHeight();

    // Get the Urho3D fish texture
    Texture2D* decalTex = cache->GetResource<Texture2D>("Textures/UrhoDecal.dds");

    for (unsigned i = 0; i < NUM_SPRITES; ++i)
    {
        // Create a new sprite, set it to use the texture
        SharedPtr<Sprite> sprite(new Sprite(context_));
        sprite->SetTexture(decalTex);

        // The UI root element is as big as the rendering window, set random position within it
        sprite->SetPosition(Vector2(Random() * width, Random() * height));

        // Set sprite size & hotspot in its center
        sprite->SetSize(IntVector2(128, 128));
        sprite->SetHotSpot(IntVector2(64, 64));

        // Set random rotation in degrees and random scale
        sprite->SetRotation(Random() * 360.0f);
        sprite->SetScale(Random(1.0f) + 0.5f);

        // Set random color and additive blending mode
        sprite->SetColor(Color(Random(0.5f) + 0.5f, Random(0.5f) + 0.5f, Random(0.5f) + 0.5f));
        sprite->SetBlendMode(BLEND_ADD);

        // Add as a child of the root UI element
        ui->GetRoot()->AddChild(sprite);

        // Store sprite's velocity as a custom variable
        sprite->SetVar(VAR_VELOCITY, Vector2(Random(200.0f) - 100.0f, Random(200.0f) - 100.0f));

        // Store sprites to our own container for easy movement update iteration
        sprites_.Push(sprite);
    }
}

void Sprites::MoveSprites(float timeStep)
{
    Graphics* graphics = GetSubsystem<Graphics>();
    float width = (float)graphics->GetWidth();
    float height = (float)graphics->GetHeight();

    // Go through all sprites
    for (unsigned i = 0; i < sprites_.Size(); ++i)
    {
        Sprite* sprite = sprites_[i];

        // Rotate
        float newRot = sprite->GetRotation() + timeStep * 30.0f;
        sprite->SetRotation(newRot);
        
        // Move, wrap around rendering window edges
        Vector2 newPos = sprite->GetPosition() + sprite->GetVar(VAR_VELOCITY).GetVector2() * timeStep;
        if (newPos.x_ < 0.0f)
            newPos.x_ += width;
        if (newPos.x_ >= width)
            newPos.x_ -= width;
        if (newPos.y_ < 0.0f)
            newPos.y_ += height;
        if (newPos.y_ >= height)
            newPos.y_ -= height;
        sprite->SetPosition(newPos);
    }
}

void Sprites::SubscribeToEvents()
{
    // Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent(E_UPDATE, HANDLER(Sprites, HandleUpdate));
}

void Sprites::HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    using namespace Update;

    // Take the frame time step, which is stored as a float
    float timeStep = eventData[P_TIMESTEP].GetFloat();
    
    // Move sprites, scale movement with time step
    MoveSprites(timeStep);
}

 

EDIT: And the Lua example as well:

03_Sprites.lua

-- Moving sprites example.
-- This sample demonstrates:
--     - Adding Sprite elements to the UI
--     - Storing custom data (sprite velocity) inside UI elements
--     - Handling frame update events in which the sprites are moved

require "LuaScripts/Utilities/Sample"

local numSprites = 100
local sprites = {}

-- Custom variable identifier for storing sprite velocity within the UI element
local VAR_VELOCITY = StringHash("Velocity")

function Start()
    -- Execute the common startup for samples
    SampleStart()

    -- Create the sprites to the user interface
    CreateSprites()

    -- Hook up to the frame update events
    SubscribeToEvents()
end

function CreateSprites()
    local decalTex = cache:GetResource("Texture2D", "Textures/UrhoDecal.dds")

    local width = graphics.width
    local height = graphics.height

    for i = 1, numSprites do
        -- Create a new sprite, set it to use the texture
        local sprite = Sprite:new()
        sprite.texture = decalTex
        sprite:SetFullImageRect()

        -- The UI root element is as big as the rendering window, set random position within it
        sprite.position = Vector2(Random(width), Random(height))

        -- Set sprite size & hotspot in its center
        sprite:SetSize(128, 128)
        sprite.hotSpot = IntVector2(64, 64)

        -- Set random rotation in degrees and random scale
        sprite.rotation = Random(360.0)
        sprite.scale = Vector2(1.0, 1.0) * (Random(1.0) + 0.5)

        -- Set random color and additive blending mode
        sprite:SetColor(Color(Random(0.5) + 0.5, Random(0.5) + 0.5, Random(0.5) + 0.5, 1.0))
        sprite.blendMode = BLEND_ADD

        -- Add as a child of the root UI element
        ui.root:AddChild(sprite)

        -- Store sprite's velocity as a custom variable
        sprite:SetVar(VAR_VELOCITY, Variant(Vector2(Random(200.0) - 100.0, Random(200.0) - 100.0)))

        table.insert(sprites, sprite)
    end
end

function SubscribeToEvents()
    -- Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent("Update", "HandleUpdate")
end

function MoveSprites(timeStep)
    local width = graphics.width
    local height = graphics.height

    for i = 1, numSprites do
        local sprite = sprites[i]
        sprite.rotation = sprite.rotation + timeStep * 30

        local newPos = sprite.position
        newPos = newPos + sprite:GetVar(VAR_VELOCITY):GetVector2() * timeStep

        if newPos.x >= width then
            newPos.x = newPos.x - width
        elseif newPos.x < 0 then
            newPos.x = newPos.x + width
        end
        if newPos.y >= height then
            newPos.y = newPos.y - height
        elseif newPos.y < 0 then
            newPos.y = newPos.y + height
        end
        sprite.position = newPos
    end
end

function HandleUpdate(eventType, eventData)
    local timeStep = eventData:GetFloat("TimeStep")

    MoveSprites(timeStep)
end

-- Create XML patch instructions for screen joystick layout specific to this sample app
function GetScreenJoystickPatchString()
    return
        "<patch>" ..
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" ..
        "        <attribute name=\"Is Visible\" value=\"false\" />" ..
        "    </add>" ..
        "</patch>"
end

 

As you can see, the code is clean enough and well enough documented to learn from. Unfortunately there aren't equivalent Lua examples right now.

EDIT: Ok, my bad.  Fortunately there are in fact Lua examples as well!  They were just very well hidden in the /Bin/Data/LuaScript folder.

 

Hello World

 

Urho3D commits a common sin and one that drives me absolutely nuts with game engines.  It’s Hello World, in fact, all of it’s C++ examples are built over a “Sample” class.  This means when the reader wants to start from scratch on their own project, they have to tear through the base class to figure out what goes into a core application.  I get why they do this, so they can focus on the feature they want to show, but at least one example should be as complete as possible with no underlying class to build on.  Fortunately I have done this for you.  The following is basically the “minimum usable” Urho3D application:

 

TestMain.h

#pragma once

#include "Application.h"


using namespace Urho3D;

class TestMain : public Urho3D::Application {
   OBJECT(TestMain);

public:
   TestMain(Urho3D::Context*);

   virtual void Setup();
   virtual void Start();
   virtual void Stop() {}

private:
   void onKeyDown(StringHash,  VariantMap&);

};

 

TestMain.cpp

#include "TestMain.h"
#include "Engine.h"
#include "Graphics.h"
#include "Input.h"
#include "InputEvents.h"
#include "ResourceCache.h"
#include "UI.h"
#include "Font.h"
#include "Text.h"

using namespace Urho3D;

DEFINE_APPLICATION_MAIN(TestMain)

TestMain::TestMain(Urho3D::Context* context) : Application(context){
}

void TestMain::Setup(){
   engineParameters_["FullScreen"] = false;
}

void TestMain::Start(){
   SubscribeToEvent(E_KEYDOWN, HANDLER(TestMain,onKeyDown));

   SharedPtr<Text> text(new Text(context_));
   text->SetText("Hello Cruel World!");
   text->SetColor(Color::WHITE);
   text->SetFont(GetSubsystem<ResourceCache>()->GetResource<Font>("Fonts/BlueHighway.ttf"), 42);
   text->SetHorizontalAlignment(HA_CENTER);
   text->SetVerticalAlignment(VA_CENTER);

   GetSubsystem<UI>()->GetRoot()->AddChild(text);
}

void TestMain::onKeyDown(StringHash event, VariantMap& data){
   engine_->Exit();
}

 

It creates a windowed Hello World application, displays the text “Hello Cruel World” in white, centered to the screen and waits for any key to be pressed before exiting.

While basic, it should give you some idea how Urho3D works.  There are times, like when trying to figure out parameters engineParameters takes that you really wish for better reference documentation, but it was fairly simple to get things up and running.  I did have a bit of a struggle with life cycle, when I tried to put more logic into Setup() instead of Start() but otherwise things mostly worked how I expected.   Speaking of documentation…

 

The Documentation

 

So what’s the documentation like?  It’s split in to two parts, the documentation that has been written covering the various aspects, tasks and systems in Urho3D.  There is also an auto generated class reference. You can read the documentation here.

 

As you can see, most of the major systems are covered:

image

 

The documentation is well written in clear English, and for the most part covers what you would expect it to.  For an open source project I have to say, the overall documentation level is very good.  The only area I was somewhat let down by was the reference material.

 

There is an automatically generated class reference available:

image

But the details are pretty sparse:

image

 

So, for example, if you are hunting down say… what audio formats are supported, this information can be a bit hard to find and may result in you having to jump into the source code.  I do wish there was more implementation specific details in the reference materials.

 

Perhaps I am nit picking at this point…  working so much in Java lately, JavaDoc has really spoiled me.

 

In summary, the documentation is solid, great in fact for an open source project.  I would however appreciate more detail in the reference material.

 

Tools

 

Part of what makes an engine and engine is the tooling it supports.  Urho3D is no exception.  We already mentioned Urho3DPlayer, but there are several other tools, one of which is actually run in the player.  There is a full blown 3D level editor:

image

 

The editor enables you to create and edit several node types:

image

 

And provides context appropriate property editing:

image

 

It’s not going to win any beauty pageants, but it is a full functioning 3D world editor written entirely in AngelScript.  So if it doesn’t have functionality you want, simply add it.  The code is all available in the Bin\Data\Scripts\Editor folder:

image

 

With full code access, you should easily be able to extend the editor to fit whatever type of game you are looking at creating.

 

In addition to the editor, there are a number of other tools.  There is AssetImporter from the Assimp project, for importing 3D assets.  There is also a tool for importing Ogre3D assets.  PackageTool, for pulling your assets all together, a shader compiler, lightmap generator and more.

 

Summary

 

Urho3D is an impressive, well documented, cross platform game engine with clean accessible code and a ton of examples.  There are of course some negatives too.  The tools aren’t nearly as polished as you see in many commercial engines, the reference material could be a bit more extensive and the community isn’t huge.  I can’t speak to performance as I never dove in that deeply.  Is it worth checking out for your own game project?  Well, if control and open source are important to you and you like C++, AngelScript and/or Lua, I would most certainly give it a look. 

 

What do you think, does Urdo3D look interesting to you?  Would you like to see more in depth tutorials from GameFromScratch.com?  Let me know!

Programming , ,

blog comments powered by Disqus

Month List

Popular Comments