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

 

I find once you’ve learned a couple of programming languages, the way you learn future programming languages changes a bit.  Instead of learning a language feature by feature, you instead tend to jump right in and learn the language relative to languages you already know.  In this case I find it handy to create a quick cheat sheet or Coles/Cliff notes version as I learn that programming language.  This is that sheet, so if you already know a couple programming languages and want to learn Kotlin, hopefully this will be as useful as any tutorial at getting you going quickly.  Keep in mind I don’t even pretend to be a subject matter expert here!

 

Hello World

Starting off with a Hello World example is all but required by law, so here it is:

fun main(args: Array<String>){
    println("Hello World")
}

As you can see the app entry point is main() just like most C influenced programming languages.  Functions are marked with fun keyword and unlike Java, they do not have to be in a class nor in a package really cutting down the code count.  Variables and parameters are named in the format  name:type, it is increasingly popular for variable type to be on the right ( Haxe, Swift, Go, etc ).  Otherwise nothing shocking here.  It should be noted that semicolon line terminators are completely optional.

 

Variables

Read Only Vs. Variant Types

Let's look at a simple example with variables allocated.

fun main(args: Array<String>){
    val meaningOfLife:Int = 42;
    var meaningOfDeath = meaningOfLife +1
    meaningOfLife++ // NOT ALLOWED!!!
}

Notice val and var.  A val type is read only and once initialized cannot be altered.  A var type is a traditional variable and as you can see in this case, type can be inferred automatically by the compiler.  The final line there will not compile because meaningOfLife is a read only type.  If it was a var type however, that line would compile just fine (in other words, there is a postfix increment operator in Kotlin).  Oh and Kotlin supports C++ style // Comments.  Speaking of comments…

 

Commenting

All the traditional C++ style comments are supported, as are JDoc style

// This is a comment
/*
And so is this
 */
/**
 * And this is a JDoc/KDoc style comment
 * @param args Comment documenting param args meaning
 */
fun main(args: Array<String>){

}

 

Numeric Types

Kotlin has several built in number types: Char, Byte, Short, Int, Float, Long and Double:

fun main(args: Array<String>){
    var byte: Byte = 127 // Signed byte, -128 to 127
    var char: Char = 'A' // A 16bit Unicode character
    var short: Short = Short.MAX_VALUE //16bit signed MAX_VALUE == 32767
    var int: Int = 0xff // 32bit signed, Hex can be used with 0x prefix
    var long:Long = 0b11101101// 64bit signed, binary can be used with 0b prefix
    var float:Float = 3.14f // 32bit floating point number, floats designated with f postfix
    var double:Double = 3.1e10 // 64bit floating point, IEEE notation can be used too

    //double = float; // automatic down conversation is not allowed
    //float = double; // Nor is up conversion!

    double = float.toDouble() //Explicit conversion is allowed
    float = double.toFloat()

    byte = short.toByte() // allowed, but value too big so value is -1
    short = 42;
    byte = short.toByte() // value fits, new val would be 42
}

Bigger and smaller types share no relationship, so automatic conversation does not exist, except in the case of literals.  So you cant automatically assign a short to a byte, nor a byte to a short without calling the appropriate to() method.  Truncation will occur if the type doesn’t fit the new type.

 

Functions

As we’ve seen already, functions are marked with the fun keyword.  The format is “fun named(args): return type” like so:

fun doSomething(a:Int, b:String): String {
    return "$b $a";
}

fun main(args: Array<String>){
    println(doSomething(42,"Meaning of Life is"));
}

This example declares a function that takes and Int and a String and returns a String.  This example also illustrates the use of string templates in Kotlin.  Inside a string you can use the $ symbol to do a C printf style format.  If however you need to use a dollar sign in a literal string you can escape it in the form {‘$’}.

 

Nullable Types

Functions can also return a null value, but need to be marked as such using the ? operator, like so:

fun setName(name:String) : String? {
    if(name == "Mike")
        return "Mike"
    else
        return null;
}
fun main(args: Array<String>) {
    var name = setName("Mike");
    if (name is String) {
        // in if block containing an is, no casting is required
        println(name);
    }
}

As you can see, with a type preceded with a ? can be set to null.  This example also illustrates the is operator, which is the Kotlin analog of typeof in C++.  Another neat trick is illustrated here, within the scope of an if using the is operator, typecasts are not required.  Speaking of typecasts…

 

Typecasts

As we saw earlier, all of the built in numeric types have a toXXX() method for type conversion.  However to straight casts, Kotlin has “safe” and “unsafe” casts.  An unsafe cast could potentially result in an exception because the type cast isn’t possible.  To perform an unsafe cast, use the as operator, like so:

    var i:Int = 42;
    println(i as String);

However if you run this code, BOOM!

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String.

If there is a possibility your cast could fail, instead use the operator as? like so:

 

    var i:Int = 42;
    println(i as? String);

This will result in either the casted value being returned, but if the cast cannot be performed, instead of throwing an exception, it instead returns null.

 

Conditionals and Flow Control

Kotlin works much like most modern languages with a couple exceptions.  if works pretty much like you would expect, except its an expression and returns a value ( the evaluated conditional ) like so:

    var a = 1; var b = 2;
    var bigger = if( a > b) a else b;
    println(bigger); // Prints 2

As a result Kotlin does not have C's confusing ternary ? operators. Additionally you can also set the value returned within an if block, it's simply the last value within the block. Like so:

enum class Enemies { Orc, Skeleton, Pigeon}
fun main(args: Array<String>) {
    var enemy = Enemies.Pigeon;
    println("Enemy was of type " +
        if(enemy == Enemies.Orc){
            // Do Orc related code
            "Orc";
        }
        else{
            "Not Orc";
        }
    );
}

As you can see, the final value in the if block is the returned value by the if statement.  Oh yeah… and Kotlin supports enums, as you can see from this example.

 

One other major difference in Kotlin is there is no else if, nor is there a switch statement.  Instead you have the somewhat confusingly named when that fills both roles, like so:

enum class Enemies { Orc, Skeleton, Pigeon}
fun main(args: Array<String>) {
    var enemy = Enemies.Pigeon;
    when(enemy){
        Enemies.Pigeon -> print("Pigeon");
        Enemies.Orc -> print("Orc");
        else -> {
            print("Who the heck knows at this point??")
        }
    }
}

Much like a C/C++ style switch statement except there is no case keyword, default is replaced with an else statement and you use –> instead of a colon.

You can also do ranges in when statements, like so:

fun main(args: Array<String>) {
    var meaningOfLife:Int = 42;
    when(meaningOfLife){
        in 1..22 -> print("Between 1 and 22");
        !in 22..44 -> print("Not between 22 and 44");
        else -> {
            // None of the above
        }
    }
}

 

For, while and do-while loops all work pretty much the same as other languages.  Kotlin supports break, return and continue statements and they work as expected ( and can be used to short circuit a when statement ).  You can however set a label using the @ postfix then specify it specifically in the break/continue/return statement, like so:

fun main(args: Array<String>) {
    outer@ for(i in 1..100){
        inner@ for(j in 1..100) {
            if (j == 42) {
                continue@outer;
            }
        }
    }
}

This above example will immediately cause the outer loop to jump to it’s next iteration when the inner loops condition is true, effectively short circuiting the inner loop. (Yes, an un-labeled break would have the exact same result)

 

Extension Method

Class can be easily via extensions methods.

class A {}

fun A.somethingNew() {
    print("Gave A new superpowers, woot")
}

fun String.toA() : A {
    return A();
}
fun main(args: Array<String>) {
    var a = A();
    a.somethingNew()

    var s = "Meaningless initial value";
    s.toA().somethingNew();

}

As you can see any class can be extended using the form 'fun classname.newMethod". You can also extended built-in classes, like shown here with String.

 

And that brings us nicely too…

 

Classes

As we just saw, a class is declared like:

class MyClass {
    
}

 

In fact for an empty class like this, you can omit the body entirely, like:

class MyClass;

fun main(args: Array<String>) {
    var myClass = MyClass();
}

Of course, that code wont actually do anything.  As you can see from this and earlier examples there is no new operator.

 

Constructors

Kotlin has a primary constructor, which is similar to a default constructor in C++.   However no code can be contained in the constructor.  Here is an example:

class MyClass(myString:String){};

fun main(args: Array<String>) {
    var myClass = MyClass("test");
}

If you need to set initial values programmatically, you can do so in the init block, like so:

class MyClass(stringParam:String){
    var myString:String;
    val valToAppend: String = "42";
    init {
        myString = stringParam;
        myString += valToAppend;
    }

    constructor(stringParam:String, myInt:Int) : this(stringParam){
        myString += myInt.toString();
    }
};

fun main(args: Array<String>) {
    var myClass = MyClass("test");
    print(myClass.myString); // Prints test42

    var myClass2 = MyClass("test", 43);
    print(myClass2.myString); //Prints test4243 !!!!
}

This example also showed how to set a secondary constructor using the constructor keyword.  Note the call back to the default constructor in the secondary constructor.  Also note the result on myClass as per the comment, showing the order of constructor calls.

 

Inheritance

 

The base class of all classes in Kotlin is Any, which is analogous to object in Java ( and there is no equivalent in C++ ).  Inheritance looks almost exactly like Java, like so:

open class Base{};

class Derived : Base() {};

The only major difference is the parent class is marked open, otherwise it would be marked final. If the base class has a constructor, you must call it in the derived class like so:

open class Base(param:Int){};

class Derived : Base(42) {};

 

If a derived class has no primary constructor then it’s secondary constructors need to call the base class using super like so:

open class Base(param:Int){};

class Derived : Base {
    constructor(param:Int) : super(param){}
}

 

Method inheritance is done with a combination of open and override, like so:

open class Base {
    open fun baseFunc() {
        println("base");
    }
};

class Derived : Base() {
    override fun baseFunc() {
        println("derived");
    }
}

fun main(args: Array<String>) {
    var derived = Derived()
    derived.baseFunc() // prints "derived"
}

 

There are also interfaces in Kotlin, but they are probably a bit different than what you expect, as the interface can contain both abstract functions as well as implementations, like so:

interface BaseInterface {
    fun a()
    fun b() {print("b");}
};

class implementation : BaseInterface {
    override fun a() { print("a");}
}

fun main(args: Array<String>) {
    var imp = implementation()
    imp.a();
    imp.b();
}

The abstract method must be implemented in the derived class.  The only difference between an interface and abstract class is an interface does not have state.  Like Java you can only have one base class but as many interfaces as wanted.  If you name collision, it can be resolved like so:

interface A {
    fun a(){print("A")};
};
interface B {
    fun a(){print("B")};
};


class implementation : A,B {
    override fun a() {
        super<A>.a();
        super<B>.a();
    }
}

fun main(args: Array<String>) {
    var imp = implementation()
    imp.a();
}

 

Functional Programming

Kotlin also has good functional programming capabilities, consider the following example that takes a function, both anonymous or named:

fun onCallback(callback:() -> Unit) {
    return callback();
}
fun otherFunc() { print("Maybe"); }

fun main(args: Array<String>) {
    onCallback({print("Callme")});
    onCallback(::otherFunc);
}

 

An anonymous function takes the form (params) –> return.  In the above example there are no params and no return.  In Kotlin Unit is the equivalent of void in C.  The :: operator returns a callable reference.

 

 

This material should be more than enough to get started making a game in Kotlin.  I guess we shall see.  Of course, this is just a quick start, to dig deeper the entire language reference is available here.

Programming , ,

30. November 2015

 

The Visual Studio team at Microsoft just released Service Pack 1 for Visual Studio 2015.  The editor now supports several more languages such as Go, Swift and Ruby, command line REPL for C#, new NuGet and .Net releases and more.  From the announcement blog post:

  • New Visual Studio Icon. Responding to your feedback on UserVoice, we’ve tweaked the Visual Studio 2015 icon in Update 1 to make it easier to differentiate visually between multiple versions of Visual Studio running side by side on the same machine:
    New icon for Visual Studio
  • .NET Framework 4.6.1. Visual Studio 2015 Update 1 includes the latest version (4.6.1) of the .NET Framework. You can read about all the new features on the .NET blog.
  • Editor support for new languages. The Visual Studio editor now provides built-in syntax highlighting and basic IntelliSense support for languages including Go, Java, Perl, R, Ruby, and Swift. We support the TextMate bundle
    model for language grammars and snippets, allowing you to extend this with support for other languages.
    Editor support for new languages (showing R)
  • IncrediBuild-Visual Studio partnership. With this collaboration and at no additional cost, developers can use IncrediBuild’s build engine to lay out build plans for their applications with more parallelized execution of the build. This leverages hardware resources more effectively and provides monitoring to identify bottlenecks and better understand resource usage. For complete details, see the post, Improving your build times with IncrediBuild and Visual Studio 2015.
  • Tools for Universal Windows Apps v1.2. This update enables you to build and submit apps to the Windows Store targeting Windows 10 SDK Version 1511. It includes several developer productivity improvements to .NET Native, the XAML designer, the manifest designer, Windows Store packaging, and the debugger in this release. If you don't already have Tools for Universal Windows Apps installed, you can enable them by modifying the Visual Studio 2015 installation, or directly installing them from http://go.microsoft.com/fwlink/?LinkID=619614.
  • Native support for behaviors in Universal Windows apps. Behaviors are an easy way of adding common interactivity to your XAML apps without having to add more imperative code. These are natively supported in Update 1, shipping as a NuGet Package (available for both managed and native projects), and accepting contributions as an open source project. The package can also be installed through the Blend Assets Pane (under “Behaviors”). Learn more from theXAML Behaviors, open source and on UWP post on the Windows Developer blog, start contributing by visiting theGitHub page, or request features by raising issues.
  • MSTest and CodeCoverage support for ASP.NET 5. The Visual Studio testing tools now support MSTest framework-based tests for ASP.NET 5 applications and add support for CodeCoverage with ASP.NET 5 on x86/x64 platforms targeting the CoreCLR/CLR. The MSTest framework components are available from the NuGet gallery.
  • Parallel Test Execution: The Visual Studio testing tools introduce support for parallel execution of test cases leveraging the available cores on the machine, with Test Explorer indicating the progress of parallel tests. The test execution engine is launched on each available core as a distinct process, and is given a container (assembly, DLL, or relevant artifact) with the tests to execute according to the semantics of the test framework. VS supports parallel execution through all launch points (e.g. the command line and IDE commands like Test Explorer, CodeLens, and various “Run” commands). For details on how to enable this feature, refer to the Release Notes.
    Parallel Test Execution feature showing tests running at the same time
  • C# Interactive Window and command-line REPL. We’ve added more functionality and fixed a number of bugs in these features that first appeared in the CTP. For RTM we’ve also cleaned up some of the command-line argument handling as described in the detailed notes on GitHub. (Note that NuGet support and the VB scripting API are not available with this release, but we’re still actively working on them. In the meantime, you can play with the C# scripting API available on GitHub.)
  • Managing analysis issues. We’ve heard from many customers that when they install a Roslyn analyzer from NuGet or Visual Studio Extensions, thousands of code analysis issues end up showing up in the Error List, leading them to abandon the analyzer. With this update you can now suppress all current issues to a global suppression file, view and manage baselined issues (to audit suppressions or review baselined issues), show analysis warnings and messages for only ‘my code changes,’ and remove duplicate instances of warnings in the error list to focus results to the unique set.
    Managing analysis issues
  • NuGet and NuGet Package Manager. NuGet 3.3 is now bundled with Update 1, and we’ve made a number of changes to the NuGet Package Manager interface including a tab-based UI to help filter groups of packages, action buttons in the package list for quick access to common management functions, a Consolidate tab for packages you work with at the solution level, and an Update tab that allows you to select and update multiple packages together.
    Updated NuGet package manager
  • Visual Studio license improvements. Signing in to unlock the IDE with your subscription is one of those features that you do not want to see interrupting your workflow. Towards this goal, Update 1 has improvements that will ensure the IDE stays unlocked for a year or more after signing in as long as you have regular access to the internet to keep the license renewed in the background. More improvements to reduce sign ins are still to come.

Full details are available in the release notes.  I know I’m installing right away, but that’s mostly because I found Visual Studio 2015 to be a bit of a mess, so I’m hoping this is an improvement and I can move up from VS2013 finally!

GameDev News, Programming

30. November 2015

 

 

 

This entry in the Closer Look series is a bit different than normal.  First, Blade Engine is very much a work in progress, so expect bugs and flaws and minimal documentation.  Second, it’s actually built over top of an existing game engine, LibGDX.  Finally, it’s a game engine focused on one very specific genre – adventure games.  Given the popularity of hidden object games on mobile these days, there are no doubt a number of people looking for an appropriate engine.  So without further adieu, I present the Bladecoder Adventure Engine, an open source cross platform LibGDX based game engine and editor for creating adventure games.

image

As always there is an HD video version available here.

 

Meet Bladecoder Adventure Engine

 

Blade engine consists of two parts, the underlying game engine and the editor that is layered on top of it.  It is designed in such a way that you can work entirely in the editor and never once right a line of source code.  You assemble your game from a collection of Chapters, Scenes and Actors and added events and actions in the form of verbs.  If you want to modify the fundamental structure of the game itself, you are going to have to jump into the underlying source code.  Fortunately that is an option, as Bladecode Engine is hosted on Github and the source is available under the incredibly liberal Apache 2 license.

 

Blade Engine Features at a Glance:

  • Multi platform support: Android, IOS, Desktop (Windows, OSX, Linux) and HTML
  • Several animation techniques: sprite/atlas animation, Spine (cutout) animation and 3d model animation
  • 3d character support
  • Multiresolution to deal with different densities and screen sizes
  • Multilanguage support
  • Open source and free (as in beer and freedom)
  • Code free game creation possible

 

The heart of Bladecoder is ultimately the editor, so let’s focus there after we cover getting started.

 

Getting Started

 

To get started with Bladecoder you need to have Java and git installed and properly configured.  Bladecoder uses the JavaFX ui library so you will have to use JDK 8 or newer or be prepared to have to configure JavaFX manually in the build process.  You will also require an internet connection for the build process to succeed the first time. To start, from a terminal or command line, change to the folder you want to install Bladecoder and enter:

git clone https://github.com/bladecoder/bladecoder-adventure-engine.git

cd bladecoder-adventure-engine

gradlew build

gradlew run

 

There is an example repository, including the work in progress game The Goddess Robbery available in the repository https://github.com/bladecoder/bladecoder-adventure-tests.  You should probably clone this repository too, as this is perhaps the single biggest documentation source available right now.

 

The Editor

 

Assuming the compilation process went without issue above, you should now see the Adventure Editor, where the bulk of your work will occur.

image

 

Your game is composed of a collection of Chapters, which in turn contain Scenes.  Scenes in turn are a collection of Actors and organized in layers:

image

 

Game Props enables you to set global properties of your game:

image

 

Resolution enables you to quickly create scaling modes for supporting multiple device resolutions ( think Retina ):

image

 

While Assets enables you to import multiple defined assets include audio and music files, texture atlases, 3D models, images and more.

image

 

You organize your scene using the editor available in the center of the window:

image

You can place actors on different layers, define walk paths, etc.  Click the Test button to preview that scene in action.

 

The actual logic of your game is defined on the right hand side of the editor. 

Here you can set properties of your actors:

image

 

Create and edit dialogs:

image

 

Define sounds and animations:

image

 

Clicking the edit icon will bring up the appropriate editor:

image

 

While selecting an animation will preview it in the scene:

GIF

 

Finally Verbs are the heart of your application:

image

 

You can think of verbs an analogous to event handlers, and they can be applied at the world, scene or actor level.  There are also default verbs that will be fired if unhandled.  Think the generic “I don’t know how to use that” messages from adventure games from the past.

 

Let’s look at an example from the Scene, handling the Init verb which is fired when the scene is ready.

image

 

This verb causes the sequence of actions shown at the bottom part of the above image to be fired when the scene init verb is called.  This causes the player to move, a dialog sequence, the player is scripted to drop an item, a state value is changed, etc.  You can create new elements by clicking the + icon:

image

 

And filling out the resulting form.  Each element has a different form associated with it.  Here for example is the result of the Say element:

image

 

Once complete simply click the play or package button:

image

 

Play launches the standard loader:

image

 

This screen can obviously be customized to each individual game.  While package brings up a form enabling you to build your game for a variety of platforms:

image

 

And that essentially is it.

 

Help and Community

This is certainly a weak point of the Bladecoder engine, it’s the result of a single coder, there is minimal help available and if you don’t know how to debug Java code, you will probably end up in trouble, at least at this point in it’s lifecycle.  There is currently no community or forum available for this engine but perhaps that will change in the future.  I spoke with the developer a few times however and he was very responsive and quick with fixes and answers.  He is also on twitter at @bladerafa if you want status updates on the project.

For now documentation consists of a minimal wiki although for the most part the best source of documentation is going to be from following the examples.

 

Summary

Make no mistakes, this is very much an under development engine so expect things to blow up spectacularly at any time.  When it does, you are probably going to be on your own figuring out why as there is no community to fall back on.  All that said this is a surprisingly robust tool that makes the process of creating an adventure game exceedingly simple.  Once the engine matures a little bit it will be an excellent tool for even a non-programmer interested in making adventure games.  For now though if you are competent in Java and interested in making an adventure game, this engine takes care of a hell of a lot of work for you and provides full source code for when it doesn’t.  Plus at the end of the day, the price is certainly good too!

 

The Video

Design, Art, Programming , , , ,

25. November 2015

 

With the upcoming LibGDX jam, it dawned on me I hadn’t done anything with LibGDX in a while.  I decided to look into doing a mini game series in advance of the Jam and decided it was a good opportunity for me to look into the Kotlin programming language.  Ironically a day later, RoboVM and IntelliJ announce a Kotlin code competition… stars aligning I suppose.

 

So I decided to start with Kotlin-afying a LibGDX project and see how the process went.  This tutorial is the result of that experience, although to be honest calling it a tutorial is a bit of a joke as the process was amazingly simple.

 

Before we begin there are a couple of things you are going to need:

 

Open the project in IntelliJ just like normal with a Java application.

In your project, in core create a new Kotlin file beside your main class like so:

image

 

That’s one of the cool things about Kotlin, it can exist along side existing java sources.  Once you create the Kotlin file, this popup will be shown:

image

 

Click the link and let it configure as a Kotlin module. Defaults are good, click OK.

image

 

Now this part is impressive and I discovered it by accident.  Open your existing .java file and copy the contents, then paste them into your newly created kt file.  When prompted, let it convert the Java to Kotlin code:

image

 

Now the default project will be converted to Kotlin, but there will be a pair of errors:

image

 

Kotlin does not appear to like unallocated variables.  There are a few options here.  You can move the initialization of batch and img to the KotlinDemo constructor, you can default initialize them to null (this will however cause LibGDX to explode, so not recommended ;) ) or you can add the lateinit modifer, which is the route I went.  Here is the resulting code:

package com.gamefromscratch

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch

class KotlinDemo : ApplicationAdapter() {
    internal lateinit var batch: SpriteBatch
    internal lateinit var img: Texture

    override fun create() {
        batch = SpriteBatch()
        img = Texture("badlogic.jpg")
    }

    override fun render() {
        Gdx.gl.glClearColor(1f, 0f, 0f, 1f)
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
        batch.begin()
        batch.draw(img, 0f, 0f)
        batch.end()
    }
}

Congratulations, you’ve just created your first Kotlin application!  The mix and match nature enables you to slowly port your code over to Kotlin making the transition exceedingly easy.

Now there is one last very important step, we need to delete the original .java class. 

image

 

When you delete it, you want to make sure you don’t do a smart delete, as we want the existing references to this class to remain (as our Kotlin class is replacing it):

image

 

I’m going to continue to play around with Kotlin, so expect more coverage over the next few days/weeks.  Let me know what you think of Kotlin… any interest?

Programming ,

23. November 2015

 

 

In this tutorial we are going to look at audio programming in Cocos2d-x.  We will look at playing music and sound effects using SimpleAudioEngine, one of two engines built into Cocos2d-x.  There is a second, newer, more commplex and experimental audio engine AudioEngine, that we will discuss later.  Let’s start straight away by playing some music.  To make use of SimpleAudioEngine we need to add an additional include call:

#include "SimpleAudioEngine.h"

 

Next we need a song of some sorts to play, simply copy an appropriate file into your resources folder.  Myself I used an mp3 file named creatively enough song.mp3.

Supported Audio File Formats


The audio formats supported by Cocos2D-x depend entirely on what platform you run on.  The primary thing to be aware of is the ogg format is the preferred music format on Android platforms, while it is completely unsupported on iOS, which prefers MP3.

You should be aware that the MP3 format is patent encumbered format and generally should be avoided when possible.  If your app reaches certain sales thresholds, you may be required to pay license fees.  Sadly this generally isn’t an option on iOS devices as MP3 is the primary audio format used.  For sound effects, WAV are commonly used offering quick playback ability at the cost of file size.  Here are the details of supported audio files on iOS

Time now for some coding.  Implement the following init() method:

bool HelloWorld::init()
{
   if (!Layer::init())
      return false;

   auto audio = CocosDenshion::SimpleAudioEngine::getInstance();
   audio->preloadBackgroundMusic("song.mp3");
   audio->playBackgroundMusic("song.mp3");

   return true;
}

That is all that is required to load and play a music file. In fact the preloadBackgroundMusic() call wasn't even required so we could have used even less code. However preloading your music guarantees that you will not suffer a slow down the first time a song plays. You can also pause and resume playback of background music, or switch tracks completely, like so:

   eventListener->onKeyPressed = [audio](EventKeyboard::KeyCode keyCode, Event* event) {

      switch (keyCode) {
         case EventKeyboard::KeyCode::KEY_SPACE:
            if (audio->isBackgroundMusicPlaying())
               audio->pauseBackgroundMusic();
            else
               audio->resumeBackgroundMusic();
            break;

         case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
            audio->playBackgroundMusic("song2.mp3");
            break;

         case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
            audio->playBackgroundMusic("song.mp3");
            break;
      }
   };

   _eventDispatcher->addEventListenerWithFixedPriority(eventListener, 2);

Hitting the spacebar will toggle the playback of the currently playing song.  Hitting the right arrow will start playing (or start over if already playing) song2.mp3. Hitting the left arrow will start or re-start playback of song.mp3.  You will notice from this example that only one song can be played at a time.  Generally this isn’t a limitation as it is normal to only have one active sound track at a time. 

setBackgroundMusicVolume() doesn't work!


A bit of a warning, at least on Windows, calling setBackgroundMusicVolume() does nothing, making it impossible to change the volume of a playing music file. This may not be the case on other platforms, I did not test. It was filed as a bug a long time back and does not appear to have been addressed.

 

Now let's look at playing sound effects instead.  Playing music and effects is almost identical.  The biggest difference is that sound effects are expected to support multiple concurrent instances.  That is to say, while you can only play one song at a time, you can play multiple sound effects at once. Consider this sample:

bool HelloWorld::init()
{
   if (!Layer::init())
      return false;

   auto audio = CocosDenshion::SimpleAudioEngine::getInstance();
   
   audio->preloadEffect("gun-cocking-01.wav");
   audio->preloadEffect("gun-shot-01.wav");

   audio->playEffect("gun-cocking-01.wav");

   Director::getInstance()->getScheduler()->schedule([audio](float delta) {
      audio->playEffect("gun-gunshot-01.wav");
      audio->unloadEffect("gun-cocking-01.wav");
   }, this, 1.5f, 0, 0.0f, false, "myCallbackKey");

   return true;
}

 

In this example we preload two WAV sound effects, a gun cocking and a gun shot.  Playing a sound effect is as simple as calling playEffect() passing in the file name.  Of course, be certain to copy the appropriate sound files to your project’s resource folder before running this example.  Next this example queues up a lambda method to be called 1.5 seconds of the gun cocking sound is played to play our gun shot sound.  At this point we are done with our gun cocking effect so we unload it from memory using unloadEffect().  You can still call playEffect with that file in the future, but it will result in the file being loaded again.

 

This example might be somewhat convoluted, but it illustrates and works around a key weakness in the CocosDenshion audio library.  It is a very simple and straight forward library but if you want to do “advanced” things like detecting when a song or audio effect has ended, unfortunately this functionality is not available.  You either have to use the experimental AudioEngine, which we will cover later, or use an external audio library such as FMOD.  SimpleAudioEngine is extremely easy to use, but not very powerful, so it’s certainly a trade off.  If you just need background music and fire and forget sound effects SimpleAudioEngine should be just fine for you.

 

One final topic to cover is handling when your app is minimized or forced into the background, you most certainly want to stop audio playback.  This is thankfully easily accomplished in your AppDelegate there are a pair of methods, applicationDidEnterBackground() and applicationWillEnterForeground().  Simply add the following code:

void AppDelegate::applicationDidEnterBackground() {
   auto audio = CocosDenshion::SimpleAudioEngine::getInstance();
   audio->pauseAllEffects();
   audio->pauseBackgroundMusic();
}

void AppDelegate::applicationWillEnterForeground() {
   auto audio = CocosDenshion::SimpleAudioEngine::getInstance();
   audio->resumeAllEffects();
   audio->resumeBackgroundMusic();
}

 

This will cause all of your currently playing sound effects and music files to be paused when your application enters the background and they will all result when your application regains focus.

Programming , ,

 

Month List

Popular Comments