修改预制游戏,在游戏结束时还原

时间:2019-08-10 11:22:06

标签: c# unity3d

在我的游戏中,弹丸有多种类型。我有玩家的弹丸,也有一些敌人的弹丸。但是所有这些弹丸都是从相同的脚本定向的。

为了使每个弹丸具有不同的行为,我为每个弹丸做了一个预制件,该预制件在“武器”触发时实例化。这样,每个预制件都有自己的损坏和其他组件统计信息。

在游戏中,我希望用户能够更改预制件“击中损坏”,但是一旦用户死亡,则需要将其还原并重新启动游戏。

所以我的问题是,在升级菜单中,我如何更改每个不同弹丸的DamageOnhit值,因为这些弹丸都附在了不同武器上。

我的3种不同的弹丸预制件(将来会更多) Prefabs

每个预制件的int计数器 Damage

我的投射物导致每个不同的投射物以1点的标准伤害开始。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//[RequireComponent (typeof(Rigidbody2D))]
public class Projectile : MonoBehaviour {

    [Header ("Speed")]
    public float baseSpeed;
    public float randomSpeed;
    public Vector2 SpeedV2;
    public Vector2 Direction;

    [Header ("Damage")]
    public int DamageOnHit = 1;

    [Header ("Layers")]
    public LayerMask solid_layer;
    public LayerMask entities_layer;

    [Header ("OnHit FX")]
    public GameObject HitFxPrefab;
    public GameObject DustFxPrefab;

    [Header ("Bounce")]
    public bool BounceOnCollide = false;
    public int bouncesLeft = 0;

    [HideInInspector]
    public Health owner; // owner of the projectile
    private Vector2 Position; // Current position
    private Vector2 movementCounter = Vector2.zero;  // Counter for subpixel movement
    public BoxCollider2D myCollider;
    List<Health> healthsDamaged = new List<Health>(); // List to store healths damaged

    void Awake () {
        if (myCollider == null) {
            myCollider = GetComponent<BoxCollider2D> ();
        }
    }

    void Start () {
        // keeping everything Pixel perfect
        Position = new Vector2 (Mathf.Round(transform.position.x), Mathf.Round(transform.position.y));
        transform.position = Position;
    }

    void Update () {
        SpeedV2 = new Vector2 (transform.right.x, transform.right.y) * (baseSpeed + Random.value * randomSpeed) * Time.deltaTime;
    }

    void LateUpdate () {
        if (SpeedV2.x != 0) {
            MoveH (SpeedV2.x);
        }

        if (SpeedV2.y != 0) {
            MoveV (SpeedV2.y);
        }
    }

    void DestroyMe () {
        if (HitFxPrefab != null) {
            var h = Instantiate (HitFxPrefab, transform.position, transform.rotation);
            h.transform.localScale = transform.lossyScale;
            h.transform.localRotation = Quaternion.Euler (new Vector3(0f, 0f, Random.value * 360f));
        }
        Destroy (gameObject);
    }

    void DestroyMeWall () {
        if (HitFxPrefab != null) {
            var h = Instantiate (HitFxPrefab, transform.position, transform.rotation);
            h.transform.localScale = transform.lossyScale;
            h.transform.localRotation = Quaternion.Euler (new Vector3(0f, 0f, Random.value * 360f));
        }
        Destroy (gameObject);
    }

    public void BounceHorizontal () {
        bouncesLeft--;
        transform.right = new Vector3 (-transform.right.x, transform.right.y, transform.right.z);
        SpeedV2 *= 0.8f;
    }

    public void BounceVertical () {
        bouncesLeft--;
        transform.right = new Vector3 (transform.right.x, -transform.right.y, transform.right.z);
        SpeedV2 *= 0.8f;
    }

    void OnCollideWith (Collider2D col, bool horizontalCol = true) {
        var component = col.GetComponent<Health> ();
        // If the target the hitbox collided with has a health component and it is not our owner and it is not on the already on the list of healths damaged by the current hitbox
        if (component != null && component != owner && !healthsDamaged.Contains(component)) {
            // Add the health component to the list of damaged healths
            healthsDamaged.Add (component);

            // Apply the damage
            var didDamage = component.TakeDamage (DamageOnHit);
            // Destroy the projectile after applying damage
            if (didDamage) {
                DestroyMe ();
                return;
            }
        }

        // if the projectile hit's a solid object, destroy it
        if (col.gameObject.layer ==  (int)Mathf.Log(solid_layer.value, 2)) {
            DestroyMeWall ();
            return;
        }
    }

    void OnCollideWithEntity(Collider2D col) {
        var component = col.GetComponent<Health> ();
        // If the target the hitbox collided with has a health component and it is not our owner and it is not on the already on the list of healths damaged by the current hitbox
        if (component != null && component != owner && !healthsDamaged.Contains(component)) {
            // Add the health component to the list of damaged healths
            healthsDamaged.Add (component);

            // Apply the damage
            var didDamage = component.TakeDamage (DamageOnHit);
            // Destroy the projectile after applying damage
            if (didDamage) {
                DestroyMe ();
            }
        }
    }


    // Function to move the Actor Horizontally, this only stores the float value of the movement to allow for subpixel movement and calls the MoveHExact function to do the actual movement
    public bool MoveH(float moveH) {
        this.movementCounter.x = this.movementCounter.x + moveH;
        int num = (int)Mathf.Round(this.movementCounter.x);
        if (num != 0)
        {
            this.movementCounter.x = this.movementCounter.x - (float)num;
            return this.MoveHExact(num);
        }
        return false;
    }

    // Function to move the Actor Horizontally, this only stores the float value of the movement to allow for subpixel movement and calls the MoveHExact function to do the actual movement
    public bool MoveV(float moveV) {
        this.movementCounter.y = this.movementCounter.y + moveV;
        int num = (int)Mathf.Round(this.movementCounter.y);
        if (num != 0)
        {
            this.movementCounter.y = this.movementCounter.y - (float)num;
            return this.MoveVExact(num);
        }
        return false;
    }

    // Function to move the Actor Horizontally an exact integer amount
    public bool MoveVExact(int moveV) {
        int num = (int)Mathf.Sign((float)moveV);
        while (moveV != 0) {
            bool solid = CheckColInDir(Vector2.up * (float)num, solid_layer);
            if (solid) {
                if (BounceOnCollide && bouncesLeft > 0) {
                    bouncesLeft--;
                    num = -num;
                    moveV = -moveV;
                    BounceVertical ();
                } else {
                    this.movementCounter.x = 0f;
                    DestroyMeWall ();
                    return true;
                }
            }

            bool entity = CheckColInDir(Vector2.up * (float)num, entities_layer);
            if (entity) {
                var entit = CheckColsInDirAll (Vector2.up * (float)num, entities_layer);
                OnCollideWithEntity (entit [0]);
            }

            moveV -= num;
            transform.position = new Vector2 (transform.position.x, transform.position.y + (float)num);
        }
        return false;
    }


    // Function to move the Actor Horizontally an exact integer amount
    public bool MoveHExact(int moveH) {
        int num = (int)Mathf.Sign((float)moveH);
        while (moveH != 0) {
            bool solid = CheckColInDir(Vector2.right * (float)num, solid_layer);
            if (solid) {
                if (BounceOnCollide && bouncesLeft > 0) {
                    bouncesLeft--;
                    num = -num;
                    moveH = -moveH;
                    BounceHorizontal ();
                } else {
                    this.movementCounter.x = 0f;
                    DestroyMeWall ();
                    return true;
                }
            }

            bool entity = CheckColInDir(Vector2.right * (float)num, entities_layer);
            if (entity) {
                var entit = CheckColsInDirAll (Vector2.right * (float)num, entities_layer);
                OnCollideWithEntity (entit [0]);
            }

            moveH -= num;
            transform.position = new Vector2 (transform.position.x + (float)num, transform.position.y);
        }
        return false;
    }

    // Helper function to check if there is any collision within a given layer in a set direction (only use up, down, left, right)
    public bool CheckColInDir (Vector2 dir, LayerMask layer) {
        Vector2 leftcorner = Vector2.zero;
        Vector2 rightcorner = Vector2.zero;

        if (dir.x > 0) {
            leftcorner = new Vector2 (myCollider.bounds.center.x + myCollider.bounds.extents.x, myCollider.bounds.center.y + myCollider.bounds.extents.y - .1f);
            rightcorner = new Vector2 (myCollider.bounds.center.x + myCollider.bounds.extents.x + .5f, myCollider.bounds.center.y - myCollider.bounds.extents.y + .1f);
        } else if (dir.x < 0) {
            leftcorner = new Vector2 (myCollider.bounds.center.x - myCollider.bounds.extents.x - .5f, myCollider.bounds.center.y + myCollider.bounds.extents.y - .1f);
            rightcorner = new Vector2 (myCollider.bounds.center.x - myCollider.bounds.extents.x, myCollider.bounds.center.y - myCollider.bounds.extents.y + .1f);
        } else if (dir.y > 0) {
            leftcorner = new Vector2 (myCollider.bounds.center.x - myCollider.bounds.extents.x + .1f, myCollider.bounds.center.y + myCollider.bounds.extents.y + .5f);
            rightcorner = new Vector2 (myCollider.bounds.center.x + myCollider.bounds.extents.x - .1f, myCollider.bounds.center.y + myCollider.bounds.extents.y);
        } else if (dir.y < 0) {
            leftcorner = new Vector2 (myCollider.bounds.center.x - myCollider.bounds.extents.x + .1f, myCollider.bounds.center.y - myCollider.bounds.extents.y);
            rightcorner = new Vector2 (myCollider.bounds.center.x + myCollider.bounds.extents.x - .1f, myCollider.bounds.center.y - myCollider.bounds.extents.y - .5f);
        }

        return Physics2D.OverlapArea(leftcorner, rightcorner, layer);
    }


    // The same as CheckColInDir but it returns a Collider2D array of the colliders you're collisioning with
    public Collider2D[] CheckColsInDirAll (Vector2 dir, LayerMask layer) {
        Vector2 leftcorner = Vector2.zero;
        Vector2 rightcorner = Vector2.zero;

        if (dir.x > 0) {
            leftcorner = new Vector2 (myCollider.bounds.center.x + myCollider.bounds.extents.x, myCollider.bounds.center.y + myCollider.bounds.extents.y - .1f);
            rightcorner = new Vector2 (myCollider.bounds.center.x + myCollider.bounds.extents.x + .5f, myCollider.bounds.center.y - myCollider.bounds.extents.y + .1f);
        } else if (dir.x < 0) {
            leftcorner = new Vector2 (myCollider.bounds.center.x - myCollider.bounds.extents.x - .5f, myCollider.bounds.center.y + myCollider.bounds.extents.y - .1f);
            rightcorner = new Vector2 (myCollider.bounds.center.x - myCollider.bounds.extents.x, myCollider.bounds.center.y - myCollider.bounds.extents.y + .1f);
        } else if (dir.y > 0) {
            leftcorner = new Vector2 (myCollider.bounds.center.x - myCollider.bounds.extents.x + .1f, myCollider.bounds.center.y + myCollider.bounds.extents.y + .5f);
            rightcorner = new Vector2 (myCollider.bounds.center.x + myCollider.bounds.extents.x - .1f, myCollider.bounds.center.y + myCollider.bounds.extents.y);
        } else if (dir.y < 0) {
            leftcorner = new Vector2 (myCollider.bounds.center.x - myCollider.bounds.extents.x + .1f, myCollider.bounds.center.y - myCollider.bounds.extents.y);
            rightcorner = new Vector2 (myCollider.bounds.center.x + myCollider.bounds.extents.x - .1f, myCollider.bounds.center.y - myCollider.bounds.extents.y - .5f);
        }

        return Physics2D.OverlapAreaAll(leftcorner, rightcorner, layer);
    }
}


UpgradeMenu


    public void UpgradeDamage ()
    {
      Projectile.DamageOnHit += 1;

    //  ScoreManager.Score -= upgradeCost;

      UpdateValues();
    }

我希望能够为每个不同的预制件升级此值。 我尝试通过将DamageOnHit更改为静态来进行此操作,但是一旦升级了该值即可。所有的弹丸都升级了。这不是我想要的,因为我希望能够单独更改每个预制件。

2 个答案:

答案 0 :(得分:1)

两种选择:

  • 在射弹的每个实例上设置DamageOnHit

    每次Instantiate一个新的射弹预制棒时,获取其Projectile组件并将其DamageOnHit设置为所需值。

  • 每次游戏重新启动时,请复制每个预制资产

    我们将它们称为“ ProjectileShotgunProto”和“ ProjectileSkeletonProto”。在玩家射击时,您将呼叫Instantiate(ProjectileShotgunProto),而不是实例化您的原始预制件。

在任何情况下,请不要从您的代码中更改原始的预制资产,这会导致问题。

答案 1 :(得分:1)

您创建BulletManager.cs(将此对象附加到将始终处于活动状态的对象或空的游戏对象)

public static BulletManager instance;
private void Awake
{
  if ( instance == null ) //this creates a Singleton so you can access it directly from everywhere, won't go deep into explaining how it works exactly
    {
        instance = this;
    }
    else
    {
        Destroy (gameObject);
    }
}

public int machinegunDmg; //set the initial values in the editor
public int shotgunDmg;
public int skeletonDmg;

现在用适当的标签标记您所有的预制件,假设您对机枪弹丸预制件使用“ MachineGunProj”标签。

取决于您实例化的预制件,您已将附加到所有预制件的相同脚本从该BulletManager脚本中损坏。

private int DamageOnHit;  
//this will get called everytime you instantiate a new prefab that holds this script; it will check for its own tag and depending on it will set the damage in this script to be equal to the appropriate value from BulletManager.cs
private void Start
{
    if(this.gameObject.CompareTag("MachineGunProj"))
    {
      this.DamageOnHit = BulletManager.instance.machinegunDmg;
    }
    else if(this.gameObject.CompareTag("ShotgunProj"))
    {
      this.DamageOnHit = BulletManager.instance.shotgunDmg;
    }
    //else if -- do the same for every prefab you have
}

对于升级,您需要更改BulletManager.cs中的值。 例如:

public void UpgradeMachineGun()
{
   BulletManager.instance.machinegunDmg++; //next time you spawn a machinegun prefab it will take the upgraded value
}

*我在没有任何文本编辑器的帮助下直接在上面编写了上面的代码,因此我有可能错过了一些东西,但是总的来说,这是它应该如何工作的想法。如果某事不起作用,我将非常高兴为您提供进一步的帮助:)