Upload
tara
View
115
Download
6
Tags:
Embed Size (px)
DESCRIPTION
418383 การเขียนโปรแกรมเกม User Interface Programming. ประมุข ขันเงิน [email protected]. Game User Interface. Game User Interface. Game User Interface. เราต้องการ control ลักษณะคล้ายกับของโปรแกรมประยุกต์ทั่วไป ปุ่มกด radio button check box drop down list box sliders ฯลฯ. - PowerPoint PPT Presentation
Citation preview
418383 การเขยนโปรแกรมเกมUser Interface Programming
ประมข ขนเงน[email protected]
Game User Interface
Game User Interface
Game User Interface
• เราตองการ control ลกษณะคลายกบของโปรแกรมประยกตทวไป– ปมกด– radio button– check box– drop down list box– sliders– ฯลฯ
วธการสราง User Interface
• เขยนเองทกอยาง–
• ใชไลบรารทคนอนสรางไว– ใช WinForms• Control อยขางนอก XNA• เหมาะสำาหรบใชเวลาสราง editor ตางๆ
– ใชไลบรารสำาหรบสราง User Interface ในเกมโดยเฉพาะ• Control อยใน XNA• เหมาะสำาหรบใชสราง user interface ในเกม
การใช XNA กบ WINFORMS
การทำางานของ XNA ปกต• เรา subclass Game• Game สรางหนาตางหนงหนาตางสำาหรบเกมของคณ
• เรา override เมธอด Update และ Draw
• บางกรณเราอาจพบวา framework นมขอจำากด– บางครงคณอยากจะสรางหนาตางเอง– บางครงคณอาจจะอยากสราง editor สำาหรบเกม
Microsoft.Xna.Framework.Game
• XNA ประกอบดวย assembly หลายๆ ตว– Microsoft.Xna.Framework– Microsoft.Xna.Framework.Graphics– Microsoft.Xna.Framework.Content– ฯลฯ
• Microsoft.Xna.Framework.Game มคลาส Game ทเปนโคดระดบสงทใช assembly
อน ในการสราง application สำาหรบเกมโดยเฉพาะ
การรนโคดเกมดวยวธอน• คณตองสรางคลาสททำาหนาทแทน Game• ในทนเราจะสราง control ทโคด XNA สามารถวาดรปใสได
• แลวเอา control นไปเปนสวนประกอบของ โปรแกรมทใช Windows Forms ธรรมดา
• โคดตวอยางทอยในWinFormsGraphicsSample_4_0
จะมคลาส GraphicsDeviceControl สำาหรบทำาหนาทนโดยเฉพาะ
GraphicsDeviceControl
• สบเชอสายมาจากSystem.Windows.Form.Cotnrol– มความสามารถในการวาดรปตวเองบนหนาจอ– ใช GraphicsDevice ของ XNA ในการวาดรป
• สามารถใชมนใน WinForms Designer ได– แตเวลาใชจะวาดรปตวเองเปนพนทวางสฟาเฉยๆ
สรางโปรแกรม Windows Forms ทใช XNA ได
• สราง Windows Forms Application แทนการสรางXNA Game
• เพม Reference ตอไปน– Microsoft.Xna.Framework– Microsoft.Xna.Framework.Graphics
• คดลอกไฟล– GraphicsDeviceControl.cs– GraphicsDevice.cs– ServiceContainer.cs
สรางโปรแกรม Windows Forms ทใช XNA ได
• สราง subclass ของ GraphicsDeviceControl ใหม โดย override เมธอด
– Initialize– Draw
การจดการ GRAPHICS DEVICE
การจดการ GraphicsDevice
• ในโปรแกรมหนงๆ อาจม GraphicsDeviceControl อยไดหลายๆ ตว
• แตเพอใหโปรแกรมมประสทธภาพ ควรจะมGraphicsDevice เพยงแคตวเดยวเทานน
GraphicsDeviceService
• คลาสททำาการจดการ GraphicsDevice• สรางมนขนมาเพยงตวเดยว แลวแจกจายให
GraphicsDeviceControl หลายๆ ตวใช
• มเมธอด AddRef สำาหรบใชเพมGraphicsDeviceControl ตวใหม– เมอ AddRef ถกเรยกครงแรกจะสราง
GraphicsDevice ขนมาใหม– แตเมอถกเรยกครงตอไปจะไมสรางใหมให
GraphicsDeviceService
• มเมธอด Release สำาหรบใหGraphicsDeviceControl เรยกเมอมนจะเลกใชGraphicsDevice– ถาเมอเรยกแลวจำานวน GraphicsDeviceControl ทใช
เปน 0 แลว GraphicsDeviceService จะทำาลายGraphicsDevice ทง
GraphicsDevice ขนาดแตกตางกน• เมอม GraphicsDeviceControl หลายๆ ตวแตละตวอาจมพนทแตกตางกน
• แต GraphicsDevice มเพยงแคตวเดยว และ GraphicsDeviceControl ทกตวตองใชมนรวม
กน• แลวเจา GraphicsDevice ตวนควรจะม back
buffer ขนาดเทาใดด?
GraphicsDevice ขนาดแตกตางกน• โคดตวอยางจะกำาหนดขนาด back buffer ใหม
ขนาดใหญกวา GraphicsDeviceControl ทใหญทสด
• เวลา GraphicsDeviceControl ตางๆ จะใชGraphicsDevice “ ” มนจะตองกำาหนด หนาตาง ในGraphicsDevice ทมนจะใชกอนเรยกใชจรง
• หลงจากวาดรปใส GraphicsDevice เสรจแลวก ตอง copy ขอมลเฉพาะสวนทสนใจนำาไปแสดงผล
BeginDraw Draw EndDraw
• วาดรปตวเองโดยของ GraphicsDeviceControl จงแบง เปนสามขนตอน และแตละขนตอนมเมธอดของตวเอง
• GraphicsDeviceControl.BeginDraw– กำาหนดขนาดของ GraphicsDevice ใหใหญกวาพนทตวเอง– กำาหนดบรเวณของ GraphicsDevice ทจะใชจรง (Viewport)
• GraphicsDeviceControl.Draw– วาดรปตวเองตามทผใชตองการ
• GraphicsDevice.EndDraw– เรยก GraphicsDevice.Present เพอเอารปทวาดใส
GraphicsDevice ไปแสดงผลในบรเวณของตวเอง
การอาน CONTENT ในWINFORMS APPLICATION
อาน Content ใน WinForms App
• ถาคณตองการอาน content ทสรางดวย content pipeline คณตองทำาสองอยางตอไปน– Content ทคณจะใชจะตองถก build ไปพรอมกบ
project ของคณ– ตองสราง ContentManager
Build Content พรอมกบ App
• สราง content project ใหมโดยเลอกAdd New Item Empty Content Project
• ใส content ทคณตองการใชใน content project ทสราง
• แต content project ไมสามารถ build ตวเองได• คณตองสราง XNA Game Library ขนมาอนหนง• แลวเพม content project เขาใน game library โดย
เพมมนเขาใน Content Reference ของ game library• หลงจากนนจงเพม reference ของ game library
ลงใน application
สราง ContentManager
• ContentManager ตองการ GraphicsDevice สำาหรบ อานขอมลทางกราฟกสตางๆ ( เชน Texture2D)
• เวลา ContentManager ตองการใช GraphicsDevice มนจะไปเรยกหา GraphicsDevice จากคลาสท
implement IGraphicsDeviceService• ใน GraphicsDeviceControl จะม property Services ท
เราสามารถไปดง IGraphicsDeviceService ออกมาได• ดวธการสราง ContentManager ใน constructor ของ
SpriteFontControl
อนเมชนใน WINFORMS APPLICATION
อนเมชนใน WinForms Application
• Application ทเขยนดวย Windows Forms ทวไปจะไมมภาพเคลอนไหว– Control ตางๆ สวนใหญจะอยนง– จะถกปลกใหตนขนมาเพอวาดรปตวเองใหมเมอผใช
ปอน input• ตางกบเกม– ตองมการวาดรปใหมอยอยางตอเนอง– เกมใน XNA สวนใหญจะวาดรปแบบน
• วธการวาดรปของ WinForms กบของ XNA จงเขากนไมได
เมอใช XNA กบ WinForms
• เมอคณสราง GraphicsDeviceControl แลวจะตองเลอกวาจะใชวธการวาดรปตวเองแบบไหน
• ในโคดตวอยางม control ทใชวธการวาดทงสองแบบ– SpriteFontControl ใชวธวาดแบบ WinForms– TriangleControl ใชวธวาดแบบ XNA
วธวาดแบบ WinForms
• หากตองการใชวธวาดแบบ WinForms เวลา subclass GraphicsDeviceControl
กไมตองเขยนโคดเพมเตม– แค override Initialize กบ Draw ตามปกต– Draw จะถกเรยกเมอ control จะตองวาดตวเองโดยอตโนมต
วธการวาดแบบ WinForms
• ถาหากตองการให control ทำาการวาดตวเองใหม ทกๆ ชวงเวลาทกำาหนด ให
– สราง Timer ไวสำาหรบจบเวลาทผานไป– ตงคา Timer.Interval ใหตรงกบชวงเวลาทตองการ– สรางเมธอดทจะถกเรยกเมอ Timer ตสญญาณเวลา– แลวเพมเมธอดนนเขาใน event Timer.Tick– หลงจากนนเรยก Timer.Start()
• โคดขางบนทงหมดควรใสไวใน constructor ของsubclass ของ GraphicsDeviceControl ทคณเขยน
วธการวาดแบบ WinForms
• โคดตวอยางtimer = new Timer();timer.Interval =
(int)TargetElapsedTime.TotalMilliseconds;timer.Tick += Tick;timer.Start();
วธการวาดแบบ WinForms
• ขอด– เขากบสวนอนของระบบ UI ไดดทสด– สามารถเอาเวลาระหวางท Timer ตสญญาณไปใชทำาอยางอนได
– ใชงานไดดถาม control หลายตวทตองทำาอนเมชนพรอมกน
• ขอเสย– อาจไมไดภาพเคลอนไหวทลนไหลทสด– Timer อาจตสญญาณชากวากำาหนดถาระบบกำาลงทำางานหนก
– Timer มความแมนยำาจำากด
วธการวาดแบบ XNA (1)
• SpinningTriangleControl ทำาการวาดรปบอยทสด เทาทจะทำาไดโดยการเพม handle ใส event
Application.Idle– Application.Idle += Tick;
• Application.Idle จะถกปลอยออกมาดวย Win32 message queue ทกครงท message queue วาง
• ถาจะใชเมธอดนในการวาดรป เราจะตองเรยก เมธอด Invalidate ใน Tick
วธการวาดแบบ XNA (1)
• กลไกการทำางาน– Win32 message queue ยง Application.Idle – Invalidate ถกเรยก– Invalidate สง WM_PAINT ไปยง control– WM_PAINT ถกประมวลผล ทำาให control วาดตวเองใหม– ไมม message คางใน queue ทำาให Application.Idle ถกเรยกใหม
• ถาใน event handler ไมมการเรยก Invalidate แลว จะม Application.Idle สงมาเพยงครงเดยวเทานน
วธการวาดแบบ XNA (1)
• ขอด– เขยนโคดสน
• ขอเสย– อาจไมไดอนเมชนทลนไหลทสด เนองจากมชวงเวลา
ระหวางท Application.Idle ถกสงกบการวาดรปจรง
วธการวาดแบบ XNA (2)
• เราสามารถทำาใหโปรแกรมของเราเชค Win32 message queue อยางตอเนอง เพอใหตอบสนอง
ตอ message ไดอยางรวดเรวยงขน• ขนแรกใหใส event handler ใหมให
Application.Idle– Application.Idle += TickWhileIdle;
• TickWhileIdle จะเขา infinite loop แลวเรยก Tick ทนทเมอ message queue วาง
วธการวาดแบบ XNA (2) void TickWhileIdle(object sender, EventArgs e) { NativeMethods.Message message;
while (!NativeMethods.PeekMessage(out message, IntPtr.Zero, 0, 0, 0))
{ Tick(sender, e); } }
วธการวาดแบบ XNA (2)
• NativeMethods.PeekMessage เปนเมธอดทเรา เขยนขนมาเพอดวาม message ใน Win32
message queue หรอไม
วธการวาดแบบ XNA (2) static class NativeMethods { [StructLayout(LayoutKind.Sequential)] public struct Message { public IntPtr hWnd; public uint Msg; public IntPtr wParam; public IntPtr lParam; public uint Time; public System.Drawing.Point Point; }
[DllImport("User32.dll"] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool PeekMessage(out Message message,
IntPtr hWnd, uint filterMin, uint filterMax, uint flags); }
วธการวาดแบบ XNA (2)
• ขอด– ไดอนเมชนทลนไหลทสด
• ขอเสย– เขากบระบบสวนอนไมไดเนองจากแยงเวลาเขาไปใชหมด
– เอาเวลาการทำางานของ CPU ไปใช 100%– เกดปญหาถาม control ทตองทำาอนเมชนพรอมๆ กน
เมธอด Tick
• เพอใหอนเมชนลนไหล เมธอด Tick จะตองทำาการupdate สถานะของเกมและวาดรปในอตราทคงท
• เทคนคการวาดทงสองแบบของเราทผานไมไดรบประกนอตราการวาด
• ดงนนใน Tick จะตองมการเชคนาฬกาวาเวลาผานไปเทาไหรแลว
แลวจงเรยก update เพอเวลาผานไปมากกวาคาบ ทตองทำาการ update
เมธอด Tick Stopwatch stopWatch = Stopwatch.StartNew(); readonly TimeSpan TargetElapsedTime =
TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 60); readonly TimeSpan MaxElapsedTime =
TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 10);
TimeSpan accumulatedTime; TimeSpan lastTime;
เมธอด Tick void Tick(object sender, EventArgs e) { TimeSpan currentTime = stopWatch.Elapsed; TimeSpan elapsedTime = currentTime - lastTime; lastTime = currentTime;
if (elapsedTime > MaxElapsedTime) elapsedTime = MaxElapsedTime; accumulatedTime += elapsedTime;
bool updated = false; while (accumulatedTime >= TargetElapsedTime) { Update(); accumulatedTime -= TargetElapsedTime; updated = true; }
if (updated) Invalidate(); }
IN-GAME USER INTERFACE
ไลบรารสำาหรบสราง User Interface
• ขณะนมไลบรารสำาหรบสราง user interface ใน XNA หลายตว– xWinForms (http://sourceforge.net/projects/xwinforms/)– BlackStar GUI (http://blackstar.codeplex.com/)– XNA Simple GUI (http://simplegui.codeplex.com/)– Windows System for XNA (http://wsx.codeplex.com/)– Nuclex Framework (
http://nuclexframework.codeplex.com/)• Library อนๆ– หาขอมลเพมไดจาก
http://forums.create.msdn.com/forums/t/15274.aspx
Nuclex Framework
• เราจะใช Nuclex Framework– เขยนสำาหรบ XNA 4.0– มการ update เมอไมนานมาน
• โปรเจคอนๆ หลายตวรสกจะเลกทำากนไปหลงจากป 2009 กเยอะ• การใช Nuclex Framework– เวบใชแนะนำาใหดาวนโหลด source code แลวเพมโปรเจคทตองการเขาในเกมของคณ
– ในกรณการทำา user interface เราจะใช• Nuclex.Input• Nuclex.UserInterface
GuiManager
• Nuclex.GuiManager เปนคลาสทใชในการแสดง ผล GUI control ทงหมด
– คณสามารถเพม control “ ” อนๆ ใหเปน ลก ของGuiManager
– เมอ GuiManager.Draw ถกเรยก มนจะวาดลกของมนทงหมด
• GuiManager เปน DrawableGameComponent
DrawableGameComponent
• คลาส DrawableGameComponent เปนกลไลของXNA ในการแยกเกมออกเปนสวนๆ ทเปนอสระจากกน– สามารถเอาไปเพมใหกบ Game เพอใหเกมมความสามารถใหม
– สามารถใช DrawableGameComponent เดยวกนกบ เกมหลายๆ เกมได
DrawableGameComponent
• เวลาสราง DrawableGameComponent จะตองoverride เมธอดตอไปน– Initialize– LoadContent– UnloadContent– Update– Draw
• คลายๆ กบสราง Game และ Screen ใหม
DrawableGameComponent
• DrawableGameComponent กบ Screen ไมเหมอนกน– ณ เวลาหนงจะม Screen เพยงแค Screen เดยว– “ ” คณ เปลยน Screen– ในเวลาหนงจะม DrawableGameComponent มากกวาหนงตว
– “ ” คณ เพม DrawableGameComponent เมอตองการใช
– “ ” คณ ลบ DrawableGameComponent เมอเลกใช
DrawableGameComponent
• สงทเรามกจะได DrawableGameComponent ทำา– เคอรเซอรของเมาส– User Interface
• ผมไมคอยชอบใช DrawableGameComponent– ควบคมการ Update และ Draw ของมนยาก เพราะ
Game จะเรยกฟงกชนเหลานโดยอตโนมต
DrawableGameComponent
• ถาตองการเพม DrawableGameComponent เขาในเกม ใหสง Components.Add(<component ทตองการ>) ใน
constructor ของเกม
public Game1(){ graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; Components.Add(new MyComponent(this));}
• เมธอดตางๆ ของ DrawableGameComponent จะถกเรยก เมอเมธอดเดยวกนของ Game ถกเรยก
การใช GuiManager
• สรางฟลดชนด GuiManager ในคลาส Game• ใน constructor ของ Game– สราง GuiManager– เพม GuiManager เขาใน Components
การใช GuiManagerpublic class UserInterfaceDemoGame : Game {
public UserInterfaceDemoGame() { this.graphics = new GraphicsDeviceManager(this); this.gui = new GuiManager(this); Components.Add(this.gui); IsMouseVisible = true; }
// ...
private GuiManager gui;}
Screen
• GuiManager ตองม Screen ของมน– ชอซำากนกบ Screen ของ Game แตคนละตว
• Screen มหนาทจดการสถานะของ GUI ตางๆ• เราอาจม Screen หลายๆ อนถาเรามระบบ GUI หลายตว
• แตสวนมากจะมแคตวเดยว
Desktop Control
• ระบบ GUI จะมตนไมของ control– Control ตวหนงสามารถม control ตวอนเปนลก
• Control ทอยระดบบนสดเรยกวา Desktop Control– Control นเปนลกของ screen– Desktop Control เปนพนททไมมส– ถาคณเอา control อนไปใสเปนลกของ desktop
control มนจะปรากฏอยบนหนาจอเกมโดยตรง
การใช GuiManager
• ในฟงกชน Initialize ของ Game– สราง Screen โดยให Viewport ของ GraphicsDevice
เปน argument– ในขนนคณอาจจะกำาหนดขอบเขตของ Desktop
Control ไมใหใหญเกนไปได
การใช GuiManagerprotected override void Initialize() { Viewport viewport = GraphicsDevice.Viewport; Screen mainScreen = new Screen(viewport.Width, viewport.Height); this.gui.Screen = mainScreen;
mainScreen.Desktop.Bounds = new UniRectangle( new UniScalar(0.1f, 0.0f), new UniScalar(0.1f, 0.0f), // x and y new UniScalar(0.8f, 0.0f), new UniScalar(0.8f, 0.0f) // width and
height );
base.Initialize();}
UniScalar
• การบอกตำาแหนงของ Nuclex Framework ใชกลไกคลาย กบของ CeGUI (http://www.cegui.co.uk)
• Coordinate ทกตวแทนดวยคลาส UniScalar• UniScalar มสวนประกอบสองสวน– Fractional part = “ ”อตราสวนเทาไหรของความกวางของ พอ– Offset = หางจากตำาแหนงทกำาหนดวย fractional part มากพกเซล
• ตวอยาง– new UniScalar(0.5f, 50) = ตำาแหนงทหางจากจดกงกลางของ
พอมา 50 พกเซล
UniScalar
• ดงนนnew UniRectangle( new UniScalar(0.1f, 0.0f), new UniScalar(0.1f, 0.0f), // x and y new UniScalar(0.8f, 0.0f), new UniScalar(0.8f, 0.0f) // width and
height);
จงเปนสเหลยมทมขนาด 80% ของ control พอ และอยตรงกลาง control พอพอด
สราง Control อนๆ• สราง control อนๆ เพอมาใสเปนลกของ desktop
control• ในกรณนเราจะสราง WindowControl ซงเปน
หนาตางซงขางในสามารถบรรจ control อนๆ ได
สราง Control อนๆpublic partial class DemoDialog : WindowControl {
public DemoDialog() { InitializeComponent(); }
}
สราง Control อนๆpartial class DemoDialog {
private Nuclex.UserInterface.Controls.LabelControl helloWorldLabel; private Nuclex.UserInterface.Controls.Desktop.ButtonControl okButton; private Nuclex.UserInterface.Controls.Desktop.ButtonControl cancelButton; private void InitializeComponent() { this.helloWorldLabel = new Nuclex.UserInterface.Controls.LabelControl(); this.okButton = new Nuclex.UserInterface.Controls.Desktop.ButtonControl(); this.cancelButton = new
Nuclex.UserInterface.Controls.Desktop.ButtonControl();
// helloWorldLabel this.helloWorldLabel.Text = "Hello World! This is a label."; this.helloWorldLabel.Bounds = new UniRectangle(10.0f, 15.0f, 110.0f, 30.0f);
สราง Control อนๆ // okButton this.okButton.Bounds = new UniRectangle( new UniScalar(1.0f, -180.0f), new UniScalar(1.0f, -40.0f), 80, 24 ); // cancelButton this.cancelButton.Bounds = new UniRectangle( new UniScalar(1.0f, -90.0f), new UniScalar(1.0f, -40.0f), 80, 24 ); // DemoDialog this.Bounds = new UniRectangle(100.0f, 100.0f, 512.0f, 384.0f); Children.Add(this.helloWorldLabel); Children.Add(this.okButton); Children.Add(this.cancelButton); } }
Children.Add
• เมอสราง control เสรจแลวกใหไปเพมมนเปนลกของ control อนโดยการเรยกเมธอด Add ของ property Children
• เชน เราสามารถเพม DemoDialog เปนลกของ Desktop Control ไดดงตอไปน
protected override void Initialize() {
// ...code from previous step...
// Next, we add our demonstration dialog to the screen mainScreen.Desktop.Children.Add(new DemoDialog());
base.Initialize();}
การจดการกบ Event ของ Control ตางๆ
• เชนเดยวกบ WinForms controlcontrol ของ Nuclex Framework ม event
ทเราสามารถกำาหนด ใหมนได• เชน คลาส ButtonControl ม event Pressed ทจะถกสงทกครงเมอปมถกกด
• เราสามารถเพม handler ทม signature เปน
void Handler(object sender, EventArgs arguments)
ใหเปนตวจดการ event ได
การจดการกบ Event ของ Control ตางๆ
private void createDesktopControls(Screen mainScreen) {
// Button through which the user can quit the application ButtonControl quitButton = new ButtonControl(); quitButton.Text = "Quit"; quitButton.Bounds = new UniRectangle( new UniScalar(1.0f, -80.0f), new UniScalar(1.0f, -32.0f), 80, 32 ); quitButton.Pressed += delegate(object sender, EventArgs arguments) { Exit(); }; mainScreen.Desktop.Children.Add(quitButton);
}