EngineJS

介紹

EngineJs 是一個輕量的遊戲引擎框架,啟發於 Scratch 的積木程式語言,有許多相似的語法,對於從學習 Scratch 到入門 JavaScript 的新手十分的友善,既使尚未學習過任何程式語言也能輕鬆入門,快速做出屬於自己的遊戲。

環境準備

1. 線上編輯器
2. 使用 CDN

<script src="https://orangeappletw.github.io/engine.js/engine-min.js"></script>

開始

這個章節將會一步一步帶你做出一個完整的小遊戲,所有的步驟都會附上程式碼與實際範例,可以點擊範例程式執行並觀察成果。

創造遊戲

Engine(canvasId);

canvasId: canvas 元素的 ID

var Game = Engine('stage');

初始化遊戲設定

Game.set({
    width: 400, // Default: 640px
    height: 400, // Default: 480px
    debugMode: true, // Default: false
    precision: 4 // 像素碰撞的分辨率,單位是 pixel
});

Koding School 平台編輯程式,不需要初始化遊戲

載入素材

Game.preload([path1, path2, path3], completeCallback, progressCallback);

Game.preload([
    './assets/background.png',
    './assets/bird.png',
    './assets/ground.png',
    './assets/pipes.png',
    './assets/start-button.png',
    './assets/gameover.png',
    './assets/jump.ogg',
    './assets/bgm.ogg'
],function() {
    Game.start();
});

Koding School 平台編輯程式,不需要載入素材

設定背景

Game.setBackdrop(path, x, y, width, height);path: 素材的網址
x: 背景圖左上角 x 座標
y: 背景圖左上角 y 座標
width: 長度
height: 寬度

Game.setBackdrop('./assets/background.jpg');
範例程式

創造角色

創造出小鳥,預設位置為場景中央

var bird = Game.createSprite('./assets/bird.png');

創造出三組水管,並設定座標位置

var p1 = createSprite('./assets/pipes.png');
var p2 = createSprite('./assets/pipes.png');
var p3 = createSprite('./assets/pipes.png');
p1.x = 1200;
p2.x = 1700;
p3.x = 2200;
p1.y = Math.random()*600 + 150;
p2.y = Math.random()*600 + 150;
p3.y = Math.random()*600 + 150;
範例程式

遊戲迴圈

Game.forever(fn) | Game.aways(fn) | Game.update(fn) fn: 遊戲迴圈,重複不斷執行的函式

在遊戲迴圈裡不斷移動水管,如果水管移動超出邊界就重置水管的位置

forever(function () {
 updatePipes();
});

重置水管的函式,將水管移到右邊遊戲場景外,並隨機水管的位置

var pipes = [p1, p2, p3];
function updatePipes () {
    for (var i=0; i<3; i++) {
        pipes[i].x -= 5;
        if (pipes[i].x < -100) {
            pipes[i].x += 1500;
            pipes[i].y = 100 + Math.random()*700;
        }
    }
}
範例程式

遊戲事件

幫鳥加上重力,創造變數 vx 表示鳥的下降速度

var vy = 0;
forever(function () {
   updatePipes();
   updateBird();
});
function updateBird () {
    bird.y += vy;
    vy += 0.5;
}

當滑鼠點擊時,鳥要往上飛行

when('click', jump);
function jump () { 
    vy = -8;
    sound.play('./assets/jump.ogg');
}

小鳥碰撞水管時停止遊戲

forever(function () {
    if (bird.touched([p1, p2, p3])) {
        stop();
    }
});
範例程式

遊戲音效

進入遊戲後就不斷重複播放背景音樂

 var bgm = sound.play('./assets/bgm.ogg', true);

當滑鼠點擊銀幕時,播放跳耀的音效

 function jump () { 
    vy = -8;
    sound.play('./assets/jump.ogg');
 }
範例程式

顯示文字

設計計分板並顯示在畫面左上方

forever(function () {
    print(scores, 10, 10, 'white', 60);
});

當重置一組水管時分數加一

function updatePipes () {
    for (var i=0; i<3; i++) {
       pipes[i].x -= 5;
       if (pipes[i].x < -100) {
           pipes[i].x += 1500;
           pipes[i].y = 100 + Math.random()*700;
           scores++;
       }
   }
}
範例程式

完成

創造地板、開始按鈕、遊戲結束Logo,並隱藏結束Logo

var startBtn = createSprite('./assets/start-button.png');
var gameOverLogo = createSprite('./assets/gameover.png');
var ground = createSprite('./assets/ground.png');
startBtn.y = 500;
gameOverLogo.y = 350;
ground.y = 880;
gameOverLogo.hidden = true;

當點擊開始按鈕時,執行初始化函式 start,遊戲初始化函式會初始角色的座標與歸零分數,並將飛行狀態改為 true

startBtn.when('click', start);
 
var runing = false;
function restart () {
    scores = 0;
    vy = 0;
    running = true;
    bird.y = 450;
    startBtn.hidden = true;
    pipes.forEach(function (p, i) {
        p.x = 1200 + 500*i;
        p.y = 100 + Math.random()*700;
    });
 }

當玩家撞到水管或是地板或是超出上方邊界,執行遊戲結束的函式 gameOver,將會顯示結束 logo 和重新開始的按鈕,並修改飛行狀態為 false

bird.when('touch', [tubeUp, tubeDown], gameOver);
Game.forever(function() {
    if(bird.y > 900 || bird.touched(ground) || bird.touched(pipes)) {
        gameOver();
    }
});
 
function gameOver () {
     running = false;
     startBtn.hidden = false;
     gameOverLogo.hidden = false;
 }

改寫遊戲迴圈的判斷式

Game.forever(function() {
    if(!running) {
        return;
    }
}
範例程式

角色屬性

座標

Sprite.x, Sprite.y角色的 x, y 座標

bird.x = 50;
bird.y = 50;
範例程式

方向

Sprite.direction角色面向的方向,值介於 0 ~ 359 度

bird.direction = 180;
範例程式

縮放

Sprite.sacle角色大小縮放比例,預設為 1

bird.scale = 0.5;
範例程式

旋轉方式

Sprite.rotationStyle角色旋轉的方式,三種方式
full (預設)
flipped (左右翻轉)
fixed (固定不旋轉)

Sprite.rotationStyle = 'fixed'
範例程式

透明度

Sprite.opacity值介於 0 ~ 1

Sprite.opacity
範例程式

造型編號

Sprite.costumeId角色當前造型,造型列表的索引

Sprite.costumeId = 1;
範例程式

圖層

Sprite.layer角色當前所在的圖層

 Sprite.layer = 2;
範例程式

隱藏

Sprite.hiddentrue 設為隱藏,false 設為不隱藏

Sprite.hidden = true;
範例程式

角色方法

移動到

Sprite.moveTo(x, y);x: 目的位置 x 座標
y: 目的位置 y 座標

bird.moveTo(100, 100);
範例程式

移動

Sprite.move(vx, vy);vx: 水平移動距離 vx
vy: 垂直移動距離 vy

Sprite.move(100, 100);
範例程式

朝向前移動

Sprite.stepForward(d);d: 移動的步數

Sprite.stepForward(50);
範例程式

碰到邊界就反彈

Sprite.bounceEdge();

bird.forever(function() {
    this.stepForward(10);
    this.bounceEdge();
});
範例程式

朝向

Sprite.toward(target);target: Sprite 角色對象

Sprite.toward(target);                           
範例程式

綁定事件

Sprite.when(eventName, fun);eventname: 'click', 'touched', 'hover', 'mousedown', 'mouseup'
fun: 事件觸發執行的函式

bird_1.when('click', function() {
    score++;
});
範例程式
bird_1.when('touch', bird_2, function() {
    bird_2.moveTo(10, 10);
});
範例程式
bird_1.when('touch', foods, function() {
    score++;
});
範例程式
bird_1.when('on_mousedown', function() {
    score++;
});
範例程式
bird_1.when('on_mouseup', function() {
    score++;
});
範例程式
bird_1.when('on_hover', function() {
    score++;
});
範例程式

碰撞檢測

sprite.touched(target);target: 若 sprite 碰撞到 target 返回 true

Sprite.touched(target);
範例程式

角色迴圈

Sprite.forever(fun);fun: 不斷執行的函式,this 綁定角色對象

bird.forever(function() {
    this.stepForward(1);
});
範例程式

播放動畫

Sprite.animate(frames, time, callback);frames: 動畫造型的順序
time: 動畫每一秒切換的幀數
callback: 動畫結束後執行的回呼函式

bird.animate([0, 1, 2, 3, 4, 5], 100);
範例程式

銷毀

Sprite.destroy();

bird.destroy();
範例程式

廣播

Sprite.destroy();

bird.when('listen', 'gameOver', function () {
    this.destroy();
});
Game.broadcast('gameOver');
範例程式

角色之間的距離

Sprite.distanceTo();

bird_1.distanceTo(bird_2);
範例程式

事件

Game.on | Game.on綁定遊戲的事件的方法 Sprite.on | Sprite.on綁定角色事件的方法

碰撞 touch

Sprite.on('touch', target, callback);單一對象的碰撞

bird.on('touch', bird, callback);
範例程式

Sprite.on('touch', [target], callback);多個對象的碰撞,可以傳入陣列

bird.on('touch',[bird_1, bird_2], callback);
範例程式

點擊 click

Game.on('click', callback);點擊遊戲場景

Game.on('click', function () {
    bird.scale += 0.5;
});
範例程式

Sprite.on('click', callback);當滑鼠點擊 sprite 執行函式

bird.on('click', bird, function () {
    this.scale += 0.5;
});
範例程式

Sprite.on('click', [bird_1, bird_2, bird_3], callback);當滑鼠點擊 sprite 執行函式

bird.on('click', birds, function () {
    this.scale += 0.5;
});
範例程式

滑鼠按下

Game.on('mousedown', callback);

Game.on('mousedown', function() {
    bird.scale += 1;
});
範例程式

Sprite.on('mousedown', callback);

Game.on('mousedown', bird, function() {
    bird.scale += 1;
});
範例程式

滑鼠放開

Game.on('mouseup', callback);

Game.on('mouseup', function() {
    bird.scale += 1;
});
範例程式

Sprite.on('mouseup', bird, callback);

bird.on('mouseup', function() {
    bird.scale += 1;
});
範例程式

鍵盤按下

Game.on('keydown', keyName, callback);

當按下任意按鍵,執行函式

Game.on('keydown', function() {
    bird.scale += 0.2;        
});
範例程式

當按下特定按鍵,執行函式

Game.on('keydown', keyName, callback);

Game.on('keydown', 'space', function() {
    bird.scale += 0.2;        
});
範例程式

鍵盤放開

on('keyup';, keyName, callback);

當放開任意按鍵,執行函式

Game.on('keyup', function() {
    bird.scale += 0.5;        
});
範例程式

on('keyup';, keyName, callback);

當放開特定按鍵,執行函式

Game.on('keyup', 'space' , function() {
    bird.scale += 0.5;        
});
範例程式

按鍵持續按壓

Game.on('holding', callback);

持續按壓任意按鍵,觸發執行函式,可以傳入 'any' 或是省略參數

Game.on('holding', function() {
    bird.direction += 3;
});
範例程式

Game.on('holding', keyName, callback);

持續按壓特定按鍵,觸發執行函式

Game.on('holding', 'right', function() {
    bird.x += 1;
});
範例程式

鍵盤&滑鼠

滑鼠

Game.cursor.x, Game.cursor.y滑鼠 x,y 座標Game.cursor.left, Game.cursor.right滑鼠左右鍵狀態Game.cursor.isDown滑鼠是否被按住

var cursor = Game.cursor;
forever(function(){
    var y = 80
    print('**滑鼠測試**', 30, y, 'white');
    print('cursor.x: ' + cursor.x, 30, y+ 20, 'white');
    print('cursor.y: ' + cursor.y, 30, y + 2*20, 'white');
    print('cursor.left: ' + cursor.left, 30, y + 3*20, 'white');
    print('cursor.right: ' + cursor.right, 30, y + 4*20, 'white');
    print('cursor.isDown: ' + cursor.isDown, 30, y + 5*20, 'white');
});
範例程式

鍵盤

Game.key[keyName] 鍵盤中特定鍵的狀態

forever(function(){
    var y = 80
    print('**鍵盤測試**', 30, y + 8*20, 'white');
    print('key.q: ' + key.q, 30, y + 9*20, 'white');
    print('key.w: ' + key.w, 30, y + 10*20, 'white');
    print('key.e: ' + key.e, 30, y + 11*20, 'white');
    print('key.r: ' + key.r, 30, y + 12*20, 'white');
});
範例程式

聲音

播放

sound.play(fileName, loop);fileName: 音效素材的路徑
loop: 非必要參數,傳入 true 則音效會不斷反覆播放

sound.play("shoot.mp3");
範例程式
範例程式

設定音量

sound.setVolume(num);num: 0 ~ 1 的音量大小

sound.setVolume(0.5);
範例程式

靜音

sound.mute(bool);bool: 若為 true 則將所有音效靜音

sound.mute(true);
範例程式

停止播放

sound.stop();停止所有的音效

sound.stop();
範例程式

繪筆

畫筆的屬性

設定繪筆的顏色、大小

pen.color繪筆線條的顏色pen.size繪筆線條的寬度尺寸pen.fillColor幾何圖形的填充的顏色

var pen = Game.pen;
 
pen.color = "red";
pen.size = 30;
pen.fillColor = "blue";
範例程式

線條

Game.pen.drawLine(x1, y1, x2, y2);

x1: 起點 x 座標
y1: 起點 y 座標
x2: 終點 x 座標
y2: 終點 y 座標

Game.pen.drawLine(10, 10, 150, 150);
範例程式

矩形

Game.pen.drawRect(x, y, width, height);

x: x 座標
y: y 座標
width: 長
height: 寬

Game.pen.drawRect(400, 40, 200, 100);
範例程式

圓形

Game.pen.drawCircle(x, y, r);

x: 圓心 x 座標
y: 圓心 y 座標
r: 半徑長

Game.pen.drawCircle(200, 100, 100);
範例程式

三角形

Game.pen.drawTriangle(x1, y1, x2, y2, x3, y3);

x1, y1: 角 1 的座標
x2, y2: 角 2 的座標
x3, y3: 角 3 的座標

Game.pen.drawTriangle(200, 200, 300, 300, 200, 300);
範例程式

多邊形

pen.drawCircle(x1, y1, x2, y2, x3, y3, ...);

Game.pen.drawPolygon(320, 240, 520, 120, 520, 420, 100, 400, 100, 200);
範例程式

文字

Game.print(text, x, y, color, size, fontStyle);

text: 文字的內容
x: X 座標
y: Y 座標

color: 顏色 fontStyle: 字型,預設為 "Arial"

Game.print('Hello World!', 300, 400, 'red', 100);
範例程式

Game.pen.drawText(text, x, y, color, size, fontStyle);

text: 文字的內容
x: X 座標
y: Y 座標
font: 字型,預設為 "Arial"

Game.pen.drawText('測試123', 100, 100);
範例程式