Beispiel #1
0
    private void Cmd_fireWeapon()
    {
        /* Direction and accuracy */
        aimDirection = (fireLocation.position - playerCenter.position);
        aimDirection.Normalize();
        float inaccuracy = (!isAiming) ?
                           playerWeapons.hipAimAngle() :
                           playerWeapons.adsAimAngle();
        float aimAngle = Mathf.Atan2(aimDirection.y, aimDirection.x) + (Mathf.Deg2Rad * inaccuracy);

        //Debug.Log("aim angle: " + aimAngle);
        aimDirection.x = Mathf.Cos(aimAngle);
        aimDirection.y = Mathf.Sin(aimAngle);
        aimDirection.Normalize();

        Quaternion bulletRotation = Quaternion.AngleAxis(
            (aimAngle * Mathf.Rad2Deg) + aimAngleOffset,
            Vector3.forward);

        /* Bullet prefab */
        GameObject bullet = Instantiate(
            bulletPrefab, fireLocation.position, bulletRotation);

        bullet.GetComponent <Rigidbody2D>().velocity = bullet.transform.up * bulletSpeed;
        /* Spawn the bullet on the Clients */
        NetworkServer.Spawn(bullet);
        Destroy(bullet, bulletLifetime);

        /* Audio */
        if (!isServer)
        {
            Cmd_PlayWeaponAudio();
        }
        else
        {
            Rpc_PlayWeaponAudio();
        }

        /* Raycast */
        RaycastHit2D[] hits    = new RaycastHit2D[maxHits];
        int            numHits = Physics2D.RaycastNonAlloc(
            fireLocation.position,
            aimDirection,
            hits,
            maxShootDistance,
            allShootableLayers.value);

        /* Detect precision damage.  Keep track of names of precision objects
         * hit and the parent object.  Hard-coded based on player heirarchy:
         * Player_vX (contains the life script and principal collider)
         *   -->PointerBody
         *        -->PlayerCenterCriticalSpot
         */
        HashSet <int> needsPrecisionDamage = new HashSet <int>();

        foreach (RaycastHit2D hit in hits)
        {
            if (hit.collider != null)
            {
                int root_id = hit.transform.root.GetInstanceID();
                if (hit.collider.tag == precisionTagName)
                {
                    needsPrecisionDamage.Add(root_id);
                }
                Debug.Log("Hit: " + hit.collider.name + " (" + hit.collider.GetInstanceID() + ").  Root: " +
                          hit.transform.root.name + " (" + hit.transform.root.GetInstanceID() + ").  Tag: " +
                          hit.collider.tag);
            }
        }

        /* Variable to prevent damage through walls.
         * Relies on the order of the raycast results array. */
        bool wasWallHit = false;

        foreach (RaycastHit2D hit in hits)
        {
            if (hit.collider != null)
            {
                int  root_id           = hit.transform.root.GetInstanceID();
                bool isPrecisionDamage = needsPrecisionDamage.Contains(root_id);

                /* Apply damage only to players, for now */
                PlayerLife opponentLife = hit.transform.GetComponent <PlayerLife>();
                if (opponentLife != null && !wasWallHit)
                {
                    float damage = 0.0f;
                    float minRange, maxRange;

                    /* Determine range falloff damage based on if ADS or not */
                    if (!isAiming)
                    {
                        minRange = playerWeapons.EquippedWeapon.hipMinRange;
                        maxRange = playerWeapons.EquippedWeapon.hipMaxRange;
                    }
                    else
                    {
                        minRange = playerWeapons.EquippedWeapon.adsMinRange;
                        maxRange = playerWeapons.EquippedWeapon.adsMaxRange;
                    }

                    /* Calculate the amount of damage to do based on range and precsion hits */
                    float distance = (this.transform.position - hit.transform.position).magnitude;
                    if (distance <= minRange)
                    {
                        damage = (isPrecisionDamage) ?
                                 playerWeapons.EquippedWeapon.roundMaxPrecisionDamage :
                                 playerWeapons.EquippedWeapon.roundMaxDamage;
                    }
                    else if (distance >= maxRange)
                    {
                        damage = (isPrecisionDamage) ?
                                 playerWeapons.EquippedWeapon.roundMinPrecisionDamage :
                                 playerWeapons.EquippedWeapon.roundMinDamage;
                    }
                    else
                    {
                        float lerp = Mathf.Clamp(
                            (distance - minRange) / (maxRange - minRange),
                            0.0f, 1.0f);
                        float damMax = (isPrecisionDamage) ?
                                       playerWeapons.EquippedWeapon.roundMaxPrecisionDamage :
                                       playerWeapons.EquippedWeapon.roundMaxDamage;
                        float damMin = (isPrecisionDamage) ?
                                       playerWeapons.EquippedWeapon.roundMinPrecisionDamage :
                                       playerWeapons.EquippedWeapon.roundMinDamage;
                        damage = Mathf.Lerp(damMax, damMin, lerp);
                    }

                    Debug.Log("Hit Player: " + hit.collider.name);

                    /* Apply Damage */
                    opponentLife.Cmd_applyDamage(damage, isPrecisionDamage);
                }
                /* Hit non-player */
                else
                {
                    wasWallHit = true;
                }
            }
        }

        /* Editor debug raycast */
        Debug.DrawRay(
            fireLocation.position,
            aimDirection * maxShootDistance,
            Color.magenta, 0.1f);

        /* Update weapon TODO: recoil */
        Rpc_UpdatePlayerWeapons(1);
    } /* Cmd_fireWeapon */