public void Update() { if (m_Balls.Any(b => b.InGame && b.Velocity.Module > 0)) { var newVelocities = new Dictionary <IBallInternal, NewVelocity>(); double performed = 0; while (performed < 1) { newVelocities.Clear(); var validBalls = m_Balls.Where(b => b.InGame); double step = Math.Min(1 - performed, validBalls.Where(b => b.Velocity.Module > 0).Select(b => b?.BankDistance).Min() ?? double.PositiveInfinity); step = Math.Min(step, m_BallSteps.Where(kvp => kvp.Key.InGame).Min(kvp => kvp.Value.Step)); foreach (IBallInternal b in validBalls) { if (m_BallSteps.ContainsKey(b)) { m_BallSteps[b].Update(step); } b.UpdatePosition(step); newVelocities[b] = new NewVelocity(b.Velocity); } performed += step; foreach (var info in m_BallSteps.Where(kvp => kvp.Key.InGame).Where(kvp => kvp.Value.Step.ToleranceEqual(0))) { HandleBallCollision(info.Key, info.Value, newVelocities); } foreach (var data in newVelocities.Where(kvp => kvp.Value.IsValid)) { data.Key.SetVelocity(data.Value.Value); } if (newVelocities.Any(kvp => kvp.Value.IsValid) || validBalls.Any(b => b.DirectionUpdated)) { ComputeSteps(); } } } }
public override void Behavior() { Player player = Main.player[projectile.owner]; const float PlayerStayDist = 40f; projectile.ai[0] -= 1 / 60f; projectile.ai[1] -= 1 / 60f; /**************** * Chase Player * ****************/ Vector2 Direction = player.Center - projectile.Center; Direction.X -= PlayerStayDist * player.direction; Direction.Y -= 30f; Direction.Normalize(); float TargetDist = Vector2.Distance(player.Center - new Vector2(PlayerStayDist * player.direction, 30f), projectile.Center); int NewDirection = Main.player[projectile.owner].direction; Vector2 NewVelocity = projectile.velocity; if (TypeOfAttack != 0 || projectile.ai[0] < 0.01f) { AUA = false; atacking = false; } if (TypeOfAttack == 0) { /**************** * Shoot to NPC * ****************/ float targetDist = viewEnemyDist * 6; Vector2 targetPos = new Vector2(0f, 0f); Vector2 trgdir = new Vector2(NewDirection, 0); for (int k = 0; k < 200; k++) { NPC npc = Main.npc[k]; if (npc.CanBeChasedBy(this, false)) { float distance = Vector2.Distance(npc.Center, player.Center); if ((distance < targetDist) && Collision.CanHitLine(projectile.position, projectile.width, projectile.height, npc.position, npc.width, npc.height)) { targetDist = Vector2.Distance(npc.Center, projectile.Center); trgdir = npc.Center - projectile.Center; trgdir.X = Math.Sign(trgdir.X); targetPos = npc.Center; AUA = true; } } } if (AUA) { if (targetPos == new Vector2(0f, 0f)) { AUA = false; projectile.ai[1] = 0f; } ///Direction = targetPos - projectile.Center; ///Direction.Normalize; NewDirection = Math.Sign(trgdir.X); if (projectile.ai[0] < 0.01f || projectile.ai[1] > 0.01f) { if (projectile.ai[1] < 0.01f && projectile.ai[0] < 0.01f) { projectile.ai[1] = 1.09f; } else if (projectile.ai[1] % 0.1f < 1f / 60f) { ///StandoPlayer.Talk((projectile.ai[1] % 0.1f).ToString()); Vector2 D = targetPos - projectile.Center; D.Normalize(); Vector2 ShootV = D * ShootVel; ShootV = ShootV.RotatedByRandom(Math.PI / 12); int proj = Projectile.NewProjectile(projectile.Center.X + NewDirection * projectile.Size.X * 0.2f, projectile.Center.Y - projectile.Size.Y * 0.2f, ShootV.X, ShootV.Y, Shoot, projectile.damage, projectile.knockBack, projectile.owner, 0f, 0f); Main.projectile[proj].timeLeft = 300; Main.projectile[proj].netUpdate = true; } projectile.ai[0] = 2f; } atacking = true; } } else if (TypeOfAttack != 0) { /************* * Chase NPC * *************/ float targetDist = viewEnemyDist; Vector2 targetPos = new Vector2(0f, 0f); Vector2 trgdir = new Vector2(NewDirection, 0); for (int k = 0; k < 200; k++) { NPC npc = Main.npc[k]; if (npc.CanBeChasedBy(this, false)) { float distance = Vector2.Distance(npc.Center, player.Center); if ((distance < targetDist) /* && Collision.CanHitLine(projectile.position, projectile.width, projectile.height, npc.position, npc.width, npc.height)*/) { targetDist = Vector2.Distance(npc.Center, projectile.Center); trgdir = npc.Center - projectile.Center; trgdir.Y = 0f; trgdir.X = Math.Sign(trgdir.X); targetPos = npc.Center - trgdir * (npc.width + projectile.width) * 0.45f; AUA = true; } } } if (AUA) { Direction = targetPos - projectile.Center; Direction.Normalize(); NewDirection = Math.Sign(trgdir.X); if (targetDist < projectile.width) { atacking = true; } } } /************************* * Check Player distance * *************************/ if (Vector2.Distance(player.Center, projectile.Center) > MaxDist) { Direction = player.Center - projectile.Center; Direction.X -= 30f * player.direction; Direction.Y -= 30f; Direction.Normalize(); AUA = atacking = false; } if (Vector2.Distance(player.Center, projectile.Center) > maxPlayerDist + 239) { projectile.position = player.Center - new Vector2(30f * player.direction, 30f); TargetDist = 0; NewVelocity = new Vector2(0, 0); } /*************************** * Processing speed(wagon) * ***************************/ if (TargetDist > 1f) { if (TargetDist > maxPlayerDist) { NewVelocity = Direction * Math.Max(player.velocity.Length(), 5f); } else { float temp = inertia * 0.5f; NewVelocity = (projectile.velocity * temp + Direction * chasePlayerSpeed) / (temp + 1); } } else { NewVelocity *= 0.833333333f; } if (NewVelocity.HasNaNs()) { NewVelocity = projectile.velocity; // This is bug fix ^_^ } if (projectile.velocity.Length() > maxSpeed) { projectile.velocity.Normalize(); projectile.velocity *= 9; } projectile.direction = NewDirection; projectile.spriteDirection = projectile.direction; projectile.velocity = NewVelocity; SelectFrame(); CreateDust(); projectile.netUpdate = true; }