【Unity】脚本与组件操作 C#版


前言

利用Unity创建C#脚本,可以将脚本作为作为组件挂载到游戏物体上,这样脚本组件就会出现在检视窗口,可以像其他内置组件一样方便修改。

一、创建和使用脚本

在工程窗口的某个目录中操作,右键Create->C# Script即可,要注意初始化命名,文件名要与脚本中的类名保持一致,如果修改了脚本,类名也要随之改变。

二、 初识脚本

新建的脚本都会有以下内容:

示例代码如下:

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

public class NewBehaviourScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start(){ }

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

Unity规定脚本中必须包含一个类,且继承Unity内置的MonoBehaviour类。

在Unity中,MonoBehaviour是用于创建脚本的基类,它是一个C#类,继承自UnityEngine.Object类。

MonoBehaviour提供了一系列的内置函数(如Start、Update、OnTriggerEnter等),这些函数可以在脚本中被重写和使用,用于控制游戏对象的行为和属性。它支持与Unity的生命周期函数进行交互,可以让开发者在不同的游戏阶段调用不同的函数,实现游戏对象的初始化、运行和销毁等操作。

通过继承MonoBehaviour类,开发者可以在脚本中使用Unity API,比如操作游戏对象、控制音频、动画、碰撞等效果。同时,MonoBehaviour还支持序列化,可以在Unity编辑器中直接修改脚本中的属性值,方便开发者进行调试和测试。

MonoBehaviour是Unity中的一个重要类,它提供了一系列内置函数和支持Unity API的功能,方便开发者控制游戏对象的行为和属性,实现游戏的功能和效果。

之后有两个函数:
Update函数会在每一帧被调用,可以实现用户输入、角色移动、角色行为等功能。
Start函数在物体刚刚被创建时调用,即在第一个Update之前只被调用一次。

三、用脚本控制游戏物体

把脚本拖动到游戏物体检视窗口下方的空白区域即可。

在这里插入图片描述
成功的话可以看到新添加了一个名称和类名相一致的组件。
可以使用Debug.Log("hello,world")语句进行调试,可以在Unity的控制台窗口看到输出。(类似于js中的Console.log语句)

四、变量与检视窗口

自定义脚本相当于自定义了一种新的组件,内置组件的参数可以在编辑器中进行调整,脚本也可以!

示例代码如下:

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

public class Name : MonoBehaviour
{
    public string Myname;
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("my name is " + Myname);
    }
}

在代码中定义了一个公共变量,在检视窗口的脚本组件上就可以编辑参数。
在这里插入图片描述

然后就可以在控制台看到my name is llz了!

甚至可以在游戏运行时修改,不需要反复启动和停止游戏。

五、通过组件控制游戏物体

通过检视窗口可以随时修改参数,但是通过脚本修改参数更为普遍。大多数组件参数都可以修改,例如刚体的质量、渲染器的材质,组件的开关。

5.1 访问组件

在脚本中获取一个组件,可以用内置的GetComponent函数,可以实现把一个组件保存到一个变量之中。

示例代码如下

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

public class Visit : MonoBehaviour
{
    public Rigidbody rb; //需要在函数外定义
   
    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>(); //获取刚体组件
        rb.mass = 10f;  //定义刚体质量为10kg
        rb.AddForce(Vector3.up * 10f); //施加一个向上的,大小为10N的力(只在刚创建物体时生效)
    }

    // Update is called once per frame
    void Update()
    {
        rb.AddForce(Vector3.up * 110f); //持续施加一个向上的,大小为110N的力
    }
}

首先定义刚体组件,这样rb就是该物体刚体组件的引用变量,只要是刚体组件支持的操作,可以在脚本中任意使用。

其中,定义一个数字变量为 10f,其中的“f”表示这是一个浮点数(float),而不是整数(int)。在 C# 中,如果要定义一个浮点数,需要在数字后面加上“f”,以区分整数。如果不加上“f”,编译器会默认这是一个整数。如果要定义一个整数变量,可以这样写:int myInt = 10;

以及为什么是10kg而不是10g,是因为Unity 中的物理系统是基于米-千克-秒(MKS)单位的,所以 Mass 属性的值应该是千克(kg)而不是克(g)

对于一个物体能挂多少脚本并没有限制。

脚本组件也可以用GetComponent获得,例如获取名为Myname.cs的组件,可以写为GetComponent<Myname>();

六、访问其他游戏物体

一个脚本不仅可以对当前挂载的物体进行操作,还可以引用其他物体。

6.1 用变量引用游戏物体

在脚本中添加 public GameObject变量,不需要设置初始值。

示例代码如下:

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

public class Enemy : MonoBehaviour
{
    public GameObject player;//定义游戏物体
    void Start()
    {
        transform.position = player.transform.position - Vector3.forward * 10f;
        //读取player的位置,并设置本物体的位置在它后方
    }
}

这样检视窗口就会出现其他游戏物体的变量,只需要将相应物体拖动到变量的文本框里即可。如下图所示:
在这里插入图片描述
另外,引用其他物体时,变量类型不仅可以是GameObject或者一个组件,也可以将游戏物体拖到这个变量上,只要被拖拽的物体确实有这个组件就可以。

(不要用面向对象的方式去理解)组件和物体可以是对应的关系。

6.2 查找子物体

当管理一系列同类型的游戏物体时,有时候需要在脚本中用数组或者容器的方式来管理它们。

可以将一群敌人都放在一个物体之下,通过查找子物体的方法遍历所有物体。

代码如下(示例):

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

public class WaypointManager : MonoBehaviour
{
    public Transform[] waypoints;
    // Start is called before the first frame update
    void Start()
    {
        waypoints = new Transform[transform.childCount];
        int i = 0;
        //用foreach循环访问所有子物体
        foreach(Transform t in transform)
        {
            waypoints[i++] = t;
        }
    }
}

也可以用transform.Find("Gun");来查找某一物体,但是效率不好估计。

6.3 通过标签或名称查找物体

如果要查找的物体不是子物体,也可以通过特定信息来查找。例如,可以使用GameObject.Find方法通过名称查找物体。如果用标签寻找,可以用GameObject.FindWithTag方法或者GameObject.FindGameObjectsWithTag方法。

代码示例如下

	GameObject player;
    GameObject player2;
    GameObject[] enemies;
    void Start()
    {
        player = GameObject.Find("Player");
        player2 = GameObject.FindWithTag("Player");
        enemies = GameObject.FindGameObjectsWithTag("Enemy");
    }

使用标签查找时,需要给物体设置标签
在这里插入图片描述

七、常用事件函数

Unity会在特定事件发生时调用不同的函数,这些特定的函数被称为事件函数,因为是在特定事件发生时由引擎层调用的。

7.1 基本更新函数

在每一帧刚开始的时候(渲染之前),对物体的位置、状态或行为进行计算,然后渲染出来。Update函数在每一帧刚刚开始时被调用。

示例代码如下:

	void Update()
    {
        float distance = speed * Time.deltaTime * Input.GetAxis("Horizontal");
        transform.Translate(Vector3.right * distance);
    }

物理引擎也会按照物理帧更新,机制与Update类似,但是更新时机不同,要尽可能在FixedUpdate中进行物理相关的操作。

示例代码如下:

    private void FixedUpdate()
    {
        Vector3 force = transform.forward * driveForce * Input.GetAxis("Vertical");
        rigidbody.AddForce(force);
    }

有时候不仅需要在每帧之前操作物体,还需要在所有的Update函数之后再进行一些操作,例如更新相机位置等。

示例代码如下:

   	private void LateUpdate()
    {
        //在一帧的最后阶段,将摄像机转向玩家角色的位置。这样相机旋转会更加流畅
        Camera.main.transform.LookAt(target.transform);
    }

7.2 初始化函数

在每一帧之前,往往需要做一些初始化的工作,Start函数会在第一次Update等函数和物体加载出来之前被调用。
Awake函数比Start函数调用还要早,在场景加载时就会被调用。

八、时间和帧率

Update函数可以用来侦测输入或者其他事件,并作出相应的行为。但是游戏的帧率并不是一个固定的值,如果按照帧率考虑物体的移动,可以给出以下代码:

    public float diantancePerFrame;
    void Update()
    {
        transform.Translate(0, 0, diantancePerFrame);//按照帧率前进,不一定是匀速运动
        transform.Translate(0, 0, diantancePerFrame * Time.deltaTime);//匀速
    }

引入Time.deltaTime之后,可以通过每一帧移动的距离*两帧之间的时间间隔得到一个固定速率,这样就可以实现物体的匀速运动了!

九、创建和销毁物体

大部分游戏会在游戏运行中实时生成角色、宝物、子弹等,Unity中提供了Instantiate函数专门创建一个新的物体。

示例代码如下:

    public GameObject enemy;
    void Start()
    {
        //以enemy为模板,生成五个敌人
        for(int i = 0; i < 5; i++)
        {
            Instantiate(enemy);
        }
    }

可以用已经存在的物体作为模板(最常用的是使用预制体作为模板)

另外,还可以用Destory函数摧毁游戏物体或者组件。

示例代码如下:

    private void OnCollisionEnter(Collision collision)
    {//导弹发生碰撞时摧毁这枚导弹
        if (collision.gameObject.tag == "Missile")
        {
            Destroy(gameObject, 0.5f);
            //第二个参数代表0.5s后才会执行销毁动作
        }
    }

十、脚本无效化

游戏物体可以标记为不被激活的状态,相当于临时在场景中删除,可以使用脚本实现无效化,也可以勾选检视窗口的激活复选框。
在这里插入图片描述
当一个父物体被标记为不被激活时,会覆盖所有子物体的激活状态。

附录

事件说明
Update每一帧被调用
LateUpdate每一帧游戏逻辑之后,渲染之前调用
FixedUpdate固定更新,用于物理系统
Awake当一个脚本实例被载入时调用
Start在Update函数第一次调用之前调用
Reset重置为默认值时调用
OnMouseEnter/Over/Exit/Down/Up/Drag当鼠标光标进入/悬浮/移出/单击/释放单击/拖拽GUI元素或碰撞体中时调用
OnTriggerEnter/Exit/Stay当碰撞体进入/脱离/接触触发器时调用
OnCollisionEnter/Exit/Stay当此Collider/Rigidbody触发/停止触发/持续触发另一个时被调用
OnEnable/Disable/Destoroy对象变为激活/非激活/MonoBehavior被摧毁状态时可使用
OnGUI渲染和处理GUI事件时调用,每帧调用一次

总结

以上就是这篇文章的主要内容,本文简单介绍了C#脚本的创建和使用、用脚本控制游戏物体等内容,同时介绍了一些常用事件函数。

如果有错误或者补充可以在留言处提出~

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

404Gloria

你的鼓励是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值