예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
    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;
            }
        }
    }
예제 #6
0
    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);
        }
    }
예제 #7
0
	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();
	}
예제 #8
0
        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);
        }
예제 #9
0
        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);
    }
예제 #11
0
 public override void SetStaticDefaults()
 {
     DisplayName.SetDefault("Supernova Ball");
     ProjectileHelper.RegisterMassiveBlast(projectile.type);
 }
예제 #12
0
        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;
        }
예제 #13
0
    //{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");
    }
예제 #14
0
 public override void SetStaticDefaults()
 {
     DisplayName.SetDefault("Holy Wrath Ball");
     Main.projFrames[projectile.type] = 1;
     ProjectileHelper.RegisterMassiveBlast(projectile.type);
 }