Game development tutorial: Swift and SpriteKit - Part 5 Sprite Animation

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.





Game development tutorial: Swift and SpriteKit - Part 4 Actions

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.





LibGDX project setup using the Gradle application

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 ,





Adventures in Phaser with TypeScript–Handling Keyboard Input

24. June 2014

 

 

In the previous part we looked at handling graphics in Phaser, now we are going to look at handling input.  This part is going to be code heavy and fairly light on description.  Look to the code comments for more details.

As is pretty common with game frameworks, there are a number of different ways to handle input and a number of different devices, so lets get started!

 

Using the cursor keys and polling for input

 

/// <reference path="phaser.d.ts"/>

// Demonstrate the use of arrow keys in a Phaser app
// This application demonstrates creation of a Cursor and polling for input
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;
    cursors: Phaser.CursorKeys;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload,
        update: this.update});
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        // create the cursor key object
        this.cursors = this.game.input.keyboard.createCursorKeys();
    }

    update() {
        // Update input state
        this.game.input.update();

        // Check each of the arrow keys and move accordingly
        // If the Ctrl Key + Left or Right arrow are pressed, move at a greater rate
        if (this.cursors.down.isDown)
            this.jetSprite.position.y++;
        if (this.cursors.up.isDown)
            this.jetSprite.position.y--;
        if (this.cursors.left.isDown) {
            if (this.cursors.left.ctrlKey)
                this.jetSprite.position.x -= 5;
            else
                this.jetSprite.position.x--;
        }
        if (this.cursors.right.isDown) {
            if (this.cursors.right.ctrlKey)
                this.jetSprite.position.x += 5;
            else
                this.jetSprite.position.x++;
        }
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

When you run this code the familiar jet sprite is rendered centered to the canvas. You can then use the arrow keys to move the fighter around.  As you can see, in the state for each key is information on modifier keys like Control and Alt.  Polling for input ( that is, checking status each call to update ) is a valid way of controlling a game, but sometimes you instead want to respond to input as it arrives.  Let’s look now at an example of event driven keyboard handling:

 

/// <reference path="phaser.d.ts"/>

// Demonstrate keyboard input handling via callback
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;
    W: Phaser.Key;
    A: Phaser.Key;
    S: Phaser.Key;
    D: Phaser.Key;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload
        });
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    moveLeft() {
        this.jetSprite.position.add(-1, 0);
    }
    moveRight() {
        this.jetSprite.position.add(1, 0);
    }
    moveUp(e: KeyboardEvent) {
        // As you can see the event handler is passed an optional event KeyboardEvent
        // This contains additional information about the key, including the Control
        // key status.
        // Basically if the control key is held, we move up or down by 5 instead of 1
        if (e.ctrlKey) 
            this.jetSprite.position.add(0, -5);
        else
            this.jetSprite.position.add(0, -1);
    }
    moveDown(e: KeyboardEvent) {
        if (e.ctrlKey)
            this.jetSprite.position.add(0, 1);
        else
            this.jetSprite.position.add(0, 1);
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        // Create a key for each WASD key
        this.W = this.game.input.keyboard.addKey(Phaser.Keyboard.W);
        this.A = this.game.input.keyboard.addKey(Phaser.Keyboard.A);
        this.S = this.game.input.keyboard.addKey(Phaser.Keyboard.S);
        this.D = this.game.input.keyboard.addKey(Phaser.Keyboard.D);

        // Since we are allowing the combination of CTRL+W, which is a shortcut for close window
        // we need to trap all handling of the W key and make sure it doesnt get handled by 
        // the browser.  
        // Unfortunately you can no longer capture the CTRL+W key combination in Google Chrome
        // except in "Application Mode" because apparently Google thought an unstoppable un prompted
        // key combo of death was a good idea...
        this.game.input.keyboard.addKeyCapture(Phaser.Keyboard.W);

        // Wire up an event handler for each K.  The handler is a Phaser.Signal attached to the Key Object
        this.W.onDown.add(SimpleGame.prototype.moveUp, this);
        this.A.onDown.add(SimpleGame.prototype.moveLeft, this);
        this.S.onDown.add(SimpleGame.prototype.moveDown, this);
        this.D.onDown.add(SimpleGame.prototype.moveRight, this);
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

As you can see, you can also create Phaser.Key objects and attach onDown event handlers ( technically Signals ) to each.  Of course you can reuse the same handler for multiple keys.  A couple key things to notice here… unlike the previous example, holding down a key will not cause continuous movement.  You must press and release the key over and over.  If you want constant movement, either use a polling method, use and action instead of updating each frame, or add some logic to move until the key is released.

 

The other thing to be aware of here is the use of the CTRL+W combination and addKeyCapture().  addKeyCapture() allows you to prevent the event from bubbling up, so once you’ve handled the key combination, it’s done.  Otherwise it would keep being passed up, either to other objects in the scene, or to the browser itself.  You can also use addKeyCapture to prevent default web behavior, such as scrolling when SPACE is pressed.

 

Programming , , , ,





Unity for PlayStation Mobile released and PlayStation Mobile 2.0 SDK released

23. June 2014

 

Thanks to a tip from a reader David I have become aware of the release for PlayStation Mobile and it’s completely free.  Here’s the details from the Unity Blog post.

 

Following hot on the heels of the PlayStation®Mobile (PSM) public preview, we’re proud to announce the full official release of the Unity for PSM build. Hurrah!

Tell me it’s free

Yep, the extremely good news is that, for the first time ever, anyone on the PSM Developer Program can publish their Unity content to PlayStation®Store and target PlayStation®Vita (PS Vita) completely free of charge.

There’s no dev kit; there are no fees. What’s more, the PSM build option works with both the free version of Unity and Unity Pro so developing and deploying your PS Vita game need never cost you a dime.

What do I get?

Amongst other things, the Unity for PSM build option features In-App Purchase APIs, so it’s easy to bring free-to-play content to the PlayStation®Store. Plus, you can use the Unity for PSM build option to distribute to the new entertainment system from Sony Computer Entertainment Inc. (SCE): PlayStation®TV.

If you’ve already downloaded the public preview, you’ll also notice that we’ve been busy fixing bugs, boosting performance and adding on-device script debugging.

Sounds cool, how do I get hold of it?

Download a dedicated version of the Unity engine with the PSM build option here (we’ll be integrating it in the Unity product cycle A.S.A.P.). Note that to deploy to PSM you have to register with SCE – it’s quick and simple. The PSM build option is only available for the Windows version of Unity.

How does PSM deployment differ from Unity’s PS Vita build option?

The PSM build option is designed to provide quick, simple and free access for development on a standard retail PS Vita. Unity’s existing PS Vita build option, on the other hand, gives you full native access to PS Vita and full access to PSN. As part of your PS Vita dev kit, you also get a comprehensive suite of performance and native debugging tools, Visual Studio integration and Razor CPU/GPU performance tools.

Why target PS Vita?

If you’re thinking about making the leap to console development, targeting PS Vita is a great way to familiarize yourself with PlayStation® controls and conventions. What’s more, porting your existing mobile games to PS Vita is extremely easy!

 

Also from Sony we heard that PlayStation Mobile SDK v 2.0 was released:

 

Image

The official versions of "Unity for PSM" and "PSM SDK 2.0" are now available!
Publish your unique and innovative games and applications!

The official versions of "Unity for PSM" and "PSM SDK 2.0" are now available!
Submission of master packages deployed by the new SDKs has been enabled.

The official version of "Unity for PSM"

We have fixed bugs according to your feedback from the Public Preview to release the official version of "Unity for PSM".
Many thanks for your cooperation!

Here are the differences between the official version and the Public Preview.

  • Added functions to create and submit master packages.
  • Settings to publish PlayStation®TV compatible applications has been enabled.
  • Enabled to use "rear touch pad" feature in your games / applications.

Please refer to the FAQ Unity for PSM Overview for how to set up development environments and the development Flow.

PSM SDK 2.0

"PSM SDK 2.0" is exclusive for PS Vita and was made based on PSM SDK 1.20. PlayStation®TV is also supported with PSM SDK 2.0.

Main differences between "PSM SDK 2.0" and "PSM SDK 1.2" are as below.

  • Enabled to use "rear touch pad" feature in your games / applications.
  • Compressed textures are available.
  • Increased available memory (resource heap memory: 96MiB, graphics memory: 96MiB).

PlayStation®TV with PSM SDK 1.2

An updated version of PSM Publishing Utility is now available for PSM SDK 1.2.
It enables you to publish PSM Applications developed by PSM SDK 1.2 to PlayStation®TV.
Download the update zip package from SDK 1.21.02 tab on the PSM SDK download page .

Please also refer to Comparison between Unity for PSM and PSM SDKs for detailed explanation of the differences.

"PSM Application Development Guidelines" have been updated

With the release of new SDKs, we have updated the "PSM Application Development Guidelines".
https://psm.playstation.net/static/general/all/en/development_guidelines.html

The major changes/modifications are as below:

  • Added requirements for PlayStation®TV support.
  • As PSM Applications developed with "Unity for PSM" and "PSM SDK 2.0" will be distributed to PS Vita store (and as optional to PS Vita TV store) exclusively, some requirements were omitted for those SDKs.
  • Some of the restrictions regarding Networking feature were removed.

 

I’m guessing there are a few things confusing here as the branding is getting a bit muddled at this point, I’ll try to address what I can.

 

First off… what’s the difference between Unity for PlayStation Mobile vs Unity for PS Vita?

Well the most obvious difference is Unity for Vita requires a PlayStation license and developer kit and gives full access to the device.  Unity for PSM on the other hand is completely free and requires only a PSM developer license ( currently free ) and will work on commercial hardware.  The limitations however I am currently unaware of.  Presumably Unity for PSM has the same hardware constraints as PSM 2.

 

What is the difference between PSM SDK and Unity for PlayStation Mobile?

They are completely different things.  PSM for Unity is an additional target for the Unity development environment.  PSM on the other hand is a C# based game development kit similar to XNA.

 

What happened to PSM for Android support?

My guess is they put a bullet in it.  The increased memory constraints is a sure sign of that.  The sad part is, it was the requirement to support ancient phones that handicapped PSM in the first place.

 

Can you recommend a good book for PlayStation Mobile programming?

Why yes, yes I can, one written by yours truly. :)  Of course there is a tutorial series here.  It was written for 1.0 SDK but sadly, not all that much has changed.

News ,





Month List

DisqusCommentsSummary