You are here: Home Articles บทความในนิตยสาร Pantip Guide บทความในนิตยสาร Pantip Guide ฉบับที่ 44

XNA Community Thailand

บทความในนิตยสาร Pantip Guide ฉบับที่ 44

อีเมล พิมพ์

บทความในนิตยสาร Pantip Guide ฉบับที่ 44 : การพัฒนาเกมง่ายๆ ด้วย XNA Game Studio ตอนที่ 4 การควบคุมอุปกรณ์อินพุต...

               สวัสดีผู้อ่านทุกท่านครับ ก่อนที่จะเข้าสู่เนื้อหาของบทความในตอนนี้ ผมขอคั่นเรื่องสั้นๆ ก่อน เนื่องจากว่าในวันที่ 11 มิถุนายน 2552 ทางไมโครซอฟต์ได้ประกาศให้ดาวน์โหลด XNA Game Studio 3.1 ซึ่งเป็นเวอร์ชันใหม่ล่าสุดในตอนนี้ โดยผู้ผ่านสามารถดาวน์โหลดได้จาก http://www.microsoft.com/downloads/details.aspx?FamilyID=80782277-d584-42d2-8024-893fcd9d3e82&displaylang=en โดยขั้นตอนการลงโปรแกรมก็ไม่ยาก ซึ่งจะต้อง Uninstall XNA Game Studio 3.0 ออกก่อน แล้วลงตัวใหม่ซึ่งจะมีทั้ง XNA Game Studio 3.0 และ 3.1 ด้วย สำหรับในเวอร์ชันนี้มีการเพิ่มความสามารถเพิ่มเติมที่เด่นๆ ก็คือ มีการสร้างเกมที่มีระบบ Avatar ได้โดยผู้เล่นสามารถปรับแต่งตัวละครของตัวเองได้ และความสามารถที่เพิ่มขึ้นอีกอย่างหนึ่งคือสามารถเล่นไฟล์วิดีโอได้ ซึ่งหลายคนที่เคยใช้ XNA ได้รอคอยกันมานาน ทั้งนี้สามารถดูรายละเอียดเพิ่มเติมได้จาก  http://creators.xna.com/en-US/news/xnagamestudio3.1  ดังนั้น บทความต่อจากนี้ไปผมข้อใช้ XNA Game Studio 3.1 ในการสร้างงานประกอบบทความละกันนะครับ

                สำหรับในตอนนี้เราจะมาพูดถึงการเขียนโปรแกรมเพื่อควบคุมอุปกรณ์อินพุต โดยจะกล่าวถึงอุปกรณ์หลักที่นิยมใช้สำหรับเล่นเกมคือ คีย์บอร์ด เมาส์ และ Xbox 360 Controller โดยเฟรมเวิร์คที่ใช้สำหรับรับอุปกรณ์และใช้จัดการกับอุปกรณ์อินพุตนี้คือ Microsoft.XNA.Framework.Input ซึ่งเป็นหนึ่งในเฟรมเวิร์คพื้นฐานที่มีมากับ XNA 

                ก่อนอื่นมาทำความรู้จักกับอุปกรณ์อินพุตทั้งสามนี้ก่อน ซึ่งโดยทั่วไปแล้วอุปกรณ์อินพุตแบ่งออกเป็น 2 แบบด้วยกัน คือ แบบดิจิตอล (Digital) และแบบแอนาลอก (Analog) ซึ่งถ้าเป็นแบบดิจิตอลอุปกรณ์อินพุตจะส่งค่าออกมาเป็น On หรือ Off เท่านั้น ตัวอย่างของอินพุตแบบดิจิตอลคือ ปุ่มบนคีย์บอร์ด หรือปุ่มบน Xbox 360 Controller เป็นต้น สำหรับอินพุตแบบแอนาลอกอุปกรณ์อินพุตจะส่งค่าออกมาเป็นช่วงของตัวเลข ยกตัวอย่างเช่น Stick ใน Xbox 360 Controller เป็นต้น โดยใน XNA Game Studio 3.1 นี้ค่าที่รับมาจาก Stick จะมีค่าอยู่ในช่วง -1.0 ถึง 1.0 และ Trigger จะมีค่าอยู่ในช่วง 0.0 ถึง 1.0 ทั้งสองค่าเป็นตัวแปรชนิด float แต่ถ้าเป็นเมาส์ค่าที่ได้เพิ่มเติมคือตำแหน่งของเคอเซอร์โดยให้ค่าออกมาในระดับพิกเซล



รูปที่ 1 Xbox 360 Controller



รูปที่ 2 Keyboards



รูปที่ 3 Mouse

 ที่สำคัญอีกอย่างหนึ่งสำหรับเรื่องอุปกรณ์อินพุตคือถ้าเป็นเมาส์จะรองรับเฉพาะเครื่องพีซี สำหรับเครื่อง Xbox 360 จะรองรับเฉพาะคีย์บอร์ดและ Xbox 360 Controller นะครับ และสำหรับจำนวนปุ่มและจำนวนอุปกรณ์ที่รองรับได้ สรุปดังตาราง

อุปกรณ์

ปุ่มดิจิตอล

แอนาลอก

ความสามารถในการสั่น

รองรับในเครื่องพีซี

รองรับในเครื่อง

Xbox 360

จำนวนอุปกรณ์

ที่รองรับ

Xbox 360 Controller

14

4

มี

ใช่

ใช่

4

Keyboard

>100

0

ไม่มี

ใช่

ใช่

1

Mouse

5

3

ไม่มี

ใช่

ไม่ใช่

1


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



รูปที่ 4 สร้างโปรเจคใหม่ชื่อ Pantip_Article_04

 เมื่อสร้างโปรเจคใหม่แล้วเราจะได้โค้ดเริ่มต้นที่ให้เข้ามาซึ่งในส่วนของ Using Statement จะมี Framework Input มาด้วยคือ using Microsoft.Xna.Framework.Input ซึ่งเป็นส่วนสำคัญของบทความตอนนี้
ในโฟว์เดอร์ Contents ให้เพิ่ม SubFolder: Textures พร้อมทั้งเพิ่มรูป sprite.png ซึ่งเป็นรูปของตัวละครโดยแบ่งออกเป็น 4 ส่วน ขนาด 100X400 ดังรูปที่ 5 (หากไม่เข้าใจเรื่อง sprite ลองไปอ่านตอนที่ 3 อีกครั้ง)



รูปที่ 5 Sprite ของตัวละคร
 
หลังจากนั้นประกาศตัวแปรที่เป็น Global ที่สำคัญคือ sprite เอาไว้เก็บรูป และตัวแปรที่เก็บคุณสมบัติที่เตรียมไว้วาดรูปคือตัวแปร position (ตำแหน่งที่ใช้วาดรูป), scale (ขนาดของรูป), rotation (การหมุนของรูป), และ origin (จุดศูนย์กลางของรูปเพื่ออ้างอิงตอนหมุน) ซึ่งเขียนโค้ดได้ดังนี้

        private Texture2D sprite;

        private int spriteIndex=0;

 

        private Vector2 position = new Vector2(0.0f, 0.0f);

        private Vector2 scale = new Vector2(1.0f, 1.0f);

        private float rotation = 0.0f;

        private Vector2 origin = new Vector2(50.0f, 50.0f);


จากนั้นในเมธอด LoadContent() ให้เพิ่มคำสั่งโหลดรูปและปรับตำแหน่งที่วาดรูปให้เป็นกึ่งกลางของ Windows form โดย Viewport คือขนาดของฟอร์มที่ใช้งานจริงไม่รวม Title ของวินโดว์

protected override void LoadContent()

        {

            // Create a new SpriteBatch, which can be used to draw textures.

            spriteBatch = new SpriteBatch(GraphicsDevice);

 

            sprite = Content.Load<Texture2D>("Textures/sprite");

            position.X = graphics.GraphicsDevice.Viewport.Width / 2;

            position.Y = graphics.GraphicsDevice.Viewport.Height / 2;

 

        }


สำหรับในเมธอด Update() ให้เพิ่มโค้ดเพื่อเรียกเมธอดในการเรียกใช้งาน Xbox 360 Controller, Keyboard และ Mouse ดังนี้

protected override void Update(GameTime gameTime)

        {

            // Allows the game to exit

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)

                this.Exit();

 

            UpdateInputXbox360();

            UpdateInputKey();

            UpdateInputMouse();

 

            base.Update(gameTime);

        }


สร้างเมธอด UpdateInputXbox360() เพื่อควบคุม Xbox 360 Controller ทุกปุ่มดังนี้

private void UpdateInputXbox360()

        {

            GamePadState s = GamePad.GetState(PlayerIndex.One); //รับ state จาก Xbox 360 Controller

            ButtonState bp = ButtonState.Pressed; //กำหนดปุ่มเพื่อเปรียบเทียบว่ามีการกดปุ่มหรือเปล่า

 

            //ตรวจสอบว่ามีการกดปุ่ม A, B, X, Y หรือเปล่าหากมีการกดปุ่มจะปรับขนาดของรูปให้ย่อหรือขยาย

            if (s.Buttons.A == bp)

                scale.Y *= 1.01f;

            if (s.Buttons.B == bp)

                scale.X *= 1.01f;

            if (s.Buttons.X == bp)

                scale.X *= 0.99f;

            if (s.Buttons.Y == bp)

                scale.Y *= 0.99f;

 

            //ตรวจสอบว่ามีการกดปุ่ม Start หรือเปล่า หากมีการกดจะกำหนดค่าให้เป็นเหมือนตอนเริ่มต้น

            if (s.Buttons.Start == bp)

            {

                position.X = graphics.GraphicsDevice.Viewport.Width / 2;

                position.Y = graphics.GraphicsDevice.Viewport.Height / 2;

                rotation = 0.0f;

                scale = new Vector2(1.0f, 1.0f);

                spriteIndex = 0;

            }

 

            //ถ้ากดปุ่ม Back จะออกจากโปรแกรมทันที

            if (s.Buttons.Back == bp)

                Exit();

 

            //ตรวจสอบว่ามีการกดปุ่ม D-Pad หรือเปล่าซึ่งมีอยู่ 4 ทิศทาง โดยหากมีการกดปุ่มจะเลื่อนรูปซ้าย ขวา             

            //ขึ้นหรือลง พร้อมทั้งปรับหน้าตัวละครให้หันหน้าตามปุ่มที่กดโดยควบคุมจาก spriteIndex

            if (s.DPad.Left == bp)

            {

                spriteIndex = 3;

                position.X -= 10.00f;

            }

            if (s.DPad.Right == bp)

            {

                spriteIndex = 1;

                position.X += 10.00f;               

            }

            if (s.DPad.Up == bp)

            {

                spriteIndex = 0;

                position.Y -= 10.00f;               

            }

            if (s.DPad.Down == bp)

            {

                spriteIndex = 2;

                position.Y += 10.00f;

            }

 

            //ตรวจสอบว่ามีการกดปุ่ม Left-Right Shoulder หรือ Left-Right Bumper

            //ซึ่งถ้ามีการกดปุ่ม LB จะให้รูปไปอยู่ติดขอบบน และถ้ากดปุ่ม RB จะให้รูปอยู่ติดขอบล่าง

            if (s.Buttons.LeftShoulder == bp)

                position.Y = origin.Y;

            if (s.Buttons.RightShoulder == bp)

                position.Y = graphics.GraphicsDevice.Viewport.Height - origin.Y;

 

            //ตรวจสอบว่ามีการกดปุ่ม Left Thumbstick หรือ Right Thumbstick (กดปุ่มตรงกลางของคันโยก)

            //ซึ่งถ้ามีการกดปุ่ม Left Thumbstick จะให้รูปไปอยู่ติดขอบซ้าย

            //และถ้ากดปุ่ม Right Thumbstick จะให้รูปอยู่ติดขอบขวา

            if (s.Buttons.LeftStick == bp)

                position.X = origin.X;

            if (s.Buttons.RightStick == bp)

                position.X = graphics.GraphicsDevice.Viewport.Width-origin.X;

 

            //ตรวจสอบว่ามีการโยก Left Thumbstick โดยหากโยกไปด้านใดรูปก็จะเลื่อนตำแหน่งไปด้านนั้น

            Vector2 ts = s.ThumbSticks.Left;

            position.X += 9.0f * ts.X;

            position.Y -= 9.0f * ts.Y;

 

            //ตรวจสอบว่ามีการโยก Right Thumbstick โดยหากโยกไปแถบซ้าย รูปจะหมุนทวนเข็มนาฬิกา

            //แต่ถ้าโยกไปฝั่งขวา รูปจะหมุนตามเข็มนาฬิกา

            ts = s.ThumbSticks.Right;

            rotation += 0.1f * ts.X;

            rotation += 0.1f * ts.Y;

 

            //ตรวจสอบว่ามีการกดปุ่ม Left Trigger หรือ Right Trigger โดย

            //ถ้ากด Left Trigger จะเกิดการสั่นที่จอย ด้านซ้าย และถ้ากด Right Trigger จะสั่นที่จอยด้านขวา

            float tr = s.Triggers.Left;

            GamePad.SetVibration(PlayerIndex.One, tr, 0.0f);

            tr = s.Triggers.Right;

            GamePad.SetVibration(PlayerIndex.One, 0.0f, tr);

        }


ถัดมาเพิ่มเมธอด UpdateInputKey() เพื่อเขียนคำสั่งสำหรับควบคุม Keyboard โดยหลักสำคัญคือสร้างตัวแปร KeyboardState เพื่อเก็บสถานะของคีย์ แล้วตรวจเช็คว่ามีการกดหรือเปล่าโดยใช้คำสั่ง IsKeyDown ซึ่งในตัวอย่างนี้เช็คว่ามีการกดปุ่ม A, W, S, D หรือเปล่าหากมีการกดก็จะเลื่อนรูปไปทางซ้าย ขึ้น ลง ขวา ตามลำดับดังนี้

private void UpdateInputKey()

        {

            KeyboardState keyboardState = Keyboard.GetState();

            if (keyboardState.IsKeyDown(Keys.Escape))

            {

                Exit();

            }

            if (keyboardState.IsKeyDown(Keys.A))

            {

                spriteIndex = 3;

                position.X -= 10.11f;

            }

            if (keyboardState.IsKeyDown(Keys.W))

            {

                spriteIndex = 0;

                position.Y -= 10.11f;

            }

            if (keyboardState.IsKeyDown(Keys.S))

            {

                spriteIndex = 2;

                position.Y += 10.11f;

            }

            if (keyboardState.IsKeyDown(Keys.D))

            {

                spriteIndex = 1;

                position.X += 10.11f;

            }

        }

 

หลังจากนั้นเพิ่มเมธอด UpdateInputMouse() เพื่อเขียนคำสั่งควบคุมเมาส์ โดยหลักสำคัญอยู่ที่สร้าง MouseState เพื่อเก็บ State ของเมาส์ หากต้องการตรวจสอบการคลิ๊กซ้ายหรือขวาสามารถใช้คำสั่ง current_mouse.LeftButton == ButtonState.Pressed และสามารถเก็บค่าตำแหน่งของเมาส์จาก current_mouse.X หรือ current_mouse.Y ดังนี้

private void UpdateInputMouse()

        {

            MouseState current_mouse = Mouse.GetState();

            if (current_mouse.LeftButton == ButtonState.Pressed)

            {

                position.X = current_mouse.X;

                position.Y = current_mouse.Y;

            }

        }

 

ขั้นตอนสุดท้ายคือนำรูป Sprite มาวาดตามตำแหน่ง การหมุน และขนาด ตามที่เราได้กำหนดจากอุปกรณ์นำเข้า โดยเพิ่มโค้ดในเมธอด Draw() ดังนี้

protected override void Draw(GameTime gameTime)

        {

            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            /*spriteBatch.Draw(รูป sprite, ตำแหน่ง, ตัดส่วนของรูป sprite มาแสดง ซึ่งมีขนาด 100x100, โทนสีของรูป ถ้าเป็นสีขาวจะเป็นรูปปกติต้นแบบ แต่ถ้าต้องการเปลี่ยนโทนสีก็สามารถทำได้, มุมที่รูปหมุนหน่วยเป็น radian , จุดศูนย์กลางของรูป, ปรับขนาดของรูป, effect ที่ใส่ให้กับรูป,  ลำดับ layer ของ sprite มีค่าระหว่าง
 
0-1);*/

 

            spriteBatch.Draw(sprite, position,new Rectangle(100*spriteIndex,0,100,100), Color.White, rotation, origin, scale, SpriteEffects.None, 0);

            spriteBatch.End();

 

            base.Draw(gameTime);

        }


แล้วขั้นตอนที่สำคัญอีกอย่างหนึ่งคือ การแสดงรูป Cursor ของเมาส์ ซึ่งโดยปกติแล้วจะไม่แสดง คำสั่งที่ให้แสดงผล เราต้องใส่คำสั่งเพิ่มในคอนสตรัคเตอร์ Game1() ดังนี้

public Game1()

        {

            graphics = new GraphicsDeviceManager(this);

            Content.RootDirectory = "Content";

            this.IsMouseVisible = true;

        }

 เป็นอันว่าเสร็จเรียบร้อยเมื่อตรวจทานครบถ้วนแล้วถ้าไม่มีสีแดงขีดเส้นใต้ (error) ก็รันโปรแกรมด้วยการกดปุ่ม F5 ได้เลย ซึ่งจะได้ผลลัพธ์ดังรูปที่ 6



รูปที่ 6 ผลจากการรันโปรแกรม

 จากที่กล่าวมาข้างต้นตอนนี้เราก็สามารถควบคุมตัวละคร หรือวัตถุอื่นๆ ในเกมของเราได้แล้ว หรือถ้าหากใครที่ต้องการสร้างเป็นคลาสใหม่เพื่อใช้ในการควบคุมตัวละครหลายๆ ตัวพร้อมกันก็สามารถทำได้นะครับ สำหรับในตอนหน้าจะเขียนถึงเรื่องการทำ Splash screen ของเกมเพื่อแสดงโลโก้ของตัวเอง และวิธีการสร้างเมนูในเกม อย่าลืมฝึกเขียนกันเรื่อยๆ นะครับ

ดาวน์โหลด Source Code

 

Comments

avatar gmax0209
0
 
 
อยากทราบว่า โค้ดจอย xbox ใช้ร่วมกับจอย PC อันละ100กว่าบาทได้ไหมครับ
avatar mankajib
0
 
 
ไม่แน่ใจเหมือนกันนะ แต่คิดว่าไม่น่าจะได้นะครับ เดี๋ยวต้องลอง
avatar gmax0209
0
 
 
ครับผม พอดี มะมีจอยลองอ่า และอีกอย่างจอยXBox มันแพง - -.
กรุณา login เข้าสู่ระบบก่อน
 

บทความที่เกี่ยวข้อง