Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
3. November 2015

 

In today’s Closer Look we are looking at the open source C# based 2D game engine Duality.  The Closer Look series is a combination of review and getting started tutorial that is aimed at helping a developer decide if a game engine is the right choice for them.

 

There is also an HD video version of this guide available here.

 

First I need to start with a confession.  A few people mentioned Duality to me in the past and each time I dismissed it, very quickly.  An open source C# based, non-cross platform Unity-wannabe developed by a single guy?  Yeah right… pass.  These types of projects are a dime a dozen until people quickly realized that developing a product like Unity is actually a hell of a lot harder then they thought, even if they just focused on 2D.

 

Well, let me just start by saying I was wrong… very wrong.  A bit of a spoiler alert, but Duality impressed the hell out of me and I think it will impress the hell out of you.  There is one thing to be aware of right up front from that previous paragraph… “non-cross platform”.  Right up front this is the biggest flaw of Duality so no sense wasting a ton of time if this is a deal breaker.  That said, it’s not the huge problem it used to be as there has been a lot of work underway to make Duality cross platform.  It’s built on top of OpenGL and the entire core as well as all class libraries are now portable class libraries.  In theory this means, aside from the editor which is tied to WinForms, a duality project should be able to run on any modern C# capable platform with OpenGL support.

 

Getting Started

 

Getting started with Duality is easy but may add some complications for integrating with source control, updating or collaborating with others.  The duality download is the engine, and the tools AND your game.  When you spawn a new project in Duality, it downloads and sets up another Duality environment.  You can download the latest version right here. (That’s a direct link by the way).

 

The download is simply a zipped folder.  Extract it somewhere, it’s contents should look something like this:

image

 

Simply double click DualityEditor.exe to get started.  After launching and agreeing to the MIT license, you will be greeted by this window:

image

 

Dont worry, it should only take a few seconds depending on your internet speed.  A full install currently weighs in at around 120mb.  Once done downloading the editor Dualitor should now be loaded:

image

 

I suppose this is a good time to point out that you need to have Visual Studio 2013 or newer installed and with patches applied.

 

The Editor

 

The editor is extremely straight forward, let’s do a quick guided tour of it’s features.  It should be noted, the entire editor can be docked/undocked, hidden or shown as desired, so the layout is completely up to you.

 

Editor View

image

 

You can have multiple instances of the scene view running and you switch between them using the tabs at the top:

image

 

You can also rearrange the views however you wish, such as:

image

 

In addition to the Scene Editor where you compose the entities that make up your scene, there are two other options available in this view:

image

Game View and RigidBody Editor.  The game view is like a running preview of your game, while RigidBody editor is for defining physics shapes, which we will see later on.

 

Scene View

This is your game’s scene graph.  This is where you can select the entitles that make up your scene as well as the components that compose them.  Additionally you can create new entities or add new components here.

image

We will cover this process in a bit more detail later on.

 

Project View

The Project View is essentially the assets that compose your game, things like images, fonts, audio files, etc.

image

New assets can also be created here, using either the right click menu or via drag and drop from Explorer.  We will also cover Project View in more detail later.

 

Advisor View

Advisor view is basically a context sensitive help, like a stationary and in-depth tool tip.  As your mouse location or keyboard cursor change, the context switches and content is updated.

image

 

It’s handy while learning your way around but will probably be turned off in short order to free up screen real estate.

 

Object Inspector

The contents of this window changed based on the currently selected item.  If an entity is selected in the Scene View, the properties of all the components that make up the entity are shown, like below:

image

 

While selecting an asset will show the corresponding editor, like this one for ttf font files:

image

 

Note in this case all of the values are grayed out because I selected one of the built in non-editable assets.  Note the font preview at the top of the window… neat.

 

Finally there is the menu and toolbar across the top:

image

 

This tool bar enables you to load the source in Visual Studio ( the C# icon ), compile + run, compile + debug, or preview in the editor.

 

All told, a streamlined and somewhat minimal but highly configurable editing environment.  I never once experienced a crash or lock up in my time with Duality, so at least for me, stability and performance seem pretty solid.

 

Creating a Game

 

So that’s the editor covered, let’s take a look at using it to actually create a game.  You may have guessed at this point that Duality uses a component based design.  The entities that make up your scene are in turn composed of components that provide that functionality.  The top level entity is called a Game Object and you can create one in the Scene View by right clicking and selecting New->GameObject.

 

image

 

The other options simply create a pre-populated GameObject for you.  Your newly created entity will now be available (and re-nameable) in the Scene View:

image

 

Now let’s right click our game object and add some components to it.  We want to be able to position our object in the world, so let’s first add a transform component.  Simply select New->Transform.

image

 

Let’s make this a sprite, right click again, then select new->Graphics->SpriteRenderer.

image

 

Your entity should now look like:

image

 

Plus if you look over at the editor window, you will see a sprite now appears using the default sprite:

image

 

While in the object inspector you can now edit the two components attached to our object:

image

 

You can also edit the translation, rotation and scale of the sprite in the editor view using one of the cleanest 2D widgets I’ve yet experienced:

movewidget

 

Now let’s add our own sprite, simply drag and drop from Explorer to the Project view, like so:

DragDrop

 

Now if you select the newly created pixmap, you will see it’s settings in the Inspector window:

image

 

Notice like fonts there is a preview of the asset file.  Now we can update our SpriteRenderer’s SharedMaterial property by dragging our new asset over, like so:

ChangeTexture

You will notice that Duality automatically created two new assets, a Material and Texture definition.  You can go a great deal deeper if you wish, for example changing the draw technique that is used to renderer the material to screen, which in turn you can drill down and define your own vertex and fragment shaders, etc.  The details are nicely hidden away from you, but if you want to drop down into the technical details you easily can.  That is beyond what we are going to cover today however.

 

Now we have created a sprite game object that can be positioned in the scene, now let’s go ahead and make it do something.  Let’s add a physics RigidBody component to it by selecting New->Physics->RigidBody:

image

 

As you can see in Inspector, once the rigid body is added, there are a number of values you can configure in the component:

image

 

In this case however we are going to stick to the defaults.  You can also edit the physics bounding shape if desired.  With the game object selected, in the editor view switch to RigidBody Editor, and you can now define a new rigid body shape.

rigidBody

 

Notice will editing the rigid body, the Inspector window has yet a different set of options available:

image

 

Now, lets go ahead and preview our handy work.  If you want to see a more accurate result, switch to Game View, then click the play icon:

image

 

And you should see:

Running

 

So we’ve got a physics enabled sprite being drawn with almost zero effort, pretty cool.

 

The Coding Experience

 

So, that’s the editor down.  Let’s take a look now at what the coding experience is like.  Click the C# icon to load your project in Visual Studio:

image

 

Your starting project is extremely straight forward:

image

 

Your “game” itself is actually implemented as a plugin, that is what the class CorePlugin.cs is.  The contents are incredibly sparse:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Duality;

namespace Duality_
{
  /// <summary>
  /// Defines a Duality core plugin.
  /// </summary>
  public class Duality_CorePlugin : CorePlugin
  {
    // Override methods here for global logic
  }
}

 

This is where the global logic and variables of your application reside.  The majority of game logic however will be in the form of components.  A default component is created, YourCustomComponentType.cs, which contains the following code:

using System;
using System.Collections.Generic;
using System.Linq;

using Duality;

namespace Duality_
{
  public class YourCustomComponentType : Component
  {
    
  }
}

 

That's about it, not a lot of boilerplate code required.  Do a compile for your project in Visual Studio.  Now if you go back to editor and add a component to a GameObject you will already see this type is available through the powers of reflection:

image

 

Now let’s add our own new Component, this one for adding WASD controls to our entity.  Simply create a new class called WASDControl.cs with the following code:

using System;
using System.Collections.Generic;
using System.Linq;

using Duality;
using Duality.Components;

namespace Duality_
{
    [RequiredComponent(typeof(Transform))]
    public class WASDControl : Component, ICmpUpdatable, ICmpInitializable
    {
        Vector2 position;

        public void OnInit(Component.InitContext context)
        {
            position = new Vector2(0, 0);
        }
        
        public void OnUpdate()
        {
            var transformComponent = this.GameObj.GetComponent<Transform>();
            position.X = 0; position.Y = 0;

            if (DualityApp.Keyboard.KeyReleased(Duality.Input.Key.W))
                position.Y -= 10f;
            if (DualityApp.Keyboard.KeyReleased(Duality.Input.Key.A))
                position.X -= 10f;
            if (DualityApp.Keyboard.KeyReleased(Duality.Input.Key.S))
                position.Y += 10f;
            if (DualityApp.Keyboard.KeyReleased(Duality.Input.Key.D))
                position.X += 10f;

            transformComponent.MoveBy(position);
        }

        public void OnShutdown(Component.ShutdownContext context)
        {
        }
    }
}

 

This example illustrates a couple of things.  First if your component requires the existence of a certain component, you can define that using the RequiredComponent attribute.  Next you can see I inherited from two additional interfaces, ICmpUpdatable and ICmpInitializable.  The first class tells Duality that your game implements Update() and should be called each frame.  The second indicates you have initialization or cleanup code and thus implement OnInit() and OnShutdown().

 

Otherwise the code is quite simple.  Your component has access to it’s parent game object in the form of GameObj and can access child components using GetComponent().  The component also has access to the engine itself through the DualityApp class, which is used in this example to poll the keyboard state.  This component can now be added in the editor to any game object that has a transform component making for easy code reuse.

 

Given the amount of space already used, I can’t go into extreme detail about what Duality can and can’t do from a programming point of view, but you can get a pretty good idea from looking at the class reference documentation.  The video version also has a bit more in depth on the coding experience if you are interested.

 

Documentation and Community

 

The primary documentation for Duality is the wiki available here.  It’s a collection of tutorials covering most of what you need to get started.  Perhaps most important piece of documentation is the reference material that is included with the engine, however I could not find an online version.  The reference material is fairly comprehensive and while a bit light in places, for the most part has what you need well documented.

Another aspect of Duality is the samples.  These can be downloaded directly within the editor via File->Manage Packages:

image

The code for these projects is also available on Github here.

The community is small but active.   The primary source of help is going to be the forum.  Fortunately it seems like the vast majority of questions receive and answer and the author seems quite active.  Of course the source is available as well.

 

Summary

 

I have to say, I love being surprised by engines and Duality certainly surprised me.  It is a very focused 2D only engine and the requirement for Windows for a development machine.  This is of course going to turn many off.  For the rest though, Duality represents a great, free, open source C# 2D engine.  It’s polished, well documented, well supported and well designed.  There's not much more you can ask for in an engine.

 

The Video

 

Programming


25. October 2015

 

In this Closer Look At we are going to be taking a closer look at the Otter2D game engine.  The Closer Look At series is a combination of an introduction, overview and getting started tutorial that is designed to help you quickly decide if a game engine/framework/library is right for you.  Otter2D is an open sourceotterlogo C# based open source game engine built over top of the SFML framework.  Otter2D provides essentially all of the functionality of SFML as well as higher level game engine features like animations, collisions, sessions and components.

 

As always there is an HD video version of this guide available here.

 

Doing what I do for a living I generally am surprised by a game engine or tool.  If I haven’t used it personally I have at least heard of it.  Otter on the other hand took me completely by surprise and for the most part it’s been a fun (and quick!) journey.  There isn’t a ton to Otter2D, it’s a code only framework built over a framework I am already familiar with.  If you have prior SFML experience, Otter2D will come quickly to you.  Due to the composition of Otter2D, this closer look is going to lean much more toward the code/tutorial side.  Let’s jump in.

 

Getting Started

 

Otter2D is available as a zip file (direct download link) or you can build from current source on Bitbucket.  The code is distributed under this license, excerpted below:

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

In case you are wondering, there are no conditions after the colon.  So basically it’s a license that lets you do pretty much whatever you want so long as you keep the license intact.

Getting set up is easy but could be better.  Unfortunately Otter2D is not configured to be used as an external library which is a bit of an odd choice.  Instead you add the Otter2D project to your solution and link to it as a dependency in your project, like so:

image

Full instructions on getting started Visual Studio are available here.

 

Your First Application

 

Now that you’ve got Otter downloaded and configured, let’s create our first application.

using Otter;

namespace OtterScratchPad
{
    class Program
    {
        static void Main(string[] args)
        {
            Game game = new Game();
            game.Color = Color.White;

            Scene scene = new Scene();

            Entity entity1 = new Entity();
            entity1.AddGraphic(Image.CreateCircle(90,Color.Red));
            scene.Add(entity1);

            game.Start(scene);
        }
    }
}

 

When you run this example you get:

image

 

Otter2D code is very similar to a traditional Entity Component System (ECS) in it’s approach.  Game is the heart of your application, while scene represents your game world.  The scene itself is composed of entities, which in turn contain defined components like Graphic we used above, or actual components, which we will see later.  A more common approach to the above solution is to derive your game objects from Entity instead, like so:

 

using Otter;

namespace OtterScratchPad
{
    class Player : Entity
    {
        public Player(float x, float y) : base(x, y)
        {
            this.AddGraphic(Image.CreateCircle(120, Color.Red));
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Game game = new Game();
            game.Color = Color.White;

            Scene scene = new Scene();

            Entity entity1 = new Player(0,0);
            scene.Add(entity1);

            game.Start(scene);
        }
    }
}

 

Those two examples are functionally equivalent.  As you can see in the second example when we pass coordinates to our Player Entity the origin by default is the top left corner, both of the screen as well as the sprite.  We will look at changing this shortly.  Congratulations however, you just created your first successful Otter2D application.  Easy eh?  Let’s move on and add some sophistication.

 

Input and Image Loading

 

In our next example, instead of creating a graphic procedurally, we are instead going to load a sprite.  For the source images, I am using the freely available sprites announced here.  Specifically I am using this sprite of a B17 bomber. 

 1

Obviously you can use whatever image you wish, so long as the file format is supported.  Keep in mind, Otter2D is built over SFML so it has the same graphics support as SFML which means your sprite can be in bmp, hdr, gif, jpg, png, pic, psd, tga formats.  Additionally in this example we are going to look at handling keyboard input to move our image left and right in response to key presses.  Alright, on to the code:

using Otter;

namespace OtterScratchPad
{
    class PlayerImage : Entity
    {
        public PlayerImage(float x, float y) : base(x, y)
        {
            this.AddGraphic(new Image("1.png"));
        }
        public override void Update()
        {
            if (Input.KeyDown(Key.Right))
            {
                this.X++;
            }
            if (Input.KeyDown(Key.Left))
            {
                this.X--;
            }

            base.Update();
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Game game = new Game();
            game.Color = Color.White;

            Scene scene = new Scene();

            Entity entity1 = new PlayerImage(0,0);
            scene.Add(entity1);

            game.Start(scene);
        }
    }
}

 

And when you run it:

example1

 

Note when you launch an Otter2D application, it doesn’t have focus and thus wont receive keyboard events.  This seems to be a bug in the underlying SFML libraries.  I spent a few minutes trying to fix it and sadly couldn’t.  Shouldn’t be a big deal as a production game wont use a console window to construct the main window, so this shouldn’t occur.  As you can see from this example, loading sprites and polling input are both trivial exercises, so let’s move on to animations.

 

Sprite Animations

 

In this example I’ve taken the three different frames of the B17 bomber and created a single 3x1 768x256 using ImageMagick.  The end result was:

ss

 

Not very exciting an animation, but each frame the propeller has turned slightly.  Let’s look at the process in Otter2D of using an animated sprite from a single sheet.  In this example we also show how to move the sprites origin or pivot point to it’s middle.

using Otter;

namespace OtterScratchPad
{
    class PlayerSpriteMap : Entity
    {
        enum Animations { Idle };
        Spritemap<Animations> spriteMap = new Spritemap<Animations>("ss.png", 256, 256);

        public PlayerSpriteMap(float x, float y) : base(x, y)
        {
            this.AddGraphic(spriteMap);
            spriteMap.CenterOrigin();
            spriteMap.Add(Animations.Idle, new int[] { 0, 1, 2 }, new float[] { 9.0f, 4.0f, 10.0f });
            spriteMap.Play(Animations.Idle);
        }
        public override void Update()
        {

            if (Input.KeyDown(Key.Right))
            {
                this.X += 300f * this.Game.RealDeltaTime / 1000;
            }
            if (Input.KeyDown(Key.Left))
            {
                this.X -= 300f * this.Game.RealDeltaTime / 1000;
            }

            base.Update();
        }

    }


    class Program
    {
        static void Main(string[] args)
        {
            Game game = new Game();
            game.Color = Color.White;

            Scene scene = new Scene();

            Entity entity1 = new PlayerSpriteMap(game.HalfWidth,game.HalfHeight);
            scene.Add(entity1);

            game.Start(scene);
        }
    }
}

 

Run it and:

 

example2

 

You may have to squint to see it, but that is certainly an animated sprite.  Instead of using Image we instead use a SpriteMap which takes the individual sprite dimensions as well as the spritesheet file name in it’s constructor.  The entity is then centered with a call to CenterOrigin().  Animations is simply a user defined enum that is used as the key within the sprite map.  When the map is added we pass in an array of ints or strings representing the frames offset within the source image as well as the duration for each frame of animation.

 

Collisions

 

Next we will modify the earlier example so we now have two airplane sprites that can collide with each other.  In addition to adding two sprites to the world, the example has also been changed so you can create both a player and non-player sprite, so only one responds to keyboard input.  Additionally instead of simply moving via X++, we change it so we move at a fixed frame rate depending on the elapsed time since the last frame.

using Otter;

namespace OtterScratchPad
{
    class PlayerSpriteMapWithCollisions : Entity
    {
        enum Animations { Idle };
        Spritemap<Animations> spriteMap = new Spritemap<Animations>("ss.png", 256, 256);

        enum ColliderTypes { Planes };
        bool isPlayer;
        public PlayerSpriteMapWithCollisions(float x, float y, bool player) : base(x, y)
        {
            isPlayer = player;
            this.AddGraphic(spriteMap);
            spriteMap.CenterOrigin();
            spriteMap.Add(Animations.Idle, new int[] { 0, 1, 2 }, new float[] { 9.0f, 4.0f, 10.0f });
            spriteMap.Play(Animations.Idle);

            this.AddCollider(new BoxCollider(256, 256, ColliderTypes.Planes));
            this.Collider.CenterOrigin();
        }

        public override void Update()
        {
            if (isPlayer)
            {
                if (Input.KeyDown(Key.Right))
                {
                    this.X += 100f * this.Game.RealDeltaTime / 1000;
                }
                if (Input.KeyDown(Key.Left))
                {
                    this.X -= 100f * this.Game.RealDeltaTime / 1000;
                }

                // Check for collisions
                if (this.Collider.Overlap(X, Y, ColliderTypes.Planes))
                    this.X = 0f;
            }
            base.Update();
        }

    }


    class Program
    {
        static void Main(string[] args)
        {
            Game game = new Game();
            game.Color = Color.White;

            Scene scene = new Scene();

            Entity entity1 = new PlayerSpriteMapWithCollisions(0,game.HalfHeight,true);
            Entity entity2 = new PlayerSpriteMapWithCollisions(game.Width - 128, game.HalfHeight, false);

            scene.Add(entity1);
            scene.Add(entity2);

            game.Start(scene);
        }
    }
}

 

And run it:

example3

 

You may notice the collision isn’t amazingly accurate.  This is because in this example we used a box collider but there is some dead pixel space between our wing and the end of the image.  If you require increased accuracy you could instead us a pixel collider, but it will have a profound effect on performance.

 

Sound and Music

 

Next lets look at adding audio support to our game.  Let’s start by adding some sound effects to our player:

    class PlayerImageWithSound : Entity
    {
        // 30 cal burst:: http://www.freesound.org/people/Hamp999/sounds/151620/
        Sound sound1 = new Sound("sound1.wav");

        // Bomb drop http://www.freesound.org/people/sunch/sounds/274090/
        Sound sound2 = new Sound("sound2.wav");

        public PlayerImageWithSound(float x, float y) : base(x, y)
        {
            this.AddGraphic(new Image("1.png"));

            //Center within and without
            this.Graphic.CenterOrigin();
        }
        public override void Update()
        {
            if (Input.KeyDown(Key.Num1))
            {
                sound1.Play();
            }
            if (Input.KeyDown(Key.Num2))
            {
                sound2.Play();
            }

            base.Update();
        }
    }

 

When you hit the 1 key a certain sound effect plays, hit the 2 key a different sound effect plays.  There are two important things to note with audio in Otter2D.  Once again, it depends on SFML for the audio code so Otter supports the file formats that SFML supports ( which are too many to list ).  Additionally playing a sound halts earlier versions of that sound, so if you want multiple concurrent plays of the same sound, you need to create multiple instances.

 

Now let’s take a look at a music example.  Instead of extending another Entity, we will be creating our own Scene this time.

using Otter;

namespace OtterScratchPad
{
    class PlayerImageWithSound : Entity
    {
        // 30 cal burst:: http://www.freesound.org/people/Hamp999/sounds/151620/
        Sound sound1 = new Sound("sound1.wav");

        // Bomb drop http://www.freesound.org/people/sunch/sounds/274090/
        Sound sound2 = new Sound("sound2.wav");

        public PlayerImageWithSound(float x, float y) : base(x, y)
        {
            this.AddGraphic(new Image("1.png"));

            //Center within and without
            this.Graphic.CenterOrigin();
        }
        public override void Update()
        {
            if (Input.KeyDown(Key.Num1))
            {
                sound1.Play();
            }
            if (Input.KeyDown(Key.Num2))
            {
                sound2.Play();
            }

            base.Update();
        }
    }

    class SceneWithMusic : Scene
    {
        // Sound file is http://www.freesound.org/people/Diboz/sounds/216071/
        // Play, not looping
        public Music song = new Music("music.ogg", false);

        public SceneWithMusic() : base()
        {
            song.Play();
        }

        public override void Update()
        {
            base.Update();

            if (Input.MouseButtonPressed(MouseButton.Left))
                Music.GlobalVolume -= 0.1f;
            if (Input.MouseButtonPressed(MouseButton.Right))
                Music.GlobalVolume += 0.1f;

            if (Input.KeyPressed(Key.Space))
            {
                // Fast forward 10 seconds on spacebar if 10 seconds remain in play time
                if ((song.Offset + 10000) < song.Duration)
                    song.Offset += 10000;
            }
            if (!song.IsPlaying)
            {
                System.Console.WriteLine("Music stopped");
                Game.Close();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Game game = new Game();
            game.Color = Color.White;

            Scene scene = new SceneWithMusic();

            Entity entity1 = new PlayerImageWithSound(0,game.HalfHeight);


            scene.Add(entity1);

            game.Start(scene);
        }
    }
}

In this example there is now music playing when you start your game and you can fast forward the song by pressing the space bar.  Additionally global (all sound effects and music ) volume can be increased and decreased using the left and right mouse button, also illustrating how easy it is to poll the mouse for input as well. 

 

Components

 

I mentioned earlier that Otter2D has component support?  Well we saw a bit of it in action with the addition of Graphic objects to our Entity.  In this case though we are going to drop in slightly more advanced components, as well as create one of our own.

    class CustomComponent : Component
    {
        public override void Update()
        {
            base.Update();
            float alpha = Entity.GetGraphic<Image>().Alpha;
            alpha -= 0.005f;
            if (alpha <= 0.0f)
                alpha = 1.0f;
            Entity.GetGraphic<Image>().Alpha = alpha;
        }
    }
    // A Player Entity with components attached
    class PlayerWithComponents : Entity
    {
        public PlayerWithComponents(float x, float y) : base(x, y)
        {
            this.AddGraphic(new Image("1.png"));

            Axis axis = Axis.CreateWASD();
            BasicMovement movement = new BasicMovement(100, 100, 20);
            movement.Axis = axis;
            AddComponents(
                axis,
                movement,
                new CustomComponent()
                );
            this.Graphic.CenterOrigin();
        }
    }

 

And when you run it:

example4

 

Here we’ve used a set of built in keys, one for applying movement to your entity.  The parameters passed in limit x and y velocity as well as the rate of acceleration.  Then we create another component that maps the WASD keys to an axis, which can be used to drive our movement component.  Finally we create a custom component that changes our alpha over time.

 

Documentation and Community

 

Otter2D’s documentation consists of a collection of examples here and a generated reference manual available here.  It’s not a huge body of work however Otter2D is extremely simple to use so doesn’t really need much more.  Additionally it is built on top of SFML, so that underlying documentation and community are also available.  That said, it is built on the C# bindings of SFML and that community is much smaller than the main SFML community.

 

In terms of community there is a small forum available here.  It’s not extremely active but it is a place to get your questions answered.  There are a handful of tutorials on the web but not a huge amount by any definition of the word.

 

Conclusion

 

Otter2D is a pretty solid 2D game engine built over top of a well established framework.  It was extremely easy to learn and use, the design is clean enough you can intuit most of the process.   On major flaw I never discussed was the support for the Ogmo level editor, which IMHO was a very bad choice.  First off, it simply doesn't work, loaded levels are mangled.  Worse though, Ogmo itself was a frustrating mess to work with… every single change to the map (adding a layer, changing size, tile format, etc. ), completely destroyed everything you had done up to that point.  Adding support for a better editor such as Tiled would be relatively short work, but this was by far the most frustrating part of working with Otter2D.

 

Otherwise it is exactly what it is.  A clean, easy to use, fairly full featured 2D C# game engine.  As it is built over SFML and in C# deploying to platforms such as Android or iOS is most likely going to be painful ( no documentation exists ) and will most certainly require a Xamarin license.  For a 2D desktop title or as a learning game engine however, Otter2D would be a very solid choice.  As odd as it sounds, Otter2D was simply fun to work with, somewhat like Love2D, especially after dealing with much more complex engines or even SFML itself.

 

The Video

Programming


23. October 2015

 

In a past life in which I sat in a cubicle and someone actually gave me a pay check every week I was a huge fan of Xamarin products.  They do very a good job of enabling .NET developers to leverage their skill across many platforms.  In fact, they are the technology that Unity is built on top off.  That said, I became increasingly less of a fan when the checks stopped and expenses came out of my own pocket!

 

There are many people out there that view making money from software as somehow evil.  I am certainly not one of those people.  In that corporate environment, where developers are paid salaries, rent is paid for office space, taxes are paid, etc…  the price of a software tool like Xamarin is trivial to justify.  In the world of indie game development though, this is often simply not the case.

 

Thing is, Xamarin has become a necessary evil for so many C# based game engines ( MonoGame, WaveEngine, Duality, Paradox, etc ) if you want to port to iOS or Android.  Many of these developers will never see a dime from their efforts, while a select few will become massively rich and a certain middle ground will eek out a living doing what they love.  It’s the later two groups that keep companies like Unity and Unreal afloat, and those two groups don’t come into being without the former group.

 

The challenge with Xamarin has always been their license structure has always been pretty awful for amateur developers.  How many people have chosenn not to work in C# simply because their is a price tag attached?  After years of awaiting a newer friendlier license structure (or Microsoft buyout), hope is on the horizon.

 

Today, in response to Xamarin’s recent acquisition of RoboVM, I ended up in this Twitter conversation with Nat Friedman, CEO of Xamarin:

 

First, in regard to the acquisition of RoboVM and how long the free for LibGDX developers offer will be extended:

image

 

Then more on the indie friendly nature of Xamarin, or lack thereof:

image

(Portion excerpted, Twitter message threading is bizarre)

image

image

 

This is news I am certain many C# game developers and tool providers are going to be delighted to hear.  Hopefully something happens fairly soon, as I’ve been waiting about 6 years and counting at this point! ;)

Programming News


5. October 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 give you a good idea if a game engine is a good fit for you.  Today we areCloserLook going to be looking at the Wave Engine.  The Wave Engine started life in 2011 and is a C# based 2D/3D engine that runs on Mac, Linux and Windows and is capable of targeting all of those plus iOS, Android and Windows Mobile, although a Xamarin license may be required for some mobile targets.  There is no cost to develop using the current version of Wave Engine, however you are required to show a splash screen on application start.

 

As always there is an HD video version of this guide available here.

 

Meet Wave Engine

 

With the release of version 2, Wave Engine now includes a level editing tool to help you quickly compose scenes.  Judging by the number of “Wave Engine vs Unity” or “Wave Engine vs Unreal Engine” searches on Google, this was a heavily requested feature.  Do be aware though that the editor is quite young, and it certainly shows sometimes.

 

As mentioned earlier, Wave Engine is C# based game engine and games can be written entirely in Visual Studio or MonoDevelop/Xamarin Sutdio if you prefer.  The editor however can make like a great deal easier and integration between your code and the editor is well done and makes heavy use of reflection.  This makes your requirement to a editing support to your own classes extremely easy as we will see shortly.

 

As is quickly becoming the norm, Wave Engine is built around a entity/component model.  Your scene is a series of entities, and those entities are in turn composed of components, behaviours and drawables (renderers).  These can be composed using either the editor or entirely in code.  Let’s take a look at the editor.

 

Wave Visual Editor

 

image

 

Let’s take a quick tour around the editor.

 

Asset Management

image

This is where the various assets ( textures, models, materials, scenes ) that make up your game are managed.  You can often, but not always, create an instance of an asset by dragging it on to the viewport.  Options here are fairly simple, mostly limited to renaming and deleting assets.  A bit of a warning, I ran into some issues when deleting assets, especially when I deleted an asset then added a new version with the same name.  Hopefully these behaviours will be ironed out in time.  Not that a scene, which is where you assemble your various assets for display in the game, is in fact an asset itself.

 

Depending on the type of asset, double clicking it will either invoke a built in tool, such as the material editor or 3D model viewer, or invoke the native application if no behaviour is defined.

 

Console

image

This is where your various levels of debug information are displayed.  You can filter between errors, warnings, informational and debug logs and of course you can clear it all out.

 

Scene Graph

image

 

The Entity hierarchy is the scene graph of your game scene.  Each scene has it’s own hierarchy.  All the assets in the hierarchy are entities which in turn are holders for various components.  Entities can be parented to other entities and will inherit their transforms.  There are several kinds of entities that can be created, depending on if you are in 2D or 3D mode.  To create an entity simply click the + icon.

The 3D entities:

image

 

The 2D Entities:

image

 

You can effectively built any of the pre-existing entity types by using an empty entity and adding all of the same components and behaviors.  Speaking of which, with an entity selected you can then access the Entity details, where you configure components and add more.  Here for example is the 3D camera’s details:

image

 

New components or behaviours can be added using the + icon.  For visible objects such as models or sprites, a Drawable component also needs to be added.  Here for example is the process of adding a film grain to our camera:

image

 

Select Components, then FilmGrainLens, then OK:

image

 

You should now be able to configure the amount of film grain in the Entity Details panel:

image

 

Viewport

image

 

This is the area where you place entities within your scene.  It is also the aspect of Wave Engine editor that by far needs the most work.  When an object is selected ( using the Entity Hierarchy, direct selection rarely works ) a widget appears for translation, scaling or rotation depending on the settings in the toolbar at the top.  In the top right corner is a widget enabling you to switch between the different camera views.  If your camera is selected you can see the camera’s viewing frustum as well as a preview of what the camera sees, like the image shown above.  You can zoom using the scroll wheel, pan with middle mouse button and rotate the view using the right mouse button.  There does not appear to be an orbit ability, which is frustrating.

 

The major current flaws are the selection mechanics ( left click works sometimes ), manipulators dont work if you click on the arrow portion, there is only one view at a time and selecting and position a camera is a rage inspiring prospect.  The single viewport with poor viewport controls makes positioning entities far more frustrating than it should be.  In fact, I tend to position entities using direct numeric entry because the viewport is so frustrating to use.  Hopefully these areas are improved soon, as all are fairly easy things to fix.

 

Toolbar

A fair bit of functionality is packed into the toolbar, as shown below:

image

 

Tools and Editors

 

As mentioned earlier, there are a few tools built directly in to Wave Editor.  Some of these are invoked by selected an asset in the asset viewer.  Others are invoked when creating new assets in the Assets menu:

 

image

 

Model Viewer

image

 

Material Editor

image

 

SpriteSheet Tool

image

Create Font

image

 

Coding in Wave Engine

 

So we’ve looked at the editor in some depth, now let’s take a look at the coding experience.  As the editor is actually a fairly recent addition, Wave Engine can obviously has pretty solid code support.  Let’s take a look at the process of creating a camera and adding film grain to it like we did earlier in the editor.  The results of the Editor are two fold, a series of file formats that the engine can understand and a CSharp project that you can edit.  You can load the solution from the File menu:

image

 

Your project should look like this:

image

 

The first project is the bootstrap for your game, it’s the second project where your code goes.

Game.cs

#region Using Statements
using System;
using WaveEngine.Common;
using WaveEngine.Common.Graphics;
using WaveEngine.Framework;
using WaveEngine.Framework.Services;
#endregion

namespace ProgrammaticCamera
{
    public class Game : WaveEngine.Framework.Game
    {
        public override void Initialize(IApplication application)
        {
            base.Initialize(application);

      ScreenContext screenContext = new ScreenContext(new MyScene()); 
      WaveServices.ScreenContextManager.To(screenContext);
        }
    }
}

 

MyScene.cs

#region Using Statements
using System;
using WaveEngine.Common;
using WaveEngine.Common.Graphics;
using WaveEngine.Common.Math;
using WaveEngine.Components.Cameras;
using WaveEngine.Components.Graphics2D;
using WaveEngine.Components.Graphics3D;
using WaveEngine.Framework;
using WaveEngine.Framework.Graphics;
using WaveEngine.Framework.Resources;
using WaveEngine.Framework.Services;
#endregion

namespace ProgrammaticCamera
{
    public class MyScene : Scene
    {
        protected override void CreateScene()
        {
            this.Load(WaveContent.Scenes.MyScene);           
        }
    }
}

 

WaveContent.cs

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

// File generated on 2015-10-04 12:43:05 PM
namespace ProgrammaticCamera
{
    using System;
    
    
    public sealed class WaveContent
    {
        
        public sealed class Scenes
        {
            
            /// <summary> Path to Content/Scenes/MyScene.wscene </summary>
            public const string MyScene = "Content/Scenes/MyScene.wscene";
        }
    }
}

 

Game.cs creates your scene, MyScene.cs is your scene and WaveContent.cs is a system generated file for mapping resources in the editor into code friendly variables.  MyScene.cs is where your logic will go.  Let’s do a simple example that creates a red spinning cube entirely procedurally.

 

#region Using Statements
using System;
using WaveEngine.Common;
using WaveEngine.Common.Graphics;
using WaveEngine.Common.Math;
using WaveEngine.Components.Cameras;
using WaveEngine.Components.Graphics2D;
using WaveEngine.Components.Graphics3D;
using WaveEngine.Framework;
using WaveEngine.Framework.Graphics;
using WaveEngine.Framework.Resources;
using WaveEngine.Framework.Services;
using WaveEngine.ImageEffects;
using WaveEngine.Materials;
#endregion

namespace ProgrammaticCamera
{
    public class MyScene : Scene
    {
        protected override void CreateScene()
        {
            this.Load(WaveContent.Scenes.MyScene);  
         
            //Create a new red material
            WaveEngine.Materials.StandardMaterial material = new 
                                                             StandardMaterial(
                                                             Color.Red,
                                                             DefaultLayers.
                                                             Opaque);

            //Create our new entity with the name "cube"
            Entity entity = new Entity("cube");

            // AddComponent is chainable.  Add a Transform3D for position, 
            ModelRenderer so it renders
            // and a MaterialMap containing our material
            entity.AddComponent(Model.CreateCube())
                .AddComponent(new Transform3D())
                .AddComponent(new ModelRenderer())
                .AddComponent(new MaterialsMap(material));

            // Accessing components is easy.  Let's position at 0,0,0, even 
            though this is actually the default
            entity.FindComponent<Transform3D>().Position = new Vector3(0f, 0f, 
                                              0f);

            // We can also add behaviors to our entity.  Let's make it spin
            entity.AddComponent(new Spinner());

            // You can also get components by type, the true/false is wether the 
            type needs to be an exact match
            var spinner = (Spinner)entity.FindComponent(typeof(Spinner), true);
            // Spin on the Y axis
            spinner.IncreaseY = 5f;

            // Finally add our component to the active scene using EntityManager 
            global
            EntityManager.Add(entity);
        }
    }
}

 

And when run:

WaveEd1

 

The code is pretty heavily commented, so I wont bother with much explanation.  Keep in mind that code could actually be a great deal shorter.  Things were done the way they are for demonstration purposes only.  The entire thing could have been defined in a single chain of AddComponent calls.

 

Next let’s take a look at a 2D example that shows how you can respond to input and more tightly integrate into the editor.  We are going to add a class that can be used to control a 2D player sprite, such as the players character in a 2D game.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using WaveEngine.Common.Graphics;
using WaveEngine.Common.Input;
using WaveEngine.Components.Animation;
using WaveEngine.Components.Graphics2D;
using WaveEngine.Framework;
using WaveEngine.Framework.Graphics;
using WaveEngine.Framework.Services;

namespace SpriteTest
{
    [DataContract]
    class MyPlayer : Behavior
    {
        [RequiredComponent]
        public Transform2D transform2D;

        [RequiredComponent]
        public SpriteAtlas spriteAtlas;

        [RequiredComponent]
        public Animation2D animation2D;

        [RequiredComponent]
        public SpriteAtlasRenderer spriteAtlasRender;

        public MyPlayer()
            : base("MyPlayer")
        {
            transform2D = null;
            spriteAtlas = null;
            animation2D = null;
            spriteAtlasRender = new SpriteAtlasRenderer();
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void Update(TimeSpan gameTime)
        {
            if(WaveServices.Input.KeyboardState.Left == ButtonState.Pressed)
                transform2D.X -= (float)(100.0 * gameTime.TotalSeconds);
            if (WaveServices.Input.KeyboardState.Right == ButtonState.Pressed)
                transform2D.X += (float)(100.0 * gameTime.TotalSeconds);
        }

    }
}

 

Now in Wave Editor when you add a new Entity you should see your type as an option as a component that can be added to an entity.

image

 

As you can see, the types we added and marked as [RequiredComponent] are exposed to the editor.  I define a sprite sheet for our player (see video for the complete process), then when you run the game:

waved4

Pretty cool.

 

Engine Features

 

Of course, we can only go into a very small subset of the actual engine functionality in this tutorial, so let’s take a quick look at the marketing feature set:

 

Wave Engine is a C# component-based modern game engine which allows you to create cross-platform games and apps for many platforms: Windows, Linux, MacOS, iOS, Android, Windows Store and Windows Phone.

Wave Engine supports the same set of features in all its platforms to make it easy to port all your projects to other supported platforms.

You also have a great set of extensions with the complete code on github, to use WaveEngine with Kinect, OculusRift, Vuforia, Cardboard, LeapMotion and much more.

 

There is also a product roadmap available here for some direction on where Wave Engine development is headed.

 

Documentation and Community

 

At first glance Wave Engine has extremely good documentation.  After closer inspection this proves to be untrue, in fact, this is certainly an area that Wave Engine needs to improve.  For example I couldn’t find a single comprehensive link on the 3D export process ( supported formats, process involved, etc ) an area that most certainly should be well documented.

 

There is a wiki that serves as the getting started guide and tutorial in one.  Again at first glance it looks pretty complete, but when you start opening up entries and see that 75% of them are just stubs you know there is an issue.  The generated reference material also at first glance looks very good, but once you start diving in you realize that there is almost no descriptive text in any of the entries.  This is extremely disappointing… I can live without tutorials/manual when getting started, but a lack of reference is a painful pill to swallow.  There is also a technical blog that covers a mismatch of subjects.

 

There is a community forum that seems fairly active.  In researching the product Google led me to far too many questions without answers however.  Given the state of the documentation, this makes things even more frustrating.  If you aren’t the type to figure things out yourself, this will be a frustrating experience.  The design is straightforward enough that you can intuit most steps, but when you run into a wall, it hurts, a lot.

 

Fortunately there are several starter kits hosted on Github.  It is through this source code that you will mostly figure out how to work with Wave Engine.

 

Books

 

There are currently no books covering Wave Engine development.  Will update here if that changes.

 

Summary

 

Like the Paradox Game Engine, WaveEngine provides a solid code focused cross platform C# based alternative to Unity.  The design is clean, the code is intuitive and the examples are quite good.  The new editor is a step in the right direction and should certainly help with productivity, but does need a layer of polish.  The documentation certainly needs more attention too, especially if this engine is going to be used by newer developers.  The kernel here though shows a great deal of promise and the direction they are going is certainly the right one.  The api itself is quite large in scope, containing most of the functionality you will need.

 

One thing I don’t really understand, nor could I find a good source on, is the business model here.  Besides the splash screen, there are no real costs or requirements when using this engine.  There is currently no value add or upsell version, so I don’t understand where the company is making their money.  For non-open source projects, that is always a huge question mark in my head when evaluating an engine.  Companies ultimately need to make money to continue development, so this is certainly a huge question mark.  So they either use this engine for their own development and release it to others for altruistic reasons, or something is going to change.

 

If you like what you saw today though, I certainly recommend you check out Wave Engine.  With no cost and a minimal download, you have very little to lose!

 

The Video

Programming


24. August 2015

 

In this tutorial in our ongoing Paradox3d Game Engine tutorial series  we are going to look at controlling a Paradox game engine scene programmatically.  This includes accessing entities created in the editor, creating new entities, loading assets and more.  It should give you a better idea of the relationship between the scene and your code.

 

As always there is an HD video available here.

 

Creating a Simple Script

 

As part of this process we are going to be attaching a script to a scene entity programmatically.  First we need that script to be created.  We covered this process back in this tutorial if you need a brush up.  We are going to create an extremely simple script named BackAndForth.cs, which simply moves the entity back and forth along the x-axis in our scene.  Here is the contents of the script:

using System;
using SiliconStudio.Paradox.Engine;

namespace SceneSelect
{
    public class BackAndForth : SyncScript
    {
        private float currentX = 0f;
        private const float MAX_X = 5f;
        bool goRight = false;
        public override void Update()
        {
            if (Game.IsRunning)
            {
                if (goRight)
                {
                    currentX += 0.1f; 
                }
                else
                {
                    currentX -= 0.1f;
                }

                if (Math.Abs(currentX) > MAX_X)
                    goRight = !goRight;

                Entity.Transform.Position.X = currentX;
            }
        }
    }
}

 

If you've gone through the previous tutorials, this script should require no explanation.  We simply needed an example script that we can use later on.  This one merely moves the attached entity back and forth across the X axis until it reaches + or – MAX_X.

 

Now what we want to do is attach this script to the Sphere entity created in the default scene.  This means we are going to need to be able to locate an entity in code, and perhaps more importantly, we need some code to run.  We could create our own custom Game class like we did last tutorial, but this time we are going to do things a bit different.  Instead we are going to create a StartupScript.

 

First we new to create a new empty Entity in our scene to attach the script component to.  I called mine Config:

image


Next we create the Script we are going to attach.  Start with the following extremely simple script, Startup.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SiliconStudio.Paradox.Engine;
using SiliconStudio.Paradox.Rendering;

namespace SceneSelect
{
    public class Startup : StartupScript
    {
        public override void Start()
        {
            base.Start();
        }
    }
}

 

A StartupScript is a type of script that is loaded, as you may guess, on start. Unlike the Sync/AsyncScript classes we used earlier, there is no per frame update callback occurring.  This makes StartupScripts very useful for exactly this type of configuration tasks.

 

Now that we have our script, let’s attach it to our entity:

image

 

Finding an Entity using Code

 

First we are going to look at the process of locating an entity creating in Paradox Studio using code.  The following code will select the Sphere from the default scene using LINQ.

    var sphere = (from entities in this.SceneSystem.SceneInstance
                    where entities.Components.ContainsKey(ModelComponent.Key)
                    select entities).FirstOrDefault();

You can get the currently active scene using SceneSystem.SceneInstance, which contains a simple collection of Entity objects.  We then filter by entities with Components of type ModelComponent.  There are many ways we could have accomplished the same thing.  This query actually returns all entities in the scene that have a ModelComponent attached, which is overkill.  We could also select by the entities Name attribute:

image

Using the code:

    var sphere = (from entities in this.SceneSystem.SceneInstance
                    where entities.Name == "Sphere" select entities).
                                         FirstOrDefault();
    if (sphere == null) return;

 

Attaching a Script Component Programmatically

 

    ScriptComponent scriptComponent = new ScriptComponent();
    scriptComponent.Scripts.Add(new BackAndForth());
    sphere.Components.Add<ScriptComponent>(ScriptComponent.Key, scriptComponent);

 

Now that we have a reference to our sphere Entity, adding a new component is pretty simple.  Remember that the ScriptComponent is a collection of Script objects.  Simply Add() an instance of our newly created BackAndForth script.  Finally attach a ScriptComponent to our Sphere’s Components collection. 

 

When we run this code we will see:

BackAndForth

 

Creating a new Entity

 

We can also create another entity programmatically.

    Entity entity = new Entity(position: new SiliconStudio.Core.Mathematics.
                    Vector3(0, 0, 1), name: "MyEntity");
    var model = (SiliconStudio.Paradox.Rendering.Model)Asset.Get(typeof(
                SiliconStudio.Paradox.Rendering.Model), "Sphere");
    ModelComponent modelComponent = new ModelComponent(model);
    entity.Add<ModelComponent>(ModelComponent.Key, modelComponent);

 

Here we create a new entity with the name “MyEntity” and set it’s location to (0,0,1).  Next we get a reference to the ProceduralModel created in Paradox Studio, with a call to Asset.Get() specifying the type and URL ( you can see the Url value by mouse overing the asset in the Asset Viewer panel in Studio).  Now we create a new ModelComponent using this Model.  (Keep in mind, changes to it the Model will affect all instances, as I will show momentarily).  Finally we add the ModelComponent to the entity.

Finally we add our newly created entity to the scene using:

    SceneSystem.SceneInstance.Scene.AddChild(entity);

Now when we run the code:

BackAndForth2

 

As I mentioned earlier, changes to the Model will affect all instances.  For example, let’s say we create a new Material in the editor and apply it to the model.

image

Now the code:

    Entity entity = new Entity(position: new SiliconStudio.Core.Mathematics.
                    Vector3(0, 0, 1), name: "MyEntity");
    var model = (SiliconStudio.Paradox.Rendering.Model)Asset.Get(typeof(
                SiliconStudio.Paradox.Rendering.Model), "Sphere");
    var material = Asset.Load<Material>("MyMaterial");
    model.Materials.Clear();
    model.Materials.Add(new MaterialInstance(material));
    ModelComponent modelComponent = new ModelComponent(model);
    entity.Add<ModelComponent>(ModelComponent.Key, modelComponent);

And the (non-animated) result:

image

As you can see, the material on all of the Spheres has been replaced.  If you do not want this behaviour, you will have to create a new Model, either in Studio or programmatically.

 

New Entity using Clone

 

We could have also created our entity using the Clone() method of our existing Entity.

    var anotherSphere = sphere.Clone();
    sphere.Transform.Position.Z = 1f;
    SceneSystem.SceneInstance.Scene.AddChild(anotherSphere);

Keep in mind, the close will get all of the components of the cloned Entity, so if we clone after we add the ScriptComponent, it will also have the script attached.

 

 

Our complete source example:

using System.Linq;
using SiliconStudio.Paradox.Engine;
using SiliconStudio.Paradox.Rendering;

namespace SceneSelect
{
    public class Startup : StartupScript
    {
        public override void Start()
        {
            base.Start();

            var sphere = (from entities in this.SceneSystem.SceneInstance
                         where entities.Components.ContainsKey(ModelComponent.
                                                               Key)
                         select entities).FirstOrDefault();
            //var sphere = (from entities in this.scenesystem.sceneinstance
            //              where entities.name == "sphere" select entities).
                                                 firstordefault();
            //if (sphere == null) return;

            ScriptComponent scriptComponent = new ScriptComponent();
            scriptComponent.Scripts.Add(new BackAndForth());
            sphere.Components.Add<ScriptComponent>(ScriptComponent.Key, 
                                                   scriptComponent);


            Entity entity = new Entity(position: new SiliconStudio.Core.
                            Mathematics.Vector3(0, 0, 1), name: "MyEntity");
            var model = (SiliconStudio.Paradox.Rendering.Model)Asset.Get(typeof(
                        SiliconStudio.Paradox.Rendering.Model), "Sphere");
            var material = Asset.Load<Material>("MyMaterial");
            model.Materials.Clear();
            model.Materials.Add(new MaterialInstance(material));
            ModelComponent modelComponent = new ModelComponent(model);
            entity.Add<ModelComponent>(ModelComponent.Key, modelComponent);

            SceneSystem.SceneInstance.Scene.AddChild(entity);

            var anotherSphere = sphere.Clone();
            sphere.Transform.Position.Z = 1f;
            SceneSystem.SceneInstance.Scene.AddChild(anotherSphere);
        }
    }
}

And, running:

BackAndForth3

 

The Video

 

Programming


AppGameKit Studio

See More Tutorials on DevGa.me!

Month List