ผลต่างระหว่างรุ่นของ "Oop lab/objects co-ordination"
Jittat (คุย | มีส่วนร่วม) (หน้าที่ถูกสร้างด้วย ': ''หน้านี้เป็นส่วนของ oop lab''') |
Jittat (คุย | มีส่วนร่วม) |
||
(ไม่แสดง 17 รุ่นระหว่างกลางโดยผู้ใช้คนเดียวกัน) | |||
แถว 1: | แถว 1: | ||
− | : '' | + | : ''หน้านี้เป็นส่วนหนึ่งของ [[oop lab]]'' |
+ | |||
+ | มีสองแนวทางหลัก ๆ ในการจัดการประสานงานระหว่าง object ในเกม | ||
+ | |||
+ | * Game เป็นตัวประสานงานจัดการทั้งหมด | ||
+ | * ให้ object ต่าง ๆ จัดการกันเอง และแจ้ง Game เฉพาะเมื่อเกิดเหตุการณ์สำคัญ | ||
+ | |||
+ | [[Image:Game-control.png]] | ||
+ | |||
+ | อย่างไรก็ตาม ไม่ใช่ว่าแต่ละเกมจะต้องมีรูปแบบในการติดต่อแบบเดียว ในเกมหนึ่ง ๆ อาจจะมีทั้งส่วนที่ Game เป็นคนจัดการและส่วนที่ object จัดการกันเองด้วยก็ได้ | ||
+ | |||
+ | == Game เป็นตัวประสานงานทั้งหมด == | ||
+ | |||
+ | เกมที่เราเขียนมาทั้งหมด โดยมากจากอยู่ในรูปแบบนี้ ทั้ง [[Oop lab/simple ship game|Ship game]] และ [[Oop lab/flappy dot|Flappy dot]] | ||
+ | |||
+ | == Object ติดต่อกันเอง == | ||
+ | การที่ object จะจัดการกิจกรรมอื่น ๆ ได้เองนั้น object จะต้องอ้างถึง object อื่น ๆ ที่เกี่ยวข้องได้ด้วย นอกจากนี้ ในบางครั้งที่เกิดเหตุการณ์ที่สำคัญ เช่น game over แล้ว object จะต้องสามารถแจ้งผลต่าง ๆ ให้กับ Game ได้ด้วย | ||
+ | |||
+ | === การอ้างถึงวัตถุอื่น ๆ ในเกม === | ||
+ | สามารถดำเนินการได้หลายแบบ | ||
+ | |||
+ | ==== 1. เก็บไว้เป็น field ==== | ||
+ | ในกรณีที่ object ของคุณมีจำนวนไม่มาก คุณอาจจะเก็บ field ของวัตถุอื่นไว้ใน object ก็ได้ ยกตัวอย่างเช่น ถ้าคุณมีผู้เล่นสองคน อาจจะเก็บผู้เล่นอีกฝ่ายเป็น field ได้ | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | class Player { | ||
+ | private Player otherPlayer = null; | ||
+ | |||
+ | //... | ||
+ | public setOtherPlayer(player) { | ||
+ | otherPlayer = player; | ||
+ | } | ||
+ | //... | ||
+ | public isHit() { | ||
+ | //... now you can access the other player with otherPlayer field. | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ในส่วน init ใน Game อาจเป็นดังนี้ | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | public init() { | ||
+ | player1 = new Player(); | ||
+ | player2 = new Player(); | ||
+ | player1.setOtherPlayer(player2); | ||
+ | player2.setOtherPlayer(player1); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== 2. อ้างผ่านทาง Game ==== | ||
+ | ถ้าเราต้องการอ้าง object ในเกมที่เปลี่ยนไปมา เช่น monster เพิ่มขึ้นเรื่อย ๆ หรือกระสุนที่เปลี่ยนไปมา ตัว object เอง จะไม่สามารถเก็บวัตถุพวกนี้ได้ (เพราะว่ามีการแก้ไขตลอด) อีกทางที่เราทำได้คืออ้างถึงผ่านทาง Game | ||
+ | |||
+ | อย่างไรก็ตามถ้าเราต้องการใช้วิธีนี้ เราจะต้องให้ object อ้างถึง Game ได้ด้วย โดยทำได้สองแบบหลัก ๆ คือ | ||
+ | |||
+ | '''2.1 เพิ่ม field game ในวัตถุ''' | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | class Player { | ||
+ | private Game game; | ||
+ | |||
+ | public Player(Game game) { | ||
+ | //... | ||
+ | this.game = game; | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | และกำหนดค่าให้เมื่อสร้าง object เหล่านี้ | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | public void init() { | ||
+ | //... | ||
+ | player1 = new Player(this); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | '''2.2 อ้างผ่านคลาส Game''' | ||
+ | |||
+ | ในคลาส game ของเรา เราอาจจะมี static method เพื่ออ้างถึง instance ของคลาสได้ | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | class MySampleGame extends BasicGame { | ||
+ | private static MySampleGame currentGame = null; | ||
+ | |||
+ | //... | ||
+ | public static getCurrentGame() { | ||
+ | return MySampleGame.currentGame; | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | try { | ||
+ | MySampleGame.currentGame = new MySampleGame("Super Ship Game"); | ||
+ | AppGameContainer appgc = new AppGameContainer(MySampleGame.currentGame); | ||
+ | appgc.setDisplayMode(640, 480, false); | ||
+ | appgc.start(); | ||
+ | } catch (SlickException e) { | ||
+ | e.printStackTrace(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | โดยคลาส Player จะสามารถอ้างถึง game ได้ โดยสั่งเช่น | ||
+ | |||
+ | game = MySampleGame.getCurrentGame(); | ||
+ | |||
+ | ลักษณะการเขียนแบบนี้ ถ้าเขียนให้รัดกุมขึ้นสามารถอ่านรายละเอียดเพิ่มได้ที่ [http://en.wikipedia.org/wiki/Singleton_pattern Singleton Pattern] จาก wikipedia | ||
+ | |||
+ | {{กล่องเทา|'''ข้อควรระวัง''' เราควรจะใช้ static เท่าที่จำเป็น ไม่ควรเก็บทุกสิ่งทุกอย่างเป็น static public หมดเพื่อความง่ายในการอ้างถึง เพราะว่าการใช้ตัวแปรแบบ static คือการสร้างการขึ้นต่อกันกับคลาส ซึ่งจะทำให้เราทดสอบโปรแกรมยากมากในอนาคต ตัวแปรแบบ static ก็เปรียบเสมอตัวแปร global ในรูปแบบหนึ่งนั่นเอง}} | ||
+ | |||
+ | เมื่อเราอ้างถึง game ได้แล้ว เราอาจจะเพิ่มเมท็อดในการอ้างถึงวัตถุต่าง ๆ ในเกม เช่น | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | class MySampleGame extends BasicGame { | ||
+ | private LinkedList<Monster> monsters; | ||
+ | |||
+ | public List<Monster> getMonsters() { | ||
+ | return monsters; | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | โค้ด Player อาจเป็นดังนี้ | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | public boolean isHit() { | ||
+ | |||
+ | //-------------------------------------- | ||
+ | // approach 1: keep field | ||
+ | List<Monster> monsters = game.getMonsters(); | ||
+ | |||
+ | //-------------------------------------- | ||
+ | // approach 2: get it from class Game | ||
+ | List<Monster> monsters = MySampleGamge.getMonsters(); | ||
+ | |||
+ | for (Monster monster : monsters) { | ||
+ | // doSomething.... | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === การแจ้งเหตุการณ์ === | ||
+ | เมื่อมีเหตุการณ์ที่เราจำเป็นต้องแจ้งกับ game วิธีที่ทำได้ง่าย ๆ ถ้าเราสามารถอ้างถึงคลาส game ได้ คือการให้ object เรียกเมท็อดที่ต้องการในคลาส game | ||
+ | |||
+ | ยกตัวอย่างเช่น เราอาจจะสร้างเมท็อด monsterHit ในคลาส MySampleGame | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | class MySampleGame externs BasicGame { | ||
+ | public void monsterHit(Monster monster) { | ||
+ | //.... | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | จากนั้นในเมท็อดที่ object เราก็สามารถเรียกเมท็อดดังกล่าวได้ | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | public boolean isHit() { | ||
+ | //... | ||
+ | for (Monster monster : monsters) { | ||
+ | if (monster.closeTo(this)) { //... any condition you like. | ||
+ | game.monsterHit(monster) | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> |
รุ่นแก้ไขปัจจุบันเมื่อ 09:33, 22 กันยายน 2557
- หน้านี้เป็นส่วนหนึ่งของ oop lab
มีสองแนวทางหลัก ๆ ในการจัดการประสานงานระหว่าง object ในเกม
- Game เป็นตัวประสานงานจัดการทั้งหมด
- ให้ object ต่าง ๆ จัดการกันเอง และแจ้ง Game เฉพาะเมื่อเกิดเหตุการณ์สำคัญ
อย่างไรก็ตาม ไม่ใช่ว่าแต่ละเกมจะต้องมีรูปแบบในการติดต่อแบบเดียว ในเกมหนึ่ง ๆ อาจจะมีทั้งส่วนที่ Game เป็นคนจัดการและส่วนที่ object จัดการกันเองด้วยก็ได้
เนื้อหา
Game เป็นตัวประสานงานทั้งหมด
เกมที่เราเขียนมาทั้งหมด โดยมากจากอยู่ในรูปแบบนี้ ทั้ง Ship game และ Flappy dot
Object ติดต่อกันเอง
การที่ object จะจัดการกิจกรรมอื่น ๆ ได้เองนั้น object จะต้องอ้างถึง object อื่น ๆ ที่เกี่ยวข้องได้ด้วย นอกจากนี้ ในบางครั้งที่เกิดเหตุการณ์ที่สำคัญ เช่น game over แล้ว object จะต้องสามารถแจ้งผลต่าง ๆ ให้กับ Game ได้ด้วย
การอ้างถึงวัตถุอื่น ๆ ในเกม
สามารถดำเนินการได้หลายแบบ
1. เก็บไว้เป็น field
ในกรณีที่ object ของคุณมีจำนวนไม่มาก คุณอาจจะเก็บ field ของวัตถุอื่นไว้ใน object ก็ได้ ยกตัวอย่างเช่น ถ้าคุณมีผู้เล่นสองคน อาจจะเก็บผู้เล่นอีกฝ่ายเป็น field ได้
class Player {
private Player otherPlayer = null;
//...
public setOtherPlayer(player) {
otherPlayer = player;
}
//...
public isHit() {
//... now you can access the other player with otherPlayer field.
}
}
ในส่วน init ใน Game อาจเป็นดังนี้
public init() {
player1 = new Player();
player2 = new Player();
player1.setOtherPlayer(player2);
player2.setOtherPlayer(player1);
}
2. อ้างผ่านทาง Game
ถ้าเราต้องการอ้าง object ในเกมที่เปลี่ยนไปมา เช่น monster เพิ่มขึ้นเรื่อย ๆ หรือกระสุนที่เปลี่ยนไปมา ตัว object เอง จะไม่สามารถเก็บวัตถุพวกนี้ได้ (เพราะว่ามีการแก้ไขตลอด) อีกทางที่เราทำได้คืออ้างถึงผ่านทาง Game
อย่างไรก็ตามถ้าเราต้องการใช้วิธีนี้ เราจะต้องให้ object อ้างถึง Game ได้ด้วย โดยทำได้สองแบบหลัก ๆ คือ
2.1 เพิ่ม field game ในวัตถุ
class Player {
private Game game;
public Player(Game game) {
//...
this.game = game;
}
}
และกำหนดค่าให้เมื่อสร้าง object เหล่านี้
public void init() {
//...
player1 = new Player(this);
}
2.2 อ้างผ่านคลาส Game
ในคลาส game ของเรา เราอาจจะมี static method เพื่ออ้างถึง instance ของคลาสได้
class MySampleGame extends BasicGame {
private static MySampleGame currentGame = null;
//...
public static getCurrentGame() {
return MySampleGame.currentGame;
}
public static void main(String[] args) {
try {
MySampleGame.currentGame = new MySampleGame("Super Ship Game");
AppGameContainer appgc = new AppGameContainer(MySampleGame.currentGame);
appgc.setDisplayMode(640, 480, false);
appgc.start();
} catch (SlickException e) {
e.printStackTrace();
}
}
}
โดยคลาส Player จะสามารถอ้างถึง game ได้ โดยสั่งเช่น
game = MySampleGame.getCurrentGame();
ลักษณะการเขียนแบบนี้ ถ้าเขียนให้รัดกุมขึ้นสามารถอ่านรายละเอียดเพิ่มได้ที่ Singleton Pattern จาก wikipedia
ข้อควรระวัง เราควรจะใช้ static เท่าที่จำเป็น ไม่ควรเก็บทุกสิ่งทุกอย่างเป็น static public หมดเพื่อความง่ายในการอ้างถึง เพราะว่าการใช้ตัวแปรแบบ static คือการสร้างการขึ้นต่อกันกับคลาส ซึ่งจะทำให้เราทดสอบโปรแกรมยากมากในอนาคต ตัวแปรแบบ static ก็เปรียบเสมอตัวแปร global ในรูปแบบหนึ่งนั่นเอง
เมื่อเราอ้างถึง game ได้แล้ว เราอาจจะเพิ่มเมท็อดในการอ้างถึงวัตถุต่าง ๆ ในเกม เช่น
class MySampleGame extends BasicGame {
private LinkedList<Monster> monsters;
public List<Monster> getMonsters() {
return monsters;
}
}
โค้ด Player อาจเป็นดังนี้
public boolean isHit() {
//--------------------------------------
// approach 1: keep field
List<Monster> monsters = game.getMonsters();
//--------------------------------------
// approach 2: get it from class Game
List<Monster> monsters = MySampleGamge.getMonsters();
for (Monster monster : monsters) {
// doSomething....
}
}
การแจ้งเหตุการณ์
เมื่อมีเหตุการณ์ที่เราจำเป็นต้องแจ้งกับ game วิธีที่ทำได้ง่าย ๆ ถ้าเราสามารถอ้างถึงคลาส game ได้ คือการให้ object เรียกเมท็อดที่ต้องการในคลาส game
ยกตัวอย่างเช่น เราอาจจะสร้างเมท็อด monsterHit ในคลาส MySampleGame
class MySampleGame externs BasicGame {
public void monsterHit(Monster monster) {
//....
}
}
จากนั้นในเมท็อดที่ object เราก็สามารถเรียกเมท็อดดังกล่าวได้
public boolean isHit() {
//...
for (Monster monster : monsters) {
if (monster.closeTo(this)) { //... any condition you like.
game.monsterHit(monster)
}
}
}