1. Trang chủ
  2. » Công Nghệ Thông Tin

Building XNA 2.0 Games- P8 potx

30 264 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 30
Dung lượng 1,76 MB

Nội dung

198 CHAPTER 7 ■ PARTICLE MAYHEM AddParticle(new Smoke(loc, Rand.GetRandomVector2(-50f, 50f, -50f, 10f) - traj * Rand.GetRandomFloat(0.001f, 0.1f), 1f, 1f, 1f, 0.25f, Rand.GetRandomFloat(0.05f, 0.25f), Rand.GetRandomInt(0, 4))); AddParticle(new Smoke(loc, Rand.GetRandomVector2(-50f, 50f, -50f, 10f), 0.5f, 0.5f, 0.5f, 0.25f, Rand.GetRandomFloat(0.1f, 0.5f), Rand.GetRandomInt(0, 4))); } } We’re making a bunch of dust here! The first AddParticle() call sends a bit of light smoke back in the direction the bullet came from, albeit much slower (and at a random speed). The second AddParticle() creates a softer, darker bit of smoke. Since we’re doing 16 of each, we get a soft spray of dust, as shown in Figure 7-11 (it looks better in motion, obviously). Figure 7-11. Bullet ricochet CHAPTER 7 ■ PARTICLE MAYHEM 199 Adding Zombies Shooting the earth is fun enough, but what we really need here are some undead punching bags, and not a moment too soon! We’re all the way to Chapter 7 with nary a monster in sight, so, without further ado, let’s make some zombies! We need to start off with some graphics. We’ll use a few new images: head2.png, torso2.png, and legs2.png, as shown in Figure 7-12. Figure 7-12. Zombie parts We’ll add these images to the Content project in two solutions: CharacterEditor and ZombieSmashers. We also need to upgrade CharacterEditor again to allow the user to specify which textures to use. Zombies in the Character Editor First, we’ll change the arrays as created in Game1.LoadContent() to contain two indices. Fortu- nately, we don’t need to change the loading, because we coded it to automatically load the textures based on the length of the array. legsTex = new Texture2D[2]; torsoTex = new Texture2D[2]; headTex = new Texture2D[2]; weaponTex = new Texture2D[1]; Let’s add a new tab to our low-budget triggers/script tab area, turning it into a triggers/ script/textures tab area. We’ll start by creating a new class-level constant: const int AUX_SCRIPT = 0; const int AUX_TRIGS = 1; const int AUX_TEXTURES = 2; Now we’ll draw our texture-selection panel in Draw(). We’ll just be iterating through the four texture indices, incrementing, decrementing, and drawing text. #region Texture Switching if (auxMode == AUX_TEXTURES) { 200 CHAPTER 7 ■ PARTICLE MAYHEM for (int i = 0; i < 4; i++) { if (DrawButton(210 + i * 21, 40, 1, mouseState.X, mouseState.Y, mouseClick)) { switch (i) { case 0: if (charDef.HeadIndex > 0) charDef.HeadIndex ; break; case 1: if (charDef.TorsoIndex > 0) charDef.TorsoIndex ; break; case 2: if (charDef.LegsIndex > 0) charDef.LegsIndex ; break; case 3: if (charDef.WeaponIndex > 0) charDef.WeaponIndex ; break; } } string t = charDef.HeadIndex.ToString(); switch (i) { case 1: t = charDef.TorsoIndex.ToString(); break; case 2: t = charDef.LegsIndex.ToString(); break; case 3: t = charDef.WeaponIndex.ToString(); break; } text.Color = Color.White; text.DrawText(212 + i * 21, 60, t); if (DrawButton(210 + i * 21, 85, 2, mouseState.X, mouseState.Y, mouseClick)) { switch (i) { CHAPTER 7 ■ PARTICLE MAYHEM 201 case 0: if (charDef.HeadIndex < headTex.Length - 1) charDef.HeadIndex++; break; case 1: if (charDef.TorsoIndex < torsoTex.Length - 1) charDef.TorsoIndex++; break; case 2: if (charDef.LegsIndex < legsTex.Length - 1) charDef.LegsIndex++; break; case 3: if (charDef.WeaponIndex < weaponTex.Length - 1) charDef.WeaponIndex++; break; } } } } #endregion Finally, we add a third tab button to our triggers/script/texture area: #region Script/Trigs Selector . . . if (auxMode == AUX_TEXTURES) { text.Color = Color.Lime; text.DrawText(300, 110, "tex"); } else { if (text.DrawClickText(300, 110, "tex", mouseState.X, mouseState.Y, mouseClick)) auxMode = AUX_TEXTURES; } #endregion Our texture selection panel (and zombie) is shown in Figure 7-13. We’ve set up the zombie with some simple animations: idle, fly, land, and run—which we’ve dealt with before—and hit, which will become a new reserved word animation that we’ll set a character to when it has been hit. 202 CHAPTER 7 ■ PARTICLE MAYHEM Figure 7-13. Texture selection and a brand-new zombie Bringing Zombies into the Game Now let’s bring the zombie into ZombieSmashers. First, put the zombie.zmx file into data/chars, and make sure to include it in the project and select Copy If Newer. Now is probably a good time to add a new field to Character to specify which team that character is on (the good guys or the bad guys). At the class level in Character, add the following: public const int TEAM_GOOD_GUYS = 0; public const int TEAM_BAD_GUYS = 1; public int Team; CHAPTER 7 ■ PARTICLE MAYHEM 203 Then change the constructor to this: public Character(Vector2 newLoc, CharDef newCharDef, int newId, int newTeam) { Id = newId; Team = newTeam; Now that our Character class has a new team field and constructor, we need to update Game1.Initialize() to load the new zombie file and create characters using the new constructor. charDef[(int)CharacterType.Guy] = new CharDef("chars/guy"); charDef[(int)CharacterType.Zombie] = new CharDef("chars/zombie"); character[0] = new Character(new Vector2(100f, 100f), charDef[(int)CharacterType.Zombie], 0, Character.TEAM_GOOD_GUYS); We deemed it prudent to make eight zombies, spaced at 100-pixel intervals across our map. They will just spawn in the sky, land, and stand there. for (int i = 1; i < 9; i++){ character[i] = new Character(new Vector2((float)i * 100f, 100f), charDef[(int)CharacterType.Zombie], i, Character.TEAM_BAD_GUYS); character[i].Map = map; } Now, in Draw(), we’ll draw all existing characters instead of just the guy at index 0. Change the character[0].Draw() line as follows: for (int i = 0; i < character.Length; i++) if (character[i] != null) character[i].Draw(spriteBatch); There! We’ve added our zombie character definition file zombie.zmx to ZombieSmashers, parsed the file as CharacterType.Zombie, created eight zombies, and are now drawing all char- acters every frame. The result is shown in Figure 7-14. We don’t have hit collision yet, but that’s coming up soon. 204 CHAPTER 7 ■ PARTICLE MAYHEM Figure 7-14. Zombies in a row Time for the fun part! Smashing Zombies We finally get to the whole point: smashing zombies. It’s time to put our weapons to use. Shooting Zombies First, we need to put a function in Character that will determine if a vector is within our hit boundaries. public bool InHitBounds(Vector2 hitLoc) { if (hitLoc.X > Location.X - 50f * Scale && hitLoc.X < Location.X + 50f * Scale && hitLoc.Y > Location.Y - 190f * Scale && hitLoc.Y < Location.Y + 10f * Scale) return true; return false; } CHAPTER 7 ■ PARTICLE MAYHEM 205 Let’s create a class to manage all things related to hitting characters; we’ll call it HitManager. We’ll use it to iterate through valid characters, determine if characters are fair game, and figure out what to do with characters that get hit. We are also going to do some refactoring in the Particle class, adding some properties for Owner, and making both Location and Trajectory into public fields. class HitManager { public static bool CheckHit(Particle p, Character[] c, ParticleManager pMan) { bool r = false; CharDir tFace = GetFaceFromTraj(p.Trajectory); for (int i = 0; i < c.Length; i++) { We’ll want to make sure characters can’t hurt themselves with their own particles (other- wise, we could end up hitting ourselves with our own bullets): if (i != p.Owner) { if (c[i] != null) { if (c[i].InHitBounds(p.Location)) { if (p is Bullet) { if(tFace == CharDir.Left) c[i].Face = CharDir.Right; else c[i].Face = CharDir.Left; c[i].SetAnim("idle"); c[i].SetAnim("hit"); c[i].Slide(-100f); pMan.MakeBulletBlood (p.Location, p.Trajecotry / 2f); pMan.MakeBulletBlood (p.Location, -p.Trajectory); pMan.MakeBulletDust (p.Location, p.Trajectory); r = true; } } } 206 CHAPTER 7 ■ PARTICLE MAYHEM } } return r; } } GetFaceFromTraj() is a short function that returns CharDir.Right for positive x trajectories, and CharDir.Left for negative and zero x trajectories. public static CharDir GetFaceFromTraj(Vector2 trajectory) { return (trajectory.X <= 0) ? CharDir.Left : CharDir.Right; } Now, in ParticleManager, we need to create a method for MakeBulletBlood(). It’s a bit like MakeBulletDust(). We’ll be calling it twice: once for the exit wound and once for a splatter in the direction of the bullet. public void MakeBulletBlood(Vector2 loc, Vector2 traj) { for (int t = 0; t < 32; t++) AddParticle( new Blood(loc, traj * -1f * Rand.GetRandomFloat(0.01f, 0.1f) + Rand.GetRandomVector2(-50f, 50f, -50f, 50f), 1f, 0f, 0f, 1f, Rand.GetRandomFloat(0.1f, 0.3f), Rand.GetRandomInt(0, 4))); } Let’s define Blood. When we instantiate Blood, we’ll send it a location, trajectory, color, size, and icon. We’ll be using the same images as we used for smoke, but tinted red so they look fine and bloody. We’ll be drawing wide and thin, and at the angle of its trajectory, so we get good bits of splatter. CHAPTER 7 ■ PARTICLE MAYHEM 207 class Blood : Particle { public Blood(Vector2 loc, Vector2 traj, float r, float g, float b, float a, float size, int icon) { Location = loc; Trajectory = traj; this.r = r; this.g = g; this.b = b; this.a = a; this.size = size; flag = icon; owner = -1; Exists = true; rotation = GlobalFunctions.GetAngle(Vector2.Zero, traj); frame = Rand.getRandomFloat(0.3f, 0.7f); } When we update the blood, we want it to be slightly affected by gravity, but not so much that it doesn’t seem a bit misty. public override void Update(float gameTime, Map map, ParticleManager pMan, Character[] c) { Trajectory.Y += gameTime * 100f; if (Trajectory.X < -10f) Trajectory.X += gameTime * 200f; if (Trajectory.X > 10f) Trajectory.X -= gameTime * 200f; rotation = GlobalFunctions.GetAngle(Vector2.Zero, Trajectory); [...]... 0.5f), SpriteEffects.None, 1.0f ); } } Our last order of business is changing our Bullet.Update() function to allow the bullets to strike zombies public override void Update(float gameTime, ZombieSmashersXNA.map.Map map, ParticleManager pMan, Character[] c) { if (HitManager.CheckHit(this, c, pMan)) frame = 0f; if (map.CheckParticleCol(loc)) Now we’re checking for hits from Bullet.Update() and killing off... int flag) { Location = loc; Trajectory = traj; Owner = owner; flag = flag; Exists = true; frame = 0.5f; } 211 212 CHAPTER 7 ■ PARTICLE MAYHEM public override void Update(float gameTime, ZombieSmashersXNA.map.Map map, ParticleManager pMan, Character[] c) { HitManager.CheckHit(this, c, pMan); KillMe(); } public override void Draw(SpriteBatch sprite, Texture2D spritesTex) { // } } We’ll be using flag... everything looks right CHAPTER 7 ■ PARTICLE MAYHEM Figure 7-17 Fun air combos! Conclusion Finally, we got to do all the fun stuff in this chapter! Let’s go over the improvements we put into Zombie Smashers XNA: • Implemented a particle system with a particle manager, particle bass class, and a bunch of assorted particles • Implemented map updating, which we used to make our torch segments generate fire and... You may not have professional equipment, but having some sound is what is important For instance, just for fun, a few friends created a Tower Defense clone (a game that involves a lot of sounds) using XNA During the development process, it was important to get sounds working as soon as possible to know where and how they would fit in While the team scoured the Internet for decent sounds, they used placeholder . Rand.GetRandomFloat( -0. 2f, 0f) + Rand.GetRandomVector2(- 1 20 f, 1 20 f, - 1 20 f, 1 20 f), 1f, 0f, 0f, 1f, Rand.GetRandomFloat (0. 01f, 0 .25 f), Rand.GetRandomInt (0, 4))); } MakeBulletDust(loc, traj * - 20 f); MakeBulletDust(loc,. Smoke(loc, Rand.GetRandomVector2(-50f, 50f, -50f, 10f) - traj * Rand.GetRandomFloat (0. 001 f, 0. 1f), 1f, 1f, 1f, 0 .25 f, Rand.GetRandomFloat (0. 05f, 0 .25 f), Rand.GetRandomInt (0, 4))); AddParticle(new. MakeBulletBlood(Vector2 loc, Vector2 traj) { for (int t = 0; t < 32; t++) AddParticle( new Blood(loc, traj * -1f * Rand.GetRandomFloat (0. 01f, 0. 1f) + Rand.GetRandomVector2(-50f, 50f, -50f, 50f), 1f, 0f,

Ngày đăng: 01/07/2014, 22:20