Atlasiet modeli no tā pozīcijas ekrānā
Kopsavilkuma
Tas ļauj jums izvēlēties modeli peles kursora pozīcijā. Novietojot kursoru virs modeļa, trāpījuma teksts mainās uz Patiess.
Darbības vide
Priekšnoteikumi
Atbalstītās XNA versijas |
|
Atbalstītās platformas |
|
Windows nepieciešamā Vertex Shader versija | 2.0 |
Windows nepieciešamā Pixel Shader versija | 2.0 |
Darbības vide
platforma |
|
Kā strādāt ar paraugu
Darbojas tastatūraXbox | 360 kontrolierismouse | touch | ||
---|---|---|---|---|
Kursora kustība | ↑↓←→ | Kreisā nūja | Peles kustība | - |
viela
Ekrāna koordinātu pārvēršana par 3D telpiskajām koordinātām
Iespējams, vēlēsities atlasīt modeli 3D telpā ar peli. Šajā gadījumā ir nepieciešams pārveidot divdimensiju koordinātu punktu ekrānā uz trīsdimensiju koordinātu, kur modelis pastāv, un veikt hit spriedumu.
Tomēr, lai paplašinātu elementu no 2D uz 3D, nav iespējams atrast punktu ar 3D koordinātām no 2D ekrāna koordinātām tikai X un Y. Piemēram, ja jūs iedomājaties, ka faktiski noklikšķināt uz ekrāna, jūs sapratīsit, ka nav iespējams noteikt, vai pozīcija 3D telpā, kad noklikšķināt, atrodas objekta, paša objekta vai objekta priekšā.
Tāpēc tā vietā, lai attēlotu noklikšķināto pozīciju kā punktu, tā tiek uzskatīta par līniju, kas izstiepta no kameras pozīcijas klikšķa virzienā. Veicot sadursmes noteikšanu starp līniju un objektu, ir iespējams izvēlēties modeli. Starp citu, līnijas parametrus XNA var apstrādāt ar struktūru, ko sauc par Ray.
Pozīcijas iegūšana 3D telpā no ekrāna pozīcijas
XNA nav metodes, kā atrast līniju ekrāna klikšķa virzienā. Tomēr, tā kā ir iespējams atrast punktu 3D telpā, norādot ekrāna koordinātas un dziļumu, ir iespējams atrast līniju, savienojot kameras pozīciju un 3D telpas koordinātu punktu, kas pārveidots noteiktā dziļumā.
Objektu-telpas koordinātu atrašana no ekrāna-telpas koordinātām ir viegli izdarāma, izmantojot metodi "Viewport.Unproject".
// ビューポートを取得
Viewport viewport = this.GraphicsDevice.Viewport;
// スクリーンの位置を Vector3 で作成 (Z は 1.0 以下を設定)
Vector3 screenPosition = new Vector3(this.markPosition, 1.0f);
// スクリーン座標を3次元座標に変換
Vector3 worldPoint = viewport.Unproject(screenPosition,
this.projection,
this.view,
Matrix.Identity);
Pirmais arguments ir Vector3 ar ekrāna koordinātām un dziļumu. Iestatiet X, Y uz ekrāna koordinātām un Z uz dziļuma vērtību. Dziļums ir atkarīgs no projekcijas matricas parametriem "nearPlaneDistance" un "farPlaneDistance", kur var norādīt 0.0f, lai atrastu attālumu no kameras pozīcijas līdz nearPlaneDistance, un 1.0f, lai noteiktu attālumu no kameras pozīcijas līdz farPlaneDistance.
Otrais arguments ir projekcijas matrica, bet trešais arguments ir skata matrica.
Kā atgriezto vērtību var atrast objekta-telpas vektoru.
Viewport.Unproject
metode
Projicē vektoru no ekrāna telpas uz objekta telpu.
avots | 3. vektors | Ekrāna koordinātu vektors konvertēšanai uz objekta-telpas koordinātām |
Projekcijas | Matricas | Projektīvā matrica |
skats | Matricas | Skatīt matricu |
pasaule | Matricas | Norāda galīgo pasaules matricas koordinātu transformāciju, kas jāveic |
Atgrieztās vērtības | 3. vektors | Vektora iegūšana objekta telpā |
Izveidojiet staru
Līnijas parametri var būt Staru struktūras. Pirmais arguments konstruktoram ir stara sākumpunkts, bet otrais arguments ir stara orientācija.
Iestatiet kameras pozīciju kā sākuma punktu un aprēķiniet orientāciju, atņemot kameras pozīciju no 3D telpas koordinātām, kas jau ir pārveidotas par orientāciju. Orientācija ir iestatīta uz vienības vektoru, izmantojot vektoru3.Normalizēt metodi.
// マークが指す方向へのレイを作成
Ray ray = new Ray(this.cameraPosition,
Vector3.Normalize(worldPoint - this.cameraPosition));
Ray
Konstruktors
Izveidojiet "Ray" struktūras gadījumu, kas satur līnijas parametrus.
pozīcija | 3. vektors | Staru sākumpunkts |
virziens | 3. vektors | Stara virziens |
Bumbas un staru hitbox
ModelMesh klase, kas ielādēta no satura konveijera, satur sfēras datus, kas ietver sietu, ko sauc par rekvizītu BoundingSphere. Norādot staru, kuru tikko izveidojāt šīs klases Intersects metodē, varat pārbaudīt, vai sfēra un stars saduras.
Sadursmes gadījumā tiek atgriezts attālums starp stara sākumu un sadursmes punktu. Ja sadursmes nav, null tiek atgriezta, tāpēc paraugs pārbauda, vai sadursme notiek ar nulles spriedumu.
Tomēr šī metode pieņem, ka modelis atrodas sākumā. Ja jūs pārvietojat modeli, jums būs jāpārveido stari, kad modelis pārvietojas.
Starp citu, šis izlases modelis ir sfēra, tāpēc es domāju, ka to var precīzi noteikt.
// 球とレイとの当たり判定を行う
this.isHit = false;
foreach (ModelMesh mesh in this.model.Meshes)
{
if (mesh.BoundingSphere.Intersects(ray) != null)
{
// 球とレイは交差している
this.isHit = true;
break;
}
}
BoundingSphere.Intersects
metode
Tiek veikta sadursmes noteikšana starp iekļaujošo bumbu un staru.
raja | Raja | Rejs, lai spriestu par sadursmi ar bumbu |
Atgrieztās vērtības | Nullable<float> | Sadursmes gadījumā tas atgriež attālumu starp staru sākuma punktu un trieciena punktu ar sfēru. Ja sadursmes nav, null tiek atgriezta. |
Visi kodi
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if WINDOWS_PHONE
using Microsoft.Xna.Framework.Input.Touch;
#endif
namespace ModelSelectByScreenPosition
{
<summary>
ゲームメインクラス
</summary>
public class GameMain : Microsoft.Xna.Framework.Game
{
<summary>
グラフィックデバイス管理クラス
</summary>
private GraphicsDeviceManager graphics = null;
<summary>
スプライトのバッチ化クラス
</summary>
private SpriteBatch spriteBatch = null;
<summary>
スプライトでテキストを描画するためのフォント
</summary>
private SpriteFont font = null;
<summary>
モデル
</summary>
private Model model = null;
<summary>
マーク
</summary>
private Texture2D mark = null;
<summary>
マーク画像の中心位置
</summary>
private Vector2 markCenterPosition = Vector2.Zero;
<summary>
マークの位置
</summary>
private Vector2 markPosition = new Vector2(100.0f, 100.0f);
<summary>
モデルへの当たり判定フラグ
</summary>
private bool isHit = false;
<summary>
カメラの位置
</summary>
private Vector3 cameraPosition = new Vector3(0.0f, 0.0f, 10.0f);
<summary>
ビューマトリックス
</summary>
private Matrix view;
<summary>
プロジェクションマトリックス
</summary>
private Matrix projection;
<summary>
GameMain コンストラクタ
</summary>
public GameMain()
{
// グラフィックデバイス管理クラスの作成
this.graphics = new GraphicsDeviceManager(this);
// ゲームコンテンツのルートディレクトリを設定
this.Content.RootDirectory = "Content";
#if WINDOWS_PHONE
// Windows Phone のデフォルトのフレームレートは 30 FPS
this.TargetElapsedTime = TimeSpan.FromTicks(333333);
// バックバッファサイズの設定
this.graphics.PreferredBackBufferWidth = 480;
this.graphics.PreferredBackBufferHeight = 800;
// フルスクリーン表示
this.graphics.IsFullScreen = true;
#endif
}
<summary>
ゲームが始まる前の初期化処理を行うメソッド
グラフィック以外のデータの読み込み、コンポーネントの初期化を行う
</summary>
protected override void Initialize()
{
// ビューマトリックス
this.view = Matrix.CreateLookAt(
this.cameraPosition,
Vector3.Zero,
Vector3.Up
);
// プロジェクションマトリックス
this.projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
(float)this.GraphicsDevice.Viewport.Width /
(float)this.GraphicsDevice.Viewport.Height,
1.0f,
100.0f
);
// コンポーネントの初期化などを行います
base.Initialize();
}
<summary>
ゲームが始まるときに一回だけ呼ばれ
すべてのゲームコンテンツを読み込みます
</summary>
protected override void LoadContent()
{
// テクスチャーを描画するためのスプライトバッチクラスを作成します
this.spriteBatch = new SpriteBatch(this.GraphicsDevice);
// フォントをコンテンツパイプラインから読み込む
this.font = this.Content.Load<SpriteFont>("Font");
// モデルを作成
this.model = this.Content.Load<Model>("Model");
// ライトとビュー、プロジェクションはあらかじめ設定しておく
foreach (ModelMesh mesh in this.model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
// デフォルトのライト適用
effect.EnableDefaultLighting();
// ビューマトリックスをあらかじめ設定
effect.View = this.view;
// プロジェクションマトリックスをあらかじめ設定
effect.Projection = this.projection;
}
}
// マーク作成
this.mark = this.Content.Load<Texture2D>("Mark");
// マークの中心位置
this.markCenterPosition = new Vector2(this.mark.Width / 2, this.mark.Height / 2);
}
<summary>
ゲームが終了するときに一回だけ呼ばれ
すべてのゲームコンテンツをアンロードします
</summary>
protected override void UnloadContent()
{
// TODO: ContentManager で管理されていないコンテンツを
// ここでアンロードしてください
}
<summary>
描画以外のデータ更新等の処理を行うメソッド
主に入力処理、衝突判定などの物理計算、オーディオの再生など
</summary>
<param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
protected override void Update(GameTime gameTime)
{
// キーボードの情報取得
KeyboardState keyboardState = Keyboard.GetState();
// ゲームパッドの情報取得
GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
// Xbox 360 コントローラ、Windows Phone の BACK ボタンを押したときに
// ゲームを終了させます
if (gamePadState.Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}
// 移動スピード
float speed = 200.0f;
// キーボードによるマークの移動
if (keyboardState.IsKeyDown(Keys.Left))
{
this.markPosition.X -= speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (keyboardState.IsKeyDown(Keys.Right))
{
this.markPosition.X += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (keyboardState.IsKeyDown(Keys.Up))
{
this.markPosition.Y -= speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (keyboardState.IsKeyDown(Keys.Down))
{
this.markPosition.Y += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
// ゲームパッドによるマークの移動
if (gamePadState.IsConnected)
{
this.markPosition.X += gamePadState.ThumbSticks.Left.X * speed *
(float)gameTime.ElapsedGameTime.TotalSeconds;
this.markPosition.Y -= gamePadState.ThumbSticks.Left.Y * speed *
(float)gameTime.ElapsedGameTime.TotalSeconds;
}
// マウス処理
MouseState mouseState = Mouse.GetState();
if (mouseState.X >= 0 && mouseState.X < this.Window.ClientBounds.Width &&
mouseState.Y >= 0 && mouseState.Y < this.Window.ClientBounds.Height &&
mouseState.LeftButton == ButtonState.Pressed)
{
// マウスがウインドウ内にあればマウスの位置を優先する
this.markPosition = new Vector2(mouseState.X, mouseState.Y);
}
// ビューポートを取得
Viewport viewport = this.GraphicsDevice.Viewport;
// スクリーンの位置を Vector3 で作成 (Z は 1.0 以下を設定)
Vector3 screenPosition = new Vector3(this.markPosition, 1.0f);
// スクリーン座標を3次元座標に変換
Vector3 worldPoint = viewport.Unproject(screenPosition,
this.projection,
this.view,
Matrix.Identity);
// マークが指す方向へのレイを作成
Ray ray = new Ray(this.cameraPosition,
Vector3.Normalize(worldPoint - this.cameraPosition));
// 球とレイとの当たり判定を行う
this.isHit = false;
foreach (ModelMesh mesh in this.model.Meshes)
{
if (mesh.BoundingSphere.Intersects(ray) != null)
{
// 球とレイは交差している
this.isHit = true;
break;
}
}
// 登録された GameComponent を更新する
base.Update(gameTime);
}
<summary>
描画処理を行うメソッド
</summary>
<param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
protected override void Draw(GameTime gameTime)
{
// 画面を指定した色でクリアします
this.GraphicsDevice.Clear(Color.CornflowerBlue);
// Zバッファを有効にする
this.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
// モデルを描画
foreach (ModelMesh mesh in this.model.Meshes)
{
mesh.Draw();
}
// スプライトの描画準備
this.spriteBatch.Begin();
// マーク描画
this.spriteBatch.Draw(this.mark, this.markPosition,
null, Color.White, 0.0f,
this.markCenterPosition, 1.0f, SpriteEffects.None, 0.0f);
// テキスト描画
this.spriteBatch.DrawString(this.font,
"Cursor Key Press or" + Environment.NewLine +
" MouseLeftButton Drag" + Environment.NewLine +
"Hit : " + this.isHit,
new Vector2(50.0f, 50.0f), Color.White);
// スプライトの一括描画
this.spriteBatch.End();
// 登録された DrawableGameComponent を描画する
base.Draw(gameTime);
}
}
}