ผลต่างระหว่างรุ่นของ "Se63/typescript/zombie"

จาก Theory Wiki
ไปยังการนำทาง ไปยังการค้นหา
แถว 154: แถว 154:
 
== GamePiece ==
 
== GamePiece ==
  
 +
สร้างคลาส GamePiece
 
<syntaxhighlight lang="typescript">
 
<syntaxhighlight lang="typescript">
 +
class GamePiece {
 +
  constructor(public x: number, public y: number) {}
 +
 +
  getX(): number { return this.x; }
 +
  getY(): number { return this.y; }
 +
  getPieceChar(): string { return '*'; }
 +
}
 +
</syntaxhighlight>
 +
 +
ปรับ Player และ Bot
 +
<syntaxhighlight lang="typescript">
 +
class Player extends GamePiece {
 +
  getPieceChar(): string { return '@'; }
 +
}
 +
 +
class Bot extends GamePiece {
 +
  getPieceChar(): string { return 'B'; }
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
แกะ method <tt>drawPiece</tt>
 
<syntaxhighlight lang="typescript">
 
<syntaxhighlight lang="typescript">
 +
  drawPiece(boardRows: char[][], piece: GamePiece) {
 +
    boardRows[piece.getY()][piece.getX()] = piece.getPieceChar();
 +
  }
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
แล้ววาดของลงไปด้วยโค้ดเดียวกัน (สร้างอาร์เรย์ <tt>elements</tt> ขึ้นมาก่อน โดยรวม this.bots และ this.player
 +
<syntaxhighlight lang="typescript">
 +
    let elements = [...this.bots, this.player];
 +
 +
    let board = this;
 +
    elements.forEach((piece) => {
 +
      board.drawPiece(boardRows, piece);
 +
    });
 +
</syntaxhighlight>
 +
 +
'''หมายเหตุ''': ในฟังก์ชันใน <tt>forEach</tt> เราใช้ this แทน gameBoard ไม่ได้ เพราะว่าจะมีการตีความเป็นอย่างอื่น เลยต้องสร้างตัวแปรพิเศษมาเก็บค่าไว้
  
 
== interface ==
 
== interface ==
  
 
== Bots รูปแบบอื่น ๆ ==
 
== Bots รูปแบบอื่น ๆ ==

รุ่นแก้ไขเมื่อ 07:29, 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 ไม่ได้ เพราะว่าจะมีการตีความเป็นอย่างอื่น เลยต้องสร้างตัวแปรพิเศษมาเก็บค่าไว้

interface

Bots รูปแบบอื่น ๆ