本文主要是介绍Unity3D手机游戏开发-金玺曾读书摘要(2015-4-27 19:01、2016-4-11 10:39),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
http://web01264.w31.vhost002.cn/downloads/Unity官方公布热更新方案性能对比.pdf
苹果禁止了C#的部分反射操作,禁止JIT(即时编译,程序运行时创建并运行新代码),不允许逻辑热更新,只允许使用AssetBundle
进行资源热更新。
Android应用的热更新
将执行代码预编译为assembly dll。
将代码作为TextAsset打包进Assetbundle。
运行时,使用Reflection机制实现代码的功能。
更新相应的Assetbundle即可实现热更新。
Android与iOS热更新的异同
苹果官方禁止iOS的程序热更新;JIT在iOS下无效。
热更新方案:Unity+Lua插件。
使用Lua插件进行iOS热更新的原理
脚本转化为文本资源(如同纹理、音频等)
Lua脚本可直接解释执行
更新资源的形式更新程序
Unity热更新的注意点
需要更新的代码、资源,都必须打包成AssetBundle(建议使用未压缩的格式打包)
熟悉Unity的几个重要的路径
Resources(只读)
StreamingAssets(只读)
Application.dataPath(只读)
Application.persistentDataPath(可读写)
重要路径之Resources
Resources文件夹下的资源无论使用与否都会被打包
资源会被压缩,转化成二进制
打包后文件夹下的资源只读
无法动态更改,无法做热更新
使用Resources.Load加载
重要路径之StreamingAssets
流数据的缓存目录
文件夹下的资源无论使用与否都会被打包
资源不会被压缩和加密
打包后文件夹下的资源只读,主要存放二进制文件
无法做热更新
WWW类加载(一般用CreateFromFile,若资源是AssetBundle,依据其打包方式看是否是压缩的来决定)
相对路径,具体路径依赖于实际平台
Application.streamingAssetsPath
iOS:Application.dataPath+"/Raw"或Application/xxxxxxxx-xxxx-xxxx-xxxx--xxxxxxxxxxxx/xxx.app/Data/Raw
重要路径之Application.dataPath
游戏的数据文件夹的路径(例如在Editor中的Assets)
很少用到
无法做热更新
iOS路径:
Application/xxxxxxxx-xxxx-xxxx-xxxx--xxxxxxxxxxxx/xxx.app/Data
重要路径之Application.persistentDataPath
持久化数据存储目录的路径(沙盒目录,打包之前不存在)
文件夹下的资源无论使用与否都会被打包
运行时有效,可读写
无内容限制,从StreamingAsset中
读取二进制文件或从AssetBundle读取文件来写入PersistentDataPath中
适合热更新
iOS路径:Application/xxxxxxxx-xxxx-xxxx-xxxx--xxxxxxxxxxxx/Documents
支持Unity iOS热更新的各种Lua插件的对比
uLua(asset store)
uLua插件源生版本,开山鼻祖
不会产生静态代码
反射机制,效率低下,速度慢,gc alloc频繁
已停止更新维护,不支持Unity 5.x,淡出主流
uLua & cstoLua
开发平台成熟稳定,Bug修复迅速
开发者众多,资源丰富
静态方法,性能优
有成功商业产品案例
都是基于原声版本的改进;未来,两者会合并成一个插件
sLua
静态方法,性能优
核心代码简洁
资源较少,开发平台不够成熟稳定
无成功商业产品案例
基于原声版本的改进
C#Light(L#)
淡出主流
uniLua
C#实现的Lua虚拟机,非完整方案
淡出主流
金玺曾
2013年8月出版
前言
全书通篇以实例为基础
作者 金玺曾
2013年4月11日
chap3第一人称射击游戏
在本章的内容中,将涉及摄像机控制、物理、动画、智能寻路等。
3.1策划
场景中只有一个主角和一种敌人。
3.1.1游戏介绍
在游戏场景中,会有若干个敌人的出生点,它会定时生成一些敌人,它们会寻找并攻击主角,游戏的目的就是生存下去,消灭更多敌人,获取更多分。
3.1.2 UI界面
包括主角的生命值、弹药数量、得分和瞄准星。
游戏失败后提供一个按钮重新开始游戏。
3.1.3主角
我们看不到主角本人,在屏幕上看到的是一支端在胸前的M16机关枪。按键盘的W、S、A、D键控制主角前后左右行动,移动鼠标旋转视角,按鼠标左键进行射击。
3.1.4敌人
敌人只有一种,是一个护士模样的僵尸,它将具有智能寻路功能,躲避障碍物,并攻击主角。
3.2游戏场景
这个场景使用了Lightmap和Light Probe表现静态和动态模型的光影效果。
在菜单栏选择【Component】->【Physics】->【Mesh Collider】为其添加多边形碰撞体组件。
3.3主角
需要为主角创建碰撞体,并控制其移动。
3.3.1角色控制器
在菜单栏选择【GameObject】->【Create Empty】创建一个空的游戏体,将它的Tag设为Player,它便是我们的主角。
在菜单栏选择【Component】->【Physics】->【Character Controller】为主角添加一个角色控制器组件,使用这个组件提供的功能,我们将可以实现在控制主角移动的同时与场景的碰撞产生交互,比如在行走时不会穿到墙里面去。
为主角再添加一个Rigidbody组件,取消选择Use Gravity去掉重力模拟,并选中Is Kinematic使其不受物理演算影响,这样我们才能使用脚本控制其移动。在Character Controller组件中需要调整碰撞体的位置和大小。
3.3.2摄像机
接下来我们将在Player.cs脚本中添加少许代码,使摄像机伴随着主角移动。
3.3.3武器
接下来我们将把武器绑定到摄像机上,使其随着主角移动。
3.4敌人
3.4.1寻路
Unity的寻路系统分为两部分,一部分是对场景进行设置,使其满足寻路算法的需求。另一部分是设置寻路者。
3.4.2设置动画
3.5UI界面
这一次我们将使用另一种方式,直接在场景中创建2D贴图表示UI界面。
3.6交互
3.7出生点
3.8小地图
小结
本章完成了一个完整的第一人称射击游戏实例。
chap4塔防游戏
本章将使用Unity完成一款塔防游戏。我们将在Unity内创建二维数组保存场景信息,自定义路点引导敌人行动,还将涉及摄像机控制,读取XML文件,自定义按钮等。
小结
本章完成了一个塔防游戏的实例,内容较多,我们使用二维数组定义场景中的单元格数据,制作引导敌人行动的路点,并添加一些简单的编辑器功能帮助设置路点。
5.7贴图
对于作为模型材质使用的图片,其大小必须是为2的N次方。通常会将其Texture Type设为默认的Texture类型,将Format设为Compressed模式进行压缩。
如果图片将作为UI使用,需要将Texture Type设为GUI。值得注意的是Format的设置。
5.8 3D模型导出流程
5.8.1 3ds Max静态模型导出
3ds Max是最流行的3D建模、动画软件,可以使用它来完成Unity游戏中的模型或动画,最后将模型或动画导出为FBX格式到Unity中使用。在静态模型(没有动画)制作过程中,可以遵循下列步骤和规范:
步骤08:将导出的模型和贴图复制粘贴到Unity工程路径Assets文件夹内的某个位置即可导入到Unity工程中。
5.8.2 3ds Max动画模型导出
动画模型是指那些绑定了骨骼并可以动画的模型,其模型和动画通常需要分别导出。
5.8.3 3ds Max动画导出
动画文件可以与模型文件分开保存,但动画文件中的骨骼与层级关系一定要与模型文件一致。当导出动画的时候,不需要选择模型,只需要选择骨骼和Helper物体导出即可。
动画文件的命名需要按“模型名@动画名”这样的格式命名,比如模型命名为Player,动画文件即可命名为Player@idle,Player@walk等。
5.8.4 Maya模型导出
Maya也是一款非常流行且功能强大的3D动画软件,它的内部坐标系统与Unity一样都是Y轴向上,非常适合完成Unity游戏的模型工作。
在Maya中完成模型的制作可以遵循下列步骤:
步骤06:选择需要导出的模型,在菜单栏选择File|Export Selection,将导出格式设为FBX,选择Export打开设置窗口。如果不需要导出动画,可以取消选中Animation,然后将Units设为Centimeters,最后按Export导出。
5.9动画
Unity4.0引入了全新的Mecanim动画系统,它提供了更强大的功能,使用一个叫状态机的系统控制动画逻辑,更容易实现动画过渡、IK、动画retargeting(将同一个动画使用到不同的模型上)等功能。使用Mecanim动画系统的基本步骤如下:
步骤01:将从3D动画软件中导出的FBX文件复制到Unity工程中。一个模型可以拥有多个动画,模型与动画一定要有相同的骨骼层级关系。
chap7基于TCP/IP协议的聊天实例
在VS中编译工程,在当前工程的bin目录内会出现一个UnityNetwork.dll文件,我们将把它使用到聊天客户端和服务器端内。
聊天客户端将在Unity中完成。在Unity中有两种方式使用前面完成的网络引擎,一种方法是直接将UnityNetwork.dll复制到Unity工程Assets目录的任何地方,另一种方式是直接将原始代码文件复制到Unity工程内,但需要将namespace去掉。
创建脚本ChatClient.cs,并将其指定给场景中的游戏体。这是一个标准的Unity脚本,它包括一个简单的输入框UI用于输入聊天信息,还包括一个按钮发送聊天信息。
Protobuf除了可以应用到网络中,也可以应用到文件存储中。
http://download.csdn.net/download/wsyzyrxp1/9154163
D:\protoGen\ProtoBufTransForm>protogen -i:PlanetProto.txt -o:BjoyProto.cs
protobuf-net:protogen - code generator for .proto
proto协议
package chat;
message UserChat{
required int32 m_nUserID = 1;
optional string m_strNickName = 2 [default = ""];
required string m_strMessage = 3;
}
包体长度=34-18=16
//package ServerMessage;对应using ServerMessage;
message SignUpResponse
{
optional int32 errorCode = 1;
optional float version = 2;
{
optional int32 errorCode = 1;
optional float version = 2;
}
包体长度=5=23-18
message LogonReqMessage{
required int64 acctID = 1;
required string passwd = 2;
}
包体长度=20=38-18
enum UserStatus{
OFFLINE = 0; //表示处于离线状态的用户
ONLINE = 1; //表示处于在线状态的用户
}
message UserInfo{
required int64 acctID = 1;
required string name = 2;
required UserStatus status = 3;
}
包体长度=16=34-18
message LogonRespMessage{
required bool logonResult = 1;
required UserInfo userInfo = 2;
}
包体长度=20=38-18
包体长度=5=23-18
message LogonReqMessage{
required int64 acctID = 1;
required string passwd = 2;
}
包体长度=20=38-18
enum UserStatus{
OFFLINE = 0; //表示处于离线状态的用户
ONLINE = 1; //表示处于在线状态的用户
}
message UserInfo{
required int64 acctID = 1;
required string name = 2;
required UserStatus status = 3;
}
包体长度=16=34-18
message LogonRespMessage{
required bool logonResult = 1;
required UserInfo userInfo = 2;
}
包体长度=20=38-18
///注册事件处理方法
PacketManager.Instence.RegistDoProcess (0x1234, OnProcessPacket);
PacketManager.Instence.RegistDoProcess (0x1235, OnProcessPacket1);
PacketManager.Instence.RegistDoProcess (0x1034, OnProcessPacket2);
PacketManager.Instence.RegistDoProcess (0x1134, OnProcessPacket3);
PacketManager.Instence.RegistDoProcess (0x1334, OnProcessPacket4);
///注册解析数据包方法
PacketManager.Instence.RegistParserProcess (0x1234, CDecoder.ProcessParserPacket<chat.UserChat>);
PacketManager.Instence.RegistParserProcess (0x1235, CDecoder.ProcessParserPacket<chat.SignUpResponse>);
PacketManager.Instence.RegistParserProcess (0x1034, CDecoder.ProcessParserPacket<chat.LogonReqMessage>);
PacketManager.Instence.RegistParserProcess (0x1134, CDecoder.ProcessParserPacket<chat.UserInfo>);
PacketManager.Instence.RegistParserProcess (0x1334, CDecoder.ProcessParserPacket<chat.LogonRespMessage>);
PacketManager.Instence.RegistDoProcess (0x1234, OnProcessPacket);
PacketManager.Instence.RegistDoProcess (0x1235, OnProcessPacket1);
PacketManager.Instence.RegistDoProcess (0x1034, OnProcessPacket2);
PacketManager.Instence.RegistDoProcess (0x1134, OnProcessPacket3);
PacketManager.Instence.RegistDoProcess (0x1334, OnProcessPacket4);
///注册解析数据包方法
PacketManager.Instence.RegistParserProcess (0x1234, CDecoder.ProcessParserPacket<chat.UserChat>);
PacketManager.Instence.RegistParserProcess (0x1235, CDecoder.ProcessParserPacket<chat.SignUpResponse>);
PacketManager.Instence.RegistParserProcess (0x1034, CDecoder.ProcessParserPacket<chat.LogonReqMessage>);
PacketManager.Instence.RegistParserProcess (0x1134, CDecoder.ProcessParserPacket<chat.UserInfo>);
PacketManager.Instence.RegistParserProcess (0x1334, CDecoder.ProcessParserPacket<chat.LogonRespMessage>);
//发送数据
DataUnit dataUnit = new DataUnit();
dataUnit.m_nCmd = 0x1234;
dataUnit.m_nChannelID = 1;
chat.UserChat chatmessage = new chat.UserChat();
chatmessage.m_nUserID = 125;
chatmessage.m_strNickName = "client";
chatmessage.m_strMessage = message;
dataUnit.m_oBodyUnit = chatmessage;
SocketManager.Instance.SendDataUnit (dataUnit);
dataUnit.m_nCmd = 0x1234;
dataUnit.m_nChannelID = 1;
chat.UserChat chatmessage = new chat.UserChat();
chatmessage.m_nUserID = 125;
chatmessage.m_strNickName = "client";
chatmessage.m_strMessage = message;
dataUnit.m_oBodyUnit = chatmessage;
SocketManager.Instance.SendDataUnit (dataUnit);
DataUnit dataUnit1 = new DataUnit();
dataUnit1.m_nCmd = 0x1235;
dataUnit1.m_nChannelID = 1;
chat.SignUpResponse req = new chat.SignUpResponse();
req.errorCode = 0;
req.version = 1;
dataUnit1.m_oBodyUnit = req;
SocketManager.Instance.SendDataUnit (dataUnit1);
dataUnit1.m_nCmd = 0x1235;
dataUnit1.m_nChannelID = 1;
chat.SignUpResponse req = new chat.SignUpResponse();
req.errorCode = 0;
req.version = 1;
dataUnit1.m_oBodyUnit = req;
SocketManager.Instance.SendDataUnit (dataUnit1);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
ProtoBuf.Serializer.Serialize<chat.SignUpResponse>(ms,req);
byte[] result = ms.ToArray();
ms.Close();
UnityEngine.Debug.LogError("长度:"+ result.Length);
DataUnit dataUnit1 = new DataUnit();
dataUnit1.m_nCmd = 0x1034;
dataUnit1.m_nChannelID = 1;
chat.LogonReqMessage req = new chat.LogonReqMessage();
req.acctID = 4294967296;
req.passwd = "Bjoy29438253";
dataUnit1.m_oBodyUnit = req;
SocketManager.Instance.SendDataUnit (dataUnit1);
ProtoBuf.Serializer.Serialize<chat.SignUpResponse>(ms,req);
byte[] result = ms.ToArray();
ms.Close();
UnityEngine.Debug.LogError("长度:"+ result.Length);
DataUnit dataUnit1 = new DataUnit();
dataUnit1.m_nCmd = 0x1034;
dataUnit1.m_nChannelID = 1;
chat.LogonReqMessage req = new chat.LogonReqMessage();
req.acctID = 4294967296;
req.passwd = "Bjoy29438253";
dataUnit1.m_oBodyUnit = req;
SocketManager.Instance.SendDataUnit (dataUnit1);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
ProtoBuf.Serializer.Serialize<chat.LogonReqMessage>(ms,req);
byte[] result = ms.ToArray();
ms.Close();
UnityEngine.Debug.LogError("长度:"+ result.Length);
DataUnit dataUnit1 = new DataUnit();
dataUnit1.m_nCmd = 0x1134;
dataUnit1.m_nChannelID = 1;
chat.UserInfo req = new chat.UserInfo();
req.acctID = 4294967296;
req.name = "hxh韩";
req.status = chat.UserStatus.ONLINE;
dataUnit1.m_oBodyUnit = req;
SocketManager.Instance.SendDataUnit (dataUnit1);
ProtoBuf.Serializer.Serialize<chat.LogonReqMessage>(ms,req);
byte[] result = ms.ToArray();
ms.Close();
UnityEngine.Debug.LogError("长度:"+ result.Length);
DataUnit dataUnit1 = new DataUnit();
dataUnit1.m_nCmd = 0x1134;
dataUnit1.m_nChannelID = 1;
chat.UserInfo req = new chat.UserInfo();
req.acctID = 4294967296;
req.name = "hxh韩";
req.status = chat.UserStatus.ONLINE;
dataUnit1.m_oBodyUnit = req;
SocketManager.Instance.SendDataUnit (dataUnit1);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
ProtoBuf.Serializer.Serialize<chat.UserInfo>(ms,req);
byte[] result = ms.ToArray();
ms.Close();
UnityEngine.Debug.LogError("长度:"+ result.Length);
DataUnit dataUnit1 = new DataUnit();
dataUnit1.m_nCmd = 0x1334;
dataUnit1.m_nChannelID = 1;
chat.LogonRespMessage req = new chat.LogonRespMessage();
req.logonResult = true;
chat.UserInfo req1 = new chat.UserInfo();
req1.acctID = 4294967296;
req1.name = "hxh韩";
req1.status = chat.UserStatus.ONLINE;
req.userInfo = req1;
dataUnit1.m_oBodyUnit = req;
SocketManager.Instance.SendDataUnit (dataUnit1);
ProtoBuf.Serializer.Serialize<chat.UserInfo>(ms,req);
byte[] result = ms.ToArray();
ms.Close();
UnityEngine.Debug.LogError("长度:"+ result.Length);
DataUnit dataUnit1 = new DataUnit();
dataUnit1.m_nCmd = 0x1334;
dataUnit1.m_nChannelID = 1;
chat.LogonRespMessage req = new chat.LogonRespMessage();
req.logonResult = true;
chat.UserInfo req1 = new chat.UserInfo();
req1.acctID = 4294967296;
req1.name = "hxh韩";
req1.status = chat.UserStatus.ONLINE;
req.userInfo = req1;
dataUnit1.m_oBodyUnit = req;
SocketManager.Instance.SendDataUnit (dataUnit1);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
ProtoBuf.Serializer.Serialize<chat.LogonRespMessage>(ms,req);
byte[] result = ms.ToArray();
ms.Close();
UnityEngine.Debug.LogError("长度:"+ result.Length);
//接收数据
public static int i = 0;
public System.Text.StringBuilder m_content = new System.Text.StringBuilder();
public int OnProcessPacket(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.UserChat ) )
{
ProtoBuf.Serializer.Serialize<chat.LogonRespMessage>(ms,req);
byte[] result = ms.ToArray();
ms.Close();
UnityEngine.Debug.LogError("长度:"+ result.Length);
//接收数据
public static int i = 0;
public System.Text.StringBuilder m_content = new System.Text.StringBuilder();
public int OnProcessPacket(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.UserChat ) )
{
chat.UserChat chatMessage = (chat.UserChat)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}{2}", chatMessage.m_strNickName, chatMessage.m_strMessage, i++));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}{2}", chatMessage.m_strNickName, chatMessage.m_strMessage, i++));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
}
public int OnProcessPacket1(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket1"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.SignUpResponse ) )
{
UnityEngine.Debug.LogError("OnProcessPacket1---SignUpResponse");
chat.SignUpResponse chatMessage = (chat.SignUpResponse)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}{2}", chatMessage.errorCode, chatMessage.version, i++));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
public int OnProcessPacket2(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket2"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.LogonReqMessage) )
{
UnityEngine.Debug.LogError("OnProcessPacket2---LogonReqMessage");
chat.LogonReqMessage chatMessage = (chat.LogonReqMessage)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}{2}", chatMessage.acctID, chatMessage.passwd, i++));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
public int OnProcessPacket3(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket3"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.UserInfo) )
{
UnityEngine.Debug.LogError("OnProcessPacket3---UserInfo");
chat.UserInfo chatMessage = (chat.UserInfo)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}: {2}", chatMessage.acctID, chatMessage.name, chatMessage.status));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
public int OnProcessPacket4(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket4"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.LogonRespMessage) )
{
UnityEngine.Debug.LogError("OnProcessPacket4---LogonRespMessage");
chat.LogonRespMessage chatMessage = (chat.LogonRespMessage)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}: {2}: {3}", chatMessage.logonResult,chatMessage.userInfo.acctID, chatMessage.userInfo.name, chatMessage.userInfo.status));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
{
UnityEngine.Debug.LogError("OnProcessPacket1"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.SignUpResponse ) )
{
UnityEngine.Debug.LogError("OnProcessPacket1---SignUpResponse");
chat.SignUpResponse chatMessage = (chat.SignUpResponse)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}{2}", chatMessage.errorCode, chatMessage.version, i++));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
public int OnProcessPacket2(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket2"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.LogonReqMessage) )
{
UnityEngine.Debug.LogError("OnProcessPacket2---LogonReqMessage");
chat.LogonReqMessage chatMessage = (chat.LogonReqMessage)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}{2}", chatMessage.acctID, chatMessage.passwd, i++));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
public int OnProcessPacket3(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket3"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.UserInfo) )
{
UnityEngine.Debug.LogError("OnProcessPacket3---UserInfo");
chat.UserInfo chatMessage = (chat.UserInfo)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}: {2}", chatMessage.acctID, chatMessage.name, chatMessage.status));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
public int OnProcessPacket4(DataUnit dataUnit)
{
UnityEngine.Debug.LogError("OnProcessPacket4"+dataUnit.m_nCmd);
if (dataUnit.m_oBodyUnit != null) {
if(dataUnit.m_oBodyUnit.GetType() == typeof( chat.LogonRespMessage) )
{
UnityEngine.Debug.LogError("OnProcessPacket4---LogonRespMessage");
chat.LogonRespMessage chatMessage = (chat.LogonRespMessage)dataUnit.m_oBodyUnit;
m_content.Length=0;
m_content.Append(string.Format("echo {0} : {1}: {2}: {3}", chatMessage.logonResult,chatMessage.userInfo.acctID, chatMessage.userInfo.name, chatMessage.userInfo.status));
UnityEngine.Debug.LogError(m_content.ToString());
}
}
return 0;
}
chap9将Unity游戏移植到iOS平台
9.1 iOS简介
iOS主要安装在iPhone和iPad设备上面。
开发iOS游戏或应用,首先需要到苹果公司的官方网站申请iOS开发权限,理论上只能在苹果公司的Mac计算机上开发。
iOS游戏可以发布到苹果公司的App Store中,这是发布iOS游戏的唯一合法途径。
使用Unity开发iOS游戏并不需要对Objective-C有非常深入的了解。
9.2软件安装
开发iOS游戏,首先要准备一台Mac计算机,然后到苹果公司开发者网站或Mac电脑上的App Store中免费下载Xcode软件,将其安装到Mac上。
Xcode是开发苹果软件的必备工具,最新版只支持Lion操作系统,而Snow Leopard操作系统,要下载对应的老版本。
安装好Xcode后,再安装Mac版的Unity,在Mac上安装Unity的过程与PC版基本一样。
9.3申请开发权限
9.4设置iOS开发环境
9.5测试iOS游戏
9.6发布iOS游戏
9.6.1申请发布证书
发布游戏需要申请一个用于发布的证书(之前申请的是用于测试的证书),这个证书只需要申请一次,将来可以反复使用。
chap10将Unity游戏移植到Android平台
启动Unity,在菜单栏选择Edit|Preferences|External Tools|Android SDK Location指定Android SDK的位置。
在Unity中可以直接使用Java库文件,其格式为.jar。
附录A C#语言
Unity使用的C#和微软.NET平台下的C#很像但又不完全一样。Unity内的C#运行于Mono虚拟机,它是一个开源软件平台。
值类型包括内置类型,结构和枚举。
引用类型包括类和委托。
与C++的预处理相比,C#的预处理不支持宏。
C#提供了垃圾回收器,在程序执行到对象的作用域以外时,对象会自动被系统垃圾回收,因此不需要显示地通过delete销毁。
在Unity中,继承自MonoBehaviour的类不能使用new创建,同时也不能使用构造函数。
C#使用访问修饰符pubilc、protected、internal、protected internal、private决定类或类成员的可见性,尽可能封装内部实现。
pubilc,完全公开,可以在类内部或外部任何地方访问
protected,同一名字空间内的派生类可以访问
internal,同一名字空间内的任何地方可以访问
protected internal,满足protected或internal的条件可以访问
private,仅在类内部可以访问
在当前版本的Unity中,C#并不支持名字空间。
所有C#类都是从System.Object派生出来的。
C#的委托支持泛型参数,也就是委托可以对应任何类型的参数列表。
附录B 特殊文件夹
ActionScript
存放Flash的ActionScript脚本。当游戏被导出为Flash格式的时候,这里的脚本会自动替换指定的C#脚本。
Editor
存放编辑器脚本
Gizmos
通常是存放TIF格式的图片,在OnDrawGizmos函数内使用Gizmos.DrawIcon将其画为图标在场景中显示。
Plugins/iOS
存放iOS插件,包括.a或.m、.mm文件等。
Resources
存放使用Resources.Load()动态读取的资源,它们可以是图片、模型等不同类型的资源。
Standard Assets
标准Unity资源包
StreamingAssets
独立存放到文件系统中媒体文件,如视频等。
WebPlayerTemplates
存放网页游戏模板,其中的每个模板均以一个自定义名称的子目录形式存放。
Unity3D V3.0中文快速入门教程
http://www.docin.com/p-290465538.html
Unity3D的基本界面介绍
场景面板:
动画面板Game:是用来渲染场景面板中景象的。该面板不能用作编辑,但却可以呈现完整的动画效果。
层次清单栏Hierarchy:
项目文件栏:
对象属性栏:
场景调整工具:
9.1 iOS简介
iOS主要安装在iPhone和iPad设备上面。
开发iOS游戏或应用,首先需要到苹果公司的官方网站申请iOS开发权限,理论上只能在苹果公司的Mac计算机上开发。
iOS游戏可以发布到苹果公司的App Store中,这是发布iOS游戏的唯一合法途径。
使用Unity开发iOS游戏并不需要对Objective-C有非常深入的了解。
9.2软件安装
开发iOS游戏,首先要准备一台Mac计算机,然后到苹果公司开发者网站或Mac电脑上的App Store中免费下载Xcode软件,将其安装到Mac上。
Xcode是开发苹果软件的必备工具,最新版只支持Lion操作系统,而Snow Leopard操作系统,要下载对应的老版本。
安装好Xcode后,再安装Mac版的Unity,在Mac上安装Unity的过程与PC版基本一样。
9.3申请开发权限
9.4设置iOS开发环境
9.5测试iOS游戏
9.6发布iOS游戏
9.6.1申请发布证书
发布游戏需要申请一个用于发布的证书(之前申请的是用于测试的证书),这个证书只需要申请一次,将来可以反复使用。
chap10将Unity游戏移植到Android平台
启动Unity,在菜单栏选择Edit|Preferences|External Tools|Android SDK Location指定Android SDK的位置。
在Unity中可以直接使用Java库文件,其格式为.jar。
附录A C#语言
Unity使用的C#和微软.NET平台下的C#很像但又不完全一样。Unity内的C#运行于Mono虚拟机,它是一个开源软件平台。
值类型包括内置类型,结构和枚举。
引用类型包括类和委托。
与C++的预处理相比,C#的预处理不支持宏。
C#提供了垃圾回收器,在程序执行到对象的作用域以外时,对象会自动被系统垃圾回收,因此不需要显示地通过delete销毁。
在Unity中,继承自MonoBehaviour的类不能使用new创建,同时也不能使用构造函数。
C#使用访问修饰符pubilc、protected、internal、protected internal、private决定类或类成员的可见性,尽可能封装内部实现。
pubilc,完全公开,可以在类内部或外部任何地方访问
protected,同一名字空间内的派生类可以访问
internal,同一名字空间内的任何地方可以访问
protected internal,满足protected或internal的条件可以访问
private,仅在类内部可以访问
在当前版本的Unity中,C#并不支持名字空间。
所有C#类都是从System.Object派生出来的。
C#的委托支持泛型参数,也就是委托可以对应任何类型的参数列表。
附录B 特殊文件夹
ActionScript
存放Flash的ActionScript脚本。当游戏被导出为Flash格式的时候,这里的脚本会自动替换指定的C#脚本。
Editor
存放编辑器脚本
Gizmos
通常是存放TIF格式的图片,在OnDrawGizmos函数内使用Gizmos.DrawIcon将其画为图标在场景中显示。
Plugins/iOS
存放iOS插件,包括.a或.m、.mm文件等。
Resources
存放使用Resources.Load()动态读取的资源,它们可以是图片、模型等不同类型的资源。
Standard Assets
标准Unity资源包
StreamingAssets
独立存放到文件系统中媒体文件,如视频等。
WebPlayerTemplates
存放网页游戏模板,其中的每个模板均以一个自定义名称的子目录形式存放。
Unity3D V3.0中文快速入门教程
http://www.docin.com/p-290465538.html
Unity3D的基本界面介绍
场景面板:
动画面板Game:是用来渲染场景面板中景象的。该面板不能用作编辑,但却可以呈现完整的动画效果。
层次清单栏Hierarchy:
项目文件栏:
对象属性栏:
场景调整工具:
菜单栏中包含有8个菜单选项:
文件
编辑
资源
游戏对象
组件
地形
窗口
帮助
其各自又有自己的子菜单。
Assets|Create|JavaScript
初始化函数
function Start(){
print("Game is start");
将这段代码拖拽给层次清单栏中任意一个对象,则在左下方的控制台面板中看到这句话。
刷帧函数
function Update(){
print(Time.time);
}
显示游戏开始到现在所消耗的时间值。
var AddSpeed=5;
function Update(){
transform.Translate(0,0,AddSpeed);
}
该代码为对象添加了一个在Z方向上的初始速度,如果在没有其他外力的作用下,物体将一直沿着Z方向以5的速度行驶。并且当您将这段代码拖拽给一个物体对象之后,它的这个初始速度可以作为一个接口在它的属性面板中进行修改。
除了数字作为接口之外,接口还可以是对象。
//定义一个变换对象cubeGO
var cubeGO:Transform;
文件
编辑
资源
游戏对象
组件
地形
窗口
帮助
其各自又有自己的子菜单。
Assets|Create|JavaScript
初始化函数
function Start(){
print("Game is start");
将这段代码拖拽给层次清单栏中任意一个对象,则在左下方的控制台面板中看到这句话。
刷帧函数
function Update(){
print(Time.time);
}
显示游戏开始到现在所消耗的时间值。
var AddSpeed=5;
function Update(){
transform.Translate(0,0,AddSpeed);
}
该代码为对象添加了一个在Z方向上的初始速度,如果在没有其他外力的作用下,物体将一直沿着Z方向以5的速度行驶。并且当您将这段代码拖拽给一个物体对象之后,它的这个初始速度可以作为一个接口在它的属性面板中进行修改。
除了数字作为接口之外,接口还可以是对象。
//定义一个变换对象cubeGO
var cubeGO:Transform;
//一旦按下G键
if(Input.GetKey(KeyCode.G)){
cubeGO.Transform(0,0,AddSpeed);
}
在菜单栏中选中File|Build Settings或者按下Ctrl+Shift+B键的组合来发布工程文件。
我简单介绍一下这个面板:
Scenes In Build:要发布的场景文件列表。后面的数值是场景的加载顺序,0为最先被加载的主场景文件。
Platform:导出的文件格式。如果您没有购买正式的U3D专业版软件,那么您只能发布前两种格式的文件。如果您已经购买了U3D专业版软件,那么您还得注意第四种iOS格式的文件,必须在苹果的Mac OS X操作系统下才能发布。
在start场景中的画面,完全由GUI代码绘制而成,所以在您未对项目运行的时候,Game动画面板中将不会显示任何东西。
10.3运行Android游戏
10.3.1设置Android手机
准备一部手机,CPU最好是ARMv7架构的。
Portrait表示竖屏,Landscape表示横屏。选择Auto Rotation可以自动旋转屏幕方向。
4种大小的图标,分别是96*96,72*72,48*48,36*36。
默认启动Unity游戏的时候将会看到Unity的Logo,在Splash Image中指定一张图片即可替换默认的启动画面,在Splash scaling中可以设置启动图片的缩放。
Bundle Identifier是游戏的标识。在Minimum API Level中设置游戏所支持的最小API版本。
在Device Filter中只有ARMv7 only选项。
在Install Location中提供了几种游戏安装方式,Prefer External会将游戏安装到外部存储卡中。
10.4触屏操作
鼠标操作无法实现一些特有的触屏操作,比如多点触屏。
UNITY_EDITOR、UNITY_iOS、UNITY_ANDROID是Unity预设的预处理标识符。
10.5.1从eclipse到Unity
与iOS平台一样,理论上可以使用Unity完成一款Android游戏且不写一行Android平台相关代码,但如果我们需要调用Android平台专有的API,那么就不得 不接 触一些Android平台相关的东西。
if(Input.GetKey(KeyCode.G)){
cubeGO.Transform(0,0,AddSpeed);
}
在菜单栏中选中File|Build Settings或者按下Ctrl+Shift+B键的组合来发布工程文件。
我简单介绍一下这个面板:
Scenes In Build:要发布的场景文件列表。后面的数值是场景的加载顺序,0为最先被加载的主场景文件。
Platform:导出的文件格式。如果您没有购买正式的U3D专业版软件,那么您只能发布前两种格式的文件。如果您已经购买了U3D专业版软件,那么您还得注意第四种iOS格式的文件,必须在苹果的Mac OS X操作系统下才能发布。
在start场景中的画面,完全由GUI代码绘制而成,所以在您未对项目运行的时候,Game动画面板中将不会显示任何东西。
10.3运行Android游戏
10.3.1设置Android手机
准备一部手机,CPU最好是ARMv7架构的。
Portrait表示竖屏,Landscape表示横屏。选择Auto Rotation可以自动旋转屏幕方向。
4种大小的图标,分别是96*96,72*72,48*48,36*36。
默认启动Unity游戏的时候将会看到Unity的Logo,在Splash Image中指定一张图片即可替换默认的启动画面,在Splash scaling中可以设置启动图片的缩放。
Bundle Identifier是游戏的标识。在Minimum API Level中设置游戏所支持的最小API版本。
在Device Filter中只有ARMv7 only选项。
在Install Location中提供了几种游戏安装方式,Prefer External会将游戏安装到外部存储卡中。
10.4触屏操作
鼠标操作无法实现一些特有的触屏操作,比如多点触屏。
UNITY_EDITOR、UNITY_iOS、UNITY_ANDROID是Unity预设的预处理标识符。
10.5.1从eclipse到Unity
与iOS平台一样,理论上可以使用Unity完成一款Android游戏且不写一行Android平台相关代码,但如果我们需要调用Android平台专有的API,那么就不得 不接 触一些Android平台相关的东西。
使用Unity创建塔防游戏2016-3-30 16:00
Unity3d学习笔记(五)--结合Mecanim实现怪物AI
http://blog.csdn.net/lzhq1982/article/details/12620603
Unity3D开发(五):Unity3D 4.x 使用Mecanim实现连击
http://blog.csdn.net/onerain88/article/details/12854817
怪物 动画 状态机
Project_txl/Animations/Roudan_AnimatorController.controller
Base Layer
Default state:XiaLuo
XiaLuo->Jump->Move
这里只用3个动作描述,下落状态(XiaLuo),跳跃状态(Jump),移动状态(Move)
// 使用字符串变量保存当前状态,避免多处引用写错
private static readonly string XiaLuoState = "Base Layer.XiaLuo";
private static readonly string JumpState = "Base Layer.Jump";
private static readonly string MoveState = "Base Layer.Move";
MeatEggAI.cs
在Start()中获取Animator组件引用
/// <summary>
/// 动画组件
/// </summary>
private Animator m_animator;
m_animator = this.GetComponent<Animator>();
在Update()中根据当前状态和输入参数促使状态切换
private Vector3 targetPos;
private Vector3 targetPos;
AnimatorStateInfo stateInfo = this.animator.GetCurrentAnimatorStateInfo(0);
if (stateInfo.nameHash == Animator.StringToHash(XiaLuoState) && !m_animator.IsInTransition(0))
{
m_animator.SetBool("XiaLuo", false);
m_animator.SetBool("Jump", true);
m_transform.eulerAngles = new Vector3(0, Random.Range(0,360), 0);
}
if (stateInfo.nameHash == Animator.StringToHash(JumpState) && !m_animator.IsInTransition(0))
{
m_animator.SetBool("Jump", false);
m_animator.SetBool("Move", true);
…… }
if (stateInfo.nameHash == Animator.StringToHash( MoveState))
{
……
RotateTo(targetPos);
RotateTo(targetPos);
m_transform.Translate(0, 0, 3.0f * Time.deltaTime);
}
在MonsterManager类中定义一个MonsterPref类型【MonsterLevel】:
[System.Serializable]
public class MonsterPref
{
/// <summary>
/// 怪物名称
/// </summary>
public string name;
/// <summary>
/// 怪物类型
/// </summary>
public Monster.MonsterType type;
/// <summary>
/// 怪物预制
/// </summary>
public Monster prefab;
}
我们添加了[System.Serializable]这个特性来使这个类的对象可以在监视面板中编辑。这可以使我们方便快速的改变MonsterPref中的值。
我们将预先定义的MonsterPref存储在数组MonsterPref []或List<T>中。
public MonsterPref[] monsterPrefabs;
public MonsterPref bonusPrefab;
这篇关于Unity3D手机游戏开发-金玺曾读书摘要(2015-4-27 19:01、2016-4-11 10:39)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!