双击游戏场景文件即可打开游戏工程
Scene.unity
JavaScript语言编写的脚本中,使用UTF-8编码格式
C#语言编写的脚本中,使用UTF-16编码格式
本书是在Mac OS下讲解Unity开发
2012年2月29日
宣雨松
【
Unity游戏开发实战
[美]米歇尔·梅纳德 著
史晓明 李强 译
2012年4月第1版第1次印刷
2.4.1Unity引擎
Unity 2.6.1f3 Setup
9.2.2 Unity的MonoBehaviour类
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour {
Update更新
LateUpdate延迟更新
FixedUpdate延迟更新
Awake唤醒
Start开始
}
GetComponent函数调用也是从MonoBehaviour类继承下来的。
TextRebornTimerNum.GetComponent<Text>().text = "";
如果游戏有成百上千个脚本,该怎么办呢?
Unity使用一种特殊的命令行形式来解决这个问题。
@script AddComponentMenu("SomeFolder/SomeScriptName")
通过把这行代码添加到脚本中(在任何函数之外),可以让Unity把它放入Component菜单中你所选择的子文件夹中。
9.3.1 Input类回顾
GetAxis():返回指定轴的值。这些映射到-1~1,空挡位置为0。
GetButton():如果指定的命名按钮按下,就返回True。需要使用这个函数来引用操作杆和游戏手柄按钮。也可以用于键盘上的键。
GetKey():如果指定的键按下就返回True。这不会返回操作杆按钮指令。
GetMouseButton():它在指定的鼠标按钮按下时返回True。
ResetInputAxis():使用这个函数来重置所有的输入,并且把它们恢复到空挡或是0,覆盖任何玩家的输入。
anyKey:如果玩家按下了任意键、按钮或是鼠标按钮,这个值会设置为True。
mousePosition:使用向量来保存鼠标在屏幕上的当前位置。屏幕的左下角映射为坐标(0,1)。
public Vector3 lastPos;
public Vector3 curPos;
if(Input.GetMouseButtonUp(0)){
lastPos = curPos;
curPos = Input.mousePosition;
float distance = Vector3.Distance(lastPos,curPos);
Debug.Log("distance : " + distance);
}
if (Input.GetMouseButton(0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//Ray ray = camera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
Vector3 pos1 = hit.point;//得到碰撞点的坐标
string str=string.Format("x={0},y={1},z={2}",pos1.x,pos1.y,pos1.z);
strTest=str;
}
}
Unity3D游戏开发技术详解与典型案例
吴亚峰 于复兴 编著
百纳科技 审校
2012年11月第1版
2012年2月,Unity3.5发布。
本书采用的版本为UnitySetup-3.5.0。
3.5.0f5
3.3.8协同程序和中断
任何时间处理程序都是协同程序,但是在Update和FixUpdate中不能使用协同程序。
IEnumerator timeoutScore(int Heroindex)
{
yield return new WaitForSeconds(4.0f);
ShowScore(Heroindex,false);
}
public void OnShowScore(int Heroindex)
{
bool show=m_ImageScore[Heroindex].activeSelf;
if(!show){
ShowScore(Heroindex,true);
StartCoroutine(timeoutScore(Heroindex));
}
}
// 加积分动画
public void OnShowAddScore(int Heroindex,int AddedScore)
{
StartCoroutine(timeoutAddScore(Heroindex,AddedScore));
}
IEnumerator timeoutAddScore(int Heroindex,int AddedScore)
{
yield return new WaitForSeconds(0.1f);
m_TextAddScore[Heroindex].rectTransform.localScale = Vector3.zero;
LeanTween.scale (m_TextAddScore[Heroindex].rectTransform, new Vector3 (0.1f, 0.1f, 0.1f), 0.5f).setEase (LeanTweenType.easeOutBack);
m_TextAddScore[Heroindex].text = "+" + AddedScore.ToString();
StartCoroutine (timeoutAddScoreEnd(Heroindex,AddedScore));
}
IEnumerator timeoutAddScoreEnd(int Heroindex,int AddedScore)
{
yield return new WaitForSeconds(2f);
m_TextAddScore[Heroindex].text = "";
}
】
chap1基础知识
起初Unity的版本为1.0.0,它只可部署在Mac OS下并且只能制作iPhone中的游戏。
随着它不断发展与壮大,目前Unity的版本已经升级至3.5,可同时部署在Mac OS与Windows两种操作系统之上,横跨的主流游戏平台高达9种。
Unity支持向下兼容
如何在Mac OS中搭建Unity开发环境
Mac OS下的Unity界面
Unity的导航菜单栏位于屏幕顶部
Windows下的Unity界面
Windows下导航菜单栏可随窗口移动
打包与发布
File|Build Settings
只需选择对应的打包平台,Unity便可轻松实现跨平台游戏打包与发布。
Flash Player格式需要Java虚拟机的支持
实际开发中可通过消息传递或者插件的形式将游戏平台的相关代码加入到Unity工程中。
chap2编辑器的结构
Unity中包含的5大视图:场景视图、游戏视图、层次视图、项目视图、监测视图
项目视图:游戏的资源文件,比如游戏的贴图、动画模型、声音文件
游戏脚本、预设、材质、动画、自定义字体、纹理、物理材质、GUI皮肤
这些资源需要赋予层次视图中的某些游戏对象
在项目视图的左上角点击Create按钮,将弹出一个下拉列表,可以创建游戏的相关资源
保存在Assert文件夹中
将材质赋予游戏对象时,游戏对象将显示这个材质。
层次视图:这里可创建一些模型,只具备单一的3D网格
主要存放游戏场景中具体的游戏对象,比如摄像机、平面贴图、3D贴图、光源、箱子、球体、胶囊体、模型、平面和地形
对于3D游戏来说,摄像机可以让我们以不同的角度观察游戏世界。
层次视图中的游戏对象与工程视图中的游戏资源密切相关。
游戏对象创建完毕后,即可在场景视图中看到我们创建的游戏对象。
监测视图:主要用来呈现某个游戏对象或者游戏组件的一些说明与参数信息
展示选择对象的所有描述信息
修改完监测视图的参数后,在游戏视图中可直接看到修改后的效果。
平台设定
玩家设置
Edit|Project Settings|Player
场景视图:层次视图中创建的模型都会出现在场景视图当中,在场景视图中可以修改模型的位置、旋转的角度和缩放的大小等
主要存放游戏中的模型资源。
3个箭头代表3个坐标方向
红色为x轴方向,绿色为y轴方向,蓝色为z轴方向
游戏发布后在屏幕中显示的内容只可能是摄像机照射的一部分,所以动态移动摄像机的位置即可刷新屏幕显示区域。
创建游戏对象后,默认的材质是灰色的。
在层次视图中选择摄像机后,在场景视图右下角会出现游戏预览视图,从中可以清楚地看到摄像机目前所照射的部分。
游戏视图:是游戏最终发布后展示在屏幕中的效果,屏幕展示的内容为层次视图当中摄像机照射的部分。
场景文件以.unity为后缀
运行游戏后,即可在游戏视图中看到之前编辑的游戏效果。通常游戏开发中会存在多个摄像机,它们之间根据游戏剧情的需要进行相互切换。
在Unity编辑器上方还有3个重要的按钮,从左到右依次为运行游戏、暂停游戏和逐帧运行游戏。
【运行游戏】:用于开始运行当前游戏。
【暂停游戏】:用于暂停正在运行的游戏,该按钮必须在游戏运行时点击才有效果。
【逐帧运行游戏】:主要用于程序的调试,每点击一次,游戏运行一帧。
Unity支持在游戏运行过程中可以继续编辑游戏,比如如果游戏正在运行,那么在场景视图中移动模型的位置时,在游戏视图中可以直接看到模型发生了改变的效果。但是结束游戏的时候,所有数据又会还原成运行游戏之前的样子,这可能是Unity处于安全性的考虑。编辑游戏场景的时候,一定要确保游戏没有在运行当中,或者在游戏运行状态中将编辑后游戏的相关数值记录下来,然后结束游戏,最后再将编辑时记录的数值重新编辑在游戏当中。
2.7第一个游戏实例
项目命名为CodeList_2_1
在层次视图中分别创建游戏对象平面、立方体、球体、圆柱体、胶囊体
创建光源的方式如下:
层次视图中选择Create|Directional light菜单项
使用脚本控制模型的移动
在工程视图中点击Create|JavaScript菜单项来创建一条游戏脚本,命名为Script_02_01.js
可以使用拖曳的形式绑定到层次视图中任何一个游戏对象上,并且每一个游戏对象都可以绑定多条游戏脚本。
为了让模型之间具有物理的碰撞,需要给该模型添加一个刚体(Rigidbody)属性。添加方法很简单,首先在层次视图中选择立方体对象,在Unity导航菜单栏中选择组件|物理|刚体菜单项即可
chap3 GUI游戏界面
UI界面主要包括贴图、按钮和高级控件等。
GUI高级控件包括标签、按钮、输入框、拖动条等。
显示中文时需要修改脚本的编码格式,JavaScript中修改为UTF-8即可。
脚本只有绑定在对象身上时,才会执行它自身的生命周期。
可在监测视图中为脚本中的公用变量赋值。
只有公用变量才可以在编辑器中以拖曳对象或输入的形式赋值。
在声明变量时,在变量前方添加public关键字或未添加任何关键字表示该变量为公有变量。
如:
public var str:String;
var str:String;
在变量前方添加private关键字的变量为私有变量。私有变量不会出现在编辑器中,只能在脚本中使用。
如:
private var str:String;
使用Label控件,我们不仅可以输入字符串,还可以贴图。
按钮共有3个基本状态组成:未点击状态、击中状态、点击后状态。一般情况下,游戏界面的按钮只监
听“未点击状态”与“点击后状态”。
按钮可以分为两种:普通按钮和图片按钮。
输入框按钮用于监听用户输入的信息
工具栏常位于界面顶部或者底部,其中每个按钮可以使用贴图的形式展现。
滑动条可分为两种:水平滑动条和垂直滑动条。
滚动视图控件可设定一个滚动显示区域。如果横向或纵向的GUI控件超出了其显示区域,视图下方或者
右方将会出现滚动条。
群组视图控件可将多个视图全部放在一个群组当中。
所有视图都需要依赖窗口来显示。各种各样的游戏视图都属于窗口的子类。游戏界面可以由若干个窗口
组成,窗口又由若干个视图组成。
在项目视图中点击Create|GUI Skin菜单项创建一个GUI Skin。使用GUI Skin,可以修改任何系统提供
的控件皮肤。
在监测视图中可以清晰地看到GUI Skin可设置的皮肤控件。
我们使用GUI.skin=mySkin为当前GUI的皮肤赋值,而mySkin为外部创建的自定义皮肤。在Unity编辑器
中,使用拖曳的方式将自定义皮肤赋予代码中的mySkin皮肤对象即可。
自定义风格组件可以设置一组特殊的组件。
GUI为开发者提供了游戏布局的概念,并且在布局当中所有的坐标点都是相对坐标,所以使用GUI游戏界
面布局来制作界面将更有效地实现自适应屏幕。
GUI与GUILayout的区别
使用GUI制作界面的时候,需要给每一个控件设定显示区域,如果控件的显示坐标没有计算准确,还会出现控件重叠的情况,而GUILayout无须设定显示区域,系统会自动帮我们计算控件的显示区域,并且保证它们不会重叠。
之前介绍的大部分GUI控件都可以使用GUILayout进行绘制。
线性布局是以线性连续排列的形式将GUI控件有规律地显示在屏幕中,共分为两种:一种为水平线性布
局,另一种为垂直线性布局。默认的界面是以垂直线性布局的方式来排列。
在布局中,使用Space()方法可以设置控件之间的偏移量。
使用GUILayout.FlexibleSpace()方法设置对齐方式时,它会自动获取当前屏幕的宽或高,确保两个控
件相互对齐在屏幕的两端并且不会超出屏幕。
Unity支持所有.ttf的字符集,默认的字体为Arial。
在项目视图中选择Create|GUI Skin菜单项,创建一个GUI皮肤来设置我们的自定义字体。
Unity脚本默认的编码是Western(ISO latin 1),这种编码是不支持中文的。
Unitron也是Unity提供的一个脚本编辑器,它安装在Unity根目录中。
3.3 2D贴图与帧动画
2D贴图好比在屏幕中绘制了一张静态图片,其绘制方式有两种,第一种由GUI绘制,第二种是将贴图以
材质的形式绘制在游戏对象中。
在项目视图中将需要加载的图片存储在根目录Resources中。
在开发2D游戏时,不能使用GUI来实现。GUI的渲染效率比较低,并且也无法使用Unity引擎中独具特色的功能,比如物理引擎、粒子系统和特效等。
在Unity中制作2D游戏的方法如下:首先在游戏世界中创建一个面对象,它就是2D游戏的背景地图,并
且让摄像机直对着它;接着在背景地图上继续绘制图层,它依然由面对象组成,比如主角、敌人和道具
等;最后动态更新每个面对象身上的材质贴图即可实现帧动画。
因为默认的材质会将贴图中透明的部分渲染成白色,所以主角原本透明的北京被渲染成了白色。
为了让图片的背景呈透明状,需要设置一下材质的渲染通道。
在项目视图中选择主角的材质资源,接着在右侧的监测视图中找到Shader下拉列表,然后从中选择
Transparent|Diffuse菜单项即可。
游戏对象是可以添加游戏组件的,为了让主角与其他对象发生碰撞,可以给主角绑定一个刚体组件,操作方法是在层次视图中选择主角对象,接着在Unity导航菜单栏中选择组件|物理|刚体菜单项即可。
chap4游戏脚本
【
Unity3D培训图解Unity常用脚本类的继承关系(入门篇)
http://www.docin.com/p-1075196842.html
在Unity开发框架中有4个基本层次:工程(应用程序)、场景、游戏对象和组件。
在脚本中,整个应用程序和场景由Application类控制;而游戏对象和组件类均继承于Object类。
Unity中的常用脚本可以简单的分成如下四大类:
一、宏观控制类
包括:
Application——应用程序类
Input——输入类
GUI——图形输出类
Physics——物理引擎类
Resource——资源类
Time——时间类
等等
二、游戏对象类GameObject
三、组件类Component
角色控制器类继承于碰撞器类
MonoBehavior类并不直接继承于组件类,而是通过继承Behavior类间接的继承。
四、资源类
通过脚本创建资源或者修改资源本身的情况不是很多。
】
MonoDevelop脚本编辑器是一个开源项目,被Unity公司作为核心脚本开发环境来使用。
有4个比较重要的按钮,依次是停止调试、逐过程单步调试、逐语句单步调试和跳出当前。
Unity脚本的生命周期中由系统自身调用的几个比较重要的方法。
Update正常更新,用于更新逻辑。此方法每帧都会由系统自动调用一次。
LateUpdate推迟更新,此方法在Update方法执行完后调用,同样每一帧都调用。
Awake脚本唤醒,此方法为系统执行的第一个方法,用于脚本的初始化,在脚本的生命周期中只执行一
次。
FixedUpdate固定更新,在Unity导航菜单栏中,点击Edit|Project Settings|Time菜单项后,右侧的监
测视图将弹出时间管理器,其中Fixed Timestep选项用于设置FixedUpdate的更新频率,更新频率默认
为0.02s。
固定更新常用于移动模型等操作。因为固定更新每一帧调用的时间间隔都是完全一样的,所以模型的移动过程会比较均匀。
置于这个函数中的代码每隔一定间隔执行(固定的帧率)。它通常被用来Rigidbody中用力的时候。
void FixedUpdate () {
rigidbody.AddForce(Vector3.up);
}
Start此方法在Awake方法之后、Update方法之前执行,并且只执行一次。
OnDestroy当前脚本销毁时调用。
OnGUI绘制界面。它和Update方法一样,每一帧都在调用,只是它是用来绘制界面的。
4.3.2获取游戏对象
1、通过对象名称获取对象
GameObject.Find ("Script").GetComponent<GameManager> ().Players[i].LongCoinnum = rsp.m_mUserData.m_nUserCoins;
GameObject.Find ("Script").GetComponent<GameManager> ().Players[i].Hooknum =rsp.m_mXunLongData.m_nNuJian;
GameObject.Find ("Script").GetComponent<GameManager> ().Players[i].m_score =rsp.m_mUserData.m_nUserIntegrals;
使用GameObject.Find根据名称查找物体
public void AddScore(int scoreValue)
{
GameObject.Find("Canvas").GetComponent<Text>().text="Score:"+scoreValue;
}
2、通过标签获取单个游戏对象
GameObject.FindWithTag
GameObject.FindGameObjectWithTag
3、通过标签获取多个游戏对象
GameObject.FindGameObjectsWithTag
MyFightUI.s_Inst.m_HeroAttr[Hero.Heroindex].ShowItem(ItemID);
GameObject parent=MyFightUI.s_Inst.m_HeroAttr[Hero.Heroindex].gameObject;
GameObject[] ItemArr=GameObject.FindGameObjectsWithTag("ImageItem");
for(int i=0;i<ItemArr.Length;i++){
GameObject par=ItemArr[i].transform.parent.gameObject;
if(parent==par){
Destroy(ItemArr[i]);
PluginImport.s_Inst.strItem=string.Format("角色{0}实例化道具{1}之前先删除道具{2}",Hero.Heroindex,ItemID,ItemArr[i].name);
break;
}
}
4.3.3添加组件与修改组件
新创建的游戏对象本身并不具备任何特性,为了让它具备一些功能,就必须给其添加游戏组件。游戏组
件的种类非常多,常见的游戏组件有脚本类、网格类、粒子类、物理类、声音类和渲染类等。
4.3.5克隆游戏对象
【
//停止背景音乐
GameManager.Instance.BgMusic = false;
GameManager.Instance.m_Audio.Stop();
//结算界面背景音乐
if (!ResultBGMusicgbtp)
ResultBGMusicgbtp= Instantiate (ResultBGMusicgb, ResultPos.position, Quaternion.identity) as GameObject;
】
克隆游戏对象与创建游戏对象在效果的呈现方式是完全一样的,但是从执行效率上来讲,克隆游戏对象的效率要高。使用脚本克隆游戏对象在游戏中应用非常广泛,常用于一些完全相同并且数量庞大的游戏对象。
在代码中,需要使用Instantiate()方法克隆游戏对象。如图所示,点击【开始克隆实例】后,碗中的小球开始克隆对象并且完成克隆后5秒会自动销毁。
//球体对象
var obj:GameObject;
function Start()
{
//获得球体对象
obj=GameObject.Find("Sphere");
}
function OnGUI()
{
if(GUILayout.Button("开始克隆实例",GUILayout.Height(50))){
//克隆一个obj的实例
var clone:GameObject=Instantiate(obj,obj.transform.position,obj.transform.rotation);
//5秒后销毁实例
Destroy(clone,5);
}
}
Instantiate方法的返回值就是克隆后的游戏对象,Destroy方法的第一个参数为需要销毁的游戏对象,第二个参数表示延迟几秒后销毁。
4.4用脚本来控制对象的变换
3D世界中,任何一个游戏对象在创建的时候都会附带Transform(变换)组件,并且该组件是无法删除
的。
大多数游戏物体的操作是通过游戏物体的Transform和/或Rigidbody来做的。在行为脚本内部它们可以分别通过transform和rigidbody访问。
var localScale : Vector3
相对于父级物体变换的缩放。
// 弹匣显示在半透明遮罩下面
m_ImageClip[i].transform.SetSiblingIndex(m_ImageXbBg[i].transform.GetSiblingIndex());
localPosition相对于父级的变换的位置。如果该变换没有父级,那么等同于Transform.position。
// 旧UI移到屏幕之外即可,不必删除旧UI的代码
m_FightUI.transform.localPosition=new Vector3 (0,1000,0);
//m_FreeHero.transform.localPosition=new Vector3 (800,-50,0);
void OnPrintTankPos(int Joyindex)
{
#if UNITY_ANDROID && !UNITY_EDITOR
#else
if (TankScript[Joyindex]!=null)
{
m_flag++;
if(m_flag%2==1){
Vector3 pos1=TankScript[Joyindex].transform.localPosition;
string str=string.Format("x={0},y={1},z={2}",pos1.x,pos1.y,pos1.z);
strTest=str;
}
else{
strTest="";
}
}
#endif
}
m_ImagePressYTip1[i].transform.localPosition+=new Vector3 (-4.2f,0,0);
m_ImagePressYTip2[i].transform.localPosition+=new Vector3 (-4.2f,0,0);
m_ImageWeapon1[i].transform.localPosition+=new Vector3 (-4,0,0);
m_ImageWeapon2[i].transform.localPosition+=new Vector3 (-4f,0,0);
var parent : Transform
物体变换的父级。
改变父级,将修改相对于父级的位置、缩放和旋转角度,但是保持和世界坐标的位置、旋转角度和缩放相同。
GameObject ImageItemPrefab=ItemSpawn.s_Inst.m_ImageItemPrefabs[ItemID-1];
GameObject ImageItem=Instantiate(ImageItemPrefab,ImageItemPrefab.transform.position,Quaternion.identity) as GameObject;
ItemSpawn.s_Inst.m_ImageItem[ItemID-1]=ImageItem;
MyFightUI.s_Inst.m_HeroAttr[Hero.Heroindex].m_ItemID=ItemID;
ImageItem.transform.parent=MyFightUI.s_Inst.m_Hero[Hero.Heroindex].transform;
ImageItem.transform.localPosition=new Vector3 (16.5f, 58, 0);
// 绕着Y轴每帧旋转5度
function Update(){
transform.Rotate(0,5,0);
}
// 向前移动一个物体
function Update(){
transform.Translate(0,0,2);
}
4.4.3平移游戏对象
m_transform.Translate (new Vector3(0,0,-m_speed*Time.deltaTime));
向前移动Vector3.forward
向后移动-Vector3.fwd
向左移动Vector3.left
向右移动Vector3.right
【
福建农林大学东方学院计算机科学系毕业设计(论文)
http://www.docin.com/p-780503552.html
5.4对小鸟碰撞后的Level_3.cs脚本控制
GameObject bird_p=Resources.Load("Prefab/Bird") as GameObject;
m_Bird=Instantiate(bird_p) as GameObject;
m_Bird.transform.parent=this.transform.GetChild(0);
m_Bird.transform.localPosition=BirdPoint;
m_Bird.transform.localEulerAngles=new Vector(0.0f,0.0f,0.0f);
m_Bird.transform.localScale=new Vector(1.0f,1.0f,1.0f);
5.6小鸟方向的控制
bird.cs
//小鸟的初始位置
Vector3 BirdPoint=new Vector(0.0f,0.0f,0.0f);
BirdPoint=this.transform.localPosition;
W键
this.transform.localPosition+=new Vector(0.0f,250.0f*Time.deltaTime,0.0f);;
//三维坐标中定义Y轴为向上或向下,控制其向上行走速度,每帧+250像素
S键
this.transform.localPosition-=new Vector(0.0f,250.0f*Time.deltaTime,0.0f);;
//三维坐标中定义Y轴为向上或向下,控制其向下行走速度,每帧+250像素
A键
this.transform.localPosition-=new Vector(250.0f*Time.deltaTime,0.0f,0.0f);;
//三维坐标中定义X轴为向左或向右,控制其向左行走速度,每帧+250像素
D键
this.transform.localPosition+=new Vector(250.0f*Time.deltaTime,0.0f,0.0f);;
//三维坐标中定义X轴为向左或向右,控制其向右行走速度,每帧+250像素
20160421添加:
// Unity3D Transform中有关旋转的属性和方法测试
using UnityEngine;
using System.Collections;
public class enlerAngles : MonoBehaviour {
// // A键、D键旋转
//var eulerAngles : Vector3
//效果:与Quaternion.enlerAngles基本相同,用来设定物体的旋转角度,但不要分别设置xyz,要整体赋值。
// public float yRotation = 5.0F;
// void Update() {
// yRotation += Input.GetAxis("Horizontal");
// transform.eulerAngles = new Vector3(10, yRotation, 0);
// }
// // A键、D键、W键、S键旋转
//var rotation : Quaternion
//效果:代表了物体的旋转,不能直接为transform.rotation赋值。可以使用各种Quaternion的方法。
// public float smooth = 2.0F;
// public float tiltAngle = 30.0F;
// void Update() {
// float tiltAroundZ = Input.GetAxis("Horizontal") * tiltAngle;
// float tiltAroundX = Input.GetAxis("Vertical") * tiltAngle;
// Quaternion target = Quaternion.Euler(tiltAroundX, 0, tiltAroundZ);
// transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smooth);
// }
/*
function Rotate (eulerAngles : Vector3, relativeTo : Space = Space.Self) :void
效果,使物体旋转一个基于欧拉角的旋转角度,eulerAngles.z度围绕z轴,eulerAngles.x度围绕x轴,eulerAngles.y度围绕y轴。vector3可以变成3个分开的float值。
*/
// void Update() {
//// transform.Rotate(Vector3.right * Time.deltaTime*5);
// transform.Rotate(Vector3.up * Time.deltaTime*5, Space.World);
// }
/*
function Rotate (axis : Vector3, angle : float, relativeTo : Space = Space.Self) : void
效果:按照angle度围绕axis轴旋转。
*/
void Update() {
transform.Rotate(Vector3.right, Time.deltaTime*5);
transform.Rotate(Vector3.up, Time.deltaTime*5, Space.World);
}
/*
function RotateAround (point : Vector3, axis : Vector3, angle : float) : void
效果: 以point为中心点,以axis为轴进行旋转,类似于围绕某一点公转。
*/
// public Transform target;
// Quaternion rotation;
// void Update()
// {
// transform.RotateAround(transform.position, Vector3.up, 20 * Time.deltaTime);
// }
/*
function LookAt (target : Transform, worldUp :Vector3 =Vector3.up) : void
效果:使物体绕y轴旋转,z轴一直指向target,所以顾名思义叫LookAt。
*/
// public Transform target;
// void Update() {
// transform.LookAt (target);
// }
}
】
任何一个游戏脚本都需要去继承MonoBehaviour这个类,只是在创建JavaScript脚本的时候,系统会将其类名与继承关系隐藏起来。
在脚本相互调用的时候,首先需要通过GetComponent方法来获取脚本对象,然后通过脚本对象再去调用
JavaScript或C#脚本中的方法。
工具类
时间Time类主要用来获取当前的系统时间。
等待WaitForSeconds
随机数Random.Range
数学类Mathf
四元数Quaternion
下面简要说明这4个时间的具体含义。
当前游戏时间Time.time:从游戏开始后开始计时,表示截止目前共运行的游戏时间。
上一帧所消耗的时间Time.deltaTime:获取Update()方法中完成上一帧所消耗的时间。
固定增量时间Time.fixedTime:FixedUpdate()方法中固定消耗的时间总和。FixedUpdate()每一帧更新的时间可通过导航菜单栏Edit|Project Settings|Time菜单项去设置。
上一帧所消耗固定时间Time.fixedDeltaTime:固定更新上一帧所消耗的时间。
在程序中使用WaitForSeconds()方法可以以秒为单位让程序等待一段时间,此方法可直接使游戏主线程进入等待状态。该方法的返回值为IEnumerator类型,在需要等待的地方调用方法yield return new WiatForSeconds(2),该方法中的参数表示主线程等待的秒数。
WaitForSeconds()方法用于通知游戏主线程等待。一定要将该方法的返回类型修改为IEnumerator,否则无法实现等待。
chap5游戏元素
游戏元素可分为常用元素与不常用元素两种。
5.3光源
在3D游戏中,光源可以提升游戏的画面质感。在新创建的场景中,默认是没有光源的,场景非常昏暗,所以开发中必须在场景中添加光源组件。
Unity引擎一共为开发者提供了3种不同的光源类型——点光源、聚光灯和平行光,它们可以模拟自然界中任何一种光。光源属于游戏对象,可在场景视图中编辑它的位置以及光照的相关参数。此外,光源还支持移动、旋转和缩放等操作。
// 随着时间增加光照的范围,以2单位/秒改变半径
function Update()
{
light.range+=2.0*Time.deltaTime;
}
5.5.1摄像机
一些特殊的物体有快捷方式,如主相机使用Camera.main。
作为一个游戏对象,摄像机存在Scene视图中,它可以设置自身的位置、照射的方向、照射的面积和照射的图层等。
Clear Flags:背景显示内容,默认是天空盒子
Background:背景显示颜色
Culling Mask:用于是否显示某些层,默认为Everything(全部显示)。
Projection:摄像机的类型
Depth:摄像机的深度。若存在多个摄像机,先渲染该值较小的摄像机。【坦克战斗场景:FightResultCamera Depth为3,FightUICamera Depth为4】
之前我们介绍过如何使用代码克隆游戏对象,预设与它的原理基本一样,只是表现方式不同而已。使用代码克隆对象适合在对象数量不确定时使用,而预设更适合在编辑器中编辑游戏场景时使用,适合对象数量已知的情况。
创建预设的方式如下,在项目视图中点击Create|Prefab菜单项即可。创建完预设后,是一个空对象,然后在层次视图中创建一个立方体对象,将其拖动至右侧创建的预设对象来为预设资源赋值。
将预设文件拖动至层次视图中,即可完成对象的创建。使用预设可以减少内存开支。
此外,使用预设还有一个重要的优势,那就是编辑预设资源后,场景中所有使用预设克隆后的游戏对象将全部适应新编辑的资源,无须一个一个给场景中的对象赋值。
chap6物理引擎
物理引擎就是在游戏中模拟真实的物理效果。
Unity的物理引擎使用的是NVIDIA(英伟达)的PhysX。
6.1刚体
6.1.1简单使用
选择Component->Physics->Rigidbody菜单即可。
刚体各个属性的含义:
m_Rigidbody.angularVelocity=Vector3.zero;
Angular Drag角阻力,数值越大自身旋转的速度减慢得就越快
gameObject.GetComponent<Rigidbody>().isKinematic=false;是否受物理的影响
gameObject.GetComponent<Rigidbody>().useGravity=true;是否使用重力
Constraints冻结,停止某个轴向感应物理引擎的效果
m_Rigidbody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;冻结x轴旋转、y轴旋转和z轴旋转
m_Rigidbody.constraints = RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezePositionZ;冻结x轴方向、y轴方向和z轴方向
m_Rigidbody.constraints = RigidbodyConstraints.None;
6.1.3力
Unity中力的方式有两种:
第一种为普通力,需要设定力的方向与大小;
m_Rigidbody.AddForce(extraGravityForce);
第二种为目标位置力,需要设定目标点的位置,该物体将朝向这个目标位置施加力。
shootHit.rigidbody.AddForceAtPosition (force, shootHit.point, ForceMode.Impulse);
6.1.4碰撞与休眠
碰撞的3个重要的系统方法。
OnCollisionEnter
OnCollisionStay
OnCollisionExit
6.2碰撞器
Unity一共为对象提供了5种碰撞器,分别是盒子碰撞体、球体碰撞体、胶囊碰撞体、网格碰撞体、车轮碰撞体。
【
脚本组件在玩家人物角色附近(某个最小距离)时才被激活。可以设置一个球体范围碰撞器,当玩家的人物角色进入球体范围时,启用脚本组件。
void OnTriggerEnter(Collider hit){
if(hit.CompareTag("Player"))
enabled=true;
}
void OnTriggerExit(Collider hit){
if(hit.CompareTag("Player"))
enabled=false;
}
触发器事件传递碰撞物体的Collider组件到处理函数。
OnTriggerStay给我们一个到碰撞器的引用。从这个碰撞器我们可以获取附加到其上的刚体。
fucntion OnTriggerStay(other:Collider)
{
// 如果另一个碰撞器也有一个刚体,应用一个力到它上面
if(other.rigidbody)
{
other.rigidbody.AddForce(0,2,0);
}
}
或者我们可以通过碰撞器获取附加在同一物体上的任何组件。
fucntion OnTriggerStay(other:Collider)
{
// 如果另一个碰撞器附加了OtherScript,调用它上面的DoSomething
if(other.GetComponent(OtherScript))
{
other.GetComponent(OtherScript).DoSomething();
}
}
】
chap7输入与控制
Unity为开发者提供了Input这个类库,其中包括键盘事件、鼠标事件和触摸事件等一切跨平台所需要的
控制事件。
PC平台下的基础事件。
一般的PC都会有104个不同的按键。
按下事件
Input.GetKeyDown
监听键盘上的5个按键:W,S,A,D,空格键
抬起事件的产生完全依赖按下事件
Input.GetKeyUp
长按事件
Input.GetKey
任意键事件
Input.anyKeyDown
Input.anyKey
按下事件
Input.GetMouseButtonDown
鼠标当前位置的三维坐标
Input.mousePosition
鼠标的抬起事件必须依赖按下事件
Input.GetMouseButtonUp
长按事件
Input.GetMouseButton
7.4模型与动画
【
20151111-Revision822结算UI动画提交
// MVP共8个Animator对象
public Animator[] m_FightResultUIanimator;
// 其它共12个Animation对象
public Animation[] m_AAnim;
public Animation[] m_BAnim;
CountDownEnd函数:
m_AAnim[4].Play("AWP_tuichang Animation");
m_BAnim[4].Play("BWP_tuichang Animation");
for (int i=0; i<4; i++) {
string name=string.Format("A{0}_tuichang Animation",i+1);
m_AAnim[i].Play(name);
string name1=string.Format("B{0}_tuichang Animation",i+1);
m_BAnim[i].Play(name1);
}
if (m_bAWin) {
m_AAnim [5].Play ("ImageA_tuichang Animation");
} else {
m_BAnim[5].Play("ImageB_tuichang Animation");
}
print ("m_nMVPindex="+m_nMVPindex);
m_FightResultUIanimator[m_nMVPindex].gameObject.SetActive(false);
】
7.4.2设置3D动画
模型的骨骼动画同样包含在模型中。
Animation组件中记录着该模型的动画信息。下面简要介绍其中各个属性的含义。
Animation:默认的动画名称
Size:动画数量
Play Automatically:是否自动播放动画
Animate:勾选后表示动画播放时接收物理碰撞
Culling Type:模型的类型
7.4.3播放3D动画
animation.Play()方法用于播放动画,其参数为所播放动画的名称,不写参数表示播放默认动画。
7.5 GL图像库
GL图像库主要功能是使用应用程序来绘制常见的2D与3D几何图形。这些图形具有一定的特殊性,它们不属于3D网格图形,只会以面的形式渲染。
使用GL图像库,可在屏幕中绘制2D几何图形,并且该几何图形将永远显示在屏幕当中,不会因摄像机的移动而改变。
绘制2D图像时,需要使用GL.LoadOrtho()方法将图形映射到平面中;如果绘制的是3D图形,就无须使用此方法。
使用GL图像库时,需要将所有绘制相关的内容写在OnPostRender()方法中。有关GL图像库的脚本需要绑定在层次视图中的摄像机对象当中,否则将无法显示绘制的图形
。
Unity中平面坐标系的原点(0,0)位于左下角,每个点的横坐标和纵坐标都应当是0与1之间的浮点数,而真实的像素坐标需要根据这个浮点数来计算。
我们使用GL.Begin()方法开始绘制图形,参数为绘制图形的类型,包括线段、三角形和四边形等。最后需要使用GL.End()方法结束图形绘制。所有图形的绘制都必须在
这两个方法之间完成。
7.5.6线渲染器
线渲染器主要用于在3D世界中渲染线段。与GL图像库渲染相比,它更加专业,可以控制线段的粗细程度以及线段的数量,并且以网格对象的形式出现在3D世界中。
线渲染器以组件的形式出现在Unity当中,所以需要将它绑定在某个游戏对象当中。
7.5.7网格渲染
任何一个模型都由若干网格面组成,而每一个面又由若干个三角形组成。也就是说,模型是由若干个三角形面组成的。
chap8持久化数据
Unity提供了一个用于本地持久化保存与读取数据的类——PlayerPrefs。它的工作原理是以键值对的形式将数据保存在文件中。
8.1.1保存与读取数据
PlayerPrefs类可保存与读取3种基本数据类型,它们是浮点型、整型和字符串型。
SetFloat
SetInt
SetString
GetFloat
GetInt
GetString
8.1.2删除数据
8.2自定义文件
PlayerPrefs是轻量级的存储。
8.3.1创建关卡
游戏关卡也可以称为游戏场景。
8.3.2切换关卡
如需使用代码切换关卡,首先需要在应用程序中授权该关卡。
点击【Add Current】按钮可为当前游戏关卡授权。
public void OnAnimEventFightResultUILeave()
{
Application.LoadLevel(0);// ID为0的关卡表示程序运行时第一个进入的场景
Debuger.Log(string.Format("进入上一个场景"));
}
chap9多媒体与网络
总的来说,音频可以分为两种,一种为游戏音乐,另一种为游戏音效,前者多为较长的音乐,如游戏背
景音乐;而后者则多是较短的音效。
Unity 3D游戏引擎共支持4种音乐格式的文件,具体如下。
aiff:适用于较短的音乐文件,可用作游戏音效。
wav:适用于较短的音乐文件,可用作游戏音效。
mp3:适用于较长的音乐文件,可用作游戏音乐。
ogg:适用于较长的音乐文件,可用作游戏音乐。
音频是一个游戏组件,因此需要将其绑定在游戏中的某个对象上才能发挥作用。
系添加音频组件的方法如下,首先在Unity菜单栏中选择GameObject|CreateEmpty菜单项,创建一个空游戏对象,然后在层次视图中选择该对象,接着在导航菜单栏中选择Component|Audio|Audio Source菜单项,此时音频组件将被绑定在该对象上。
将goldFruit.mp3文件拖曳到项目资源视图中,并将音乐文件放置在sound文件夹内。然后选择已经绑定音频组件的游戏对象,此时右侧的监测视图中将出现该对象的音频组件信息。
将声音文件拖曳至右侧的Audio Clip(音频剪辑),这样就完成了音频组件的赋值。
GameObject重命名为audio
将audio.cs(用记事本打开另存为utf-16格式,否则在MonoDevelop中会出现乱码)绑定在摄像头上,将audio游戏对象拖动赋值给Music这个AudioSource这个对象。统在播放音频时,需要使用AudioSource组件对象。
在Unity中,我们需要使用MovieTexture(电影纹理)来添加游戏视频。MovieTexture对象继承自纹理
对象,所以其用法与纹理基本一样。Unity支持的视频格式包括.mov、.mpg、.mpeg、.mp4、.avi和.asf
。在播放视频之前,需要先创建电影纹理。
和音频组件一样,电影纹理也需要绑定在某个游戏对象上才能发挥其效果。一般情况下,游戏视频都是
以平面形式展现的,所以可在游戏场景中创建一个Plane(面)对象。
电影纹理不仅可以在对象中播放,也可以在GUI在播放,不过在GUI中播放的效率要比在游戏对象中低一
些,但是在GUI中可随意修改视频的尺寸。
Plane对象属于网格模型,而网格模型的尺寸是无法轻易修改的,所以在播放视频时,它不如GUI灵活。
9.3网络
网络下载功能在游戏中已经非常普遍,它就好比游戏对外的接口,可动态拓展游戏的内容,比如下载游戏场景、人物模型、游戏音乐和游戏视频等。资源下载完
毕后,可被程序读取合并到游戏中。
Unity为开发者提供了WWW下载类,它的原理是以GET请求的形式向服务器请求数据,然后等待服务器返回,在向服务器请求数据时,将请求的地址传入其构造函数即可开始下载。在下载过程,可以使用Yield()方法或者isDone()方法来判断下载是否完成。
9.3.1下载文件
文件下载成功后,会保存在WWW对象中。使用Unity提供的下载方法,开发者可以任意下载文件,但需要注意的是,目前系统只支持PNG和JPG类型贴图文件的下载。如果下载失败,系统会抛出异常,并使用Debug.Log(www.error)方法打印错误信息。
【
Unity网络多玩家游戏开发教程
http://www.docin.com/p-963613938.html
chap1 Unity自带网络功能
Unity提供了名为NetworkView的组件。
Network.Instantiate on the receiving client failed because the asset couldn't be found in the project
http://www.csdn123.com/html/topnews201408/34/434.htm
NetworkView组件
为游戏对象添加NetworkView组件的方法是,单击Component|Miscellanenous|Network View命令
State Synchronization:表示要同步(串行化)的状态信息
此属性有3个可选项。
Off表示不需要同步任何状态;
Reliable Delta Compressed表示使用可信任的数据差异压缩传输方式,且只传输变化了的数据,若没有变化,那么就不会传输任何
数据;
Unreliable表示要使用不信任的数据传输方式,每次都传输全部的数据,每次都传输全部的数据,即使数据没有发生变化(需要占用
更大的带宽)。
Observed:表示要同步的信息的类型
ID:唯一的表示特定对象上的NetworkView组件。
乒乓球的游戏逻辑
Ball.cs
//起始速度
float StartSpeed=5f;
//最大速度
float MaxSpeed=20f;
//当前速度
float currentSpeed;
//当前运动方向
Vector2 currentDir;
//是否重新发球
bool resetting=false;
//朝指定方向移动球体
Vector2 moveDir=currentDir*currentSpeed*Time.deltaTime;
transform.Translate(new Vector3(moveDir.x,0f,moveDir.y));
OnTriggerEnter
//与球场上下边界发生碰撞
if(other.tag=="Boundary"){
//反转三维坐标中Z轴的值,二维坐标中Y轴的值
currentDir.y*=-1;
}
//与球拍发生碰撞
if(other.tag=="Player"){
//反转三维坐标中X轴的值,二维坐标中X轴的值
currentDir.x*=-1;
}
//与球场界限发生碰撞
if(other.tag=="Goal"){
//重新发球
StartCoroutine(resetBall());
//加分
other.SendMessage("GetPoint",SendMessageOptions.DontRequireReceiver);
//增加速度
currentSpeed+=SpeedIncrease;
//检测乒乓球的速度,是否在指定的范围之内
currentSpeed=Mathf.Clamp(currentSpeed,StartSpeed,MaxSpeed);
IEnumerator resetBall()
{
resetting=true;
yield return new WaitForSeconds(3f);
Start();
resetting=false;
}
球拍的游戏逻辑
Paddle.cs
】
chap10游戏实例——突出重围
Unity已经将脚本转化为MVC模式,并且进行了细致的划分。比如OnGUI负责UI的绘制,它就是视图组件
;Update、LateUpdate和FixedUpdate负责逻辑更新,属于模型组件;而鼠标、键盘和手柄的事件就是
控制器组件。它们相互通信共同完成游戏的主循环。