private Particle newParticle(Vector2 pos, float angle, Vector2 sourceVelocity) { Particle particle = new Particle(); particle.Position = pos; float directionAngle = (float)MathHelper.ToRadians((XnaHelper.RandomAngle(angle, _arc))); float speed = applyVariance(_particleSpeed, _speedVariance); particle.Velocity = speed * XnaHelper.VectorFromAngle(directionAngle); particle.Scale = applyVariance(_particleScale, _scaleVariance); particle.Angle = angle; particle.LifeTime = TimeSpan.FromSeconds(applyVariance((float)_particleLife.TotalSeconds, _particleLifeVariance)); if (Reversed) { float secondsAlive = (float)particle.LifeTime.TotalSeconds; //start at the end particle.Position = particle.Position + particle.Velocity * secondsAlive; //comment above and uncomment below for a cool effect (unintentional side effect while working on particles. //not sure why it looks so awesome, but it does) //particle.Position = particle.Position + particle.Velocity * secondsAlive * (1 - _particleDecelerationFactor); //movce in reverse particle.Velocity = Vector2.Negate(particle.Velocity); //start at end scale particle.Scale = _particleScale + _scaleRate * secondsAlive; //start at end rotation particle.Angle = _particleRotationSpeed * secondsAlive; } particle.Velocity += sourceVelocity; return(particle); }
protected void lookThisWay(Vector2 direction) { SpriteState spriteDirection; float angle = XnaHelper.RadiansFromVector(direction); if (angle > -Math.PI / 4 && angle < Math.PI / 4) { spriteDirection = SpriteState.FaceUp; } else if (angle >= Math.PI / 4 && angle < 3 * Math.PI / 4) { spriteDirection = SpriteState.FaceRight; } else if (angle > 3 * Math.PI / 4 || angle < -3 * Math.PI / 4) { spriteDirection = SpriteState.FaceDown; } else { spriteDirection = SpriteState.FaceLeft; } _sprite.AnimationState = (int)spriteDirection; }
private void handleInput(InputManager input) { if (input.Exit) { this.PopState = true; } if (_blackHole.State == BlackHole.BlackHoleState.Exhausted) { return; } _player.MoveDirection = input.MoveDirection; _player.LookDirection = XnaHelper.DirectionBetween(_player.Center, input.MouseLocation); if (input.FirePrimary && _player.UnitLifeState == PhysicalUnit.LifeState.Living) { _primaryWeapon.Trigger(_player.Position, input.MouseLocation); } if (input.FireSecondary && _player.UnitLifeState == PhysicalUnit.LifeState.Living) { _secondaryWeapon.Trigger(_player.Position, input.MouseLocation); } if (input.TriggerGadget1) { _primaryGadget.Trigger(); } if (input.DebugKey) { _blackHole.Explode(); } }
public void CheckAndApplyUnitCollision(PhysicalUnit other) { if (!Collides) { return; //don't check collision if unit shouldn't collide } //special shattered collision detection if (_lifeState == LifeState.Shattered) { tempRec.Width = _hitRect.Width / ICE_DIVISIONS; tempRec.Height = _hitRect.Height / ICE_DIVISIONS; for (int i = 0; i < ICE_DIVISIONS; i++) { for (int j = 0; j < ICE_DIVISIONS; j++) { tempRec.X = (int)(_fragments[i, j].Position.X - tempRec.Width / 2); tempRec.Y = (int)(_fragments[i, j].Position.Y - tempRec.Height / 2); if (tempRec.Intersects(other.HitRect)) { Vector2 fVel = _fragments[i, j].Velocity; float fMass = (float)Mass / (ICE_DIVISIONS * ICE_DIVISIONS); temp = other.Velocity; other._velocity = (other._velocity * (other.Mass - fMass) + 2 * fMass * fVel) / (fMass + other.Mass); _fragments[i, j].Velocity = (fVel * (fMass - other.Mass) + 2 * other.Mass * temp) / (fMass + other.Mass); } } } return; //ignore normal collision detection } //check if fire should be transferred float dist = XnaHelper.DistanceBetweenRects(HitRect, other.HitRect); if (dist < FIRE_SPREAD_DISTANCE) { if (_statusEffects.Fire > other._statusEffects.Fire) { StatEffect transfer = new StatEffect() { Fire = FIRE_SPREAD_FACTOR * dist / FIRE_SPREAD_DISTANCE * _statusEffects.Fire }; other.ApplyStatus(transfer); ApplyStatus(transfer * -FIRE_SPREAD_LOSS); } } if (XnaHelper.RectsCollide(HitRect, other.HitRect)) { temp = other._velocity; //temp is a static reusable vector other._velocity = (other._velocity * (other.Mass - this.Mass) + 2 * this.Mass * this._velocity) / (this.Mass + other.Mass); this._velocity = (this._velocity * (this.Mass - other.Mass) + 2 * other.Mass * temp) / (this.Mass + other.Mass); } }
protected override void UpdateWeapon(GameTime gameTime) { switch (_hookState) { case (HookState.Idle): { if (_firing) { _hookState = HookState.Fired; _hookPosition = _owner.Position; _hookAngle = XnaHelper.RadiansFromVector(_fireDirection); _hookVelocity = _fireDirection * HOOK_SPEED; } break; } case (HookState.Fired): { if (!(_firing) && Vector2.Distance(_hookPosition, _owner.Position) < MAX_RANGE) { _hookPosition += _hookVelocity; _hookHitRect.X = (int)_hookPosition.X; _hookHitRect.Y = (int)_hookPosition.Y; } else { _hookState = HookState.Retracting; } break; } case (HookState.Retracting): { _hookPosition -= HOOK_SPEED * Vector2.Normalize(_hookPosition - _owner.Center); if (XnaHelper.PointInRect(_hookPosition, _owner.HitRect)) { _hookState = HookState.Idle; } break; } case (HookState.Attached): { _hookPosition = _hookedUnit.Center; Vector2 pullForce = HOOK_FORCE * XnaHelper.DirectionBetween(_owner.Position, _hookedUnit.Position); _owner.ApplyForce(pullForce); _hookedUnit.ApplyForce(Vector2.Negate(pullForce)); if (_firing) { _hookState = HookState.Idle; } break; } } }
/// <summary> /// Move the sprite in the given direction based on its moveForce property /// </summary> /// <param name="direction">Direction to move. Should be normalized for normal movement.</param> private void moveThisWay(Vector2 direction, GameTime gameTime) { //apply movement force, taking into account cryo effect (which slows) ApplyForce(_moveForce * direction * (1 - _statusEffects.Cryo / MAX_STAT_EFFECT)); if (_movementParticleEffect != null) { _movementParticleEffect.Spawn(Center, XnaHelper.DegreesFromVector(-direction), gameTime.ElapsedGameTime, _velocity); } }
public bool PositionInLight(Vector2 position) { // if the angle isn't zero, then it's a cone-shaped light TODO: this isn't actually true if (Angle != 0) { return(XnaHelper.IsPointInsideTriangle(GetVertices(), position)); } return(false); }
private void setPosition(Vector2 blackHolePosition, Vector2 playerPosition, int levelWidth, int levelHeight) { //set bounds on new spawn location bool leftSide = (XnaHelper.RandomInt(0, 1) == 0); _position.X = leftSide ? 0 : levelWidth; _hitRect.X = leftSide ? 0 : levelWidth - _hitRect.Width; _sprite.FlipH = !leftSide; _position.Y = XnaHelper.RandomInt(0, levelHeight); _hitRect.Y = (int)_position.Y; }
public override void CheckAndApplyCollision(PhysicalUnit unit, TimeSpan time) { if (_hookState == HookState.Fired || _hookState == HookState.Retracting) { if (XnaHelper.RectsCollide(_hookHitRect, unit.HitRect)) { _hookedUnit = unit; _hookState = HookState.Attached; } } }
protected override void UpdateWeapon(GameTime gameTime) { if (_firing) { _attackParticleEffect.Spawn(_owner.Center, XnaHelper.DegreesFromVector(_fireDirection), gameTime.ElapsedGameTime, _owner.Velocity); //recoil _owner.ApplyImpact(-_recoil * _fireDirection, 1); } _attackParticleEffect.Update(gameTime); }
/// <summary> /// Attempt to fire a weapon. /// Only fires if enough time has passed since the last fire and enough ammo is available /// </summary> /// <param name="firePosition"></param> /// <param name="targetPosition"></param> public void Trigger(Vector2 firePosition, Vector2 targetPosition) { if (_currentAmmo >= _ammoConsumption && _tillNextFire.TotalSeconds <= 0) { _firing = true; _fireDirection = XnaHelper.DirectionBetween(firePosition, targetPosition); _targetDestination = targetPosition; _currentAmmo -= _ammoConsumption; _tillNextFire = _fireDelay; } }
private void setPosition(Vector2 blackHolePosition, int levelWidth, int levelHeight) { //set bounds on new spawn location int minX, maxX, minY, maxY; //spawn in bounds -- default for burst wave minX = 0; maxX = levelWidth; minY = 0; maxY = levelHeight; if (_isTrickleWave) //spawn out of bounds { switch (XnaHelper.RandomInt(0, 3)) { case 0: //top minX = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxX = levelWidth + OUT_OF_BOUNDS_SPAWN_BUFFER; minY = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxY = 0; break; case 1: //right minX = levelWidth; maxX = levelWidth + OUT_OF_BOUNDS_SPAWN_BUFFER; minY = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxY = levelHeight + OUT_OF_BOUNDS_SPAWN_BUFFER; break; case 2: //bottom minX = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxX = levelWidth + OUT_OF_BOUNDS_SPAWN_BUFFER; minY = levelHeight; maxY = levelHeight + OUT_OF_BOUNDS_SPAWN_BUFFER; break; case 3: //left minX = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxX = 0; minY = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxY = levelHeight + OUT_OF_BOUNDS_SPAWN_BUFFER; break; } } XnaHelper.RandomizeVector(ref _spawnLocation, minX, maxX, minY, maxY); //if spawned too close to black hole, try again if ((_spawnLocation - blackHolePosition).Length() < MIN_BLACKHOLE_SPAWN_DISTANCE) { setPosition(blackHolePosition, _levelBounds.Width, _levelBounds.Height); } }
/// <summary> /// Attempt to fire a weapon. Return true if successfull /// Only fires if enough time has passed since the last fire /// </summary> /// <param name="firePosition"></param> /// <param name="targetPosition"></param> public bool Trigger(Vector2 firePosition, Vector2 targetPosition) { if (_tillNextFire.TotalSeconds <= 0) { _firing = true; _fireDirection = XnaHelper.DirectionBetween(firePosition, targetPosition); _targetDestination = targetPosition; _tillNextFire = _fireDelay; return(true); } return(false); }
public void Update(GameTime gameTime, Rectangle levelBounds, Vector2 blackHolePosition) { if (_lifeState == LifeState.Dormant) { _startTime -= gameTime.ElapsedGameTime; if (_startTime <= TimeSpan.Zero) { _lifeState = LifeState.Living; CanInteract = true; setWaypoint(blackHolePosition, levelBounds.Width, levelBounds.Height); setPosition(blackHolePosition, levelBounds.Width, levelBounds.Height); } } else if (_lifeState == LifeState.Living) { _duration -= gameTime.ElapsedGameTime; if (_duration < TimeSpan.Zero) { _lifeState = LifeState.Ghost; CanInteract = false; } if (Vector2.Distance(_nextWaypoint, Position) < MIN_WAYPOINT_DISTANCE) { setWaypoint(blackHolePosition, levelBounds.Width, levelBounds.Height); } MoveDirection = XnaHelper.DirectionBetween(Position, _nextWaypoint); } else if (_lifeState == LifeState.Ghost) { MoveDirection = XnaHelper.DirectionBetween(Position, _nextWaypoint); _leaveTimer -= gameTime.ElapsedGameTime; _sprite.ScaleFactor = MathHelper.Lerp(0.0f, 1.0f, (float)_leaveTimer.TotalSeconds / LEAVE_LEVEL_TIME); _sprite.Shade = Color.Lerp(Color.Transparent, Color.White, (float)_leaveTimer.TotalSeconds / LEAVE_LEVEL_TIME); if (_leaveTimer < TimeSpan.Zero) { _lifeState = LifeState.Destroyed; } } if (Vector2.Distance(_nextWaypoint, Position) < MIN_WAYPOINT_DISTANCE) { setWaypoint(blackHolePosition, levelBounds.Width, levelBounds.Height); } base.Update(gameTime, levelBounds); }
private void setWaypoint(Vector2 blackHolePosition, int levelWidth, int levelHeight) { //set bounds on new spawn location int minX, maxX, minY, maxY; //spawn in bounds minX = 0; maxX = levelWidth; minY = 0; maxY = levelHeight; //keep reselecting position until find a position far enough from black hole do { XnaHelper.RandomizeVector(ref _nextWaypoint, minX, maxX, minY, maxY); }while (Vector2.Distance(blackHolePosition, _nextWaypoint) < MIN_BLACKHOLE_DISTANCE); }
public override void CheckAndApplyCollision(PhysicalUnit unit, TimeSpan time) { if (!_firing || !unit.Collides) { return; //don't check collisions if not firing } float fireAngle = XnaHelper.RadiansFromVector(_fireDirection); if (XnaHelper.RectangleIntersectsArc(unit.HitRect, _owner.Center, _range, fireAngle, _hitArc)) { _tempVector = unit.Center - _owner.Center; _tempVector.Normalize(); unit.ApplyImpact(_force * _tempVector, 1); unit.ApplyDamage(_damage); } }
public virtual void Update(GameTime gameTime, Vector2 playerPosition, Vector2 blackHolePosition, Rectangle levelBounds) { Vector2 directionToPlayer = XnaHelper.DirectionBetween(Position, playerPosition); MoveDirection = directionToPlayer; LookDirection = directionToPlayer; if (_meleeWeapon != null) { _meleeWeapon.Update(gameTime); if ((playerPosition - Position).Length() <= _meleeWeapon.Range && _lifeState == LifeState.Living) { _meleeWeapon.Trigger(Center, playerPosition); } } base.Update(gameTime, levelBounds); }
private void setPosition(Vector2 blackHolePosition, int levelWidth, int levelHeight) { //set bounds on new spawn location int minX, maxX, minY, maxY; //spawn in bounds -- default for burst wave minX = 0; maxX = levelWidth; minY = 0; maxY = levelHeight; switch (XnaHelper.RandomInt(0, 3)) { case 0: //top minX = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxX = levelWidth + OUT_OF_BOUNDS_SPAWN_BUFFER; minY = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxY = 0; break; case 1: //right minX = levelWidth; maxX = levelWidth + OUT_OF_BOUNDS_SPAWN_BUFFER; minY = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxY = levelHeight + OUT_OF_BOUNDS_SPAWN_BUFFER; break; case 2: //bottom minX = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxX = levelWidth + OUT_OF_BOUNDS_SPAWN_BUFFER; minY = levelHeight; maxY = levelHeight + OUT_OF_BOUNDS_SPAWN_BUFFER; break; case 3: //left minX = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxX = 0; minY = -OUT_OF_BOUNDS_SPAWN_BUFFER; maxY = levelHeight + OUT_OF_BOUNDS_SPAWN_BUFFER; break; } do { XnaHelper.RandomizeVector(ref _position, minX, maxX, minY, maxY); }while (Vector2.Distance(blackHolePosition, _position) < MIN_BLACKHOLE_DISTANCE); }
private void shatter() { _lifeState = LifeState.Shattered; for (int row = 0; row < ICE_DIVISIONS; row++) { for (int col = 0; col < ICE_DIVISIONS; col++) { _fragments[row, col].Health = FRAGMENT_HEALTH * _statusEffects.Cryo / MAX_STAT_EFFECT; _fragments[row, col].Position.X = Position.X + (0.5f + _sprite.Width * (float)col / ICE_DIVISIONS); _fragments[row, col].Position.Y = Position.Y + (0.5f + _sprite.Height * (float)row / ICE_DIVISIONS); XnaHelper.RandomizeVector(ref _fragments[row, col].Velocity, -FRAGMENT_MAX_VELOCITY, FRAGMENT_MAX_VELOCITY, -FRAGMENT_MAX_VELOCITY, FRAGMENT_MAX_VELOCITY); Vector2.Add(ref _fragments[row, col].Velocity, ref _velocity, out _fragments[row, col].Velocity); Vector2.Multiply(ref _fragments[row, col].Velocity, FRAGMENT_VELOCITY_FACTOR, out _fragments[row, col].Velocity); _fragments[row, col].Angle = 0f; _fragments[row, col].AngularVelocity = XnaHelper.RandomAngle(0.0f, FRAGMENT_MAX_ANGULAR_VELOCITY); _fragments[row, col].ScaleFactor = 1f; _fragments[row, col].Active = true; } } }
public List <Vector2> GetFarseerVertices() { // create a list of vectors List <Vector2> vertices = new List <Vector2>(); Vector2 a = Vector2.Zero; // the second vector is the first endpoint, which should take into account angle and range, where angle takes into account where the light is aimed Vector2 b = Engine.Physics.PositionToPhysicsWorld(new Vector2(Range / 1.5f, Range / 1.5f)); b = XnaHelper.RotateVector2(b, Angle - MathHelper.PiOver2 + 0.17f, a); // the third vector is the second endpoint, which should take into account angle, range, and the light's "fov", or the light's interior angle Vector2 c = XnaHelper.RotateVector2(b, Fov, Vector2.Zero); vertices.Add(a); vertices.Add(b); vertices.Add(c); return(vertices); }
public List <Vector2> GetVertices() { // create a list of vectors List <Vector2> vertices = new List <Vector2>(); // the first vector is the light's position Vector2 a = Position; // the second vector is the first endpoint, which should take into account angle and range, where angle takes into account where the light is aimed Vector2 b = Position + new Vector2(Range / 1.5f, Range / 1.5f); b = XnaHelper.RotateVector2(b, Angle - MathHelper.PiOver2 + 0.17f, a); // the third vector is the second endpoint, which should take into account angle, range, and the light's "fov", or the light's interior angle Vector2 c = XnaHelper.RotateVector2(b, Fov, a); vertices.Add(a); vertices.Add(b); vertices.Add(c); return(vertices); }
protected override void UpdateWeapon(GameTime gameTime) { _contactEffect.Update(gameTime); _destinationEffect.Update(gameTime); _proximityEffect.Update(gameTime); int projectilesToSpawn = _firing ? _projectilesPerFire : 0; foreach (Projectile p in _projectiles) { if (p.ProjectileState == Projectile.State.Dormant && projectilesToSpawn > 0) { float rotAngle = XnaHelper.RandomAngle(0, _spread); Matrix.CreateRotationZ(MathHelper.ToRadians(rotAngle), out tempMatrix); p.Initialize(_owner.Position, Vector2.Transform(_fireDirection, tempMatrix), _projectileInfo, _targetDestination, _owner.Velocity, _contactEffect, _destinationEffect, _proximityEffect); projectilesToSpawn--; } p.Update(gameTime); } System.Diagnostics.Debug.Assert(projectilesToSpawn == 0, "did not spawn all projectiles", "Number left: " + projectilesToSpawn, new object[] { this }); if (_fireParticleEffect != null) { if (_firing) { _fireParticleEffect.Spawn( _owner.Position, XnaHelper.DegreesFromVector(_fireDirection), gameTime.ElapsedGameTime, _owner.Velocity); } _fireParticleEffect.Update(gameTime); } }
public virtual void Update(GameTime gameTime, Rectangle levelBounds) { switch (_lifeState) { case LifeState.Living: case LifeState.Ghost: { if (Panicked) { _panicTimer -= gameTime.ElapsedGameTime; if (_panicTimer <= TimeSpan.Zero) { _panicTimer = TimeSpan.FromSeconds(PANIC_DIRECTION_CHANGE_FREQUENCY); XnaHelper.RandomizeVector(ref _moveDirection, -1, 1, -1, 1); _lookDirection = _moveDirection; } } lookThisWay(LookDirection); if (MoveDirection.Length() > 0) { moveThisWay(MoveDirection, gameTime); } //handle burning ApplyDamage(_statusEffects.Fire * (float)gameTime.ElapsedGameTime.TotalSeconds * FIRE_DPS); break; } case LifeState.Disabled: case LifeState.Frozen: { if (_statusEffects.Cryo <= 0) { _lifeState = LifeState.Living; //still cold after defrosting _statusEffects.Cryo = MAX_STAT_EFFECT / 2; } break; } case LifeState.Shattered: { for (int y = 0; y < ICE_DIVISIONS; y++) { for (int x = 0; x < ICE_DIVISIONS; x++) { _fragments[x, y].Angle += _fragments[x, y].AngularVelocity * (float)gameTime.ElapsedGameTime.TotalSeconds; _fragments[x, y].Position += _fragments[x, y].Velocity * (float)gameTime.ElapsedGameTime.TotalSeconds; _fragments[x, y].Velocity += _fragments[x, y].Acceleration * (float)gameTime.ElapsedGameTime.TotalSeconds; _fragments[x, y].Acceleration = Vector2.Zero; _fragments[x, y].Health -= FRAGMENT_MELT_RATE * (float)gameTime.ElapsedGameTime.TotalSeconds; _fragments[x, y].ScaleFactor = _fragments[x, y].Health / FRAGMENT_HEALTH * FRAGMENT_SCALE_FACTOR; XnaHelper.ClampVector(ref _fragments[x, y].Velocity, FRAGMENT_MAX_VELOCITY, out _fragments[x, y].Velocity); if (_fragments[x, y].BeingEaten) { _fragments[x, y].Health -= FRAGMENT_EAT_RATE * (float)gameTime.ElapsedGameTime.TotalSeconds; } } } return; } case LifeState.BeingEaten: { _sprite.ScaleFactor -= BLACK_HOLE_EAT_SCALE_FACTOR * (float)gameTime.ElapsedGameTime.TotalSeconds; if (_sprite.ScaleFactor <= 0) { _lifeState = LifeState.Destroyed; } break; } case LifeState.Destroyed: default: { return; //don't update anything } } stayInBounds(levelBounds.Width, levelBounds.Height); _velocity += _acceleration * (float)gameTime.ElapsedGameTime.TotalSeconds; Position += _velocity * (float)gameTime.ElapsedGameTime.TotalSeconds; controlVelocity(_maxSpeed, gameTime.ElapsedGameTime); _sprite.Angle += _angularVelocity * (float)gameTime.ElapsedGameTime.TotalSeconds; LookDirection = Vector2.Zero; MoveDirection = Vector2.Zero; _acceleration = Vector2.Zero; if (_movementParticleEffect != null) { _movementParticleEffect.Update(gameTime); } //burning visual effect _burningParticleEffect.Spawn(Position, 0.0f, gameTime.ElapsedGameTime, _velocity); _burningParticleEffect.IntensityFactor = _statusEffects.Fire / MAX_STAT_EFFECT; _burningParticleEffect.Update(gameTime); //cryo visual effect if (_statusEffects.Cryo > 0 && _lifeState != LifeState.Disabled) { _sprite.Shade = Color.Lerp(Color.White, Color.Blue, _statusEffects.Cryo / MAX_STAT_EFFECT); } _hitRect.X = (int)Position.X - _hitRect.Width / 2; _hitRect.Y = (int)Position.Y - _hitRect.Height / 2; //manage stat effects if (_statusEffects.Cryo >= MAX_STAT_EFFECT && _lifeState != LifeState.Frozen) { _lifeState = LifeState.Frozen; _iceIntegrity = maxHealth * ICE_INTEGRITY_FACTOR; _statusEffects.Fire = 0; //stop burning if frozen } //decrement every stat effect based on status resist _statusEffects -= _statusResist * (float)gameTime.ElapsedGameTime.TotalSeconds; _statusEffects.Clamp(0, MAX_STAT_EFFECT); _sprite.Update(gameTime); }
public void Update(GameTime gameTime, Rectangle levelBounds, Vector2 blackHolePos, Vector2 targetPos, Rectangle playerRect) { _standingEffect.Update(gameTime); _chargeEffect.Update(gameTime); _explodeEffect.Update(gameTime); _sprite.Update(gameTime); switch (_state) { case State.Dormant: if (SpawnEnable) { _timer -= gameTime.ElapsedGameTime; } if (_timer <= TimeSpan.Zero) { setPosition(blackHolePos, targetPos, levelBounds.Width, levelBounds.Height); _gravity.Position = _position; _state = State.Appearing; _timer = TimeSpan.FromSeconds(APPEAR_TIME); } break; case State.Appearing: _timer -= gameTime.ElapsedGameTime; if (_timer <= TimeSpan.Zero) { _timer = TimeSpan.FromSeconds(MAX_SCAN_TIME); _lockOnTimer = TimeSpan.FromSeconds(LOCK_ON_TIME); _state = State.Scanning; _sprite.Shade = Color.White; } else { _standingEffect.Spawn(_position, XnaHelper.DegreesFromVector(_direction), gameTime.ElapsedGameTime, Vector2.Zero); _sprite.Shade = Color.Lerp(Color.Transparent, Color.White, (APPEAR_TIME - (float)_timer.TotalSeconds) / APPEAR_TIME); } break; case State.Scanning: _timer -= gameTime.ElapsedGameTime; _standingEffect.Spawn(_position, XnaHelper.DegreesFromVector(_direction), gameTime.ElapsedGameTime, Vector2.Zero); _position.Y += scanVelocity(targetPos.Y - _position.Y) * (float)gameTime.ElapsedGameTime.TotalSeconds; _hitRect.Y = (int)_position.Y - _hitRect.Height / 2; //scan for player //check if player found or scan time up if (_hitRect.Top < targetPos.Y && targetPos.Y < _hitRect.Bottom) { _lockOnTimer -= gameTime.ElapsedGameTime; } if (_lockOnTimer < TimeSpan.Zero || _timer < TimeSpan.Zero) { _timer = TimeSpan.FromSeconds(CHARGE_TIME); _state = State.Locked; _direction = _sprite.FlipH ? -Vector2.UnitX : Vector2.UnitX; } break; case State.Locked: _timer -= gameTime.ElapsedGameTime; if (_timer < TimeSpan.Zero) { _state = State.Charging; Vector2.Multiply(ref _direction, MOVE_SPEED, out _velocity); } break; case State.Charging: //trace movement path for (int i = 0; i < PARTICLE_SPAWN_GRANULARITY; i++) { _position.X += _velocity.X * (float)gameTime.ElapsedGameTime.TotalSeconds / PARTICLE_SPAWN_GRANULARITY; float angle = (_sprite.FlipH) ? 90 : -90; _chargeEffect.Spawn(_position, angle, gameTime.ElapsedGameTime, Vector2.Zero); } _hitRect.X = (int)_position.X - _hitRect.Width; _gravity.Position = _position; if (outOfBounds(levelBounds.Width, levelBounds.Height)) { _sprite.Reset(); _timer = _spawnTime; _state = State.Dormant; } break; case State.BeingEaten: _timer -= gameTime.ElapsedGameTime; //_explodeEffect.Spawn(_position, 0.0f, gameTime.ElapsedGameTime, Vector2.Zero); if (_timer <= TimeSpan.Zero) { _state = State.Dormant; _timer = _spawnTime; } break; } }