Download presentation
Presentation is loading. Please wait.
1
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 2D圖形與字型的呈現
2
本章目的 介紹XNA支援的 2D圖形格式 介紹2D圖形的應用範圍 以多個範例來示範在XNA架構下2D圖形和字型的呈現方式
3
2D 圖形的應用範圍 紋理圖(Texture) 精靈圖(Sprite) 小張的背景拼圖 大張的背景圖
4
紋理圖 展開的UV貼圖
5
2D角色精靈圖
6
無接縫2D圖形
7
大張捲動的背景圖
8
XNA可輸入的 2D圖形格式 .BMP取自Bitmap的縮寫,是無壓縮的點陣圖形檔。
.DDS 是可以包含有 alpha 值的圖形檔案。也可以是有六張貼圖的立體紋理圖 (cube map) .DIB與BMP相似,所以BMP也被稱為DIB。 .HDR每一個像素除了有RGB資訊外,還有改點的亮度資訊。 .JPG全彩及灰階圖形資料標準壓縮檔。採用失真壓縮演算法。 .PFM一種字型格式。 .PNGPNG 是包含有 alpha 值的圖形檔案。 .PPM可移植的像素映射位圖檔。 .TGA全稱Truevision Targa,包含有 alpha 值的圖形檔案。
9
MipMap 圖
10
一個典型的2D圖形上載與繪出方式 宣告 上載 (更新) 繪出
public class Game1 :Microsof.Xna.Framework.Game { // 宣告 一個 Texture2D 參照 Texture2D mySpriteTexture; … protected override void LoadContent() // 上載一張2D圖形 mySpriteTexture = Content.Load<Texture2D>("png-0001"); Protected override void Draw(GameTime gameTime) // 繪出 Texture2D spriteBatch.Begin(); Vector2 pos = new Vector2(100, 100); spriteBatch.Draw(mySpriteTexture, pos, Color.White); spriteBatch.End(); 宣告 上載 (更新) 繪出
11
呈現出一個2D圖形 protected override void Draw(GameTime gameTime) {
graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here spriteBatch.Begin(); Vector2 pos = new Vector2(0, 0); spriteBatch.Draw( mySpriteTexture, pos, // 位置 Color.White); // 過濾顏色 也就是完全不過濾 spriteBatch.End(); base.Draw(gameTime); }
12
Draw XNA提供: 七種繪出紋理圖的方法 和三種畫出字串的方法 範例一:上載並呈現一張2D圖形(4-9~4-11)
載入一張2D圖在content中 宣告2D圖之變數於Game1 Load 2D圖於LoadContent() 繪圖於Draw()
13
縮放或呈現部分 2D 圖形 (範例一及範例二) // 方式 1 :目的地位置
Vector2 pos = new Vector2(0, 0); spriteBatch.Draw(mySpriteTexture, pos, // 位置 Color.White); // 過濾顏色 也就是完全不過濾 // 方式 2 :改變 過濾顏色 pos.X = 150; spriteBatch.Draw(mySpriteTexture, pos, Color.Red); // 只要紅色
14
縮放或呈現部分 2D 圖形 // 方式 3 :標示目的地的位置和寬高
Rectangle rec = new Rectangle(300, 10, 43, 64); spriteBatch.Draw(mySpriteTexture, rec, Color.White); // 方式 4 :標示目的地位置寬高和來源矩形的位置寬高 Rectangle rec2 = new Rectangle(400, 10, 340, 210); Rectangle rec_SRC = new Rectangle(40, 20, 380, 230); spriteBatch.Draw(mySpriteTexture, rec2, rec_SRC, Color.White);
15
範例三:2D圖形的旋轉 宣告一Global variable “Angle”於Game1 在Update()中改變Angle的值
於Draw()中繪出旋轉後的圖形
16
旋轉的 2D 圖形(範例三) Rectangle recDest = new Rectangle(graphics.GraphicsDevice.Viewport.Width / 2, graphics.GraphicsDevice.Viewport.Height / 2, mySpriteTexture.Width, mySpriteTexture.Height); spriteBatch.Draw(mySpriteTexture, // 2D Texture recDest, // 目的區 的 矩形區塊 null, // 來源區 的 矩形區塊 Color.White, // 顏色 濾鏡 MathHelper.ToRadians(Angle), // 旋轉徑度 new Vector2(mySpriteTexture.Width / 2, mySpriteTexture.Height / 2), // 2D Texture旋轉中心點 SpriteEffects.None, // 旋轉效果 0.6f); // 圖層深度 0.0 ~ 1.0 (後)
17
SpriteSortMode.BackToFront
18
SpriteSortMode.FrontToBack
19
範例四:彈跳得2D圖形 如何實作一個精靈圖類別: 專案 加入類別 輸入檔案名稱,選擇『加入』 加入程式碼
20
範例四:彈跳得2D圖形 namespace WindowsGame1 { class ClassSprite { public Texture2D texture; // 2D 紋理圖 public Vector2 position; // 2D 紋理圖 的位置 private Vector2 screenSize; // 視窗寬高 public Vector2 velocity = Vector2.Zero; // 2D 紋理圖 的位移速度 public ClassSprite(Texture2D texture, Vector2 position, Vector2 screenSize) { this.texture = texture; this.position = position; this.screenSize = screenSize; }
21
範例四:彈跳得2D圖形 // 移動 public void Move() { // 右緣 碰到 視窗右邊了 if (position.X + texture.Width + velocity.X > screenSize.X) velocity.X = -velocity.X; // 下緣 碰到 視窗底邊了 if (position.Y + texture.Height + velocity.Y > screenSize.Y) velocity.Y = -velocity.Y; // 左緣 碰到 視窗左邊了 if (position.X + velocity.X < 0) // 上緣 碰到 視窗上邊了 if (position.Y + velocity.Y < 0) position += velocity; } } }
22
範例四:彈跳得2D圖形 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 Texture2D texture = Content.Load<Texture2D>("CD");// 上載圖形 // 產生精靈圖物件 mySprite1 = new ClassSprite(texture, new Vector2(0f, 0f), new Vector2(graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height)); mySprite1.velocity = new Vector2(5, 5); // 設位移速度 }
23
範例四:彈跳得2D圖形 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 mySprite1.Move(); // 移動精靈圖物件 base.Update(gameTime); }
24
範例四:彈跳得2D圖形 protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here spriteBatch.Begin(SpriteBlendMode.AlphaBlend); spriteBatch.Draw(mySprite1.texture, mySprite1.position, Color.White); spriteBatch.End(); base.Draw(gameTime); }
25
範例五:互相碰撞的2D圖形 定義『碰撞』 宣告兩個Sprite物件 設定位置及速度 處理碰撞的情況 繪圖
26
兩個矩形是否在水平方向 (X軸) 重疊 如果 X2 > X3 而且 X4 > X1
27
兩個矩形是否在垂直方向 (Y軸) 重疊
28
範例五:互相碰撞的2D圖形(新增mthod)
public bool Collides(ClassSprite other) { // 檢查是否 碰撞 return (this.position.X + texture.Width > other.position.X && this.position.X < other.position.X + other.texture.Width && this.position.Y + texture.Height > other.position.Y && this.position.Y < other.position.Y + other.texture.Height); }
29
範例五:互相碰撞的2D圖形 namespace WindowsGame1 { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game GraphicsDeviceManager graphics; SpriteBatch spriteBatch; ClassSprite mySprite1; // 精靈圖物件參照 ClassSprite mySprite2; // 精靈圖物件參照 ………
30
範例五:互相碰撞的2D圖形 protected override void LoadContent() { ……… mySprite1 = new ClassSprite(texture, new Vector2(0f, 0f), new Vector2(graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height)); mySprite1.velocity = new Vector2(5, 5); // 設位移速度 mySprite2 = new ClassSprite(texture, new Vector2(300f, 200f), mySprite2.velocity = new Vector2(-8, -5); }
31
範例五:互相碰撞的2D圖形 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 mySprite1.Move(); // 移動精靈圖物件 mySprite2.Move(); // 移動精靈圖物件 if (mySprite1.Collides(mySprite2)) { Vector2 tempVelocity = mySprite1.velocity; mySprite1.velocity = mySprite2.velocity; mySprite2.velocity = tempVelocity; } base.Update(gameTime);
32
範例五:互相碰撞的2D圖形 protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here spriteBatch.Begin(SpriteBlendMode.AlphaBlend); spriteBatch.Draw(mySprite1.texture, mySprite1.position, Color.White); spriteBatch.Draw(mySprite2.texture, mySprite2.position, Color.White); spriteBatch.End(); base.Draw(gameTime); }
33
使用無接縫圖佈滿視窗客戶區
34
範例六:無接縫貼圖 在Game1.cs宣告一個global variable叫BX_Texture 在LoadContent內上載2D圖形
利用視窗與圖形的長度與寬度計算Do Loop 的巡迴次數,並於Draw中繪圖
35
範例六:無接縫貼圖 利用視窗與圖形的長度與寬度計算Do Loop 的巡迴次數,並於Draw中繪圖
for (int i = 0; i <= W / BG_Texture.Width; i++) // i 是 X 方向 要貼幾次 { for (int j = 0; j <= H / BG_Texture.Height; j++) // j 是 Y 方向 要貼幾次 Vector2 position = new Vector2(i * BG_Texture.Width, j * BG_Texture.Height); // 算出要 貼上的位置 spriteBatch.Draw(BG_Texture, position, Color.White); }
36
使用捲動的無接縫圖佈滿視窗客戶區
37
範例七:捲動的無接縫貼圖 在Game1.cs宣告一個global variable叫BX_Texture
在LoadContent內上載2D圖形 加入一個global variable為橫向與縱向的偏移植Offset_X和Offset_Y,並於Update()中修改其值 利用視窗與圖形的長度與寬度加上偏移值後計算Do Loop 的巡迴次數,並於Draw()中繪圖
38
範例七:捲動的無接縫貼圖 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 Offset_X += -1; // 向左 Offset_Y += 0; // 不增加 base.Update(gameTime); }
39
範例七:捲動的無接縫貼圖 protected override void Draw(GameTime gameTime) { ……. int W = graphics.GraphicsDevice.Viewport.Width; int H = graphics.GraphicsDevice.Viewport.Height; spriteBatch.Begin(); for (int i = -1; i <= W / BG_Texture.Width; i++) // i 是 X 方向 要貼幾次 { for (int j = -1; j <= H / BG_Texture.Height; j++) // j 是 Y 方向 要貼幾次 { Vector2 position = new Vector2( i * BG_Texture.Width + (Offset_X % BG_Texture.Width), j * BG_Texture.Height + (Offset_Y % BG_Texture.Height)); // 算出要 貼上的位置 spriteBatch.Draw(BG_Texture, position, Color.White); } } spriteBatch.End(); base.Draw(gameTime); }
40
範例八:2D精靈與捲動背景 public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D BG_Texture; int Offset_X = 0; // X 軸 偏移値 int Offset_Y = 0; // Y 軸 偏移値 Texture2D mySpriteTexture; Rectangle[,] srcRect = new Rectangle[4, 4]; int pcW = 85; // 主角的寬 int pcH = 153; // 主角的高 int Dir = 2; // 走路的方向 int Seq = 0; // 走路的第幾個動作 bool pcStop = true; // 主角 停止走路 KeyboardState oldState; double StepDuration = 0; … }
41
範例八:2D精靈與捲動背景 public class Game1 : Microsoft.Xna.Framework.Game { …………. public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; this.IsMouseVisible = true; this.Window.AllowUserResizing = true; this.Window.Title = "行走中的小王子 (↑↓←→空白鍵)"; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) srcRect[i, j] = new Rectangle(j * pcW, i * pcH, pcW, pcH); }
42
範例八:2D精靈與捲動背景 protected override void Update(GameTime gameTime) {………… // TODO: Add your update logic here KeyboardState newState; // 宣告一個 KeyboardState 結構的變數 newState = Keyboard.GetState(); //得到目前鍵盤全部按鍵的狀況 if (newState.IsKeyDown(Keys.Escape)) this.Exit(); //判斷Esc鍵是否已經被按下 else if (newState.IsKeyDown(Keys.Up) && Dir != 1) { Dir = 1; Seq = 0; pcStop = false; } else if (newState.IsKeyDown(Keys.Down) && Dir != 0) { Dir = 0; Seq = 0; pcStop = false; } else if (newState.IsKeyDown(Keys.Right) && Dir != 2) { Dir = 2; Seq = 0; pcStop = false; } else if (newState.IsKeyDown(Keys.Left) && Dir != 3) { Dir = 3; Seq = 0; pcStop = false; } else if (newState.IsKeyDown(Keys.Space) && oldState.IsKeyUp(Keys.Space)) { pcStop = !pcStop; } else if (!pcStop) { StepDuration += gameTime.ElapsedGameTime.TotalMilliseconds; if (StepDuration > 300) { StepDuration = 0; Seq++; // 下一張 Seq = Seq % 4; // 每一方向只有四張 } } oldState = newState; if (pcStop) { } else if (Dir == 1) // 向下 Offset_Y += 1; else if (Dir == 0) // 向上 Offset_Y -= 1; else if (Dir == 2) // 向左 Offset_X -= 1; else if (Dir == 3) // 向右 Offset_X += 1; base.Update(gameTime);
43
範例八:2D精靈與捲動背景 protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here int W = graphics.GraphicsDevice.Viewport.Width; int H = graphics.GraphicsDevice.Viewport.Height; spriteBatch.Begin(); for (int i = -1; i <= W / BG_Texture.Width+1; i++) // i 是 X 方向 要貼幾次 { for (int j = -1; j <= H / BG_Texture.Height+1; j++) // j 是 Y 方向 要貼幾次 { Vector2 position = new Vector2( i * BG_Texture.Width + (Offset_X % BG_Texture.Width), j * BG_Texture.Height + (Offset_Y % BG_Texture.Height)); // 算出要 貼上的位置 spriteBatch.Draw(BG_Texture, position, Color.White); } } Rectangle DesRect = new Rectangle( this.Window.ClientBounds.Width / 2 - pcW / 2, this.Window.ClientBounds.Height / 2 - pcH / 2, pcW, pcH); spriteBatch.Draw(mySpriteTexture, DesRect, srcRect[Dir, Seq], Color.White); spriteBatch.End(); base.Draw(gameTime); } } }
44
有16個小圖的角色圖
45
範例九: 2D 字型 新增XNA遊戲方案 Contnet(^-R); 加入; 新增項目;
選用Sprite Font範本,並將名稱改為Courier New.spritefont; 加入 系統產生新的文字檔Courier New.spritefont在Content下
46
加入字型項
47
Courier New.spritefont 字型項目
48
範例九: 2D 字型 說明page 4-35 XML格式檔案 宣告global variable(Font1)在Game1
Load Font 於LoadContent() 設定字串的內容及要寫的位置 使用spriteBatch.DrawString在draw()來顯示字串。 說明三種spriteBatch.DrawString的格式(4-37~4-39)
49
SpriteBatch .DrawString()
第一種格式:(簡易型) SpriteBatch.DrawString (SpriteFont, String, Vector2, Color); 使用範例: spriteBatch.DrawString(Font1, // 字型 message, // 字串 FontPos, // 位置 Color.Black // 字的顏色 );
50
SpriteBatch .DrawString()
SpriteBatch.DrawString (SpriteFont, String, Vector2, Color, Single, Vector2, Single, SpriteEffects, Single); 使用範例: spriteBatch.DrawString(Font1, // 字型 message, // 字串 FontPos, // 位置 Color.Black, // 字的顏色 0, // 旋轉角度 FontOrigin,// 字串中心點 3.0f, // 縮放倍數 SpriteEffects.None,// 旋轉效果 0); // 圖層深度 0.0 ~ 1.0 (後)
51
SpriteBatch .DrawString()
SpriteBatch.DrawString (SpriteFont, String, Vector2, Color, Single, Vector2, Vector2, SpriteEffects, Single); 使用範例: spriteBatch.DrawString(Font1, // 字型 message, // 字串 FontPos, // 位置 Color.Black, // 字的顏色 0, // 旋轉角度 FontOrigin,// 字串中心點 new Vector2(2,3), // 縮放倍數 SpriteEffects.None,// 旋轉校果 0); // 圖層深度 0.0 ~ 1.0 (後)
52
範例十: 旋轉的2D 字型 Easy 設定一旋轉角度Angle為global variable 在update()中改變角度
在draw()中將字寫出
53
範例十一: 2D圖形與字型之應用 先做出一個透空的PNG圖檔(如page 4-41),在Content中讀入此圖檔。
在Game1中宣告一global variable為儲血量。 在LoadContent將圖形載入 在Update控制血量的改變 在Draw繪出血條圖,包括外框,血條框和血條損耗框 繪出文字
54
範例十一: 2D圖形與字型之應用 在Game1中宣告一global variable為儲血量。
public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D myHPBar; // 2D圖形 int myCurrentHP = 100; // HP總數值 SpriteFont Font1; // 文字(myCurrentHP數值顯示)
55
範例十一: 2D圖形與字型之應用 在LoadContent將圖形載入
protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); myHPBar = Content.Load<Texture2D>(“HPBar”);// HPBar整張圖案載入 Font1 = Content.Load<SpriteFont>(“Courier New”);//文字載入 // TODO: use this.Content to load your game content here }
56
範例十一: 2D圖形與字型之應用 在Update控制血量的改變
protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); HandleInput(); // 按鍵控制 // TODO: Add your update logic here base.Update(gameTime); } private void HandleInput() { KeyboardState myKeys = Keyboard.GetState(); // 按下方向鍵"上"HP數值+1 if (myKeys.IsKeyDown(Keys.Up) == true) { myCurrentHP += 1; } // 按下方向鍵"下"HP數值-1 if (myKeys.IsKeyDown(Keys.Down) == true) { myCurrentHP -= 1; } // 將myCurrentHP值定為在最小0,最大100 myCurrentHP = (int)MathHelper.Clamp(myCurrentHP, 0, 100); }
57
spriteBatch.Draw() (p. 4-12)
1. 繪出 spriteBatch.Draw(mySpriteTexture, pos, Color.White); 2. 過濾顏色 spriteBatch.Draw(mySpriteTexture, pos, Color.Red); 3. 設定目的地之位置(前兩參數)和寬高(後兩參數) spriteBatch.Draw(mySpriteTexture, rec, Color.White); 4. 設定目的地的位置與寬高以及來源圖型的位置與寬高 spriteBatch.Draw(mySpriteTexture, rec2, rec_src, Color.White);
58
範例十一: 2D圖形與字型之應用 在Draw繪出血條圖,包括外框,血條框和血條損耗框
protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here // 程式視窗的寬/2 int WDWidth = this.Window.ClientBounds.Width / 2; int WDHeight = this.Window.ClientBounds.Height / 2; // 文字部分定義 string output = Convert.ToString(myCurrentHP) + "%"; // 顯示出來的文字 Vector2 FontOrigin = Font1.MeasureString(output) / 2; // 字串中心點 Vector2 FontPos = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2, graphics.GraphicsDevice.Viewport.Height / );// 字串的位置
59
範例十一: 2D圖形與字型之應用 在Draw繪出血條圖,包括外框,血條框和血條損耗框 // 開始繪出圖案
spriteBatch.Begin(); //1. 灰色全劃 2. HP值量條,綠色依照比例畫出 3. 畫整個外框 spriteBatch.Draw(myHPBar, new Rectangle(WDWidth - myHPBar.Width / 2, WDHeight - myHPBar.Height / 2, myHPBar.Width, 22), // 寬與高 new Rectangle(0, 45, myHPBar.Width, 44), Color.Gray); // 目的來源的位置, 顏色 // 2. new Rectangle(WDWidth - myHPBar.Width / 2, WDHeight - myHPBar.Height / 2, (int)(myHPBar.Width * ((double)myCurrentHP / 100)), 22),// 寬與高 new Rectangle(0, 45, myHPBar.Width, 44), Color.Green);// 目的來源的位置, 顏色 // 3. 整個外框 new Rectangle(WDWidth - myHPBar.Width / 2, WDHeight - myHPBar.Height / 2, myHPBar.Width, 22),// 寬與高 new Rectangle(0, 0, myHPBar.Width, 44), Color.White);// 目的來源的位置, 顏色
60
範例十一: 2D圖形與字型之應用 繪出文字 // 開始繪出圖案與文字 // Draw the string
spriteBatch.DrawString(Font1, // 字型 output, // 字串 FontPos, // 位置 Color.Black, // 字的顏色 0, // 旋轉角度 FontOrigin,// 字串中心點 1.0f, // 縮放倍數 SpriteEffects.None, 0.5f); // 圖層深度 0.0 ~ 1.0 (後) spriteBatch.End(); base.Draw(gameTime); }
61
The End
Similar presentations