我的新書AI 職場超神助手:ChatGPT 與生成式 AI 一鍵搞定工作難題的教材投影片已製作完成
歡迎各位有需要的教師和博碩文化索取教材

[25- Pixi教學] 遊戲開始、結束與過關畫面

遊戲關卡概念

每個遊戲一般都會需要關卡的概念,也就是過關後可以再重新進行遊戲,並且需要有關卡結局畫面。
今天我們就是要製作這樣的一個過關或遊戲結束的畫面,如下圖:

在pixi內使用文字

在pixi4.0之後可以直接利用pixi來做出很漂亮的文字效果,以下為官網的範例

var app = new PIXI.Application(800, 600, {backgroundColor: 0x1099bb});
document.body.appendChild(app.view);

var basicText = new PIXI.Text('Basic text in pixi');
basicText.x = 30;
basicText.y = 90;

app.stage.addChild(basicText);

var style = new PIXI.TextStyle({
    fontFamily: 'Arial',
    fontSize: 36,
    fontStyle: 'italic',
    fontWeight: 'bold',
    fill: ['#ffffff', '#00ff99'], // gradient
    stroke: '#4a1850',
    strokeThickness: 5,
    dropShadow: true,
    dropShadowColor: '#000000',
    dropShadowBlur: 4,
    dropShadowAngle: Math.PI / 6,
    dropShadowDistance: 6,
    wordWrap: true,
    wordWrapWidth: 440
});

var richText = new PIXI.Text('Rich text with a lot of options and across multiple lines', style);
richText.x = 30;
richText.y = 180;

app.stage.addChild(richText);

成果如下:

現在更支援Bitmap font,請參見官網的demo

var app = new PIXI.Application();
document.body.appendChild(app.view);

// // Load them google fonts before starting...!
window.WebFontConfig = {
    google: {
        families: ['Snippet', 'Arvo:700italic', 'Podkova:700']
    },

    active: function() {
        // do something
        init();
    }
};

// include the web-font loader script
/* jshint ignore:start */
(function() {
    var wf = document.createElement('script');
    wf.src = ('https:' === document.location.protocol ? 'https' : 'http') +
        '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
    wf.type = 'text/javascript';
    wf.async = 'true';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);
})();
/* jshint ignore:end */

function init()
{
    PIXI.loader
        .add('desyrel', 'required/assets/desyrel.xml')
        .load(onAssetsLoaded);

    function onAssetsLoaded() {
        var bitmapFontText = new PIXI.extras.BitmapText('bitmap fonts are\n now supported!', { font: '35px Desyrel', align: 'right' });

        bitmapFontText.x = app.screen.width - bitmapFontText.textWidth - 20;
        bitmapFontText.y = 20;

        app.stage.addChild(bitmapFontText);
    }
}

顯示成果如下:

新增遊戲關卡畫面

新增檔案GameRoundEnd.ts,內容如下:

import Container = PIXI.Container;
import { eventEmitter } from "../Main";
import { GameFlowEvent } from "../core/Event";

export class GameRoundEnd extends Container {
    private text:PIXI.Text;
    constructor() {
        super();
        this.interactive = true;
        this.visible = false;
        eventEmitter.on(GameFlowEvent.GameEndWithTimeout, ()=>{
            this.text.text = "Time is up!";
            this.text.x = 260;
            this.text.y = 200;
            this.visible = true;
        });
        eventEmitter.on(GameFlowEvent.GameEndWithNoPath, ()=>{
            this.text.text = "Game over";
            this.text.x = 260;
            this.text.y = 200;
            this.visible = true;
        });
        eventEmitter.on(GameFlowEvent.GamePass, ()=>{
            this.text.text = "Congratulations! \nYou passed!";
            this.text.x = 210;
            this.text.y = 200;
            this.visible = true;
        });
        //黑底
        let gt = new PIXI.Graphics();
        gt.beginFill(0x000000, 0.9);
        gt.drawRect(0,0,860,540);
        gt.endFill();
        this.addChild(gt);
        //文字
        this.text = new PIXI.Text("Congratulations! \nYou passed!", {
            fontWeight: 'bold',
            fontSize: 60,
            fontFamily: 'Arial',
            fill: '#ff0000',
            align: 'center',
            stroke: '#FFFFFF',
            strokeThickness: 3
        });
        this.addChild(this.text);
        //再玩一次按鈕
        let btn = new PIXI.Graphics();
        btn.beginFill(0x75C7ED);
        btn.drawRoundedRect(700,480,115,35,10);
        btn.endFill();
        btn.buttonMode = true;
        btn.interactive = true;
        btn.on("mouseup", this.trigger.bind(this));
        btn.on("touchend", this.trigger.bind(this));
        this.addChild(btn);
        let newGame = new PIXI.Text("New Game", {
            fontWeight: 'bold',
            fontSize: 20,
            fontFamily: 'Arial',
            fill: '#75C6ED',
            align: 'center',
            stroke: '#FFFFFF',
            strokeThickness: 6
        });
        newGame.x = 705;
        newGame.y = 483;
        this.addChild(newGame);
    }
    public trigger(){
        eventEmitter.emit(GameFlowEvent.CreateNewGameRequest);
        this.visible = false;
    }
}

並修改GameBoard.ts內iconClickHandler的內容如下

let iconClickHandler = ()=>{
    this.cancelTips();
    if (this.selected) {
        let selectCorrect = false;
        this.select2 = new Point(x, y);
        this.iconSelected(this.select2);
        setTimeout(()=>{
            if (board.hasSameValue(this.select1, this.select2)) {
                if (! (this.select1.x == x && this.select1.y == y) ) {
                    let path = new Path(this.select1, this.select2, board);
                    if(path.canLinkInLine()){
                        this.pathHistory.push(path);
                        this.valueHistory.push(board.getValue(this.select1));
                        LinkedLine.instance.drawPath(path);
                        this.clearIcon(this.select1);
                        this.clearIcon(this.select2);
                        eventEmitter.emit(GameFlowEvent.LinkedLineSuccess);
                        selectCorrect = true;
                        //判斷還有沒有路走
                        if(board.gameRoundEnd()){
                            eventEmitter.emit(GameFlowEvent.GamePass);
                        }else if(board.getFirstExistPath() == null){
                            if(reloadTimes > 0){
                                this.reloadBoard();
                                eventEmitter.emit(GameFlowEvent.BoardNeedReload);
                            }else{
                                eventEmitter.emit(GameFlowEvent.GameEndWithNoPath);
                            }
                        }
                    }
                }
            }
            if(selectCorrect){
                SoundMgr.play('Sound_select_crrect');
            }else{
                SoundMgr.play('Sound_select_error');
                this.iconUnSelected(this.select1);
                this.iconUnSelected(this.select2);
            }
            this.selected = false;
        },0);

    } else {
        this.select1 = new Point(x, y);
        this.iconSelected(this.select1);
        this.selected = true;
        SoundMgr.play('Sound_select_1');

    }
};

今日成果

線上demo:http://claire-chang.com/ironman2018/1109/
今日成果下載:ironman20181109


17年資歷女工程師,專精於動畫、影像辨識以及即時串流程式開發。經常組織活動,邀請優秀的女性分享她們的技術專長,並在眾多場合分享自己的技術知識,也活躍於非營利組織,辦理活動來支持特殊兒及其家庭。期待用技術改變世界。

如果你認同我或想支持我的努力,歡迎請我喝一杯咖啡!讓我更有動力分享知識!