DAY 13
0
Modern Web

## 實戰 - 地圖遊戲超基礎版

### 定義這個程式中有哪些物件

OOP 以物件(object)為思考主體，所以最重要的就是先定義出會有哪些物件：

• 場景物件(Scene)
• 角色物件(Actor)

### Scene 類別

constructor，接收兩個參數(widthheight)，用來定義出這個場景的長寬。

• map：透過 widthheight 計算出一個二維陣列，用來存放目前場景的長相
• actors：存放這個場景中的所有 Actor 實體物件
class Scene {
constructor(width, height) {
const map = new Array(width).fill('-');
for (let i=0; i < map.length; i++) {
map[i] = new Array(height).fill('-');
}
this.map = map;
this.width = width;
this.height = height;
this.actors = [];
}
}
• register：將 Actor 實體物件放到 actors 裡面
• unregister：將指定的 Actor 實體物件移除
class Scene {

// ...

register(actor) {
this.actors.push(actor);
this.map[actor.x][actor.y] = actor.sign;
this.draw();
}

unregister(actor) {
const index = this.actors.indexOf(actor);
this.actors.splice(index, 1);
this.map[actor.x][actor.y] = '-';
this.draw();
}
}
• changeActorPosition：將 Actor 放到新的位置上
class Scene {

// ...

changeActorPosition(actor, x, y) {
// 舊的移除
this.map[actor.x][actor.y] = '-';
// 新的補上
this.map[x][y] = actor.sign;

this.draw();
}
}
• draw：將目前的二維場景(map)畫在 console 上
class Scene {

// ...

draw() {
let display = '';
for (let i = 0; i < this.map.length; i++) {
for (let j = 0; j < this.map[i].length; j++) {
display += this.map[j][i];
}
display += '\n';
}
console.clear();
console.log(display);
}
}

### Actor 類別

constructor，接收四個參數(scenexysign)，分別代表放置的場景、x位置、y位置與代表符號。

class Actor {
constructor(scene, x, y, sign) {
this.scene = scene;
this.x = x;
this.y = y;
this.sign = sign.substr(0, 1);
scene.register(this);
}
}
• exit：離開這個場景(Scene)
class Actor {

// ...

exit() {
this.scene.unregister(this);
}
}
• moveTo：移動到指定的 x,y 位置
class Actor {

// ...

moveTo(x, y) {
const { width, height } = this.scene
if (x < 0 || y < 0 || x >= width || y >= height) {
return
}
this.scene.changeActorPosition(this, x, y);
this.x = x;
this.y = y;
}
}

### 畫圖囉！

class Scene {
constructor(width, height) {
const map = new Array(width).fill('-');
for (let i=0; i < map.length; i++) {
map[i] = new Array(height).fill('-');
}
this.map = map;
this.width = width;
this.height = height;
this.actors = [];
}

register(actor) {
this.actors.push(actor);
this.map[actor.x][actor.y] = actor.sign;
this.draw();
}

unregister(actor) {
const index = this.actors.indexOf(actor);
this.actors.splice(index, 1);
this.map[actor.x][actor.y] = '-';
this.draw();
}

changeActorPosition(actor, x, y) {
// 舊的移除
this.map[actor.x][actor.y] = '-';
// 新的補上
this.map[x][y] = actor.sign;

this.draw();
}

draw() {
let display = '';
for (let i = 0; i < this.map.length; i++) {
for (let j = 0; j < this.map[i].length; j++) {
display += this.map[j][i];
}
display += '\n';
}
console.clear();
console.log(display);
}
}

class Actor {
constructor(scene, x, y, sign) {
this.scene = scene;
this.x = x;
this.y = y;
this.sign = sign.substr(0, 1);
scene.register(this);
}

exit() {
this.scene.unregister(this);
}

moveTo(x, y) {
const { width, height } = this.scene
if (x < 0 || y < 0 || x >= width || y >= height) {
return
}
this.scene.changeActorPosition(this, x, y);
this.x = x;
this.y = y;
}
}

const s = new Scene(10, 10);
const a = new Actor(s, 5, 5, 'A');
const b = new Actor(s, 2, 6, 'B');

• s：場景物件，寬高都是 10
• a：演員物件，以 s 為場景，位置落在 5,5，在地圖上用 A 來代表
• b：演員物件，以 s 為場景，位置落在 2,6，在地圖上用 B 來代表

### 讓角色動起來！

window.addEventListener('keyup', e => {
// 預設操控第一隻角色
const actor = s.actors[0];
switch (e.code) {
case 'ArrowUp':
actor.moveTo(actor.x, actor.y-1);
break;
case 'ArrowDown':
actor.moveTo(actor.x, actor.y+1);
break;
case 'ArrowLeft':
actor.moveTo(actor.x-1, actor.y);
break;
case 'ArrowRight':
actor.moveTo(actor.x+1, actor.y);
break;
default:
break;
}
});

### 最終版

class Scene {
constructor(width, height) {
const map = new Array(width).fill('-');
for (let i=0; i < map.length; i++) {
map[i] = new Array(height).fill('-');
}
this.map = map;
this.width = width;
this.height = height;
this.actors = [];
}

register(actor) {
this.actors.push(actor);
this.map[actor.x][actor.y] = actor.sign;
this.draw();
}

unregister(actor) {
const index = this.actors.indexOf(actor);
this.actors.splice(index, 1);
this.map[actor.x][actor.y] = '-';
this.draw();
}

changeActorPosition(actor, x, y) {
// 舊的移除
this.map[actor.x][actor.y] = '-';
// 新的補上
this.map[x][y] = actor.sign;

this.draw();
}

draw() {
let display = '';
for (let i = 0; i < this.map.length; i++) {
for (let j = 0; j < this.map[i].length; j++) {
display += this.map[j][i];
}
display += '\n';
}
console.clear();
console.log(display);
}
}

class Actor {
constructor(scene, x, y, sign) {
this.scene = scene;
this.x = x;
this.y = y;
this.sign = sign.substr(0, 1);
scene.register(this);
}

exit() {
this.scene.unregister(this);
}

moveTo(x, y) {
const { width, height } = this.scene
if (x < 0 || y < 0 || x >= width || y >= height) {
return
}
this.scene.changeActorPosition(this, x, y);
this.x = x;
this.y = y;
}
}

const s = new Scene(10, 10);
const a = new Actor(s, 5, 5, 'A');
const b = new Actor(s, 2, 6, 'B');

window.addEventListener('keyup', e => {
// 預設操控第一隻角色
const actor = s.actors[0];
switch (e.code) {
case 'ArrowUp':
actor.moveTo(actor.x, actor.y-1);
break;
case 'ArrowDown':
actor.moveTo(actor.x, actor.y+1);
break;
case 'ArrowLeft':
actor.moveTo(actor.x-1, actor.y);
break;
case 'ArrowRight':
actor.moveTo(actor.x+1, actor.y);
break;
default:
break;
}
});

## TODO

• 角色走到牆壁就當掉了
• 角色撞到別的角色就吃掉了(lol)

• 使用 extends，也就是子類別的用法，去擴充 Actor，創造不同類型的角色(比如說每隔兩秒會瞬間移動的角色)
• 增加遊玩價值，放個獎勵或鬼在場景中，加入計分系統等

## 結語

0 與 1

### 1 則留言

0
TD
iT邦新手 4 級 ‧ 2021-09-29 09:34:34

class Scene {
constructor(width, height) {
...
this.width = width
this.height = height
}
...
}
class Actor {
...
moveTo(x, y) {
const { width, height } = this.scene
if (x < 0 || y < 0 || x >= width || y >= height) {
return
}
this.scene.changeActorPosition(this, x, y);
this.x = x;
this.y = y;
}
}
ycchiuuuu iT邦新手 5 級 ‧ 2021-09-29 13:04:11 檢舉

TD 你真的是大家的小精靈欸～超貼心的！