[Xvna.forumb.biz]XNA basic for newbie

50
Copyrights by HuyetSat - Xvna.forumb.biz - 2010 Nếu muốn tự mình viết trò chơi máy tính thì đây sẽ là tài liệu cần thiết cho bạn. Nó sẽ hướng dẫn bạn lập trình xna từ những điều cơ bản nhất đến khi bạn có thể viết một game hoàn chỉnh! Bạn cần phải biết qua về C# trước khi đọc tài liệu này. Đây là một tài liệu hữu ích cho những newbie chưa từng viết game! Các game mình hướng dẫn rất đơn giản (GetSix, Pong, Asteroids) để newbie dễ hiểu. Cái gì cũng phải bắt đầu từ đơn giản trước. , bác sĩ cũng phải học các mổ Amiđan trước khi được phân công vào một ca giải phâu não Xvna.forumb.biz là diễn đàn của tài liệu này, nếu cần thêm thông tin có đề cập đến trong tài liệu, vui lòng truy cập vào diễn đàn. Bản quyền thuộc về HuyetSat - Xvna.forumb.biz . yêu cầu bạn ghi rõ nguồn gốc nếu bạn muốn phát hành tài liệu này trên trang web hoặc forum cá nhân của bạn. Contact me at [email protected] or http://xvna.forumb.biz

Transcript of [Xvna.forumb.biz]XNA basic for newbie

Page 1: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Nếu muốn tự mình viết trò chơi máy tính thì đây sẽ là tài liệu cần thiết cho bạn. Nó sẽ hướng dẫn bạn lập trình xna từ những điều cơ bản nhất đến khi bạn có thể viết một game hoàn chỉnh! Bạn cần phải biết qua về C# trước khi đọc tài liệu này. Đây là một tài liệu hữu ích cho những newbie chưa từng viết game! Các game mình hướng dẫn rất đơn giản (GetSix, Pong, Asteroids) để newbie dễ hiểu. Cái gì cũng phải bắt đầu từ đơn giản trước. , bác sĩ cũng phải học các mổ Amiđan trước khi được phân công vào một ca giải phâu não

Xvna.forumb.biz là diễn đàn của tài liệu này, nếu cần thêm thông tin có đề cập đến trong tài liệu, vui lòng truy cập vào diễn đàn.

Bản quyền thuộc về HuyetSat - Xvna.forumb.biz . yêu cầu bạn ghi rõ nguồn gốc nếu bạn muốn phát hành tài liệu này trên trang web hoặc forum cá nhân của bạn.

==========================================

Contact me at [email protected] or http://xvna.forumb.biz

Page 2: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Copyrights by Xvna.forumb.biz © - 2010VietNam XNA Game Development Community!Written by HuyetSat.

Chương 1:

Phát triển game là gì?, XNA là gì và tại sao lại viết game trên xna.

1.Tại sao lại cần phát triển game?

Đây là một số lý do chính:+Doanh thu từ game cao hơn nhiều so với phim ảnh!+Lập trình game là một thách thức lớn về mặt kỹ thuật!+Lập trình game là môt công việc thú vị!

2.Viết game như thế nào?

Có 2 cách chính nếu bạn muốn viết game:+Sử dụng một số engine như GameMaker, RPG Maker, FPS Creator, ... Nói chung là chỉ cần có ý tưởng và tài nguyên là được. những engine trên hok yêu cầu bạn phải biết lập trình! Bạn chỉ cần Drag và Drop object , chọn thêm method có sẵn trong engine thế là bạn đã có game! Nói chung là ko nên sài mấy engine này! Lập trình chính là xương sống của GameMaking chứ hok phải design!

+Học về C, C++ ,..., hệ thống đồ họa API, vât lý, toán học cao cấp. những kiến thức rất khó nhưng cũng rất hữu ích! Tuy vậy tài liệu này viết cho newbie nên chúng ta cũng ko bắt đầu với nó :>

Cái chúng ta bắt đầu là C# và xna 3.1 ! nó đơn giản nhưng cũng hok kém phần hiệu quả trong lập trình game! Yêu cầu của một Game Project hoàn chỉnh:+Game đó phải chơi được! tức là đồ họa khá, hoạt hình mượt, có nội dung, có thắng thua, kết hợp với hiệu ứng âm thanh.+Phải có một kế hoạch rõ ràng: Tốt nhất các bạn viết hết các ý tưởng và thuật toán mà các bạn nghĩ ra lên giấy, sau đó lọc ra những cái khả thi, mở xna lên và bắt đầu code!+ Nghiên cứu kỹ cách bạn sẽ code: Code là một nghệ thuật! có nhiều cách để lập trình tức là bạn sẽ thấy có nhiều thuật toán cho một vấn đề, cái chính là bạn phải chọn ra

Contact me at [email protected] or http://xvna.forumb.biz

Page 3: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

một giải pháp hiểu quả nhất (Đơn giản, tốn it tài nguyên khi run, phải hiệu quả ...) cái này mấy chương sau mình sẽ đưa ra ví dụ cụ thể.

3. XNA là gì và Tại sao lại là C# và XNA?

XNA là một công nghệ làm game của microsoft phát triển. nó hướng đến đối tượng sử dụng là các học sinh, sinh viên và những người đam mê lập trình game... Bản XNA 3.1 yêu cầu bạn phải có visual studio 2008 trở lên (bạn có thể down bản Express 2008 SP1) tại trang web của microsoft và bộ XNA 3.1 (hoàn toàn miễn phí). Do XNA sử dụng C# nên bắt buộc bạn phải có nền tảng C# tốt. nếu chỉ làm game đơn giản thì bạn nắm vững phần lập trình hướng đối tượng của C# là ok! Sau khi cài đặt XNA, nó sẽ tích hợp trực tiếp vào visual studio C# , bạn có thể chọn new project => XNA 3.1 Window game. XNA có 1 ưu điểm là viết game đc cho Xbox, Zune game vẫn chạy trên HĐH Window mobile mấy cái này quan trọng lắm nhé, nếu bạn muốn kiếm tiền từ việc viết game thì Xbox là môi trường hấp dẫn ko thua PC. Nếu game bạn viết hay thì có thể mang lên chợ game XBox của microsoft mà bán cho những người chơi game khác.

Search Các bài hướng dẫn training về C# và xna tại xvna!

4. Giao diện sử dụng cho coder khi bạn làm việc trên Visual C# 2008 express edition!

Contact me at [email protected] or http://xvna.forumb.biz

Page 4: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

5.Hướng dẫn Download và cài đặt xna.

Contact me at [email protected] or http://xvna.forumb.biz

Page 5: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Chương 2:

Các thành phần cơ bản của xna

1.Hệ tọa độNew bie các bạn nên bắt đầu với trục tọa độ 2D của XNA.Gốc (0:0) nằm ở đỉnh trên cùng, bên trái của màn hình game khi bạn run game!Trục Ox hướng từ trái sang phải theo chiều dươngTrục Oy hướng từ trên xuống dưới theo chiều dươngGiá trị tọa độ có thể là số thực (float)

Nhờ có hệ tọa độ mà bạn có thể tạo ra vị trí (position) vận tốc (velocity), gia tốc (accelerate), trọng lực (gravity) ...

2.các thành phần Game, GameService và Game Component

Ko bắt buộc bạn phải sử dụng, tuy nhiêu nếu bạn dùng chúng thì chương trình của bạn sẽ đơn giản đi rất nhiều!

2.1. Game, Service và những điều cần lưu ý

Gốc gác của XNA là 1 class được xây dựng , chính là Microsoft.Xna.Framework.Game (gọi tắt là Game) Bạn sẽ thấy 1 file là program.cs sẽ run cái Game1.cs này và nó chính là file chứa toàn bộ mã nguồn chính để chạy game, nó bao gồm mọi thành phần của game, thường thì chúng ta cần 1 thể hiện của class Game1 là đủ. Trong class game chính của bạn (đc kế thừa từ Game) sẽ thấy có rất nhiều method mà Game cho phép bạn override: initilize(), Update() ... Tuy nhiên khởi đầu cho việc lập trình là khai báo biến, bạn nên khai báo các biến như là Player, hay Enemy... nhiều Enemy thì có thể tạo 1 class chứa toàn bộ tụi nó gọi là Enemy Manager chả hạn, nếu bạn có nhiều màn trong game thì chúng ta khai báo player , Enemy trong từng màn (dùng GameCompoment - sẽ nói sau) và khai báo màn ở file game chính (như mặc định là Game1.cs đó) Bạn có thể cấp dữ liệu về một thứ dùng chung nào đó cho các GameCômpoment bằng cách dùng service:

Contact me at [email protected] or http://xvna.forumb.biz

Page 6: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Services.AddService(typeof(SpriteBatch), spriteBatch);

GameCompoment sẽ có giá trị của spriteBatch mà dùng cho 2D graphic ở Draw method Tiếp đến bạn có method Initilize() nó sẽ được gọi trước Update hay Draw method, bạn thiết lập các giá trị cơ bản như: chạy nhạc nền hay tùy chọn full màn hình, thiết lập cho Enemy và player nếu có... LoadContent là method giúp bạn load tài nguyên từ thư mục Content (theo mặc định sẽ là thư mục gốc chứa tài nguyên). Cú pháp để load khá đơn giản. thực ra bạn load ở đâu cũng đc nhưng thường là sau khi Init và khi đã bắt đầu chạy game (vào Update) thì chả ai lại load lại content cả, nó sẽ có thể gây ra những lỗi nghiêm trọng Update là method có nhiệm vụ duyệt tất cả các thành phần của game, KT điều kiển để Update cho game (VD tốc độ của object là 1, sau 1 lần update , tọa độ của nó sẽ cộng thêm bởi 1) Khi dùng Update bạn nên cẩn thận đừng để quá nhiều object Update 1 lúc game sẽ rất lắc. bạn nên KT điều kiện mà sẽ Update cho object (VD như chỉ Update cho những Object nằm trong vùng nhìn thấy của camera khi làm game 3D) Theo mặc định thì XNA update 60 lần 1 giây bạn có thể tăng giảm con số này tùy thix cho phù hợp với game và sức chịu đựng của cái máy bạn: code dưới đây làm XNA update 100 lần 1 giây

Draw Method là cái bạn cần chú ý sau cùng, nó cũng hết sức quan trọng vì mọi thứ bạn nhìn thấy trong game đều đc đưa lên ở đây . tất nhiên điều này là ko bắt buộc bạn có thể để nó trong Update, tuy nhiên XNA đã tạo sẵn cho chúng ta rùi, ngu gì ko sài và làm chương trình đơn giản hơn? Draw cũng đc "update" như ở Update() method nhưng chỉ là khi có sự thay đổi thích hợp liên quan đến Update method nghĩa là bạn cũng KT ĐK đc ở đây nhưng chỉ là để Draw object cho thix hợp thôi, còn về game lôgic thì để ở Update() là hay nhất Bạn có thể thắc mắc về mấy chữ Base trong môi method. Nhiệm vụ của chúng rất đơn giản thôi, đó là gọi các method tương ứng của các gamecompoment trong game (nếu có) ví dụ như Update Method (sau khi Update cho Game1.cs xong, phần Base.Update(gameTime) sẽ update cho tất cả các GameCompoment đã đăng ký (khởi tạo và added vào mảng Compoments của class Game1.cs)

2.2.GameCompoment và DrawableGameCompoment

Cach tạo ra GameComponent, chọn như sau: kích phải vào project trong cửa sổ Solution...

Contact me at [email protected] or http://xvna.forumb.biz

Page 7: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Sau đó chọn XNA 3.1 >> GameComponent >> gõ tên lớp vào trường Name.

Visual sẽ tạo cho bạn một lớp kế thừa từ GameComponent có tên lớp bạn vừa gõ vào trong trường Name.

Contact me at [email protected] or http://xvna.forumb.biz

Page 8: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Components là một danh sách List<(Drawable)GameCompoment> của Game, nó đc tạo sẵn cho bạn. những gì bạn cần làm là tạo class kế thừa từ (Drawable)GameCompoment và add những thể hiện của class vừa viết này vào mảng Components và nó sẽ đc tự động Update hay Draw trong những method Base.Update(GameTime) hay Base.Draw(GameTime) của Game !

Giải thích kỹ hơn một tý thì nó là thế này:Chúng ta sử dụng (Drawable)GameComponent, class sẵn có của XNA. Dùng nó rất có lợi bởi lẽ trong Class Game1.cs của chúng ta, XNA đã tạo một List có tên Components. Mỗi Đối tượng là GameComponent hay là DrawableGameComponent khi đc Add vào mảng này sẽ đc tự động chạy các method quan trọng như initilize, update (nếu là Drawable thì có thêm Draw method). Nghĩa là nếu bạn tạo ra 100 object kiểu này thì sẽ đỡ công code, chúng ta chỉ cần đưa nó vào mảng Component là xong! Mặt khác sử dụng Class component trên chúng ta còn có 1 tham số quan trọng đó là Game, tức là Game1.cs đó khi XNA tạo sẵn cho bạn lớp Game1.cs có phải nó kế thừa từ Microsoft.Xna.Framework.game. Khi nhập dữ liệu (bằng 1 method trùng tên với tên của class) trong Game1.cs (thuờng ở LoadContent Method). Khi đã có Game trong tay bạn có thể dễ dàng lấy dữ liệu từ Game1.cs truyền cho các GameComponent (thông qua Service). Khi using Microsoft.Xna.Framework.GamerServices; nghĩa là chúng lấy khả năng cho phép XNA truyền dữ liệu từ chuơng trình chính (Game1.cs) sang Các gameComponent

Các gameComponent là những phần tạo lên 1 game hoàn chỉnh đc viết cho XNA. Bạn sẽ thấy chúng luôn có một biến đc nhập vào, đó là game và khi đó mỗi GameCompoment sẽ có sẵn một biến tên là Game (nó liên quan trực tiếp) đến game1.cs . VD bạn có thể thêm GameCompoment object vào game chính như sau: Game.Compoments.Add(object); Drawable cũng như GameCompoment, cái khác là nó có khả năng Draw mà ko cần thêm code ở game chính làm game code của chúng ta đơn giản đi rất nhiều. GameCompoment dành cho những thứ ko cần draw như camera, light, materials, input ...Biến Game thực sự rất hữu ích, khi mà bạn cần các giá trị từ game chính (VD: Game.GraphicDevice - nếu ko có nó thì đố bạn tìm được giá trị aspectRatio mà làm ko gian chiếu phối cảnh khi viết game 3D)

Contact me at [email protected] or http://xvna.forumb.biz

Page 9: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Ngoài ra nó có thể nhận giá trị mà Game chính truyền cho thông qua service, theo như VD phần 1:( ở phần 1, trong class game1.cs: Services.AddService(typeof(SpriteBatch), spriteBatch); ) Lấy service ở gameComponent: spriteBatch = Game.Services.GetService(typeof(SpriteBatch)) nếu bạn dùng Drawable, bạn sẽ dùng cái spriteBatch cho Draw method, từ đó Compoment sẽ có khả năng tự Draw kiểu như :spriteBatch.Draw(texture,position,Color.White)

chỉ cần base.Draw(gameTime) là đủ để Vẽ tất cả DrawableGameCompoment trong game là xong!

Tất cả những thứ liên quan đến service tốt nhất bạn sờ đến nó ở initilize() lúc này init của game chính đã chạy và biến truyền dữ liệu đó ko bị null, bạn sẽ ko mất thời gian debug mấy lỗi vớ vẩn như thế :D

Ngoài ra, hai thuộc tính của GameCompoment là Enable và Visiable, nếu chúng là false thì trong phần Base ở các method Update và Draw trong class Game chính sẽ ko chạy (tức là nó ko hề hoạt đông và ko nhìn thấy)

3. Sử dụng Texture, Audio, Video

Xem tại mục XNA cơ bản - Xvna.forumb.biz

Chương 3: Code Game Đầu tiên của bạn! - GetSix

1.Ý tưởng của game!

Đây là tài liệu dành cho newbie, nên game rất đơn giản. newbie nên tự coi và tự code game, tuy đơn giản những từ những game đơn giản này, bạn sẽ tích lũy nhiều kinh

Contact me at [email protected] or http://xvna.forumb.biz

Page 10: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

nghiệm cho nhưng game phức tạp hơn! Mình sẽ cố gắng code thật dễ hiểu và khoa học cho các bạn tiện theo dõi.

GetSix là trò chơi hết sức đơn giản. bạn sẽ quay súc xắc và nếu đc 6 điểm bạn sẽ chiến thắng, nếu ko game sẽ đưa ra số điểm bạn đổ đc và tạo cơ hội cho bạn đổ súc sắc một lần nữa. :> Nào bắt tay vào việc luôn chứ nhẩy :)

2.Tạo tài nguyên cho game!

Kich phai chuột vào mục Content trong cửa sổ solution >> Add new Item >> Sprite Font >> đặt tên cho Font là "font" >> Add

Contact me at [email protected] or http://xvna.forumb.biz

Page 11: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

3.Lập trình cơ bản cho GetSix

3.1 Tao số ngẫu nhiên!

Tạo số ngẫu nhiên thường là phần cơ bản của game, từ số ngẫu nhiên chúng ta tạo ra vị trí, tốc độ, số lượng, chỉ số sức mạnh... của đối tượng trong game một cách ngẫu nhiên! Người chơi ko biết đc một số ngẫu nhiên là bao nhiêu, điều này tạo ra hứng thú cho họ

Class mình xây dựng để tạo số ngẫu nhiên, sử dụng method Get(num) nhằm tạo 1 số nguyên ngẫu nhiên từ 0 đến num///namespace GetSix_Xvna.forumb.biz{ static class GetRanDom { static Random random = new Random();

public static int Get(int num) { random.GetHashCode(); return random.Next(num)+1; } }

Contact me at [email protected] or http://xvna.forumb.biz

Page 12: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010}

3.2 Điều khiển Input từ keyBoard bằng kỹ thuật Press và Release!

Class này xây dựng nhằm mục đích check input dễ dàng hơn cho player. Method Press(key) xác định khi một key dc nhấn xuống! method trả về true trong suốt quá trình key được nhấn! Method Release(Key) xac dinh khi một key được nhấn xuống, sau đó nó được nhả ra, khi nó nhả ra thì method này mới trả về true Method Update() phải được gọi trong Update(GameTime) của class Game của bạn!///namespace GetSix_Xvna.forumb.biz{ class Input { KeyboardState keyBoard ; KeyboardState lastKeyBoard = Keyboard.GetState();

public void Update() { lastKeyBoard = keyBoard; keyBoard = Keyboard.GetState(); } public bool Press(Keys key) { return keyBoard.IsKeyDown(key); } public bool Release(Keys key) { return (keyBoard.IsKeyUp(key) && lastKeyBoard.IsKeyDown(key)); } }}

3.3 Hoàn thiện trò chơi trong class Game chính!

Dưới đây là class chính cho trò chơi GetSix! namespace GetSix_Xvna.forumb.biz{ /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; //Cac bien ban khai bao': int number = 0; Input input = new Input(); SpriteFont font;

Đây là hàm cấu trúc cho game: public Game1() {

Contact me at [email protected] or http://xvna.forumb.biz

Page 13: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; }

Chúng ta thiết lập spriteBatch ở đây, load font từ Content ở đây cũng được! protected override void Initialize() {//Thiết lập cho spriteBatch của bạn ở đây, chúng ta sẽ dùng nó trong //việc Draw text lên game spriteBatch = new SpriteBatch(GraphicsDevice);//Load font từ content font = Content.Load<SpriteFont>("font"); base.Initialize(); }

Method Update này sẽ được gọi đi gọi lại trong suốt quá trình chạy game, mục đích là Kiểm tra tính lôgic của game thông qua các câu lệnh mà bạn code! protected override void Update(GameTime gameTime) {//Update cho Input input.Update(); //Nhan space de quay suc xac if (input.Release(Keys.Space)) //So diem suc xac la` 1 den 6! number = 1 + GetRanDom.Get(5); //Thoat neu nhan esc if (input.Release(Keys.Escape)) Exit();

base.Update(gameTime); }

Method Draw(GameTime) này làm nhiệm vụ đưa đồ họa lên màn hình, nhớ phải begin() spriteBatch trước khi bạn muốn Draw bất cứ thứ gì lên màn hình và End() sau khi đã Draw hết mọi thứ bạn muốn. protected override void Draw(GameTime gameTime) {//Thiết lập màu nền là CornflowerBlue! GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();

DrawText("Chao mung ban den voi tro choi Do suc xac!", new Vector2(100, 200),Color.Red);

if (number == 0) DrawText("Moi ban quay so", new Vector2(100, 300), Color.Purple); else if(number == 6) DrawText("Xin chuc mung, ban da chien thang khi quay dc so 6", new Vector2(100, 300), Color.Pink); else DrawText("Diem so hien tai ma ban quay duoc: " + number, new Vector2(100, 300), Color.PowderBlue);

DrawText("Nhan Space de bat dau quay so!", new Vector2(150, 400), Color.PapayaWhip); DrawText("Nhan ESC de thoat game!", new Vector2(150, 500), Color.OrangeRed);

Contact me at [email protected] or http://xvna.forumb.biz

Page 14: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 spriteBatch.End();

base.Draw(gameTime); }

Method DrawText , Draw nội dung , vị trí viết chữ và màu chữ public void DrawText(string st, Vector2 pos,Color color) { spriteBatch.DrawString(font, st, pos, color); }

Xong rùi đó!

Chương 4: Viết một Game có tính tương tác cao - Pong!

1.Tại sao lại là pong?

Pong là một trò chơi cổ điển, Chính xác thì nó là game đầu tiên của thế giới! tuy vậy pong lại là một trò chơi thú vị, có tính tương tác cao và có đủ yếu tố của một game hoàn chỉnh. Thêm nữa code trò pong khá đơn giản nên newbie có thể nắm được mã lệnh một cách dễ dàng, từng đó bạn sẽ rút ra đc kinh nghiệm lập trình xna cho bản thân

Contact me at [email protected] or http://xvna.forumb.biz

Page 15: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Trong pong sẽ có 2 cây vợt (pad) và 1 quả bóng (ball). Người chơi hoặc AI sẽ điều khiển vợt, đánh bóng và nếu đối phương ko đỡ đc quả bong bạn đánh về phía họ, bạn sẽ ghi được 1 điểm!

Chúng ta sẽ xây dựng 2 phiên bản cho pong: player vs player và player vs AI !

2. Chuẩn bị tài nguyên

Ko có gì đặc biệt cả, các bạn chỉ cần kiểu như:

: Trái banh để đánh

: Cây vợt

1 Sprite Font (Cách tạo có ở chương trước)

3. Code Game!

Bạn nhận thấy cả ball và pad đều chuyển động, nếu muốn một vật chuyển động nó phải có 2 yếu tố là vị trí và vận tốc. bạn cũng cần kiểm tra va chạm của cả vợt và bóng trong quá trình chơi đúng ko nào? vậy chúng ta đã tìm ra những điểm chung của pad và ball, do đó sẽ rất tiện nếu chúng ta xây dựng 1 lớp cơ sở là Sprite từ đó pad và ball sẽ kế thừa từ Sprite! Hãy nhớ thứ tự code game: Bao giờ cũng phải code lớp cơ sở trước, sau đó đến các lớp mở rộng của nó và cuối cùng mới là class game chính !

Sprite là gì? Nói một cách nôm na thì sprite và những vật thể có thể di chuyển và tương tác trong game (người chơi, kẻ thù, NPC...). Phân biệt nó với static hay solid object, tức là những đối tượng cứng ko tương tác hay thay đổi trong game (như bức tường, hòn đá...).

3.1 Sprite class

Contact me at [email protected] or http://xvna.forumb.biz

Page 16: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Dưới đây là chi tiết cho lớp Sprite:

namespace Pong_Xvna.forumb.biz{ /// <summary> /// This is a game component that implements IUpdateable. /// </summary> public class Sprite : Microsoft.Xna.Framework.DrawableGameComponent {

Điểm chung của ball và pad sẽ được thể hiện ở đây. Texture (một bức ảnh 2D bao phủ lên đối tượng trong game)Vị trí, vận tốc, SpriteBatch làm nhiệm vụ Draw Sprite!Điểm Center (trả về tọa độ tâm của Sprite) làm cơ sở cho thuật toán nảy cho trái banh!Đánh dấu là protected để đảm bảo lớp mở rộng của bạn có thể sử dụng lại những biến này!

protected Texture2D texture; protected Vector2 position, velocity; protected SpriteBatch sp;

Hãy tạo thói quen xây dựng thuộc tinh, tất nhiên, bạn có thể đánh dấu là public cho position và velocity, tuy thế với 1 game phức tạp , thuộc tính sẽ làm bạn dễ dàng nhận ra giá trị hơn nhiều so với biến. Tạo thói quen đặt tên : viết thường cho biến và viết hoa chữ cái đầu tiên cho thuộc tính! Như là 1 quy tắc ngầm vậy và bạn sẽ ko bao giờ nhầm lẫn giữa 2 loại này. public Vector2 Center { get { return position + new Vector2(texture.Width / 2, texture.Height / 2); } } public Vector2 Position { get { return position; } set { position = value; } } public Vector2 Velocity { get { return velocity; } set { velocity = value; } }

Method cấu trúc cho sprite, cái "base" ở đây là do nó kế thừa từ DrawableGameComponent! public Sprite(Game game,Vector2 pos, Vector2 velo) : base(game) { this.position = pos; this.velocity = velo;

Sử dụng Service lấy từ class Game chính, sau này khi code class game chính, chúng ta sẽ Add service, bây giờ cứ GetService cái đã ! sp = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));

Contact me at [email protected] or http://xvna.forumb.biz

Page 17: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

mã lệnh thể hiện List Component của Class game chính sẽ add Sprite vào, sau này nó sẽ được tự động Update và Draw, bạn khỏi phải dài dòng code thêm trong class game chính (Game ở đây là biến có liên quan trực tiếp đến Game chính của bạn (Game1.cs) Game.Components.Add(this); }

Bây giờ đến thuật toán va chạm. do đặc thù của pad là object pad có dạng hcn nên chúng ta viết method trả về hcn bao quanh lấy pad! Như dưới đây:

public Rectangle getBound() { return new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height); }

Để xác định va chạm giữa 2 Sprite, ta chỉ việc xem xem hcn bao quanh 2 Sprite đó có trùng nhau hay ko! Intersects() method sẽ xác định việc đó và hành dưới đây sẽ xác định xem 2 Sprite có va chạm nhau hay ko! Quá đơn giản phải không bạn. public bool CheckCollides(Sprite s) { return getBound().Intersects(s.getBound()); }

Không cần Update gì nhiều, đoạn code này bạn cũng hiểu là khi velocity != vector2.Zero thì vật sẽ di chuyển theo 2 trục Ox và Oy theo các giá trị velocity.X và velocity.Y public override void Update(GameTime gameTime) { position += velocity;

base.Update(gameTime); }

Quá đơn giản! đưa sprite lên màn hinh của người chơi. public override void Draw(GameTime gameTime) { sp.Draw(texture, position, Color.White); base.Draw(gameTime); } }}

3.2 Xây dựng lớp Pad (player control)

Như bạn thấy, pad kế thừa từ sprite!

public class Pad : Sprite {

Input, chúng ta cũng sẽ getService nó từ Game chính!

Contact me at [email protected] or http://xvna.forumb.biz

Page 18: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Index là chỉ số cho người chơi, do index khác nhau nên sau này mã lệnh để Check Keyboard cũng sẽ khác nhau.Point là số điểm người chơi, dựa vào đó mà xác định thắng thua.Ở đây pad sẽ có chuyển động gia tốc để tăng tính hấp dẫn , gia tốc = 2. Input input; int index; int point = 0;

float accel = 2f;

public int Point { get { return point; } set { point = value; } } public Pad(Game game,Vector2 pos,Vector2 velo,int index) : base(game,pos,velo) { this.index = index;

Đây là class riêng cho pad, bạn có thể load texture ở đây, tuy vậy ở Sprite thì ko được load Texture do nó là đồ dùng chung của pad và ball texture = Game.Content.Load<Texture2D>("pad"); input = (Input)Game.Services.GetService(typeof(Input)); }

Như bạn thấy , tùy theo index mà sẽ có cách Check KeyBoard khác nhau. Vận tốc thay đổi bởi gia tốc, do đó pad sẽ di chuyển theo kiểu chậm dần đều hay nhanh dần điều! public override void Update(GameTime gameTime) {//Pad chuyển dộng lên trên if (index == 1 ? input.Press(Keys.Up) : input.Press(Keys.W)) velocity.Y -= accel;//Pad chuyển động xuống dưới else if (index == 1 ? input.Press(Keys.Down) : input.Press(Keys.S)) velocity.Y += accel;//Do có gia tốc, ta phải giới hạn lại vân tốc! giá trị chỉ nằm trong khoảng [-7,7] velocity.Y = MathHelper.Clamp(velocity.Y, -7, 7);

Vector2 lastPos = position;//Base se tien hành : position+= velocity;

base.Update(gameTime);//Ngan chan pad ra khoi man hình (kick thước: 800 x 500) if (position.Y < 0 || position.Y > 500 - texture.Height) position = lastPos; }

3.3 Ball Class.

public class Ball : Sprite {

Contact me at [email protected] or http://xvna.forumb.biz

Page 19: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 public Ball(Game game,Vector2 pos, Vector2 velo) : base(game,pos,velo) {//load texture texture = Game.Content.Load<Texture2D>("ball"); }

Ball sẽ đảo tốc độ Y nếu bóng chạm biên!, tại sao chúng ta ko KT tọa X? đơn giản là Khi bóng khi quá màn hình ở trục X tức là 1 bên đã ghi điểm, tốt nhất phần ghi điểm chúng ta hãy code ở class Game chính. public override void Update(GameTime gameTime) { if (position.Y < 0 || position.Y > 500 - texture.Height) velocity.Y *= -1;

base.Update(gameTime); }

3.4 Class Game Chính (Game1.cs)

Class này Kế thừa từ Game của xna!

public class Game1 : Microsoft.Xna.Framework.Game {

Chúng ta khai báo pad, ball, font (Để ghi điểm người chơi), input (class từ chương trước) GraphicsDeviceManager graphics; SpriteFont font; SpriteBatch spriteBatch; Input input = new Input();

Pad player1, player2; Ball ball;

public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content";

//Đặt kick thước màn hình: graphics.PreferredBackBufferWidth = 800; graphics.PreferredBackBufferHeight = 500; }

Chủ yếu là thiết lập cho các biến đã khai báo ở trên. Đặt 2 pad tại 2 đầu màn hình theo tọa độ của nó, truyền cho ball tốc độ X dương nhằm cho biết player bên trái sẽ là người giao bóng! protected override void Initialize() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); Services.AddService(typeof(SpriteBatch), spriteBatch); Services.AddService(typeof(Input), input);

Contact me at [email protected] or http://xvna.forumb.biz

Page 20: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 font = Content.Load<SpriteFont>("font");

player1 = new Pad(this, new Vector2(0, 300), Vector2.Zero, 0);

player2 = new Pad(this, new Vector2(780, 300), Vector2.Zero, 1);

ball = new Ball(this, new Vector2(30, 330), new Vector2(5, 0));

base.Initialize(); }

Đầu tiên phải Update Input! Kiểm tra va chạm của pad với ball, từ đó thay đổi vận tốc cho ball. Có nhiều cách để làm việc này. Chúng ta tính khoảng cách từ trung tâm pad đến trung tâm ball để xác định tốc độ trục Y cho ball. Có 2 lý do để sài thuật toán này.+ Nó rất đơn giản chỉ là : Math.Abs(ball.Center.Y - player1.Center.Y)/5+ Hiệu quả: khi người chơi đánh 1 pha bóng mạo hiểm (điểm chạm của quả bóng nằm xa trung tâm của pad, do đó player dễ đánh hụt) họ sẽ làm cho vận tốc trục Y của ball đặt giá trị cao (bóng sẽ nảy rất mạnh ) gây khó khăn cho đối thủ! Ngược lại thì 1 pha bóng an toàn (điểm chạm gần tâm pad) sẽ đẩy bóng nảy yếu và đối thủ dễ phản công! Cái này thể hiện 1 nguyên tắc rất cơ bản của game: Liều ăn nhiều protected override void Update(GameTime gameTime) { input.Update();

if (player1.CheckCollides(ball)) ball.Velocity = new Vector2(ball.Velocity.X * -1, Math.Abs(ball.Center.Y - player1.Center.Y)/5); if (player2.CheckCollides(ball)) ball.Velocity = new Vector2(ball.Velocity.X * -1, Math.Abs(ball.Center.Y - player2.Center.Y)/5);

Sau khi bóng vượt qua biên màn hình, điểm sẽ được ghi và trái bóng được giao từ phía người chơi vừa ghi điểm, code dưới đây thể hiện điều này: if (ball.Position.X < 0) { player2.Point++; ball.Position = new Vector2(740, 330); ball.Velocity = new Vector2(-5, 0); player1.Position = new Vector2(0, 300); player2.Position = new Vector2(780, 300); } if(ball.Position.X > 760) { player1.Point++; ball.Position = new Vector2(30, 330); ball.Velocity = new Vector2(5, 0); player1.Position = new Vector2(0, 300); player2.Position = new Vector2(780, 300); } base.Update(gameTime); }

Contact me at [email protected] or http://xvna.forumb.biz

Page 21: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Cuối cùng là Draw method. Bạn phải begin spriteBatch, sau đó, Draw cho các GameComponent thông quá base.Draw(GameTime), cuối cùng dùng SpriteBatch vẽ điểm số của từng người chơi lên màn hình protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.Black);

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);// Draw cho tất cả gameComponent có trong Components của Game1 !// ball và pad điều đã add vào list này, xem lại lớp Sprite.cs

base.Draw(gameTime);

spriteBatch.DrawString(font, "Player 1: " + player1.Point, new Vector2(100, 100), Color.White); spriteBatch.DrawString(font, "Player 2: " + player2.Point, new Vector2(600, 100), Color.White);

spriteBatch.End(); } }}

Về cơ bản thì Pong: player vs player đã hoàn thành, bạn chỉ cần xác định ai win kiểu như:if(player1.Point>4){

spriteBatch.DrawString(font, "Player 1 win!", new Vector2(200, 200), Color.White);Components.Clear();

} else if (player2.Point > 4){

Components.Clear(); spriteBatch.DrawString(font, "Player 2 win!", new Vector2(200, 200), Color.White);}

Sẽ xác định người đầu tiên đạt 5 điểm sẽ dành chiến thắng!

Phần tiếp theo mình sẽ nói đến cách xây dựng AI cho Pong!

4. Xây dựng AIPad

4.1 Viết Class AIPad

Bạn xây dựng lớp AIPad kế thừa từ Sprite, chúng ta chỉ cần code như dưới đây, đơn giản là AIPad sẽ có cách chuyển động khác với Pad mà người chơi điều khiển. Chúng ta sẽ code AI tại class Game chính. /// </summary> public class AIPad : Sprite { int point = 0;

Contact me at [email protected] or http://xvna.forumb.biz

Page 22: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

public int Point { get { return point; } set { point = value; } } public AIPad(Game game, Vector2 pos, Vector2 velo) : base(game, pos, velo) { texture = Game.Content.Load<Texture2D>("pad"); } }

4.2 Sửa lại trong game chính như sau:

Đầu tiên tạo ra thể hiện cho AIPad:

AIPad player2;

Có 4 yếu tố tạo nên 1 AI tốt:-Dễ bị đánh bại: Gamer nào cũng muốn win, nếu họ ko win đc, họ sẽ ko đời nào chơi game của bạn.-không dễ bị đánh bại: Đối thủ quá yếu làm gamer thấy chán và họ đi tìm một game khó hơn.-Khả năng thay đổi: Nó có thể từ dễ trở thành khó hơn khi người chơi lên tay và giữ họ ngồi xuống lâu hơn để chinh phục các mức độ mới-Khả năng sống động: AI cần có tính logic, có thể dự đoán đc giống như là một con người đnag chơi cùng bạn vậy (di chuyển, tấn công...) giúp người chơi có thể phán đoán và chiến thắng trong game.

Bây giờ nói đến cách tạo ra AI. Mấu chốt của game là làm sao cho pad đánh trúng (va chạm) với ball để đánh quả banh về phía đối thủ phải hok nào. Giả sử ban code trong Update như sau: AIPad.Position.Y = Ball.Position.Y (Thực ra la hok dc vì Position là thuộc tính)thì mọi chuyện sẽ ra sao? Hiển nhiên AIPad luôn cùng tọa độ Y với ball và do đó nó luôn di chuyển cùng với ball => nó sẽ ko bao giờ đánh hụt. AI đã làm quá tốt, ko có 1 chút sơ hở nào và đây cũng là điểm ko tốt của AI. Người chơi ko bao giờ hứng thú với AI Pad ko bao giờ đánh hụt. Nói cách khác là player sẽ ko bao giờ chiến thắng, họ sẽ thấy điều này ko thú vị . Do đó chúng ta sẽ code cho AIpad có tính "người" hơn. Tức là nó vẫn có sơ hở để người chơi có thể chiến thắng

Theo cách tính vân tốc Y của ball: Math.Abs(ball.Center.Y - player1.Center.Y)/5

Contact me at [email protected] or http://xvna.forumb.biz

Page 23: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Trong file mẫu mình làm, quả bóng ball.texture.Width/2 = 20 pixel, Pad.texture.Width/2 = 30 Pixel. Do đó khoảng cách xa nhất mà hai điểm center của pad và ball có thể có mà vẫn đảm bảo va chạm giữa chúng là 50 pixel! Chia cho 5 tức là vận tốc tối đa (theo độ lớn) mà ball có theo trục Y (ball.Velocity.Y) sẽ là 50/5 = 10 pixel / 1 lần Update . Vậy cú đánh tốt nhất của bạn có thể có sẽ có đổ nảy (tốc độ Y) của trái banh là 10 pixel. Vậy nếu mình code như sau:if (player2.Center.Y < ball.Center.Y) { player2.Velocity = new Vector2(0, 10); } else { player2.Velocity = new Vector2(0, -10); }

Thì AI cũng ko bao giờ đánh hụt, đơn giản tốc độ Y của nó đã bằng với tốc độ Y cao nhất có thể có là 10 pixel / 1 lần Update.

Để AIpad người hơn, chúng ta sửa lại

//Trong Update method !

player2 = new AIPad(this, new Vector2(780, 300), Vector2.Zero);

if (player2.Center.Y < ball.Center.Y) { player2.Velocity = new Vector2(0, 5); } else { player2.Velocity = new Vector2(0, -5); }

Nếu như vậy với những cú đánh khó, AIpad sẽ bó tay chịu chết! nhưng với những cú đánh dễ, nó sẽ phản đòn lại bạn và bạn sẽ loay hoay tìm cách chống đỡ! Sao nào, thú vị đấy chứ, bây giờ bạn đã có 1 AI tạm ổn để chơi cùng! Để tăng độ khó, bạn tăng tốc độ Y của AIpad từ 5 lên 9 xem nào Nâng cấp game: thử tăng số lượng pad cho nhiều người chơi hoặc chơi 1 lúc nhiểu quả ball , tạo vật cản trên đường đi của ball ...

Contact me at [email protected] or http://xvna.forumb.biz

Page 24: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Chương 5: Các tạo gameComponent một Cách "Động" - Asteroids Project

Pong ở chương 4 là một game thú vị, phải ko nào? nhưng những thể hiện được chúng ta tạo ra hoàn toàn bằng tay (khai báo, cấu trúc, điều khiển ... )

Thực tế trong game, object phải được tạo ra một cách "động", tùy thuộc điều kiện của trò chơi. Ví dụ, 1 RangeMonster sẽ bắt ra 100 đạn lửa, đạn lửa sẽ phải đc tạo ra theo cách động (chẳng lẽ bạn định khai báo 100 đạn lửa rùi khi nào cần thì Show nó ra ah)

Lần này mình sẽ hướng dẫn các bạn viết trò Asteroids. Một phi thuyền do người chơi sẽ lơ lủng trong ko gian, phi thuyền bắn vở các thiên thạch trôi gần mình, khi vỡ sẽ có nhiều mảnh thiên thạch nhỏ hơn vỡ ra, và cứ thế nếu cứ bắn , nó sẽ lại vỡ ra . Tất nhiên tất cả thiên thạch sẽ được tạo ra 1 cách động! Ngoai ra trong game, minh sẽ hướng dẫn cách tạo GUI đơn giản, các sử dụng particle effect

Chung ta cũng sẽ xóa bỏ thiên thạch bằng cách "đông" - dùng mã lệnh, khi chúng có kích thước quá nhỏ!

Tài nguyên các bạn có thể sử dụng trong asteroids project mẫu mà mình làm (code và debug hết gần 4h )

Hình dưới đây là toàn bộ nội dung dự án :

Contact me at [email protected] or http://xvna.forumb.biz

Page 25: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

1.Core Folder

Chứa những class cơ sở: Sprite và GameScene-Sprite mở rộng ra cho Player, Rock và bullet-GameScene mở rộng ra cho StartScene, ActionScene và EndScene.

1.1Sprite

Sprite khá giống với sprite trong dự án pong, mình thêm vài thứ sau:

//Method loại bỏ sprite khi bạn ko cần dùng đến nó nữa (thiên thạch bị nổ chẳng hạn)public virtual void Remove() { position = -100 * Vector2.One; Visible = false; Enabled = false; Dispose(true); }

Contact me at [email protected] or http://xvna.forumb.biz

Page 26: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

//Trong update thêm code để sprite cuộn trong màn hình public override void Update(GameTime gameTime) { position += velocity; //Cuon trong man hinh if (position.X < 0) position.X = 800 - texture.Width; if (position.X > 800 - texture.Width) position.X = 0; if (position.Y < 0) position.Y = 600 - texture.Height; if (position.Y > 600 - texture.Height) position.Y = 0; base.Update(gameTime); }

Đầu tiên chúng ta nói qua về một Draw() method đầy đủ các tham số:spriteBatch.Draw(texture, position , sourceRectangle, Color.White, angle, origin, scale, SpriteEffects, depth);Các tham số lần lượt là:Texture: bức ảnh load từ Content và sẽ bao phủ lên toàn bộ sprite.Position: Vị trí mà XNA sẽ Draw sprite lên màn hình của gamerSourceRectangle: hình chữ nhật trên bức ảnh là chúng ta vừa load vào (chỉ có những vùng trên bức ảnh thuộc hình chữ nhật đó mới đc thể hiện trong game. Bạn có thể khởi tạo một Rectangle với thuộc tính tọa độ X,Y và chiều dài , chiều rộng.Color: Màu sẽ tô nếu bức ảnh có vùng trống (tuy nhiên tô kiểu AlphaBlend thì nó sẽ tự động không tô màu những vùng ảnh trống)(float)angle: Góc sẽ xoay sprite (mặc định là 0f)(Vector2)Origin : tọa độ điểm trung tâm sprite (đặt là tọa độ tâm của một frame),

Nếu angle != 0 thì sprite sẽ xoay xung quanh điểm origin.Scale: Phóng to hay thu nhỏ sprite theo cùng tỉ lệ width/heightSpriteEffect: hiệu ứng lật texture (ngang, dọc hoặc ko dùng)Depth: Độ sâu (sprite nào có depth cao hơn thì được draw chèn lên trên sprite có

detph thấp hơn, nếu cùng depth thì sprite nào đc tạo ra trước sẽ bị sprite Draw đè lên trên (chỉnh thêm ở Begin() method của spriteBatch nữa... )

Trong Draw method, mình sử dụng sp.Draw với đầy đủ 7 tham số public override void Draw(GameTime gameTime) { sp.Draw(texture, position,new Rectangle(0,0,texture.Width,texture.Height), Color.White,angel, new Vector2(texture.Width/2,texture.Height/2) ,Scale,SpriteEffects.None,1f); base.Draw(gameTime); }

Contact me at [email protected] or http://xvna.forumb.biz

Page 27: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 20101.2.GameScene Class:

Bạn tạo ra 1 lớp mới thuôc loại DrawableGameCompoment, gọi là GameScene, có thể đánh dấu nó là abtract cũng đc. Vì chúng ta sẽ tạo ra những class khác nhau cho những màn khác nhau dựa trên sự thừa kế từ GameSceneBan tạo những method sau:Show() : Enable và Visiable của scêne là true, khi đó màn chơi sẽ đc hiển thị (đc update và draw ở game chính)Hide() : ngược với Show(), dùng khi bạn muốn qua màn khác

GameScene ko có mảng Compoments như của Game chính, dó đó bạn có thể tạo mảng này (mảng chứa các gameCompoment khác trong màn, VD như là menu ở màn start, Player và Enemy ở màn Action)

Compoments của GameScene cũng hoạt động giống như ở game chính vậy, do đó ở Update và Draw method, bạn lần lượt Update và Draw cho mỗi object (kế thừa từ GameCômpoment) có các thuộc tính Enable và Vísiable là true như sau:

public override void Update(GameTime gameTime) { // Update the child GameComponents for (int i = 0; i < components.Count; i++) { if (components[i].Enabled) { components[i].Update(gameTime); } }

base.Update(gameTime); }

/// <summary> /// Allows the game component draw your content in game screen /// </summary> public override void Draw(GameTime gameTime) { // Draw the child GameComponents (if drawable) for (int i = 0; i < components.Count; i++) { GameComponent gc = components[i];

Contact me at [email protected] or http://xvna.forumb.biz

Page 28: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 if ((gc is DrawableGameComponent) && ((DrawableGameComponent) gc).Visible) { ((DrawableGameComponent) gc).Draw(gameTime); } } base.Draw(gameTime);

}Dưới đây là toàn bộ code của GameScene:

#region Using Statements

using System.Collections.Generic;using Microsoft.Xna.Framework;

#endregion

namespace game{ /// <summary> /// This is the base class for all game scenes. /// </summary> public abstract class GameScene : DrawableGameComponent { /// <summary> /// List of child GameComponents /// </summary> private readonly List<GameComponent> components;

public GameScene(Game game) : base(game) { components = new List<GameComponent>(); Visible = false; Enabled = false; }

/// <summary> /// Show the scene /// </summary> public virtual void Show() { Visible = true;

Contact me at [email protected] or http://xvna.forumb.biz

Page 29: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 Enabled = true; }

/// <summary> /// Hide the scene /// </summary> public virtual void Hide() { Visible = false; Enabled = false; }

/// <summary> /// Components of Game Scene /// </summary> public List<GameComponent> Components { get { return components; } }

/// <summary> /// Allows the game component to update itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> public override void Update(GameTime gameTime) { // Update the child GameComponents for (int i = 0; i < components.Count; i++) { if (components[i].Enabled) { components[i].Update(gameTime); } }

base.Update(gameTime); }

/// <summary> /// Allows the game component draw your content in game screen

Contact me at [email protected] or http://xvna.forumb.biz

Page 30: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 /// </summary> public override void Draw(GameTime gameTime) { // Draw the child GameComponents (if drawable) for (int i = 0; i < components.Count; i++) { GameComponent gc = components[i]; if ((gc is DrawableGameComponent) && ((DrawableGameComponent) gc).Visible) { ((DrawableGameComponent) gc).Draw(gameTime); } } base.Draw(gameTime); } }

}

Sử dụng GameScene cũng đơn giản thôi, bạn tạo class cho Action Scêne chả hạn, khai báo các thành phần của mảng này (Enemy, player thuộc loại Drawable) và add nó vào mảng compoments của GameScene. Khi dùng trong game chính , vậy là khi show chúng sẽ hoạt động và nhìn thấy, hide khi bạn chuyển màn (dựa vào thuộc tính Enable và Visiable của GameScene) và Scene tự động Update và Draw (dựa vào thuộc tính Enable và Visiable của chính thành phần trong mảng đó).

Cách1 đơn giản hơn rất nhiều đúng ko? Nhưng chỉ là với sl màn it thôi, màn nhiều thì switch mệt nghỉ! Cách 2 thì phức tạp hơn nhưng tiện ở chỗ các compoments sẽ tự nó Update và Draw, nếu game có nhiều nhân vật (VD: 100 Enemy khác nhau) thì cũng tiết kiệm đc thời gian code đáng kể đấy! nếu dùng cách 2 khi chuyển màn trong game chính , bạn dùng method sau để chuyển màn:activeScene = anyScene;

protected void ShowScene(GameScene scene) { activeScene.Hide(); activeScene = scene; scene.Show(); }

Contact me at [email protected] or http://xvna.forumb.biz

Page 31: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Ở đây mình viết thêm hiệu ứng hình ảnh thông qua biến color, kỳ thuật đây là độ mờ đục (tham số 4) của một new Color ! do thay đổi độ mờ đục của hình nền mà bạn sẽ nhìn thấy như thể nó vừa hiện ra.

2. Effect folder

Nói chung thì đây là class tạo ra effect nổ, cháy thông qua các particle (texture rất nhỏ), do chuyển động ko ngừng nên người xem có cảm giác có thứ gì đó đang phập phùng, (nổ, cháy...)

Các class fire, smoke và explosion chứa các chỉ số cho phép bạn tạo ra effect khác nhau, ... cũng khá đơn giản...

3. GUI Folder

Phần này mình viết mẫu các lớp Button (tạo ra nút chọn), Menu (gồm 1 danh sách button và check keyboard để điều khiển button) và Bar (một thanh hiện thị HP của player)

Cách sử dụng những lớp này xem thêm ở mã lệnh các Scene nhé.

4.Helper Folder

Chỉ bổ sung thêm lớp AssetPath, chứa các hằng số là đường đẫn đến resource trong content để tiện khi code thui

5.Object Folder

Ở đây velocity của player được tính dụa trên thuộc tính góc (angel) và tốc độ (speed)//KT phim di chuyen if (input.Press(Keys.Up)) speed += 0.2f; if (input.Press(Keys.Down)) speed -= 0.2f; if (input.Press(Keys.Right)) angel += (float)Math.PI / 50; if (input.Press(Keys.Left)) angel -= (float)Math.PI / 50; speed = MathHelper.Clamp(speed, -3, 5);

velocity = new Vector2(speed * (float)Math.Cos(angel - MathHelper.PiOver2), speed * (float)Math.Sin(angel - MathHelper.PiOver2));

Contact me at [email protected] or http://xvna.forumb.biz

Page 32: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Mọi người xem bài "Lập trình ứng dụng toán và lý" tại mục xna cơ bản nhéHàm để tạo ra bullet một cách động://Check key de ban' if (input.Press(Keys.Space)) { if (time > 300) { time -= 300; Bullet b = new Bullet(game, Position, Vector2.Zero,angel); bullets.Add(b); } else { time += gameTime.ElapsedGameTime.Milliseconds; } } else { time = 300; }

Thực ra bullet cũng chuyển động dựa vào angle và speed như player, do bullet có speed cao hơn (phần init của bullet) và có cùng angle với player => bullet sẽ bay cùng hướng với player và có cảm giác phi thuyền đang bắn ra đạn!Đây là đoạn mã Update của bullet:public override void Update(GameTime gameTime) { velocity = new Vector2(speed * (float)Math.Cos(angel - MathHelper.PiOver2), speed * (float)Math.Sin(angel - MathHelper.PiOver2));

//Neu co va cham, bullet tu tieu huy position += velocity;

if (position.X < 0 || position.Y < 0 || position.X > 750 || position.Y > 550) { Remove(); } }

Bullet ko cuộn mà sẽ bị remove khi ra khỏi biên màn hình!

6.Scene Folder

Đều kế thừa từ gameScene, mọi thể hiện đều tận dụng đc list DrawableGameComponent của GameScene, thế nên những class nãy giờ mình viết, mình đều add vào cái List này, (GUI, Sprites... ) rất tiện đúng ko?

6.1 SceneManager:

Contact me at [email protected] or http://xvna.forumb.biz

Page 33: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010public class SceneManager : Microsoft.Xna.Framework.DrawableGameComponent { GameScene active; StartScene start; ActionScene action; HelpScene help; EndScene end; List<GameScene> sceneList = new List<GameScene>();

public List<GameScene> SceneList { get { return sceneList; } } internal EndScene End { get { return end; } } public GameScene Active { get { return active; } } internal HelpScene Help { get { return help; } } internal StartScene Start { get { return start; } } public ActionScene Action { get { return action; } set { action = value; } }

public SceneManager(Asteroids game) : base(game) { start = new StartScene(game, Game.Content.Load<Texture2D>(AssetPath.BG + "startBG")); action = new ActionScene(game, Game.Content.Load<Texture2D>(AssetPath.BG + "battleBG")); help = new HelpScene(game, Game.Content.Load<Texture2D>(AssetPath.BG + "startBG")); end = new EndScene(game, Game.Content.Load<Texture2D>(AssetPath.BG + "startBG"));

sceneList.Add(start); sceneList.Add(action); sceneList.Add(help); sceneList.Add(end);

active = start; ShowScene(start); }

/// <summary> /// Allows the game component to perform any initialization it needs to before starting

Contact me at [email protected] or http://xvna.forumb.biz

Page 34: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 /// to run. This is where it can query for any required services and load content. /// </summary> public override void Initialize() { foreach (GameScene scene in sceneList) scene.Initialize();

base.Initialize(); }

Ở đây, đầu tiên tạo ra một danh sách các màn (Scene) trong game, từ đó mình khai báo, thiết lập các màn và Add nó vào líst. Ngoài ra khai báo thêm 1 ActiveScene nhằm mục đích:+bạn muốn chạy scene nào thì gán nó thành ActiveScene thông qua ShowScene method !+Quá trình Update và Draw Scene, nó chỉ thực hiện với ActiveScene, do đó bạn sẽ tốn ít tài nguyên máy tính khi phải lặp đi lặp lại mã lệnh trong Update và Draw !

public void ShowScene(GameScene scene) { active.Hide(); scene.Initialize(); active = scene; scene.Show(); } /// <summary> /// Allows the game component to update itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> public override void Update(GameTime gameTime) { active.Update(gameTime);

base.Update(gameTime); } public override void Draw(GameTime gameTime) {

active.Draw(gameTime);

base.Draw(gameTime); } }}

Quá đơn giản đúng ko nào

6.2 StartScene, EndScene.

Thêm một vài button, add nó vào compoments...

Contact me at [email protected] or http://xvna.forumb.biz

Page 35: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010

Cái chính là biến game ở đây, tham số thuộc kiểu Asteroids , tức chính là class Game chính của chúng ta. Mình tạo 1 thuộc tính SceneManager trả về biến sceneManager của game chính, do đó từ những Scene phụ như Start, End, bạn cũng có thể điều khiển việc chuyển màn thông qua SceneManager !class StartScene:GameScene { Button start; Button end;

public StartScene(Asteroids game, Texture2D BG) : base(game, BG) { Compoments = new List<DrawableGameComponent>(); Texture2D active = game.Content.Load<Texture2D>(AssetPath.GUI+"Selected"); Texture2D wait = game.Content.Load<Texture2D>(AssetPath.GUI + "NoSelect"); start = new Button(game, active, wait, Button.Status.active,"Start!"); start.Position = Vector2.Zero; end = new Button(game, active, wait, Button.Status.wait,"Quit"); end.Position = new Vector2(0, 50); listButton.Add(start); listButton.Add(end); menu = new Menu(game, listButton); Compoments.Add(menu); input = (Input)Game.Services.GetService(typeof(Input)) as Input; } public override void Update(GameTime gameTime) { if (menu.Index == 0 && input.Release(Keys.Enter)) { game.SceneManager.Action = new ActionScene(game, game.Content.Load<Texture2D>(AssetPath.BG + "battleBG")); game.SceneManager.ShowScene(game.SceneManager.Action); } if (menu.Index == 1 && input.Release(Keys.Enter)) Game.Exit(); base.Update(gameTime); } }

6.3 ActionScene

Để update và check va chạm cho các object trong game (rock, player, bullet), xem mã sau:

for (int i = 0; i < rocks.Count;i++ ) { foreach (Bullet b in player.Bullets) { //KT va cham bullet voi rock if (b.CheckCollides(rocks[i])) { b.Remove(); explosion.AddParticles(rocks[i].Center);

Contact me at [email protected] or http://xvna.forumb.biz

Page 36: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 smoke.AddParticles(rocks[i].Center); player.Point += 100; //Tao them 3 rock nho? hon if (rocks[i].Scale > 0.9f) { Rock r1 = new Rock(game, rocks[i].Center, new Vector2(GetRanDom.Get(5) - 2, GetRanDom.Get(5) - 2), rocks[i].Scale * 2 / 3); rocks.Add(r1); Compoments.Add(r1); Rock r2 = new Rock(game, rocks[i].Center, new Vector2(GetRanDom.Get(5) - 2, GetRanDom.Get(5) - 2), rocks[i].Scale * 2 / 3); rocks.Add(r2); Compoments.Add(r2); Rock r3 = new Rock(game, rocks[i].Center, new Vector2(GetRanDom.Get(5) - 2, GetRanDom.Get(5) - 2), rocks[i].Scale * 2 / 3); rocks.Add(r3); Compoments.Add(r3); } rocks[i].Remove(); } //Update cho bullet } //KT va cham cua player voi rock if (player.CheckCollides(rocks[i])) { fire.AddParticles(player.Position); smoke.AddParticles(player.Position); rocks[i].Remove(); player.HitPoint--; if (player.HitPoint <= 0) { score = player.Point; game.SceneManager.ShowScene(game.SceneManager.End); } }

Class cho từng object chỉ nên code những vấn đề của riêng object đó, còn khi những object tương tác với nhau, tốt hơn bạn nên code trong Scene chung của các object, ở đây là ActionScene. Dùng lệnh for và foreach để KT check va chạm giữa các object, ngoài ra còn remove những object ko còn sử dụng đã được gọi phương thức Remove() Việc remove object khoi list object (bullets, rocks) và component của GameScene sẽ làm cho số lần lặp mã lệnh mỗi đợt Update và Draw giảm xuống, game cũng sẽ chạy mượt hơn (trò này ít chứ mấy game chiến thuật thì có cả ngàn object)

if (!rocks[i].Enabled) { Compoments.Remove(rocks[i]); rocks.Remove(rocks[i]); } for (int i = 0; i < player.Bullets.Count;i++) if (player.Bullets[i].Enabled) player.Bullets[i].Update(gameTime); else

Contact me at [email protected] or http://xvna.forumb.biz

Page 37: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 player.Bullets.Remove(player.Bullets[i]));

Action có 1 biến lưu lại số điểm người chơi - score.

score = player.Point;

(mỗi lần bắn trúng rock, score của player sẽ tăng), khi player chết (HP <0), score sẽ đưa ra thành tích người chơi ở EndScene.

7. Class game chính - Asteroids.cs Game chính hầu như chả có gì ngoài vài cái service truyền cho GameComponent (Input, spriteBatch), ngoài ra bạn tạo 1 thể hiện và cấu trúc cho sceneManager, rùi add nó vào Component, thế thui, mọi chuyện h tự cái method base.Update(gameTime) với base.Draw(GameTime) nó tự làm việc, viết theo kiểu này bạn đã tận dụng được tốt đa sức mạnh của xna! Mã lệnh game chính này chỉ chạy chủ yếu dựa vào kế thừa từ Microsoft.Xna.Framework.Game

public class Asteroids : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics;

SceneManager sceneManager;

//Services: Input input = new Input(); SpriteBatch spriteBatch;

public SceneManager SceneManager { get { return sceneManager; } }

public Asteroids() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content";

graphics.PreferredBackBufferWidth = 800; graphics.PreferredBackBufferHeight = 600; } protected override void Initialize() { spriteBatch = new SpriteBatch(GraphicsDevice);

//Add services Services.AddService(typeof(SpriteBatch), spriteBatch); Services.AddService(typeof(Input), input);

sceneManager = new SceneManager(this); sceneManager.Initialize(); Components.Add(sceneManager);

Contact me at [email protected] or http://xvna.forumb.biz

Page 38: [Xvna.forumb.biz]XNA basic for newbie

Copyrights by HuyetSat - Xvna.forumb.biz - 2010 base.Initialize(); } protected override void Update(GameTime gameTime) { input.Update();

//Update Active Scene ! base.Update(gameTime); }

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

spriteBatch.Begin(SpriteBlendMode.AlphaBlend); //Draw Active Scene ! base.Draw(gameTime); spriteBatch.End(); } }

Lẽ ra cái code dưới này xna tạo sẵn cái program.cs cho bạn, mình gom nó vào class game chính cho gọn lại thui //Entry point! - WRITTEN BY HUYETSAT - Xvna.forumb.biz :) static class Program { /// <summary> /// The main entry point for the application. /// </summary> static void Main(string[] args) { using (Asteroids game = new Asteroids()) { game.Run(); } } }}

Xong Asteroids rùi đó, mong các bạn tự tìm lại cách viết thông qua hướng dẫn mình nhé, nếu thấy có thì mở file mẫu ra xem rùi nhớ tự code chứ đùng C với V ở đây nhá

Nâng cấp game: Có rất nhiều thứ để thử khả năng lập trình của bạn: tăng thêm Item, thêm Ênemy có AI, viết thêm thằng Boss, thêm vũ khí như tên lửa, vòng bảo vệ ... Ai phát triển tiếp trò asteroid này thì nhớ Up lên để mọi người cùng thưởng thức nhé

Lời kết: Hi vọng các newbie sẽ thấy thích thú với game coding thông qua tài liệu này! Mình cũng mất gần 2 ngày để viết tài liệu + làm Resource + tạo project mẫu!

Chúc mọi người training Zui Zẻ - HuyetSat - Xvna.forumb.biz

Contact me at [email protected] or http://xvna.forumb.biz