PHASER.JS 遊戲框架 心得分享

Email: hank@catchad.com.tw

League of Legends: MiSs830320

Battle.net: MiSs830320#3631 (D3, 爐石戰記, 暴雪英霸)

Blade & Soul: 貴大師

Dragon Nest: 阿貴控肉飯

Twitch: http://www.twitch.tv/hank5678/

阿貴

Phaser.js

Getting Started

Sprites

Physics

Input

Overlap

Camera

Tilemap

Phaser.js

Performance (Pixi.js)

Tiled map editor

Examples

Getting Started

<!DOCTYPE html>
<html>
<head>
    <title>phaser demo</title>
    <link rel="stylesheet" href="assets/styles/normalize.css">
</head>
<body>
    <div id="phaser-container"></div>
</body>
</html>
<script src="assets/scripts/phaser.2.4.4.min.js"></script>
<script src="assets/scripts/game.js"></script>

HTML code:

Getting Started

var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-container', { preload: preload, create: create, update: update });
function preload() {
    // 預載遊戲裡面需要的東西
}

function create() {
    // 預載完成 開始創建phaser世界
}

function update() {
    // 刷新
}

JS code:

Demo:

Sprites

function preload() {
    // 預載遊戲裡面需要的東西
    game.load.image('coin', 'assets/images/coin.png');
    game.load.image('ground', 'assets/images/ground.png')
}

coin.png

ground.png

function create() {
    // 預載完成 開始創建phaser世界
    // 設定背景色
    game.stage.backgroundColor = "#6888FF";
    // 放一個金幣
    var coin = game.add.sprite(600, 350, 'coin');
    // 放第一塊陸地
    var ground1 = game.add.tileSprite(0, game.height-16, 800, 16, "ground");
    // 放第二塊陸地
    var ground2 = game.add.tileSprite(450, 500, 300, 16, "ground");
}

Sprites

tileSprite

Demo:

Physics

function preload() {
    // 預載遊戲裡面需要的東西    
    ...
    game.load.spritesheet('mario', 'assets/images/mario.png', 32, 32);
}

mario.png

32

32

32 * 6


function create() {
    // 預載完成 開始創建phaser世界
    game.physics.startSystem(Phaser.Physics.ARCADE); // ARCADE, NINJA, P2
    game.time.desiredFps = 60; // 設定FPS為60

    // 新增一個管理物理碰撞的群組
    platforms = game.add.group();

    // 放第一塊陸地
    var ground1 = game.add.tileSprite(0, game.height-16, 800, 16, "ground");
    game.physics.arcade.enable(ground1); // 啟動它的物理反應
    ground1.body.immovable = true;       // 靜止不動
    platforms.add(ground1);              // 把陸地加入物理碰撞的群組

    // 放玩家
    player = game.add.sprite(0, 0, 'mario');
    game.physics.arcade.enable(player);
    player.anchor.set(0.5, 0.5);  // 設定基準點
    player.body.bounce.y = 0.2;   // 彈性
    player.body.gravity.y = 300;  // 重力
}

Physics

(0, 0)

(0.5, 0.5)

(1, 1)

function update() {
    // 計算 player 與 platforms 群組的物理碰撞
    game.physics.arcade.collide(player, platforms);
}

Physics

Player

Platforms

Demo:

Input

function create() {
    // 預載完成 開始創建phaser世界
    ...    
    // 定義鍵盤方向鍵
    cursors = game.input.keyboard.createCursorKeys();
    // 放玩家
    ...
    player.body.collideWorldBounds = true;
    player.animations.add('walk', [0, 1, 2, 3], 10, true); //loop
}

0

1

2

3

walk

4

5

jump

dead

Input

function update() {
    player.body.velocity.x = 0; // 不動
    // 按左鍵
    if (cursors.left.isDown) {
        player.body.velocity.x = -150;     // 向左移動
        player.scale.x = -1;               // 水平翻轉
        if( player.body.touching.down ) {  // 玩家在地上
            player.animations.play('walk');
        }
    }
    // 沒有按左鍵 and 沒有按右鍵 and 玩家在地上
    if( cursors.left.isUp && cursors.right.isUp && player.body.touching.down ) {
        player.animations.stop(); // 暫停動畫
        player.frame = 0;         // 顯示原地不動影格
    }
    // 按上鍵 and 玩家在地上
    if (cursors.up.isDown && player.body.touching.down) {
        player.body.velocity.y = -300;  // 向上移動
        player.animations.stop();       // 暫停動畫
        player.frame = 4;               // 顯示跳影格
    }
}

Demo:

Overlap

function create() {
    // 預載完成 開始創建phaser世界
    ...
    coins = game.add.group(); // 建立coins群組
    // 放十二個金幣
    for (i = 0; i < 12; i++) {
        var coin = game.add.sprite(i*70, 0, 'coin');
        game.physics.arcade.enable(coin);
        coin.body.gravity.y = 600;  // 重力
        coin.body.bounce.y = 0.3 + Math.random() * 0.5;  // 隨機的彈性值
        coins.add(coin);  // 把金幣加入coins群組
    }
}

Overlap

function update() { 
    // 計算 player 與 platforms 群組的物理碰撞
    game.physics.arcade.collide(player, platforms);
    // 計算 coins群組 與 platforms 群組的物理碰撞
    game.physics.arcade.collide(coins, platforms);
    // 計算 player 與 coins 群組的重疊狀態
    game.physics.arcade.overlap(player, coins, collectCoin);
    ...
}
function collectCoin(player, coin) {    
    coin.kill(); // 刪除金幣
}

Player

Platforms

Coins

Demo:

Overlap

function preload() {
    // 預載遊戲裡面需要的東西
    ...
    game.load.image('luigi', 'assets/images/luigi.png');
}

luigi.png

Overlap

function create() {
    ...
    // 放壞人
    enemies = game.add.group();
    var luigi = game.add.sprite(650, 350, 'luigi');
    game.physics.arcade.enable(luigi);
    luigi.anchor.set(0.5, 0.5);
    luigi.body.gravity.y = 600;
    luigi.body.bounce.y = 0.5;
    enemies.add(luigi);
}

(0, 0)

(0.5, 0.5)

(1, 1)

Overlap

function update() {
    // 計算 player 與 platforms 群組的物理碰撞
    game.physics.arcade.overlap(player, enemies, overlapEnemies);    
    ...
}
function overlapEnemies(player, enemy) {
    if( player.y + player.body.halfHeight <= enemy.y - enemy.body.halfHeight  ) {
        player.body.velocity.y = -150; // 向上移動
        enemy.kill();
    } else {
        game.physics.arcade.isPaused = true; // 暫停物理引擎的運算
        game.add.tween(player).to( { y: player.y+500 }, 1000, Phaser.Easing.Back.In, 500);
        player.animations.stop(); //暫停目前的動畫
        player.frame = 5;         //顯示死掉的影格
    }
}

player.y

halfHeight 

enemy.y

halfHeight 

Demo:

Camera

var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-container', { preload: preload, create: create, update: update });
function create() {
    // 設定phaser遊戲世界的範圍
    game.world.setBounds(0, 0, 1600, 600);     
    var ground1 = game.add.tileSprite(0, game.height-16, 1600, 16, "ground");
    ...
}

800

600

1600

Camera

function update() {
    // 鏡頭跟隨玩家位置
    game.camera.focusOnXY(player.x , player.y );
    ...
}

800

600

Demo:

Tilemap

Tilemap

function preload() {
    game.load.tilemap('map', 'assets/mapdata/map.json', Phaser.Tilemap.TILED_JSON);
    game.load.image('tiles', 'assets/images/tiles.png');
}

tiles.png

Tilemap

function create() {
    game.stage.backgroundColor = '#6888FF'; // 設定背景色
    map = game.add.tilemap('map');    // 把 map 加入遊戲
    map.addTilesetImage('tiles');     // 把 map 使用到的圖塊加入進去
    layer = map.createLayer('world'); // 把 Tiled 定義的圖層加進來
    layer.resizeWorld();              // 設定layer範圍為遊戲世界邊界(setBounds)
    map.setCollisionBetween(14, 16);  // 設定圖塊中需要物理碰撞的單位
    map.setCollisionBetween(20, 25);
    map.setCollisionBetween(27, 29);
    map.setCollision(40);
    map.setTileIndexCallback(11, getCoin);  // 設定圖塊被碰到時的 callback
    ...
}

1

14

15

16

20

25

11

40

Tilemap

function update() {
    game.physics.arcade.collide(player, layer);
    ...
}

Player

Layer

Demo:

END

參考連結:

簡報demo:

https://event.catchad.com.tw/hanktest/phaser_demo/demo-01.html   ~   demo-08.html

 

phaser:
http://phaser.io/

 

phaser社群:

http://www.html5gamedevs.com/forum/14-phaser/

 

Tiled:

http://www.mapeditor.org/

Phaser.js 遊戲框架 心得分享

By 蔡阿貴

Phaser.js 遊戲框架 心得分享

2016/03/09 前端工程師聚會簡報

  • 1,911