Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
11. March 2015

 

Copperlicht, a somewhat recently open sourced WebGL game engine has just released version 1.9.

 

Release notes are, shall we say…  terse.  Here they are in the entirity from the Copperlicht forums.

 

Hi,
CopperLicht 1.9 is now available for download. Get it here:
http://www.ambiera.com/copperlic...


Added support for realtime reflecting water surfaces, rendering to textures, inverting the depth test, shader callbacks, pointer lock, and more clearly rendered 2D Overlays.



Have fun with it!

 

Although the archive itself has slightly more detailed release notes:

 

---------------------------------------------
CopperLicht 1.9
---------------------------------------------

- Added realtime reflecting water surfaces.
  There is now a special scene node which renders water surfaces, which can be used to create rivers,
  lakes, and oceans. It is highly configurable, so it can be used to create various,
  realistic looking water surfaces.
 
- Added support for rendering to textures.
  See CL3D.Renderer.setRenderTarget() and CL3D.Renderer.addRenderTargetTexture() for this.

- Added support for inverting the depth test.
  See CL3D.Renderer.setInvertedDepthTest() for this.
 
- Introduced the option to use callbacks for shader settings constants when creating your own materials.

- Full screen with pointer lock now works again on Chrome. Previously, this stopped working
  after Google changed their implementation.

- Fixed 3D sound node to play sound looped even if set to 'play once'

 

Copperlicht is from (one of the?) creator of the popular IrrLicht game engine.  They also have a number of other tools available, such as the CopperCube world editor and irrKlang a cross platform audio library.  It’s one of those products I’ve intended to take a closer look at for some time.

News


15. January 2015

 

I’ve been doing a long running Phaser with TypeScript tutorial series that illustrates basically everything you need to know to create a complete game using the Phaser HTML5 game engine.  I decided to put together a video tutorial showing how to put it all together to make a complete game.

 

Now, keep in mind, the game is incredibly simple… I wanted to keep the entire thing to under an hour after all ( I failed, it’s an hour and a half ), so I had to keep the scope reasonable in size.  So as a result I’ve created Extreme Walking Simulator!  Yeah, you walk… and that’s it actually.  You walk forever and ever in front of the same looping background.  However, you are left with a complete but simple game but most importantly, a framework of code that can be expanded upon to build much more complex games.  It also illustrates program flow, drawing sprites, playing music, changing states, handling input and all the other things a “full” game has to do.

 

In addition to the code, all of the assets used are available on GitHub.  This includes my incredible title music, the Blend files used for the main character and the level scene.  Everything you need to create this game is there in the Assets folder.  Feel free to play around and use it however you want.  That said, the textures just came from Google Image Search, so no clue if there is a copyright on any of them, so don’t use them in a commercial project! I believe all of my Github stuff is set to Creative Commons license…  if it’s not, assume you can do anything you want with it and that you have absolutely no warranty.

 

Ok, enough preamble, let’s jump right in!  The tutorial is available in two parts on YouTube in 1080p ( or embedded below):

 

 

Following are the game itself, then the source listings, finally the two videos in an embedded player.

 

EXTREME WALKING SIMULATOR!

 

EDIT: Removed to prevent music auto playing, to play the game click here instead. Warning, loud

Controls:

  • Click the title screen to get started
  • Tap right arrow to start walking/speed up
  • Tap left arrow to slow down/stop
  • Press ESC to stop the torture!

 

 

The Source Code

 

index.html

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Hello Phaser</title>
    <link rel="stylesheet" href="app.css" type="text/css" />
    <script src="phaser.js"></script>
    <script src="GameObjects/MyScene.js"></script>
    <script src="GameObjects/Player.js"></script>
    <script src="States/TitleScreenState.js"></script>
    <script src="States/GamePlayState.js"></script>
    <script src="States/GameOverState.js"></script>
    <script src="app.js"></script>
</head>
<body>
    <div id="content"></div>
</body>
</html>

 

app.ts

module Game {
    export class ExtremeWalkingSimulator {
        game: Phaser.Game;


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

        preload() {
            // Graphics
            this.game.load.image("title", "Graphics/TitleScreen.png");
            this.game.load.image("scene", "Graphics/scene720p.png");
            this.game.load.image("gameover", "Graphics/GameOver.png");

            //Spritesheets
            this.game.load.atlasXML("HERO_WALKING", "Graphics/Hero_Walking.png", "Graphics/Hero_Walking.xml");
            this.game.load.atlasXML("HERO_IDLE", "Graphics/Hero_Idle.png", "Graphics/Hero_Idle.xml");

            // Audio
            this.game.load.audio("TitleSong", ["Sounds/TitleSong.mp3", "Sounds/TitleSong.ogg",
"Sounds/TitleSong.wav"]); } create() { this.game.state.add("TitleScreenState", GameFromScratch.TitleScreenState, true); this.game.state.add("GamePlayState", GameFromScratch.GamePlayState, false); this.game.state.add("GameOverState", GameFromScratch.GameOverState, false); this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; } } } window.onload = () => { var game = new Game.ExtremeWalkingSimulator(); };

 

Player.ts

module GameFromScratch {
    export enum PlayerState { IDLE, WALKING }

    export class Player extends Phaser.Sprite {
        game: Phaser.Game;
        playerState: PlayerState;
        RIGHT_ARROW: Phaser.Key;
        LEFT_ARROW: Phaser.Key;
        ESCAPE: Phaser.Key;
        walkingSpeed: number;

        public static MAX_SPEED: number = 30;

        constructor(game: Phaser.Game, x: number, y: number) {
            this.game = game;

            
            this.walkingSpeed = 0;

            //Wire up input handlers
            this.RIGHT_ARROW = this.game.input.keyboard.addKey(Phaser.Keyboard.RIGHT);
            this.RIGHT_ARROW.onDown.add(Player.prototype.MoveRight, this);

            this.LEFT_ARROW = this.game.input.keyboard.addKey(Phaser.Keyboard.LEFT);
            this.LEFT_ARROW.onDown.add(Player.prototype.MoveLessRight, this);

            this.ESCAPE = this.game.input.keyboard.addKey(Phaser.Keyboard.ESC);
            this.ESCAPE.onDown.add(Player.prototype.GameOver, this);
            super(game, x, y, "HERO_WALKING", 0);

            this.anchor.set(0.0, 1.0);
            this.StartIdle();
        }

        update() {
            if (this.playerState == PlayerState.WALKING) {
                this.x += (this.walkingSpeed / Player.MAX_SPEED) * (60 / this.game.time.elapsedMS);

                // This logic depends on scene being added first.
                var stageWidth = this.game.stage.getChildAt(0).getBounds().width;
                if (this.x > stageWidth * .75)
                    this.x = stageWidth * .25;
            }
            super.update();
        }

        // Worse function name ever!
        MoveLessRight() {
            if (this.playerState != PlayerState.IDLE) {
                this.walkingSpeed--;
                if (this.walkingSpeed > 0)
                    this.animations.currentAnim.speed = this.walkingSpeed;
                else
                    this.StartIdle();
            }
        }

        MoveRight() {
            if (this.playerState == PlayerState.IDLE) {
                this.StartWalking();
            }
            else {
            if (this.walkingSpeed < Player.MAX_SPEED)
                this.walkingSpeed++;
                this.animations.currentAnim.speed = this.walkingSpeed;
            }
        }

        StartWalking() {
            this.playerState = PlayerState.WALKING;
            this.walkingSpeed = 5;
            this.loadTexture("HERO_WALKING", 0);
            this.animations.add("walk");
            this.animations.play("walk", this.walkingSpeed, true);
        }

        StartIdle() {
            this.loadTexture("HERO_IDLE", 0);
            this.playerState = PlayerState.IDLE;
            this.animations.add("Idle");
            this.animations.play("Idle",15,true);
        }

        GameOver() {
            this.game.state.start("GameOverState");
        }

    }
}

 

MyScene.ts

module GameFromScratch {

    export class MyScene extends Phaser.Sprite {
        game: Phaser.Game;
        nextFrame: Phaser.Sprite;

        constructor(game: Phaser.Game, x: number, y: number) {
            super(game, x, y, "scene", 0);
            this.nextFrame = new Phaser.Sprite(this.game, this.width, 0, "scene", 0);
            this.game.add.existing(this.nextFrame);
        }
    }
}

 

TitleScreenState.ts

module GameFromScratch {
    export class TitleScreenState extends Phaser.State {
        game: Phaser.Game;
        music: Phaser.Sound;

        constructor() {
            super();
        }

        titleScreenImage: Phaser.Sprite;

        preload() {

        }
        create() {
            this.titleScreenImage = this.add.sprite(0, 0, "title");
            this.titleScreenImage.scale.setTo(this.game.width/this.titleScreenImage.width, this.game.height
/
this.titleScreenImage.height); this.music = this.game.add.audio("TitleSong"); this.music.volume = 100; this.music.loop = true; this.music.play(); this.input.onTap.addOnce(this.titleClicked, this); } titleClicked() { this.music.stop(); this.game.state.start("GamePlayState"); } } }

 

GamePlayState.ts

module GameFromScratch {
    export class GamePlayState extends Phaser.State {
        game: Phaser.Game;
        player: GameFromScratch.Player;
        myScene: GameFromScratch.MyScene;

        constructor() {
            super();
        }

        preload() {
        }
        create() {
            this.myScene = new MyScene(this.game, 0, 0);
            this.player = new Player(this.game, 0, this.game.height - 50);

            this.game.add.existing(this.myScene);
            this.game.add.existing(this.player);

            this.game.world.setBounds(0,0,this.myScene.width * 2, this.myScene.height);
            this.game.camera.follow(this.player);
        }
    }
}

 

GameOverState.ts

module GameFromScratch {
    export class GameOverState extends Phaser.State {
        game: Phaser.Game;
        gameOverSprite: Phaser.Sprite;

        constructor() {
            super();
        }

        preload() {
        }
        create() {
            this.gameOverSprite = this.add.sprite(0, 0, "gameover", 0);
            this.gameOverSprite.scale.setTo(this.game.width / this.gameOverSprite.width, this.game.height /
this.gameOverSprite.height); this.input.onDown.add(() => { this.game.state.start("TitleScreenState", true); }, this);; } } }

 

 

 

The Videos

 

Part One:

 

Part Two:

Programming


29. December 2014

 

Shortly before the holidays began I received a review copy of Core HTML5 2D Game Programming and amid all the holiday insanity, I’ve been slowly making my way through this title.  As with all reviews, I don’t give star ratings, I think the value of a book is determined mostly by the perspective and requirements of the reader.  OfCoreHTML5 course, some books are just simply bad.  Bad grammar, bad topic choice, bad humour.  Fortunately that is not the case here.  From a technical perspective this is a good book (with one glaring flaw).  Now the question is, is it a good book for you?

 

First let’s talk about the target audience.  This book is not aimed at complete beginners, prior experience with JavaScript and HTML5 is assumed.  Some JavaScript related topics are covered ( dealing with this, profiling/debugging in Chrome, simple inheritance, etc. ) but if you don’t already understand some JavaScript and haven’t ever touched on HTML5 or CSS work, you will be lost.  No prior game programming experience is assumed, although you may struggle a bit with some of the terminology if completely new.  There is however a fairly solid glossary that while get you through.  For more experienced game developers, this probably isn’t the title for you.

 

Ultimately this is a learn by doing book.  Through the course of the book you are putting together a basic platforming game called Snail Bait, built using the assets of the open source Android title Replica Island.  The game is available to be played online at http://corehtml5games.com… or at least, it’s supposed to be.  When I go to that site I get:

 

image

 

Hmmm, that’s unfortunate.  I am not sure if this is an ongoing problem, or just temporary.  Judging by an earlier review on Amazon about the server being unavailable, this is a recurring problem.  It is however a bit of a big problem, as many of the code listings in this book are actually partial, so having access to the complete project is very important.  The book repeatedly references this site, so with it down, so is a great deal of the appeal of this book.  Unfortunately the publisher doesn’t appear to make the code available anywhere else, at least not the book’s version.

 

Now back to the actual contents of the book.  This book covers pretty much all aspects of what you need to make a complete 2D HTML5 game.  One critical thing to understand with this title is everything is created from scratch.  The book makes use of no existing libraries, so you learn how to do things from scratch.  There is merit to learning how to do everything yourself at least initially.  That said, you will probably make a better game using libraries that have already dealt with all the various cross browser issues and optimizations for you.

 

The book does cover a surprising number of topics, starting with handling the game loop and ending with basic network programming.  For each topic there are a number of callout notes on game development or HTML5 idiosyncrasies.  For the most part, they are topical and rarely feel superfluous.  In between it covers animation, graphics, input, hit detection, dealing with mobile (controls and resolutions), particles, audio, easing and more.  The coverage of each topic is fairly comprehensive and easily understood.  One thing you might want to note, this book is entirely about using canvas for rendering, with absolutely no coverage of WebGL.  Given the increasing support for WebGL ( IE and Safari are both finally on board ), this could be a pretty big negative.

 

As I mentioned earlier, the majority of the book is about creating a single game step by step using what you’ve learned up till this point.  The code snippets are clear but without access to the finished whole, trying to figure out how it all fits together is difficult.  There is however one chapter dedicated to putting all the pieces you’ve learned together to make a simpler but complete  game, Bodega’s Revenge.  Unfortunately, these are also partial code listings, so without access to the source code, readers may struggle filling in the pieces.

 

What’s my verdict on this book then?  The book itself is quite good.  If you have some basic JavaScript knowledge and are looking at learning how to do HTML5 canvas based game development from scratch, it’s a very good resource.  There is an impressive amount of information jammed into this book with no obvious missing pieces.  If you are looking at purchasing this title, be certain to check if the site is available before you do! 

 

I would highly suggest the author or publisher make the code available on a much more reliable source, such as Github.

Programming


6. October 2014

 

 

In today’s tutorial we are going to cover the simple but powerful concept of grouping in Phaser.  As the name suggested, grouping allows you to group like minded Sprites together.  Probably easiest to jump right in with a simple example:

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    sprite: Phaser.Sprite;
    group: Phaser.Group;
    
    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload:
            this.preload, render: this.render
        });
    }
    preload() {
        this.game.load.image("decepticon", "decepticon.png");
        
    }
    render() {

    }
    create() {
        this.group = this.game.add.group();
        this.group.create(0, 0, "decepticon");
        this.group.create(100, 100, "decepticon");
        this.group.create(200, 200, "decepticon");

        this.game.add.tween(this.group).to({ x: 250 }, 2000,
            Phaser.Easing.Linear.None, true, 0, 1000, true).start();
    }
}

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

 

And run it:

 

 

As you can see, all objects in the group are updated as the group is updated.  You may notice we created the sprites directly in the group using Group.create, but we didn’t have to.  We could have just as easily done:

 

    create() {
        this.group = this.game.add.group();
        var sprite1 = this.game.add.sprite(0, 0, "decepticon");
        var sprite2 = this.game.add.sprite(100, 100, "decepticon");
        var sprite3 = this.game.add.sprite(200, 200, "decepticon");
        this.group.add(sprite1);
        this.group.add(sprite2);
        this.group.add(sprite3);

        this.game.add.tween(this.group).to({ x: 250 }, 2000,
            Phaser.Easing.Linear.None, true, 0, 1000, true).start();
    }

 

You can also add groups to groups, like so:

 

    create() {
        this.group = this.game.add.group();
        this.group2 = this.game.add.group();

        this.group.create(0, 0, "decepticon");

        this.group2.create(100, 100, "decepticon");
        this.group2.create(200, 200, "decepticon");

        this.group.add(this.group2);

        this.game.add.tween(this.group).to({ x: 250 }, 2000,
            Phaser.Easing.Linear.None, true, 0, 1000, true).start();
    }

 

The above code performs identically to the earlier example.  This can provide a great way to organize your game into logical entities, such as a group for the background, a group for scrolling foreground clouds, a group for bullets, etc.

 

Grouping things together is all nice and good, but if you can’t do anything to the group, it’s mostly just pointless.  Fortunately then, there is quite a bit you can do with a group.  You can loop through them:

 

    create() {
        this.group = this.game.add.group();

        this.group.create(0, 0, "decepticon");
        this.group.create(100, 100, "decepticon");
        this.group.create(200, 200, "decepticon");

        // Set each item in the group's x value to 0
        this.group.forEach((entity) => {
            entity.x = 0;
        }, this, false);

        this.game.add.tween(this.group).to({ x: 250 }, 2000,
            Phaser.Easing.Linear.None, true, 0, 1000, true).start();
    }

 

You can sort them:

 

    create() {
        this.group = this.game.add.group();

        this.group.create(0, 0, "decepticon");
        this.group.create(100, 100, "decepticon");
        this.group.create(200, 200, "decepticon");

        // Sort group by y coordinate descending
        this.group.sort("y", Phaser.Group.SORT_DESCENDING); 
        this.game.add.tween(this.group).to({ x: 250 }, 2000,
            Phaser.Easing.Linear.None, true, 0, 1000, true).start();
    }

 

You can update a property on all group members at once:

 

    create() {
        this.group = this.game.add.group();

        this.group.create(0, 0, "decepticon");
        this.group.create(100, 100, "decepticon");
        this.group.create(200, 200, "decepticon");

        // set the alpha value of all sprites to 50%
        this.group.setAll("alpha", 0.5);

        this.game.add.tween(this.group).to({ x: 250 }, 2000,
            Phaser.Easing.Linear.None, true, 0, 1000, true).start();
    }

 

Running:

 

 

You can get the index of any item within the group:

 

    create() {
        this.group = this.game.add.group();

        var sprite1 = this.group.create(0, 0, "decepticon");
        this.group.create(100, 100, "decepticon");
        this.group.create(200, 200, "decepticon");
        this.group.sort("y", Phaser.Group.SORT_DESCENDING);

        var index = this.group.getIndex(sprite1);
        this.game.add.text(0, 0, "Sprite1's index is:" + index,
            { font: "65px Arial", fill: "#ff0000", align: "center" },
            this.group); // Index should be 2

        this.game.add.tween(this.group).to({ x: 250 }, 2000,
            Phaser.Easing.Linear.None, true, 0, 1000, true).start();
    }

 

Running:

 

 

And as you might be able to see from the above example, you can also add text objects directly to groups!

One other important concept of Groups is being dead or alive.  There are all kinds of methods for checking if an entity is alive or not, like so:

 

    create() {
        this.group = this.game.add.group();

        var sprite1 = this.group.create(0, 0, "decepticon");
        this.group.create(100, 100, "decepticon");
        this.group.create(200, 200, "decepticon");


        sprite1.alive = false;
        this.group.forEachDead((entity) => {
            entity.visible = false;
        }, this);

        this.game.add.tween(this.group).to({ x: 250 }, 2000,
            Phaser.Easing.Linear.None, true, 0, 1000, true).start();
    }

 

This kills off the first of the three sprites, leaving you:

 

 

This tutorial only scratched the surface on what groups can do.  Simply put, they are a convenient data type for logically holding your game objects.  The only thing I didn’t mention is what happens when a group doesn’t have a parent.  In this situation, that parent is the games’ World, which… is a group.

 

Programming


23. September 2014

 

 

In the previous particle tutorial I used something called a tween followed by the instructions “don’t worry about it, I will cover them later”.  Well, welcome to later!

 

First off, what exactly is a tween?  It’s actually probably exactly what you expect it is, basically it’s “between” turned into a verb.  Tweens are all about transitioning from one state to another, and they are incredibly handy.  Let’s just straight in with an example:

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    sprite: Phaser.Sprite;
    
    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload:
            this.preload, render: this.render
        });
    }
    preload() {
        this.game.load.image("decepticon", "decepticon.png");
        
    }
    render() {
    }
    create() {
        this.sprite = this.game.add.sprite(0, 0, "decepticon");
        this.game.add.tween(this.sprite).to(
            { x: 400 }, 5000, Phaser.Easing.Linear.None, true, 0, Number.MAX_VALUE, true);
    }
}

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

 

This example shows a to() tween, which is it tweens between the initial value and the value you specify.  When creating a tween, you pass in the option you wish to tween, in this case a Phaser.Sprite.  The first value are the properties we wish to tween, in this cases sprite’s x value.  Next we tell it how long to take ( 5 seconds ), then pass in the easing function we want to use, in this case none ( which by the way, would have been the default value ), next is the delay before beginning ( right away ), how many times to perform ( infinite ) the tween, then finally we pass true to bounce.  Bounce says after you are done the tween, go back to the beginning.

 

And here is the result

 

 

As you can see the image moves across the screen until it’s x value is 400.

 

Now let’s take a look at how the easing function affects the tween.  Instead of no easing function, let’s apply an elastic band type affect.  We use InOut, which means it will ease at the beginning and end of the Tween.

 

    create() {
        this.sprite = this.game.add.sprite(0, 0, "decepticon");
        this.game.add.tween(this.sprite).to({ x: 400 }, 5000,
            Phaser.Easing.Elastic.InOut, true, 0, Number.MAX_VALUE, true);
    }

 

And the result:

 

 

Tweens don't have to be limited to positioning items either, you can tween just about any value. For example, let’s instead tween the alpha value of our sprite:

 

    create() {
        this.sprite = this.game.add.sprite(0, 0, "decepticon");
        this.game.add.tween(this.sprite).to({alpha:0 }, 5000,
            Phaser.Easing.Quadratic.In, true, 0, Number.MAX_VALUE, true);
    }

 

And the result

 

 

You can also chain together tweens to perform a series of transitions:

 

    create() {
        this.sprite = this.game.add.sprite(0, 0, "decepticon");
        this.game.add.tween(this.sprite)
            .to({ x: 400 }, 2000)
            .to({ y: 250 }, 2000)
            .to({ x: 0 }, 2000)
            .to({ y: 0 }, 2000).loop().start();
    }

 

Resulting in:

 

 

Tweens also have event handlers attached. Here for example is a tween that has an onStart and onComplete event handler, that fire before and after the tween completes respectively.

 

    create() {
        this.sprite = this.game.add.sprite(0, 0, "decepticon");
        var tween = this.game.add.tween(this.sprite);
        tween.to({ x: 400 });

        tween.onStart.addOnce(() => {
            this.sprite.scale.setMagnitude(0.5);
        });
        tween.onComplete.addOnce(() => {
            this.game.add.tween(this.sprite).to({ x: 0 }).start();
            },this);
        tween.start();
    }

 

Tweens provide a pretty powerful but simple way of adding actions, either in sequence or parallel, to your game’s contents.

 

Programming


GFS On YouTube

See More Tutorials on DevGa.me!

Month List