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

 

CastleDB is a light weight database written in Haxe with data composed of sheets.  It makes storing structured data extremely simple, much like working with an Excel spreadsheet and much simpler than a traditional database.  The resulting data is stored in JSON making it easily used in almost any game engine or programming language.   Most interestingly you can treat 2D game levels just like any other data using the newly built in level editor.

 

There is an HD video version of this guide available here.  It covers mostly the same details as this tutorial but goes into a bit more depth of using the level editor.

 

Let’s first take a look at the database side of things.  Even without the level editing abilities, games are often in need of simple database services.  Simply download and extract the archive for your appropriate platform:

image

 

Then run cdb.exe.  The interface looks like this:

image

 

Start by creating a new sheet by clicking Create a sheet.  This is comparable to creating a new table in a database.

image

 

Simply name your sheet and click Create.

 

Next we add some columns to our newly created sheet, same basic process.

image

 

Next pick the column type.

image

 

Optionally tick Required if the field cant be left empty.

image

 

You could select List and link to another database creating complex relationships.  Now we can populate a a database using the “New Line” command.  Select a type like Sprite (Image) and the appropriate dialog is displayed.

image

 

Now save the cdb file somewhere and you can access the data with code relatively easily.  First create a source file with the following contents, the black magic that links your cdb file to haxe code.

package com.gamefromscratch.castledemo.db;
private typedef Init = haxe.macro.MacroType < [cdb.Module.build("new.cdb")] > ;

 

And now you can consume it like:

package com.gamefromscratch.castledemo;

import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.Lib;
import haxe.Resource;

import com.gamefromscratch.castledemo.db.MyData;
class Main 
{
	
	static function main() 
	{
		
		#if js
		MyData.load(null);
		#else
		MyData.load(haxe.Resource.getString("new.cdb"));
		#end
		trace(MyData.myDB.get(Lich).HitPoints);
	}
	
}

 

Pretty simple over all.  Now what was that about a level editor?

 

Well… remember back when you created the first sheet?  You may remember a little checkbox “Create Level”.

image

 

Well this creates a table just like any other with some prepopulated values:

image

 

Width and Height are the number of cells that compose your level, the rest will be populated shortly.  Notice the Edit button that appears now?  Click it.

image

TADA!  Level editor.

The level editor can work in tiles or objects, let’s start with a single object layer for our background image.  Click the New Layer button at the top right.

image

Name it then click create.  Now click the File… button and we will select our background tiles.

image

 

Your image will now appear ready for painting, like so:

image

 

In Tile mode, simply select the tile, or tiles you wish to paint with like so:

image

 

Now back on your layer make sure you are in Tiles mode:

image

 

And paint away:

GIF

 

You can also work in object mode, which allows you to place sets of tiles without being confined to the grid.  First, define a set of tiles as an object:

GIF2

 

Now you can switch your level to object mode and draw using the created objects instead.

 

Now perhaps coolest of all, you can also instance data easily enough.  For example, we could add and place NPCs on our map, first we extend the map sheet to have an addition field, a List called npc, like so:

image

The List contains a reference to our monster table for example, x,y coordinates and an id.  Now if you head back to your map, you will see you’ve got an additional layer created:

image

 

Which you can now use to place NPCs or other data in your world.  You could do the same thing for collision data, whatever you wish.

This is only scratching the surface of what the level editor can do, there is even auto-tiling support built in.  Be sure to watch the video version for a more in-depth idea of the level editors capabilities.  Then when you are all done, it’s ultimately just data that you’ve been working with.

 

Now the downside is, there is no level loader when you are done.  So whatever engine or game you are importing the result into, it’s still just data.  It’s going to be your responsibility to display it all on screen.

 

The Video

Programming

5. November 2015

 

In this tutorial we are going to look at playing back music in our SFML game.  We will look at streaming an ogg file from disk.  We will also quickly look at the basics of handling time in SFML as we add fast forward and rewind abilities to our music playback.

 

There is an HD version of this tutorial here.

 

Playing music files is different from playing audio files and we will deal with this in a separate tutorial.  Music files are designed to be streamed from disk, not resident in memory.  SFML supports the following file formats:

  • ogg
  • wav
  • flac
  • aiff
  • au
  • raw
  • paf
  • svx
  • nist
  • voc
  • ircam
  • w64
  • mat4
  • mat5
  • pvf
  • htk
  • sds
  • avr
  • sd2
  • caf
  • wve
  • mpc2k
  • rf64

 

You will notice a very noticeable exception from that list, the mp3 format. That is because the mp3 format is encumbered by a number of patents and should be avoided to protect yourself from potential licensing fees.  Fortunately the ogg format offers similar file sizes and similar audio quality as the mp3 format without the licensing pitfalls.  If you require to covert formats the free software Audacity is an excellent and easy choice.

 

The major difference between sound effect and music is the sound effect stays resident in memory, while a Music file is streamed from disk.  Both classes still possess a great deal of common behaviour.  In fact if you look at the inheritance tree you will see that they have a common base class.

 

image

 

Now lets finally create some code showing how to actually play and control music files.

 

// Demonstrate that the hills are alive with the sound of music
#include "SFML/Graphics.hpp"
#include "SFML/Audio.hpp"
#include <iostream>

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;
  sf::Music music;
  music.openFromFile("audio/goats_typicalamerican.ogg");
  music.setVolume(50);

  music.play();

  while (renderWindow.isOpen()){
    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
        renderWindow.close();


      if (event.type == sf::Event::EventType::KeyPressed){

        // Up and down to control volume
        if (event.key.code == sf::Keyboard::Key::Down)
          music.setVolume(music.getVolume() - 10);
        if (event.key.code == sf::Keyboard::Key::Up)
          music.setVolume(music.getVolume() + 10);
        

        // Left and right to control tracking position
        if (event.key.code == sf::Keyboard::Key::Right){
          auto newPos = music.getPlayingOffset() + sf::seconds(5);
          music.setPlayingOffset(sf::Time(newPos));
        }
          
        if (event.key.code == sf::Keyboard::Key::Left){
          auto newPos = music.getPlayingOffset() - sf::seconds(5);
          if (newPos.asSeconds() <= 0.0f) newPos = sf::seconds(0);
          music.setPlayingOffset(sf::Time(newPos));
        }

        std::cout << "Current volume is :" << music.getVolume() << " position is: " 
          << music.getPlayingOffset().asSeconds() << std::endl;
      }
    }

    renderWindow.clear();
    renderWindow.display();
  }
}

 

You’ll notice that loading a music file is pretty much identical to loading any other asset in SFML.  Keep in mind the Music class actually owns the underlying data of the music that is played so it is not a light weight class so be careful when they are created.  However since the Music file is played from disk instead of from memory, it is safe to allocated multiple concurrent Music files, such as one per song played, without being hugely wasteful.

 

The code itself is fairly self explanitory.  You can set the volume directly on a music file that is being played, you can control music playback using vcr style play/pause/stop() controls.  You can also control the position of the sound using a combination of getPlayingOffset() and setPlayingOffset().  As you can see there are also time operators built into SFML such as sf::seconds() or sf::milliseconds() making time based math extremely simple.

 

There is a great deal more you can do with audio files, but we will cover that in the sound effects tutorial.

 

The Video

 

Programming , ,

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 ,

26. October 2015

 

In the previous tutorial we look at the process of using sprites in SFML.  Today we are going to look instead at using a sprite sheet or texture atlas.  The process is very similar to working with a normal sprite, except that you have multiple sprites on a single texture.  Loading and swapping textures in memory is an expensive operation, so holding multiple sprites together can greatly improve the speed of your game.

 

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

 

Many game engines have implicit support for spritesheets and sprite animation, however SFML does not.  There are however libraries built on top of SFML that provide this functionality or you can roll the required functionality yourself with relative ease.  Before we can continue we need a sprite sheet, which is simply one or more images with multiple frames of animation.  This is the one I am using:

dragonFrames

 

This isn’t the full sized image however.  The source file is actually 900x1200 pixels in size.  It should be noted that this size isn’t actually ideal.  Power of two texture dimensions should be preferred ( such as 512x256, 1024x1024, 2048x2048, etc. ).  In earlier version of OpenGL including OpenGL ES 1.x, a power of two texture was actually required.  These days, it is no longer a requirement, but a PoT texture generally will perform better.  As to file dimensions, you can fairly safely go up to 2048x2048 and support even rudimentary GPU’s like the Intel HD3000 series, but sizes of 4096x4096 are generally possible on most modern desktop and mobile GPUs.   You can notice from this image that it contains 12 textures, each 300x400 pixels in size.

 

Now we need code to extract a single frame from the texture and as you will see, it’s actually remarkably easy:

// Demonstrate creating a spritesheet
#include "SFML/Graphics.hpp"

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;
  sf::Texture texture;
  texture.loadFromFile("images/dragonFrames.png");

  sf::Sprite sprite(texture,sf::IntRect(0,0,300,400));


  while (renderWindow.isOpen()){
    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
        renderWindow.close();
    }

    renderWindow.clear();
    renderWindow.draw(sprite);
    renderWindow.display();
  }
}

 

This will draw just a small rectangular portion of our source texture, representing the first frame, like so:

image

 

Really that’s all that there is to it.  To add animation, we simply change the rectangular source after the fact, like so:

// Demonstrate creating a spritesheet
#include "SFML/Graphics.hpp"

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;
  sf::Texture texture;
  texture.loadFromFile("images/dragonFrames.png");

  sf::IntRect rectSourceSprite(300, 0, 300, 400);
  sf::Sprite sprite(texture,rectSourceSprite);
  sf::Clock clock;

  while (renderWindow.isOpen()){
    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
        renderWindow.close();
    }

    if (clock.getElapsedTime().asSeconds() > 1.0f){
      if (rectSourceSprite.left == 600)
        rectSourceSprite.left = 0;
      else
        rectSourceSprite.left += 300;

      sprite.setTextureRect(rectSourceSprite);
      clock.restart();
    }

    
    renderWindow.clear();
    renderWindow.draw(sprite);
    renderWindow.display();
  }
}

 

And when run:

GIF

 

You may notice right away that animation doesn’t look right and that’s a keen eye you’ve got there.  In this example we are simply going across the top three frames of animation from left to right.  The proper animation should actually be 0,1,2,1,0 not 0,1,2,0,1,2.  That said, in a proper game you would either roll your own animation class or use an existing one.  When we get to the process of creating a complete game, we will cover this process in detail.

 

In the above example we change frames of animation by changing the sprites source texture rect with a call to setTextureRect().  As I mentioned in the previous tutorial you could actually generate a new sprite per frame if preferred, as the sf::Sprite class is very light weight.

 

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 , ,

Month List

Popular Comments