2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 第九章 相機類別與玩家角色.

Slides:



Advertisements
Similar presentations
自己做, 自己玩 Xbox 遊戲實作 視覺化實驗室 VLAB 莊世坤 2010/11/24 自我介紹
Advertisements

第一單元 建立java 程式.
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 第六章 3D繪出管道流程、著色器與特效檔.
实证 作业:语言调查 赵万林 哲社学院 学号:
我在哈佛、麥肯錫 學到的一流工作術 富坂美織◎著.
宁夏正阳社会工作服务中心 服务成果汇报材料.
陳維魁 博士 儒林圖書公司 第九章 資料抽象化 陳維魁 博士 儒林圖書公司.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
Project 2 JMVC code tracing
手持式裝置之隨身照護應用 Android開發環境設定 鐘國家 老師.
手持式裝置之隨身照護應用 Android開發環境設定 鐘國家 老師.
資料結構設計與C++程式應用 Fundamentals of Data Structures and Their Applications Using C++ 第3章 佇列 資料結構設計與C++程式應用.
ANDROID 中的 3D 繪圖 作者:陳鍾誠.
類別(class) 類別class與物件object.
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 2D圖形與字型的呈現.
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 第五章 頂點定義與基本形狀的繪出.
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 第七章 音樂音效.
Java 程式設計 講師:FrankLin.
攝影 Dolly Track 攝影機操作術語 Pan right (left), Tilt up (down) ,
JAVA 程式設計與資料結構 第四章 陣列、字串與數學物件.
靜定桁架分析 (應用電腦).
第一單元 建立java 程式.
Ch20. 計算器 (Mac 版本).
CLICK HERE TO ADD YOUR TITLE
Unity LAB 2D UFO Tutorial
仁濟醫院董之英紀念中學 一九九九年三月八日
CLICK HERE TO ADD YOUR TITLE
72% 29% 33% ADD YOUR TITLE HERE 点击此处添加文本信息。
3D Game Programming Projection
Xxxx集团有限公司 封面页.
王豐緒 銘傳大學資訊工程學系 問題:判斷是否為長方形.
GridView.
Class & Object 靜宜大學資工系 蔡奇偉副教授 ©2011.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 第三章 XNA 遊戲程式基本架構.
95學年上學期高二物理 黃信健.
95學年上學期高二物理 黃信健.
30% 30% CLICK HERE TO ADD YOUR TITLE CLICK HERE TO ADD YOUR TITLE
97學年上學期高二物理 黃信健.
函數應用(二)與自定函數.
陣列與結構.
B A C D ADD YOUR TEXT ADD YOUR TEXT ADD YOUR TEXT ADD YOUR TEXT
目标 流程控制 字符串处理 C# 的类和对象 C# 访问修饰符 C# 构造函数和析构函数.
#include <iostream.h>
方法進階及物件導向基礎 Lecturer: 楊昌樺.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
ADD YOUR TITLE HERE ADD YOUR NAME.
進階UI元件:ListView元件以及複選 靜宜大學資管系 楊子青
坐標 →配合課本 P49~56 重點 在坐標平面上,以 ( m , n ) 表示 P 點的坐標,記為 P ( m , n ),m 為 P 點的 x 坐標,n 為 P 點的 y 坐標。 16.
2 滾動、力矩角、動量.
期末報告第一題 通訊四甲 B 湯智瑋.
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
Activity的生命週期: 播放音樂與影片 靜宜大學資管系 楊子青
JAVA 程式設計與資料結構 第三章 物件的設計.
第四教学项目 话剧排练及影视鉴赏.
中式烹调技艺 第五章.
Scratch: 動畫或遊戲編程 任務6:太空旅遊.
Windows Phone Game 行動遊戲開發
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
加速感測器 靜宜大學資管系 楊子青.
第十章、核銷系統操作之注意事項.
SQLite資料庫 靜宜大學資管系 楊子青.
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 第十二章 燈光、背景與天空包.
就學貸款 相關注意事項 學生事務處 /生活輔導組.
生命銀行 生命銀行.
方法(Method) 函數.
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
InputStreamReader Console Scanner
03 Click here to add your text.Click here to add your text.Click here to add your text.Click here to add your text.Click here to add your text.Click here.
Presentation transcript:

2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 第九章 相機類別與玩家角色

本章目的 實作幾種常見的相機類別外 介紹玩家角色(PC)的實作部份

相機在3D遊戲程式扮演的角色 頂點處理的一系列過程中跟相機有關的是視覺空間轉換矩陣和投影空間的轉換矩陣

視覺空間轉換矩陣 在世界空間的物件與相機 以相機的觀點為原點 物件跟著移動 以相機的觀點為原點,並且朝向正Z軸 ,物件跟著旋轉

視覺矩陣 Matrix ViewMatrix = Matrix.CreateLookAt( new Vector3(0.0f, 2.0f, 2.0f), // 相機觀測點 Vector3.Zero, // 相機目標點 Vector3.Up); // 相機的 上方向量

相機上方向量的迷思 參數中的相機上方向量並不是真正的相機正上方的向量 函數內部的運算是以相機目標點到相機觀測點的向量為相機的向前向量 再以向前向量和相機的上方向量算出外積,也就是向前向量和相機的上方向量所構成的平面的法向量,來當作相機的向右向量 最後再以向前向量和相機的向右向量算出外積,也就是向前向量和相機的向右向量所構成的平面的法向量,來當作相機真正的正上方的向

投影矩陣 Matrix ProjectMatrix = Matrix.CreatePerspectiveFieldOfView( MathHelper.ToRadians(45.0f), // 視角 1.333f, // 寬高比 1.0f, // 近平面 10000.0f); // 遠平面

投影空間轉換矩陣的作用

相機在3D遊戲程式所扮演的角色

範例一:簡易的相機操控 ↑、↓:控制相機在X軸的旋轉角度 <-、->:控制相機在Y軸的旋轉角度 A、D:控制相機在Z軸的旋轉角度 W、S:控制相機在YZ軸的遠近位置 Z、X:控制相機的可視角度 10

範例一:簡易的相機操控 第一個範例示範簡易的操控,包括: 3D模型的世界矩陣設定 相機擺設的位置 相機鏡頭可視角度的調整

範例一:簡易的相機操控 public class Game1 : Microsoft.Xna.Framework.Game { …… // Global variable declaration float modelRotationX = 0; // X 軸 旋轉角度 全域變數 float modelRotationY = 0; // Y 軸 旋轉角度 全域變數 float modelRotationZ = 0; // Z 軸 旋轉角度 全域變數 float PosY = 10.0f, PosZ = 10.0f; // 相機 的位置 float fov = 45.0f; // 視角 public Game1() { ………… } ……}

範例一:簡易的相機操控 protected override void Update(GameTime gameTime) {………. KeyboardState newState; // 宣告一個KeyboardState 結構的變數 newState = Keyboard.GetState(); //得到目前鍵盤每一個按鍵的狀況 if (newState.IsKeyDown(Keys.Left)) //判斷Left鍵是否已經被按下 modelRotationY -= 0.01f; else if (newState.IsKeyDown(Keys.Right)) //判斷Right鍵是否已經被按下 modelRotationY += 0.01f; if (newState.IsKeyDown(Keys.Up)) //判斷Up鍵是否已經被按下 modelRotationX -= 0.01f; else if (newState.IsKeyDown(Keys.Down)) //判斷Down鍵是否已經被按下 modelRotationX += 0.01f;

範例一:簡易的相機操控 protected override void Update(GameTime gameTime) {………. if (newState.IsKeyDown(Keys.A)) //判斷A鍵是否已經被按下 modelRotationZ -= 0.01f; else if (newState.IsKeyDown(Keys.D)) //判斷D鍵是否已經被按下 modelRotationZ += 0.01f; if (newState.IsKeyDown(Keys.W)) //判斷W鍵是否已經被按下 { PosY -= 0.1f; PosZ -= 0.1f; } else if (newState.IsKeyDown(Keys.S)) //判斷S鍵是否已經被按下 { PosY += 0.1f; PosZ += 0.1f; } if (newState.IsKeyDown(Keys.Z)) //判斷Z鍵是否已經被按下 { fov++; if (fov > 179) fov = 179; } else if (newState.IsKeyDown(Keys.X)) //判斷X鍵是否已經被按下

範例一:簡易的相機操控 protected override void Update(GameTime gameTime) {………. if (newState.IsKeyDown(Keys.Space)) { modelRotationX = modelRotationY = modelRotationZ = 0; PosY = PosZ = 2; } base.Update(gameTime);

範例一:簡易的相機操控 protected override void Update(GameTime gameTime) {………. if (newState.IsKeyDown(Keys.Space)) { modelRotationX = modelRotationY = modelRotationZ = 0; PosY = PosZ = 2; } base.Update(gameTime);

範例一:簡易的相機操控 protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here foreach (ModelMesh mesh in myModel.Meshes) { // 設定網格的呈現效果 (世界、觀測、投影矩陣) foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateScale(0.1f); // 如果模型太大 就縮小一些 effect.World = effect.World * Matrix.CreateRotationX(modelRotationX); effect.World = effect.World * Matrix.CreateRotationY(modelRotationY); effect.World = effect.World * Matrix.CreateRotationZ(modelRotationZ); effect.View = Matrix.CreateLookAt(new Vector3(0.0f, PosY, PosZ), Vector3.Zero, Vector3.Up); effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(fov), 1.333f, 1.0f, 10000.0f); } // 畫出在 模型 中的 某一個 網格 mesh.Draw(); } base.Draw(gameTime); } } } 17

範例二:起霧了 protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(new Color(255,255,0)); //背景黃色 foreach (ModelMesh mesh in myModel.Meshes) { // 設定網格的呈現效果 (世界、觀測、投影矩陣) foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.FogEnabled = true; effect.FogColor = new Vector3(1, 1, 0); effect.FogStart = 1; effect.FogEnd = 20; ……….. // 畫出在 模型 中的 某一個 網格 mesh.Draw(); } base.Draw(gameTime); } } }

範例二:起霧了 調整相機遠近(W,S)是否會因起霧在視覺上有所不同? Yes 調整相機鏡頭的可視角度(Z,X)是否會因起霧在視覺上有所不同? No

範例三:審視3D物件的相機類別 A、D : 控制相機在Y軸的旋轉角度 W、S:控制相機在X軸的旋轉角度 Z、X:控制相機在Z軸的遠近位置

範例三:審視3D物件的相機類別 InspectionCamera Class namespace WindowsGame1 { public class InspectionCamera : Microsoft.Xna.Framework.GameComponent public float cameraRotationX = 0; // 相機 X 軸 旋轉角度 public float cameraRotationY = 0; // 相機 Y 軸 旋轉角度 public float cameraDistance = 10; // 相機 Z 軸 位置 public Vector3 InspectionPoint = new Vector3(0, 0, 0); // 相機的 注視點 public Matrix view; // 由 上面 四個變數 算出的 視覺矩陣 public Matrix projection = // 投影矩陣 Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, // 視角 45度 1.333f, // 螢幕 寬高比 1, // 最近的Z軸截點 1000); // 最遠的Z軸截點 public InspectionCamera(Game game) : base(game) { // TODO: Construct any child components here } public override void Initialize() { // TODO: Add your initialization code here base.Initialize(); } 21

範例三:審視3D物件的相機類別 InspectionCamera Class public override void Update(GameTime gameTime) { // TODO: Add your update code here KeyboardState newState; // 宣告一個KeyboardState 結構的變數 newState = Keyboard.GetState(); //得到目前鍵盤每一個按鍵的狀況 float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds; if (newState.IsKeyDown(Keys.W)) //判斷 W 鍵是否已經被按下 cameraRotationX += time * 0.1f; if (newState.IsKeyDown(Keys.S)) cameraRotationX -= time * 0.1f; if (cameraRotationX > 90.0f) cameraRotationX = 90.0f; else if (cameraRotationX < -90.0f) cameraRotationX = -90.0f; if (newState.IsKeyDown(Keys.D)) cameraRotationY -= time * 0.1f; if (newState.IsKeyDown(Keys.A)) cameraRotationY += time * 0.1f; if (newState.IsKeyDown(Keys.X)) cameraDistance += time * 0.025f; if (newState.IsKeyDown(Keys.Z)) cameraDistance -= time * 0.025f; if (cameraDistance > 100) cameraDistance = 100; else if (cameraDistance < 2) cameraDistance = 2; //cameraDistance = (int)MathHelper.Clamp(cameraDistance, 2, 100); if (newState.IsKeyDown(Keys.Space)) //判斷 空白鍵 是否已經被按下 { cameraRotationX = 0; cameraRotationY = 0; cameraDistance = 10; } view = Matrix.CreateRotationY(MathHelper.ToRadians(cameraRotationY)) * Matrix.CreateRotationX(MathHelper.ToRadians(cameraRotationX)) * Matrix.CreateLookAt(new Vector3(0, 0, cameraDistance), InspectionPoint, Vector3.Up); base.Update(gameTime); } } } 22

範例三:審視3D物件的相機類別 namespace WindowsGame1 { public class Game1 : Microsoft.Xna.Framework.Game {………….. InspectionCamera camera; ……….. protected override void Initialize() { // TODO: Add your initialization logic here Grid = new GameComponent_Grid(this); this.Components.Add(Grid); camera = new InspectionCamera(this); this.Components.Add(camera); base.Initialize(); } 23

範例三:審視3D物件的相機類別 namespace WindowsGame1 { public class Game1 : Microsoft.Xna.Framework.Game {………….. protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here foreach (ModelMesh mesh in myModel.Meshes) { // 設定網格的呈現效果 (世界、觀測、投影矩陣) foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateScale(0.05f); // 如果模型太大 就縮小一些 effect.View = camera.view; effect.Projection = camera.projection; } // 畫出在 模型 中的 某一個 網格 mesh.Draw(); } Grid.view = camera.view; Grid.projection = camera.projection; base.Draw(gameTime); } } } 24

範例四:第一人稱相機類別 、 :控制相機的遠近距離 、:控制相機在Y軸的旋轉角度

範例四:第一人稱相機類別 FirstPersonCamera using Microsoft.Xna.Framework; // 因為用到 Matrix、Vector3 using Microsoft.Xna.Framework.Graphics; // 因為用到 GraphicsDeviceManager、Viewport using Microsoft.Xna.Framework.Input; // 因為用到 KeyboardState namespace WindowsGame1 { class FirstPersonCamera : Microsoft.Xna.Framework.GameComponent { public Matrix view; // 視覺矩陣 public Matrix projection = // 投影矩陣 Matrix.CreatePerspectiveFieldOfView( MathHelper.PiOver4, 1.333f, 1, 1000); public Vector3 FrontVector = new Vector3(0, 0, -1); //相機的 往前向量 public Vector3 Position = new Vector3(0.0f, 2.0f, 20.0f); // 相機的位置 public float Yaw = 0.0f; // 相機的Y軸旋轉角度 public float YawDelta = 0.2f; // 旋轉角度 的 增減量 public float MoveDelta = 2; // 前後走 的 增減量

範例四:第一人稱相機類別 FirstPersonCamera //更新 相機 的位置 public void UpdateCamera(Vector3 Position, float Yaw) { //攝影機一開始是 朝向 負 Z 軸 看著(0, 0, -1) Vector3 LookAt = Position + // 向量 X 矩陣 ==> 向量 (假設 w 值 = 0) Vector3.TransformNormal(FrontVector, Matrix.CreateRotationY(Yaw)); // 根據 相機的位置 相機要看到的點 相機上方的向量 得到 視覺矩陣 view = Matrix.CreateLookAt(Position, // 相機的位置 LookAt, // 相機要看到的點 new Vector3(0.0f, 1.0f, 0.0f)); } public FirstPersonCamera(Game game) : base(game) { // TODO: Construct any child components here } public override void Initialize() { base.Initialize(); }

範例四:第一人稱相機類別 FirstPersonCamera //更新 相機 的位置 public void UpdateCamera(Vector3 Position, float Yaw) { //攝影機一開始是 朝向 負 Z 軸 看著(0, 0, -1) Vector3 LookAt = Position + // 向量 X 矩陣 ==> 向量 (假設 w 值 = 0) Vector3.TransformNormal(FrontVector, Matrix.CreateRotationY(Yaw)); // 根據 相機的位置 相機要看到的點 相機上方的向量 得到 視覺矩陣 view = Matrix.CreateLookAt(Position, // 相機的位置 LookAt, // 相機要看到的點 new Vector3(0.0f, 1.0f, 0.0f)); } public FirstPersonCamera(Game game) : base(game) { // TODO: Construct any child components here } public override void Initialize() { base.Initialize(); } public override void Update(GameTime gameTime) { // TODO: Add your update code here float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds; KeyboardState newState; // 宣告一個KeyboardState 結構的變數 newState = Keyboard.GetState(); //得到目前鍵盤每一個按鍵的狀況 if (newState.IsKeyDown(Keys.Right)) Yaw -= YawDelta * elapsedTime; //判斷Right鍵是否已經被按下 if (newState.IsKeyDown(Keys.Left)) Yaw += YawDelta * elapsedTime; //判斷Left鍵是否已經被按下 if (newState.IsKeyDown(Keys.Up)) //判斷Up鍵是否已經被按下 Position += Vector3.Transform(MoveDelta * elapsedTime * FrontVector, Matrix.CreateRotationY(Yaw)); if (newState.IsKeyDown(Keys.Down)) //判斷Down鍵是否已經被按下 Position += Vector3.Transform(-MoveDelta * elapsedTime * FrontVector, UpdateCamera(Position, Yaw); base.Update(gameTime);

範例四:第一人稱相機類別 FirstPersonCamera public override void Update(GameTime gameTime) { // TODO: Add your update code here float elapsedTime = float)gameTime.ElapsedGameTime.TotalSeconds; KeyboardState newState; // 宣告一個KeyboardState 結構的變數 newState = Keyboard.GetState(); //得到目前鍵盤每一個按鍵的狀況 if (newState.IsKeyDown(Keys.Right)) Yaw -= YawDelta * elapsedTime; //判斷Right鍵是否已經被按下 if (newState.IsKeyDown(Keys.Left)) Yaw += YawDelta * elapsedTime; if (newState.IsKeyDown(Keys.Up)) //判斷Up鍵是否已經被按下 { Position += Vector3.Transform(MoveDelta * elapsedTime *FrontVector, Matrix.CreateRotationY(Yaw)); } if (newState.IsKeyDown(Keys.Down)) //判斷Down鍵是否已經被按下 { Position += Vector3.Transform(-MoveDelta * elapsedTime * FrontVector, UpdateCamera(Position, Yaw); base.Update(gameTime); } }}

範例四:第一人稱相機類別 public class Game1 : Microsoft.Xna.Framework.Game { …………… { …………… FirstPersonCamera camera; protected override void Initialize() { // TODO: Add your initialization logic here ……………… camera = new FirstPersonCamera(this); // 新增第一人稱相機 this.Components.Add(camera); // 將第一人稱相機加入為Game的元件 base.Initialize(); }

範例四:第一人稱相機類別 { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here foreach (ModelMesh mesh in myModel.Meshes) { // 設定網格的呈現效果 (世界、觀測、投影矩陣) foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateScale(0.05f) * Matrix.CreateTranslation(3,0,0); effect.View = camera.view; effect.Projection = camera.projection; } // 畫出在 模型 中的 某一個 網格 mesh.Draw(); ………. } Grid.view = camera.view; Grid.projection = camera.projection; base.Draw(gameTime); } } }

範例五:第三人稱相機類別與PC類別 W、S:相機的前進後退控制 A、D:控制相機在Y軸的旋轉角度控制 、 :3D物件的前進後退控制 、:3D物件的Y軸的旋轉角度控制

本範例主要使用的類別有三個 ThirdPersonCamera.cs GameComponent_Grid.cs 範例五:第三人稱相機類別與PC類別 本範例主要使用的類別有三個 ThirdPersonCamera.cs GameComponent_Grid.cs GameComponent_PC.cs

範例五:第三人稱相機類別與PC類別 GameComponent_PC public class GameComponent_PC : Microsoft.Xna.Framework.DrawableGameComponent { Model myModel; //宣告一個 模型物件 全域變數 Matrix[] transforms; // 宣告一個 骨架轉換矩陣 全域變數 ………….. // Constructor public GameComponent_PC(Game game, Model model): base(game) { // TODO: Construct any child components here myModel = model; } public override void Initialize() // 複製骨架矩陣的陣列備用 { // TODO: Add your initialization code here transforms = new Matrix[myModel.Bones.Count]; myModel.CopyAbsoluteBoneTransformsTo(transforms); base.Initialize(); }

範例五:第三人稱相機類別與PC類別 GameComponent_PC public override void Draw(GameTime gameTime) { foreach (ModelMesh mesh in myModel.Meshes) { // 設定網格的呈現效果 (世界、觀測、投影矩陣) foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateScale(0.05f) * Matrix.CreateRotationY(MathHelper.ToRadians(Yaw)) * Matrix.CreateTranslation(Position); effect.View = View; effect.Projection = Projection; } // 畫出在 模型 中的 某一個 網格 mesh.Draw(); } } } }

範例五:第三人稱相機類別與PC類別 Game1.cs 視覺矩陣和投影矩陣還是需要主程式適時的提供 跟玩家角色類別有關的程式: 宣告一個玩家角色類別的參照 產生一個玩家角色物件 加入成為Game的物件 宣告第三人稱相機物件要追蹤此物件

範例五:第三人稱相機類別與PC類別 Game1.cs public class Game1 : Microsoft.Xna.Framework.Game { \\宣告全域變數 …………. GameComponent_PC NPC_01; ThirdPersonCamera camera; protected override void Initialize() { // TODO: Add your initialization logic here …………………….. NPC_01 = new GameComponent_PC(this,Content.Load<Model>(“tortoise”)); this.Components.Add(NPC_01); // 由這裡加入 DrawableGameComponent camera = new ThirdPersonCamera(this, NPC_01); this.Components.Add(camera); base.Initialize(); }

範例五:第三人稱相機類別與PC類別 Game1.cs protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here Grid.view = camera.view; Grid.projection = camera.projection; \\將第三人稱相機最新的視覺矩陣和投影矩陣傳入給玩家角色物件 NPC_01.View = camera.view; NPC_01.Projection = camera.projection; base.Draw(gameTime); } } }

範例五:第三人稱相機類別與PC類別 ThirdPersonCamera.cs class ThirdPersonCamera : Microsoft.Xna.Framework.GameComponent { public Matrix view; // 視覺矩陣 public Matrix projection = Matrix.CreatePerspectiveFieldOfView( MathHelper.PiOver4, 1.333f, 1, 1000); public float distance = 10; //從3D 物件到相機的距離 public float Yaw = 0.0f; // 第一人稱的Y軸旋轉角度 public float YawDelta = 10.0f; // 旋轉角度 的 增減量 public float MoveDelta = 2; // 相機的移動增量 public float cameraHeight = 5.0f; // 相機的高度 GameComponent_PC tortoise; public ThirdPersonCamera(Game game, GameComponent_PC tortoise) : base(game) { // TODO: Construct any child components here this.tortoise = tortoise; } public override void Initialize() { base.Initialize(); }

範例五:第三人稱相機類別與PC類別 ThirdPersonCamera.cs class ThirdPersonCamera : Microsoft.Xna.Framework.GameComponent { ………… \\ 經由按鍵調整距離和角度 public override void Update(GameTime gameTime) { // TODO: Add your update code here float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds; KeyboardState newState; // 宣告一個KeyboardState 結構的變數 newState = Keyboard.GetState(); //得到目前鍵盤每一個按鍵的狀況 if (newState.IsKeyDown(Keys.A)) Yaw -= YawDelta * elapsedTime; //判斷 A 鍵是否已經被按下 if (newState.IsKeyDown(Keys.D)) Yaw += YawDelta * elapsedTime; //判斷 D 鍵是否已經被按下 if (newState.IsKeyDown(Keys.W)) //判斷 W 鍵是否已經被按下 { distance -= MoveDelta * elapsedTime; } if (newState.IsKeyDown(Keys.S)) //判斷 S 鍵是否已經被按下 { distance += MoveDelta * elapsedTime; } //相機的觀測點 Vector3 LookFrom = Vector3.Transform(new Vector3(0, cameraHeight, -distance), Matrix.CreateRotationY(MathHelper.ToRadians(Yaw)) * Matrix.CreateRotationY(MathHelper.ToRadians(tortoise.Yaw)) * Matrix.CreateTranslation(tortoise.Position) ); // 根據 相機的位置 相機要看到的點 相機上方的向量 得到 視覺矩陣 view = Matrix.CreateLookAt(LookFrom, // 相機的位置 tortoise.Position, // 3D 物件的 位置 (相機要看到的點) new Vector3(0.0f, 1.0f, 0.0f)); // 相機上方的向量 base.Update(gameTime); } } }

範例六:第三人稱相機類別(前進與轉彎) W、S:相機的前進後退控制 A、D:相機在Y軸的旋轉角度控制 、 :3D物件的前進後退控制 、:3D物件的Y軸的旋轉角度控制 空白鍵:相機和3D物件都歸回初始狀態

範例六:第三人稱相機類別(前進與轉彎) GameComponent_PC public class GameComponent_PC2 : Microsoft.Xna.Framework.DrawableGameComponent { Model myModel; //宣告一個 模型物件 全域變數 Matrix[] transforms; // 宣告一個 骨架轉換矩陣 全域變數 public Vector3 Position = new Vector3(0.0f, 0.0f, 0.0f); // 3D 物件的 位置 public float Yaw = 0.0f; // 第一人稱的Y軸旋轉角度 public float YawDelta = 15.0f; // 旋轉角度 的 單位量 public float MoveDelta = 0.15f; // 前進的單位量 \\ 加入兩變數來記錄前進速度與轉彎速度 float MoveSpeed = 0; // 前進的速度 float YawSpeed = 0.0f; // 轉彎的速度 public Matrix View = Matrix.CreateLookAt(new Vector3(0.0f, 20.0f, 20.0f), Vector3.Zero, Vector3.Up); public Matrix Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), 1.333f, 1.0f, 10000.0f);

範例六:第三人稱相機類別(前進與轉彎) GameComponent_PC public class GameComponent_PC2 : Microsoft.Xna.Framework.DrawableGameComponent { ………. public override void Update(GameTime gameTime) { // TODO: Add your update code here float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds; KeyboardState newState; // 宣告一個KeyboardState 結構的變數 newState = Keyboard.GetState(); //得到目前鍵盤每一個按鍵的狀況 if (newState.IsKeyDown(Keys.Right)) YawSpeed -= 0.1f; //判斷Right鍵是否已經被按下 if (newState.IsKeyDown(Keys.Left)) YawSpeed += 0.1f; Yaw += YawSpeed * YawDelta * elapsedTime; if (newState.IsKeyDown(Keys.Up)) //判斷Up鍵是否已經被按下 { if (MoveSpeed < 0) MoveSpeed = 0; else if (MoveSpeed < 10) MoveSpeed++; else MoveSpeed = 10; } if (newState.IsKeyDown(Keys.Down)) //判斷Down鍵是否已經被按下 { if (MoveSpeed > 0) MoveSpeed = 0; else if (MoveSpeed > -10) MoveSpeed--; else MoveSpeed = -10; } Position += Vector3.Transform(new Vector3(0, 0, MoveSpeed * MoveDelta * elapsedTime), Matrix.CreateRotationY(MathHelper.ToRadians(Yaw)));

範例六:第三人稱相機類別(前進與轉彎) GameComponent_PC public class GameComponent_PC2 : Microsoft.Xna.Framework.DrawableGameComponent { ………. public override void Update(GameTime gameTime) { // TODO: Add your update code here float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds; KeyboardState newState; // 宣告一個KeyboardState 結構的變數 newState = Keyboard.GetState(); //得到目前鍵盤每一個按鍵的狀況 if (newState.IsKeyDown(Keys.Right)) YawSpeed -= 0.1f; //判斷Right鍵是否已經被按下 if (newState.IsKeyDown(Keys.Left)) YawSpeed += 0.1f; //判斷Left鍵是否已經被按下 Yaw += YawSpeed * YawDelta * elapsedTime; if (newState.IsKeyDown(Keys.Up)) //判斷Up鍵是否已經被按下 { if (MoveSpeed < 0) MoveSpeed = 0; else if (MoveSpeed < 10) MoveSpeed++; else MoveSpeed = 10; } if (newState.IsKeyDown(Keys.Down)) //判斷Down鍵是否已經被按下 { if (MoveSpeed > 0) MoveSpeed = 0; else if (MoveSpeed > -10) MoveSpeed--; else MoveSpeed = -10; } Position += Vector3.Transform(new Vector3(0, 0, MoveSpeed * MoveDelta * elapsedTime), Matrix.CreateRotationY(MathHelper.ToRadians(Yaw))); if (newState.IsKeyDown(Keys.Space)) //判斷Space鍵是否已經被按下 { Position = new Vector3(0.0f, 0.0f, 0.0f); // 3D 物件的 位置 Yaw = 0.0f; // 第一人稱的Y軸旋轉角度 YawDelta = 0.1f; // 旋轉角度 的 增減量 MoveDelta = 0.05f; // 前後走 的 增減量 MoveSpeed = 0; YawSpeed = 0; } base.Update(gameTime);

範例七:彈簧相機類別 相機照應該是會晃動的 假設在3D物件和相機之間綁著一條會晃動的彈簧,彈簧因為有彈力和阻力,所以會有較為逼真的呈現 45

彈簧相機類別和3D物件的運作關係 46

The End