您的位置:首页 > 移动开发 > Unity3D

Unity3D手机游戏开发的一些笔记

2015-09-02 17:07 603 查看
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">发布选项:50页</span></span>


选中Run In Background 即使游戏窗口失去焦点,也会在后台运行.

如果在Display Resolution Dialog中选择Disabled,游戏在每次启动时不会显示一个用于设置显示分辨率的窗口。

;Icon选择组;可以设置不同大小的图标,如果不指定,他们将会自动调用Default Icon中设置的图标并自动缩放。可能会有锯齿

Override for Standalone根据分辨率替换默认图标.

默认启动Unity游戏会看到Unity的商标,在Splash Image中指定一张图片即可.(这个功能只有在pro版本中才能使用)

;Oher Settings选项组。Static Batching是Unity Pro版本功能,它将静态模型整合,但有时会使游戏尺寸变大,如果不清楚优化原理,建议慎重使用这个功能。

;Rendering Path中可以设置3钟渲染模式:

1.Deferred Lighting有最真是的灯光效果,可以不受数量限制地使用灯光和实时阴影,所有的灯光都支持per-pixel(用于计算normal maps),该模式当前不支持抗锯齿和半透明显示。只有unity pro才支持这种模式,需要显卡支持shader model 3.0或更高。不支持手机平台。

2.Forward Rendering以Shader为基础,只能用一个方向光实时阴影。在【Edit】->【Project Settings】->【Quality】,在Pixel Light Count里可以设置per pixel灯光的最大数量。

3.Vertex Lit是灯光效果最简单的渲染模式,不支持实时阴影。不支持normal maps,但有最好的性能,适合在一些较差的硬件上使用。

Navigation寻路简单实用:60页

Gizmos小提示的使用:79页

void OnDrawGizmos()
{
Gizmos.DrawIcon(transform.position, "item.png", true);//允许缩放
}
item.png纹理在Gizmos文件下。

屏幕自动分辨率,只能按高度比例

小地图制作:80页

摄像机的Normalized viewport rect属性

指定如何将摄像机的视图绘制到屏幕坐标系上(取值范围为0-1)

X:摄像机视图在屏幕上被绘制的水平初始位置

Y:摄像机视图在屏幕上被绘制的垂直初始位置

W:摄像机视图输出图像占屏幕宽度的比例

H:摄像机视图输出图像占屏幕高度的比例

U3D屏幕的坐标系是以左下角为坐标原点,向右为X轴,向上为Y轴
原文:http://blog.csdn.net/kfqcome/article/details/10159201

87页:在不基础MonBehaviour的类前面加[System.Serializable]使得变量可以被Inspector界面获得。其二:指示一个类可以序列化(数组?),不能被继承。

91页: 在函数前面添加[ContextMenu("BuildMap")]//上下文菜单,添加它之后,可以在编辑状态下手动执行BuildMap

99页:在Assets目录下创建名为Editor的文件夹,名称是特定的,不能改变,所有需要在编辑状态下执行的脚本都应当存放到这里。

99页:接着上面一条,在函数名称前加[MenuItem("PathTool/Set Parent %q")] 菜单栏里会多出一个PathTool菜单,菜单下有Set Parent选项。快捷键是Ctrl+q。点击会运行这个函数。记得using UnityEditor;

100页:接着上面,这里的代码只有在编辑状态才能被执行,注意PathTool继承自ScriptableObject并在前面引用了UnityEditor。所有在这里使用的属性和函数均为static类型。

106-109页:excel生成xml数据
xml基本格式。必须定义两列table只有这样在Excel中才能批量映射数据元素。
<?xml version="1.0" encoding="uft-8"?>   uft-8不支持就改成gb2312
<ROOT>
<!--  content -->
<table wave="" enemyname="" level="" wait="" />
<table wave="" enemyname="" level="" wait="" />
</ROOT>
</pre><p>111页:用官方精简的XMLParser解析读取XML数据:</p><p></p><pre name="code" class="csharp">    void ReadXML()
{
enemylist = new ArrayList();
XMLParser xmlparser = new XMLParser();//XML解析器
XMLNode node = xmlparser.Parse(xmldata.text);//开始解析TextAsset
XMLNodeList list = node.GetNodeList("ROOT>0>table");//只是看看有几行table
for(int i=0;i<list.Count;i++)
{
//从XML节点里
string wave = node.GetValue("ROOT>0>table" + i + ">@wave");//获取第i行table的wave值
string enemyname = node.GetValue("ROOT>0>table" + i + ">@enemyname");
string level = node.GetValue("ROOT>0>table" + i + ">@level");
string wait = node.GetValue("ROOT>0>table" + i + ">@wait");

SpawnData data = new SpawnData();//保存从xml提取的数据
data.wave = int.Parse(wave);
data.enemyname = enemyname;
data.level = int.Parse(level);
data.wait = int.Parse(wait);
enemylist.Add(data);//获取某行的所有数据
}
}


117页:RotateTo函数的实现方法。

121页:Mesh和UV的一些应用

第五章:资源创建

134页:Render Mode是一个重要的选项,当设为Important时渲染将达到像素质量,设为Not Important则总是一个顶点光,但可以获得更好的性能。

Culling Mask:选择遮罩可以控制光英雄的对象。

Lightmapping:可设为RealtimeOnly或BackedOnly,这将使光源仅能用于实时照明或烘培Lightmap。默认是Auto

环境光:是unity提供的一种特殊光源,它没有范围和方向的概念,会整体的改变场景亮度。环境光在场景中是一直存在的,在菜单栏选择【Edit】->【Render Settings】 Ambient Light

Fog雾:Fog Density雾的强度。雾功能对性能造成一定影响,在硬件性能较差的平台要谨慎使用这个功能。

135页:lightmapping 烘培?使用灯光贴图的模型必须有第二套UV,这套UV原则上不能有UV重叠的地方。

136页:【Window】->【Lightmapping】打开Lightmapping窗口。选择Build下面的Back Reflection Probes再点Build进行烘培设置。

Bounces:决定光子的计算级别。其他一些属性可以在136-137页看。所有光影贴图都会自动存放在当前场景的存放路径。

isset用来检测该变量是否被设置。

164页:服务器配置

174页:WWW的基本应用

175页:GET请求

176页:POST请求。using System.Collections.Generic;Dictionary

178页:上传下载图片

1、选中图片:Inspector窗口下第一个选项,Texture Type 改成 Advanced;

2、选中Read/Write Enabled。

3、选中下方Override for Standalone,Format这图片ARGB 32bit

180页:下载声音文件

224页:对象序列化于反序列化简单演示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
//                    运行时刻 序列化         格式化          二进制
namespace ConsoleApplication1
{
[Serializable]//序列化是将对象状态转换为可保持或传输的格式的过程。
public class Player
{
public int id;
public string name;
public int life;
}
class Program
{
static void Main(string[] args)
{
Player player = new Player();
player.id = 1;
player.name = "hero";
player.life = 1000;
using(MemoryStream stream =new MemoryStream())//创建存储区为内存的流 IO
{
//创建序列化类
BinaryFormatter bf = new BinaryFormatter();//以二进制格式将对象或整个连接对象图形序列化和反序列化。
bf.Serialize(stream, player);//将对象(或具有指定顶级(根)的对象图形)序列化给指定流
//bf将player对象序列化到stream内存流中。
stream.Seek(0, SeekOrigin.Begin);//将流中的位置设成,开始!?
Player player2;
player2 = (Player)bf.Deserialize(stream);//将stream保存的数据反序列化。然后转化成Player类对象
Console.WriteLine("{0},{1},{2}", player.id, player2.name, player2.life);
}
}
}
}


225页:简单的Server和Client连接发送接收数据

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;//套接字
namespace SimpleServer
{
class Program
{
static void Main(string[] args)
{
string ip = "127.0.0.1";
//端口
int port = 8000;
try
{
//获得终端地址
IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(ip), 8000);//本机地址
//创建socket
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//          监听                               地址族-ip4版本地址      套接字类型-双向连接的字节流   协议类型-Tcp
listener.Bind(ipe);//相对 - 开始连接
//开始监听 最大允许处理1000个连接
listener.Listen(1000);//开始监听
Console.WriteLine("开始监听");
//开始接受客户端请求  程序在这里会阻住
Socket mySocket = listener.Accept();//接受一个连接。将这个"连接socket"返回。保存在mySocket

byte[] bs = new byte[1024];
int n = mySocket.Receive(bs);//将接受的数据存入缓存区bs //在等待另一个连接 发送数据
Console.WriteLine(n.ToString());
mySocket.Send(bs);//发送数据。到连接的Socket
mySocket.Close();
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace SimpleClient
{
class Program
{
static void Main(string[] args)
{
//服务器ip地址
string ip = "127.0.0.1";
//服务器端口
int port = 8000;
try
{
//获得终端
IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(ip), port);
Socket client = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
//开始连接服务器,程序会在这里阻住,直到连接成功或失败
client.Connect(ipe);

Console.WriteLine("连接到服务器");
//向服务器发送数据
string data = "hello world";
byte[] bs = UTF8Encoding.UTF8.GetBytes(data);//字符串转化到字节集
client.Send(bs);
byte[] rev = new byte[256];
//接受到服务器返回的数据
client.Receive(rev);//在等待另一个连接 发送数据
Console.WriteLine(UTF8Encoding.UTF8.GetString(rev));
client.Close();
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}


编译c#成dll放到unity中使用时,要将net framework版本至少设成3.5。class权限也要是public

251页:
protogen -i:chatapp.proto -o:chatapp.cs
package ChatAPP;//命名空间
message User {//类
required string name=1;//123好像只是第几变量
required string chat=2;//required必须的变量
optional string email=3;//可选的变量
}

message Chat{
repeated User user = 1;//多个User变量(数组?)
}


335页:设置Android游戏工程









342页:触屏API

<pre name="code" class="csharp">public class AndroidTouch : MonoBehaviour
{

Vector2 m_screenpos = new Vector2();
float m_speed = 0.1f;
// Use this for initialization
void Start()
{
//Debug.Log(Input.multiTouchEnabled);
Input.multiTouchEnabled = true;//设置多点触屏
}

// Update is called once per frame
void Update()
{
if (Input.GetKeyUp(KeyCode.Escape))
Application.Quit();
#if !UNITY_EDITOR && (UNITY_IOS || UNITY_ANDROID)//判断是编辑(pc)平台还是移动手机平台
MobileInput();
#else
DesktopInput();
#endif
}
void DesktopInput()
{
//记录鼠标左键的移动距离
float mx=Input.GetAxis("Mouse X");
float my=Input.GetAxis("Mouse Y");
if(mx!=0 || my!=0)
{
//鼠标左键
if(Input.GetMouseButton(0))
{
Camera.main.transform.Translate(new Vector3(mx,my,0));
}
}
}
//滑动输入
void MobileInput()
{
if (Input.touchCount < 0)
return;
if (Input.touchCount == 1)
{
//开始触屏
if (Input.touches[0].phase == TouchPhase.Began)//触屏阶段==开始
{
//记录手指触屏的位置
m_screenpos = Input.touches[0].position;
}
else if (Input.touches[0].phase == TouchPhase.Moved) //手指移动
{
//移动摄像机
Camera.main.transform.Translate(new Vector3(Input.touches[0].deltaPosition.x * m_speed, Input.touches[0].deltaPosition.y * m_speed, 0));
//deltaPosition增量值
}
//手指离开屏幕后
if (Input.touches[0].phase == TouchPhase.Ended && Input.touches[0].phase != TouchPhase.Canceled)
//系统取消跟踪触摸,如用户把屏幕放到他脸上或超过五个接触同时发生。这是一个触摸的最后状态
{
Vector2 pos = Input.touches[0].position;//离开位置
//手指水平移动(多点)
if (Mathf.Abs(m_screenpos.x - pos.x) > Mathf.Abs(m_screenpos.y - pos.y))
{
if (m_screenpos.x > pos.x)
{
//开始点.x大于结束点.x      手指向左滑动
}
else
{
//否则 向右滑动
}
}
else //手指垂直移动
{
if (m_screenpos.y > pos.y)
{
//开始点.y大于结束点.y      手指向下滑动(Y上小,下大)
}
else
{
//否则向上滑动
}
}
}
}
else if(Input.touchCount>1)
{
//记录两个手指的位置
Vector2 finger1 = new Vector2();
Vector2 finger2 = new Vector2();
//记录两个手指的移动距离
Vector2 mov1 = new Vector2();
Vector2 mov2 = new Vector2();
for(int i=0;i<2;i++)
{
Touch touch = Input.touches[i];
if (touch.phase == TouchPhase.Ended)
break;
//如果手指处于移动状态
if(touch.phase==TouchPhase.Moved)
{
float mov = 0;
if(i==0)
{
//获得手指1的位置和移动
finger1 = touch.position;
mov1 = touch.deltaPosition;//移动量
}
else
{
//获得手指2的位置和移动
finger2 = touch.position;
mov2 = touch.deltaPosition;
//获得手指移动距离
if(finger1.x>finger2.x)//获取最右边手指的增量
{
mov = mov1.x;
}
else
{
mov = mov2.x;
}
if(finger1.y>finger2.y)//获取下面那根手指的增量
{
mov += mov1.y;
}else
{
mov += mov2.y;
}
//根据手指移动距离改变摄像机位置
Camera.main.transform.Translate(0, 0, mov * m_speed);
}
}
}
}
}
}




348页:java代码

F:\unity5.3.2f1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Development\Classes

package com.testc.test;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;

import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

//mainActivitty继承自UnittyPlayerActtivitty
public class MainActivity extends UnityPlayerActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

//准备在unity中调用的参数,有两个参数
protected void HelloWorld(final String title,final String content)
{
runOnUiThread(new Runnable()
{
public void run()
{
MakeDialog(title,content);
}
});
}

//显示对话框
public void MakeDialog(String title,String content)
{
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

builder.setTitle(title)
.setMessage(content)
.setCancelable(false)
.setPositiveButton("OK", null);

builder.show();
}
}


349页:Clean出现一些问题。

建立project时Theme改为none。还有main什么的把值直接删掉

另外:AndroidManifest.xml在F:\unity5.3.2f1\Editor\Data\PlaybackEngines\AndroidPlayer\Apk

AndroidMainfest.xml文件改:包+类名

<activity android:name="com.testc.test.MainActivity"
<img src="http://img.blog.csdn.net/20160201171143083?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />


350页:

AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");


351页:在Eclipse查看Log

355页:设置导出的eclipse工程:

一些库要把鼠标放在出错那里,点导入XX库!函数放在最高基类或继承,如:UnityPlayerActivity这个类

另外可以选择:

UnityPlayerNativeActivity extends UnityPlayerActivity


JAVA:

protected void HelloWorld(final String title,final String content)
{
runOnUiThread(new Runnable(){
public void run(){
MakeDialog(title,content);
}
});
}

//显示对话框
public void MakeDialog(String title,String content)
{
AlertDialog.Builder builder= new AlertDialog.Builder(UnityPlayerNativeActivity.this);
builder.setTitle(title)
.setMessage(content)
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
UnityPlayer.UnitySendMessage("AndroidManager","AndroidCallback","");

}});
builder.show();
}


c#:

try
{
string[] args = new string[2];
args[0] = "Hello";
args[1] = "World";
Debug.Log(active.ToString());
//   active.Call("MakeDialog", args);
active.Call("HelloWorld");//被调用的函数名+参数数组
Debug.Log("完成调用!");
}
catch(System.Exception ex)
{
Debug.Log(ex.Message);
}
运行方式:项目右键 Run-As ->AndroidApplicattion。然后 就可以run了。

355页:

android:debuggable="false"
有问题可以删掉或改
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: