基础介绍:
Unity3d的布局
•Scene View (场景视图)-用于放置物体
•Game View(游戏视图)-表示游戏在运行时的外观
•Hierarchy(层次视图)-当前场景中的游戏物体的列表用来放置GameObject.
•Project(工程视图)-显示当打开工程所有可用的物体和资源
•Instpector(检视视图) -显示当前选中物体的细节和属性
基本组成:
GameObject,可以携带各种Component(每个GameObject至少带有Transform组件,所有的组件都可以从顶部菜单Component里面找到并添加给游戏对象)。
Component组件,附加在GameObject上,不同的组件可以使GameObject具有不同的属性,Transform、碰撞器、刚体、渲染器等都是组件,脚本也是组件的一种,对象所表现出来的行为都是由组件实现的。
预制:
用于程序运行时,动态实例化对象的“母体”,比如,在射击类游戏中,子弹的生成就可以使用实例化预制的方式来实现,这就好比是Flash中的各种Display类,你可以定义它的各种属性方法,然后在使用的时候直接实例化一个实例。
在project面板右击选择Creat——Prefab新建一个预制,将Hierarchy面板中要制成预制的对象拖到这个新建预制上即可。
标签和层:
标签(tag)用于辨别物体,与name类似,使用对象的tag和name都可以找到对应的物体(GameObject.Find(“Name”)、 GameObject.FindWitnTag(“Tag”))。默认是Untagged,可以通过Inspector面板里面Tag的下拉菜单选择Add Tag项来添加新的标签, 在tagmanager中点开Tags左侧的小三角 通过size来增加标签的数量,每个Element内都填入新标签的名字
层(layer),在使用某些功能的时候,可以通过层来过滤不需要运用该功能的对象,也就是把该功能运用到特定的层,比如,相机的Culling Mask属性,通过选择特定层可以实现只显示位于被选中的层的对象。层的添加也是在标签管理器中,Unity已经设置了8个层,你是不能对这8个层进行修改的,你可以从第9个(也就是user layer8)开始添加你定义的层。
资源:
.unitypackage格式的文件可以直接import到unity中,记住最好是在打开unity的情况下,在project面板里右击,然后在import packages中选中你要导入的资源。注:Unity不识别中文路径,因此要导入的资源千万不要放在中文目录下!!!还有你的工程也不要新建在中文目录下!!!(你新建工程的时候选择中文路径的话,也建不起来~)也可以把你的场景打包,导出.unitypackage资源包,然后可以在其他项目中导入使用。(在project面板里右击, export package)另外,利用工程面板(project)右键菜单中的import new assets可以导入其他形式的资源,如,模型、音频、视频等,当然也可以直接将外部文件夹中的资源拖到project中的方式完成导入。
物理引擎:
unity使用NVIDIA PhysX物理引擎
碰撞器:各种基本体的碰撞器(box、sphere、capsule、cylinder),网格碰撞器(mesh collider)、车轮碰撞器(Wheel collider)、地形碰撞器(terrain collider)——碰撞器组件在你选中对象的时候会以绿色线框显示。
碰撞检测:碰撞器碰撞检测、光线投射(射线)、触发器碰撞检测,通过碰撞检测可以得到与当前对象发生碰撞的对象信息,使用碰撞的相关函数OnCollisionEnter(碰撞器碰撞检测)、OnTriggerEnter(触发器碰撞检测)、Physics.Raycast(光线投射)获取。
刚体:模拟物体物理现象的基础,加了刚体组件才能模拟重力、阻力等。
力:作用于刚体,你只要通过添加各种力,就可以使刚体表现出跟现实中一样的受力情况。
坦克大战知识点介绍:
*新建坦克的时候创建Cube,来进行坦克物体的坐标矫正,把坦克的position设置为0。(如果直接放置坦克可能会有坦克移动或者碰撞时 慢、飘起来的情况。)
1.
坦克移动通过forward,up,right来设置方向
坦克移动的脚本 写在void Update ()函数里面
//移动
if (Input.GetKey (KeyCode.UpArrow)){
transform.Translate(Vector3.forward*Time.deltaTime*10);
}
//旋转
if (Input.GetKey (KeyCode.LeftArrow)) {
transform.Rotate(Vector3.up*Time.deltaTime*-60);
}
2.给坦克加上box collider和rigidbody两个物理属性。
Collider是最基本的触发物理的条件,例如碰撞检测。基本上,没有Collider物理系统基本没有意义(除了重力)。
Rigidbody是物体的基本物理属性设置,当检测碰撞完之后,就要计算物理效果,而Rigidbody就是提供计算基本参数的玩意。
Collider 必须搭配 Rigidbody 来使用,就像 Rigidbody 必须搭配 GameObject一样。
3.因为子弹在游戏中会出现很多,所以应该用prefabs来制作,这样可以有效的节省游戏资源。
让子弹碰撞到目标等待一段时间就消失
//碰撞检测
void OnCollisionStay(Collision collisionInfo) {
Instantiate(bomb, transform.position, transform.rotation);
StartCoroutine(WaitAndDestroy(0.5F));
}
//等待0.5秒让子弹消失
IEnumerator WaitAndDestroy(float waitTime) {
yield return new WaitForSeconds(waitTime);
//销毁子弹
Destroy(gameObject);
}
//当子弹数小于0等待3秒自动填装 因为update不停得刷帧所以加一个bFirst判断执行一次
if (iCurrentBulletCnt <= 0){
if (isFirst){
StartCoroutine(WaitAndShot(3.0F));
}
return;
}
if (Input.GetKeyDown(KeyCode.Space) && iCurrentBulletCnt > 0){
Rigidbody clone;
clone = Instantiate(Bullet1, FirePoint.transform.position, FirePoint.transform.rotation) as Rigidbody;
clone.velocity = transform.TransformDirection(Vector3.forward *50);
iCurrentBulletCnt-= 1;
isFirst = true;
}
//等待装填子弹
IEnumerator WaitAndShot(float waitTime){
if (isFirst){
isFirst = false;
yield return new WaitForSeconds(waitTime);
//填装100发子弹
iCurrentBulletCnt = 100;
}
}
4.音乐
Unity3D游戏引擎一共支持4个音乐格式的文件
.AIFF 适用于较短的音乐文件可用作游戏打斗音效
.WAV 适用于较短的音乐文件可用作游戏打斗音效
.MP3 适用于较长的音乐文件可用作游戏背景音乐
.OGG 适用于较长的音乐文件可用作游戏背景音乐
GameObject -> CreateEmpty 创建成功后我命名为audio。
给audio添加一个AudioSource属性,这个属性非常的重要,Unity播放音乐主要就是要靠这个东西。
Component ->Audio ->Audio Source。
**给坦克加上音效,需要先给摄像机加上Audio Listener,这里强调一下AudioListenr ,它音频监听器,用来监听音乐文件的播放。这是一个重要的属性,一定要勾选,只有勾选后才可以进行音乐的播放。
5.两个脚本相互调用
1)如果两个已经绑定在gameobject上
设置gameobject的tag值 这里设为fire.
在Script1.cs里有两个方法是
public void setBulletcnt(int iCnt){
iCurrentBulletCnt = iCnt;
}
public void jump(){
Debug.Log(“jump”);
}
在Script2.cs里调用
方法一:
GameObject.FindWithTag("fire").GetComponent<Bullet>().setBulletcnt(50);
GameObject.FindWithTag("fire").GetComponent<Bullet>().jump();
方法二:
public Script1 other;
other = (Bullet)GameObject.FindWithTag("fire").GetComponent("Bullet");
other.setBulletcnt(50);
other.jump();
2)如果没有绑定在gameobject上
js调用js 直接脚本名.变量名
C#调用C#声明static public 变量名,然后脚本名.变量名调用
js调用C# var c = gameObject.GetComponent("脚本名");
脚本名.变量名调用
C#调用js 脚本名c = (脚本名)gameObject.GetComponent<脚本名>();
脚本名.变量名调用
ScriptA.cs里声明 static public void ChangeTool()
{
Debug.Log("========================"+"ChangeTool"+"========================");
}
调用:
ScriptB.cs里写ScriptA.ChangeTool();
动画Animation:
主要是将一帧帧的图片放进数组里然后通过renderer.material.mainTexture = animation0[icurFrame]来渲染。
6.场景切换
如果游戏有几个场景,需要在File->Build Settings里面设置场景顺序
用Application.LoadLevel(1)来切换场景。
MonoDevelop几个常用的快捷键
SHIFT + Tab 选中的代码左移
Tab 选中代码右移
CTRL + ALT +C 注释/不注释该行
CTRL+K 删除光标所在行的该行后面的代码
CTRL+ DOWN 像鼠标滚轮一样向下拖
CTRL + UP 像鼠标滚轮一样向上拖
CTRL + F 查找该脚本
CTRL + SHIFT + F 查找全部脚本
CTRL + H 替换代码
CTRL + SHIFT +W 关掉所有脚本
1:Unity内部的脚本,是通过附加自定义脚本对象到游戏物体组成的,在Unity脚本内部有不同的特定函数,而且被指定调用,下列是几个最常见的:
Awake:场景被加载时候运行,在任何Start函数调用之前被调用
Start:这个函数常用初始化脚本对象,设置游戏对象开始状态(第一次),比如说太空大战游戏开始运行时候,敌方战机的随机下落。
Update: 这个函数在渲染一帧之前被调用,这里的代码是大部分游戏行为被执行的地方,游戏主体函数.
Fixeupdate:这个函数在每个物理(rigidbody)时间步被调用一次,这是处理基于物理游戏的地方。
LateUpdate:每一帧之后调用.
自定义句柄:
他们都以On开始,比如OnCollisionEnter,OnTriggerEnter,OnGUI等
2:Time
Time类包含了一个非常重要的类变量,称为deltaTime,这个变量包含从上一次调用Update或FixedUpdate(根据你是在Update函数还是在FixedUpdate函数中)到现在的时间量.
所以对于上面的粒子,修改它使这个物体以一个恒定的速度旋转而不依赖于帧率
void Update () {
transform.Rotate(0, 5 * Time.deltaTime, 0);
}
void Update (){
transform.Translate(0,0,2*Time.deltaTime);
}
如果你加或是减一个每帧改变的值,你应该将它与Time.deltaTime相乘。当你乘以Time.deltaTime时,意思就是:我想以 10米/秒移动这个物体不是10米/帧。这不仅仅是因为你的游戏将独立于帧而运行,同时也是因为运动的单位容易理解。
3.从MonoBehaviour继承
所有的行为脚本必须从MonoBehaviour继承(直接或间接)。在Javascript中这自动完成,但是必须在C#或Boo脚本中显示申明。如果你在Unity内部使用Asset -> Create -> C Sharp/Boo Script菜单创建脚本,创建模板已经包含了必需的定义。
public class NewBehaviourScript : MonoBehaviour {...} // C#
class NewBehaviourScript (MonoBehaviour): ... # Boo
4.使用Awake或Start函数来初始化
Javascript中放置在函数之外的代码,在C#或Boo中要放置在Awake或Start中。
Awake和Start的不同是Awake在场景被加载时候运行,而Start在第一次调用Update或FixedUpdate函数之前被调用,所有Awake函数在任何Start函数调用之前被调用。
5.类名必须与文件名相同
Javascript中,类名被隐式地设置为脚本的文件名(不包含文件扩展名)。在c#和Boo中必须手工做
6.不要使用命名空间
7.只有序列化的成员变量会显示在检视面板中
8.避免使用构造函数
二、 优化
1)尽量利用GetComponent来缓存对象
Transform _transform;
void Start(){
_transform = GetComponent<Transform>();
}
void Update(){
_transform.position += _transform.forward;
}
2)用作Texture的PNG图片,默认Texture Type为Texture;但用作GUI的PNG图片,需把Texture Type设为GUI,不然会有质量损失
3)着色器与硬件相关,不同的平台会做不同的优化,因此在Unity中,如果游戏运行在移动端,建议将模型的shader从Diffuse转为Mobile/Diffuse
4)位移比乘除速度快,对效率要求高,且满足2的幂次方的乘除方法,可以采用位移的方式:
左移相当于乘,左移一位相当于乘以2;
右移相当于除,右移一位相当于除以2;
C#的int最大32位(如果编译器默认64,就不是这个结果),所以1<<32 = 1<< 0
5)合理组织场景,a)方便管理 b)使用Unity官方提供的CombineChildren代码提高性能
6)使用Unity Remote远程调试(待测)
三、C#
1. 而不管是在Java还是C++中,一旦修改了被遍历对象,在修改前生成的iterator都会失效,所以《C++ Primer》及Java课本中曾警告过不要在用iterator遍历集合时增删集合元素,看来Objective-C中也是一样。结论:在Foreach(...)循环里尽量不要更改操作的源,
四、调试:
Debug.Log(string.Format("{0:d}", stateInfo.IsName("Base Layer.attack1")));
错误:
1.
unity3d的脚本里面最好不要写中文注释,不然有可能代码无效
例如:
//这里写注释的话可能下面的if代码就失效
if(bFirst)
2.all compiler errors to be fixed before you can enter playmode
所有的编译错误必须更正,在你进入(播放或游戏)模式前
3.Failed to call function PlayAnimation of class SimpleSprite
Calling function PlayAnimation with no parameters but the function requires 1.
参数有问题
五、插件:
iTween物体移动轨迹设定
NGUI 界面设计
EasyMotion2D 动画插件
六、组件
1.角色控制器
CharacterController controller;
controller = GetComponent<CharacterController>();
controller.Move(Vector3.right * Time.deltaTime*currentVel);
这里不能再用transform.position来运动物体。
七、总结