当前位置:   article > 正文

C# in Unity官方教程笔记_c# unity 入门

c# unity 入门


前言

C# Unity入门


一、脚本

物体的脚本定义物体的动作或属性。脚本打钩才运行,不打钩不运行。
创建脚本的方式:
1.在项目栏创建脚本后拖拽到物体上
2.在Inspector中给游戏物体添加组件

二、函数

Start()函数在物体进入场景后调用,Debug.Log()可以获取任意变量的值并打印在控制台上中

三、作用域和访问修饰符

成员(变量和函数)默认为private,除非特定声明为public才能在类外访问。public成员会在Inspector中显示,可以在运行时修改参数进行演示,退出运行状态时不在Inspector中保存。一个变量在类中且在函数外初始化,则他会被Inspector中的值覆盖,若在Start()/Awake()中赋值则他们出现在Inspector中设置过变量之后,不会被Inspector中的值覆盖。

四、Awake()和Start()函数

Awake方法是Unity中的一个特殊方法,当对象被加载到场景中时调用。
Start方法是Unity中的另一个特殊方法,当对象在场景中开始其第一帧之前调用。
在生命周期中都只运行一次。但Start()只能在启动脚本组件时(打钩)被调用。游戏中遇到敌军,Awake配备弹药,启动脚本组件时使用Start在定义时间内射击

五、Update()和FixedUpdate()函数

Update():在每个使用它的脚本中每帧调用一次。基本上只要需要变化或调整都要用Update来实现:非物理对象的移动,简单的计时器,输入检测等等。不是按固定时间调用的。
FixedUpdate():按固定时间调用,时间间隔相同。任何影响刚体(即物理对象)的动作都应该使用这个函数

六、MonoBehaviour脚本编写向导

将光标放在需要插入函数的位置,按Ctrl+Shift+M启动向导,可以选择想创建的函数
一个类继承自Unity的MonoBehaviour类,这意味着它可以附加到Unity的游戏对象上

七、Vector向量

2D:(x,y)相对于原点的坐标,
点积函数 Vector3.Dot() :点积为0,则两向量垂直
飞行模拟器:场景向上向量和飞机向前向量的关系,点积为0则飞机阻力最小,点积正值增大,则飞机爬升,可以增加阻力,点积负值增大,则飞机俯冲
叉积函数 Vector3.Cross() :计算出一个向量,这个向量与两参数向量垂直
计算出坦克围绕哪个轴转动,两参数向量确定一个平面,围绕垂直于这个平面的轴转动

八、启动和禁用组件

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

public class EnableComponents : MonoBehaviour
{
    private Light myLight;

    // Start is called before the first frame update
    void Start()
    {
        myLight = GetComponent<Light>();
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyUp(KeyCode.Space)) 
        {//用.enabled标记来禁用组件
            myLight.enabled = !myLight.enabled;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

九、激活游戏组件

gameObject.SetActive(false);
当父对象被停用,则子对象也不会在场景中出现,但子对象是活跃状态,子对象在层级结构中是停用状态。
myObject.activeSelf myObject.activeInHierarchy

十、Translate Rotate

平移 旋转
在Unity中,Transform组件是非常重要的一个组件,它存在于所有的GameObject游戏对象中,并且控制着对象的位置、旋转和缩放。
在Unity中,游戏循环是按照每一帧来进行更新和渲染的。每一帧代表了游戏画面的静态图像。Update函数是Unity的默认函数之一,它在每一帧渲染之前被调用,因此它非常适合用于更新游戏对象的状态和执行逻辑。

当Update函数被调用时,Time.deltaTime属性就被更新了。它存储了上一帧和当前帧之间的时间间隔。我们可以使用以下方式获得它:

float deltaTime = Time.deltaTime;
接下来,我们可以将deltaTime与其他数值(例如速度、加速度等)相乘,以控制游戏对象的运动或计算其他基于时间的效果。这是一个示例:

public float speed = 5.0f;
 
void Update()
{
    float deltaTime = Time.deltaTime;
    
    // 根据deltaTime来移动游戏对象
    transform.Translate(Vector3.forward * speed * deltaTime);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在上述示例中,我们使用deltaTime将速度和位移向量(Vector3.forward)相乘,以计算物体的移动距离。这样,我们就可以确保在不同帧率下,物体以相同的速度移动。

需要注意的是,如果在每一帧中使用固定的数值而不乘以deltaTime,游戏对象的运动速度将会受到帧率的影响。在高帧率下,物体会以较快的速度移动,在低帧率下,物体会以较慢的速度移动。为了避免这种情况,我们使用Time.deltaTime来根据每帧的持续时间来调整移动距离,从而实现平滑的动画和运动效果。

using UnityEngine;
using System.Collections;

public class TransformFunctions : MonoBehaviour
{
    public float moveSpeed = 10f;
    public float turnSpeed = 50f;
    
    
    void Update ()
    {
        if(Input.GetKey(KeyCode.UpArrow))
            transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
        
        if(Input.GetKey(KeyCode.DownArrow))
            transform.Translate(-Vector3.forward * moveSpeed * Time.deltaTime);
        
        if(Input.GetKey(KeyCode.LeftArrow))
            transform.Rotate(Vector3.up, -turnSpeed * Time.deltaTime);
        
        if(Input.GetKey(KeyCode.RightArrow))
            transform.Rotate(Vector3.up, turnSpeed * Time.deltaTime);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

十一、LookAt

可用于将游戏对象的正面指向世界中的另一个transform
可以让摄像机对准某一物体,跟随他的运动

using UnityEngine;
using System.Collections;

public class CameraLookAt : MonoBehaviour
{
    public Transform target;
    
    void Update ()
    {
        transform.LookAt(target);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

十二、Destroy ()

销毁游戏对象或组件(退出运行状态还有,只是在运行界面里销毁)
延时三秒销毁其他游戏物体

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

public class DestroyBasic : MonoBehaviour
{
    public GameObject other;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.Space))
        {//延时3s
            Destroy(other,3f);
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

十三、Input.GetButton() Input.GetKey()

均返回Bool值
GetKey可以用KeyCode制定特定按钮
GetButton还可以用字符串表示某按键,比如Jump表示Space键,可以修改positive button修改Jump表示的键

十四、Input.GetAxis()

返回-1~1之间的浮点数,NegativeButton和PositiveButton,Gravity越大返回0点的速度越快,Sensitivity越大离开原点的速度越快,Snap当同时按NegativeButton和PositiveButton时返回0点,Dead越大盲区越大,当用操纵杆操作时不想感知操纵杆的轻微晃动,盲区越大,操纵杆需要越大的移动幅度才有效
float h=Input.GetAxis(“Horizontal”);//水平方向
float v=Input.GetAxis(“Vertical”);//垂直方向

十五、OnMouseDown()

鼠标按下时执行此函数

using UnityEngine;
using System.Collections;

public class MouseClick : MonoBehaviour
{
    void OnMouseDown ()
    {//施加一个反作用力
        rigidbody.AddForce(-transform.forward * 500f);
        rigidbody.useGravity = true;//添加了重力,所以会倒下
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

十六、GetComponent()

访问与同一个游戏对象关联的其他脚本或其他游戏对象的脚本。此函数会占用大量处理能力,因此要少用,最好在awake和start函数中调用,或仅在首次需要时调用一次
UsingOtherComponents

using UnityEngine;
using System.Collections;

public class UsingOtherComponents : MonoBehaviour
{
    public GameObject otherGameObject;//其他游戏对象
    
    
    private AnotherScript anotherScript;
    private YetAnotherScript yetAnotherScript;
    private BoxCollider boxCol;
    
    
    void Awake ()
    {//在awake中进行初始化
        anotherScript = GetComponent<AnotherScript>();//引用和同一个游戏对象关联的其它脚本
        //引用其他游戏对象关联的脚本
        yetAnotherScript = otherGameObject.GetComponent<YetAnotherScript>();
        boxCol = otherGameObject.GetComponent<BoxCollider>();
    }
    
    
    void Start ()
    {
        boxCol.size = new Vector3(3,3,3);
        //访问其他脚本的公开变量
        Debug.Log("The player's score is " + anotherScript.playerScore);
        Debug.Log("The player has died " + yetAnotherScript.numberOfPlayerDeaths + " times");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

AnotherScript

using UnityEngine;
using System.Collections;

public class AnotherScript : MonoBehaviour
{
    public int playerScore = 9001;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

YetAnotherScript

using UnityEngine;
using System.Collections;

public class YetAnotherScript : MonoBehaviour
{
    public int numberOfPlayerDeaths = 3;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在Unity游戏开发引擎中,BoxCollider 是一个组件,用于给游戏对象(GameObject)添加一个盒状(Box-shaped)的碰撞器(Collider)。碰撞器是物理模拟的一部分,用于确定游戏对象之间的碰撞和接触。
1.形状:它是一个立方体(或称为盒子),其尺寸(宽度、高度和深度)可以在Unity的Inspector窗口中设置。
2.物理交互:当与其他带有碰撞器的游戏对象接触或碰撞时,BoxCollider 会触发相关的事件或回调。
3.属性:BoxCollider 有一些可配置的属性,如Is Trigger(是否作为触发器)、Material(物理材质)等。
在Unity中,创建BoxCollider 通常很简单:只需在Inspector窗口中点击“Add Component”按钮,并从列表中选择“Box Collider”即可。然后,你可以根据需要调整其尺寸和其他属性。
在Unity中,BoxCollider.size 是一个表示盒形碰撞器(BoxCollider)大小的属性。这个属性定义了盒形碰撞器在三维空间中的尺寸,通常是一个包含三个浮点数的Vector3向量,分别对应宽度(Width)、高度(Height)和深度(Depth)。
BoxCollider.size 的值决定了盒形碰撞器在物理模拟中占据的空间大小。当其他游戏对象或碰撞器与这个盒形碰撞器发生接触或碰撞时,Unity的物理引擎会考虑这个大小来确定碰撞是否发生以及碰撞的响应。
此外,需要注意的是,BoxCollider.size 的值是以盒形碰撞器的中心点(Center)为基准的。中心点可以通过BoxCollider.center 属性来设置,它是一个Vector3向量,表示盒形碰撞器中心在世界空间中的位置。因此,在调整BoxCollider.size 的值时,需要考虑到中心点的位置,以确保盒形碰撞器能够正确地包围游戏对象并正确地响应碰撞。

十七、DeltaTime

delta只两个值之间的差,Time.deltaTime指的是两帧之间的时间,这个值通常用于处理与帧率无关的物理模拟、动画和移动,以确保在所有设备上都有一致的表现。利用这个值可以让物体匀速运动,即每秒运动同样的距离,避免由于帧率不同导致的运动不流畅
transform.position += new Vector3(speed * Time.deltaTime, 0.0f, 0.0f);//x轴运动
一个物体每帧运动同样的距离,由于帧之间的时间间隔不同,整体效果不流畅

十八、数据类型

值类型 引用类型
在这里插入图片描述

using UnityEngine;
using System.Collections;

public class DatatypeScript : MonoBehaviour 
{
    void Start () 
    {
        //值类型变量,transform.position不会改变
        Vector3 pos = transform.position;
        pos = new Vector3(0, 2, 0);
        
        //引用类型变量,transform.position会改变
        Transform tran = transform;
        tran.position = new Vector3(0, 2, 0);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

十九、类

脚本名和类名一致,面向对象编程的原则之一是一个类扮演一个职责或角色,类包含变量和方法
public 类名 对象名=new 类名();//实例化 构造函数,创建类和struct时,都要调用构造函数
构造函数可以有多个,没有返回值(连void都没有),根据调用时的参数对应相应的构造函数。构造函数可以设置默认值,限制实例化。创建构造函数,输入CTOR,再按Tab,即可插入构造函数代码片段

二十、Instantiate

克隆游戏对象,常用于克隆prefab(预配置对象,保存在项目素材中)

using UnityEngine;
using System.Collections;

public class UsingInstantiate : MonoBehaviour
{
    public Rigidbody rocketPrefab;  
    
    void Update ()
    {
        if(Input.GetButtonDown("Fire1"))
        {
            Instantiate(rocketPrefab);//prefab将在默认位置实例化,即位置0
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
using UnityEngine;
using System.Collections;

public class UsingInstantiate : MonoBehaviour
{
    public Rigidbody rocketPrefab;
    public Transform barrelEnd;//可以在Inspector中指定对象
    void Update ()
    {
        if(Input.GetButtonDown("Fire1"))
        {
            Instantiate(rocketPrefab, barrelEnd.position, barrelEnd.rotation);
            //利用空物体barrelEnd的位置和旋转,定义克隆后的prefab的位置和旋转
            //Instantiate返回一个名为object的类型
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
using UnityEngine;
using System.Collections;

public class UsingInstantiate : MonoBehaviour
{
    public Rigidbody rocketPrefab;
    public Transform barrelEnd;
    
    void Update ()
    {
        if(Input.GetButtonDown("Fire1"))
        {
            Rigidbody rocketInstance;
            rocketInstance = Instantiate(rocketPrefab, barrelEnd.position, barrelEnd.rotation) as Rigidbody;//Instantiate会返回一个名为object的对象,类型强制转换为Rigidbody
            rocketInstance.AddForce(barrelEnd.forward * 5000);//用Rigidbody的AddForce方法,参数是施加力的方向
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

barrelEnd.forward * 5000 计算了一个新的向量,该向量与 barrelEnd 的前向方向相同,但大小是 5000 单位。在Unity中,力的单位是牛顿(N),但这里的 5000 只是一个数值,它代表了你想要施加的力的大小。
AddForce 方法将这个计算出的力向量应用到 rocketInstance 物体上。
barrelEnd.forward 提供了力的方向,它是基于 barrelEnd 的局部坐标系的。
AddForce 施加的是一个瞬间的力。
在游戏中创建多个克隆体时,这些克隆体仍会存在于场景中,可以编写一个脚本规定在指定时间后将其从世界中移除

using UnityEngine;
using System.Collections;

public class RocketDestruction : MonoBehaviour
{
    void Start()
    {
        Destroy (gameObject, 1.5f);//prefab可以用此脚本在指定时间后移除克隆体
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

二十一、数组

数组不是类型,是特定类型的变量集合
int[] myIntArray=new int[5]; 长度为5的int型数组
初始化方法:
1.在start函数中初始化,myIntArray[0]=5;
2.声明时初始化 int[] myIntArray={5,30,40,22,33};
3.声明为public的数组可以在Inspector中定义长度和值,也可以用脚本获取指定标签的对象

using UnityEngine;
using System.Collections;

public class Arrays : MonoBehaviour
{
    public GameObject[] players;

    void Start ()
    {
        players = GameObject.FindGameObjectsWithTag("Player");//带player标签的对象组,玩家集合
        
        for(int i = 0; i < players.Length; i++)
        {
            Debug.Log("Player Number "+i+" is named "+players[i].name);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

二十二、Invoke

将函数调用安排在指定延时后发生

using UnityEngine;
using System.Collections;

public class InvokeScript : MonoBehaviour 
{
    public GameObject target;
    
    
    void Start()
    {
        Invoke ("SpawnObject", 2);//两秒后调用SpawnObject方法。两个参数,第一个是调用方法名(此方法必须没有参数,返回值为void),第二个是延时时间
    }
    
    void SpawnObject()
    {
        Instantiate(target, new Vector3(0, 2, 0), Quaternion.identity);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
using UnityEngine;
using System.Collections;

public class InvokeRepeating : MonoBehaviour 
{
    public GameObject target;
    
    
    void Start()
    {
        InvokeRepeating("SpawnObject", 2, 1);//反复调用,每隔一秒调用一次
        CancelInvoke("SpawnObject");//取消调用
        
    }
    
    void SpawnObject()
    {
        float x = Random.Range(-2.0f, 2.0f);
        float z = Random.Range(-2.0f, 2.0f);
        Instantiate(target, new Vector3(x, 2, z), Quaternion.identity);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

二十三、枚举

可以在类内或类外创建。switch语句中用枚举,会自动补充各种情况。
类外:可以创建一个只包含一个枚举的脚本,其他类可以访问这个枚举
类内:这个类要用到这个枚举

using UnityEngine;
using System.Collections;

public class EnumScript : MonoBehaviour 
{
    enum Direction {North, East, South, West};//枚举
    //默认North=0, East=1, South=2, West=3
    //enum Direction {North=1, East, South, West};其他值以此往后退
    //也可以给每一个指定值
    //enum Direction:short {North, East, South, West}; 声明为short类型

        void Start () 
    {
        Direction myDirection;//声明一个Direction变量
        
        myDirection = Direction.North;
    }
    
    Direction ReverseDirection (Direction dir)
    {
        if(dir == Direction.North)
            dir = Direction.South;
        else if(dir == Direction.South)
            dir = Direction.North;
        else if(dir == Direction.East)
            dir = Direction.West;
        else if(dir == Direction.West)
            dir = Direction.East;
        
        return dir;     
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

二十四、线性插值

在制作游戏时,有时可以在两个值之间进行线性插值。这是通过 Lerp 函数来完成的。线性插值会在两个给定值之间找到某个百分比的值。例如,我们可以在数字 3 和 5 之间按 50% 进行线性插值以得到数字 4。这是因为 4 是 3 和 5 之间距离的 50%。
在 Unity 中,有多个 Lerp 函数可用于不同类型。对于我们刚才使用的示例,与之等效的将是 Mathf.Lerp 函数,如下所示:

// 在此示例中,result = 4
float result = Mathf.Lerp (3f, 5f, 0.5f);

Mathf.Lerp 函数接受 3 个 float 参数:一个 float 参数表示要进行插值的起始值,另一个 float 参数表示要进行插值的结束值,最后一个 float 参数表示要进行插值的距离。在此示例中,插值为 0.5,表示 50%。如果为 0,则函数将返回“from”值;如果为 1,则函数将返回“to”值。
Lerp 函数的其他示例包括 Color.Lerp 和 Vector3.Lerp。这些函数的工作方式与 Mathf.Lerp 完全相同,但是“from”和“to”值分别为 Color 和 Vector3 类型。在每个示例中,第三个参数仍然是一个 float 参数,表示要插值的大小。这些函数的结果是找到一种颜色(两种给定颜色的某种混合)以及一个矢量(占两个给定矢量之间的百分比)。
让我们看看另一个示例:

Vector3 from = new Vector3 (1f, 2f, 3f);
Vector3 to = new Vector3 (5f, 6f, 7f);

// 此处 result = (4, 5, 6)
Vector3 result = Vector3.Lerp (from, to, 0.75f);

在此示例中,结果为 (4, 5, 6),因为 4 位于 1 到 5 之间的 75% 处,5 位于 2 到 6 之间的 75% 处,而 6 位于 3 到 7 之间的 75% 处。
使用 Color.Lerp 时适用同样的原理。在 Color 结构中,颜色由代表红色、蓝色、绿色和 Alpha 的 4 个 float 参数表示。使用 Lerp 时,与 Mathf.Lerp 和 Vector3.Lerp 一样,这些 float 数值将进行插值。
在某些情况下,可使用 Lerp 函数使值随时间平滑。请考虑以下代码段:

void Update ()
{
light.intensity = Mathf.Lerp(light.intensity, 8f, 0.5f);
}

如果光的强度从 0 开始,则在第一次更新后,其值将设置为 4。下一帧会将其设置为 6,然后设置为 7,再然后设置为 7.5,依此类推。因此,经过几帧后,光强度将趋向于 8,但随着接近目标,其变化速率将减慢。请注意,这是在若干个帧的过程中发生的。如果我们不希望与帧率有关,则可以使用以下代码:

这意味着强度变化将按每秒而不是每帧发生。
请注意,在对值进行平滑时,通常情况下最好使用 SmoothDamp 函数。仅当您确定想要的效果时,才应使用 Lerp 进行平滑。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/864308
推荐阅读
相关标签
  

闽ICP备14008679号