Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

8. July 2014

 

In this part of the LibGDX tutorial series we are going to take a look at using GLSL shaders.  GLSL standards for OpenGL Shader Language and since the move from a fixed to programmable graphics pipeline, Shader programming has become incredibly important.  In fact, every single thing rendered with OpenGL has at least a pair of shaders attached to it.  It’s been pretty transparent to you till this point because LibGDX mostly takes care of everything for you.  When you create a SpriteBatch object in LibGDX, it automatically creates a default vertex and fragment shader for you.  If you want more information on working with GLSL I put together the OpenGL Shader Programming Resource Round-up back in May.  It has all the information you should need to get up to speed with GLSL.  For more information on OpenGL in general, I also created this guide.

 

Render Pipeline Overview

 

To better understand the role of GL shaders, it’s good to have a basic understanding of how the modern graphics pipeline works.  This is the high level description I gave in PlayStation Mobile book, it’s not plagiarism because I’m the author. :)

 

A top-level view of how rendering occurs might help you understand the shader process. It all starts with the shader program, vertex buffers, texture coordinates, and so on being passed in to the graphics device. Then this information is sent off to a vertex shader, which can then transform that vertex, do lighting calculations and more (we will see this process shortly). The vertex shader is executed once for every vertex and a number of different values can be output from this process (these are the out attributes we saw in the shader earlier). Next the results are transformed, culled, and clipped to the screen, discarding anything that is not visible, then rasterized, which is the process of converting from vector graphics to pixel graphics, something that can be drawn to the screen.

The results of this process are fragments, which you can think of as "prospective pixels," and the fragment are passed in to the fragment shader. This is why they are called fragment shaders instead of pixel shaders, although people commonly refer to them using either expression. Once again, the fragment shader is executed once for each fragment. A fragment shader, unlike a vertex shader, can only return a single attribute, which is the RGBA color of the individual pixel. In the end, this is the value that will be displayed on the screen. It sounds like a horribly complex process, but the GPUs have dedicated hardware for performing exactly such operations, millions upon millions of times per second. That description also glossed over about a million tiny details, but that is the gist of how the process occurs.

 

So basically shaders are little programs that run over and over again on the data in your scene.  A vertex shader works on the vertices in your scene ( predictably enough… ) and are responsible for positioning each vertex in the world.  Generally this is a matter of transforming them using some kind of Matrix passed in from your program.  The output of the Vertex shader is ultimately passed to a Fragment shader.  Fragment shaders are basically, as I said above, prospective pixels.  These are the actual coloured dots that are going to be drawn on the users screen.  In the fragment shader you determine how this pixel will appear.  So basically a vertex shader is a little C-like program that is run for each vertex in your scene, while a fragment shader is run for each potential pixel.

 

There is one very important point to pause on here…  Fragment and Vertex shaders aren’t the only shaders in the modern graphics pipeline.  There are also Geometry shaders.  While vertex shaders can modify geometry ( vertices ), Geometry shaders actually create new geometry.  Geometry shaders were added in OpenGL 3.2 and D3D10.  Then in OpenGL4/D3D11 Tessellation shaders were added.  Tessellation is the process of sub-dividing a surface to add more detail, moving this process to silicon makes it viable to create much lower detailed meshes and tessellate them on the fly.  So, why are we only talking about Fragment and Vertex shaders?  Portability.  Right now OpenGL ES and WebGL do not support any other shaders.  So if you want to support mobile or WebGL, you can’t use these other shader types.

 

SpriteBatch and default Shaders

 

As I said earlier, when you use SpriteBatch, it provides a default Vertex and Fragment shader for you.  Let’s take a look at each of them now.  Let’s do it in the order they occur, so let’s take a look at the vertex shader first:

 

attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;

uniform mat4 u_projTrans;

varying vec4 v_color;
varying vec2 v_texCoords;

void main()
{
    v_color = a_color;
    v_color.a = v_color.a * (256.0/255.0);
    v_texCoords = a_texCoord + 0;
    gl_Position =  u_projTrans * a_position;
}

 

As I said, GLSL is a very C-like language, right down to including a main() function as the program entry point.  There are a few things to be aware of here.  First are attribute and uniform  variables.  These are variables that are passed in from your source code.  LibGDX takes care of most of these for you, but if you are going to write your own default shader, LibGDX expects all of them to exist.  So then, what is the difference between a uniform and attribute variable?  A uniform stays the same for every single vertex.  Attributes on the other hand can vary from vertex to vertex.  Obviously this can have performance implications, so if it makes sense, prefer using a uniform.  A varying value on the other hand can be thought of as the return value, these values will be passed on down the rendering pipeline ( meaning the fragment shader has access to them ).  As you can see from the use of gl_Position, OpenGL also has some built in values.  For vertex shaders there are gl_Position and gl_PointSize.  Think of these as uniform variables provided by OpenGL itself.  gl_Position is ultimately the position of your vertex in the world.

 

As to what this script does, it mostly just prepares a number of variables for the fragment shader, the color, the normalized ( 0 to 1 ) alpha value and the texture to bind to, in this case texture unit 0.  This is set by calling Texture.Bind() in your code, or is called by LibGDX for you.  Finally it positions the vertex in 3D space by multiplying the vertices position by the transformation you passed in as u_projTrans.

 

Now let’s take a quick look at the default fragment shader:

#ifdef GL_ES
#define LOWP lowp
    precision mediump float;
#else
    #define LOWP
#endif

varying LOWP vec4 v_color;
varying vec2 v_texCoords;

uniform sampler2D u_texture;

void main()
{
    gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}

 

As you can see, the format is very similar.  The ugly #ifdef allows this code to work on both mobile and higher end desktop machines.  Essentially if you are running OpenGL ES then the value of LOWP is defined as lowp, and precision is set to medium.  In real world terms, this means that GL ES will run at a lower level of precision for internal calculations, both speeding things up and slightly degrading the result. 

The values v_color and v_texCoords were provided by the vertex shader.  A sampler2D on the other hand is a special glsl datatype for accessing the texture bound to the shader.  gl_FragColor is another special built in variable ( like vertex shaders, fragment shaders have some GL provided variables, many more than Vertex shaders in fact ), this one represents the output color of the pixel the fragment shader is evaluating.  texture2D essentially returns a vec4 value representing the pixel at UV coordinate v_texCoords in texture u_texture.  The vec4 represents the RGBA values of the pixel, so for example (1.0,0.0,0.0,0.5) is a 50% transparent red pixel.  The value assigned to gl_FragColor is ultimately the color value of the pixel displayed on your screen.

 

Of course a full discussion on GLSL shaders is wayyy beyond the scope of this document.  Again if you need more information I suggest you start here.  I am also no expert on GLSL, so you are much better off learning the details from someone else! :)  This does however give you a peek behind the curtain at what LibGDX is doing each frame and is going to be important to us in just a moment.

 

Changing the Default Shader

 

There comes a time where you might want to alter the default shader and replace it with one of your own.  This process is actually quite simple, let’s take a look.  Let’s say for some reason you wanted to render your game entirely in black and white?  Here are a simple vertex and fragment shader combo that will do exactly this:

 

Vertex shader:

attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;

uniform mat4 u_projTrans;

varying vec4 v_color;
varying vec2 v_texCoords;

void main() {
    v_color = a_color;
    v_texCoords = a_texCoord0;
    gl_Position = u_projTrans * a_position;
}

Fragment shader:

#ifdef GL_ES
    precision mediump float;
#endif

varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform mat4 u_projTrans;

void main() {
        vec3 color = texture2D(u_texture, v_texCoords).rgb;
        float gray = (color.r + color.g + color.b) / 3.0;
        vec3 grayscale = vec3(gray);

        gl_FragColor = vec4(grayscale, 1.0);
}

I saved each file as vertex.glsl and shader.glsl respectively, to the project assets directory.  The shaders are extremely straight forward.  The Vertex is in fact just the default vertex shader from LibGDX.  Once again remember you need to provide certain values for SpriteBatch to work… don’t worry, things will blow up and tell you if they are missing from your shader! :)  The fragment shader is simply sampling the RGB value of the current texture pixel, getting the “average” value of the RGB values and using that as the output value.

 

Enough with shader code, let’s take a look at the LibGDX code now:

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.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class ShaderTestApp extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;
    Sprite sprite;
    String vertexShader;
    String fragmentShader;
    ShaderProgram shaderProgram;

    @Override
    public void create () {
        batch = new SpriteBatch();
        img = new Texture("badlogic.jpg");
        sprite = new Sprite(img);
        sprite.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        vertexShader = Gdx.files.internal("vertex.glsl").readString();
        fragmentShader = Gdx.files.internal("fragment.glsl").readString();
        shaderProgram = new ShaderProgram(vertexShader,fragmentShader);
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        batch.setShader(shaderProgram);
        batch.draw(sprite,sprite.getX(),sprite.getY(),sprite.getWidth(),sprite.getHeight());
        batch.end();
    }
}

 

And when you run it:

image

 

Tada, your output is grayscale!

As to what we are doing in that code, we load each shader file as a string.  When then create a new ShaderProgram passing in a vertex and fragment shader.  The ShaderProgram is the class the populates all the various variables that your shaders expect, bridging the divide between the Java world and the GLSL world.  Then in render() we set our ShaderProgram as active by calling setShader().  Truth is, we could have done this just once in the create method instead of once per frame.

 

Multiple Shaders per Frame

 

In the above example, when we set the shader program, it applied to all of the output.  That’s nice if you want to render the entire world in black and white, but what if you just wanted to render a single sprite using your shader?  Well fortunately that is pretty easy, you simply change the shader again.  Consider:

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.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class ShaderTest2 extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;
    Sprite leftSprite;
    Sprite rightSprite;
    String vertexShader;
    String fragmentShader;
    ShaderProgram shaderProgram;

    @Override
    public void create () {
        batch = new SpriteBatch();
        img = new Texture("badlogic.jpg");
        leftSprite = new Sprite(img);
        rightSprite = new Sprite(img);

        leftSprite.setSize(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight());
        leftSprite.setPosition(0,0);
        rightSprite.setSize(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight());
        rightSprite.setPosition(Gdx.graphics.getWidth()/2,0);

        vertexShader = Gdx.files.internal("vertex.glsl").readString();
        fragmentShader = Gdx.files.internal("fragment.glsl").readString();
        shaderProgram = new ShaderProgram(vertexShader,fragmentShader);
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        batch.setShader(null);
        batch.begin();
        batch.draw(leftSprite, leftSprite.getX(), leftSprite.getY(), leftSprite.getWidth(), leftSprite.getHeight());
        batch.end();

        batch.setShader(shaderProgram);
        batch.begin();
        batch.draw(rightSprite, rightSprite.getX(), rightSprite.getY(), rightSprite.getWidth(), rightSprite.getHeight());
        batch.end();
    }
}

 

And when you run it:

image

 

One using the default shader, one sprite rendered using the black and white shader.  As you can see, it’s simply a matter of calling setShader() multiple times.  Calling setShader() but passing in null restores the default built-in shader.  However, each time you call setShader() there is a fair amount of setup done behind the scenes, so you want to minimize the number of times you want to call it.  Or…

 

Setting Shader on a Mesh Object

 

Each Mesh object in LibGDX has it’s own ShaderProgram.  Behind the scenes SpriteBatch is actually creating a large single Mesh out of all the sprites in your screen, which are ultimately just textured quads.  So if you have a game object that needs fine tune shader control, you may consider rolling your own Mesh object.  Let’s take a look at such an example:

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class MeshShaderApp extends ApplicationAdapter {
    SpriteBatch batch;
    Texture texture;
    Sprite sprite;
    Mesh mesh;
    ShaderProgram shaderProgram;

    @Override
    public void create () {
        batch = new SpriteBatch();
        texture = new Texture("badlogic.jpg");
        sprite = new Sprite(texture);
        sprite.setSize(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());

        float[] verts = new float[30];
        int i = 0;
        float x,y; // Mesh location in the world
        float width,height; // Mesh width and height

        x = y = 50f;
        width = height = 300f;

        //Top Left Vertex Triangle 1
        verts[i++] = x;   //X
        verts[i++] = y + height; //Y
        verts[i++] = 0;    //Z
        verts[i++] = 0f;   //U
        verts[i++] = 0f;   //V

        //Top Right Vertex Triangle 1
        verts[i++] = x + width;
        verts[i++] = y + height;
        verts[i++] = 0;
        verts[i++] = 1f;
        verts[i++] = 0f;

        //Bottom Left Vertex Triangle 1
        verts[i++] = x;
        verts[i++] = y;
        verts[i++] = 0;
        verts[i++] = 0f;
        verts[i++] = 1f;

        //Top Right Vertex Triangle 2
        verts[i++] = x + width;
        verts[i++] = y + height;
        verts[i++] = 0;
        verts[i++] = 1f;
        verts[i++] = 0f;

        //Bottom Right Vertex Triangle 2
        verts[i++] = x + width;
        verts[i++] = y;
        verts[i++] = 0;
        verts[i++] = 1f;
        verts[i++] = 1f;

        //Bottom Left Vertex Triangle 2
        verts[i++] = x;
        verts[i++] = y;
        verts[i++] = 0;
        verts[i++] = 0f;
        verts[i] = 1f;

        // Create a mesh out of two triangles rendered clockwise without indices
        mesh = new Mesh( true, 6, 0,
                new VertexAttribute( VertexAttributes.Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE ),
                new VertexAttribute( VertexAttributes.Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE+"0" ) );

        mesh.setVertices(verts);

        shaderProgram = new ShaderProgram(
                Gdx.files.internal("vertex.glsl").readString(),
                Gdx.files.internal("fragment.glsl").readString()
                );
    }

    @Override
    public void render () {

        Gdx.gl20.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        Gdx.gl20.glClearColor(0.2f, 0.2f, 0.2f, 1);
        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
        Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
        Gdx.gl20.glEnable(GL20.GL_BLEND);
        Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);

        batch.begin();
        sprite.draw(batch);
        batch.end();

        texture.bind();
        shaderProgram.begin();
        shaderProgram.setUniformMatrix("u_projTrans", batch.getProjectionMatrix());
        shaderProgram.setUniformi("u_texture", 0);
        mesh.render(shaderProgram, GL20.GL_TRIANGLES);
        shaderProgram.end();
    }
}

And when you run it:

 

image

This sample is long but fairly simple.  In create() we create the geometry for a quad by defining 2 triangles.  We then load our ShaderProgram just like we did in the earlier example.  You may notice in creating the Mesh we define two VertexAttribute values and bind them to values within our ShaderProgram.  These are the input values into the shader.  Unlike with SpriteBatch and the default shader, you need to do a bit more of the behind the scenes work when rolling your own Mesh.

 

Then in render() you see we work with the SpriteBatch normally but then draw our Mesh object using Mesh.render, passing in the ShaderProgram.  Texture.bind() is what binds the texture from LibGDX to texture unit 0 in the GLSL shader.  We then pass in our required uniform values using setUniformMatrix and setUniformi ( as in int ).  This is how you set up uniform values from the Java side of the fence.  u_texture is saying which texture unit to use, while u_projTrans is the transformation matrix for positioning items within our world.  In this case we are simply using the projection matrix from the SpriteBatch.

 

Using a Mesh instead of a Sprite has some disadvantages however.  When working with Sprites, all geometry is batched into a single object and this is good for performance.  More importantly, with Mesh you need to roll all the functionality you need from Sprite as you need it.  For example, if you want to support scaling or rotation, you need to provide that functionality.

Programming , ,

7. July 2014

Today Oculus announced they have acquired RakNet and immediately released it under a modified BSD open source license.  The code is already available on their Github repository.  If you’ve never heard of it, RakNet is a low level C++ networking engine providing features like object replication, voice chat and patching.  A number of engines such as Unity and Havok already license RakNet and it has been used in hundreds of games.

 

From the Oculus Press release:

Oculus Acquires & Open Sources RakNet

We’re pleased to announce that we’ve acquired RakNet, one of the leading networking middleware systems in the games industry. We open-sourced it starting today under a modified BSD license (the same license Facebook uses for its open source projects) from the Oculus GitHub repo:https://github.com/OculusVR/RakNet.

For those unfamiliar with RakNet, it is a comprehensive C++ game networking engine designed for ease of use and performance. The tech is tuned for cross-platform, high-performance applications that operate across a wide variety of network types. Key features include object replication, remote procedure calls, patching, secure connections, voice chat, and real-time SQL logging. The technology has been licensed by thousands of indie developers, as well as companies like Unity, Havok, Mojang, Maxis and Sony Online Entertainment.

We’ve known Kevin Jenkins, founder of Jenkins Software and lead engineer on RakNet, for years, and we’ve used RakNet internally at Oculus for various networked systems and tools. After working with Kevin for a few months, we were all excited by the idea of open-sourcing RakNet to the community.

If you’re interested in checking out (or forking) RakNet, head over to the Oculus GitHub repo athttps://github.com/OculusVR/RakNet. We’re looking forward to seeing where the community takes the project next!

 

 

Pretty awesome news.  Perhaps the sale to Facebook wasn’t so terrible after all?

3. July 2014

 

Back in Part 3  of this SpriteKit/Swift tutorial series we looked at loading game sprites using a texture atlas and implemented a simple animation system.  At the time I said this wasn’t the way you perform animation and that I would cover the proper way later.  Then in Part 4 we covered SpriteKit actions showing how to perform a number of different actions.  Now we look to combine the two, using actions to perform sprite sheet based animations using a TextureAtlas.

 

This example is basically a perfect mash-up of the prior two tutorials, so it will be code heavy and explanation light.  So, on to the code!

 

import SpriteKit

 

class GameScene: SKScene {

    let textureAtlas = SKTextureAtlas(named:"jet.atlas")

    var spriteArray = Array<SKTexture>();

    

    var monsterSprite = SKSpriteNode();

    

    override func didMoveToView(view: SKView) {

        view.scene!.anchorPoint = CGPoint(x: 0.5,y: 0.5)

        

        spriteArray.append(textureAtlas.textureNamed("sprite1"));

        spriteArray.append(textureAtlas.textureNamed("sprite2"));

        spriteArray.append(textureAtlas.textureNamed("sprite3"));

        spriteArray.append(textureAtlas.textureNamed("sprite4"));

        spriteArray.append(textureAtlas.textureNamed("sprite5"));

        spriteArray.append(textureAtlas.textureNamed("sprite6"));

 

        monsterSprite = SKSpriteNode(texture:spriteArray[0]);

        monsterSprite.position = CGPoint(x:-view.bounds.width/2, y:0)

        monsterSprite.xScale = 2;

        monsterSprite.yScale = 2;

        addChild(self.monsterSprite);

        

 

        let animateAction = SKAction.animateWithTextures(self.spriteArray, timePerFrame: 0.20);

        let moveAction = SKAction.moveBy(CGVector(view.bounds.width,0), duration: 1.4);

        let group = SKAction.group([ animateAction,moveAction]);

        let repeatAction = SKAction.repeatActionForever(group);

        self.monsterSprite.runAction(repeatAction);

    }

    

    override func update(currentTime: NSTimeInterval) {

        if(monsterSprite.position.x > self.view.bounds.width/2){

            monsterSprite.position.x = -self.view.bounds.width/2;

        }

    }

 

}

 

And when you run it:

 

JetAnimation

 

Basically we create our texture atlas like we did before, but instead of creating individual SKSpriteNodes using the atlas, we instead create an array of SKTextures.  We then pass that array of textures, representing each animation frame, to the action animateWithTexture.  The parameter timePerFrame represents how long each individual frame will be shown.  The rest is just a couple more SKActions to make things interesting.  One to move the sprite from the left to the right, one to group the texture animation and move action together, then another action to repeat it forever.

 

As you can see, between TextureAtlas and animateWithTexture, creating animations in SpriteKit is pretty easy.

2. July 2014

 

Now that we’ve tackled the basics of graphics, let’s take a look at making our game “do” something.  This is often the job of SKActions, so let’s jump right in with a simple example.  Just like in the last example I am going to use the basic project structure we established back in the very first post.  All code samples are going to be in the GameScene.

 

 

import SpriteKit

 

class GameScene: SKScene {

    let monkey = SKSpriteNode(imageNamed: "EvilMonkey.png")

    

    override func didMoveToView(view: SKView) {

        let background = SKSpriteNode(imageNamed: "beach.png")

        background.position = CGPoint(x:0,y:0)

        background.anchorPoint = CGPoint(x:0.0,y:0.0)

        background.size = view.bounds.size

 

        monkey.anchorPoint = CGPoint(x:0.5,y:0.5)

        monkey.position = CGPoint(x:view.bounds.midX,y:view.bounds.midY)

        

        self.addChild(background)

        self.addChild(monkey)

    }

    

    override func mouseDown(theEvent: NSEvent!) {

        let action = SKAction.moveTo(

            CGPoint(x:theEvent.locationInWindow.x,y:theEvent.locationInWindow.y),

            duration:2

            );

        monkey.runAction(action)

    }

}

 

Now when you run it, wherever you click the screen, that’s where the monkey will go.  It will move at whatever rate is required to get there in 2 seconds.

Monkey

 

Note, the terrible jerkiness and colour saturation were a side effect of me trying to keep the animated gif small, not because of SpriteKit.

The magic here is of course the SKAction class.  Here we create a moveTo action and pass in the mouse pointer location and the duration of how long we want the action to last.  Finally we assign the action to our sprite using runAction, passing in the action to run.  Spritekit automatically determines how much to update each frame to match the animation to the duration you provided.

 

Here each time you click the mouse you override the current action, causing the last action to stop.  What if we wanted each action to queue up instead?  Let’s find out.

import SpriteKit

 

class GameScene: SKScene {

    let monkey = SKSpriteNode(imageNamed: "EvilMonkey.png")

    var actions = Array<SKAction>();

    

    override func didMoveToView(view: SKView) {

        let background = SKSpriteNode(imageNamed: "beach.png")

        background.position = CGPoint(x:0,y:0)

        background.anchorPoint = CGPoint(x:0.0,y:0.0)

        background.size = view.bounds.size

        

        monkey.anchorPoint = CGPoint(x:0.5,y:0.5)

        monkey.position = CGPoint(x:view.bounds.midX,y:view.bounds.midY)

        

        self.addChild(background)

        self.addChild(monkey)

    }

    

    override func mouseDown(theEvent: NSEvent!) {

        let action = SKAction.moveTo(

            CGPoint(x:theEvent.locationInWindow.x,y:theEvent.locationInWindow.y),

            duration:2

        );

 

        actions.insert(action, atIndex:0);

        

        if(monkey.hasActions() == false){

            monkey.runAction(actions.removeLast(), completion: queueNextActionIfExists);

        }

    }

    

    func queueNextActionIfExists(){

        if(actions.count > 0){

            monkey.runAction(actions.removeLast(), completion: queueNextActionIfExists);

        }

    }

}

 

In this example, the monkey will now follow your clicks after it finishes handling its current action.  So for example if you click 20 times, the monkey is going to move 20 times, taking a total of 40 seconds.  The trick here is the completion callback in runAction.  Basically this is a function that will be called when the current action complete.  In this case, when an action finishes, it checks to see if there are any more actions awaiting, and if there are, runs them.

 

This is a special case example of a completion, as it is recursive.  In many cases you can write more compact code using closures, a feature of most modern languages, including Swift.  Let’s take a look at a closure example for handling completion:

    override func mouseDown(theEvent: NSEvent!) {

        let action = SKAction.moveTo(

            CGPoint(x:theEvent.locationInWindow.x,y:theEvent.locationInWindow.y),

            duration:2

        );

        

        monkey.runAction(action,completion: { () -> Void in

            self.monkey.runAction(SKAction.moveTo(CGPoint(x:0,y:0),duration:2));

            }

        );

    }

 

In this example the completion function is passed in to runAction as an unnamed closure.  In other languages this is often known as an anonymous function.  When run, this will cause the monkey to move to where ever you click, then immediately to the origin once it’s done moving.  Which syntax you prefer is up to you.  Closures are a big part of functional programming, but they are also completely optional in Swift.

 

So far we have looked at performing a series of actions on demand ( as the user clicks, we queue them up ).  However, if you want to run a series of pre-determined actions in sequence, there is a much easier way to accomplish this.  Let’s take a look.

 

import SpriteKit

 

class GameScene: SKScene {

    let monkey = SKSpriteNode(imageNamed: "EvilMonkey.png")

    

    override func didMoveToView(view: SKView) {

        let background = SKSpriteNode(imageNamed: "beach.png")

        background.position = CGPoint(x:0,y:0)

        background.anchorPoint = CGPoint(x:0.0,y:0.0)

        background.size = view.bounds.size

        

        monkey.anchorPoint = CGPoint(x:0.5,y:0.5)

        monkey.position = CGPoint(x:view.bounds.midX,y:view.bounds.midY)

        

        self.addChild(background)

        self.addChild(monkey)

        

        doStuff();

    }

 

    func doStuff(){

        var actions = Array<SKAction>();

        actions.append(SKAction.moveTo(CGPoint(x:300,y:300), duration: 1));

        actions.append(SKAction.rotateByAngle(6.28, duration: 1));

        actions.append(SKAction.moveBy(CGVector(150,0), duration: 1));

        actions.append(SKAction.colorizeWithColor(NSColor.redColor(), colorBlendFactor: 0.5, duration: 1));

        let sequence = SKAction.sequence(actions);

        monkey.runAction(sequence);

    }

}

 

When you run this:

Monkey2

 

It runs each action, predictably enough, in sequence.  A sequence action is simply an array of SKActions that are run back to back.  As you can see there a number of different actions available and many more I haven’t covered here.  What you see in this example is a movement to a certain point, a rotation by an angle ( in radians… 360 degrees ), a moveBy, which is a movement relative to the current position.  Finally a colorize, which is basically tinting the image 50% red.

 

So that’s performing a number of actions in sequence, what if you want to perform then at the same time?  Well, there’s an app… er, Action for that too!

    func doStuff(){

        var actions = Array<SKAction>();

        actions.append(SKAction.moveTo(CGPoint(x:300,y:300), duration: 1));

        actions.append(SKAction.rotateByAngle(6.28, duration: 1));

        actions.append(SKAction.moveBy(CGVector(150,0), duration: 1));

        actions.append(SKAction.colorizeWithColor(NSColor.redColor(), colorBlendFactor: 0.5, duration: 1));

        let group = SKAction.group(actions);

        monkey.runAction(group);

    }

 

The only real difference is we create a group instead of a sequence.  You still create an array of SKActions and add them to the group.  Now when you run it:

Monkey3

 

Finally, this is something a reader wrote in asking me to cover.  Sometimes you want to simply make a sound when a sprite is selected.  This as well is easily accomplished using actions:

 

import SpriteKit

 

class SpriteWithClickSound: SKSpriteNode{

    override func mouseDown(theEvent: NSEvent!) {

        let clickAction = SKAction.playSoundFileNamed("ding.wav", waitForCompletion: true);

        self.runAction(clickAction);

    }

}

 

class GameScene: SKScene {

    let monkey = SpriteWithClickSound(imageNamed: "EvilMonkey.png")

    

    override func didMoveToView(view: SKView) {

        let background = SKSpriteNode(imageNamed: "beach.png")

        background.position = CGPoint(x:0,y:0)

        background.anchorPoint = CGPoint(x:0.0,y:0.0)

        background.size = view.bounds.size

        

        monkey.anchorPoint = CGPoint(x:0.5,y:0.5)

        monkey.position = CGPoint(x:view.bounds.midX,y:view.bounds.midY)

        monkey.userInteractionEnabled = true;

        

        self.addChild(background)

        self.addChild(monkey)

    }

 

}

In this example, when you click on the monkey, the sound ding.wav will be played.  Of course, you will need to add a WAV to your project for this to work properly.  One thing you should notice here is I called userInteractionEnabled on my SKSpriteNode derived object.  If you don’t call this, your node won’t receive events ( like mouseDown for example! ).  The actual action of playing a sound via action is:

let clickAction = SKAction.playSoundFileNamed("ding.wav", waitForCompletion: true);

self.runAction(clickAction);

Most of the code above is about subclassing SKSpriteNode to implement mouseDown. 

One last thing to be aware of before I move on here… Swift does NOT inherit init functions from their parent and frankly this sucks.  I was going to put the call to userInteractionEnabled in SpriteWithClickSound’s init() method.  When I do this, like so:

class SpriteWithClickSound: SKSpriteNode{

    init(imageNamed:String){

        super.init(imageNamed:imageNamed);

        // handle user input on

        self.userInteractionEnabled = true;

    }

}

 

At runtime you will get the very cryptic error:

/Users/Mike/Documents/Projects/SpriteKit/Actions3/Actions3/GameScene.swift: 3: 3: fatal error: use of unimplemented initializer 'init(texture:)' for class 'Actions3.SpriteWithClickSound'


 

This is as I said earlier, because Swift doesn’t inherit init methods ( think constructor if you are coming from C++, C# or Java ) from it’s parent class.  This frankly really sucks, as you then have to either a) provide no init method, in which case the proper init method will be called, or b) implement every bloody init method the class you inherited from.  Take the SKSpriteNode for example, it has 4 init functions, so if you want to implement userInteractionEnabled in the init method, you would have to do it like this:

 

class SpriteWithClickSound: SKSpriteNode{

    init(imageNamed:String){

        super.init(imageNamed:imageNamed);

        // handle user input on

        self.userInteractionEnabled = true;

    }

    init(texture:SKTexture){

        super.init(texture:texture);

        self.userInteractionEnabled = true;

    }

    

    init(color:SKColor,size:CGSize){

        super.init(color:color,size:size);

        self.userInteractionEnabled = true;

    }

    init(texture:SKTexture,color:SKColor,size:CGSize)

    {

        super.init(texture:texture,color:color,size:size);

        self.userInteractionEnabled = true;

    }

    

 

That, is some seriously ugly code!  It was also a complete pain in the ass to write.  The fact it only throws up on runtime is even worse.  Hopefully this is something that get’s fixed in Swift soon.  Until then, basically keep any and all logic out of init methods if you can help it.

26. June 2014

 

Since LibGDX 1.1, there has been a massively improved way of creating a LibGDX project.  This document looks at how you get up and started using the setup application.

 

First thing you have to do is download it.  Head on over to the LibGDX download page and download Setup App.

 

Libgdx1

 

Now that you’ve downloaded the file gdx-setup.jar, double click it and say OK to any security questions.  If it doesn’t load when you double click it, you either don’t have Java installed ( you need a JDK to work with LibGDX ) or your file extensions handling for .java files are broken.  Assuming everything worked correctly the setup app should have loaded.

 

Here is an example I’ve configured already:

Libgdx2

 

One important thing is you need to have the Android SDK installed as well.  Google have made the process rather confusing, as their default download is bundled with Eclipse.  If you are intending to use a different IDE, the download you want is under “Download for other Platforms”, which is an extremely stupid name…  anyways, you need to have the Android SDK ( Android Build Tools version 19.1 as of time of writing, keep in mind you have to configure the Android SDK after downloading it ) installed as you have to provide the path to where you installed it.  

 

Otherwise it’s the usual suspects here, your project name, package and class.  Keep in mind they follow Java variable naming conventions, so for example, no spaces and mostly just alphanumeric characters.  LibGDX version allows you to choose which version of LibGDX to use, although oddly enough in every release there has only ever been the option for the most recent release.

 

In the Sub Projects section, you are deciding what targets you want to support.  If you aren’t on a Mac, iOS will not be an option.  

 

Extensions are where you configure which of the LibGDX extensions you want installed/configured.  Bullet is a physics engine, free type is a font engine, tools give you the various command line tools that are bundled with LibGDX ( I believe ), Controllers is gamepad support, Box2d is a 2D physics engine while Box2dlights is… well I have no idea what that is.

 

Now the part that is of critical importance is “Advanced”.  In all honest I think the “Advanced” options are far more important than the extensions.  I would actually instead suggest making the Setup app a 2 step process and make Advanced a mandatory process.  Anyways enough about my opinions, click advanced!

LibGdx3

 

This is where you pick what kind of IDE you use.  For each you intend to use, tick the checkbox and it will generate the appropriate project files.  In this case I am going to be using IntelliJ IDEA, so I will tick next to IDEA.  The Maven mirror box is probably something you will never use so let’s ignore it.  Offline mode is a bit more difficult to decide.  Basically the project you create will automatically go online and figure out what dependencies your project has and make sure your project is always up to date.  If you aren’t going to have an internet connection reliably or yours is ungodly slow, you may consider ticking Offline Mode.  Otherwise you are probably best served leaving it unticked.  Now click Save.

 

Now back in the Setup app, click Generate:

LibGdx4

 

Now the setup app will churn away for a while, downloading required files and configuring your project. If there is something wrong with your configuration, you will be warned.  On my PC using my cell connection the process took about a minute.  If successful it should look like this:

LibGDX5

 

There is still some configuration to be done for running each project type in your IDE.  I have already covered that process in IntelliJ right here.  You only need to read the last half of that link.

 

Programming ,

Month List

Popular Comments

RIM releases GamePlay 1.4
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


Home > News >

7. August 2012

logo_powered_black

I wrote sometime back about RIM’s open-source Gameplay SDK.  GamePlay is a complete 3D engine that targets Blackberry OS 10/PlayBook OS, Android, iOS, Windows and MacOS X.  They just announced the release of 1.4 and it’s full of some pretty nice additions:

 

New features

  • Lua script bindings on all public interfaces of the framework.
  • Script binding generator tool for creating user-defined Lua script bindings from Doxygen XML.
  • AI state machine for AI programming/scripting on game objects.
  • Virtual gamepad input support with custom theming using UI system.
  • Optimizations using NEON math for mobile platforms.
  • Compressed texture support for DXT, PVRTC, ATC and ETC1.
  • Improved modular shaders with support for #include in shaders and new light map support.
  • Optimizations and Improvements to the UI system such as inertial scrolling and scrollbars.
  • Pre-built versions of the gameplay-encoder and gameplay-luagen tools.
  • Optimizations in animation and physics.
  • Fixes to support Maya 2012/2013 COLLADA DAE_FBX export.
  • FBX 2013 format support.

 

The also announced their roadmap for future versions:

The ‘next’ branch features for v1.5, v1.6, v1.7

  • Linux support.
  • Vehicle physics.
  • AI path finding with navigation meshes.
  • Physical Gamepad input for Xbox 360, Wii, and Bluetooth® HID controllers.
  • Terrain.
  • Scene editor tool.

 

 

You can read the full announcement here or head over here to get started.  Lua scripting is a very nice addition, especially for those that prefer not to work at the C++ level ( include me in that camp! ).  Terrain and scene editing tools will go a long way towards helping adoption.

 

Nice work GamePlay team! 

 

If I could make a suggestion if anyone on the team is listening, I would recommend a rebrand at this point.  Gameplay is an apt name, but it is incredibly generic, meaning that your discoverability is going to be abysmal.  You’ve created a great product here, it would be a shame that people didn’t use it simply because they couldn’t find it!  Just adding a second word the next name (Gameplay NEXT GameplayGO Gameplay-A-GoGo) would help a ton and allow you to keep your existing documentation, website, etc… unchanged.

News ,

blog comments powered by Disqus

Month List

Popular Comments