赞
踩
C# Unity入门
物体的脚本定义物体的动作或属性。脚本打钩才运行,不打钩不运行。
创建脚本的方式:
1.在项目栏创建脚本后拖拽到物体上
2.在Inspector中给游戏物体添加组件
Start()函数在物体进入场景后调用,Debug.Log()可以获取任意变量的值并打印在控制台上中
成员(变量和函数)默认为private,除非特定声明为public才能在类外访问。public成员会在Inspector中显示,可以在运行时修改参数进行演示,退出运行状态时不在Inspector中保存。一个变量在类中且在函数外初始化,则他会被Inspector中的值覆盖,若在Start()/Awake()中赋值则他们出现在Inspector中设置过变量之后,不会被Inspector中的值覆盖。
Awake方法是Unity中的一个特殊方法,当对象被加载到场景中时调用。
Start方法是Unity中的另一个特殊方法,当对象在场景中开始其第一帧之前调用。
在生命周期中都只运行一次。但Start()只能在启动脚本组件时(打钩)被调用。游戏中遇到敌军,Awake配备弹药,启动脚本组件时使用Start在定义时间内射击
Update():在每个使用它的脚本中每帧调用一次。基本上只要需要变化或调整都要用Update来实现:非物理对象的移动,简单的计时器,输入检测等等。不是按固定时间调用的。
FixedUpdate():按固定时间调用,时间间隔相同。任何影响刚体(即物理对象)的动作都应该使用这个函数
将光标放在需要插入函数的位置,按Ctrl+Shift+M启动向导,可以选择想创建的函数
一个类继承自Unity的MonoBehaviour类,这意味着它可以附加到Unity的游戏对象上
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; } } }
gameObject.SetActive(false);
当父对象被停用,则子对象也不会在场景中出现,但子对象是活跃状态,子对象在层级结构中是停用状态。
myObject.activeSelf myObject.activeInHierarchy
平移 旋转
在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);
}
在上述示例中,我们使用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); } }
可用于将游戏对象的正面指向世界中的另一个transform
可以让摄像机对准某一物体,跟随他的运动
using UnityEngine;
using System.Collections;
public class CameraLookAt : MonoBehaviour
{
public Transform target;
void Update ()
{
transform.LookAt(target);
}
}
销毁游戏对象或组件(退出运行状态还有,只是在运行界面里销毁)
延时三秒销毁其他游戏物体
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); } } }
均返回Bool值
GetKey可以用KeyCode制定特定按钮
GetButton还可以用字符串表示某按键,比如Jump表示Space键,可以修改positive button修改Jump表示的键
返回-1~1之间的浮点数,NegativeButton和PositiveButton,Gravity越大返回0点的速度越快,Sensitivity越大离开原点的速度越快,Snap当同时按NegativeButton和PositiveButton时返回0点,Dead越大盲区越大,当用操纵杆操作时不想感知操纵杆的轻微晃动,盲区越大,操纵杆需要越大的移动幅度才有效
float h=Input.GetAxis(“Horizontal”);//水平方向
float v=Input.GetAxis(“Vertical”);//垂直方向
鼠标按下时执行此函数
using UnityEngine;
using System.Collections;
public class MouseClick : MonoBehaviour
{
void OnMouseDown ()
{//施加一个反作用力
rigidbody.AddForce(-transform.forward * 500f);
rigidbody.useGravity = true;//添加了重力,所以会倒下
}
}
访问与同一个游戏对象关联的其他脚本或其他游戏对象的脚本。此函数会占用大量处理能力,因此要少用,最好在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"); } }
AnotherScript
using UnityEngine;
using System.Collections;
public class AnotherScript : MonoBehaviour
{
public int playerScore = 9001;
}
YetAnotherScript
using UnityEngine;
using System.Collections;
public class YetAnotherScript : MonoBehaviour
{
public int numberOfPlayerDeaths = 3;
}
在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 的值时,需要考虑到中心点的位置,以确保盒形碰撞器能够正确地包围游戏对象并正确地响应碰撞。
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); } }
脚本名和类名一致,面向对象编程的原则之一是一个类扮演一个职责或角色,类包含变量和方法
public 类名 对象名=new 类名();//实例化 构造函数,创建类和struct时,都要调用构造函数
构造函数可以有多个,没有返回值(连void都没有),根据调用时的参数对应相应的构造函数。构造函数可以设置默认值,限制实例化。创建构造函数,输入CTOR,再按Tab,即可插入构造函数代码片段
克隆游戏对象,常用于克隆prefab(预配置对象,保存在项目素材中)
using UnityEngine;
using System.Collections;
public class UsingInstantiate : MonoBehaviour
{
public Rigidbody rocketPrefab;
void Update ()
{
if(Input.GetButtonDown("Fire1"))
{
Instantiate(rocketPrefab);//prefab将在默认位置实例化,即位置0
}
}
}
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的类型 } } }
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方法,参数是施加力的方向 } } }
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可以用此脚本在指定时间后移除克隆体
}
}
数组不是类型,是特定类型的变量集合
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); } } }
将函数调用安排在指定延时后发生
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); } }
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); } }
可以在类内或类外创建。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; } }
在制作游戏时,有时可以在两个值之间进行线性插值。这是通过 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 进行平滑。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。