Archive

Archive for the ‘game development’ Category

งาน UAV Community “Unmanned Unlimited” 2014

Categories: C# .NET, game development Tags:

XNA first steps [ เริ่มต้นกับ XNA ]

ช่วงนี้เป็นช่วงที่ผม เรียนเรื่องการเขียนเกมส์ อืม ไม่ได้ความว่าผมจะไปทำเกมส์ขายที่ไหน หรอก ผมทำงานอยู่ในทีมพัฒนาระบบจำลองยุทธ์ และเราก็เล็งเห็นแล้วว่าอีกไม่นาน เทคโนโลยีที่เราใช้กับ ระบบของเรามันกำลังล้าแล้ว เราก็มองหาเทคโนโลยีที่ดีกว่า ใหม่กว่า และยืนยาวกว่า นั่นเอง

พูดแค่นี้ทุกคนก็คงเห็นด้วยเพราะการจะทำระบบอะไรสักอย่าง เงื่อนไขที่ผมกล่าวถือว่าเป็นพื้นฐานแลกที่เราจะมองกัน แล้วค่อยไปพิจาณาเรื่องอื่น ๆ ต่อไป

ครับเอาเป็นว่า ตัวที่ผมสนใจก็คือ XNA
กล่าวโดยย่อนะครับ XNA เป็น Framework ในการพัฒนาเกมส์ที่ผลิตโดย บริษัท Microsoft แน่นอนครับ มันเป็น เทคโนโลยีที่ทำงานบน .NET Framework ซึ่งตัว XNA นั่นประกอบด้วย library และเครื่งมือ ที่จะช่วยให้ผู้พัฒนาเกมส์สามารถทำงานได้รวดเร็ว และสามารถพัฒนาเกมส์ให้สามารถใช้งานได้ บน Windows Xbox 360 รวมถึง Windows Phone 7 ส่วนในรายละเอียดของ XNA ก็ไปอ่านเพิ่มเติมต่อที่นี่ก็แล้วกันนะครับ  http://en.wikipedia.org/wiki/Microsoft_XNA  [ อะไร อะไรก็ wiki นะครับเดี๊ยวนี้ ]

เอาเป็นว่าผมมองตัวนี้ก็เพราะว่า ผมไม่ต้องไปกังวลในเรื่องของการแสดงภาพ เสียง รวมถึงการจัดการกับ input device ต่าง ๆเลย และที่สำคัญ มันทำงานบน development platform ที่ผมใช้งานอยู่แล้ว แค่นี้เป็นอันว่า จบประเด็นข้อเหตุผลในการเลือก

ลองมามองในด้านของ การพัฒนาเกมส์กันบ้างครับ
– เกมส์ programming นั้นจะแตกต่างจากการเขียนโปรแกรม windows  ตามที่เราทราบกันนะครับ การเขียน โปรแกรมบนwindows นั้นเป็นเขียนแบบ event driven หมายถึง code ที่เราเขียน จะอยู่ใน event handler ซึ่งจะถูกเรียกใช้ก็ต่อเมื่อ มีเหตุการณ์อะไรสักอย่างเกิดขึ้น กับ control เช่นการ click mouse เป็นต้น ขี้เกียจ
– เกมส์ programming นั้นเป็น real-time ครับ และก็ไม่มีการรอ event เพื่อการทำงาน  การทำงานจะเป็น loop ที่เราเรียกว่า game loop มีการคำนวณ game status มีการตรวจสอบ input ภายใน loop ในแต่ระรอบของการทำงาน เพราะฉะนั้นการทำงาน programmer จะต้องเขียนโปรแกรมเพื่อ ตรวจสอบ และสั่งการภายใน loop นั่นเองครับ
ดังนั้น typical game loop ประกอบด้วย ขั้นตอน ตามที่แสดงรูปด้านล่าง
จะเห็นว่า loop นั้นเกิดขึ้นใน ส่วนสีเหลือง ซึ่งก็จะมีการรับค่า input คำนวณสถานะต่าง ๆ ของเกมส์ ตรวจสอบ กฎเกณฑ์ต่าง ที่เกมส์กำหนด update ค่า แล้วจึง ให้ feedback กลับไป เช่นการแสดงหล หรือเสียงเป็นต้น ทำอย่างนี้ไปเรื่อย ๆ จนกว่าจะออกจากเกมส์
ส่วน วงรอบเกมส์ของ XNA จะเห็นดังภาพ ครับ


อันที่จริง มันก็ไม่ได้ต่างกัน นัก เพียงแต่ XNA ทำ loop ไว้ให้ โดยทีกำหนดว่า ภายใน update() function ผู้พัฒนาต้อง ตรวจสอบ input คำนวณสถานะ และตรวจสอบ กฎ ต่าง ๆ  และการ feedback ต่าง ๆ ให้ทำใน Draw() function
คงพอได้ concept นะครับ

ลองมาดูการ implement กันบ้างนะครับ

ก่อนที่เราจะทำงาน กับ XNA ได้ก็ต้องมีการ ติดตั้งกันเสียก่อนนะครับ สามารถไป download ได้ที่  http://creators.xna.com/en-US/downloads ตรวจสอบให้ดีนะครับ ท่านควรจะ download version ไหน ขึ้นอยู่กับว่าท่านใช้ visual studio version ไหน ครับซึ่งมันก็หมายถึงท่านใช้ framework version ไหนนั่นเอง 2.0 3.5 หรือ 4.0 ท่าก็เลือก XNA ให้เหมาะสมกับท่าน ได้เลย หลังจากติดตั้งแล้ว ก็มาเริ่มกันเลยนะครับ ( ของผมเองใช้  version 4.0 เพราะผมใช้ visual studio 2010 .Net framework version 4.0  code เป็น C# .net นะครับ)

เริ่มด้วยการ Project ใหม่นะครับ แล้วเลือก Windows Game เราจะพบว่า template ได้มีการสร้าง ไฟล์ให้เรา หลายไฟล์ที่สำคัญก็คือ Game1.cs ซึ่งเป็น file ที่มี game loop และก็ยังมี Content folder ซึ่งมีไว้สำหรับเก็บ พวก resources ต่าง ๆเช่น รูป sprite ที่เราจะใช้งานเป็นต้น

การเพิ่ม หรือ เอารูปที่เตรียมไว้มาใส่ ใน content ก็เพียงแต่ click mouse ขวาที่ content แล้วเลือก “Add/Existing item…” แล้วก็วิ่งไปหา Image file ที่ต้องการ (ship3 คลิก ขวาแล้วเลือก save linke as…)  อ่านตรงนี้ให้ เข้าใจนะครับ เมื่อ เพิ่ม image เข้ามาใน content แล้วลอง click รูปแล้วดู properties จะเห็นว่า มี Asset Name ที่เป็นชื่อของ รูปภาพ ชื่อเหล่านี้จะเก็บไว้สำหรับอ้างอิงในการ เรียกใช้ต่อไป ครับ

สิ่งที่เราต้องการทำใน Project นี้ก็คือการ load ภาพแล้วแสดงในหน้าจอนั่นเอง ครับ ดังนั้นเราก็แค่ ใส่ code ลงใน LoadContent() method เพื่อ load รูป และใส่ code ใน UnloadContent() เพื่อ เอาสิ่งที่ load ออกไป เรายังไม่มีการ ทำอะไรใน Update() เพราะว่าเราแค่แสดงรูปเท่านั้น   และเพื่อแสดงภาพเราก็จะใส code ลงใน Draw() method ตามนี้เลย ครับ

เพื่อให้มันสั้น ผม ลบ comment ออกนะครับ code ที่เราเพิ่มจะอยู่ระหว่าง // — our code #1,2,3,4,5 นะครับ


public class Game1 : Microsoft.Xna.Framework.Game
{
 GraphicsDeviceManager graphics;
 SpriteBatch spriteBatch;
 // -- our code #1 --------------------------
 private Texture2D ship;
 private Vector2 ship_pos;
 // -----------------------------------------
 public Game1()
 {
   graphics = new GraphicsDeviceManager(this);
   // -- our code #2------------------------------
   graphics.PreferredBackBufferHeight = 600;
   graphics.PreferredBackBufferWidth = 800;
   Window.Title = "Game Test ver. 1.0 - Teerapong S.";
   // ------------------------------------------
   Content.RootDirectory = "Content";
 }

 protected override void Initialize()
 {
   // TODO: Add your initialization logic here
   base.Initialize();
 }

 protected override void LoadContent()
 {
   // Create a new SpriteBatch, which can be used to draw textures.
   spriteBatch = new SpriteBatch(GraphicsDevice);

   // TODO: use this.Content to load your game content here
   // --- our code #3 ------------------------------------
    ship = Content.Load<Texture2D>("ship3");  // using asset name นะครับ
  // -----------------------------------------------------

 }

 protected override void UnloadContent()
 {
  // TODO: Unload any non ContentManager content here
  // --- our code #4 ------------
   ship.Dispose();     // free resources, and release memory ไม่มีก็ยังได้
  // -----------------------------
 }

 protected override void Update(GameTime gameTime)
 {
  // Allows the game to exit
  if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
  this.Exit();

  // TODO: Add your update logic here
  base.Update(gameTime);
 }

 protected override void Draw(GameTime gameTime)
 {
   GraphicsDevice.Clear(Color.CornflowerBlue);

   // TODO: Add your drawing code here
   // --- our code # 5 ------------------------
   spriteBatch.Begin();
   spriteBatch.Draw(ship, ship_pos, Color.White);
   spriteBatch.End();
   // -----------------------------------------
   base.Draw(gameTime);
 }
}

จะเห็นว่าเราประกาศ ตัวแปร 2 ตัว  ship และ ship_pos นะครับ เป็น Texture2D กับ Vector2 จะยังไม่ขอ พูดอะไรเกี่ยว variable type ครับแล้วเรามีการกำหนด ค่าเริ่มต้น ใน constructor นิดหน่อย เป็นการกำหนด ขนาด windows สำหรับแสดงภาพ  our code #2

ต่อมาใน loadContent เราทำการ load resource ชื่อว่า ship3 ตรวจสอบ asset name ของresources ให้ดีนะครับ ไม่จะเป็นต้องตรงกับชื่อไฟล์ก็ได้ ถ้าหากเราไม่ได้มีการแกไขส่วนใหญ่จะต้องกลับชื่อไฟล์

ใน UnloadContent ใส่ไว้เพื่อ unload resource นั่น ๆ นะครับ ผมเข้าใจว่าอาจไม่ต้อง ก็ได้ ปล่อยให้ framework มันจัดการเอง [ ปกติถ้าเรา เขียน c++ หรือ c ต้องกำจัดให้หมด ]

สุดท้ายเรา draw เพื่อแสดงรูป นะครับ

สังเกตว่าการแสดงผลใด ๆ ก็ตามต้อง อยู่ระหว่าง spriteBatch.Begin() และ spriteBatch.End()

ลอง run ดู จะได้รูปเรือ ขนาดเท่าต้นฉบับบ แสดงอยู่ที่ตำแหน่ง x = 400 , y = 300  ( นับจากมุม บนซ้าย x เป็นแนวนอน y เป็น แนวตั้งนะครับ ,มุมบนซ้าย เป็นตำแหน่ง x = 0 , y = 0 )

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

หากต้องการให้มีการเคลื่อนที่จะต้องทำอย่างไร ลองคิดดูครับ …………………………….. ใช้แล้วเปลี่ยน ค่า ship_pos

Ship_pos instance ของ  class Vector2 เป็นซึ่ง coordinate ในระนาบ 2 มิติ มีแค่ค่า x,y เท่านั้น เพราะฉะนั้นการเคลือน ภาพก็ต้องทำการ บวกหรือ ลบ ค่า X หรือ Y นี่แหละครับ และจะต้องทำภายใน Update() mehtod ตาม code ที่แสดงด้านล่าง นะครับ


protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
// ourcode #6 ----------------------------
KeyboardState keystate = Keyboard.GetState();
//ขึ้นบน
if (keystate.IsKeyDown(Keys.Up))
ship_pos = new Vector2(ship_pos.X, ship_pos.Y - 0.5f);
//ลงล่าง
if (keystate.IsKeyDown(Keys.Down))
ship_pos = new Vector2(ship_pos.X, ship_pos.Y + 0.5f);

// ไปซ้าย
if (keystate.IsKeyDown(Keys.Left))
ship_pos = new Vector2(ship_pos.X - 0.5f , ship_pos.Y );
// ไปขวา
if (keystate.IsKeyDown(Keys.Right))
ship_pos = new Vector2(ship_pos.X + 0.5f, ship_pos.Y );
// ---------------------------------------
base.Update(gameTime);
}

Code มีความหมาย ตาม remark ไว้ไห้

เป็นการตรวจจับ keyboard ว่ามีการ กดปุ่ม หัวลูกศรหรือป่าว และเป็น หัวลูกศรทิศไหน ก็ ดำเนินการกับ ดำแปร ship_pos ในด้านที่ ควรจะเป็น ถ้าไม่เข้าใจ ลอง ร่างหน้าจอใน กระดาษดูนะครับ แล้วจะเข้าใจเอง ขี้เกียจอธิบาย lazy  อะ
เอาดูจากรูป ก็แล้วกัน

ส่วนใคร ไม่เข้าใจการเพิ่มค่า shiop_pos.X และ ship_pos.Y ลองทำแบบนี้แทนก็ได้

Ship_pos.Y -= 0.5f ;

หรือ

Ship_pos.Y = Ship_pos.Y – 0.5f ;

ใครไม่เข้าใจอะไร ก็ลอง mail มาคุยกันก็ได้ หรือ คุยกันผ่านทาง blog ก็ได้

ขอให้สนุกสนานกับการเริ่มต้น กับ XNA  นะครับ

ธีระพงษ สนธยามาลย์

Teerapong Sontayaman

s_teerapong2000@yahoo.com


Categories: C# .NET, game development, XNA Tags:

XNA Game Development [เริ่มต้นกับ XNA]

June 10, 2011 Leave a comment

Categories: game development, XNA

Real-Time Framework [ Single- to Multi-Server Online Game ]

ได้มีโอกาสร่วมอยู่ในงานวิจัย และพัฒนาเกมที่เป็นกึ่ง ๆ online game  แบบ single-server ซึ่ง เดินมาถึงจุดที่ single – server ไม่สามารถให้บริการได้เนื่องจาก มี ผู้ใช้มากขึ้น และจำนวน object หรือ entity ก็มากขึ้นเป็นเงาตามตัวเช่นเดียวกัน  การพัฒนาก็เริ่มมอง หา solution ทำจะช่วยแก้ปัญหาโดยต้องใช้ เวลา และ แรงงาน  ไม่มากนัก  และ RTF ก็เป็น solution หนึ่งที่ น่าสนใจเป็นอย่างยิ่ง ครับ

Real-Time Framework หรือ RTF คือ middleware ที่จะช่วยให้เราสามารถเปลี่ยน Single-Server ให้เป็น Multi-Server online game ครับ  อ้างจาก cast study ที่อ้างอิงในบทความนี้ นะครับว่า  game ประเภท Fast-paced action เช่น First Persons Shooters หรือ FPS นั้น หากต้องการความสามารถ ในการ ขยายระบบรองรับผู้เล่นจำนวนมาก แล้วละก็ ต้องมี สถาปัตยกรรม แบบ multi-server ถึง จะทำได้  แต่การทำ mult-server นั้นเป็นงานที่ท้าทายต่อผู้พัฒนา  เนื่องจาก การประมวลผลจะต้องเป็นการประมวลผลแบบ ขนาน และการ distribute game state  ก็ต้องทำอย่าง มีประสิทธิภาพ  ครับ สองงานหลัก ๆ ที่ game แบบ multi-server นั้นต้อง จัดการให้ได้ ก็คือ เรื่องของการ ทำให้เป็นการประมวลผลแบบขนาน และ การประสานงาน การแจกจ่ายสถานะของ game ให้ได้ประสิทธิภาพ

เนื่องจากว่า มุมมองที่เราจะนำ RTF มาใช้งานก็คือผู้พัฒนา ที่มี game ที่เป็น single-server เป็นของตัวเองอยู่แล้ว และต้องการ ปรับปรุง ให้เป็น multi-server โดยที่ไม่ต้องไปลือระบบของตัวเอง จนแทบจะเรียกได้ว่า ต้องทำกันไหม อะไร แบบนั้นอะครับ  เนื่องจากว่า RTF นั้น จะช่วย ในเรื่องของ การทำ parallelization  และ การจัดการกับ game state โดยเฉพาะในเรื่องของการแจกจ่าย game state ให้อัตโนมัติ  ผุ้พัฒนาที่ใช้ RTF ไม่ต้องเข้าไปดำเนินการเรื่องนี้ เพียงแค่เรียกใช้ผ่าน hight level support ของ RTF เท่านั้นเอง

เพื่อให้ภาพนะครับ ดูจากภาพ แรก

จากภาพเป็นโครงสร้างและการทำงานของ game แบบ single-server นะครับ จะเห็นว่า server เพียงตัวเดียวควบคุมการทำงานทั้งหมด  การคำนวน game states การโต้ตอบกับ ผู้ใช้ และการกระจาย game states กลับไปให้ client ทั้งหมด  ครับ รูปต่อไป


จากภาพแสดงให้เป็น สถาปัตยกรรมแบบ Multi-server game จะเห็นว่า งานการประมวลผล game state การโต้ตอบกับผู้ใช้และการ กระจาย game state นั้นถูกแบ่งออกไป ให้ server อื่น ๆ ช่วยทำงาน  ซึ่งจะเห็นได้ว่า แน่นอนครับการขยายระบบ การเพิ่มจำนวนผู้เล่น ย่อมเกิดขึ้นได้ โดยสถาปัตยกรรมแบบ mult-server

ปัญหาคือว่า ผู้พัฒนาที่มี game ที่เป็น single-server อยู่ในมือจะทำให้เป็น mult-server ได้ด้วย RTF อย่างไร     (ตามที่ได้กล่าวไปแล้วว่า RTF จะช่วยให้ เราเปลี่ยจาก single-server เป็นเป็น Multi-server ได้) จะขอไว้ต่อใน คราวหน้านะครับ

s_teerapong2000@yahoo.com – Soft Speed Solution

Reference
[From a Single- to Multi-Server Online Game: A Quake 3 Case Study Using RTF  , Alexander Ploss, Stefan Wichmann, Frank Glinka , and Sergei Gorlatch  University of Munster, Germany]