Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

22. June 2014

 

Title kinda says it all, LibGDX 1.2 was released today.  The update includes:

 

 

I don’t think the breaking changes will impact any of our tutorial series.  Interesting to see the new AI extension, will be nice to see how that develops ( A* next? ).  Improved IntelliJ build times are certainly welcome.  You can get started here.

News ,

18. June 2014

This press release crossed my virtual desk today:


Autodesk Announces Maya LT 2015 Extension 1

Today Autodesk announced the first extension release for Maya LT 2015. The update enhances the animation experience for professional indie game makers by allowing artists to create more elaborate characters and environmental objects. The animation export tool gives artists a completely new method of exporting multiple animations per FBX file, making it easier to get animated content into a game engine, while set driven key and utility nodes help artists better control the relationships between objects in a scene.

New features include:
-- Game Exporter: simplifies how models and animations are exported from Maya LT for use in game engines, allowing artists to define their ideal export settings and have them saved the next time the file is opened. Artists can define multiple animation clips within the tool by giving each a name along with a start and stop frame.
-- Added Set Driven Key: gives artists an easier way to link animations in one scene. For example, having one character jump, while another ducks, simultaneously. Set Driven Key also improves interoperability with certain auto-rigging tools, making it easier for Maya LT users to leverage those tools to create their character rigs.
-- Rigging Utility Nodes: New utility nodes in Maya LT let artists finely tweak and adjust their character rigs and animations in the node editor, giving riggers and animators better control over character animations. The new utility nodes also make it easier for artists to use auto-generated character rigs.

The extension for Maya LT will be available today for all current monthly and perpetual customers.

 

MayaLT RiggingUtilityNodes 1920x1080

 

Remember a few weeks back Autodesk reduced the price to Maya LT from $50/month to $30/month.  As someone who has gotten used to it in Blender, the ability to create and name multiple animation in a scene is a great addition ( and long overdue ).  Frankly anything that makes rigging easier is always welcome by me.

 

It’s nice to see constant updates instead of annual releases, I hope this is a trend that continues.

18. June 2014

 

In this part we are going to look at how to add animations to a TileMap in LibGDX.  Along the way we are going to look at using Properties a very important part of using Tile maps, as properties contain your games “data”.  First let’s take a look at setting properties in Tiled.  I am adding a second Tileset to my existing map called “Water” using the following graphic I download from Google Images.  Tiled doesn’t support animations, so we are going to hack support in using properties.

 

WaterTiles

 

You can get more details on working with Tiled here.

 

Properties are set in the Tile, not the Cell in TileEd.  Load the above image as a new Tileset in Tiled named Water.  We are working with just 3 of the water tiles:

Te1

 

Right click on a tile and select Tile Properties...

Te2

Now we want to set a property “Water Frame” and give it the value of 1.

Te3

 

Now repeat for the next two water tiles, with the values 2 and 3 respectively.

 

In addition to Tile properties, you can also set properties at the Layer and Map level.  Properties are just a name value pair of strings when imported into LibGDX.  Let’s take a look at that process now.

 

Save your tiled map and add it to the assets folder of your project.  Also add all the various texture maps used for tiles.  Let’s look at some ( heavily commented ) code that builds on our earlier tile map example:

package com.gamefromscratch;

 

import com.badlogic.gdx.ApplicationAdapter;

import com.badlogic.gdx.Gdx;

import com.badlogic.gdx.Input;

import com.badlogic.gdx.InputProcessor;

import com.badlogic.gdx.graphics.GL20;

import com.badlogic.gdx.graphics.OrthographicCamera;

import com.badlogic.gdx.graphics.Texture;

import com.badlogic.gdx.graphics.g2d.Sprite;

import com.badlogic.gdx.graphics.g2d.SpriteBatch;

import com.badlogic.gdx.maps.tiled.*;

import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;

import java.util.*;

 

public class TiledTest extends ApplicationAdapter implements InputProcessor {

    Texture img;

    TiledMap tiledMap;

    OrthographicCamera camera;

    TiledMapRenderer tiledMapRenderer;

    SpriteBatch sb;

    Texture texture;

    Sprite sprite;

    ArrayList<TiledMapTileLayer.Cell> waterCellsInScene;

    Map<String,TiledMapTile> waterTiles;

    floatelapsedSinceAnimation = 0.0f;

 

    @Override public void create () {

        float w = Gdx.graphics.getWidth();

        float h = Gdx.graphics.getHeight();

 

        camera = new OrthographicCamera();

        camera.setToOrtho(false,w,h);

        // Position the camera over 100pixels and up 400 to capture more interesting part of map

        camera.translate(100,400);

        camera.update();

        //Load our tile map

        tiledMap = new TmxMapLoader().load("MyCrappyMap.tmx");

 

        tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap);

        Gdx.input.setInputProcessor(this);

 

        // We created a second set of tiles for Water animations

        // For the record, this is bad for performance, use a single tileset if you can help it

        // Get a reference to the tileset named "Water"

        TiledMapTileSet tileset =  tiledMap.getTileSets().getTileSet("Water");

 

 

        // Now we are going to loop through all of the tiles in the Water tileset

        // and get any TiledMapTile with the property "WaterFrame" set

        // We then store it in a map with the frame as the key and the Tile as the value

        waterTiles = new HashMap<String,TiledMapTile>();

        for(TiledMapTile tile:tileset){

             Object property = tile.getProperties().get("WaterFrame");

            if(property != null)

                waterTiles.put((String)property,tile);

        }

 

        // Now we want to get a reference to every single cell ( Tile instance ) in the map

        // that refers to a water cell.  Loop through the entire world, checking if a cell's tile

        // contains the WaterFrame property.  If it does, add to the waterCellsInScene array

        // Note, this only pays attention to the very first layer of tiles.

        // If you want to support animation across multiple layers you will have to loop through each

        waterCellsInScene = new ArrayList<TiledMapTileLayer.Cell>();

        TiledMapTileLayer layer = (TiledMapTileLayer) tiledMap.getLayers().get(0);

        for(int x = 0; x < layer.getWidth();x++){

            for(int y = 0; y < layer.getHeight();y++){

                TiledMapTileLayer.Cell cell = layer.getCell(x,y);

                Object property = cell.getTile().getProperties().get("WaterFrame");

                if(property != null){

                    waterCellsInScene.add(cell);

                }

            }

        }

    }

 

    @Override public void render () {

        Gdx.gl.glClearColor(1, 0, 0, 1);

        Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);

        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        camera.update();

        tiledMapRenderer.setView(camera);

        tiledMapRenderer.render();

 

        // Wait for half a second to elapse then call updateWaterAnimations

        // This could certainly be handled using an Action if you are using Scene2D

        elapsedSinceAnimation += Gdx.graphics.getDeltaTime();

        if(elapsedSinceAnimation > 0.5f){

            updateWaterAnimations();

            elapsedSinceAnimation = 0.0f;

        }

    }

 

    // This is the function called every half a second to update the animated water tiles

    // Loop through all of the cells containing water.  Find the current frame and increment it

    // then update the cell's tile accordingly

    // NOTE!  This code depends on WaterFrame values being sequential in Tiled

    private void updateWaterAnimations(){

        for(TiledMapTileLayer.Cell cell : waterCellsInScene){

            String property = (String) cell.getTile().getProperties().get("WaterFrame");

            Integer currentAnimationFrame = Integer.parseInt(property);

 

            currentAnimationFrame++;

            if(currentAnimationFrame > waterTiles.size())

                currentAnimationFrame = 1;

 

            TiledMapTile newTile = waterTiles.get(currentAnimationFrame.toString());

            cell.setTile(newTile);

        }

    }

 

    @Override public boolean keyDown(int keycode) {

        return false;

    }

 

    @Override public boolean keyUp(int keycode) {

        if(keycode == Input.Keys.LEFT)

            camera.translate(-32,0);

        if(keycode == Input.Keys.RIGHT)

            camera.translate(32,0);

        if(keycode == Input.Keys.UP)

            camera.translate(0,-32);

        if(keycode == Input.Keys.DOWN)

            camera.translate(0,32);

        if(keycode == Input.Keys.NUM_1)

            tiledMap.getLayers().get(0).setVisible(!tiledMap.getLayers().get(0).isVisible());

        if(keycode == Input.Keys.NUM_2)

            tiledMap.getLayers().get(1).setVisible(!tiledMap.getLayers().get(1).isVisible());

        return false;

    }

 

    @Override public boolean keyTyped(char character) {

 

        return false;

    }

 

    @Override public boolean touchDown(int screenX, int screenY, int pointer, int button) {

        return false;

    }

 

    @Override public boolean touchUp(int screenX, int screenY, int pointer, int button) {

        return false;

    }

 

    @Override public boolean touchDragged(int screenX, int screenY, int pointer) {

        return false;

    }

 

    @Override public boolean mouseMoved(int screenX, int screenY) {

        return false;

    }

 

    @Override public boolean scrolled(int amount) {

        return false;

    }

}

Basically what we do is load our map, then we loop through the “Water” tile set and grab a reference to any tile marked as a Waterframe.  We then perform the same action, looping through all of the cells in our map ( on the first layer! ) and if the cells tile has a reference to a tile that has the Waterframe property defined.  Then every half a second we update each cell to the next available frame of animation, or loop back to the first frame if none are available.

 

Now if you run this code, voila!  Animated water:

Te4

 

In this case we manually updated tiles in the map.  LibGDX does however present another option.  They have recently added an Animated tile class.  That said, this functionality is very new so warning ,there be dragons.  In fact, I didn’t find a single implementation online, so this may in fact be the first!

 

Here is a code example using AnimatedTiledMapTile to achieve the same effect:

 

package com.gamefromscratch;

 

import com.badlogic.gdx.ApplicationAdapter;

import com.badlogic.gdx.Gdx;

import com.badlogic.gdx.graphics.GL20;

import com.badlogic.gdx.graphics.OrthographicCamera;

import com.badlogic.gdx.graphics.Texture;

import com.badlogic.gdx.graphics.g2d.Sprite;

import com.badlogic.gdx.graphics.g2d.SpriteBatch;

import com.badlogic.gdx.maps.tiled.*;

import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;

import com.badlogic.gdx.maps.tiled.tiles.AnimatedTiledMapTile;

import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile;

import com.badlogic.gdx.utils.Array;

 

public class TiledTest extends ApplicationAdapter{

    Texture img;

    TiledMap tiledMap;

    OrthographicCamera camera;

    TiledMapRenderer tiledMapRenderer;

    SpriteBatch sb;

    Texture texture;

    Sprite sprite;

    Array<AnimatedTiledMapTile> waterTilesInScene;

    Array<StaticTiledMapTile> waterTiles;

    floatelapsedSinceAnimation = 0.0f;

 

    @Override public void create () {

        float w = Gdx.graphics.getWidth();

        float h = Gdx.graphics.getHeight();

 

        camera = new OrthographicCamera();

        camera.setToOrtho(false,w,h);

        camera.translate(100,400);

        camera.update();

        tiledMap = new TmxMapLoader().load("MyCrappyMap.tmx");

 

        tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap);

 

        TiledMapTileSet tileset =  tiledMap.getTileSets().getTileSet("Water");

 

        waterTiles = new Array<StaticTiledMapTile>();

        for(TiledMapTile tile:tileset){

            Object property = tile.getProperties().get("WaterFrame");

            if(property != null) {

                waterTiles.add(new StaticTiledMapTile(tile.getTextureRegion()));

            }

        }

 

        waterTilesInScene = new Array<AnimatedTiledMapTile>();

 

        TiledMapTileLayer layer = (TiledMapTileLayer) tiledMap.getLayers().get(0);

        for(int x = 0; x < layer.getWidth();x++){

            for(int y = 0; y < layer.getHeight();y++){

                TiledMapTileLayer.Cell cell = layer.getCell(x,y);

                Object property = cell.getTile().getProperties().get("WaterFrame");

                if(property != null){

                    cell.setTile(new AnimatedTiledMapTile(0.5f,waterTiles));

                }

            }

        }

 

    }

 

    @Override public void render () {

        Gdx.gl.glClearColor(1, 0, 0, 1);

        Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);

        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        camera.update();

        tiledMapRenderer.setView(camera);

        tiledMapRenderer.render();

    }

}

 

Ultimately the logic is very similar.  Here however we actually replace the tile type of for each water instance we find in our map with a AnimatedTiledMapTile.  It is passed an interval to update ( 0.5 second again ) as well as an array of tiles to use as part of the animation.  The logic is basically identical, you just have slightly less control and no longer have to handle the updating on your own!

16. June 2014

 

In the previous tutorial part we looked at working with a single Sprite.  Reality is, very few games are composed of singular sprites.  UI’s are made up of a number of different sprites, animations are composed of several different frames, each composed of a single image.  Loading hundreds of individual textures is not good for performance.  A very common solution is to use a texture atlas ( or sprite sheet ).  Fortunately Xcode make it extremely easy.

 

We are going to use the same sprite we did in the previous tutorial, you can download it here.  As you can see, it’s actually a zip file containing a number of png images:

Ta1

 

Extract the zip file and rename it jet.atlas.

Now in Xcode, in Project Navigator, right click your project and select Add to Project

Ta2

 

Select the directory ( not the files ) and click add.  Defaults should be ok, but make sure it’s set to copy.

Ta3

 

And you are done.  The following code:

import SpriteKit

 

class GameScene: SKScene {

    

    override func didMoveToView(view: SKView) {

        var sprite = SKSpriteNode(imageNamed:"sprite4")

        sprite.xScale = 4

        sprite.yScale = 4

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

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

        self.addChild(sprite)

    }

    

}

 

Will load the sprite from the Atlas that had the file name “sprite4.png”.  NOTE HOWEVER, if you add an image named sprite4 to your project, it will be loaded instead of the Texture Atlas.

 

So, what exactly did Xcode do?  We behind the scenes, it went ahead an combined all of your images together into a single OpenGL optimized image, and created a reference file telling SpriteKit how to access it.  Let’s take a look at the results.

 

First, build your game.  Select Product->Build For->Running

Ta4

 

You should now have a Products folder in your project.  Right click the .app file for your project and select Show in Finder:

Ta5

 

Now right click the .app file and select Show Package Contents:

Ta6

 

Navigate into contents->resources->jet.atlasc and you will see two files, one is an image, the other a plist.  Let’s look at the image first:

 

Jet 1

 

That’s out images smash together in a power of 2 friendly texture that your GPU can handle efficiently.  The plist file:

Ta7

 

This plist shows SpriteKit how to access each individual image within the larger image.  To you however the process is pretty transparent.  Basically group all common images together in a directory.  Give the directory a .atlas name and add it to your project, then access each image as you would normally.

 

Sometimes however you may want to access the TextureAtlas itself.  You can do that as well, let’s take a look at how:

import SpriteKit

 

class GameScene: SKScene {

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

    var currentTexture:Int = 1;

    

    override func didMoveToView(view: SKView) {

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

        

        let sprite=SKSpriteNode(texture:textureAtlas.textureNamed("sprite1"))

        sprite.xScale = 8

        sprite.yScale = 8

        self.addChild(sprite)

    }

    

    override func keyDown(theEvent: NSEvent!) {

        // On any key press move to the next texture

        var sprite = self.scene.children[0] asSKSpriteNode

 

        switch currentTexture {

            case 1:

                sprite.texture = textureAtlas.textureNamed("sprite2")

            case 2:

                sprite.texture = textureAtlas.textureNamed("sprite3")

            case 3:

                sprite.texture = textureAtlas.textureNamed("sprite1")

            default:

                break

        }

        ++currentTexture

        if(currentTexture > 3) {

            currentTexture = 1

        }

    }

}

 

Now run it, and each time you press a key it will advance to the next frame.

 

 

 

First let me stop right here and make one thing perfectly clear… THIS IS NOT HOW YOU DO ANIMATION! :)  We will cover animation later. This was just a small code segment to illustrate how to access a TextureAtlas directly.  

 

As you can see, it’s as simple a matter as creating an SKTextureAtlas and passing in the file name.  You can then access each individual SKTexture within the atlas using textureNamed passing in the file name you used for the original image in the atlas directory.  As you can see, you do not need to pass in the file extension.  Here we see a Swift switch statement in action.  Switch statements are important to Swift and quite capable.  You can switch on Ints like we have done here, but you can also use strings. It is tempting to use the sprite name here, but an important thing to realize is the SKSprite name is NOT the same as the SKTexture name.  Unless you manually name the sprite, it will be nil.  Unlike C++, case statements in Swift do not fall through, so you do not need to provide a break statement for each case.  However, there are two caveats to be aware of.  First, every single possible value must be handled.  If you don’t want to handle every possible value you can provide a default handler which will catch everything else.  However each case ( even default ) must contain at least one executable statement, thus the break in default.  This only scratches the surface of switch… you can also specify multiple values in a case using commas, provide ranges using the .. and … operators, etc.

 

That’s it for TextureAtlases, on to the next part!

, ,

13. June 2014

 

As you can imagine by the name “SpriteKit”, Sprites are a pretty core part of creating a game using SpriteKit.  We are going to continue building on the minimal application we created in the previous part.  I want to point out, this isn’t the recommended way of working with SpriteKit, it is instead the simplest way.  In a proper application we would be more data driven and store our data in SKS files instead of simply adding them to the project.  This is something we will cover later on.  First lets jump right in with code.

 

We are going to replace the the class GameScene we created in the last tutorial.  In SpriteKit, the fundamentals of your game are organized into SKScene objects.  For now we only have one.  Let’s look:

 

import SpriteKit

 

class GameScene: SKScene {

        let sprite = SKSpriteNode(imageNamed: "sprite1.png")

    

    override func didMoveToView(view: SKView) {

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

        sprite.xScale = 4

        sprite.yScale = 4

        self.addChild(sprite)

    }

    

    override func mouseDown(theEvent: NSEvent!) {

        self.sprite.position = CGPoint(x:theEvent.locationInWindow.x,y:theEvent.locationInWindow.y)

    }

}

 

We add the sprite “sprite1.png” to our project directory, simply drag and drop it from Finder.  The sprite(s) ill be using are from the zip file available here.  When you run this code, click anywhere and you should see:

 

Sd1

 

Where ever you click the mouse, the sprite will be drawn.

One immediate change you will notice in this code is sprite was moved out of didMoveToView and made a member variable.  This allows us to access sprite in different functions ( although we could retrieve the sprite from the Scene, something we will see later ). In Swift there are only two main ways of declaring a variable, let and var.  var is a variable meaning it’s value can change.  Using let on the other hand you are declaring a the the value cannot change, this is the same as a const in other languages.  As we touched on briefly in the last part, a let declared value can be assigned later using the ? postfix operator.  In this case, it will have the value of nil at initialization, unless one is specifically given like in the code we just did.  One thing you may notice is, unlike C++, C# and Java, Swift currently has no access modifiers.  In other words all variables are publicly available ( there are no private, internal, protected, etc modifiers available ).  Apparently this is only temporary and will be changed in the language later.  This personally seems like a very odd thing not to have in a language from day one.

Since we set the sprite’s anchor to the middle (0.5,0.5), the sprite will be centred to your mouse cursor.  As you can see we added a mouseDown event handler.  This class is available because SKScene inherits UIResponder, this is how you handle I/O events in your scene.  The only other new aspect to this code is:

        sprite.xScale = 4

        sprite.yScale = 4

 

 

This code causes the sprite to be scaled by a factor of 4x.  We do this simply because our source sprite was only 64x64 pixels, making it really really tiny in an empty scene!  As you can see, scaling sprites in SpriteKit is extremely easy.

 

The structure of a SpriteKit game is actually quite simple.  Your SKScene contains a graph of SKNodes, of which SKSpriteNode is one.  There are others too including SKVideoNode, SKLabelNode, SKShapeNode, SKEmitterNode and SKEffectNode.  Even SKScene itself is a SKNode, which is how all the magic happens.  Let’s take a quick look at an SKLabelNode in action.

 

import SpriteKit

 

class GameScene: SKScene {

    

    override func didMoveToView(view: SKView) {

        var label = SKLabelNode();

        label.text = "Hello World"

        label.fontSize = 128

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

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

        self.addChild(label)

    }

    

}

Which predictably enough gives you:

Sd2

 

These nodes however can be parented to make hierarchies of nodes.  Take for example a combination of the two we’ve seen, our sprite node with a text label parented to it.

import SpriteKit

 

class GameScene: SKScene {

    

    override func didMoveToView(view: SKView) {

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

        

        var sprite = SKSpriteNode(imageNamed:"sprite1.png")

        sprite.position = CGPoint(x:100,y:0);

        sprite.xScale = 4.0

        sprite.yScale = 4.0

        

        var label = SKLabelNode();

        label.text = "Jet Sprite"

        label.fontSize = 12

        label.position = CGPoint(x:0,y: 15)

        label.fontColor = NSColor.redColor()

        label.alpha = 0.5

 

        

        sprite.addChild(label)

        

        self.addChild(sprite)

    }

    

}

 

And when you run it:

Sd3

 

There are a few things to notice here.  Each Node get’s its default coordinates from it’s parents.  Since the jet sprite is parented to the scene and the scene’s anchor is set to the middle of the screen, when we position the screen 100 pixels to the right, that’s 100 pixels to the right of the centre of the screen.  Additionally, the text label is positioned relative to the sprite, so it’s positioning is relative to the sprite.  Another thing you might notice is the text is blurry as hell.  That is because the label is inheriting the scaling from it’s parent, the sprite.  As you can see you compose your scene by creating a hierarchy of various types of nodes.  Now if we were to transform the parent sprite, all the transformations will apply to the child nodes.

 

The following example shows how transforming a parent node effects all child nodes.  Spoilers, it also shows you how to Update a Scene… we will cover this in more detail later, so don’t pay too much attention to the man behind the curtain.

import SpriteKit

 

class GameScene: SKScene {

    

    var sprite = SKSpriteNode(imageNamed:"sprite1.png")

    override func didMoveToView(view: SKView) {

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

        

        sprite.position = CGPoint(x:0,y:0);

        sprite.xScale = 8.0

        sprite.yScale = 8.0

        

        var label = SKLabelNode();

        label.text = "Jet Sprite"

        label.fontSize = 12

        label.position = CGPoint(x:0,y: 15)

        label.fontColor = NSColor.redColor()

        label.alpha = 0.5

 

        

        sprite.addChild(label)

        

        self.addChild(sprite)

    }

    

    override func update(currentTime: NSTimeInterval) {

        if(sprite.yScale > 0) {

            sprite.yScale -= 0.1

            sprite.xScale -= 0.1

        }

        else {

            sprite.xScale = 8.0

            sprite.yScale = 8.0

        }

    }

    

}

 

Now if we run this code:

 

 

Each time update() is called, the sprite is reduced in scaling until it disappears, at which point it’s zoomed back to 8x scaling.  As you can see, the child labelNode is scaled as well automatically.

 

Notice how until this point if we wanted to access our sprite across functions we had to make it a member variable?  As I said earlier, there is another option here, you name your nodes and retrieve them later using that name.  Like so:

 

import SpriteKit

 

class GameScene: SKScene {

    

 

    override func didMoveToView(view: SKView) {

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

        var sprite = SKSpriteNode(imageNamed:"sprite1.png")

        

        sprite.name = "MyJetSprite"

        sprite.position = CGPoint(x:0,y:0);

        sprite.xScale = 4.0

        sprite.yScale = 4.0

        

        self.addChild(sprite)

    }

    

    override func update(currentTime: NSTimeInterval) {

        var sprite = self.childNodeWithName("MyJetSprite");

        if(sprite != nil){

            if(sprite.yScale > 0) {

                sprite.yScale -= 0.1

                sprite.xScale -= 0.1

            }

            else {

                sprite.xScale = 8.0

                sprite.yScale = 8.0

            }

        }

    }

    

}

You can perform some pretty advanced searches, such as searching recursively through the tree by prefixing your name with “//“.  You can also search for patterns and receive multiple results.  We will look at this in more details later.

 

This part is starting to get a bit long so I am going to stop now.  The next part will look at more efficient ways of using Sprites, such as using an Atlas, as well as look at basic animation and whatever else I think to cover!

 

Continue to Part 3

,

Month List

Popular Comments

Get Marmalade Community free for one year
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


Home > >

19. March 2014

Today from GDC, Marmalade are offering their flagship product, um… Marmalade Community Edition free for a year.  Normally Marmalade Community is priced at $150 a year.

 

So, what exactly is Marmalade?  Its a cross platform, mobile oriented C++ game framework (although Obj-C, Lua and HTML5 are options).  In their own words:

Marmalade gives you the full power of C++ - whether you’re coding for one platform or many. Perhaps even more importantly, Marmalade means you can concentrate on simply making your game the best it can be, rather than getting distracted by the mechanics of going cross-platform. Enjoy performance, openness, flexibility and great low-level access – with Marmalade.

 

Marmalade is one of the most popular mobile gaming SDKs and has been used for a number of high profile mobile titles such as Plants Vs Zombies and Call of Duty: World at War Zombies.  You can see a number of titles made with Marmalade here.

 

So what are the limitations of Marmalade Community Edition.  There are a couple:

  • only able to target iOS and Android ( not BlackBerry, Tizen or Windows Phone 8, Desktop or various devices like smart TVs )
  • show a Made with Marmalade splash screen
  • 3 seats per organization maximum
  • maximum annual revenue of $500,000

 

 If you are interested in signing up you can do so here using the promo code GDCFREE mentioned in this tweet.

blog comments powered by Disqus

Month List

Popular Comments