Unity游戏开发笔记(二)

C#中关于as关键字的使用

在C#中提供的很好的类型转换方式总结为:
Object => 已知引用类型——使用as操作符完成;
Object => 已知值类型——先使用is操作符来进行判断,再用类型强转换方式进行转换;
已知引用类型之间转换——首先需要相应类型提供转换函数,再用类型强转换方式进行转换;
已知值类型之间转换——最好使用系统提供的Conver类所涉及的静态方法。

在调用Instantiate()方法使用prefab创建对象时,接收Instantiate()方法返回值的变量类型必须和声明prefab变量的类型一致,否则接收变量的值会为null.

比如说,我在脚本里面定义:

public GameObject myPrefab;

那么在使用这个myPrefab做Instantiate()的时候,接收返回值变量的类型也必须是GameObject,如下:

GameObject newObject = Instantiate(myPrefab) as GameObject;

注意Instantiate()后面的as也要是GameObject。

又比如我们的prefab类型是我们自定义的UserObject

public UserObject prefab;

那么在使用Instantiate()时我们需要写成:

UserObject newObject = Instantiate(myPrefab) as UserObject;

比较容易犯的一个错误是我们声明的类型是:

public GameObject myPrefab;

在Instantiate()返回值却想要用Transform,如下:

Transform newObject = Instantiate(myPrefab) as Transform;

这个时候就会出现newObject为null的问题。

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

public class TankAttack : MonoBehaviour
{
    public GameObject shellPrefab; //子弹预制体
    public KeyCode fireKey = KeyCode.Space; //发射键,默认空格space键
    private Transform firePosition; //子弹发射位置
    public float shellSpeed = 15f; //子弹速度

    // Start is called before the first frame update
    void Start()
    {
        firePosition = transform.Find("FirePosition");
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(fireKey))
        {
            //GameObject.Instantiate为实例化元素,3个参数分别为 要实例化的预制体,实例化的位置,实例化的方向
            GameObject go = GameObject.Instantiate(shellPrefab, firePosition.position, firePosition.rotation) as GameObject; //用GameObject类型接收,所以用as进行类型转换
            //子弹的飞行速度和方向
            go.GetComponent<Rigidbody>().velocity = go.transform.forward * shellSpeed;
        }
    }
}

OnTriggerEnter()与OnTriggerStay()

1.触发条件

  • 双方必须有一方设置Is Trigger为Enable。
  • 双方必须有一方设置有Rigidbody刚体组件。

2.代码调试 

private void OnTriggerEnter(Collider other)
{
    Debug.Log(message:other.name);//获取gameobject的名字
    other.transform.position+= new Vector3(0, 0.44f, 0);//gameobject的y坐标发生变化。
}

3.触发分主动与被动

OnTriggerEnter(Collider other)与OntriggerStay(Collider other)的形参为被动的gameobject。
 假设:ObjectA为设置为Is Trigger的一方,
      ObjectB为接触的另一方。
  情况1:当ObjectA主动接触ObjectB,形参other为ObjectB.
  情况2:当ObjectB主动接触ObjectA,形参other为ObjectA。

Play On Awake:实例化后自动播放

子弹碰撞检测

创建Shell脚本,用于炮弹的碰撞事件

脚本挂载在Shell预制体上

Shell预制体的 Capsule Collider 属性的 Is Trigger 设置为开启状态,这样会与其它网格发生碰撞(碰撞后如不发生事件则直接穿透)

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

public class Shell : MonoBehaviour
{

    public GameObject ShellExplosionPrefab; //子弹爆炸效果的预制体
    // 脚本写完后,把做好的ShellExplosion预制体,挂在Shell预制体Shell脚本的ShellExplosionPrefab中

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    // 子弹发生碰撞时效果
    private void OnTriggerEnter(Collider other)
    {
        // 实例化爆炸效果,当前位置,当前方向
        GameObject.Instantiate(ShellExplosionPrefab, transform.position, transform.rotation);
        // 把自身销毁
        GameObject.Destroy(this.gameObject);
    }
}

爆炸效果完成后删除

创建脚本DestroyForTime,挂在预制体ShellExplosion上

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

public class DestroyForTime : MonoBehaviour
{

    public float time = 1.5f; // 生存时间(设置动画时长)

    // Start is called before the first frame update
    void Start()
    {
        Destroy(this.gameObject, time); //预制体被实例化后,在time时间长度后销毁自身
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

控制炮弹对坦克的伤害

先新增一个Tag:Tank,然后给Tank对象添加Tag属性为Tank,这样当炸弹碰撞的物体Tag属性是Tank时就是遇坦克发生碰撞,然后修改相关的属性等

Shell脚本修改为:

public class Shell : MonoBehaviour
{

    public GameObject ShellExplosionPrefab; //子弹爆炸效果的预制体

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    // 子弹发生碰撞时效果
    private void OnTriggerEnter(Collider other)
    {
        // 实例化爆炸效果,当前位置,当前方向
        GameObject.Instantiate(ShellExplosionPrefab, transform.position, transform.rotation);
        // 把自身销毁
        GameObject.Destroy(this.gameObject);
        // 子弹碰撞的物体tag为Tank,说明是坦克
        if (other.gameObject.CompareTag("Tank"))
        {
            other.gameObject.SendMessage("TankDamage"); // 调用碰撞到的对象的TankDamage()方法
        }
    }
}

新增一个TankHealth脚本,为坦克血量,挂载在坦克预制体上,所有坦克都是相同的血量属性

public class TankHealth : MonoBehaviour
{

    public int hp = 100; //坦克血量
    public GameObject tankExplosion; //坦克阵亡效果

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    // 坦克受到伤害
    void TankDamage()
    {
        if (hp <= 0) return; // 已阵亡
        hp -= Random.Range(5, 15); //每次受到伤害损失5~15一个随机的伤害
        if (hp <= 0)
        {
            // 受到伤害后阵亡,播放坦克阵亡动画 TankExplosion
            // TankExplosion 的 Play On Awake 勾选上,被实例化后自动播放
            GameObject.Instantiate(tankExplosion, transform.position + Vector3.up, transform.rotation); // 为了效果,爆炸动画向上移动1米 + Vector3.up
            GameObject.Destroy(this.gameObject); // 销毁掉坦克自身
        }
    }
}
发布了97 篇原创文章 · 获赞 21 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/sun124608666/article/details/102811074