Oop lab/simple ship game

จาก Theory Wiki
ไปยังการนำทาง ไปยังการค้นหา
หน้านี้เป็นส่วนหนึ่งของ oop lab

เราจะเขียนเกมยานอวกาศบน Slick2D กัน สำหรับส่วนนี้เราจะได้ทดลองใช้ Slick2D ในการแสดงรูปภาพและอ่านการกดปุ่มจากผู้ใช้แบบการถาม (polling)

โครงสร้างเกมพื้นฐาน

เกมใน Slick2D จะเป็นการทำงานร่วมกันของ object สอง object หลัก คือ

  • Game (อ่าน javadoc) - เป็น object ที่มีเมท็อดพื้นฐานของวนรอบของเกม คือ init, update, และ render
    • void init(GameContainer container)
    • void update(GameContainer container, int delta)
    • void render(GameContainer container, Graphics g)
  • GameContainer (อ่าน javadoc) - เป็น object ที่จัดการเกี่ยวกับการอ่านข้อมูลจากผู้ใช้ (input) การวนรอบเกม และการจัดการเกี่ยวกับการแสดงค่า fps (frame per seconds)

หมายเหตุ: โดยทางเทคนิคแล้ว Game เป็น interface และ GameContainer เป็น abstract class เราจะได้เรียนแนวคิดดังกล่าวต่อไป

เราไม่มีความจำเป็นต้องเขียนคลาส GameContainer ขึ้นมาใหม่ โดยเราจะใช้วัตถุจากคลาส AppGameContainer (ซึ่งจัดเป็น GameContainer ประเภทหนึ่ง) ในโปรแกรมของเรา อย่างไรก็ตาม เราต้องสร้างวัตถุประเภท Game ขึ้นมาเอง เพราะว่านั่นคือแกนหลักของเกมของเรา

เมท็อดทั้งสามมีหน้าที่ดังนี้

  • เมท็อด init จะถูกเรียกเพื่อให้เราเตรียมวัตถุต่าง ๆ ในเกม เราจะสร้างวัตถุต่าง ๆ เก็บไว้กับวัตถุคลาส Game ที่เราสร้าง
  • เมท็อด render มีหน้าที่แสดงภาพหน้าจอ สังเกตว่าเมท็อดจะได้รับ Graphics g มาด้วย เราสามารถสั่งวาดรูปบนหน้าจอได้ผ่านทางวัตถุ g
  • เมท็อด update จะถูกใช้เพื่อปรับค่าต่าง ๆ ของเกม ตัวแปร delta จะเก็บเวลาที่ผ่านไปจากการเรียกเมท็อดครั้งก่อน มีหน่วยเป็นมิลลิวินาที

ลำดับการเรียกเมท็อดจะเป็นดังนี้

init -> render -> update -> render -> update -> render -> update -> ...

เริ่มต้นด้วยเกมว่าง ๆ

สร้าง project ชื่อ shipgame อย่าลืมเพิ่ม Slick2D เข้าไปใน library ใน Build Path (ดูรายละเอียดที่ วิธีติดตั้ง)

จากนั้นให้สร้างคลาสชื่อ ShipGame เมื่อสร้างแล้ว ให้แก้หัวคลาสให้เป็น ดังด้านล่าง (เพิ่ม extends BasicGame)

public class ShipGame extends BasicGame {

เมื่อเพิ่มแล้ว IDE จะแจ้งว่าไม่รู้จัก BasicGame ให้ไปกดให้ IDE เพิ่มการ import ให้เรา โดย IDE น่าจะเพิ่มบรรทัดนี้มาให้ (อย่าลืมเลือกให้ถูก)

import org.newdawn.slick.BasicGame;

IDE จะยังคงบ่นต่อว่าเราไม่มี constructor (เมท็อดที่กำหนดค่าเริ่มต้นให้กับ object ของคลาส) เราก็กดให้มันเพิ่มให้ เราจะได้เมท็อดด้านล่างมา

  public ShipGame(String title) {
    super(title);
  }

ยังไม่พอ IDE ยังบ่นต่อว่าเราไม่ได้ implement method ที่ต้องมี เช่นเคย เราก็กดให้ IDE เติมให้เราโดยอัตโนมัติ มันจะเติมมาให้ 3 เมท็อดดังนี้:

  @Override
  public void render(GameContainer arg0, Graphics arg1) throws SlickException {
    // TODO Auto-generated method stub
  }

  @Override
  public void init(GameContainer arg0) throws SlickException {
    // TODO Auto-generated method stub
  }

  @Override
  public void update(GameContainer arg0, int arg1) throws SlickException {
    // TODO Auto-generated method stub
  }

สังเกตว่าชื่อ argument นั่นดูไม่สื่อความหมายใด ๆ เลย ไปแก้ให้มันดูสื่อความหมายโดยแก้หัวเมท็อดต่าง ๆ ให้เป็นดังนี้

 public void render(GameContainer container, Graphics g) throws SlickException {

 public void init(GameContainer container) throws SlickException {

 public void update(GameContainer container, int delta) throws SlickException {

สังเกตว่า ท้าย signature ของเมท็อด มีคำว่า throws SlickException อยู่ด้วย เราจะอธิบายแนวคิดของ exception ที่ตอนท้ายส่วนนี้

ตอนนี้ไล่ไปไล่มาใน IDE น่าจะไม่มี error อะไรแล้วนะครับ แต่เรายังไม่มีโปรแกรมหลักเลย

ใน Java เมท็อดที่จะเป็นโปรแกรมหลักได้จะต้องชื่อ main และเป็น static method ในคลาสบางคลาส ซึ่งเราก็จะให้อยู่ในคลาส ShipGame นี่เลย

โดยทั่วไปแล้วโปรแกรมหลักของโปรแกรมที่เขียนเชิงวัตถุจะทำหน้าที่แค่สร้าง object ที่จำเป็นแล้วก็จัดการทำให้มันรู้จักกัน แล้วก็เรียก object หลักให้ทำงาน โปรแกรมหลักของเราก็เช่นกัน เพิ่มเมท็อด main ด้านล่างลงในโค้ดของเรา

  public static void main(String[] args) {
    try {
      ShipGame game = new ShipGame("Super Ship Game");
      AppGameContainer appgc = new AppGameContainer(game);
      appgc.setDisplayMode(640, 480, false);
      appgc.start();
    } catch (SlickException e) {
      e.printStackTrace();
    }
  }

อย่าลืมไปสั่งให้ IDE import ของเพื่อให้เรารู้จัก AppGameContainer ด้วย

บรรทัดที่สำคัญมาก ๆ คือ

     ShipGame game = new ShipGame("Super Ship Game");
     AppGameContainer appgc = new AppGameContainer(game);

ซึ่งเป็นบรรทัดที่เราสร้าง object จากคลาส ShipGame และสร้าง AppGameContainer และส่ง game ของเราไปให้

ถ้าเราทดลองรัน เราจะเห็นหน้าจอสีดำเปล่า ๆ ขึ้นมา พร้อมด้วยจำนวน frame per second ที่มุมด้านซ้ายบน

แสดง sprite

ในเกม 2 มิติ ตัวละครที่แสดงบนจอมักจะเป็นรูปที่มีพื้นหลังเป็นสีใส ๆ แสดงทับกันไป รูปดังกล่าวอาจจะมีการเปลี่ยนไปมาเพื่อแสดง animation ก็ได้ เราเรียกรูปดังกล่าวว่า sprite

สร้างรูป sprite

Use a graphical software such as GIMP, Photoshop, Paint.NET to create a 64 pixel x 64 pixel image. Draw a simple spaceship whose head is in an upward direction. Make sure that the background is transparent.

Usually, when the image has transparent background, the graphic editor usually shows it like this:

219245-spaceship-sprite-transparent.png

If you background is not transparent, when you show the sprite you'll see it as an image in a white box.

We will create a directory res in your project directory for keeping all our image assets. Save the image as ship.png in directory res that we have just created.

คลาส Image

คลาสใน Slick2D ที่ใช้แสดงรูปคือคลาส Image

public class ShipGame extends BasicGame {

  private Image shipImage;

  public ShipGame(String title) {
    // ..
  }

  @Override
  public void render(GameContainer container, Graphics g) throws SlickException {
    shipImage.draw(100,100);
  }

  @Override
  public void init(GameContainer container) throws SlickException {
    shipImage = new Image("res/ship.png");
  }
}

ทำให้ยานเคลื่อนที่

บังคับควบคุม

เกมของคุณ