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('touch', target, callback);單一對象的碰撞
bird.on('touch', bird, callback);範例程式
Sprite.on('touch', [target], callback);多個對象的碰撞,可以傳入陣列
bird.on('touch',[bird_1, bird_2], callback);範例程式
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);範例程式