/// <summary> /// Fire a missile from the given shooter's position at the target position. /// </summary> /// <param name="shooter"></param> /// <param name="targetPos"></param> /// <param name="color"></param> /// <param name="verbPayload"></param> /// <returns></returns> public bool Fire(GameActor shooter, Vector3 targetPos, Classification.Colors color, GameThing.Verbs verbPayload, int damage) { if (numActiveBleeps < kMaxBleeps) { float speed = shooter.BlipSpeed; float time2Live = shooter.BlipRange / speed; Bleep bleep = new Bleep(); bleep.Position = shooter.WorldGlowPosition; bleep.StartHeight = bleep.Position.Z; bleep.Position.Z = shooter.WorldCollisionCenter.Z; bleep.Velocity = Vector3.Normalize(targetPos - bleep.Position) * speed; float vdotv = Vector3.Dot(bleep.Velocity, shooter.Movement.Velocity); if (vdotv > 0) { /// If the bullet is moving the same direction as the shooter, /// add in the shooter's speed in the bullet's direction. /// This will only speed up the bullet, not change it's firing /// direction. vdotv /= bleep.Velocity.LengthSquared(); bleep.Velocity += bleep.Velocity * vdotv; } bleep.Life = bleep.TTL = time2Live; bleep.VerbPayload = verbPayload; bleep.Damage = damage; Vector4 color4 = Classification.ColorVector4(color); /// Brighten up the color a bit. color4.X = MyMath.SmoothStep(0.0f, 1.0f, color4.X); color4.Y = MyMath.SmoothStep(0.0f, 1.0f, color4.Y); color4.Z = MyMath.SmoothStep(0.0f, 1.0f, color4.Z); bleep.Color = new Color(color4); bleep.TTTerraHit = CheckTerrainHit(bleep, speed); if (shooter.ActiveBleeps.Bleeps.Count == 0) { Shooters.Add(shooter); } shooter.ActiveBleeps.Bleeps.Add(bleep); // Increment the number of active bleeps. Without this, on the // current frame we can end up shooting enough new bleeps to // exceed the max. ++numActiveBleeps; return(true); } return(false); }
/// <summary> /// Look ahead over the life of this bleep (since it's strictly inertial) /// for when (if ever) it would strike terrain or path. We do the single /// LOS check with background on firing, but checks against other objects /// (which are probably moving) every frame. /// </summary> /// <param name="bleep"></param> /// <param name="speed"></param> /// <returns></returns> private float CheckTerrainHit(Bleep bleep, float speed) { Vector3 start = bleep.Position; Vector3 end = start + bleep.Velocity * bleep.TTL; Vector3 terrainHitPos = Vector3.Zero; float ttTerraHit = bleep.Life * 2; if (SimWorld.Terra.Terrain.LOSCheckTerrainAndPath(start, end, ref terrainHitPos)) { Vector3 total = end - start; float invRangeSq = bleep.Life / total.LengthSquared(); Vector3 toTerraHit = terrainHitPos - start; ttTerraHit = Vector3.Dot(toTerraHit, total) * invRangeSq; } return(ttTerraHit); }
/// <summary> /// Test to see if a bleep hit anything, object or terrain. /// </summary> /// <param name="shooter"></param> /// <param name="bleeps"></param> /// <param name="particle"></param> /// <returns></returns> private bool HitSomething(GameActor shooter, Bleep bleep) { Vector3 start = bleep.Position; Vector3 end = start + bleep.Velocity * Time.GameTimeFrameSeconds; Vector3 terrainHit = end; bool hitTerrain = bleep.Life - bleep.TTL >= bleep.TTTerraHit; if (hitTerrain) { /// terrain hit is current position /// - what we've travelled already (vel * (life - ttl)) /// + time from beginning to terrain hit (vel * ttTerraHit) /// We use end as current position because we've already updated TTL /// but haven't yet advanced .Position. When we do advance .Position, /// it will be to "end". terrainHit = end + bleep.Velocity * (bleep.TTTerraHit - (bleep.Life - bleep.TTL)); } const float kBleepRadius = 0.25f; GameActor hitThing = null; Vector3 hitPoint = terrainHit; if (CollSys.TestAll( start, end, kBleepRadius, _scratchHitInfo)) { for (int i = 0; i < _scratchHitInfo.Count; ++i) { GameActor other = _scratchHitInfo[i].Other; if (!ExcludedHitThing(shooter, other)) { hitThing = other; hitPoint = _scratchHitInfo[i].Contact; break; } } _scratchHitInfo.Clear(); } if (hitTerrain && (hitThing != null)) { if (Vector3.DistanceSquared(start, terrainHit) < Vector3.DistanceSquared(start, hitPoint)) { hitThing = null; hitPoint = terrainHit; } } if (hitThing != null) { OnHit(shooter, hitThing, hitPoint, bleep); } else if (hitTerrain) { OnHit(shooter, null, hitPoint, bleep); ExplosionManager.CreateSpark(hitPoint, 3, 0.4f, 1.0f); } return(hitTerrain || (hitThing != null));; }
/// <summary> /// Take care of necessary callbacks when a Bleep hits a thing. /// </summary> /// <param name="shooter"></param> /// <param name="hitThing"></param> /// <param name="bleep"></param> private void OnHit(GameActor shooter, GameThing hitThing, Vector3 hitPos, Bleep bleep) { Debug.Assert(shooter != null); shooter.OnBlipHit(hitThing, hitPos, bleep.VerbPayload, bleep.Damage); }
/// <summary> /// Update all birds in the air. /// </summary> public override void Update() { numActiveBleeps = 0; int vtxIdx = 0; if (Shooters.Count > 0) { float dt = Time.GameTimeFrameSeconds; for (int shooterIdx = Shooters.Count - 1; shooterIdx >= 0; --shooterIdx) { GameActor shooter = Shooters[shooterIdx]; List <Bleep> bleeps = shooter.ActiveBleeps.Bleeps; for (int i = bleeps.Count - 1; i >= 0; --i) { Bleep bleep = bleeps[i]; bleep.TTL -= dt; if (bleep.TTL <= 0) { OnExpire(shooter); RemoveParticle(shooter, bleeps, i); } else if (HitSomething(shooter, bleep)) { RemoveParticle(shooter, bleeps, i); } else { // Update the current blip. bleep.Position.X += bleep.Velocity.X * dt; bleep.Position.Y += bleep.Velocity.Y * dt; bleep.Position.Z += bleep.Velocity.Z * dt; bleeps[i] = bleep; // If we have room in the buffer to render it, do so. if (numActiveBleeps < kMaxBleeps) { BleepVertex vert = new BleepVertex(); vert.Position = bleep.Position; vert.Color = bleep.Color.PackedValue; vert.TexCoord = new Vector4( 0.0f, 0.0f, 1.0f - bleep.TTL / bleep.Life, bleep.StartHeight); verts[vtxIdx++] = vert; vert.TexCoord.X = 1.0f; verts[vtxIdx++] = vert; vert.TexCoord.Y = 1.0f; verts[vtxIdx++] = vert; vert.TexCoord.X = 0.0f; verts[vtxIdx++] = vert; ++numActiveBleeps; } else { Debug.Assert(false, "We should never get here. If we do it means that we're allowing Fire() to happen when we're already maxed out."); } } } Debug.Assert(shooter.ActiveBleeps.Bleeps == bleeps); if (bleeps.Count == 0) { Shooters.RemoveAt(shooterIdx); } } } if (numActiveBleeps > 0) { UpdateBuffer(numActiveBleeps); } }
private void Start() { speakBehavior = new Bleep(); moveBehavior = new Walk(); }