Unity3D 您所在的位置:网站首页 厚度后会有期 Unity3D

Unity3D

2023-11-22 11:40| 来源: 网络整理| 查看: 265

相关网址汇总

1.Unity官网(外网):unity.com 2.Unity官网(内网):unity.cn 3.Unity学习: learn.unity.com learn.unity.com/projects 4.Unity官方商店:assetstore.unity.com

基本操作以及模块简介 视角操作以及组件

组件设置 1.导航器Gizmo:表示世界坐标的方向 2.栅格Grid:表示XZ坐标平面 3.天空盒Skybox:表示游戏世界的背景

3D视图: 1.旋转视图:右键 / Alt+左键 2.视角缩放:滚轮 / Alt+右键

导航器: 1.按住Shift,点击中间的小方块,恢复方向 2.点Y轴,顶视图 3.点X轴,右视图 4.点Z轴,前视图

视野中心: 1.将某物体放置于世界中心:选中一个物体,长按住F键 此时旋转视图,似是绕着物体旋转。 2.出生点:添加一个新物体,其位于视图中心。并不是(0,0,0)。

透视和正交: 透视视图Perspective:近大远小 正交视图Orthographic:等距视图Isometric,物体显示与距离无关 在导航器下方的persp处调节。 透视,广角设定: 摄像机的广角Field默认为60°。广角越大,透视畸变太厉害。可以设为30~40°。

物体操作

Unity自带的基础模型

Cube,立方体 Sphere,球体 Capsule,胶囊体 Cylinder,圆柱体 Plane,平面

旋转工具Rotate Tools: 在Unity中,顺时针旋转,对应方向参量为负方向。 逆时针旋转,对应方向参量为正方形。 此外,按住ctrl键旋转使其每次角增量为15°。

缩放工具Scale Tools: *AF扩展插件:AfSimpleExtension 扩展功能: 1.输出物体的尺寸Scale 2.聚焦到事业重心 G键 3.快速切换正交视图与等距视图。

模型操作

网格Mesh:存储了模型的形状数据(面,顶点坐标,法向坐标等)。 材质Material:需添加到物体上,定义了物体的表面细节(颜色,是否金属,粗糙程度,是否透明......) 纹理Textures:需添加到材质上,可以是贴图。

纹理.png

模型建好以后一般导出为 fbx文件格式。

在Unity中,

一个平面是没有厚度的 正面可见,背面透明

或者说,平面的背面不会被渲染。

※ FBX文件的使用方式: 1.材质替换

选中 *.fbx 文件 在Inspector 中切到 Materials属性--->Use Embeded Materials,On Demand Remap:映射新的材质 点Apply 应用

2.使用外部材质 Use External Materials

选中fbx文件 Location:Use External Materials使用外部材质 点Apply应用,将内嵌材质解压缩到Materials目录下 直接修改Materials目录下的材质文件。 资源文件

资源文件:Assets目录下的文件,被称为资源。 常见类型:

模型文件Model *.fbx 图片文件Texture *.jpg/png/psd/tif 音频文件AudioClip *.mp3/wav/aiff 脚本文件Script *.cs 材质文件,场景文件 *.mat,*.unity

轴心,父子关系,空物体 Global全局坐标系:绝对坐标,其X Y Z 指向世界的上下东西南北 Local本地坐标系:相对坐标,其X Y Z 指向模型的前后左右上下 坐标轴的含义:

X:Right 向右 Y:up 向上 Z:forward 向前,一般要求模型直面与Z轴方向一致。 组件Component

常见组件:

Light:光照 Mesh Filter:网格过滤器,加载网格数据 Mesh Renderer:网格渲染器,无渲染物体无法显示

组件的增添与删除...... AudioSource组件的使用方式: 1.添加一个音乐文件 *.mp3/wav/aiff 2.创建一个物体

Add Component,Audio | Audio Source 将音乐文件拖到AudioSource.AudioClip属性 在3D窗口上方选 Toggle Audio On

Transform变换组件:

Position:方位 Rotation:旋转 Scale:尺寸

摄像机组件 实用操作: Align with View:调整摄像机角度使其与3D视图对齐。

预制体简述 预制体:预先规定好信息的一些游戏对象。以便于下次使用。 一些细节:

预制体导出时需要勾选其依赖(材质,脚本等),否则无法正常使用。 预制体仅仅记录了结点信息 prefab不包含材质贴图数据,仅包含引用 脚本与编程

给游戏对象挂载脚本的步骤:

创建Scripts文件夹,在其中创建一个C#文件 进入C#,编写代码,并保存 将脚本文件挂载到游戏对象中(拖拽 or AddComponent)即可

Tips:

C#文件名必须和类名一致,否则无法挂载 脚本必须被挂载到物体上,才会被调用

常用的信息代码:

GameObject obj = this.gameObject; //获取到当前脚本挂载游戏对象 string name = obj.name; //获取到游戏对象名字 Transform tr = obj.transform; // 获取到Transform属性 Vector3 pos = tr.position; //获取到Transfrom中的position值(返回值是三维向量) Debug.Lo("物体当前的位置:"+pos.ToString("F3")); //保留三位小数 //世界坐标和本地坐标 //this.gameObject.transform 可等效写为 this.transform tr.localPosition; //本地坐标 tr.position; //世界坐标 //修改某物体的坐标 this.transform.localPosition = new Vector3(1.5f, 2.5f, 0);

帧更新与物体运动 C#代码中的Update()方法:

void Update() { //Debug.Log("帧更新 Time:" + Time.time); // 获取游戏时间,测试帧率 //Debug.Log("帧更新 时间差:" + Time.deltaTime); // 每次刷新的时间差 //物体移动 //设置小车运动的速度 float speed = 100; float distance = speed * Time.deltaTime; Vector3 pos = this.transform.localPosition; pos.z += distance; this.transform.localPosition = pos; //使用Translate方法实现物体移动 this.transform.Translate(0, 0, distance); //dx,dy,dz分别为三个方向的增量,space可选择相对于哪个坐标系 this.transform.Translate(dx,dy,dz,space); //例子 this.transfrom.Translate(distance,0,distance,Space.Self/World) }

物体转向

void Start() { //转向(在途中加入一个红旗,获取到红旗方向,让小车向红旗方向运行) GameObject flag = GameObject.Find("红旗"); this.transform.LookAt(flag.transform); } void Update(){ float speed = 100; float distance = speed * Time.deltaTime; this.transform.Translate(0,0,distance,Space.Self); }

小练习:当车到达旗子时,停止运动

public class SimpleLogic : MonoBehaviour { GameObject flag; // Start is called before the first frame update void Start() { flag = GameObject.Find("红旗"); this.transform.LookAt(flag.transform); } // Update is called once per frame void Update() { //让小车到达红旗时停下来 Vector3 p1 = this.transform.position; Vector3 p2 = flag.transform.position; Vector3 p = p2 - p1; //求得两个向量的模值 float length1to2 = p.magnitude; if (length1to2 >= 30) { //设置小车运动的速度 float speed = 100; float distance = speed * Time.deltaTime; this.transform.Translate(0, 0, distance, Space.Self); } } }

物体的旋转 方式一:采用传统的改Rotation值的方式

//不易操作,官方不建议使用 transform.rotation=... //建议使用欧拉角的方式

方式二:采用欧拉角的计算方法

transform.eulerAngles = new Vector3(0,45,0) transform.localEulerAngles = new Vector3(0,45,0);

案例:将游戏对象 风扇 转起来 方案一:使用传统欧拉角

void Update() { //旋转速度(1800°/s) float rotateSpeed = 1800; float rotateValue = rotateSpeed * Time.deltaTime; Vector3 angles = this.transform.localEulerAngles; angles.y += rotateValue; this.transform.localEulerAngles = angles; }

方案二:使用Rotate() API直接调用

void Update(){ //设置旋转速度 float rotateSpeed = 1800; this.transform.Rotate(0,rotateSpeed * Time.deltaTime,0,Space.Self); }

脚本与编程的实质:

//unity框架会自动创建游戏对象为一个结点 GameObject obj = new GameObject(); //紧接着创建该游戏结点下挂载的脚本,并由框架挂载到该游戏结点下 SimpleLogic sl = new SimpleLogic(); //并由Unity自动调用Start和Update方法实现初始化和帧更新

消息函数

在c#语言中,所有的脚本类都 应该继承于 MonoBehavior 类,其作用类比于Java中的 Object 类。

消息函数(事件函数):是指一些回调函数。比如Start()方法会在脚本初始化的时候被调用,而Update()会在帧更新的时候被调用。 常见的消息函数:

Awake:初始化,仅执行一次,组件被禁用时也会调用 Start:初始化,仅执行一次,组件被禁用时不会调用 Update:帧更新,每帧调用一次 OnEnable:当组件启用的时候调用 OnDisable:当组件禁用时被调用

脚本的执行顺序

脚本的执行顺序与Hierarchy中层级顺序无关 一般的,可以在Project Setting中的Scripts Execution Order中设置脚本执行的优先级。但没必要!!!

脚本参数:

给脚本添加一个参数:

[ Tooltip("这个是Y轴向的角速度") ] public float rotateSpeed = 30f; //在Unity中,脚本参数多了一栏Rotate Speed,值为30

注意事项:

修饰符必须为 public 参数名称必须采用驼峰式命名 可采用Tooltip给参数名称添加解释 代码中的规定数值为参数的默认值,通过reset按钮可重置

值类型和引用类型: 值类型:

值类型本身是一个值,可直接赋值,若未赋值,则默认为0 不能为null

结构体类型:

本质也是值类型,不能设置为null 设置初始值时必须采用new的方式 典例:Vector3 public int intValue ; //0 public float floatValue = 0.5f; public bool boolValue = true; public string stringValue = "Hello C-Sharp"; public Vector3 rotateSpeed = new Vector3(1,1,1);

引用类型: 案例:如果一个平面内有两个红旗,我们需要手动规定小车向哪个红旗移动,就可以采用引用类型的属性

public GameObject target; //目标物体 void Start (){ this.transform.LookAt(target.transform); }

注意:一定要给引用类型赋值,否则会报 空指针异常。

鼠标的输入

旋转飞车实例:

void Update() { /* 0:鼠标左键 1:鼠标右键 2:鼠标中键 */ if (Input.GetMouseButtonDown(0)) { Debug.Log("鼠标按下"); rotateSpeed = 900f; moveSpeed = 300f; } if (Input.GetMouseButtonUp(0)) { Debug.Log("鼠标抬起"); rotateSpeed = 0f; moveSpeed = 0f; } this.transform.Rotate(0, rotateSpeed * Time.deltaTime, 0, Space.Self); this.transform.Translate(0, 0, moveSpeed * Time.deltaTime, Space.World); }

相关API:

GetMouseButtonDown:鼠标按下 GetMouseButtonUp:鼠标抬起 GetMouseButton:状态探测,只要鼠标按下,会一直调用。

旋转飞车实例2:

void Update() { /* 0:鼠标左键 1:鼠标右键 2:鼠标中键 */ if (Input.GetMouseButton(0)) { rotateSpeed = 900f; moveSpeed = 300f; } else { rotateSpeed = 0; moveSpeed = 0; } this.transform.Rotate(0, rotateSpeed * Time.deltaTime, 0, Space.Self); this.transform.Translate(0, 0, moveSpeed * Time.deltaTime, Space.World); }

&一些补充的工具函数

//获取到鼠标点击的位置坐标 Vector3 mousePos = Input.mousePosition; //获取到屏幕的尺寸 int screenWidth = Screen.width; int screenHeight = Screen.height; //获取物体的屏幕坐标 Vector3 pos = this.transform.position; Vector3 screenPos = Camera.main.WorldToScreenPoint(pos); 键盘的输入

常用API:

Input.GetKeyDown(key):按键事件,按下 Input.GetKeyUp(key):按键事件,抬起 Input.GetKey(key):案件状态,是否正被按下 代码来操作组件

操作AudioSource组件

//获取到AudioSource组件(泛型) AudioSource audio = this.GetComponent(); //播放 audio.Play();

引用别的组件: 应用场景:在主控结点中操作背景音乐的组件

public class MainLogic : MonoBehaviour { //public GameObject bgmNode; //引用扬声器组件 public AudioSource bgm; //引用脚本组件 public FanLogic fan; //风扇转速 public float rotateSpeed; void Start(){ //AudioSource audio = bgmNode.GetComponent(); //audio.Play(); bgm.Play(); } void Update(){ if(Input.GetMouseButtonDown(0)) { rotateSpeed = 800; //旋转代码在FanLogic脚本下 } } } 获取物体API

案例:主控结点下找到无人机目录下的旋翼对象,并调用它的脚本组件

//主控结点 //方式二:(在Unity中拖入) public GameObject wingNode; //方式一: void Start(){ GameObject node = GameObject.Find(无人机/旋翼); RotateLogic rotateLogic = node.GetComponent(); }

获取游戏节点的父级与子级:

//获取当前组件的父结点与父方位 Transform parent = this.transform.parent; GameObject parentNode = this.transform.parent.gameObject; //获取子结点的方位 //方式一:通过foreach遍历 foreach (Transform child in transform) { Debug.Log("子物体" + child.name); //child } //方式二:通过GetChild()索引API Transform child = this.transform.GetChild(0); //方式三:通过名字查找子项 Transform child = this.transform.Find("子项名或路径");

给物体设置新的父级:

this.transform.SetParent(null/GameObject);

切换物体的显示状态:

Transform child = this.transform.Find("xxx"); if(child.gameObject.activeSelf) { //隐藏 child.gameObject.SetActive(false); } else { //显示 child.gameObject.SetActive(true); } 资源的使用API

用户按下A,D键播放音效成功与失败

//成功音效 public AudioClip audioSuccess; //失败音效 public AudioClip audioFail; void Update() { if (Input.GetKeyDown(KeyCode.A)) { AudioSource audio = GetComponent(); audio.PlayOneShot(audioSuccess); } if (Input.GetKeyDown(KeyCode.D)) { AudioSource audio = GetComponent(); audio.PlayOneShot(audioFail); } }

制作随机音乐盒程序

using System.Collections; using System.Collections.Generic; using UnityEngine; public class MusicBox : MonoBehaviour { public AudioClip[] songs; // Start is called before the first frame update void Start() { if (songs == null || songs.Length == 0) { Debug.Log("当前歌单列表为空!"); } } // Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.Space)) { NextSong(); } } private void NextSong() { //随机播放 int randomIndex = Random.Range(0, songs.Length); //取到AudioSource组件 AudioSource audio = GetComponent(); audio.clip = this.songs[randomIndex]; audio.Play(); Debug.Log("正在播放第" + (randomIndex+1) + "首歌,歌名为:" + audio.clip.name); } } 定时调用与线程

Unity是单线程核心,暂时不必考虑线程,调度,并发。

//延迟调用API this.Invoke("函数名",延迟时间); //循环调用API this.InvokeRepeating("函数名",循环时间间隔); //查看当前线程的ID int ThreadId = Thread.CurrentThread.ManagedThreadId; //判断函数是否正在被调用 bool isInvoking = IsInvoking("函数名"); //取消该函数的调用 CancelInvoke("函数名"); //取消当前脚本所有Invoke调用 CancelInvoke(); 向量的基本运算 //定义一个三维向量 Vector3 v1 = new Vector3(3,0,4); //求向量的模长 float length = v1.magnitude; //向量标准化 Vector3 v2 = v1.normalized; //物体运动的优化写法 //定义一个三维向量来表示不同方向的速度 public Vector3 speed; //优化物体移动写法 void Update() { this.transform.Translate(speed * Time.deltaTime,Space.Self); } 预制体与实例

通过API创建实例:

首先准备子弹的预制体prefab 添加火控脚本 FireLogic.cs //子弹预制体 public GameObject bulletPrefab; //子弹目录 public Transform bulletFolder; //子弹出生点 public Transform firePoint; //炮塔的引用(为了获取到炮塔发射子弹的方向) public Transform cannon; void Update() { //创建实例 GameObject node = Object.Instantiate(bulletPrefab,bulletFolder); //指定出生点 node.transform.position = this.firePoint.position; //指定初始角度 node.transform.localEulerAngles = this.cannon.eulerAngles; //子弹脚本参数的设置(子弹飞行速度) node.GetComponent().setSpeed(0.5f); } 销毁子弹 //销毁自身结点的API Object.Destroy(this.gameObject); //注意不要写错,写为⬇,该写法是销毁组件,而并非结点 Object.Destroy(this); 物理系统与组件 刚体组件

Physic--->RigidBody:刚体组件 常用属性:

Mass:质量 Drag:摩擦力 AngularDrag:角摩擦力 ......

Physic--->Collider:碰撞模型 常用类型:BoxCollider,SphereCollider

物理材质Phsicas Material:

在Assets中添加一个Physics Material 在里面设置全局性的摩擦力Friction,弹性系数等等

碰撞检测 实现 碰撞检测的步骤:

RigidBody-->is Kinematic 勾选标记为 运动学刚体 Collider-->is Tragger 勾选 标记为触发器 挂一个脚本,添加消息函数⬇ void OnTriggerEnter(Collider other) { //拿到被碰撞物体的名字 string name = other.name; //销毁被碰撞物体 Object.Destroy(other.gameObject); Object.Destroy(this.gameObject); } 3D 射击游戏实战 1.导入模型 2.更改天空盒 Window--->Rendering--->lighting--->environment--->Skybox Material 3.添加子弹,模型,材质,脚本等 4.给子弹和怪兽添加碰撞检测 5.子弹的自动发射,自毁与预制体 6.玩家的按键操作 7.怪兽的走位移动 8.怪兽生成器 9.子弹和爆炸特效

源码展示: 子弹BulletLogic:

using System.Collections; using System.Collections.Generic; using UnityEngine; /* 子弹相关逻辑: 准备工作:子弹的预制体以及导入工程 1.子弹的Z轴移动 2.子弹的自毁 3.子弹的特效导入 */ public class BulletLogic : MonoBehaviour { //设置子弹的运动速度 [Tooltip("子弹飞行速度")] public Vector3 speed; [Tooltip("子弹飞行时长")] public float lifetime = 5f; [Tooltip("子弹爆炸特效预制体")] public GameObject explosionEffect; // Start is called before the first frame update void Start() { Invoke("SelfDestroy", lifetime); } // Update is called once per frame void Update() { this.transform.Translate(speed, Space.Self); } //触发器函数 private void OnTriggerEnter(Collider other) { Debug.Log("发生碰撞了"); //如果碰撞到怪兽 if (!other.name.StartsWith("怪兽")) return; Destroy(this.gameObject); Destroy(other.gameObject); //创建一个爆炸粒子特效对象 GameObject node = Object.Instantiate(explosionEffect,null); node.transform.position = this.transform.position; //当粒子特效播放完成时自动销毁 } //子弹自毁函数 private void SelfDestroy() { Debug.Log("子弹已自毁"); Destroy(this.gameObject); } }

玩家PlayerLogic:

using System.Collections; using System.Collections.Generic; using UnityEngine; /* 玩家相关逻辑: 准备工作:导入玩家模型的预制体资源 1.设置子弹发射点,并实现从该点定时发射子弹 2.添加玩家的按键控制移动 */ public class PlayerLogic : MonoBehaviour { //预制体资源 public GameObject bulletPrefab; //子弹生成目录 public Transform bulletFolder; //子弹发射点 public Transform firePoint; //子弹发射间隔 public float fireInterval; //玩家移动速度 public float playerSpeed; // Start is called before the first frame update void Start() { InvokeRepeating("fire", fireInterval, fireInterval); } // Update is called once per frame void Update() { float speedX = 0; //按键控制 if (Input.GetKey(KeyCode.A)) { speedX = -playerSpeed; } else if (Input.GetKey(KeyCode.D)) { speedX = playerSpeed; } else { speedX = 0; } this.transform.Translate(speedX * Time.deltaTime, 0, 0, Space.Self); } //发射子弹的函数 private void fire() { //生成一个子弹实例 GameObject bullet = Object.Instantiate(bulletPrefab, bulletFolder); //设置子弹的出生点 bullet.transform.position = this.firePoint.position; } }

怪兽EnemyLogic:

using System.Collections; using System.Collections.Generic; using UnityEngine; /* 怪兽相关逻辑: 准备工作:导入怪兽的预制体进工程 1.水平速度的蛇皮走位逻辑 2.前后速度的固定逻辑 */ public class EnemyLogic : MonoBehaviour { //水平速度 float speedX = 0; //前后速度 public float speedZ; // Start is called before the first frame update void Start() { //重复周期调用蛇皮走位 InvokeRepeating("move", 0.1f, 0.5f); } // Update is called once per frame void Update() { this.transform.Translate(speedX * Time.deltaTime, 0, speedZ * Time.deltaTime, Space.Self); } //怪兽的蛇皮走位 private void move() { //设置一个随机速度数组 float[] speed = { -5, -10, -20,-30, 5, 10, 20 ,30}; //随机选取一个速度作为水平速度 int rnum = Random.Range(0, speed.Length); //设置速度 speedX = speed[rnum]; } }

怪兽生成器EnemyCreator:

using System.Collections; using System.Collections.Generic; using UnityEngine; /* 怪兽生成器相关逻辑: 1.定时生成怪兽即可 */ public class EnemyCreator : MonoBehaviour { //要创建的怪兽预制体 public GameObject enemyPrefab; //创建怪物间隔时长 public float enemyInterval = 0.5f; // Start is called before the first frame update void Start() { InvokeRepeating("creatEnemy", 0.1f, enemyInterval); } // Update is called once per frame void Update() { } private void creatEnemy() { GameObject node = GameObject.Instantiate(enemyPrefab, this.transform); node.transform.position = this.transform.position; //调整随机出生点 int rnum = Random.Range(-50, 50); node.transform.Translate(rnum, 0, 0, Space.Self); } } 恭喜未来的游戏开发工程师,正式入门!!!后会有期!!!


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有