澳门大亨 熟悉文档

澳门大亨 熟悉文档


##开始项目的基本配置

####GameSetting.lua

  • 服务器地址基本设置
  • 设备号设置

HallConnector.lua

  • self.sessionID 测试的用户id,不同用户要设置不一样

####开始的AssertBundle打包

  • 使用Package_MacaoTycoon_Trunc 打资源包流程
    1.
    2.

页面管理中几个重要的类

绑定在panel页上的类

BaseLua.cs(动态绑定到页面上)

  • 每个panel页面都会绑定一个BaseLua
  • BaseLua用mono周期管理当前panel对应lua脚本的周期(例:Surface_3D_Login页面对应Surface_3D_Login.lua脚本)

WidgetReference.cs(固定在页面上)

  • 需要在lua脚本中处理逻辑对应的图片,按钮,Object等依赖,需绑定在这个脚本上,以便lua脚本中可以调用到

####CoroutineComponent.cs(固定在页面上)

  • 执行特殊方法类
  • 当前panel对应lua 脚本需执行延迟操作和按照一定帧率操作方法时调用

不绑定页面的其他管理类

BasePage.cs

  • 用于一个panel页面展示和隐藏

页面堆(例:LoginPageStack.lua)

  • 管理当前堆模块依赖的资源和页面
  • 并不是所有的页面和资源都有pagestack管理
  • 基本按照模块来区分页面堆(例如登入模块 会有一个LoginPageStack.lua来控制当前界面的逻辑)

GamePageStackManager.cs(页面堆管理)

  • 在GameStart Scene开始时 GamePageStackManager初始化在界面上
  • 对各个页面堆(例:LoginPageStack,CommonPageStack)通过GamePageContainer.cs进行管理
  • 调用一个pagestake会生成对应的pagestack Gameobject 在GamePageStackManager子类中(例如:在开始生成登入界面会生成一个LoginPageStack 的GameObject在GamePageStackManager的子类中)

GamePageContainer.cs

  • 对要显示的stackpage中的页面初始化,并且保存
  • 对存储的页面进行获取,移除,退出操作

####MJPage.cs

  • 在GamePageStackManager子类中生成的pagestack GameObject 都会绑定一个MJPage.cs
  • 调用对应stackpage脚本中的方法(例:OnShow()),调用GamePageContainer管理页面退出

页面重要的lua类

PageRouteManager.lua

  • pagestack的管理,对应c#端的GamePageStackManager.cs类
  • 将调用的pagestack用List.lua 以节点的方式存储,可以在页面转跳中(回退,前进页面)更好的管理

LuaBasePanel.lua

  • 是每个页面对应lua脚本的基础
  • 实现一些页面初始化,添加按钮事件,设置一些页面属性

PanelManager.lua

  • 找到需要引用的对应页面的lua脚本,在c#端 Baselua.cs和MJPage.cs中调用
  • 没有被页面堆管理的代码,需在PanelManager脚本写下页面脚本对应位置,下面例子在pop文件下

    1
    redirectPanelTbl["*.Dialog_Message"] = "pop"
  • 有页面堆管理的代码,需放在对应名字的目录下(例:Surface_3D_Login 在LoginPageStack管理,放在打包名字对应的login目录下)

GamePageStackManager.lua

  • 所有stackpage lua端的基本管理
  • 游戏开始时候{“SoundPageStack”, “CommonPageStack”, “LoginPageStack”}三个stack初始化

页面转跳的基本流程

1
st=>start: 点击转跳
op=>operation: BasePage.cs中toggleshow方法
op1=>operation: 传入资源名,页面名称,是否显示,依赖资源
op2=>operation: 加载依赖图片资源
op3=>operation: 加载依赖资源
op4=>operation: ResourceManager从AssetBundle加载界面
op5=>operation: 创建界面

cond=>condition: 存储是否有当前页面 Yes or No?
cond1=>condition: 是否显示 Yes or No?
cond2=>condition: 有依赖资源 Yes or No?
e1=>end: 显示界面
e2=>end: 隐藏界面

st->op->op1->cond2
op3->cond
cond2(yes)->op3
cond2(no)->cond
cond(yes)->cond1
cond(no)->op4
cond1(yes)->e1
cond1(no)->e2

开始游戏到登入界面代码基本流程如图

16011001

Enjoy!

unity 事件订阅,发布,可用于新手引导

主要代码事件订阅,发布

##获取事件对象进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;

public class EventBase{
private List<Action> actions = new List<Action>();

/// <summary>
/// 发布事件
/// </summary>
public void Publish ()
{
if (actions != null) {
foreach (Action action in actions) {
action();
}
}
}

/// <summary>
/// 订阅事件
/// </summary>
/// <param name="t">T.</param>
public void Subscribe (Action t)
{
if (!actions.Contains (t)) {
actions.Add (t);
}
}

/// <summary>
/// 取消事件
/// </summary>
/// <param name="t">T.</param>
public void UnSubscribe (Action t)
{
if (actions.Contains (t)) {
actions.Remove (t);
}
}

public void Clear()
{
actions.Clear ();
}

}


public class EventBase<T>: EventBase{
private List<Action<T>> actions ;

public void Publish (T t)
{
if (actions != null) {
foreach (Action<T> action in actions) {
action(t);
}
}
}

public void Subscribe (Action<T> action)
{
if (actions == null) {
actions = new List<Action<T>>();
}
if (!actions.Contains (action)) {
actions.Add (action);
}
}

public void UnSubscribe (Action<T> action)
{
if (actions == null) {
return;
}
if (actions.Contains (action)) {
actions.Remove (action);
}
}

}



public class EventServer{
private static EventServer instance = new EventServer();

//存放事件对象集合
private Dictionary<Type,EventBase> evenbasci = new Dictionary<Type, EventBase>();

public static EventServer Instance {
get{
return instance;
}
}

/// <summary>
/// 获取事件对象,并对该对象进行订阅和发布
/// </summary>
/// <returns>The event.</returns>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public T GetEvent<T> () where T: EventBase
{
Type eventtype = typeof(T);
if (!evenbasci.ContainsKey (eventtype)) {
//如果事件对象不存在,创建该事件对象
T e = Activator.CreateInstance <T>();
evenbasci.Add (eventtype,e);
}
return (T)evenbasci[eventtype];
}

public void ClearAll ()
{
foreach (EventBase e in evenbasci.Values) {
e.Clear ();
}

evenbasci.Clear ();
}
}

示例事件

1
2
3
4
5
using UnityEngine;
using System.Collections;

public class GuideTutor : EventBase {
}

用法

  • 在一定的地方订阅示例事件

    1
    2
    3
    4
    5
    6
    7
    8
    void Start () {
    EventServer.Instance.GetEvent<GuideTutor> ().Subscribe (EventLog);
    }

    void EventLog()
    {

    Debug.Log ("时间订阅");
    }
  • 在需要的地方发布事件

    1
    EventServer.Instance.GetEvent<GuideTutor> ().Publish ();

unity lua -1 最开始调用

  • lua脚本以txt的形式存储在Resources 下面
  • 用LuaSvr svr svr.start调用到脚本
  • 用 svr.luaState.getFunction(“foo”).call 来调用到里面的方法

lua

  • Table – 是一个Key Value的数据结构
  • Lua内建约定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__add(a, b)                     对应表达式 a + b
__sub(a, b) 对应表达式 a - b
__mul(a, b) 对应表达式 a * b
__div(a, b) 对应表达式 a / b
__mod(a, b) 对应表达式 a % b
__pow(a, b) 对应表达式 a ^ b
__unm(a) 对应表达式 -a
__concat(a, b) 对应表达式 a .. b
__len(a) 对应表达式 #a
__eq(a, b) 对应表达式 a == b
__lt(a, b) 对应表达式 a < b
__le(a, b) 对应表达式 a <= b
__index(a, b) 对应表达式 a.b
__newindex(a, b, c) 对应表达式 a.b = c
__call(a, ...) 对应表达式 a(...)
  • lua 面向对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Person={}

function Person:new(p)
local obj = p
if (obj == nil) then
obj = {name="ChenHao", age=37, handsome=true}
end
self.__index = self
return setmetatable(obj, self)
end

function Person:toString()
return self.name .." : ".. self.age .." : ".. (self.handsome and "handsome" or "ugly")
end

上面我们可以看到有一个new方法和一个toString的方法。其中:
1self 就是 Person,Person:new(p),相当于Person.new(self, p)
2new方法的self.__index = self 的意图是怕self被扩展后改写,所以,让其保持原样
3)setmetatable这个函数返回的是第一个参数的值。
于是:我们可以这样调用:
复制代码 代码如下:

me = Person:new()
print(me:toString())

kf = Person:new{name="King's fucking", age=70, handsome=false}
print(kf:toString())
  • 使用外部lua文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们有一个hello.lua的文件:
复制代码 代码如下:

print("Hello, World!")
如果我们:require(“hello”),那么就直接输出Hello, World!了。
注意:
1)require函数,载入同样的lua文件时,只有第一次的时候会去执行,后面的相同的都不执行了。
2)如果你要让每一次文件都会执行的话,你可以使用dofile(“hello”)函数
3)如果你要玩载入后不执行,等你需要的时候执行时,你可以使用 loadfile()函数,如下所示:
复制代码 代码如下:

local hello = loadfile("hello")
... ...
... ...
hello()

c# 对象池的简单书写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//Object Pool ( http://unitypatterns.com/resource/objectpool/ ) is licensed under:
/* The MIT License (MIT)
Copyright (c) 2013 UnityPatterns
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in the
Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */


using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public sealed class ObjectPool : MonoBehaviour
{
static ObjectPool _instance;

Dictionary<Component, List<Component>> objectLookup = new Dictionary<Component, List<Component>>();
Dictionary<Component, Component> prefabLookup = new Dictionary<Component, Component>();

public static void Clear()
{

instance.objectLookup.Clear();
instance.prefabLookup.Clear();
}

public static void CreatePool<T>(T prefab) where T : Component
{
if(prefab==null)
return;
if (!instance.objectLookup.ContainsKey(prefab))
instance.objectLookup.Add(prefab, new List<Component>());
}

public static T Spawn<T>(T prefab, Vector3 position, Quaternion rotation) where T : Component
{
if(prefab==null)
return null;
if (instance.objectLookup.ContainsKey(prefab))
{
T obj = null;
var list = instance.objectLookup[prefab];
if (list.Count > 0)
{
while (obj == null && list.Count > 0)
{
obj = list[0] as T;
list.RemoveAt(0);
}
if (obj != null)
{
obj.transform.parent = null;
obj.transform.localPosition = position;
obj.transform.localRotation = rotation;
obj.gameObject.SetActive(true);
instance.prefabLookup.Add(obj, prefab);
obj.SendMessage("OnSpawned", null, SendMessageOptions.DontRequireReceiver);
return (T)obj;
}
}
obj = (T)Object.Instantiate(prefab, position, rotation);
obj.name = prefab.name;
instance.prefabLookup.Add(obj, prefab);
obj.SendMessage("OnSpawned", null, SendMessageOptions.DontRequireReceiver);
return (T)obj;
}
else {
T obj = null;
obj = (T)Object.Instantiate(prefab, position, rotation);
obj.name=prefab.name;
return (T)obj;
}
}
public static T Spawn<T>(T prefab, Vector3 position) where T : Component
{
return Spawn(prefab, position, Quaternion.identity);
}
public static T Spawn<T>(T prefab) where T : Component
{
return Spawn(prefab, Vector3.zero, Quaternion.identity);
}

public static void Recycle<T>(T obj) where T : Component
{
if (instance.prefabLookup.ContainsKey(obj))
{
instance.objectLookup[instance.prefabLookup[obj]].Add(obj);
instance.prefabLookup.Remove(obj);
obj.transform.parent = instance.transform;
obj.gameObject.SetActive(false);
}
else
Object.Destroy(obj.gameObject);
}

public static int Count<T>(T prefab) where T : Component
{
if (instance.objectLookup.ContainsKey(prefab))
return instance.objectLookup[prefab].Count;
else
return 0;
}

public static ObjectPool instance
{
get
{
if (_instance != null)
return _instance;
var obj = new GameObject("_ObjectPool");
obj.transform.localPosition = Vector3.zero;
_instance = obj.AddComponent<ObjectPool>();
return _instance;
}
}
}

public static class ObjectPoolExtensions
{
public static void CreatePool<T>(this T prefab) where T : Component
{
ObjectPool.CreatePool(prefab);
}

public static T Spawn<T>(this T prefab, Vector3 position, Quaternion rotation) where T : Component
{
return ObjectPool.Spawn(prefab, position, rotation);
}
public static T Spawn<T>(this T prefab, Vector3 position) where T : Component
{
return ObjectPool.Spawn(prefab, position, Quaternion.identity);
}
public static T Spawn<T>(this T prefab) where T : Component
{
return ObjectPool.Spawn(prefab, Vector3.zero, Quaternion.identity);
}

public static void Recycle<T>(this T obj) where T : Component
{
ObjectPool.Recycle(obj);
}

public static int Count<T>(T prefab) where T : Component
{
return ObjectPool.Count(prefab);
}
}

android 些许记录

Android 计时器的使用

1
2
3
4
5
6
7
8
9
mTT = new TimerTask() {
@Override
public void run() {

Message msg = myHandler.obtainMessage();
msg.what = MESSAGE_SENDTO_SERVER;
myHandler.sendMessage(msg);
}
};
mTimer.scheduleAtFixedRate(mTT, 1, 4000);
  • TimerTask 后面加要在计时器中todo的事情
  • public void scheduleAtFixedRate(TimerTask task,
    Date firstTime,
    long period) 
    
  • task - task to be scheduled.
    firstTime - First time at which task is to be executed.
    period - time in milliseconds between successive task executions.

Android 摄像机预览图片上传服务器

图片处理

  • 在Camera.PreviewCallback方法中处理
  • 用YuvImage 获取图片和转化为jpg
  • 用Matrix 和 Bitmap 对图片进行高效处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    private Camera.PreviewCallback mPreviewCallback = new Camera.PreviewCallback() {

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

    if (!mNeedToSend) {
    return;
    }
    mNeedToSend = false;

    Camera.Parameters parameters = camera.getParameters();

    // Log.d(TAG, "frame updated...........:" + data.length);
    Log.d(TAG, "Data sends to the server!");
    try {
    YuvImage yuvImage = new YuvImage(data,
    parameters.getPreviewFormat(),
    parameters.getPreviewSize().width,
    parameters.getPreviewSize().height, null);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    yuvImage.compressToJpeg(
    new Rect(0, 0, parameters.getPreviewSize().width,
    parameters.getPreviewSize().height), 90,
    baos);
    yuvImage = null;

    byte cdata[] = baos.toByteArray();
    Bitmap bitmap = BitmapFactory.decodeByteArray(cdata, 0,
    cdata.length);
    baos.close();
    baos = null;

    Matrix matrix = new Matrix();
    matrix.postRotate(-90);
    matrix.postScale(-1, -1);
    Bitmap rBitmap = Bitmap
    .createBitmap(bitmap, 0, 0, bitmap.getWidth(),
    bitmap.getHeight(), matrix, true);
    bitmap.recycle();
    bitmap = null;

    int w = 252;
    int h = 336;
    float scaleWidth = ((float) w) / rBitmap.getWidth();
    float scaleHeight = ((float) h) / rBitmap.getHeight();

    Matrix matrix2 = new Matrix();
    matrix2.postScale(scaleWidth, scaleHeight);
    Bitmap rrrBitmap = Bitmap.createBitmap(rBitmap, 0, 0,
    rBitmap.getWidth(), rBitmap.getHeight(), matrix2, true);
    Log.d(TAG,
    "(" + rrrBitmap.getWidth() + ","
    + rrrBitmap.getHeight() + ")");
    rBitmap.recycle();
    rBitmap = null;

    if (null != rrrBitmap) {

    ByteArrayOutputStream rbaos = new ByteArrayOutputStream();
    //带缓冲区的输出流,能够提高文件的写入效率
    BufferedOutputStream bos = new BufferedOutputStream(rbaos);
    rrrBitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);

    bos.flush();
    bos.close();
    // Send Data to server.
    sendJpeg2Server(rbaos.toByteArray());
    rbaos.close();
    rrrBitmap.recycle();
    rrrBitmap = null;
    }

    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    }

    }

unity 给android 传递多参

androidjavaclass

1
2
AndroidJavaClass jc = new 	AndroidJavaClass("com.au.classroom.UnityPlayerActivity");
jc.CallStatic("TryClass","31",32.0f);
  • 在callstatic param object[] 传入对应个数和类型的参数

AndroidJNI

1
2
3
4
5
6
7
IntPtr clazzPtr = AndroidJNI.FindClass("com.au.classroom.UnityPlayerActivity");
IntPtr methodPtr = AndroidJNI.GetStaticMethodID(clazzPtr, "SaveAchievement", "(I)V");

var args = new object[1];
args[0] = rightcount;

AndroidJNI.CallStaticVoidMethod(clazzPtr, methodPtr, AndroidJNIHelper.CreateJNIArgArray(args));
  • clazzPtr 获取java类
  • methodPtr 获取对应的方法
    • 第二个参数为方法,第三个参数为对应方法里面的参数类型 比如 string 对应 Ljava/lang/String ; int 对应 (I)V ;两个int就为 (II)V
  • AndroidJNI.CallStaticVoidMethod 第三个参数为要传的对应数据

C# Struct 和Class 区别

Class

  • 引用
  • 可以为null
  • 实例化在堆上
  • 构造函数可以无参数
  • 必须new来实例化

Struct

  • 值类型
  • 不能为null
  • 实例化在栈上
  • 构造函数必须有参数
  • 可new ,可不new 来实例化

  • 程序运行期间动态分配的空间
  • 无序的,是一片不连续的内存域,要用户自己来控制和释放(GC)

  • 编译期间分配好的内存空间,因此要在代码中明确定义栈的大小
  • 要管存储顺序,保持先进后出的原则,是一片连续的内存域,有系统自动分配和维护

ngui和unity5.2.2的bug

Unity 5.2.1 + NGUI 3.9.2

经常 crash 在保存场景的时候

完美解决方案

修改ngui uilabel代码
line 1139 : #if !UNITY_4_3 && !UNITY_4_5 && !UNITY_4_6

修改成 : if !UNITY_4_3 && !UNITY_4_5 && !UNITY_4_6 && !UNITY_5

但是还有点问题是ngui使用动态文字,我感觉是ngui的问题,目前解决方案是把3.8.0的修改到3.9.2