Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

29. June 2016

 

Welcome to a new tutorial series here on GameFromScratch.com where we will be looking at core concepts of game programming.  This includes data structures, design patterns and algorithms commonly used in game development.  We start the series off with Finite State Machines.

 

There is an HD video version of this tutorial available here and embedded below.

 

What is a Finite State Machine?

 

A Finite State Machine (or FSM for short) is one of those concepts that sounds much scarier than it actually is.  In the simplest form it’s a datatype that can have only one value (state) from a finite selection of values(states).  The easiest way is to understand the finite state machine is to look at a real world example.

 

trafficLight

 

Yep, a traffic light is a perfect example of a FSM, or at least, the logic controlling it is.  Consider the three possible states this particular traffic light can be in.  At any given point (assuming I suppose the power is working...) the light will be one of three states, red, yellow or green.  It can never been more than one of those states at a time, it’s always red or yellow or green.  These are the two keep concepts of a finite state machine.  There are a finite number of states ( 3 in this case ) and only one is true or active at a time.

 

It’s a very simple concept, but extremely useful in game development.

 

What are FSMs Used For?

 

In game development, one of the most common uses for finite state machines is artificial intelligence.  Consider the example of PacMan’s ghosts.  A state machine can be used to control how they behave.  A ghost may have one of several different operating modes for example waiting to be released, hunting, hunted and dead.  The state machine is what is used to drive the ghost’s actions and to switch between states.  You will find AI examples absolutely loaded with state machines, often with some fuzzy logic controlling the transition between states to give a layer of unpredictability to your characters.

AI isn’t the only place of course, think of all the different things in a game that are related, there are multiple different states they can be in, but only one can be active at a time.  Game states are a very common example, where you break your game up into a series of states, for example Loading, Main Menu, Playing, High Score, Exiting.  Many game engines ( one such example is Phaser ) split your game up into a series of states.  The ultimate controller of these states is a finite state machine.  A sequential UI ( think of a sequence of dialogs controlled by next/back buttons ) can also be implemented using FSMs.  They are also commonly used to control elements in a games world.  Consider a game with a weather system, be it day or night cycles or season cycles like Spring, Summer, etc...  these would most likely be controlled via FSMs.

 

Implementing a Finite State Machine

 

The example we are going to use here is to implement a traffic light via FSM.  At it’s core the data is going to be stored in an enum, a natural fit for state machines, but stack based or array based options are also viable.  This example is not only going to switch the traffic lights periodically, it’s also going to implement callbacks so the world at large can interact with the light.  This example is implemented using C#, but should be easily adapted to most modern programming languages.

 

using System;

namespace GameFromScratchDemo
{

    public class TrafficLight{
        // This enum represents the three possible values our state machine can 
        be
        public enum States { Green, Yellow, Red };    
        // This is the amount of time for the timer to wait before changing 
        between states
        private const int LIGHT_DURATION = 5000;

        // An actual instance of our enum.
        private States _state;

        // The timer object that is going to be used to switch between states 
        private System.Threading.Timer _timer;

        // This function is called by the timer when it's time for a light to 
        change
        public void lightChanged(){
            System.Console.WriteLine("Light Changed");
            
            //  For each state, move to the next appropriate state.  I.e, red 
            becomes green, etc. 
            switch(_state){
                case States.Green:
                _state = States.Yellow;
                break;

                case States.Yellow:
                _state = States.Red;
                break;

                case States.Red:
                _state = States.Green;
                break;
            }

            // Reset our timer, so this will all happen again and again
            _timer.Change(LIGHT_DURATION,System.Threading.Timeout.Infinite);

            // Call our event.  This is used to communicate with the outside 
            world that our state change occured
            onStateChange(_state);
        }

        // In our constructor we simply set out default state (green) and 
        create/start our timer
        public TrafficLight() {
            _state = States.Green;
            System.Console.WriteLine("Light Created with initial Green state");

            _timer = new System.Threading.Timer( _ => lightChanged(), null, 
            LIGHT_DURATION,
                System.Threading.Timeout.Infinite);
        }

        // these two work together to provide the callback functionality
        // Implementing callback is going to differ greatly from langauge to 
        language
        public delegate void StateChangedResult(States newState);
        public event StateChangedResult onStateChange;
    }

    // Our actual program.  Simply create a traffic light instance
    // Register a callback that will simply print the current state returned 
    when the light state changes
    // And finally wait for the user to hit enter before ending the program
    public class Program
    {
        public static void Main(string[] args)
        {
            TrafficLight light = new TrafficLight();
            light.onStateChange += (TrafficLight.States state) => { Console.
            WriteLine(state); };
            Console.ReadLine();
        }
       
    }
}

The example is pretty well documented in the code above.  Essentially we are creating a class TrafficLight that can internally have one of three states Green, Yellow or Red.  It also implements a timer that switches between those states.  To make the code actually useful, it also implements a callback system so code external to the TrafficLight can interact with it as a black box.  The callback will be passed the current state value every time the light changes.

 

This is obviously a simple example of a state machine but the same basic premise remains regardless to complexity.  It is a very useful data structure for organizing code, especially the flow of logic.  Coupled with callbacks, it is also a great way of keeping systems decoupled as much as possible.

 

The Video

Programming, Design , ,

29. June 2016

 

Another week another Unity patch, this one version 5.3.5P6.  In addition to the usual spate of bug fixes, this patch includes several improvements to audio functionality, a bump to Oculus 1.5 and has been updated to work with XCode 8 for iOS builds.

The full release details:

Improvements
  • Audio: Added ability to transition AudioMixer snapshots by scaled and unscaled time.
  • Audio: Added virtualization of audio effects. For audio sources that are virtual because they have been culled due to low audibility or priority, attached effect components or spatializers are now also bypassed in order to save CPU use. The new behaviour is on by default, but can be turned off in the audio project settings.
  • Audio: Audio clip waveform preview now displays the actual format used for compression when the default format isn’t available on a certain platform.
  • Audio: Audio clips with the "Streaming" load type are no longer preloaded. This is done to reduce the number of open file handles in scenes referencing a large number of streamed clips. The behaviour is not affected except for a slight increase in playback delay of this type of audio clips.
  • Audio: Fixed audio clip waveform preview rendering sync issues after import, and improved the way the waveforms are being rendered to be more dynamic and reveal more detail.
  • Audio: Moved Preload Audio Data to the platform-specific settings section. The previous location was confusing as it was shown grayed-out in the inspector with a checkmark that depended on all overrides.
  • Audio: SystemInfo now includes supportsAudio info.
  • iOS: Update Build and Run to work with Xcode 8
  • VR: Updated to Oculus Version 1.5.
Fixes
  • (786827) - Animation: Fixed rotation values set in inspector restricted to [0,360] degrees when recording animation.
  • (800268) - Animation: Fixed animation event firing twice when controller is set by a script and an instantaneous transition is trigger in the same frame.
  • (778887) - Animation: Fixed crash when changing playable controller in animator in game mode.
  • (740603) - Audio: "Failed to initialize spatializer" warning message no longer appears when Spatializer Plugin is set to "None".
  • (758064) - Audio: Audio Profiler no longer shows "wrong" information when using Spatialization.
  • (632169) - Audio: AudioMixer.GetFloat() and SetFloat() now work without needing to restart Unity.
  • (782248) - Audio: AudioSource: Fixed issue whereby Doppler Level didn't work when used with custom spatializer plugins.
  • (772946) - Audio: Fixed case of component effect appearing disabled on play and becoming enabled again after pressing pause and then play.
  • (763036) - Audio: Fixed case of Unity crashing when the Disable Audio option was selected in Project Settings.
  • (784887) - Audio: Fixed crash when disabling component which uses OnAudioFilterRead.
  • (none) - Audio: Fixed handling of default DSP buffer size. Previously, once the buffer size was changed to something other than Default latency, changing it back to Default latency had no effect.
  • (781566) - Audio: Fixed issue where AudioListener with two custom scripts crashed when reinitializing the sound system.
  • (775328) - Audio: Fixed issue where the Audio Lowpass Frequency curve moved in the wrong direction in the AudioSource curve view.
  • (771825) - Audio: Fixed issue whereby adding an effect in the mixer with bypass effects enabled didn't rechain the component effect back properly.
  • (none) - Audio: Fixed issue whereby the memory profiler did not report AudioClip memory correctly. The memory allocated by AudioClips was wrongly accumulated under AudioManager.
  • (760985) - Audio: Fixed mixer reverb effects getting cut off early in standalone builds.
  • (718344) - Audio: Fixed random mixup between internal direct and reverb signal connections which could cause AudioSources to interfere and become silent under certain conditions.
  • (731177) - Audio: Large numbers of streaming audio clips no longer cause crashes in batch mode.
  • (732854) - Audio: Low Pass Filter now works on Audio Listener.
  • (715257) - Audio: Microphone.IsRecording(null) no longer returning true even when no devices were available.
  • (none) - Audio: Native audio plugin SDK: Fixed dspbuffersize having a value of 0 when default buffer size settings are selected.
  • (none) - Audio: Preloaded sounds now allow calling GetData in Start().
  • (none) - Audio: Project browser now updates after a change has been applied in the AudioImporterInspector.
  • (none) - Audio: Sounds marked as Play On Awake are now shown in Audio profiler.
  • (806648) - Editor: Fixed activate license failure if user switch user before activation.
  • (804864) - Editor: Fixed an issue causing unnecessary script compilation, and improved compilation error handling
  • (804139) - Editor: fixed an issue where custom windows could be removed when encountering errors in user editor scripts.
  • (802014) - IL2CPP: Fixed a crash that can occur during XML serialization with the .NET 2.0 profile.
  • (800496) - IL2CPP: Fixed a crash which can occur during the iteration of enum values cast as a list of System.Object values.
  • (804767) - IL2CPP: Corrected the packing for some C# struct definitions with explicit layout.
  • (805846) - IL2CPP: Fixed try/catch handling when filter type includes generic parameters.
  • (794660, 790555, 737693) OpenGLES: Fixed crash and reflection probes corruption on A9 chipsets (OpenGLES2.0).
  • (799560) - Windows Store: Fixed a crash which happened when serializing objects which have the first field be an array or a list on .NET scripting backend.
  • (805830) - Windows Store: Fixed a memory leak which leaked ~5 KB of memory per frame.
  • (804163) - Windows Store: Fixed an issue which sometimes caused "The referenced script on this Behaviour is missing!" after unloading unused assets while maintaining indirect references on the MonoBehaviours on .NET scripting backend.
  • (775624) - Windows Store: Fixed manifest generation for StoreLogo, when only scale-100 image is available.
  • (767548) - Windows Store: Load first scene after Unity splash screen is over.
  • (786277) - Windows Store: NetworkTransport.ConnectEndPoint will work correctly on UWP (required by secure sockets), note this function will not work on older Windows Store SDKs.

The patch is available for download here.

GameDev News

29. June 2016

 

Lumberyard is Amazon’s new game engine based on a forked version of CryEngine.  I did a short hands-on video of Lumberyard shortly after it was released if you want more information.  Earlier this month Amazon announced the upcoming release of Lumberyard 1.3, announcing that it would have VR support among other features.  Well that release date is now here, at least in Beta form.  This release brings with it over 130 features, improvements and fixes including some serious graphicalvolumetric_fog enhancements.  The two major features of this release are HDR support and the aforementioned VR support (currently Oculus Rift and HTC Vive).  There were several other graphical updates to the engine, including:

  • Volumetric Fog: We increased the temporal stability of volumetric fog, reduced the presence of flickering artifacts, and improved fog’s overall performance.
  • Motion Blur: To give a higher degree of control over the motion blur effect, we added a weighting algorithm to improve the visual quality of silhouettes and added a shutter speed control like those you find in a real-world camera.
  • Height Mapped Ambient Occlusion: This new feature generates ambient occlusion per pixel from a terrain height map, which brings out subtle details and depth cues in terrain that would have been previously unseen.
  • Depth of Field: We implemented a new depth of field technique that reduces edge-bleeding artifacts and utilizes fewer GPU resources.
  • Emittance: We have replaced glow with a physical-based model of emittance. This allows you to model glowing objects as proper citizens of a physically accurate world of lighting and materials. We have changed lighting calculations to properly account for emittance, and we provided a way to automatically convert older content to use the new emittance property.

On the mobile graphics side, we have improved iOS rendering performance by an average of 15%, which is a significant jump considering our mobile renderer is already leveraging Metal and GMEM to maximize performance. We also added adaptive and scalable texture compression (ATSC), which is useful for managing bandwidth, memory footprint, and power, all of which are important for low-power, mobile devices.

Finally, if you are a graphics programmer like me, then you are just as concerned about profiling and performance as pretty pixels. So one last thing I want to highlight is the integrated graphics profiler. You can now display all sorts of mission-critical performance stats in real-time, including detailed CPU and GPU timings per frame, per pipeline stage, per sub-system. You will also find many useful graphics counters like to draw call counts, shader counts, triangle, and vertices count. These run-time stats nicely complement capture-based analysis tools like RenderDoc and Lumberyard’s Driller logging system.

You can read the announcement blog here while the more detailed release notes are available here.

GameDev News

28. June 2016

 

Corona is a popular Lua powered mobile focused game engine, which just saw a new major release.  Major features of this release include Spine animation support and support for high DPI screens on both Windows and Mac.  There are several other new features however including:

Core and cross-platform features
Corona Simulator
  • High resolution screen support for macOS (retina) and Windows screens (DPI Awareness).
  • Console improvements.
  • Updates to file handling for opening projects, including opening directories and dragging files to the Corona Simulator icon to open projects.
  • native.showAlert() improvements on Windows.
  • The Corona Simulator now warns you if a plugin is required and needs configuration within build.settings.
  • You now get warnings in the Corona Simulator when there is a file name mismatch due to case sensitivity.
Android
  • Multi-Dex support.
  • Improvements to Android 6.x permission handling.
  • Support for Android Studio builds for Enterprise.
  • Videos can now be loaded from all Corona-defined directories.
  • Updated libpng to version 1.2.56.
  • Fixed an issue involving Java-based plugins and applications exiting.
  • Improvements around licensing support.
iOS
  • In-app purchase API store.purchase() can now take a table of item strings or a single item string, just like the similar API for other purchasing platforms.
  • New lines handled correctly in display.newText().
  • Improved rendering of large text objects.
  • Camera fill can now be invalidated more than once per frame.
macOS
  • Added support for system.setIdleTimer().
  • Improved handling of full screen apps.
  • Improved handling of native objects when resizing desktop builds.
  • Improved rendering of large text objects.
  • native.newTextBox() objects now support the “began” phase.
  • You can now control the window’s title bar for desktop builds.
  • Support for high resolution retina displays.
  • Added the ability to show and hide the mouse using native.setProperty().
tvOS
  • Support for On-Demand Resources.
  • Remote handling improvements including “relativeTouch”.
  • Improved rendering of large text objects.
Windows Phone 8 / Windows 10 Mobile
  • Added Visual Studio 2015 and .NET 4.6 support to CoronaCards for Windows Phone.
Windows Desktop
  • Easier to run Corona from the command line.
  • Added support for surround sound audio (5.1 and 7.1).
  • Support for high resolution screens with “DPI awareness”.
  • Added the ability to show and hide the mouse using native.setProperty().
  • Computers with touch screens will now show a virtual keyboard when you interact with native.newTextField() and native.newTextBox().
  • Better formatting for Corona Simulator error messages.

This release is available for download here.

GameDev News

28. June 2016

 

There is a new release of the Defold Game Engine, version 1.2.84.  WebView is now available on mobile platforms with certain limitations.  This release also includes improved sound on mobile devices with better call and battery management.  Among the other fixes are:

Engine

  • DEF-1674 - Added: WebView support on iOS and Android
  • DEF-1691 - Added: sound.is_phone_call_active() available on mobile devices
  • DEF-1857 - Changed: render.predicate now accepts hashes as well as strings
  • DEF-1914 - Fixed: Support for setting HTTPS URIs as resource.uri
  • DEF-1709 - Fixed: IAP callback did not run after opening a minimized app via the home screen on Android
  • DEF-1940 - Fixed: Some purchases using test accounts on Android resulted in error
  • DEF-1918 - Fixed: Stack problem on Android devices < 4.3
  • DEF-1920 - Fixed: Bundle dialogs for iOS and Android now remember the field entry data
  • DEF-1924 - Fixed: Android IAP dialog was shown multiple times if changing device orientation
  • DEF-1937 - Fixed: dmloader.js would sometimes try to load the same archive files multiple times
  • DEF-1825 - Fixed: Crash when on_message functions tried to return data
  • DEF-1278 - Fixed: Android implementation of sound.is_music_playing() now works correctly

Service

  • Updates of access token management. It is now possible to revoke access tokens.

Web

  • API documentation for render has been updated
  • An "Examples project" is now available
  • Return values has been clarified in API docs
  • API documentation has been added for WebView

If you are interested in learning more about the Defold Engine be sure to watch this video.  We also have a tutorial series in development here on GameFromScratch.com.

GameDev News

Month List

Popular Comments