بسم الله الرحمن الرحيم الدرس الحادي عشر أهلا بكم في الدرس الحادي عشر من سلسلة دروس تعلم 3D Xna (السلسلة الثانية)، سنقوم في هذا الدرس بإضافة أشباح نقطية “Point Sprites”، و سوف نستخدم تقنية ال “Billboarding” لتمثيل الرصاص في اللعبة. لتمثيل الرصاص، بإمكاننا أن نستخدم كره حقيقية ثلاثية الأبعاد، ولكن ذلك سوف يؤدي إلى زيادة الجهد على بطاقة الرسوميات. إذا بدلا من ذلك، سوف نقوم بإستخدام صورة كره نارية ثنائية الأبعاد بسيطة جدا، بإمكانك تنزيلها من هذا الرابط (أو من الملفات المرفقة في الدرس الأول). سوف يكون مطلوب منك فقط تحديد النقطة المركزية للصورة في الفضاء الثلاثي الأبعاد، و من ثم سوف تقوم ال Xna برسم الصورة، بحيث تكون دائما مواجهة للمشاهد بالإضافة إلى تحجيمها بحيث تعكس المسافة بين المشاهد و النقطة في الفضاء الثلاثي الأبعاد. تسمى هذه التقنية بال “Billboarding”. الصورة الثنائية الأبعاد أيضا تسمى شبح “Sprite”، و بما أن ال Xna يلزمها فقط إحداثيات نقطة المركز في الصورة كموقع ثلاثي الأبعاد، فإن هذه الأشباح ثنائية الأبعاد التي تستخدم في العالم الثلاثي الأبعاد تسمى بالأشباح النقطية “Point Sprites”. بما أننا بحاجة إلى نقطة واحدة فقط، سنقوم بهذه الطريقة بتوفير الكثير من نقل البيانات عبر مدخل ال PCI الخاص ببطاقة الرسوميات. عندما نبدأ بإطلاق النار، نريد أن تتحرك الرصاصات إلى الأمام بشكل متواصل. لذا، لكل رصاصة يجب أن نتابع كل من الموقع و الدوران الحالي من أجل حساب إتجاه الرصاصة، تماما مثل الطائرة. لذلك سوف نقوم بتعريف تركيب “Struct” جديد، قم بكتابته في أعلى الكود لديك، فوق المتغيرات الخاصة بنا:
struct Bullet { public Vector3 position; public Quaternion rotation; }
Texture2D bulletTexture;List<Bullet> bulletList = new List<Bullet> ();double lastBulletTime = 0;
bulletTexture = Content.Load<Texture2D> ("bullet");
if (keys.IsKeyDown(Keys.Space)) { double currentTime = gameTime.TotalGameTime.TotalMilliseconds; if (currentTime - lastBulletTime > 100) { Bullet newBullet = new Bullet(); newBullet.position = xwingPosition; newBullet.rotation = xwingRotation; bulletList.Add(newBullet); lastBulletTime = currentTime; } }
private void UpdateBulletPositions(float moveSpeed) { for (int i = 0; i < bulletList.Count; i++) { Bullet currentBullet = bulletList[i]; MoveForward(ref currentBullet.position, currentBullet.rotation, moveSpeed * 2.0f); bulletList[i] = currentBullet; } }
UpdateBulletPositions(moveSpeed);
private struct VertexPointSprite { private Vector3 position; private float pointSize; public VertexPointSprite(Vector3 position, float pointSize) { this.position = position; this.pointSize = pointSize; } public static readonly VertexElement[] VertexElements = { new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), new VertexElement(0, sizeof(float)*3, VertexElementFormat.Single, VertexElementMethod.Default, VertexElementUsage.PointSize, 0), }; public static int SizeInBytes = sizeof(float) * (3 + 1); }
VertexDeclaration pointSpriteVertexDeclaration;
pointSpriteVertexDeclaration = new VertexDeclaration(device, VertexPointSprite.VertexElements);
private void DrawBullets() { if (bulletList.Count > 0) { VertexPointSprite[] spriteArray = new VertexPointSprite[bulletList.Count]; for (int i = 0; i < bulletList.Count; i++) spriteArray[i] = new VertexPointSprite(bulletList[i].position, 50); effect.CurrentTechnique = effect.Techniques["PointSprites"]; Matrix worldMatrix = Matrix.Identity; effect.Parameters["xWorld"].SetValue(worldMatrix); effect.Parameters["xView"].SetValue(viewMatrix); effect.Parameters["xProjection"].SetValue(projectionMatrix); effect.Parameters["xTexture"].SetValue(bulletTexture); device.RenderState.PointSpriteEnable = true; effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); device.VertexDeclaration = pointSpriteVertexDeclaration; device.DrawUserPrimitives(PrimitiveType.PointList, spriteArray, 0, spriteArray.Length); pass.End(); } effect.End(); device.RenderState.PointSpriteEnable = false; } }
DrawBullets();
using System; using System.Collections.Generic; 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.Net; using Microsoft.Xna.Framework.Storage; namespace XNAseries2 { public class Game1 : Microsoft.Xna.Framework.Game { struct Bullet { public Vector3 position; public Quaternion rotation; } private struct VertexPointSprite { private Vector3 position; private float pointSize; public VertexPointSprite(Vector3 position, float pointSize) { this.position = position; this.pointSize = pointSize; } public static readonly VertexElement[] VertexElements = { new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), new VertexElement(0, sizeof(float)*3, VertexElementFormat.Single, VertexElementMethod.Default, VertexElementUsage.PointSize, 0), }; public static int SizeInBytes = sizeof(float) * (3 + 1); } enum CollisionType { None, Building, Boundary, Target } const int maxTargets = 50; int[] buildingHeights = new int[] { 0, 2, 2, 6, 5, 4 }; GraphicsDeviceManager graphics; GraphicsDevice device; Effect effect; Vector3 lightDirection = new Vector3(3, -2, 5); Matrix viewMatrix; Matrix projectionMatrix; Texture2D sceneryTexture; Texture2D bulletTexture; Model xwingModel; Model targetModel; Vector3 xwingPosition = new Vector3(8, 1, -3); Quaternion xwingRotation = Quaternion.Identity; int[,] floorPlan; float gameSpeed = 1.0f; VertexBuffer cityVertexBuffer; VertexDeclaration texturedVertexDeclaration; VertexDeclaration pointSpriteVertexDeclaration; BoundingBox[] buildingBoundingBoxes; BoundingBox completeCityBox; List<BoundingSphere> targetList = new List<BoundingSphere> (); List<Bullet> bulletList = new List<Bullet> (); double lastBulletTime = 0; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { graphics.PreferredBackBufferWidth = 500; graphics.PreferredBackBufferHeight = 500; graphics.IsFullScreen = false; graphics.ApplyChanges(); Window.Title = "Riemer's XNA Tutorials -- Series 2"; LoadFloorPlan(); lightDirection.Normalize(); SetUpBoundingBoxes(); AddTargets(); base.Initialize(); } protected override void LoadContent() { device = graphics.GraphicsDevice; effect = Content.Load<Effect> ("effects"); sceneryTexture = Content.Load<Texture2D> ("texturemap"); bulletTexture = Content.Load<Texture2D> ("bullet"); xwingModel = LoadModel("xwing"); targetModel = LoadModel("target"); SetUpVertices(); SetUpCamera(); pointSpriteVertexDeclaration = new VertexDeclaration(device, VertexPointSprite.VertexElements); } private Model LoadModel(string assetName) { Model newModel = Content.Load<Model> (assetName); foreach (ModelMesh mesh in newModel.Meshes) foreach (ModelMeshPart meshPart in mesh.MeshParts) meshPart.Effect = effect.Clone(device); return newModel; } private void LoadFloorPlan() { floorPlan = new int[,] { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,1,1,0,0,0,1,1,0,0,1,0,1}, {1,0,0,1,1,0,0,0,1,0,0,0,1,0,1}, {1,0,0,0,1,1,0,1,1,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,1,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,1,1,0,0,0,1,0,0,0,0,0,0,1}, {1,0,1,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,0,0,0,1,0,0,0,0,1}, {1,0,1,0,0,0,0,0,0,1,0,0,0,0,1}, {1,0,1,1,0,0,0,0,1,1,0,0,0,1,1}, {1,0,0,0,0,0,0,0,1,1,0,0,0,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, }; Random random = new Random(); int differentBuildings = buildingHeights.Length - 1; for (int x = 0; x < floorPlan.GetLength(0); x++) for (int y = 0; y < floorPlan.GetLength(1); y++) if (floorPlan[x, y] == 1) floorPlan[x, y] = random.Next(differentBuildings) + 1; } private void SetUpBoundingBoxes() { int cityWidth = floorPlan.GetLength(0); int cityLength = floorPlan.GetLength(1); List<BoundingBox> bbList = new List<BoundingBox> (); for (int x = 0; x < cityWidth; x++) { for (int z = 0; z < cityLength; z++) { int buildingType = floorPlan[x, z]; if (buildingType != 0) { int buildingHeight = buildingHeights[buildingType]; Vector3[] buildingPoints = new Vector3[2]; buildingPoints[0] = new Vector3(x, 0, -z); buildingPoints[1] = new Vector3(x + 1, buildingHeight, -z - 1); BoundingBox buildingBox = BoundingBox.CreateFromPoints(buildingPoints); bbList.Add(buildingBox); } } } buildingBoundingBoxes = bbList.ToArray(); Vector3[] boundaryPoints = new Vector3[2]; boundaryPoints[0] = new Vector3(0, 0, 0); boundaryPoints[1] = new Vector3(cityWidth, 20, -cityLength); completeCityBox = BoundingBox.CreateFromPoints(boundaryPoints); } private void AddTargets() { int cityWidth = floorPlan.GetLength(0); int cityLength = floorPlan.GetLength(1); Random random = new Random(); while (targetList.Count < maxTargets) { int x = random.Next(cityWidth); int z = -random.Next(cityLength); float y = (float)random.Next(2000) / 1000f + 1; float radius = (float)random.Next(1000) / 1000f * 0.2f + 0.01f; BoundingSphere newTarget = new BoundingSphere(new Vector3(x, y, z), radius); if (CheckCollision(newTarget) == CollisionType.None) targetList.Add(newTarget); } } private void SetUpCamera() { viewMatrix = Matrix.CreateLookAt(new Vector3(20, 13, -5), new Vector3(8, 0, -7), new Vector3(0, 1, 0)); projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.2f, 500.0f); } private void SetUpVertices() { int differentBuildings = buildingHeights.Length - 1; float imagesInTexture = 1 + differentBuildings * 2; int cityWidth = floorPlan.GetLength(0); int cityLength = floorPlan.GetLength(1); List<VertexPositionNormalTexture> verticesList = new List<VertexPositionNormalTexture> (); for (int x = 0; x < cityWidth; x++) { for (int z = 0; z < cityLength; z++) { int currentbuilding = floorPlan[x, z]; //floor or ceiling verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2(currentbuilding * 2 / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 1, 0), new Vector2((currentbuilding * 2 + 1) / imagesInTexture, 1))); if (currentbuilding != 0) { //front wall verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(0, 0, -1), new Vector2((currentbuilding * 2) / imagesInTexture, 0))); //back wall verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(0, 0, 1), new Vector2((currentbuilding * 2) / imagesInTexture, 1))); //left wall verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z - 1), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, buildingHeights[currentbuilding], -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x, 0, -z), new Vector3(-1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1))); //right wall verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z - 1), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2 - 1) / imagesInTexture, 0))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, 0, -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 1))); verticesList.Add(new VertexPositionNormalTexture(new Vector3(x + 1, buildingHeights[currentbuilding], -z), new Vector3(1, 0, 0), new Vector2((currentbuilding * 2) / imagesInTexture, 0))); } } } cityVertexBuffer = new VertexBuffer(device, verticesList.Count * VertexPositionNormalTexture.SizeInBytes, BufferUsage.WriteOnly); cityVertexBuffer.SetData<VertexPositionNormalTexture> (verticesList.ToArray()); texturedVertexDeclaration = new VertexDeclaration(device, VertexPositionNormalTexture.VertexElements); } protected override void UnloadContent() { } protected override void Update(GameTime gameTime) { ProcessKeyboard(gameTime); float moveSpeed = gameTime.ElapsedGameTime.Milliseconds / 500.0f * gameSpeed; MoveForward(ref xwingPosition, xwingRotation, moveSpeed); BoundingSphere xwingSpere = new BoundingSphere(xwingPosition, 0.04f); if (CheckCollision(xwingSpere) != CollisionType.None) { xwingPosition = new Vector3(8, 1, -3); xwingRotation = Quaternion.Identity; gameSpeed /= 1.1f; } UpdateCamera(); UpdateBulletPositions(moveSpeed); base.Update(gameTime); } private void UpdateCamera() { Vector3 campos = new Vector3(0, 0.1f, 0.6f); campos = Vector3.Transform(campos, Matrix.CreateFromQuaternion(xwingRotation)); campos += xwingPosition; Vector3 camup = new Vector3(0, 1, 0); camup = Vector3.Transform(camup, Matrix.CreateFromQuaternion(xwingRotation)); viewMatrix = Matrix.CreateLookAt(campos, xwingPosition, camup); projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.2f, 500.0f); } private void ProcessKeyboard(GameTime gameTime) { float leftRightRot = 0; float turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f; turningSpeed *= 1.6f * gameSpeed; KeyboardState keys = Keyboard.GetState(); if (keys.IsKeyDown(Keys.Right)) leftRightRot += turningSpeed; if (keys.IsKeyDown(Keys.Left)) leftRightRot -= turningSpeed; float upDownRot = 0; if (keys.IsKeyDown(Keys.Down)) upDownRot += turningSpeed; if (keys.IsKeyDown(Keys.Up)) upDownRot -= turningSpeed; Quaternion additionalRot = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), leftRightRot) * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), upDownRot); xwingRotation *= additionalRot; if (keys.IsKeyDown(Keys.Space)) { double currentTime = gameTime.TotalGameTime.TotalMilliseconds; if (currentTime - lastBulletTime > 100) { Bullet newBullet = new Bullet(); newBullet.position = xwingPosition; newBullet.rotation = xwingRotation; bulletList.Add(newBullet); lastBulletTime = currentTime; } } } private void MoveForward(ref Vector3 position, Quaternion rotationQuat, float speed) { Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotationQuat); position += addVector * speed; } private CollisionType CheckCollision(BoundingSphere sphere) { for (int i = 0; i < buildingBoundingBoxes.Length; i++) if (buildingBoundingBoxes[i].Contains(sphere) != ContainmentType.Disjoint) return CollisionType.Building; if (completeCityBox.Contains(sphere) != ContainmentType.Contains) return CollisionType.Boundary; for (int i = 0; i < targetList.Count; i++) { if (targetList[i].Contains(sphere) != ContainmentType.Disjoint) { targetList.RemoveAt(i); i--; AddTargets(); return CollisionType.Target; } } return CollisionType.None; } private void UpdateBulletPositions(float moveSpeed) { for (int i = 0; i < bulletList.Count; i++) { Bullet currentBullet = bulletList[i]; MoveForward(ref currentBullet.position, currentBullet.rotation, moveSpeed * 2.0f); bulletList[i] = currentBullet; } } protected override void Draw(GameTime gameTime) { device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.DarkSlateBlue, 1.0f, 0); DrawCity(); DrawModel(); DrawTargets(); DrawBullets(); base.Draw(gameTime); } private void DrawCity() { effect.CurrentTechnique = effect.Techniques["Textured"]; effect.Parameters["xWorld"].SetValue(Matrix.Identity); effect.Parameters["xView"].SetValue(viewMatrix); effect.Parameters["xProjection"].SetValue(projectionMatrix); effect.Parameters["xTexture"].SetValue(sceneryTexture); effect.Parameters["xEnableLighting"].SetValue(true); effect.Parameters["xLightDirection"].SetValue(lightDirection); effect.Parameters["xAmbient"].SetValue(0.5f); effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); device.VertexDeclaration = texturedVertexDeclaration; device.Vertices[0].SetSource(cityVertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes); device.DrawPrimitives(PrimitiveType.TriangleList, 0, cityVertexBuffer.SizeInBytes / VertexPositionNormalTexture.SizeInBytes / 3); pass.End(); } effect.End(); } private void DrawModel() { Matrix worldMatrix = Matrix.CreateScale(0.0005f, 0.0005f, 0.0005f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateFromQuaternion(xwingRotation) * Matrix.CreateTranslation(xwingPosition); Matrix[] xwingTransforms = new Matrix[xwingModel.Bones.Count]; xwingModel.CopyAbsoluteBoneTransformsTo(xwingTransforms); foreach (ModelMesh mesh in xwingModel.Meshes) { foreach (Effect currentEffect in mesh.Effects) { currentEffect.CurrentTechnique = currentEffect.Techniques["Colored"]; currentEffect.Parameters["xWorld"].SetValue(xwingTransforms[mesh.ParentBone.Index] * worldMatrix); currentEffect.Parameters["xView"].SetValue(viewMatrix); currentEffect.Parameters["xProjection"].SetValue(projectionMatrix); currentEffect.Parameters["xEnableLighting"].SetValue(true); currentEffect.Parameters["xLightDirection"].SetValue(lightDirection); currentEffect.Parameters["xAmbient"].SetValue(0.5f); } mesh.Draw(); } } private void DrawTargets() { for (int i = 0; i < targetList.Count; i++) { Matrix worldMatrix = Matrix.CreateScale(targetList[i].Radius) * Matrix.CreateTranslation(targetList[i].Center); Matrix[] targetTransforms = new Matrix[targetModel.Bones.Count]; targetModel.CopyAbsoluteBoneTransformsTo(targetTransforms); foreach (ModelMesh mesh in targetModel.Meshes) { foreach (Effect currentEffect in mesh.Effects) { currentEffect.CurrentTechnique = currentEffect.Techniques["Colored"]; currentEffect.Parameters["xWorld"].SetValue(targetTransforms[mesh.ParentBone.Index] * worldMatrix); currentEffect.Parameters["xView"].SetValue(viewMatrix); currentEffect.Parameters["xProjection"].SetValue(projectionMatrix); currentEffect.Parameters["xEnableLighting"].SetValue(true); currentEffect.Parameters["xLightDirection"].SetValue(lightDirection); currentEffect.Parameters["xAmbient"].SetValue(0.5f); } mesh.Draw(); } } } private void DrawBullets() { if (bulletList.Count > 0) { VertexPointSprite[] spriteArray = new VertexPointSprite[bulletList.Count]; for (int i = 0; i < bulletList.Count; i++) spriteArray[i] = new VertexPointSprite(bulletList[i].position, 50); effect.CurrentTechnique = effect.Techniques["PointSprites"]; Matrix worldMatrix = Matrix.Identity; effect.Parameters["xWorld"].SetValue(worldMatrix); effect.Parameters["xView"].SetValue(viewMatrix); effect.Parameters["xProjection"].SetValue(projectionMatrix); effect.Parameters["xTexture"].SetValue(bulletTexture); device.RenderState.PointSpriteEnable = true; effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); device.VertexDeclaration = pointSpriteVertexDeclaration; device.DrawUserPrimitives(PrimitiveType.PointList, spriteArray, 0, spriteArray.Length); pass.End(); } effect.End(); device.RenderState.PointSpriteEnable = false; } } } }