Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

20. January 2015

 

In this third part of multiple part video tutorial looking at using Scene2D we look at creating Groups for organizing Actors, as well as hit testing, making it possible to select actors available in your scene.  All of the code is included below.  For an HD version of the video click here.

 

 

Groups

package com.gamefromscratch.group;

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.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.utils.viewport.ScreenViewport;

public class GroupDemo extends ApplicationAdapter implements InputProcessor {
   Stage stage;

   @Override
   public void create () {
      stage = new Stage(new ScreenViewport());
      Group group =  new Group();

      Image tableImg = new Image(new Texture(Gdx.files.internal("table.png")));
      Image aceImg = new Image(new Texture(Gdx.files.internal("ace.png")));
      Image kingImg = new Image(new Texture(Gdx.files.internal("king.png")));

      tableImg.setName("table");
      aceImg.setName("ace");
      kingImg.setName("king");

      group.addActor(tableImg);
      group.addActor(kingImg);
      group.addActor(aceImg);

      stage.addActor(group);

      kingImg.setPosition(300,150);
      aceImg.setPosition(400,150);

      Gdx.input.setInputProcessor(this);
   }

   @Override
   public void render () {
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
      stage.act(Gdx.graphics.getDeltaTime());
      stage.draw();
   }

   @Override
   public boolean keyDown(int keycode) {
      Group group = (Group)stage.getActors().first();
      Image ace = (Image)group.findActor("ace");

      if(keycode == Input.Keys.RIGHT)
         if(Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT))
            ace.setRotation(ace.getRotation() + 1f);
         else
            group.setRotation(group.getRotation() + 1f);

      if(keycode == Input.Keys.LEFT)
         if(Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT))
            ace.setRotation(ace.getRotation() -1f);
         else
            group.setRotation(group.getRotation() - 1f);

      if(keycode == Input.Keys.UP)
         group.setColor(group.getColor().r,group.getColor().g,
               group.getColor().b,group.getColor().a + 0.1f );

      if(keycode == Input.Keys.DOWN)
         group.setColor(group.getColor().r,group.getColor().g,
               group.getColor().b,group.getColor().a - 0.1f );

      if(keycode == Input.Keys.NUM_1)
         ace.setZIndex(ace.getZIndex() -1);
      if(keycode == Input.Keys.NUM_2)
         ace.setZIndex(ace.getZIndex() +1);

      return true;
   }

   @Override
   public boolean keyUp(int keycode) {
      return false;
   }

   @Override
   public boolean keyTyped(char character) {
      return false;
   }

   @Override
   public boolean touchDown(int screenX, int screenY, int pointer, int button) {
      Vector2 coord = stage.screenToStageCoordinates(new Vector2((float)screenX,(float)screenY));
      Actor hitActor = stage.hit(coord.x,coord.y,false);

      if(hitActor != null)
         Gdx.app.log("HIT",hitActor.getName());

      return true;
   }

   @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;
   }
}

Programming , , ,

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

12. January 2015

 

Ok, I’ll admit, this topic isn’t the most incredibly gamedev related thing I’ve covered, but I figured enough of you might find it useful that I should share this.  Like many other things, Blender has incredibly powerful text manipulation and rendering features built in, but working with them isn’t always intuitive.  We work with text for a variety of reasons… pre-rendered title screens, menus, credits, etc… so knowing how to do this could be quite useful.  So let’s take a look.  There is also a video of this process available here.

 

Creating and rendering text in Blender

 

Add The Text Object

 

First you need to add a text object to the scene.  Text is a first class object and is added using the Add->Text menu:

image

 

Editing the Text

 

Text will now appear in your scene like so:

image

 

I want it facing the front, so I simply rotate the text using r + x + 90 to rotate 90 degrees on the X axis

Now switch in to edit mode either by hitting tab or selecting the edit option:

image

 

Now a cursor (caret) will appear beside your text:

image

In this mode you can edit your text like using a word processor.  Switch modes or press tab to stop edit mode.

 

Modifying your text

 

Now that you’ve got your text set to whatever it is you want, you can now modify it in the Properties panel.  With the text selected, locate the F icon:

image

 

Now you can set a number of properties:

image

 

A few of which are critical.  Probably the most important is the Extrude option, which gives your text depth like so:

image

 

And offset, which gives a nice bevel effect:

image

 

Changing the Font

 

Blender ships with and uses their own font BFont by default.  However you most likely want to import a TTF font from your system.  You import the font based on the type of text… regular, bold, etc.  Simply click the Open icon:

image

And load the font you wish to use.  If you are using Windows, fonts are stored under Windows\Fonts.

 

Text Positioning

 

Like a word processing tool, there are also text alignment options:

image

 

These values are set relative to the objects Origin:

image

 

The Origin can be set using menu options in Object->Transform menu

image

 

The Results

 

As I said earlier, Blender text can be used to quickly and easily make in game menus, like so:

 

image

 

Although ideally, yours will be a bit less ugly!

 

The Video

 

 

Here is the video, again there is an HD version available here.

Art ,

9. January 2015

 

I needed to create a sprite sheet for an upcoming tutorial series and managed to throw one together in an amazingly short amount of time with almost no artistic ability.  Good looking art with no ability is something many indie game developers are screaming for, so I figured I would share the process.

 

During the tutorial we use the following programs:

Mixamo Fuse (Free version available, MSRP $99USD)

Blender (Free and Open Source)

TexturePacker (Free version available, MSRP $50USD)

 

If you want more details on Mixamo, I extensively review it here.

 

The ultimate output from this entire process is the sprite sheet powering this animation:

bigguy

 

And here is the resulting sprite sheet, click it for the full resolution version:

a

 

Now finally, the video.  You can watch it in full 1080p on YouTube.

 

Coincidentally, if you want more information on how I created the above animated gif, I used a program called Cryotek Animated GIf Creator, and document the process here.  It’s a very cool program and completely free.

Programming, Art, General , , , ,

7. January 2015

 

It’s most a maintenance release, so the list of new features is fairly sparse:

 


New Features
  • Phaser.Loader now supports BLOB urls for audio files (thanks @aressler38 #1462)
  • Line.reflect will calculate the reflected, or outgoing angle of two lines. This can be used for Body vs. Line collision responses and rebounds.
  • Line.normalAngle gets the angle of the line normal in radians.
  • Line.normalX and Line.normalY contain the x and y components of the left-hand normal of the line.
  • Line.fromAngle will sets this line to start at the given x and y coordinates and for the segment to extend at angle for the given length.
  • BitmapData.drawGroup draws the immediate children of a Phaser.Group to a BitmapData. Children are only drawn if they have their exists property set to true. The children will be drawn at their x and y world space coordinates. When drawing it will take into account the child's rotation, scale and alpha values. No iteration takes place. Groups nested inside other Groups will not be iterated through.

 

You can read the complete release notes here.

 

The release 2.3 milestones are available here.

 

They also made this announcement regarding version 3:

We're hard at work on Phaser 3. Development on the brand new renderer began in earnest last year and we're already seeing exceptional results from it. You can follow our development in the forum and public repo. Even though we're working on taking Phaser 3 into ES6 and the next generation of web browsers, we haven't stopped with the 2.x branch.

 

If Phaser sounds interesting to you, of course, Gamefromscratch has an extensive tutorial series available here.

Programming, News , ,

Month List

Popular Comments

An Hour with Blender and GameFromScratch.com
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


Home > Art >

26. March 2015

 

I just started a new concept off today, please let me know if you like it.  Basically it’s a fixed duration (one hour) overview on a specific topic, in this case Blender.  The idea is to give a cross between an introduction and a tutorial on getting started with using a certain product.  In this video we look at Blender, how to configure it, how to navigate and customize the interface, what it’s composed off and the basics of operating it.

 

If there is interest, I can do “An hour with” topics that are much more focused, such as “An hour Modelling” or “An hour texturing”, etc.

 

Additionally, this is not a deep dive Blender tutorial.  Fortunately I already have one of those!  If you are looking at specifics of learning Blender, the hotkeys, etc, please start here.

 

Below is an embedded version of the video.  It is also available in full 1080p on YouTube here.

 

The Video

 

Art , ,

blog comments powered by Disqus

Month List

Popular Comments