Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


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 , , , , ,

blog comments powered by Disqus

Month List

Popular Comments

Modo Indie released and is available on Steam… on sale of course
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


Home > Art, News >

12. December 2014

 

Modo, a popular 3D modeling application ( learn more about Modo and more in my Introduction to 3D Applications post, or watch the video ) has just been released on Steam.  Actually, Steam being Steam, it’s actually on sale right now for 25% off!

 

image

 

 

Considering the full price of Modo is about $1,600, the Steam Indie version for $250 CDN is quite a bargain!  So, what’s the catch?

 

Yeah, there’s always a catch isn’t there?  So, what’s the difference between Modo and Modo Indie?  Well…

 

  • Project file (.lxf) linked to Steam account / cannot be shared with other users
  • OBJ and FBX export limited to 100k polys
  • Bake and render resolution limited to 4k
  • Command eval options unavailable
  • Command, scripts, and command history panel results unavailable except “undo” and “history”
  • Python editor, third-party scripts, and third-party plugins unavailable
  • OBJ and FBX export only
  • Can import all formats but can only save in .lxf format
  • Image save formats limited to .png, .jpg, .tiff and .exr

 

So they went the Maya LT route and limited the functionality but not the licensing.  This means you can use Modo Indie regardless to how much money you make or how you use it.  This is the deal breaker for many Indie licenses…  As to the stripped out functionality, I think the first restriction is going to be the most difficult one for many to swallow.

 

Simply put you cannot collaborate on a Modo Indie project!  Only one artist will be able to work on the project, ever.  It’s tied to your Steam account id and cannot be shared with others or distributed, although obviously you can export/import in OBJ or FBX format, so for many this wont be much of a limitation in the end.  However for teams with multiple people working on the same resource, or teams where the artist could change at some point in the future, this is going to be a gigantic deal breaker.

 

I haven’t used Modo recently enough to tell if script/plugin support is a big loss or not.  I frankly don’t recall there being any plugins back when I evaluated.  I understand why they do this though, or the very first plugin that would be released would be something to get around the 100K polygon limits.

 

The other limitations seem reasonable.  The 100K export limit precludes you from being able to use Modo as a level editor, but I don’t think many people are doing this anyways.  For game ready assets, 100K polygons and 4K texture limits seem appropriate.  If your needs are much more extreme than that, I can see how you wouldn’t be viewed as an Indie anymore and thus should have funds to purchase the full version.

 

Another affordable 3D option for indie game devs is always welcome, more choice is almost always good.  If you are interested in picking up Modo, the sale ends December 18th/2014.  That said, this is Steam we are talking about, so there will always be another bigger and better sale around the corner!  Oh, they also have a package deal with their MARI Indie texture painting package.  You can purchase both together for $315CDN.

 

Oh yeah, they also released MARI Indie as well… suppose I should mention that.  I have absolutely no experience with Mari, so I figured I would go with their description:

 

MARI indie is the fastest, most artist-friendly way to texture, paint, and detail amazing 3D assets for your game projects. Fine-tuned for individual developers and freelance artists in the game industry, MARI indie is an invaluable toolset that lets you focus on the artistic aspect of 3D game asset painting without getting bogged down by the technical side -- free of any individual commercial restrictions and without breaking your budget!

 

Delivering massive power and flexibility at minimal cost, MARI indie gives you ultimate control over painting and detailing every facet of your 3D models and animations in a way that's quick, intuitive, and highly creative -- all in one complete package that lets you work just the way you want.


Supported by the world’s most advanced layering system, MARI indie is a real workhorse. It gives game artists and content creators all the functionality they need to exactly replicate the look of assets in their games engine.

 

Once again, MARI Indie has no limitations on commerical usage, all limitations are technical:

 

  • Project file (.mra) linked to Steam account / cannot be shared with other users
  • Allowed export formats: .psd, .png, .tga, .jpg
  • Output formats no longer available .exr, .tif, .tiff, .hdr, .dds, and .ptx
  • The patch count is limited to 2 patches
  • The object count is limited to 3 objects
  • The output texture resolution size has been limited to 4k
  • Python scripting disabled

 

With zero experience with MARI I have no opinion on these limitations either way.

 

But WAIT, there’s more!

 

image

 

Yep, there is also a subscription plan available.  And at as low as $11 CDN a month it’s pretty freaking reasonable too.  For example, Maya LT is $30 a month, although they only offer monthly rates.

Art, News ,

blog comments powered by Disqus

Month List

Popular Comments