Unity部分

Unity API

说明:以下代码均属于伪代码,需要具体要求具体操作实现。

游戏路径

void Start()
{
    //游戏数据路径,只读,加密压缩
    Debug.Log(UnityEngine.Application.dataPath);
    //游戏持久化路径
    Debug.Log(UnityEngine.Application.persistentDataPath);
    //临时文件夹
    Debug.Log(UnityEngine.Application.temporaryCachePath);
    //streamingpath
    Debug.Log(UnityEngine.Application.streamingAssetsPath);
    //控制是否在后台运行
    Debug.Log(UnityEngine.Application.runInBackground);
    //打开链接
    UnityEngine.Application.OpenURL("#")
    //退出游戏
    UnityEngine.Application.Quit();
}

游戏时间操作

void Start()
{
    Debug.Log(Time.time);//总时间
    Debug.Log(Time.timeScale);//时间缩放值
    Debug.Log(Time.fixedDeltaTime);//固定间隔时间
    Debug.Log(Time.deltaTime);//前后两帧所用的游戏时间
}


void Update()
{
    timer += Time.deltaTime;
    if (timer > 3 && checking) 
    {
        Debug.Log("timer大于3s了");
        checking = false;
    }
}

向量与四元数

void Start()
{
    Vector3 V = new Vector3(1,1,1);
    Quaternion quaternion = Quaternion.identity;//初始化
    quaternion = Quaternion.Euler(V);
    quaternion = Quaternion.LookRotation(new Vector3(0,0,0));
    V = quaternion.eulerAngles;
}

场景切换

首先通过Build settings拖入场景

image-20250207214656668

然后可使用索引或名称进行转换,主要场景类操作如下:

void Start()
{
    //场景类
    
    //获取当前场景
    Scene scene = SceneManager.GetActiveScene();
    //scene.name---场景名称
    Debug.Log(scene.name);
    //场景是否加载
    Debug.Log(scene.isLoaded);
    //场景路径
    Debug.Log(scene.path);
    //场景索引
    Debug.Log(scene.buildIndex);
    //场景中对象数组
    GameObject[] gots = scene.GetRootGameObjects();
    Debug.Log(gots.Length);
    
    //场景管理类
    
    //场景跳转
    SceneManager.LoadScene("New Scene");
    //场景切换(替换先前的场景),原场景消失,留下New Scene
    SceneManager.LoadScene("New Scene",LoadSceneMode.Single);
    //场景叠加
    SceneManager.LoadScene("New Scene",LoadSceneMode.Additive);
    //已加载的场景数量
    Debug.Log(SceneManager.sceneCount);
    //创建新场景
    Scene newScene = SceneManager.CreateScene("sceneName");
    //卸载场景
    SceneManager.UnloadSceneAsync("newScene");
    //异步加载
    SceneManager.LoadSceneAsync("New Scene");
}

异步加载

//定义AsyncOperation类变量(异步)
AsyncOperation operation;
void Start()
{
    StartCoroutine(loadScene());
}
//携程异步方法加载场景,IEnumerator为多线程方法,有返回值
IEnumerator loadScene()
{
    operation = SceneManager.LoadSceneAsync("New Scene");
    //场景加载完后不自动跳转
    operation.allowSceneActivation = false;
    yield return operation;
}
void Update()
{
    Debug.Log(operation.progress);
}

Transform

image-20250209223937330

游戏组件之间的父子关系由transform组件链接,控制物体间的父子级。

一般认为Z轴向前,X轴向右。

常用数据和方法如下:

void Start()
{
    //获取位置(两种方法),position为世界位置,localPosition为相对父物体的位置
    Debug.Log(transform.position);
    Debug.Log(transform.localPosition);
    //获取选择(四元数)性质与上类似
    Debug.Log(transform.rotation);
    Debug.Log(transform.localRotation);
    Debug.Log(transform.eulerAngles);
    Debug.Log(transform.localEulerAngles);
    //获取缩放
    Debug.Log(transform.localScale);
    //向量
    Debug.Log(transform.forward);
    //...三种方向(前,右,上)

    //父子关系
    //获取父物体
    Debug.Log(transform.parent.gameObject);
    //获取子物体个数
    Debug.Log(transform.childCount);
    //解除与子物体的父子关系(所有)
    transform.DetachChildren();
    //获取子物体
    int n = 0;
    Transform trans = transform.Find("ChildObject");
    trans = transform.GetChild(n);
    //判断一个物体是否另一个物体的子物体
    bool res = trans.IsChildOf(transform);
    //设置父物体(假设这两原来不是父子关系)
    trans.SetParent(transform);
}

void Update()
{
    //一直看向(0,0,0)点
    transform.LookAt(Vector3.zero);
    //旋转
    float angle = 1;
    transform.Rotate(Vector3.up,angle);
    //绕某物体旋转(第一个参数是中心点,第二个参数是旋转方向,第三个参数为角度)
    transform.RotateAround(Vector3.zero,Vector3.up, angle);
    //移动
    transform.Translate(Vector3.forward*0.1f);
}

键鼠操作

1.鼠标操作

void Update()
{
    //鼠标点击(0-左键,1-右键,2-中键)
    //按下鼠标
    if (Input.GetMouseButtonDown(0))
    {
        Debug.Log("鼠标左键");
    }
    //持续按住鼠标
    if (Input.GetMouseButton(1))
    {
        Debug.Log("鼠标右键");
    }
    //鼠标抬起
    if (Input.GetMouseButtonUp(2))
    {
        Debug.Log("鼠标中间");
    }
}

2.键盘操作(“KeyCode.键”是枚举值)

void Update()
{
    //按下键盘按键
    if (Input.GetKeyDown(KeyCode.A))
    {
        Debug.Log("A");
    }

    //按住键盘按键
    if (Input.GetKey(KeyCode.B))
    {
        Debug.Log("B");
    }

    //松开键盘按键
    if (Input.GetKeyUp(KeyCode.C))
    {
        Debug.Log("C");
    }
}

多平台操作兼容方法---虚拟轴(轴Axis)

1.简要描述

image-20250209234623777

2.控制地点

image-20250209235130127

3.方法:

void Update()
{
    //获取轴
    float hz = Input.GetAxis("Horizontal");
    float vt = Input.GetAxis("Vertical");
    
    //虚拟键盘(同样三种方法down,up,'none')
    if (Input.GetButtonDown("Jump"))
    {
        Debug.Log("space");
    }
}

相机

深度较高的相机可改为仅深度,优先显示,多个相机依照深度的顺序可以叠加显示效果。

相机的目标纹理可用新建渲染器纹理来获取,其效果类似于镜子。

音频

音频资源组件的样子如下:

image-20250213182940671

基本代码

public AudioClip Se;     //声明音频片段变量
private AudioSource AudioPlayer;    //声明声音资源变量
public bool isLoop;     //是否循环(布尔值)
public float audioVolume;
void Start()
{
    //获取组件(十分重要的方法)
    AudioPlayer = GetComponent<AudioSource>();
    //获取音频片段
    AudioPlayer.clip = Se;
    //循环
    AudioPlayer.loop = isLoop;
    //音量
    AudioPlayer.volume = audioVolume;
    //播放音频
    AudioPlayer.Play();
}

void Update()
{
    //按键控制
    if (Input.GetKeyDown(KeyCode.P))
    {
        //当前是否正在播放声音 .isPlaying为布尔值
        if (AudioPlayer.isPlaying)
        {
            //暂停播放
            AudioPlayer.Pause();
            //停止播放
            AudioPlayer.Stop();
        }
        else
        {
            //继续播放
            AudioPlayer.UnPause();
            //开始播放
            AudioPlayer.Play();
        }
    }

    if (Input.GetMouseButtonDown(1))
    {
        //短音效播放
        AudioPlayer.PlayOneShot(Se);
    }
}

视频播放

  1. 右键创建渲染器纹理(Render Texture)
  2. 给相应的对象添加组件Video Player
  3. 选择渲染器纹理,然后添加渲染器纹理

方法:

private VideoPlayer player;//声明播放器
void Start()
{
    player = GetComponent<VideoPlayer>();
}

void Update()
{
    if (Input.GetKeyDown(KeyCode.I))
    {
        if (player.isPlaying)
        {
            player.Pause();
        }
        else
        {
            player.Play();
        }
    }
}

简单角色移动

1.使用简单的虚拟轴进行移动

private CharacterController player;
public float speed;
void Start()
{
    player = GetComponent<CharacterController>();
}

void Update()
{
    //水平轴
    float horizontal = Input.GetAxis("Horizontal");
    //竖直轴
    float vertical = Input.GetAxis("Vertical");
    //方向向量
    Vector3 dir = new Vector3(horizontal, 0, vertical);
    //朝该方向移动
    player.SimpleMove(dir * speed);
}

物理

1.刚体

(角阻力为旋转阻力)

对于高速运动的物体可使用碰撞检测为动态连续,而其撞击体使用连续。还有连续检测也可使用。

2.检测碰撞

两个物体有碰撞发生的前提如下:

1.两者都要有碰撞(Collider)组件

2.二者其一有刚体组件

image-20250214201640497

Constraints---Freeze Rotation防止因物理效果造成的旋转;Freeze Position防止因撞击造成位置的移动

Is Kinematic(是否遵循运动学),运动学刚体是指不受外力或碰撞影响的刚体。它不会受到物理引擎的模拟,而是通过直接设置位置和旋转来控制其运动。这意味着你可以手动控制运动学刚体的位置和旋转,而不会受到物理引擎的影响。

此处为OnCollision...碰撞方法:

//监听发生碰撞
private void OnCollisionEnter(Collision other)
{
    //创建物体(预设体,位置,旋转角度(Quaternion.identity为不旋转))
    Instantiate(Prefab, transform.position, Quaternion.identity);
    //销毁自身
    Destroy(gameObject);
}
//持续碰撞
private void OnCollisionStay(Collision other)
{
    
}
//结束碰撞
private void OnCollisionExit(Collision other)
{
    
}

3.Collider碰撞器(触发)

image-20250214202606877

Is Trigger选项为触发器的勾选,勾选后物理碰撞体积消失,但是存在的碰撞区域仍然存在

此处为触发器方法(函数用法与碰撞类似):

private void OnTriggerEnter(Collider other)
{

}

private void OnTriggerStay(Collider other)
{
    
}

private void OnTriggerExit(Collider other)
{
    
}
对比 Collision(碰撞) Trigger(触发)
使用时间 两者相同 两者相同
参数 Collision collision Collider other

重要的类 - GameObject(引用)

Unity 的 GameObject 类用于表示任何可以存在于场景中的事物。

此页面涉及使用 Unity GameObject 类进行的脚本编写。若要了解如何在 Unity 编辑器的场景和层级视图中使用 GameObject,请参阅用户手册的 GameObject 部分。有关 GameObject 类的每个成员的详尽参考,请参阅 GameObject 脚本参考

GameObject 是 Unity 中场景的构建块,可充当用于确定 GameObject 外观以及 GameObject 作用的功能组件的容器。

在脚本编写中,GameObject 类提供了允许在代码中使用的方法的集合,包括查找、建立连接和在 GameObject 之间发送消息,以及添加或移除附加到 GameObject 的组件和设置与其在场景中的状态相关的值。

1.场景状态属性

可以通过脚本修改一些与场景中的 GameObject 状态相关的属性。在编辑器中选择了 GameObject 时,这些属性通常与 Inspector 顶部附近显示的控件对应。

它们不与任何特定组件相关,会显示在 GameObject 的 Inspector 顶部(组件列表上方)。

在 Inspector 中查看的典型 GameObject。在此例中是方向光。场景状态属性具有红色轮廓。在 Inspector 中查看的典型 GameObject。在此例中是方向光。场景状态属性具有红色轮廓。

所有 GameObject 都在 Inspector 顶部共享一组与场景中 GameObject 状态相关的控件,这些控件可以通过 GameObject 的脚本 API 进行控制。

如果要快速列出 GameObject 类的所有可用 API,请参阅 GameObject 脚本参考

2.活动状态

GameObject 的活动状态GameObject 的活动状态

GameObject 在默认情况下处于活动状态,但可以停用,这会关闭附加到 GameObject 的所有组件。这通常意味着它将变得不可见,不会接收任何正常回调或事件,例如 UpdateFixedUpdate

GameObject 的活动状态由 GameObject 名称左侧的复选框表示。可以使用 GameObject.SetActive 控制此状态。

还可以使用 GameObject.activeSelf 读取当前活动状态,使用 GameObject.activeInHierarchy 读取 GameObject 是否在场景中实际处于活动状态。这两者中的后者是必要的,因为 GameObject 是否实际处于活动状态取决于其自身的活动状态,以及其所有父项的活动状态。如果其所有父项都不处于活动状态,则尽管它自己设置为活动状态,它也不会处于活动状态。

3.静态状态

GameObject 的静态状态GameObject 的静态状态

Unity 的一些系统(如全局光照、遮挡、批处理、导航和反射探针)依赖于 GameObject 的静态状态。可以使用 GameObjectUtility.SetStaticEditorFlags 控制哪些 Unity 系统将 GameObject 视为静态。有关详细信息,请阅读此处的静态 GameObject

4.标签和层

GameObject 的静态状态GameObject 的静态状态

标签 (Tag)提供一种在场景中标记和识别 GameObject 类型的方式,而层 (Layer)提供一种类似但不同的方式在某些内置操作(例如渲染物理碰撞)中包括或排除 GameObject 组。

有关如何在编辑器中使用标签和层的更多信息,请参阅关于标签的主要用户手册页面。

可以使用 GameObject.tagGameObject.layer 属性通过脚本修改标签和层值。还可以使用 CompareTag 方法高效地检查 GameObject 的标签,该方法包括验证标签是否存在,不会导致任何内存分配。

5.添加和移除组件

可以在运行时添加或移除组件,这对于以程序化方式创建 GameObject 或修改 GameObject 行为方式可能非常有用。请注意,还可以通过脚本启用或禁用脚本组件和某些类型的内置组件,而不销毁它们。

在运行时添加组件的最佳方法是使用 AddComponent(在显示的尖括号中指定组件类型)。若要移除组件,必须对组件本身使用 Object.Destroy 方法。

6.访问组件

最简单的情况是 GameObject 上的脚本需要访问附加到同一个 GameObject 的另一个组件(请记住,附加到 GameObject 的其他脚本本身也是组件)。为此,第一步是获取对要使用的组件实例的引用。这通过 GetComponent 方法来完成。通常要将组件对象分配给变量,而此操作使用以下代码实现。在此示例中,脚本获取对同一个 GameObject 上的 Rigidbody 组件的引用:

void Start ()
{
    Rigidbody rb = GetComponent<Rigidbody>();
}

获得对组件实例的引用后,可以像在 Inspector 中一样设置其属性的值:

void Start ()
{
    Rigidbody rb = GetComponent<Rigidbody>();

    // 更改对象的刚体质量。
    rb.mass = 10f;
}

还可以对组件引用调用方法,例如:

void Start ()
{
    Rigidbody rb = GetComponent<Rigidbody>();

    // 向刚体添加作用力。
    rb.AddForce(Vector3.up * 10f);
}

注意:可以将多个自定义脚本附加到同一个 GameObject。如果需要从一个脚本访问另一个脚本,可以像往常一样使用 GetComponent,只需使用脚本类的名称(或文件名)来指定所需的组件类型。

如果尝试检索尚未实际添加到 GameObject 的组件类型,则 GetComponent 将返回 null;如果尝试更改 null 对象上的任何值,将在运行时出现 null 引用错误。

7.访问其他 GameObject 上的组件

尽管它们有时会独立运行,但脚本通常会跟踪其他 GameObject 或者(更常见的情况)其他 GameObject 上的组件。例如,在烹饪游戏中,厨师可能需要知道炉子的位置。Unity 提供了许多不同方法来检索其他对象,每种方法都适合特定情况。

在 Inspector 中使用变量链接到 GameObject

查找相关游戏对象的最直接方法是向脚本添加公共的游戏对象变量:

public class Chef : MonoBehaviour
{
    public GameObject stove;

    // 其他变量和函数...
}

此变量在 Inspector 中会显示为 GameObject 字段

现在可以将对象从场景或 Hierarchy 面板拖到此变量上,对其进行分配。

将预制件从 Project 窗口拖动到 Inspector 窗口的 GameObject 字段中将预制件从 Project 窗口拖动到 Inspector 窗口的 GameObject 字段中

GetComponent 函数和组件访问变量与其他任何变量一样可用于此对象,因此可以使用如下代码:

public class Chef : MonoBehaviour {

    public GameObject stove;

    void Start() {
        // 在 stove 前方 2 个单位处启动 chef。
        transform.position = stove.transform.position + Vector3.forward * 2f;
    }
}

此外,如果在脚本中声明组件类型的公共变量,则可以拖动已附加该组件的任何游戏对象。这样可以直接访问组件而不是游戏对象本身。

public Transform playerTransform; 

在处理具有永久连接的单个对象时,将对象与变量链接在一起是最有用的方法。可以使用数组变量来链接同一类型的多个对象,但仍然必须在 Unity Editor 中(而不是在运行时)进行连接。在运行时定位对象通常很方便,因此 Unity 提供了两种基本方法来执行此操作,如下所述。

查找子 GameObject

有时,游戏场景会使用许多相同类型的 GameObject,例如可收集对象、路径点和障碍物。这些游戏对象可能需要由监督或响应它们的特定脚本来跟踪(例如,寻路脚本可能需要使用所有路径点)。可以使用变量来链接这些游戏对象,但是如果必须将每个新路标拖动到脚本中的变量,会使设计过程变得繁琐。同样,如果删除一个路标,则必须删除对丢失游戏对象的变量引用,这很麻烦。此类情况下,可使一组游戏对象成为一个父游戏对象的所有子对象,这种管理多个游戏对象的方式通常会更好。可以使用父游戏对象的变换组件来检索子游戏对象(因为所有游戏对象都具有隐式变换):

using UnityEngine;

public class WaypointManager : MonoBehaviour {
    public Transform[] waypoints;

    void Start()
    {
        waypoints = new Transform[transform.childCount];
        int i = 0;

        foreach (Transform t in transform)
        {
            waypoints[i++] = t;
        }
    }
}

还可以使用 Transform.Find 方法按名称查找特定子对象: transform.Find("Frying Pan");

当 GameObject 具有可以在游戏运行过程中添加和移除的子 GameObject 时,这种功能可能很有用。可以在游戏运行过程中拾取和放下的工具或器皿就是这方面的一个很好例子。

8.发送和广播消息

在编辑项目时,可以在 Inspector 中设置 GameObject 之间的引用。但是,有时无法提前设置这些内容(例如,在游戏中查找与角色最近的项目,或引用在场景加载后实例化的 GameObject)。在这些情况下,可以在运行时查找引用并在 GameObject 之间发送消息。

通过 BroadcastMessage 可以发送对命名方法的调用,而无需具体说明应实现该方法的位置。可以使用它对特定 GameObject 或其任何子项上的每个 MonoBehaviour 调用命名方法。可以选择强制要求必须至少有一个接收方(否则会生成错误)。

SendMessage 更具体一些,只对 GameObject 本身(而不对其子项)发送对命名方法的调用。

SendMessageUpwards 是类似方法,但是对 GameObject 及其所有_父项_ 发送对命名方法的调用。

9.按名称或标签查找 GameObject

只要有某种信息可以识别游戏对象,就可以在场景层级视图中的任何位置找到该游戏对象。可使用 GameObject.Find 函数按名称检索各个对象:

GameObject player;

void Start()
{
    player = GameObject.Find("MainHeroCharacter");
}

还可以使用 GameObject.FindWithTagGameObject.FindGameObjectsWithTag 方法按标签查找对象或者对象集合。

例如,在一个烹饪游戏中有一个厨师角色,厨房中有多个炉子(每个都标记为 “Stove”):

GameObject chef;
GameObject[] stoves;

void Start()
{
    chef = GameObject.FindWithTag("Chef");
    stoves = GameObject.FindGameObjectsWithTag("Stove");
}

10.创建和销毁 GameObject

可以在项目运行期间创建和销毁 GameObject。在 Unity 中,可以使用 Instantiate 方法创建 GameObject。该方法可以生成现有对象的新副本。

有关如何实例化 GameObject 的完整说明和示例,请参阅在运行时实例化预制件

还有一个 Destroy 方法,该方法将在帧更新完成后或(可选)短时间延迟后销毁对象:

void OnCollisionEnter(Collision otherObj) {
    if (otherObj.gameObject.tag == "Garbage can") {
        Destroy(gameObject, 0.5f);
    }
}

请注意,Destroy 函数可以在不影响游戏对象本身的情况下销毁个别组件。一个常见错误编写以下代码,假设它会销毁脚本所附加到的 GameObject

 Destroy(this);

…然而,由于 “this” 表示脚本而不是 GameObject,因此它实际上只会销毁调用它的脚本组件,而留下移除了脚本组件的 GameObject。

11.原始对象

GameObject 类为 Unity GameObject 菜单中的可用选项提供了基于脚本的替代方案,可用于创建原始对象

若要创建 Unity 内置原始对象的实例,请使用 GameObject.CreatePrimitive,它会实例化所指定的类型的原始对象。可用的原始类型有 SphereCapsuleCylinderCubePlaneQuad

Unity GameObject 菜单中提供的原始形状

关节

1.Hinge Joint(铰链关节)

image-20250214210202813

Anchor(锚),即轴所在的直线的位置(为比例)。

Axis(轴),也就是朝向。

2.Spring Joint(弹簧连接体)

image-20250214211656673

Connected Body需要链接有刚体的对象。

3.Fixed Joint(固定连接体)

image-20250214211804950

物理材质

image-20250217203253891

Material选项控制物理材质类型,此材质类型为新建中的物理材质(Phyiscal Material)

使用材质需要给对象两者都加上物理材质

物理材质的几个参数不难理解

射线检测

射线必须要涉及到有碰撞体的物体,否则无效。

private float distance;
void Start()
{
    // 方式1
     Ray ray = new Ray(Vector3.zero, Vector3.up);
}

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        //方式2(获得鼠标位置)
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        //声明碰撞信息类
        RaycastHit hit;
        //碰撞检测
        bool res = Physics.Raycast(ray, out hit);
        //当有碰撞的时候hit就有了内容
        if (res)
        {
            Debug.Log("Have hitted.");
            transform.position = hit.point;
        }
        //多检测(第二个参数表示距离,第三个参数表示检测图层)
        //1左移10位 第1个图层对应的其实就是二进制的10 也就是1<<1 第十个就是1<<10
        RaycastHit[] hits = Physics.RaycastAll(ray, distance, 1 << 10);
    }
}
posted @ 2025-10-13 15:56  cuupe  阅读(5)  评论(0)    收藏  举报