public bool IsTileColliding() { // detects changes rapidly, used for rotation sampling, primarily, as it is shoddy at projecting forward motion. Rectangle struckTile = ProjectileHelper.GetClosestTileCollisionInBeam(TailStart(), HeadEnd()); if (!struckTile.Equals(Rectangle.Empty)) { // samples the full length of the beam using a TilePlotLine method found in vanilla. // unreliable but gets us most of the way there. Tuple <bool, float, BeamHitLocation> collisionData = ProjectileHelper.GetCollisionData(TailStart(), TailEnd(), BeamEnd(), HeadEnd(), tailSize.X, beamSize.X, headSize.X, Distance, struckTile); Distance = collisionData.Item3 == BeamHitLocation.Tail ? 0f : Math.Min(maxBeamDistance, collisionData.Item2); return(true); } // only sample the second time if we didn't already detect collision in the beam routine // this picks up the pieces when the above method fails to properly detect collision, which happens for reasons I can't explain. Tuple <float, Rectangle> struckTileWithOffset = ProjectileHelper.GetClosestTileCollisionByForwardSampling(HeadEnd(), beamSpeed, projectile.velocity); if (!struckTileWithOffset.Item2.Equals(Rectangle.Empty)) { Tuple <bool, float, BeamHitLocation> collisionData = ProjectileHelper.GetCollisionData(TailStart(), TailEnd(), BeamEnd(), HeadEnd(), tailSize.X, beamSize.X, headSize.X, Distance, struckTileWithOffset.Item2); Distance = (collisionData.Item3 == BeamHitLocation.Tail ? 0f : Math.Min(collisionData.Item2 + struckTileWithOffset.Item1, maxBeamDistance)); return(true); } return(false); }
public bool CanHitEntity(Entity e) { if (!e.active) { return(false); } Tuple <bool, float, BeamHitLocation> collisionData = ProjectileHelper.GetCollisionData(TailStart(), TailEnd(), BeamEnd(), HeadEnd(), tailSize.X, beamSize.X, headSize.X, Distance, e.Hitbox); if (collisionData.Item1 && isEntityColliding) { bool isColliding = false; // if the beam would kill this target in one hit, no collision! if (e is NPC && projectile.damage <= ((NPC)e).lifeMax) { isColliding = true; } else if (e is Player && projectile.damage <= ((Player)e).statLifeMax2) { isColliding = true; } if (isColliding) { Distance = collisionData.Item2; // arbitrary padding ProjectileHelper.DoBeamCollisionDust(dustType, collisionDustFrequency, projectile.velocity, HeadEnd()); } } return(collisionData.Item1); }
private void HandleTileCollision() { bool isColliding = IsTileColliding(); // if distance is about to be throttled, we're hitting something. Spawn some dust. if (isColliding) { //framesSinceCollision = -5; if (BeamIntensityPercentage >= BEAM_INTENSITY_MINIMUM_FOR_COLLISION_DUST) { var dustVector = HeadEnd(); ProjectileHelper.DoBeamCollisionDust(dustType, collisionDustFrequency, projectile.velocity, dustVector); } } else { //framesSinceCollision = Math.Min(50, framesSinceCollision + 1); float beamAcceleration = 1f; // Math.Max(0, Math.Min(1, framesSinceCollision * 0.02f)); Distance = Math.Min(maxBeamDistance, Distance + beamAcceleration * beamSpeed); } // shoot sweet sweet particles for (var i = 0; i < fireParticleDensity; i++) { ProjectileHelper.DoBeamDust(projectile.position, projectile.velocity, dustType, dustFrequency, Distance, TailHeldDistance, tailSize.ToVector2(), beamSpeed); } }
public bool ShouldHandleWeaponChangesAndContinue(Player player) { if (player.HeldItem == null || player.dead) { projectile.Kill(); return(false); } if (_weaponBinding == -1) { _weaponBinding = player.HeldItem.type; } else { if (player.HeldItem.type != _weaponBinding) { // do a buttload of decay dust for (var i = 0; i < disperseDustQuantity; i++) { ProjectileHelper.DoChargeDust(GetChargeBallPosition(), dustType, disperseDustFrequency, true, chargeSize.ToVector2()); } projectile.Kill(); return(false); } } // weapon's correct, keep doing what you're doing. return(true); }
void DrawAimingTrajectory() { Vector3 direction = new Vector3(1.0f, 0.0f, 0.0f); Vector3 bankingAxis = new Vector3(0.0f, 1.0f, 0.0f); direction = Quaternion.AngleAxis(m_CurrentDesiredAngle, bankingAxis) * direction; Vector3 horizonAxis = Vector3.Cross(direction, bankingAxis); direction = Quaternion.AngleAxis(45.0f, horizonAxis) * direction; Vector3 startVelocity = direction * m_CurrentDesiredSpeed; Vector3 startPosition = new Vector3(0.0f, 0.0f, 0.0f); for (int i = 0; i < m_NumTrajectoryPositions; i++) { float currentTime = TrajectoryAimingTimeInterval * i; Vector3 trajectoryPosition = ProjectileHelper.ComputePositionAtTimeAhead (startPosition, startVelocity, m_Gravity, currentTime); m_TrajectoryObjects[i].transform.position = trajectoryPosition; // orientate the previous object to point to the current object if (i > 0) { Vector3 directionToNext = m_TrajectoryObjects[i].transform.position - m_TrajectoryObjects[i - 1].transform.position; directionToNext.Normalize(); m_TrajectoryObjects[i - 1].transform.forward = directionToNext; } } }
void Update() { float dt = Time.deltaTime; Vector3 position = transform.position; ProjectileHelper.UpdateProjectile(ref position, ref m_CurrentVelocity, m_Gravity, dt); transform.position = position; if (position.y < 0.0f) { GameObject.Destroy(this.gameObject); } }
void Update () { float timeToLand = 0.0f; float calulatedMaxSpeed = ProjectileHelper.ComputeSpeedToReachMaxFlatRange(m_GrenadeRange, m_Gravity, out timeToLand); float horizontalInput = Input.GetAxis("Horizontal"); float verticalInput = Input.GetAxis("Vertical"); float dt = Time.deltaTime; m_CurrentDesiredAngle = Mathf.Clamp(m_CurrentDesiredAngle + horizontalInput * m_TurningSpeed * dt, -60.0f, 60.0f); m_CurrentDesiredSpeed = Mathf.Clamp(m_CurrentDesiredSpeed + verticalInput * m_RangeSpeed * dt, 0.5f, calulatedMaxSpeed); DrawAimingTrajectory(); UpdateFiring(); }
public override void InitAttack(Npc target, Tower source) { base.InitAttack(target, source); if (Target != null) { _estimatedTargetPosition = Target.GetPositionInTime(FlightDuration); } _currentVelocity = ProjectileHelper.ComputeVelocityToHitTargetAtTime( transform.position, _estimatedTargetPosition, _gravity, FlightDuration); }
protected virtual void UpdateTransform() { var target = GetTargetPosition(); if (Vector3.Distance(target, transform.position) > 0.01f) { Vector3 position = transform.position; ProjectileHelper.UpdateProjectile(ref position, ref _currentVelocity, _gravity, Time.fixedDeltaTime); transform.position = position; } else { transform.position = target; } }
private void DrawAimingTrajectory(Vector3 startVelocity) { Vector3 startPosition = currentArrow.transform.position; float m_Gravity = Physics.gravity.y; int noOfPositions = 40; float distance = 0; lr.positionCount = noOfPositions + 1; lr.SetPosition(0, currentArrow.transform.position); //var res = rb.CalculateMovement(noOfPositions, 2, startVelocity); for (int i = 0; i < noOfPositions; i++) { float currentTime = TrajectoryAimingTimeInterval * i; Vector3 newPos = ProjectileHelper.ComputePositionAtTimeAhead(startPosition, startVelocity, m_Gravity, currentTime); //distance += Vector3.Distance(lr.GetPosition(i - 1), newPos); lr.SetPosition(i + 1, newPos); //lr.SetPosition(i+1, res[i]); } //lr.materials[0].mainTextureScale = new Vector3(distance, 1, 1); }
public override void SetStaticDefaults() { DisplayName.SetDefault("Supernova Ball"); ProjectileHelper.RegisterMassiveBlast(projectile.type); }
public void HandleChargingKi(Player player) { bool isCharging = false; finalChargeLimit = chargeLimit + MyPlayer.ModPlayer(player).chargeLimitAdd; // stop channeling if the player is out of ki if (MyPlayer.ModPlayer(player).IsKiDepleted()) { player.channel = false; } // keep alive routine. if (projectile.timeLeft < 4) { projectile.timeLeft = 10; } MyPlayer modPlayer = MyPlayer.ModPlayer(player); // charge the ball if the proper keys are held. // increment the charge timer if channeling and apply slowdown effect if (modPlayer.isMouseLeftHeld && !IsFired) { // shoot some dust into the ball to show it's charging, and to look cool. // Also generates light. if (!IsFired) { ProjectileHelper.DoChargeDust(GetChargeBallPosition(), dustType, chargeDustFrequency, false, chargeSize.ToVector2()); } // the player can hold the charge all they like once it's fully charged up. Currently this doesn't incur a movespeed debuff either. if (ChargeLevel < finalChargeLimit && modPlayer.HasKi(ChargeKiDrainRate())) { isCharging = true; // drain ki from the player when charging if (DBZMOD.IsTickRateElapsed(CHARGE_KI_DRAIN_WINDOW)) { MyPlayer.ModPlayer(player).AddKi(-ChargeKiDrainRate(), true, false); } // increase the charge ChargeLevel = Math.Min(finalChargeLimit, ChargeRate() + ChargeLevel); // slow down the player while charging. player.ApplyChannelingSlowdown(); } else { if (ChargeLevel == 0f) { projectile.Kill(); } } } // play the sound if the player just started charging and the audio is "off cooldown" if (!_wasCharging && isCharging && ChargeSoundCooldown == 0f) { if (!Main.dedServ) { chargeSoundSlotId = SoundHelper.PlayCustomSound(chargeSoundKey, projectile.Center, chargeSoundVolume); } ChargeSoundCooldown = chargeSoundDelay; } else { ChargeSoundCooldown = Math.Max(0f, ChargeSoundCooldown - 1); } // set the wasCharging flag for proper tracking _wasCharging = isCharging; }
//{TODO} Damn this method is long... protected virtual void Penetrate(TerminalBallisticsData penData, float stoppingDist) { ProjectileData projData = penData.projectile.projectileData; VirtualPhysicsTransform physicsTransform = penData.projectile.physicsTransform; float targetDensity = 1000.0f; //{TODO} Hook this up //343.0f - Temporary hardcoded value - 1 mach in air ~= 343 m/s ThicknessData objectThickness = ProjectileHelper.FindThickness( physicsTransform.PrevPosition, physicsTransform.Velocity.normalized, (rCH) => rCH.collider.gameObject == penData.hitInfo.collider.gameObject); //Only colliders on this object Debug.Log($"Thickness: {objectThickness.thickness}m"); //{TODO} Add some check to see if the object thickness was even found //If the projectile stops mid-object, de-activate it if (stoppingDist <= objectThickness.thickness) { penData.projectile.Active = false; Debug.Log($"Stopped after penetrating {stoppingDist}m"); return; } //Otherwise, see how fast we come out the other side physicsTransform.Position = objectThickness.exitPosition; //tex: //$$ v=\sqrt{-\frac{ACpx^3}{m}+u^2}$$ physicsTransform.VelocityMagnitude = Mathf.Sqrt( - ( ( projData.CrossSectionalArea * projData.GetDragCoefficient(physicsTransform.Velocity.magnitude / 343.0f) * targetDensity * objectThickness.thickness * objectThickness.thickness * objectThickness.thickness ) / projData.bulletMass ) + (physicsTransform.VelocityMagnitude * physicsTransform.VelocityMagnitude) ); //Modify the exit direction depending on the projectile velocity //{TODO} Rewrite! float range = 0.25f; physicsTransform.VelocityDirection += Vector3.Lerp( new Vector3( CryptoRand.Range(-range, range), CryptoRand.Range(-range, range), CryptoRand.Range(-range, range)), Vector3.zero, Mathf.Clamp(1 / physicsTransform.VelocityMagnitude, 0, 1) ); Debug.Log($"Stopping distance: {stoppingDist}"); Debug.Log($"Fully penetrated with an exit velocity of {physicsTransform.Velocity.magnitude}m/s"); }
public override void SetStaticDefaults() { DisplayName.SetDefault("Holy Wrath Ball"); Main.projFrames[projectile.type] = 1; ProjectileHelper.RegisterMassiveBlast(projectile.type); }