ผลต่างระหว่างรุ่นของ "Se63/typescript/zombie"
Jittat (คุย | มีส่วนร่วม) |
Jittat (คุย | มีส่วนร่วม) |
||
แถว 194: | แถว 194: | ||
'''หมายเหตุ''': ในฟังก์ชันใน <tt>forEach</tt> เราใช้ this แทน gameBoard ไม่ได้ เพราะว่าจะมีการตีความเป็นอย่างอื่น เลยต้องสร้างตัวแปรพิเศษมาเก็บค่าไว้ | '''หมายเหตุ''': ในฟังก์ชันใน <tt>forEach</tt> เราใช้ this แทน gameBoard ไม่ได้ เพราะว่าจะมีการตีความเป็นอย่างอื่น เลยต้องสร้างตัวแปรพิเศษมาเก็บค่าไว้ | ||
+ | |||
+ | == move bots == | ||
+ | เราทิ้งโค้ดเมทอด <tt>moveBots</tt> ไว้ เป็นโค้ดที่เรียกแล้วจะมีปัญหา (เพราะว่ายังใช้ botXs อยู่เลย) เราจะเขียนเมท็อดในการเดินไว้ในคลาส Bot เลย ดังนี้ | ||
+ | |||
+ | <syntaxhighlight lang="typescript"> | ||
+ | class Bot extends GamePiece { | ||
+ | getPieceChar(): string { return 'B'; } | ||
+ | |||
+ | move() { | ||
+ | this.x--; | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <syntaxhighlight lang="typescript"> | ||
+ | moveBots() { | ||
+ | for (let i=0; i < this.botCount; i++) { | ||
+ | this.bots[i].move(); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
== interface == | == interface == | ||
== Bots รูปแบบอื่น ๆ == | == Bots รูปแบบอื่น ๆ == |
รุ่นแก้ไขเมื่อ 07:33, 10 กรกฎาคม 2563
เนื้อหา
โค้ดเริ่มต้น
ใส่ใน jsfiddle
ส่วน HTML
<html>
<body>
<pre id="gameBoard"></pre>
</body>
</html>
ส่วน Typescript (เลือก Javascript เปลี่ยนภาษาเป็น Typescript)
const boardHeight = 30;
const boardWidth = 50;
class GameBoard {
constructor() {
this.pX = 25;
this.pY = 15;
this.botCount = 5;
this.botXs = [10,20,30,40,50];
this.botYs = [5,10,20,15,25,12]
}
showBoard() {
let boardRows = [];
for (let i = 0; i < boardHeight; i++) {
let rowChars = [];
for (let j = 0; j < boardWidth; j++) {
rowChars.push(' ');
}
boardRows.push(rowChars);
}
boardRows[this.pY][this.pX] = '@';
for (let i = 0; i < this.botCount; i++) {
boardRows[this.botYs[i]][this.botXs[i]] = 'B';
}
let boardStr = boardRows.map((row) => {
return row.join('') + "\n";
}).join('');
let boardElement = document.getElementById('gameBoard');
boardElement.innerHTML = boardStr;
}
moveBots() {
for (let i=0; i < this.botCount; i++) {
this.botXs[i]--;
}
}
step() {
this.moveBots();
this.showBoard();
}
}
gameBoard = new GameBoard();
gameBoard.showBoard();
ทำความเข้าใจกันก่อน
- gameBoard เป็น global ทำให้เราเรียก gameBoard.step() ใน console ให้เกมทำงานทีละขั้นได้
clean showBoard กันก่อน
เมทอด showBoard นั้นค่อนข้างยาวและอ่านยาก เราจะแยกเป็น method ย่อย ๆ โดยเราจะแยกเป็น initBoardArray, boardArrayToStr กับ showBoardArray
initBoardArray(): char[][] {
let boardRows = [];
for (let i = 0; i < boardHeight; i++) {
let rowChars = [];
for (let j = 0; j < boardWidth; j++) {
rowChars.push(' ');
}
boardRows.push(rowChars);
}
return boardRows;
}
boardArrayToStr(boardRows: char[][]): string {
return boardRows.map((row) => {
return row.join('') + "\n";
}).join('');
}
showBoardArray(boardRows: char[][]) {
let boardElement = document.getElementById('gameBoard');
boardElement.innerHTML = this.boardArrayToStr(boardRows);;
}
showBoard() {
let boardRows = this.initBoardArray();
boardRows[this.pY][this.pX] = '@';
for (let i = 0; i < this.botCount; i++) {
boardRows[this.botYs[i]][this.botXs[i]] = 'B';
}
this.showBoardArray(boardRows);
}
แกะ player และ bots
เราจะทำให้โค้ดอ่านง่ายขึ้นและแก้ไขได้ง่ายขึ้น ในแนวคิดแบบ object-oriented เราจะพยายามจับกลุ่ม "ของ" ที่อยู่ด้วยกันบ่อย ๆ ให้กลายเป็นชิ้นขึ้นมา (เป็นวัตถุ) สังเกตว่าในระบบของเรามีข้อมูลที่ต้องอยู่ด้วยกันอยู่สองชุดคือ
ตำแหน่งของ bot และ
this.botXs = [10,20,30,40,50];
this.botYs = [5,10,20,15,25,12]
ตำแหน่งของผู้เล่น
this.pX = 25;
this.pY = 15;
และทั้งสองกลุ่มมีการทำงานใกล้เคียงกันเมื่อพิจารณาในส่วนของการแสดงข้อมูล เราจะสร้างคลาส Bot และ Player เพื่อเก็บตำแหน่งของ bot และ player ไว้ดังนี้ (เพิ่มไว้ก่อนคลาส GameBoard)
class Player {
constructor(public x: number, public y: number) {}
}
class Bot {
constructor(public x: number, public y: number) {}
}
จากนั้นแก้ส่วน showBoard
showBoard() {
// ...
boardRows[this.player.y][this.player.x] = '@';
for (let i = 0; i < this.botCount; i++) {
boardRows[this.bots[i].y][this.bots[i].x] = 'B';
}
// ...
}
สังเกตว่าส่วน showBoard โค้ดยังดูซ้ำ ๆ กันอยู่ ขั้นตอนไปเราจะสร้าง abstraction ไปอีกชั้นหนึ่ง เพื่อให้ครอบทั้ง player และ bot
GamePiece
สร้างคลาส GamePiece
class GamePiece {
constructor(public x: number, public y: number) {}
getX(): number { return this.x; }
getY(): number { return this.y; }
getPieceChar(): string { return '*'; }
}
ปรับ Player และ Bot
class Player extends GamePiece {
getPieceChar(): string { return '@'; }
}
class Bot extends GamePiece {
getPieceChar(): string { return 'B'; }
}
แกะ method drawPiece
drawPiece(boardRows: char[][], piece: GamePiece) {
boardRows[piece.getY()][piece.getX()] = piece.getPieceChar();
}
แล้ววาดของลงไปด้วยโค้ดเดียวกัน (สร้างอาร์เรย์ elements ขึ้นมาก่อน โดยรวม this.bots และ this.player
let elements = [...this.bots, this.player];
let board = this;
elements.forEach((piece) => {
board.drawPiece(boardRows, piece);
});
หมายเหตุ: ในฟังก์ชันใน forEach เราใช้ this แทน gameBoard ไม่ได้ เพราะว่าจะมีการตีความเป็นอย่างอื่น เลยต้องสร้างตัวแปรพิเศษมาเก็บค่าไว้
move bots
เราทิ้งโค้ดเมทอด moveBots ไว้ เป็นโค้ดที่เรียกแล้วจะมีปัญหา (เพราะว่ายังใช้ botXs อยู่เลย) เราจะเขียนเมท็อดในการเดินไว้ในคลาส Bot เลย ดังนี้
class Bot extends GamePiece {
getPieceChar(): string { return 'B'; }
move() {
this.x--;
}
}
moveBots() {
for (let i=0; i < this.botCount; i++) {
this.bots[i].move();
}
}