Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
22. December 2015

 

Welcome to the next section in the ongoing Closer Look at series, a series of guides aimed at helping you decide which game engine is right for you.  Each closer look at entry is a cross between a review and a getting started tutorial that should help you decide if a game engine is right for you.  Today we are looking at the Atomic Game Engine with the extensive editor support forked from the Urho3D game engine that I covered earlier.  The engine itself is written in C++ while the primary programming language is JavaScript, however .NET and TypeScript bindings are available as is a community created Haxe binding.

 

Wait you say?  A commercial game engine forked from an open source project??? Don’t worry, put down your pitchforks, this is an example of commercialization done mostly right.  First off, it’s a noticeable improvement over the original in many ways.  Second, much of the derived source code is still available freely and open source.  Finally the Atomic team are making pro licenses available to contributors of dependencies such as Urho3D, Box2D, TypeScript, Tiled, etc.  This is a nice approach and one I would like to see more closed software layered over open source software adopt.  There is also a free version available with limitations that we will discuss shortly.

As always, there is an HD video version available here.

 

Pricing Structure

As mentioned earlier, there exists a free option and a number of other tiers.  As of writing Atomic Game Engine is currently in Early Access which includes a lower price (and increased instability…).  The pro licenses include a lifetime of upgrades.  Here is the full pricing structure:

image

 

As you can see the free version you have to choose between 3D, Android or iOS support and must have less than $100,000 annual revenue and includes a splash screen.  The indie license revenue is capped at $500,000 and there is no splash screen requirement.  In my opinion at least, this price tier is fair.  One major caveat however, to build completely from source you will need a Pro license otherwise you have to wait for new binary releases.

 

The Editor

The editing environment is probably the biggest feature of Atomic, so lets start there.  This is the welcome screen when you first load Atomic Editor:

image

 

As you can see there are several sample projects to start from.  Create a new project using File->New Project menu, which will show the following dialog:

image

 

You can work in 2D or 3D mode within Atomic.  For this example I will choose 2D.  Next define your project settings:

image

 

You will notice that TypeScript and JavaScript are the default languages available.  You can work in .NET, Haxe or even using C++ but at this point in time you will be mostly on your own.  The tooling and documentation is mostly oriented for JavaScript development for now.  As it is layered over Urho3D, if you are comfortable in using Urho3D with C++ you should be able to adapt to C++ in Atomic fairly simply, plus the majority of documentation is still applicable with minor changes.  C++, .NET and Haxe targets are beyond the scope of this review however.

 

Now that we have a project loaded, the left hand side of the editor changes slightly.  The top portion represents that assets of the current project, the mid portion contains the contents of the currently selected folder, while the bottom portion represents the scene graph of the currently selected scene.

image

 

With Scene.scene selected you can see that a default scene contains a Camera and a Node entity.  Like most modern game engines Atomic uses the composition approach, although instead of Entities and Components, you have Nodes and Components, but the end result is very similar.  Now that we have a scene selected, it should be visible in the middle portion of the UI:

image

 

This is where you select and arrange the entities within your scene.  You can instance new entities… er, nodes by dragging them in from the left side of the screen.  With a node selected, the right hand side shows the property inspector giving us access to the properties of the node as well as the components it contains:

image

 

Adding new items to the scene is trivial, simply click the Create button in the hierarchy area.  The options are limited to Node or for some reason in 3D there is an option for Light.  You can also create a prefab instance that we will discuss later.

However for adding components there are a ton more options available.  Adding a component is simple a matter of clicking Add Component in the inspector with the appropriate Node selected.

image

 

Each component type has it’s own corresponding editor.  The following for example is the Rigid Body components editor:

image

 

Game assets can be imported via drag and drop.  This process automatically triggers the appropriate importer:

GIF

 

The Programming Experience in Atomic Game Engine

The primary or lead programming language when working with Atomic Game Engine is JavaScript, while .NET, Haxe and Typescript language bindings exist (but aren’t documented).  The source code is primarily written in C++, while the editor is created using the Typescript language.  You could of course code your entire game using C++ if you preferred, but again, the process is currently undocumented.  The programming model is pretty intuitive and quick to come to terms with.  For the following code examples, I will be looking at the Platformer2D example.

 

Taking a quick look at the generated source code, you can find your project’s entry point in the Scripts folder:

image

 

Here are the contents of main.js:

// This script is the main entry point of the game

// create the start ui programmatically, we could also
// use a ui template
//create  main view
var view = new Atomic.UIView();
//create a window
var window = new Atomic.UIWindow();
//disable tile bard and make it non resizeable
window.settings = Atomic.UI_WINDOW_SETTINGS_TITLEBAR;
window.text = "Physics Platformer";

// Create a layout, otherwise child widgets won't know how to size themselves
// and would manually need to be sized
var layout = new Atomic.UILayout();
layout.rect = view.rect;
// give ourselves a little more spacing
layout.spacing = 18;
//axis to y
layout.axis = Atomic.UI_AXIS_Y;
//add ours layout to window
window.addChild(layout);

//create a text field
var text = new Atomic.UITextField();
text.text = "Please select the time of day:";
layout.addChild(text);

// Buttons layout
var buttonLayout = new Atomic.UILayout();
buttonLayout.axis = Atomic.UI_AXIS_X;
layout.addChild(buttonLayout);
var buttonDaytime = new Atomic.UIButton();
buttonDaytime.text = "Play Daytime";
buttonDaytime.onClick = function () {
  run(true);
  //we need to return value here, otherwise we will be GC'ed
  return true;
}
buttonLayout.addChild(buttonDaytime);

var buttonNightTime = new Atomic.UIButton();
buttonNightTime.text = "Play Nighttime";
buttonNightTime.onClick = function () {
  run(false);
  //we need to return value here, otherwise we will be GC'ed
  return true;
}
buttonLayout.addChild(buttonNightTime);

window.resizeToFitContent();

// add to the root view and center
view.addChild(window);
window.center();
var dayTime;
function run(daytime) {
  //ok, then remove ours window
  view.removeChild(window);
  //require GlobalVariables module, and set its dayTime value to the current daytime
  require("GlobalVariables").dayTime = daytime;
  //load main scene!
  var scene = Atomic.player.loadScene("Scenes/Scene.scene");
  //if we are running ours game on android
  if(Atomic.platform == "Android" || Atomic.platform == "iOS") {
    //requiring a dpad module
    var DPad = require("DPad");
    //create a new view
    var uiView = new Atomic.UIView();
    //creating a new DPad
    var dpad = new DPad();
    //adding horizontal and vertical buttons
    dpad.addAll();
    //ok, then we could init ours dpad
    dpad.init(uiView);
    //create a jump button
    var jumpButton = new Atomic.UIButton();
    //unset its skin, because we will use UIImageWidget
    jumpButton.skinBg = "";
    //create ours jump button image
    var jumpButtonImage = new Atomic.UIImageWidget();
    //load image
    jumpButtonImage.setImage("UI/jumpButton.png");
    //resize ours image by 2.2x
    var jumpButtonWidth = jumpButtonImage.imageWidth*2.2;
    var jumpButtonHeight = jumpButtonImage.imageHeight*2.2;
    //calculate position
    var posX = Atomic.graphics.width - Atomic.graphics.width/8-jumpButtonWidth/2;
    var posY = Atomic.graphics.height - Atomic.graphics.height/4-jumpButtonHeight/2;

    //sets jumpButton rect, specify position and end position
    jumpButton.rect = [posX, posY, posX+jumpButtonWidth, posY+jumpButtonHeight];
    //sets jumpButtonImage rect, we specify there only end position
    jumpButtonImage.rect = [0, 0, jumpButtonWidth, jumpButtonHeight];
    //adds image to jumpButton
    jumpButton.addChild(jumpButtonImage);
    //adds jumpButton to the dpad view
    dpad.view.addChild(jumpButton);
    //sets jumpButton capturing to false, because we wanna make it multitouchable
    jumpButton.setCapturing(false);
    //binds jumpButton to KEY_SPACE
    Atomic.input.bindButton(jumpButton, Atomic.KEY_SPACE);
  }
}

This is actually a fairly advanced main.js, some are as simple as:

// This script is the main entry point of the game
//Load scene
Atomic.player.loadScene("Scenes/Scene.scene");

In this particular example the first half of the code demonstrates programmatic generation of a UI.  The later half creates an on screen controller if running on a mobile platform.  As you can see from the second, much shorter main, it can be as simple as calling loadScene() passing in the scene you create using Atomic Editor.

 

The majority of code in your project will be organized in components:

image

 

Components are attached to Nodes just like any other component.  Here for example is a script component attached to the Level node in the platformer example:

image

 

And the contents of that script:

"atomic component";
//requiring LevelParser module
var LevelParser = require("LevelParser");

//A Level
var component = function (self) {
  //start function will be excecuted, after connecting our component to the node, after the constructor
  self.start = function() {
    //get TileMap2D component from our current node
    var tileMap = self.node.getComponent("TileMap2D");
    var tmxFile = tileMap.tmxFile;
    
    //looping main game song
    var music = Atomic.cache.getResource("Sound", "Sounds/JumpingBat.ogg");
    music.looped = true;

    //create LevelParser object
    var levelParser = new LevelParser(tileMap);
    levelParser.createPhysics(tileMap, tmxFile);

    var position = levelParser.getSpawnpoint();
    position[1] += 1.5;

    //create a child prefab
    var node = self.scene.createChildPrefab("Player", "Prefabs/Hero.prefab");
    //set it position to the current node position
    node.position2D = position;

    //get all entities from our map which names MovingPlatform
    var platforms = levelParser.getEntities("MovingPlatform");
    for (var i = 0; i < platforms.length; i++) {

        var p = platforms[i];
        var node = self.scene.createChildPrefab("MovingPlatform", "Prefabs/MovingPlatform.prefab");

        node.position2D = p.start;
        node.startPos = p.start;
        node.stopPos = p.stop;
    }

    //get all entities from our map which names Coin
    var coins = levelParser.getEntities("Coin");
    for (var i = 0; i < coins.length; i++) {
        var node = self.scene.createChildPrefab("Coin", "Prefabs/Coin.prefab");
        node.position2D = coins[i].position;
    }

    //get all entities from our map which names BatWaypoint
    var waypoints = [];
    var batWaypoints = levelParser.getEntities("BatWaypoint");
    for (var i = 0; i < batWaypoints.length; i++) {
        waypoints.push(batWaypoints[i].position);
    }

    //get all entities from our map which names Bat
    var bats = levelParser.getEntities("Bat");
    for (var i = 0; i < bats.length; i++) {
        var node = self.scene.createChildPrefab("Bat", "Prefabs/Bat.prefab");
        node.position2D = bats[i].position;
        node.scale2D = [.5, .5];
        node.waypoints = waypoints;
    }

    //get all entities from our map which names Vine
    var vines = levelParser.getEntities("Vine");
    for (var i = 0; i < vines.length; i++) {
        var vnode  = self.scene.createChild("Vine");
        vnode.createJSComponent("Components/Vine.js", {startPosition : vines[i].position});
    }
    
    //reduce num rays on mobile/web platforms for better performance
    if(Atomic.platform == "Android" || Atomic.platform == "iOS" || Atomic.platform == "WebGL") {
      self.scene.getChild("TheSun").getComponent("DirectionalLight2D").numRays = 512;
    }

  }

}

exports.component = component;

You may notice the exports statement at the bottom of the example and the require statement at the top.  Atomic uses CommonJS for module support.  This particular example implements the start() method, which will be called automatically on the component during creation.  There is a method update() that will be called each pass through the primary game loop and is where the majority of your game logic will most likely be performed.  You can also create and subscribed to arbitrary events, enabling easy component to component component communication.

 

This example also illustrates another powerful feature of AGE, prefabs.  In the line:

var node = self.scene.createChildPrefab("Player", "Prefabs/Hero.prefab");

This is programmatically creating a prefab named Player from the file Prefabs/Hero.prefab.  Prefabs are simply pre-configured Nodes that can be re-used and instanced easily.  To create a prefab you simply create a node, add it’s various components, then drag that node up into your project resources, generally into a folder called prefab. 

 

One other thing you may notice is that double clicking a script brings up an integrated code editor:

image

 

This is an incredibly handy feature that is sadly somewhat broken right now.  Normally the editor has a great deal more functionality including full code completion but a bug resulted in it’s removal.  As of writing they are in the process of integrating Chromium and improving the integrated editor.  That said, the majority of users make use of an external editor.  One popular choice is the Atom editor, which has a Atomic Game Engine package available:

image

 

This enables you to run Atomic projects directly from the Atom editor, or to open the current project in the Editor.  That said, it didn’t actually work for me, saying atomic-cli NPM package needed to be installed, which it was.  Not sure what the error here was.  On cool thing about using Atom as your editor, is if you also use the Typescript language, you get complete and accurate intellisense in the editor:

image

 

There is a Typescript seed project (among other things) available in this Github repository.  You may have noticed a few moments back that I mentioned a CLI, or command line interface.  Assuming you have Node installed, you can install it using the command

npm install atomic-cli –g

This interface enables you to create, edit and run projects directly from the command line, which also makes it easy to integrate AGE into existing text editors such as Sublime Text or Notepad++.

 

The actual coding process is a bit beyond the space/time we have available here.  Given that Atomic is built on top of Urho3D you can expect a full featured and expansive API including pretty much all the functionality you expect from a modern 2D or 3D game engine.  If you want more of a taste for what coding in AGE is like be sure to check out the examples repository which contains a pretty comprehensive set of examples to learn from.  Of course the existing Urho3D documentation is also a good source of information, although some things will obviously be different as this is a fork.

 

Platform Support

Once you finish developing your game it’s time to deploy and AGE makes this process easier than most.  Depending on version, the following platforms are available:

  • Windows
  • Mac
  • WebGL
  • iOS
  • Android

And building for a platform is as simple as choosing Build->Build Settings and filling in the appropriate values:

GIF

 

Documentation and Community

 

As is often the case with in development engines, documentation is not the strong point of Atomic Game Engine.  There is a complete reference guide available somewhat confusingly under the videos section of the AGE website.  There is also a robust collection of examples available, which truth told is going to be your primary source of information for the foreseeable future.  As this engine is based on a fork of the Urho3D engine, a good chunk of Urho’s existing documentation is still applicable, although it will be a challenge for new developers to figure out when this is and isn’t true.

 

There is a community forum with a  growing community.  It’s not exceedingly active, but almost every single question goes answered, which is a good sign.  Additionally there is a Gitter chat which can be thought of as a version of IRC that  lasts forever and no doubt pulls a bit of traffic away from the forum.  It does seem to be quite active and a fast source for answers.  Bugs and features are tracked using github and are very active making development quite transparent.  Finally there is a Wiki, but it is extremely sparse at the moment.

 

Summary

 

Atomic Game Engine is very much an engine under development and at times it shows.  On the other hand, it is based on a very mature engine, so there is no reason you wouldn’t be able to use it in a production ready environment.  I am not going to answer the question “Is it worth it to use Atomic instead of Urho3D?”, as value is an incredibly subjective concept.  What I will say is the Atomic Game Engine adds a layer of tooling and polish on top of a game engine that required a layer of tooling and polish and did it well.  The developer experience using Atomic is a great deal nicer than the developer experience using Urho3D.

On that point, would I recommend Atomic Game Engine to new users?  No, not yet, but mostly due to the in development nature and the current lack of documentation.  In the future though, I imagine all of that will change and this will be an easy to recommend engine.  Now, what about to more experience developers?  Well if you are willing to work on an engine that is under development, there is certainly a lot here to like.  If you are looking for a Unity-esque editing experience, but with a much cleaner coding experience and access to the source code, certainly give Atomic a shot… especially with early access pricing in effect.

 

The Video

Programming , , ,

15. December 2015

 

Over the years there have been many tutorial series here on GameFromScratch, many of them aimed at beginning game developers.  What there has never been is a series for complete beginners.  Every single programming tutorial I have ever written has assumed prior programming experience.  Today I am launching a new series that will change this.

image

Welcome to the newest tutorial series on GameFromScratch, Game Development for Complete Beginners.  I aim to teach game development with a focus on programming in this series.  However I am going to assume zero prior programming experience.  This means we will learn about the programming process, about variables, program flow and other key concepts.  We will also look at tools, debugging, profiling.  All critical tasks to learn for game development.  Of course this requires choosing a programming language and game engine or library.  For this, as you may guess from this page’s title, I chose Love ( or LÖVE/Love2D ) which uses the Lua programming language.  I will explain the reasons in more detail later, but for now simply realize it’s a beginner friendly combination and it’s a programming language that remains useful long past the beginning stages.

 

Of course this isn’t the kind of thing I can cover in a tutorial or two.  This will require a complete tutorial series.  I am actually composing it in chapter form and will publish each chapter here on GameFromScratch.  I will also be compiling the results together in e-book for Patreon supporters.  For each chapter there will also be one or more videos covering the same material.

 

In fact, there is already a video companion for this announcement post! Winking smile

 

Of course your feedback is always appreciated.  Hopefully this series helps makes entry into the world of game programming easier for new developers and it provides some mild amusement for more experienced readers!  Stay tuned for more.

Programming ,

13. December 2015

 

GDX AI, a Java based AI library that works with (but doesn’t require) LibGDX just released version 1.7.

 

From the change log:

[1.7.0]

- Updated to libgdx 1.7.1

- API Addition: added GdxAI service locator that reduces coupling with libgdx and allows you to use gdx-ai

out of a libgdx application without having to initialize libgdx environment, so avoiding the waste of resources

and the need of native libraries; see https://github.com/libgdx/gdx-ai/wiki/Initializing-and-Using-gdxAI

- API Change and Addition: Messaging API

* Removed delta time argument from the update method of the MessageDispatcher; the new GdxAI.getTimepiece().getTime() is internally used instead.

* Added return receipt support, see https://github.com/libgdx/gdx-ai/wiki/Message-Handling#return-receipt

* The report method of PendingMessageCallback now takes an additional argument for the return receipt.

- API Change and Addition: State Machine API

* Now the StateMachine interface has a generic type parameter for the state.

* Added owner's getter and setter to the DefaultStateMachine; also, the owner is now optional in constructor.

- API Change and Addition: Behavior tree API revised and improved, see https://github.com/libgdx/gdx-ai/wiki/Behavior-Trees

* Now tasks have a status that is updated each time they run.

* Added enum support in behavior tree files.

* Now parallel task can specify sequence or selector policy.

* Added cancel method for task termination, mainly used by the parallel task.

* Now you can add listeners to the tree in order to be notified when a task has run and a child is added.

* Now task methods setControl, success and fail are final.

* Now method addChild is final and Task's subclasses have to implement addChildToTask.

* Added decorator tasks Repeat and Random.

* Added leaf tasks Failure, Success and Wait.

* Added branch tasks RandomSelector and RandomSequence; removed deterministic attribute from Selector and Sequence.

* Now the UntilFail decorator succeeds when its child fails.

* Added ability to clone tasks through third-party libraries like Kryo.

* Added support for custom distributions in behavior tree files.

* Now LeafTask usage is less error prone thanks to the execute method.

GdxAI is available on Github or as part of the LibGDX setup.

GameDev News, Programming ,

11. December 2015

 

Don’t you just love it when someone else does your job for you?  As part of my recently completed Tiled tutorial series I was considering doing a pretty detailed tutorial on integrating it into one of the modern C# based game engines.  One engine certainly up for consideration was the Wave Engine, somewhat recently featured in the Closer Look At series.  Well thankfully I didn’t, because they went ahead and did it for me!

 

From the WaveEngine blog:

Using TiledMap to create your 2D game level

With TiledMap, developing 2D games in WaveEngine will not be the same anymore. Tiled maps have been used for a long time in games, now you can load and integrate TiledMap (.TMX) files, created by theTiled Map Editor (http://www.mapeditor.org/), the most popular map editor based in tiles. With Tiled, you can easily design your 2D map levels and run in WaveEngine like a charm.

Load a TiledMap (.tmx) in WaveEngine

1. Install WaveEngine.TiledMap NuGet package

First of all, you need to install WaveEngine.TiledMap NuGet package into your Game solution. This action allows you to use the TiledMap components into your project:

 

series continues here. 

 

With the NuGet TiledMap package, the process is actually quite simple.  They also have a Tiled map example available on Github.

Programming , ,

8. December 2015

 

This tutorial came about as a result of a question on my YouTube channel, although it is one of those things that you are going to need to know before long in 3D game programming, so I have made the answer part of the official Godot Engine tutorial series.  The question was:

I am making a 3d game and I want to use a sort [of] top down style camera.


I want it so that if an object gets between the player and the camera, that same object will become transparent. For that ( I think ) I can use the "Use Alpha" function in the fixed material settings.
So I think I need a raycast shooting rays ( between the player and the camera ) and if it hits something it needs to "find' which object was hit en change the material settings so it becomes transparent.


Now, the problem is that I don't know how to set this up;
-how can I get which object is hit by the ray and how to change the material?
-do I need to create a separate layer for this?

This is one of those things even the most simple 3D game is going to encounter, but the solution isn’t obvious, although the questioner was extremely close in his guess.  You can solve this using Ray casting, it’s probably just the how of it all that is difficult to figure out.

 

As always there is a video version of this tutorial available here.

 

If you have a situation like the above, where you want to determine if something is in the way of your camera, it’s exactly RayCasting that you want.  Let’s take a look at how.

 

Setting Up The Scene

 

First you need your scene to be set up correctly.  This means that each entity in your scene that can be collided with has to be a physics object of some kind.  I created the following scene arrangement:

image

 

As you can see, I have a camera and two Rigid Body objects, each with a CollisionShape (Cube) and a Test Cube child.  Additionally I created a RayCast object as a child of my camera.  Be sure to create the RayCast child before you transform your camera, so it is positioned properly.  For my RayCast I use the following settings:

image

 

My scene ends up looking like this:

image

 

The Code

 

As you can see, the Ray extends from my camera and through both objects in the scene.  In this example we want to see if we hit the first cube (“RigidBody 2”) and if we do, we want to hide it.  Time to look at some code, the following script was attached to the camera:

extends Camera


var ray = null

func _ready():
	ray = get_node("RayCast")
	set_process(true)


func _process(delta):
	if(Input.is_key_pressed(KEY_UP)):
		self.translate(Vector3(0,0.1,0))
	if(Input.is_key_pressed(KEY_DOWN)):
		self.translate(Vector3(0,-0.1,0))
	if(ray.is_enabled() and ray.is_colliding()):
		var collidedWithObject = ray.get_collider()
		if(collidedWithObject.get_name() == "RigidBody 2"):
			collidedWithObject.hide()
	else:
		get_parent().get_node("RigidBody 2").show()

 

… and that’s it.  We check to see that our ray is enabled and if it is currently colliding with something.  If it is, the first collided object is returned by the call get_collider().  In a bit of a hard coded hack, we check the name of that object, and if its our second cube, we hide the entire hierarchy.  In the event that no collision occurs, we make sure that RIgid Body 2 is visible with a call to Show().  You will notice that there is code in there to move the camera on press of the Up and Down arrow keys.  As you will see, as you move the camera, when the ray isn’t colliding, the second cube is shown, otherwise it is, like so:

 

GIF

 

It is also possible to create the ray programmatically using the PhysicsServer, like so:

extends Camera

func _ready():
	set_fixed_process(true)

func _fixed_process(delta):
	if(Input.is_key_pressed(KEY_UP)):
		self.translate(Vector3(0,0.1,0))
	if(Input.is_key_pressed(KEY_DOWN)):
		self.translate(Vector3(0,-0.1,0))

	var directState = PhysicsServer.space_get_direct_state(self.get_world().get_space())
	var collisions = directState.intersect_ray(get_translation(),Vector3(0,0,0))
	
	if(collisions.size() and collisions["collider"].get_name() == "RigidBody 2"):
		collisions["collider"].hide()
	else:
		get_parent().get_node("RigidBody 2").show()

 

Note that _process what changed to _fixed_process().  This is because space_get_direct_state() is only valid during _fixed_process or _integrate_forces() calls.  Otherwise we crate an intersect_ray() between the camera position and the origin, which in turn returns if there is a collision between those two points.  If there is, we hide the collided objects, otherwise we call show().

 

The Video

Programming ,

Month List

Popular Comments