The Unreal Engine 4 Rosetta Stone

21. April 2014

 

Comprehending any large code base is never a simple factor.  This is especially true of C++ with hits heavily used (and abused) typedef system.  The Unreal Engine has a very well defined and consistent naming convention but trying to crack it can take a bit of effort, as it’s explained piecemeal throughout the documentation. RosettaStone That is, until I found the Coding Standard document, which frankly is the very first page a C++ programmer working with UE4 should start with.  This document is the titular Rosetta Stone, the method that makes reading UE code possible.

 

Understanding their naming conventions will help you a great deal when trying to work through code samples.  A few of their choices strike me as a bit unusual, especially if you were raised on Hungarian like I was.  Here are the naming convention:

  • The first letter of each word in a name (e.g. type or variable) is capitalized, and there is usually no underscore between words. For example, Health and UPrimitiveComponent, but not lastMouseCoordinates or delta_coordinates.

  • Type names are prefixed with an additional upper-case letter to distinguish them from variable names. For example, FSkin is a type name, and Skin is an instance of a FSkin.

    • Template classes are prefixed by T.

    • Classes that inherit from UObject are prefixed by U.

    • Classes that inherit from AActor are prefixed by A.

    • Classes that inherit from SWidget are prefixed by S.

    • Classes that are abstract interfaces are prefixed by I.

    • Most other classes are prefixed by F, though some subsystems use other letters.

  • Type and variable names are nouns.

  • Method names are verbs that describe the method's effect, or describe the return value of a method that has no effect.

Variable, method, and class names should be clear, unambiguous, and descriptive. The greater the scope of the name, the greater the importance of a good, descriptive name. Avoid over-abbreviation.

All variables should be declared one at time so that a comment on the meaning of the variable can be provided. Also, the JavaDocs style requires it. You can use multi-line or single line comments before a variable, and the blank line is optional for grouping variables.

All functions that return a bool should ask a true/false question, such as "IsVisible()", or "ShouldClearBuffer()". All boolean variables must be prefixed with a "b" character (e.g. "bPendingDestruction", or "bHasFadedIn").

A procedure (a function with no return value) should use a strong verb followed by an object. An exception is if the object of the method is the object it is in; then the object is understood from context. Names to avoid include those beginning with "Handle" and "Process"; the verbs are ambiguous.

Though not required, we encourage you to prefix function parameter names with "Out" if they are passed by reference and the function is expected to write to that value. This makes it obvious that the value passed in this argument will be replaced by the function.

 

This explains all the AClass and UProperty you will encounter through out the code, and explains the far to common FSomethings you see in the code..

 

There are a few things I find unwieldy about these choices.  First, I am so used to instances starting with lower case that this seems like Anathema to me.  Second, if you are going to prefix with all capital letters, why not BBoolValue instead of bBoolValue, this seems inconsitent to me.  Next, why F for types? Finally why SWidget and S instead of Widget and W?  WButton makes a ton more sense than SButton for example.

 

At the end of the day it doesn’t really matter, the most important thing is to be consistent, which they have.  Now with a thorough understanding of their naming convention, groking the code is a heck of a lot easier.

 

Also of great important are the C++ type usage guidelines.  This is both a power and flaw of working with C++, there are more types than grains of sand in the desert, so knowing which to use is critical.

 

Portable Aliases for Basic C++ Types

  • bool for boolean values (NEVER assume the size of bool). BOOL will not compile.

  • TCHAR for a character (NEVER assume the size of TCHAR)

  • uint8 for unsigned bytes (1 byte)

  • int8 for signed bytes (1 byte)

  • uint16 for unsigned "shorts" (2 bytes)

  • int16 for signed "shorts" (2 bytes)

  • uint32 for unsigned ints (4 bytes)

  • int32 for signed ints (4 bytes)

  • uint64 for unsigned "quad words" (8 bytes)

  • int64 for signed "quad words" (8 bytes)

  • float for single precision floating point (4 bytes)

  • double for double precision floating point (8 bytes)

  • PTRINT for an integer that may hold a pointer (NEVER assume the size of PTRINT)

Don't use the C++ int type in portable code, since it's dependent on the compiler how large it is.

 

So if you are just starting out with C++ programming in Unreal, start here, it will make the journey a lot easier.

 

Finally C++ 11 guidelines are also important.  C++11 support across compilers is by no means universal but many of the features of C++11 are pretty damned useful.  Keep in mind, these guidelines are for Unreal staff working on the engine, not the end user working with the engine, so if you are say… only using Visual C++ 13, then feel free to use whatever features you want.  If you want to target as many platforms as possible though, you should be mindful of these instructions:

 

C++ 11 and Modern Language Syntax

Unreal Engine is built to be massively portable to many C++ compilers, so we're careful to use features that are compatible with the compilers we can imagine supporting. Sometimes features are so useful that we'll wrap them up in macros and use them pervasively (such as the 'override' keyword), but usually we'll wait until all of the compilers we could imagine supporting are up to the latest standard.

We are utilizing certain C++ 11 language features that appear to be well-supported across modern compilers, such as the "auto" keyword, range-based-for and lambdas. In some cases we're able to wrap up usage of these features in preprocessor conditionals (such as rvalue references in containers.) However, certain language features we may opt to avoid entirely until we're confident we won't be surprised by a new platform appearing that cannot digest the syntax.

Unless specified below as a modern C++ compiler feature we are supporting, you should refrain from using compiler-specific language features unless they are wrapped in preprocessor macros or conditionals and used sparingly.

The 'auto' Keyword

The 'auto' keyword is supported by all compilers UE4 targets and you are encouraged to use it in your code where it makes sense to do so.

Remember you can and should use const, & or * with auto just like you would with the type name. With auto, this will coerce the inferred type to be what you want.

We encourage use of the auto keyword for iterator loops (eliminates boilerplate), and also when you are initializing a variable to a new instance (eliminates redundant type name.) Some of the other uses are more contentious, but feel free to use it however you want for now and we can learn and improve best practices as we go.

Tip: If you hover over a variable in Visual Studio, it will usually tell you the inferred type.

Range Based For

This is allowed in all engine and editor code and encouraged where it can help to keep the code easier to understand and more maintainable.

Lambdas and Anonymous Functions

Lambdas are now allowed, however we are cautious about use of stateful lambdas that capture stack variables -- we're still learning about where those are appropriate. Also, stateful lambdas cannot be assigned to function pointers which we tend to use a lot. We expect to update this documentation in the future as we establish best practices.

 

So, basically ranged based for loops, stateless lambdas good, stateful lambda bad and auto is a maybe.  For the remaining features that aren’t cross platform like override, they’ve provided preprocessor conditionals to work with them.  I really wish they listed them all here though.

Programming ,




LibGDX finally reaches version 1.0!

20. April 2014

 

So it’s taken a while, 4 years to be precise, but LibGDX, the cross platform Java game development engine, has finally hit the milestone release 1.0. 

 

Everyone thought the day would never come. But here it is. libGDX 1.0 is officially released! Let me quickly run you through the most important changes:

Read the full CHANGES file for more goodies.

To try out our new setup, start here!

If you have a Gradle-based project, make sure to update the gdxVersion to “1.0.0″ and refresh your IDE project files! The new snapshot (==nightly) version is “1.0.1-SNAPSHOT”

Besides the usual bug fixing and enhancements, we also cleaned up our libGDX repo, website and wiki for the 1.0 release. The old setup UI has been deprecated, the audio and image extensions have been removed, and the demos have been gradelized and put into their own repositories. You can now also directly test the demos in your browser (or desktop, or Android device)!

Finally, we’ve setup a Patreon, that allows users to contribute to our infrastructure costs. This has been so successful, that we were able to move our build and website server to Hetzner. After the move and adding some build magic, the build now takes 10 minutes instead of 1 hour and 45 minutes. Thanks to all the patrons, you really made a difference in my life!

Going forward, we’ll try to have a much shorter release cycle (2 weeks – 1 month). The major version of libGDX will stay at 1 for the foreseeable future. The minor version will be increased when API breaking changes are introduced. The patch version will be increased in case of bug fixes and API additions. Releasing often allows you to stay as up-to-date as possible before freezing your libGDX version for a release.

 

They also have a brief blurb about the future:

With all pieces in place, Q1 2014 was used to polish up libGDX’s user experience and documentation for the 1.0 release. We now support all JVM development environments (Eclipse, IDEA, Netbeans, CLI) through our Gradle-based builds. Our build server has been upgraded so we can push out new releases much more easily (and hence regularly!). Our repository has been cleaned up, any clutter has been removed. The Wiki has been updated to reflect the latest state of APIs and setup procedures. We are ready to pull the trigger. After 4 years of development, libGDX has finally reached version 1.0.

 

There is also a detailed history of the LibGDX project.  You can read all about it in the announcement.

 

Congratulations to the LibGDX team!

News




Substance Painter release Beta 3 to Steam

17. April 2014

 

I suck at texturing.

 

There, I said it.  I love 3D modeling, I even enjoy rigging and animating.  While not my favorite activity, I am even OK with UV unwrapping…

 

But texturing, I suck at texture mapping.

 

Over the years I have tried a number of solutions that make texturing easier going back to the early days of 3D Studio Max plugins that allow you to paint directly on your models.  Since then, those tools have become progressively more built in to the base package but at the end of the day, the vast majority of texturing still takes place in Photoshop and I still suck at it.

 

Enter Substance Painter.  It appeared on Steam about a month back and I’ve been playing around with it ever since.  I intend to cover it in more detail soon, in fact I would have already if it weren't for the massive influx of goodies that came with GDC this year.  Anyways, stay tuned for more details shortly…image

 

For now, a spot a of news.  Beta 3 was just released.  Oh, and if you buy during the beta it’s 50% off.

 

Enough talking, so what exactly is Substance Painter?

 

Short version; it’s the program that makes me not completely suck at texturing.  That’s about the biggest endorsement I can give.

 

Long version, well, I’ll use their wording for that:

 

Substance Painter is a brand new 3D Painting app featuring never before seen features and workflow improvements to make the creation of textures for modern games easier than ever.


At Allegorithmic, we have a long history of working very closely with our customers, from the small independents to the largest AAA studios. Today we want you to help us design the ultimate painting tool and bring innovation and state of the art technology to every artist out there at a fair price.

 

Today, as the title suggests, they released Beta 3.  As to what’s new in BETA 3:

Testing focus

  • 2D View
Change list
  • Added: Seamless 2D View!
  • Added: Bitmap layer masks
  • Added: Environment exposure control
  • Updated: Fill Layers now use the Tools windows to set their properties
  • Updated: Materials can be applied to Fill Layers
  • Updated: Added more stencils in the stencil library
  • Updated: Particles presets updated for faster computation
  • Updated: PBR shader optimization and quality improvement for lower quality settings
  • Fixed: Layers thumbnails are linked to the currently selected channel
  • Fixed: Lots of crashes

 

Sound interesting?  Here is a video of Substance Painter in action:

There is also a free trial available.  It’s a stand alone program, although some of the import options are disabled right now ( I used OBJ personally, from Blender ).  Keep in mind it is a beta, and feels Beta-like at times.  Some features are currently missing and performance can occasionally suffer.  On the other hand, outside of some missing features, it feels production ready.  I hope to have a more detailed preview available soon.

 

If you try it out, let me know what you think.

Art, News ,




LibGDX Tutorial 11: Tiled Maps Part 1: Simple Orthogonal Maps

16. April 2014

 

If you’ve never used Tiled read this first!

 

In this tutorial part we are going to look at loading orthogonal maps in LibGDX.  Orthogonal basically means “at a right angle to” which is a fancy way of saying the camera is looking straight at the scene.  Another much less fancy word for this style of game is “top down”.  Common examples include almost every single game from the 16Bit generation of consoles such as Zelda or MegaMan.

 

One of the first problems you are going to encounter is how do you create your maps?  One very common solution is the Tiled Map Editor which fortunately I just completed a tutorial on!  This tutorial assumes you know how to generate a TMX file, so if you haven’t be sure to go through the linked tutorial.  Fortunately LibGDX makes it very easy to work with TMX files.

 

First things first we need to copy the TMX and any/all tilemap image files used to your assets folder, like so:

image

You may notice unlike earlier tutorials I am currently using IntelliJ.  With the recent switch to Gradle it is much easier to get up and running in IntelliJ and I massively prefer it to Eclipse.  That said, everything I say is equally valid in Eclipse or IntelliJ and when there are differences, I will point them out.  If you want to get started with IntelliJ read here.

 

Alright, back on topic…

 

Now that you have the map and tilesets in your project, let’s jump right in with the code:

 

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapRenderer;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;

public class TiledTest extends ApplicationAdapter implements InputProcessor {
    Texture img;
    TiledMap tiledMap;
    OrthographicCamera camera;
    TiledMapRenderer tiledMapRenderer;
    
    @Override
    public void create () {
        float w = Gdx.graphics.getWidth();
        float h = Gdx.graphics.getHeight();

        camera = new OrthographicCamera();
        camera.setToOrtho(false,w,h);
        camera.update();
        tiledMap = new TmxMapLoader().load("MyCrappyMap.tmx");
        tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap);
        Gdx.input.setInputProcessor(this);
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        camera.update();
        tiledMapRenderer.setView(camera);
        tiledMapRenderer.render();
    }

    @Override
    public boolean keyDown(int keycode) {
        return false;
    }

    @Override
    public boolean keyUp(int keycode) {
        if(keycode == Input.Keys.LEFT)
            camera.translate(-32,0);
        if(keycode == Input.Keys.RIGHT)
            camera.translate(32,0);
        if(keycode == Input.Keys.UP)
            camera.translate(0,-32);
        if(keycode == Input.Keys.DOWN)
            camera.translate(0,32);
        if(keycode == Input.Keys.NUM_1)
            tiledMap.getLayers().get(0).setVisible(!tiledMap.getLayers().get(0).isVisible());
        if(keycode == Input.Keys.NUM_2)
            tiledMap.getLayers().get(1).setVisible(!tiledMap.getLayers().get(1).isVisible());
        return false;
    }

    @Override
    public boolean keyTyped(char character) {

        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}

 

When you run the code you should see your map.  Pressing the arrow keys will scroll around the map ( and show bright red when you’ve moved beyond the extents of your map ) .  Pressing 0 or 1 will toggle the visibility of each of the two layers in your map.  ( See the tutorial on Tiled if that makes no sense ).

 

image

 

The impressive thing here is how little code was required to accomplish so much.  In a nutshell it was basically just this:

 

camera = new OrthographicCamera();
camera.setToOrtho(false,w,h);
camera.update();
tiledMap = new TmxMapLoader().load("MyCrappyMap.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap);

 

We create an OrthographicCamera, set it to the dimensions of the screen and update() it.  Next we load our map using TmxMapLoader.load() and create a OrthogonalTiledMapRenderer passing in our tiled map.

 

In our render method:

camera.update();
tiledMapRenderer.setView(camera);
tiledMapRenderer.render();

Basically update the camera ( in case we moved it using arrow keys ), pass it in to the TiledMapRenderer with setView() and finally render() the map.  That’s it.

As you can see in our key handler:

 

@Override
public boolean keyUp(int keycode) {
    if(keycode == Input.Keys.LEFT)
        camera.translate(-32,0);
    if(keycode == Input.Keys.RIGHT)
        camera.translate(32,0);
    if(keycode == Input.Keys.UP)
        camera.translate(0,-32);
    if(keycode == Input.Keys.DOWN)
        camera.translate(0,32);
    if(keycode == Input.Keys.NUM_1)
        tiledMap.getLayers().get(0).setVisible(!tiledMap.getLayers().get(0).isVisible());
    if(keycode == Input.Keys.NUM_2)
        tiledMap.getLayers().get(1).setVisible(!tiledMap.getLayers().get(1).isVisible());
    return false;
}

 

Navigating around the map is simply a matter of moving around the camera.  We move in 32pixel chunks because those are the size of our tiles.  So basically we move the camera left/right/up/down by one tile each time an arrow key is pressed.  In the event the 0 or 1 key are pressed we toggle the visibility of that particular layer.  As you can see, you can access the TileMap layers using the getLayers().get() function.

 

In the next part we will look at adding some more complex functionality.

Programming , , ,




A quick look at Tiled. An open source 2D level editor

15. April 2014

 

One very common requirement for even the most simple game is a level editor.  The level of sophistication required varies massively from game to game but a lot of the functionality is pretty common.  At the very base level, you need a tool to layout the graphics that make up your world.  Slightly more advanced, you need to define layers, properties and collision volumes.  Often people roll their own solution but you certainly don’t have to.  One very popular 2D level editor is Tiled Map Editor which exports in TMX format, perhaps the most supported 2D game format ( Cocos2D, LOVE, LibGDX and many others all support TMX out of the box ).  As I am going to be writing a tutorial about using tiled maps in LibGDX, I figured I would give a quick introduction to Tiled first.  Keep in mind, we are only going to scratch the very surface of what Tiled is capable of.

 

First off, download and install Tiled.  It has binaries available for Windows and Mac and a source (and daily builds) release available for Linux.  You can download Tiled here.  The documentation is available here.

 

The Tiled UI is pretty straight forward, although it looks quite different across platforms.  Today I will be using the MacOS version.

 

T1

 

A tiled map is fundamentally simple.  You are basically making a grid of tiles.  A tile is a fixed size image within a larger image.  The larger image is called a tile sheet.  It’s somewhat like working with legos to make a level.  Here is an example tilesheet ( taken from here ):

 

Tilesheet

 

It’s a 512x512 image composed of a number of tiles that we are going to paint our level with.

 

Now that we have our tiles, let’s create our map.  Tiled has the ability to create Orthogonal ( straight on or “top down” perspective maps ) or IsoMetric ( angled perspective ).  In this example we are creating a Orthogonal map.  Next you need to decide how many tiles your map consists of in each direction.  Yes, tiled maps are always rectangular in shape.  Finally you need to decide your tile dimensions in pixels.  Looking at the tile map above it isn’t clear how large each tile is, but that is because some of the larger constructs are actually composed of a number of tiles.  You will see how that works in a few seconds, for now simply select 32x32 pixels for tile size and 32x32 tiles for map size.  In real pixel terms, this makes our map 1024 pixels by 1024 pixels.

 

T2

 

Now we need to load our tile set into Tiled. Select Map->New Tileset

 

T3

 

Now in the resulting dialog name it and otherwise we keep the defaults.  Our tile set is made up of 32x32 tiles, so those values work.  The background colour is used if you use a particular colour colour to mark transparency.  In this case we are using the alpha channel to determine transparency, so we don’t need to set a colour value.

 

T4

 

Now if you look at the bottom corner of Tiled you will see a grid of tiles available.  You simply select a tile, then paint in the right window with it.  

 

T5

 

Let’s start by quickly paint our entire map with a grass tile.  Click a grass tile in the tile sets window, like so:

 

T6

 

Now in the left hand window, select the Fill Tool ( or hit F ), then click in the window, and it will be filed with the tile selected filling our level with a nice grass base.

 

T7

 

Now lets say we want to quickly fill in some roads.  The road tile is actually composed of four separate tiles.  This is easily handled in Tiled, simply click the top left tile in the tile set window, then holding SHIFT, click the bottom left, like so:

 

T8

 

Now you can draw with all four tiles at once by simply clicking on the map.  First select the Stamp tool, then draw out the tiles as you desire:

 

T9

 

So, what about the tiles with transparent sections like these ones?

 

T10

 

Well these are designed to be layered over top of other tiles.  Which leads us nicely to layers.  If you have ever used Photoshop or GIMP, you probably already have a pretty good understanding of layering.  Basically layers are drawn over top of lower layers.  So for example, what you draw in Layer 2 is drawn over top of what you draw in Layer 1.  

 

Right now, we only have a single layer, let’s add another one.  In the top menu, select Layer->Add Tile Layer.

 

T12

 

Now in the Layers panel you should see a second layer available.  Clicking the checkbox to the side of the layer shows/hides it’s contents.  Clicking the layer itself makes it active.  Click Tile Layer 2.

 

T11

 

You can now paint “over” the grass and road layer, like so:

T13

 

Congratulations, you’ve just created your first map.  Now we simply save it.  

 

T14

 

 

Next we will take a look at using this map in code in LibGDX.