神启

思考并回答以下问题:

  • 如何抽象技能?就像UI一样,把技能按各个方面分类。例如单体,区域。治疗,伤害。可以学,不可以学。
  • 一个txt,一个实体对象a,一个配置读取b,一个管理器c负责调用b把读取到的txt赋值给a

快速跳转

开发规范

公共规范:

  • 1.所有的类名和文件名以X开头,例如XLogicWorld.cs。
  • 2.public成员变量以大写字母开头,其他成员变量以“m_”开头,public函数以大写字母开头,其他不做约束。
  • 3.如非必要不要直接继承自MonoBehaviour这个脚本,以后几乎不会用到要直接继承自MonoBehaviour的功能。一来是功能上不必要这么做,二来是强烈不提倡脚本自己Start和Update;所有Start和Update的入口都在LogicApp中。
  • 4.代码中不要出现大量的注释和Log日志(自己调试可以,提交版本之前请将代码中无用的地方删掉)。
  • 5.不要直接调用Debug.Log(),统一使用Log.Write(…),便于日志统一管理。
  • 6.如非不可避免,代码不允许出现Warning。

LogicApp

/LogicApp.cs

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
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using resource;

class LogicApp : MonoBehaviour
{
public Camera MainCamera = null;
public Camera UICamera = null;

public string ApacheServer = "0.0.0.0:0";
public string LoginServer = "0.0.0.0:0";
public Define UserDefine = null;

public XWeUIRoot UIRoot;

public static LogicApp SP { get; private set; }

public void Start()
{
LogicApp.SP = this;
DontDestroyOnLoad(this);
CoroutineManager.Init(this);

CoroutineManager.StartCoroutine(StartDataInit());
}

private IEnumerator StartDataInit()
{
Log.Write("LogicApp StartDataInit Start");

Input.imeCompositionMode = IMECompositionMode.On;
Application.runInBackground = true;
//Application.RegisterLogCallback(new Application.LogCallback(MyExpception.OnLogCallback));
MyExpception.NewErrorEvent += new Action<string>(Statistics.ReportBug);
Log.Write(DumpApplication());

XDownloadManager.Init(true);
InitGameMgr();

XUTFirstLogin.CurLoading = AppLoader.SP;
yield return StartCoroutine(InitStartupParams());
yield return StartCoroutine(AppLoader.LoadConfig());
yield return StartCoroutine(AppLoader.LoadMaterial());

Log.Write("LogicApp StartDataInit End");

XEventManager.SP.SendEvent(EEvent.UI_Show, EUIPanel.eLoginUI);
}

private void InitGameMgr()
{
XDBConfigManager.SP.Init();
// 事件初始化
XEventManager.SP.Init();
// UI相关初始化
XUIManager.SP.Init();
// 逻辑初始化
XLogicWorld.SP.Init();

XResourceManager.Init();
XNoticeManager.SP.Init();

// 硬件消息初始化
XKeyEventGate.SP.Init();
XMouseEventGate.SP.Init();
FeatureDataUnLockMgr.SP.Init();
}

private IEnumerator InitStartupParams()
{
ServiceInfo.SetDefault();
if ((Application.platform != RuntimePlatform.WindowsWebPlayer) && (Application.platform != RuntimePlatform.OSXWebPlayer))
{
if (Application.platform != RuntimePlatform.WindowsEditor)
{
if (Application.platform == RuntimePlatform.WindowsPlayer)
{
}
}
}
yield return 0;
}

public void Update()
{
XHardWareGate.SP.Breathe();
XLogicWorld.SP.Breathe();
XCameraLogic.SP.Breathe();
XDownloadManager.Update();
XUIManager.SP.Breathe();
}

void LateUpdate()
{
XCameraLogic.SP.LateBreathe();
}

void OnGUI()
{
XCameraLogic.SP.OnRenderObject();
}

public void OnApplicationQuit()
{
//--4>TODO: 目前是单个场景, 离开直接退出
XLogicWorld.SP.OnDestroy();
}

public void OnLevelWasLoaded(int level)
{
int levelId = XLogicWorld.SP.SceneManager.LoadedSceneId;
string levelName = XLogicWorld.SP.SceneManager.LoadedSceneName;
ESceneType levelType = XLogicWorld.SP.SceneManager.LoadedSceneType;
XLogicWorld.SP.OnLevelLoaded(levelId, levelName, levelType);
}

private static string DumpApplication()
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("DumpApplication\n", new object[0]);
builder.AppendFormat(" isWebPlayer: {0}\n", Application.isWebPlayer);
builder.AppendFormat(" isPlaying: {0}\n", Application.isPlaying);
builder.AppendFormat(" isLoadingLevel: {0}\n", Application.isLoadingLevel);
builder.AppendFormat(" isEditor: {0}\n", Application.isEditor);
builder.AppendFormat(" platform: {0}\n", Application.platform);
builder.AppendFormat(" absoluteURL: {0}\n", Application.absoluteURL);
builder.AppendFormat(" dataPath: {0}\n", Application.dataPath);
builder.AppendFormat(" persistentDataPath: {0}\n", Application.persistentDataPath);
builder.AppendFormat(" temporaryCachePath: {0}\n", Application.temporaryCachePath);
builder.AppendFormat(" webSecurityHostUrl: {0}\n", Application.webSecurityHostUrl);
builder.AppendFormat(" webSecurityEnabled: {0}\n", Application.webSecurityEnabled);
builder.AppendFormat(" srcValue: {0}\n", Application.srcValue);
builder.AppendFormat(" targetFrameRate: {0}\n", Application.targetFrameRate);
builder.AppendFormat(" unityVersion: {0}\n", Application.unityVersion);
return builder.ToString();
}
}

日志

最开始,需要一个日志类,多项目通用的。

System/Platform.cs

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
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

// 日志级别枚举
public enum LogLevel
{
ERROR,
WARN,
INFO,
DEBUG,
}

// 静态工具类,里面的成员全部是静态
public static class Log
{
// 自身维护的列表,私有
private static List<string> mNetLogs = new List<string>();
private static List<string> mTempLog = new List<string>();
private static object _trace_lock = new object();

// 外界可定制这些参数
public static bool IsLogs = false;
public static int MAX_NET_LOGS = 20480;
public static int MAX_TEMP_LOG = 10;

public static string ObjectToString(object obj)
{
return obj.ToString();
}

public static void AddNetLog(string str)
{
str = DateTime.Now.ToLongTimeString() + " " + str;
if (IsLogs)
{
Debug.Log(str);
}
List<string> list = mNetLogs;
lock (list)
{
mNetLogs.Add(str);
if (mNetLogs.Count > MAX_NET_LOGS)
{
mNetLogs.RemoveAt(0);
}
}
}

public static void ClearTempLog()
{
mTempLog.Clear();
}

public static string GetNetLog()
{
string[] strArray = null;
List<string> list = mNetLogs;
lock (list)
{
// ToArray方法将List集合转换为对应的数组
strArray = mNetLogs.ToArray();
}
return string.Join("\r\n", strArray);
}

public static List<string> GetTempLog()
{
return mTempLog;
}

public static void LogMsg(string msg)
{
object obj2 = _trace_lock;
lock (obj2)
{
Console.WriteLine("{0}: LOGMSG[{1}]: {2}", DateTime.Now.ToLongTimeString(), Thread.CurrentThread.ManagedThreadId, msg);
}
}

public static void LogMsg(string msg, int i)
{
LogMsg(msg);
}

public static void AddTempLog(params object[] args)
{
// Array.ConvertAll<TInput, TOutput> 方法
// 将一种类型的数组转换为另一种类型的数组。

// Converter<TInput, TOutput> 委托
// 表示将对象从一种类型转换为另一种类型的方法。
string item = string.Join(",", Array.ConvertAll<object, string>(args, new Converter<object,string>(ObjectToString)));
mTempLog.Add(item);
if (mTempLog.Count > MAX_TEMP_LOG)
{
mTempLog.RemoveAt(0);
}
}

private static void DoLog(LogLevel level, object message)
{
switch (level)
{
case LogLevel.ERROR:
Debug.LogError(message);
break;
case LogLevel.WARN:
Debug.LogWarning(message);
break;
case LogLevel.INFO:
Debug.Log(message);
break;
case LogLevel.DEBUG:
Debug.Log(message);
break;
default:
break;
}
}

// 对外提供的四个Write重载方法
public static void Write(string format, params object[] args)
{
DoLog(LogLevel.DEBUG, string.Format(format, args));
}

public static void Write(LogLevel level, string format, params object[] args)
{
DoLog(level, string.Format(format, args));
}

public static void Write(LogLevel level, object message)
{
DoLog(level, message);
}

public static void Write(object message)
{
DoLog(LogLevel.DEBUG, message);
}
}

对象管理

XU3dEffect -> XU3dDynObject -> XU3dObject

GameBehaviour/XU3dObject.cs 所有对象的基类,没有继承MonoBehavior

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
using UnityEngine;
using System.Collections.Generic;

public class XU3dObject
{
public GameObject m_gameObject { get; private set; }
private Vector3 m_position; // 绝对坐标
protected Vector3 m_rotation; // 绝对旋转
private Vector3 m_scale; // 相对缩放
private Transform m_parent; // 父节点
private int m_layer; // 所在层
private bool m_bVisible; // 加个b表示是bool值,是否可见
private List<GameObject> m_children; // 子对象

// 获取/设置对象的可见性
public virtual bool Visible
{
get
{
if (null != m_gameObject)
m_bVisible = m_gameObject.activeSelf;
return m_bVisible;
}
set
{
m_bVisible = value;
if (null != m_gameObject && m_gameObject.activeSelf != m_bVisible) // 已经可见就不要再设置成可见了
{
m_gameObject.SetActive(m_bVisible);
}
}
}

// 获取/设置对象的全局位置
public Vector3 Position
{
get
{
if (null != m_gameObject)
m_position = m_gameObject.transform.position;
return position;
}
set
{
m_position = value;
if (null != m_gameObject)
{
m_gameObject.transform.position = m_position;
}
}
}

// 获取/设置父节点的Transform
public Transform Parent
{
get
{
if (null != m_gameObject)
m_parent = m_gameObject.transform.parent;
return m_parent;
}
set
{
m_parent = value;
if (null != m_gameObject)
{
m_gameObject.transform.parent = m_parent;
}
}
}

// 获取/设置相对于父节点的位置(相对位置)
public Vector3 LocalPosition
{
get
{
if (null == Parent) // Parent是Transform类型
return Position;
return Parent.InverseTransformPoint(Position);
/*TransformPoint是变换自身坐标到世界坐标
InverseTransformPoint是变换世界坐标到自身坐标

比如说物体a的坐标内有一个(3,3,3)的点,你想知道这个点在世界坐标的位置,就应该用TransformPoint。
反之在世界坐标下有一个点,你想知道这个点如果是在物体a的坐标下是一个什么位置,就应该用InverseTransformPoint。

其实就是在编辑器里把物体拽到根目录下的位置和物体在某物体内的位置之间的一个转换
*/
}
set
{
if(null == Parent)
Position = value; // 这个value是本地坐标
else
Position = Parent.TransformPoint(value);
}
}

public Vector3 Direction
{
get
{
if (null != m_gameObject)
m_rotation = m_gameObject.transform.eulerAngles;
return m_rotation;
}
set
{
m_rotation = value;
if (null != m_gameObject)
{
m_gameObject.transform.rotation = Quaternion.Euler(m_rotation);
}
}
}

public Vector3 LocalDirection
{
get
{
if (null == Parent)
return Direction;
return Direction - Parent.transform.eulerAngles;
}
set
{
if (null == Parent)
Direction = value;
else
Direction = Parent.transform.eulerAngles + value;
}
}

// 获取/设置相对缩放,可以让子类重写覆盖当前规则
public virtual Vector3 Scale
{
get
{
if (null != m_gameObject)
m_scale = m_gameObject.transform.localScale;
return m_scale;
}
set
{
m_scale = value;
if (null != m_gameObject)
{
m_gameObject.transform.localScale = m_scale;
}
}
}

// 获取/设置对象所在层
public int Layer
{
get
{
if (null != m_gameObject)
m_layer = m_gameObject.layer;
return m_layer;
}
set
{
m_layer = value;
if (null != m_gameObject)
{
XUtil.SetLayer(m_gameObject, m_layer);
}
}
}

// 构造函数初始化字段
public XU3dObject()
{
m_gameObject = null;
m_bVisible = true;
m_position = Vector3.zero;
m_position = Vector3.zero;
m_scale = Vector3.one;
m_parent = null;
m_children = new List<GameObject>();
}

// 对外提供的接口
// 创建一个新对象
public void NewGameObject(string name)
{
restoreInfo();
detachAll();
if (null != m_gameObject)
GameObject.Destroy(m_gameObject);
m_gameObject = new GameObject(name);
resetGameObject();
reAttachAll();
}

// 对外提供的接口
// 把对象设置
public void AttachGameObject(GameObject go)
{
AttachGameObject(go, Vector3.zero, Vector3.zero);
}

public void AttachGameObject(GameObject go, Vector3 localPosition, Vector3 localRotation)
{
if (null == go || null == m_gameObject) return;

go.transform.parent = m_gameObject.transform;
go.transform.localPosition = localPosition;
go.transform.localRotation = Quaternion.Euler(localRotation);
m_children.Add(go);
}

public void AttachU3dObject(XU3dObject u3dObject)
{
AttachU3dObject(u3dObject, Vector3.zero, Vector3.zero);
}

public void AttachU3dObject(XU3dObject u3dObject, Vector3 localPosition, Vector3 localRotation)
{
if (null == u3dObject) return;
AttachGameObject(u3dObject.m_gameObject, localPosition, localRotation);
}

private void restoreInfo()
{
// #pragma warning 编号
// 可以启用或禁用特定警告。
// 未指定警告编号时,disable 会禁用所有警告,restore 会启用所有警告。
#pragma warning disable
bool b = Visible;
Vector3 vec = Position;
vec = Direction;
Transform t = Parent;
vec = Scale;
int n = Layer;
#pragma warning restore
}

// 操作m_children列表
// 拆卸所有子对象
private void detachAll()
{
for (int i = 0; i < m_children.Count;)
{
GameObject go = m_children[i];
if (null != go && go.transform.parent == m_gameObject.transform)
{
go.transform.parent = null;
i++;
continue;
}
m_children.RemoveAt(i);
}
}

// 操作m_children列表
// 绑定所有子对象
private void reAttachAll()
{
for (int i = 0; i < m_gameObject.Count;)
{
GameObject go = m_children[i];
if (null != go)
{
go.transform.parent = m_gameObject.transform;
i++;
continue;
}
m_children.RemoveAt(i);
}
}


// 重新设置 position / rotation / parent / layer / children
private void resetGameObject()
{
if (null == m_gameObject) return;

m_gameObject.transform.parent = m_parent;
m_gameObject.transform.position = m_position;
m_gameObject.transform.rotation = Quaternion.Euler(m_rotation);
m_gameObject.transform.localScale = m_scale;

XUtil.SetLayer(m_gameObject, m_layer);

for (int i = 0; i < m_children.Count;)
{
GameObject go = m_children[i];
if (null == go)
{
m_children.RemoveAt(i);
continue;
}
go.transform.parent = m_gameObject.transform;
i++;
}
if (!m_bVisible) m_gameObject.SetActive(false);
Object.DontDestroyOnLoad(m_gameObject);
}

// 对外提供的,销毁对象
public void Destroy()
{
Destroy(false);
}

// 参数为是否销毁子对象
public virtual void Destroy(bool bDestroyAll)
{
if (null == m_gameObject)
return;

if (!bDestroyAll)
{
for (int i = 0; i < m_children.Count; i++)
{
GameObject go = m_children[i];

if (null != go && go.transform.parent == m_gameObject.transform)
{
go.transform.parent = null;
}
}
}
m_children.Clear();
GameObject.Destroy(m_gameObject);
}
}

GameBehaviour/XU3dDynObject.cs 动态对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;
using resource;
using System.Collections;

public abstract class XU3dDynObject : XU3dObject
{
public uint m_nId;
protected XResourceBase m_DynObject;

public XU3dDynObject()
{
m_nId = 0;
}

~XU3dDynObject()
{

}

public abstract void RefreshDynObject(uint id);
}

GameBehaviour/XU3dEffect.cs

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using UnityEngine;
using System.Collections;
using resource;

public class XU3dEffect : XU3dDynObject
{
private bool bDone; // 标记特效是否加载完成
private bool bPlayOver; // 标记特效是否播放结束
private NcDestroyEvent m_DestroyEvt;
public NcDestroyEvent.OnDestroyEvt onEffectPlayOver;
public delegate void OnEffectLoaded(XU3dEffect self);
private static uint mRunNumber = 0;
OnEffectLoaded mEffectLoaded;
private GameObject mEffGO;

public XU3dEffect(uint nId)
{
RefreshDynObject(nId);
}

public XU3dEffect(uint nId,OnEffectLoaded handle)
{
mEffectLoaded = handle;
RefreshDynObject(nId);
}

public override void RefreshDynObject (uint id)
{
if(m_nId == id)
return;

m_nId = id;
//releaseDynObject();
doRefreshDynObject();
}

private void doRefreshDynObject()
{
NewGameObject("Effect_" + m_nId + "_" + mRunNumber);
mRunNumber++;
bDone = false;
bPlayOver = false;
onEffectPlayOver = null;

m_DynObject = XResourceManager.GetResource(XResourceEffect.ResTypeName,m_nId);
if(m_DynObject == null)
{
Log.Write(LogLevel.ERROR,"cant find Effect ID {0}",m_nId);
return ;
}

if(m_DynObject.IsLoadDone())
{
LoadCompleted(m_DynObject.MainAsset.DownLoad);
}
else
{
if(m_DynObject != null)
m_DynObject.ResLoadEvent -= LoadCompleted;
XResourceManager.StartLoadResource(XResourceEffect.ResTypeName,m_nId);
m_DynObject.ResLoadEvent += new XResourceBase.LoadCompletedDelegate(LoadCompleted);
}
}

public void LoadCompleted(DownloadItem item)
{
#if RES_DEBUG
GameObject go = item.go as GameObject;
#else
GameObject go = item.ab.mainAsset as GameObject;
#endif
onEffectDone(m_nId,go);
}

private void onEffectDone(uint nEffectId, GameObject go)
{
bDone = true;
if(!bPlayOver)
{
if(null == go)
{
Log.Write(LogLevel.WARN, "XU3dEffect, wrong resource: {0}", m_nId);
return;
}

if(mEffGO != null)
return ;

if(m_gameObject == null)
return;

mEffGO = XUtil.Instantiate(go, m_gameObject.transform, Vector3.zero, Vector3.zero);
Object.DontDestroyOnLoad(mEffGO);
XUtil.SetLayer(mEffGO, Layer);
#pragma warning disable
mEffGO.SetActiveRecursively(true);
#pragma warning restore

if(mEffectLoaded != null)
mEffectLoaded(this);

NcAutoDestruct autoDes = mEffGO.GetComponent<NcAutoDestruct>();
if(autoDes == null)
return ;

if(autoDes.m_fLifeTime == 0)
return ;
autoDes.enabled = true;
if(mEffGO)
mEffGO.AddComponent<NcDestroyEvent>().onDestroyEvt += onEffectDestroy;
}
}

private void onEffectError(int nEffectId)
{
bDone = true;
Log.Write(LogLevel.WARN, "XU3dEffect, wrong resource: {0}", m_nId);
}

private void onEffectDestroy()
{
bPlayOver = true;
if(null != onEffectPlayOver)
{
onEffectPlayOver();
onEffectPlayOver = null;
}
Destroy(true);
//releaseDynObject();
}

// private void releaseDynObject()
// {
// if(null != m_DynObject)
// {
// if(!bDone)
// {
// m_DynObject.onDone -= onEffectDone;
// m_DynObject.onError -= onEffectError;
// }
// m_DynObject.refCount--;
// m_DynObject = null;
// }
// }

public override void Destroy (bool bDestroyAll)
{
//releaseDynObject();
base.Destroy(bDestroyAll);
}

public void FlyFromTo(Transform fromTran, Transform toTran,float speed,float HWRate)
{
if(null == fromTran || null == toTran) return;
if(null == m_gameObject) return;
NcEffectFlying fly = m_gameObject.AddComponent<NcEffectFlying>();
fly.FromPos = fromTran.position;
fly.ToPos = toTran.position;
fly.Speed = speed;
fly.HWRate = HWRate;
}

public void FlyFromTo(Vector3 fromPos, Vector3 toPos,float speed,float HWRate)
{
if(null == m_gameObject) return;
NcEffectFlying fly = m_gameObject.AddComponent<NcEffectFlying>();
fly.FromPos = fromPos;
fly.ToPos = toPos;
fly.Speed = speed;
fly.HWRate = HWRate;
}
}

GameBehaviour/IBehaviourListener.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
using System;
using UnityEngine;

public interface IBehaviourListener
{
void OnMouseDown(int mouseCode, Vector3 clickPoint);
void OnMouseUp(int mouseCode);
void OnMouseUpAsButton(int mouseCode);
void OnMouseEnter();
void OnMouseExit();
void OnControllerColliderHit(ControllerColliderHit hit);
void OnCancelSelect();
}

GameBehaviour/XObjectModel.cs

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public enum EModelEvent
{
// XGameObject
evtName,
evtHeadBoardType,
evtModelId,
evtPosition,
evtDirection,
evtVisible,
evtDestroy,
evtAttachGo,
evtScale,
evtHudVisible,
evtMatColor,

// XCharacter
evtTitle,
evtHp,
evtMaxHp,
evtWeaponId,
evtAnimation,
evtShowBlood,
evtFlyString,
evtFlyStringHalf,
evtNickName,

// XPlayer
evtUColor,
evtMountIndex,

// XNpc
evtNpcFuncHead,

evtSelect,
evtSetHeadVisiable,

// XMainPlayer,
evtAttachMainCamera,
evtFadeOut,
}

//头顶板子的类型
public enum EHeadBoard_Type
{
EHeadBoard_Type_None,
EHeadBoard_Type_Monster,
EHeadBoard_Type_Player,
EHeadBoard_Type_NPC,
EHeadBoard_Type_Num
}

public enum EMoveTarget_Type
{
EMoveTarget_Object,
EMoveTarget_Pos,
EMoveTarget_Num
}

public class XObjectModel
{
public int index = 0;
private static readonly Vector3 CAMERA_DEFAULT_POS = new Vector3 (0, 20, -20);
private static uint FootEffectID = 900038;
private static Transform m_ObjectManager = null;
private static int ObjectIndex = 0;

private static Transform ObjectParent {
get {
if (null == m_ObjectManager) {
m_ObjectManager = new GameObject ("ObjectManager").transform;
m_ObjectManager.parent = LogicApp.SP.transform;
m_ObjectManager.position = Vector3.zero;
}
return m_ObjectManager;
}
}

public delegate void LoadModelComplete (XObjectModel model);
public LoadModelComplete mainModelLoaded;
public event LoadModelComplete LoadModelEvent;

public delegate void LoadMountModelComplete(XU3dModel model);
public LoadMountModelComplete mountLoaded;

//private XGameObject m_xobj;
private XU3dModel m_MainModel;
private XU3dModel m_WeaponModel;
private XU3dModel m_MountModel;
private bool mountLoadFinish = false;

EHeadBoard_Type mHeadBoardType = EHeadBoard_Type.EHeadBoard_Type_None;
private XObjectHead m_Head;
private string m_Name;

private XU3dEffect mSelectEffect;


private XObjectHalf m_Half;

public XU3dModel mainModel {
get{ return m_MainModel; }
}

public XU3dModel mountModel {
get{ return m_MountModel; }
}

private static EAnimName[] m_mountIdleAnim = new EAnimName[]{EAnimName.Idle, EAnimName.RideIdle, EAnimName.FloatIdle};
private static EAnimName[] m_mountRunAnim = new EAnimName[]{ EAnimName.Idle, EAnimName.RideRun, EAnimName.FloatRun };
private static ESkeleton[] m_syncSkeleton = new ESkeleton[] { ESkeleton.eCapsuleBottom, ESkeleton.eCapsuleHalf, ESkeleton.eCapsuleTop };

// 信息记录
private EAnimName m_curAnim; // 切换动画时记录, 在上下坐骑的时候使用
private float m_curAnimSpeed;
private bool m_bIsVisible; // 记录是否可见, Head资源到时利用
private bool m_bShowBlood; // 记录血条是否可见, Head资源到时利用
private int m_nHp; // 记录血量, Head到时利用
private int m_nMaxHp; // 记录最大血量, Head到时利用
private string m_nNpcFuncName; // 记录npc头顶面板图片, 资源到时使用
private string m_nNickName;

private EMoveTarget_Type mMoveTType;
private GameObject m_MoveTarget;
private XU3dEffect m_FootEffect;
private Vector3 m_MoveTargetPos;

public interface IModelListener
{
void OnModelLoaded();
void OnWeaponLoaded();
}

public void AddModelListener(IModelListener pML)
{
mListenerList.Add (pML);
}

List<IModelListener> mListenerList = new List<IModelListener> ();

public XObjectModel ()
{
m_MainModel = null;
m_WeaponModel = null;
m_MountModel = null;
m_Head = null;

m_bIsVisible = true;
m_bShowBlood = false;
m_nHp = 0;
m_nMaxHp = 1;
}

public void HandleEvent(EModelEvent evt, params object[] args)
{
switch (evt)
{
case(EModelEvent.evtName):
onName ((string)args [0]);

break;
case(EModelEvent.evtModelId):
onModelId ((uint)args [0]);

break;
case(EModelEvent.evtWeaponId):
onWeaponID ((uint)args [0]);

break;
case(EModelEvent.evtPosition):
onPosition ((Vector3)args [0]);

break;
case(EModelEvent.evtDirection):
onDirection ((Vector3)args [0]);

break;
case(EModelEvent.evtMatColor):
onMatColor ((Color)args [0]);

break;
case(EModelEvent.evtVisible):
onVisible ((bool)args [0]);

break;
case(EModelEvent.evtDestroy):
onDestroy ();

break;
case(EModelEvent.evtAttachGo):
onAttachGo ((ESkeleton)args [0], (GameObject)args [1], (Vector3)args [2], (Vector3)args [3]);

break;
case(EModelEvent.evtScale):
onScale ((float)(args [0]));

break;
case(EModelEvent.evtMountIndex):
onMountIndex ((ushort)args [0]);

break;
case(EModelEvent.evtAttachMainCamera):
onAttachMainCamera ();

break;
case(EModelEvent.evtHp):
onHp ((int)(args [0]));

break;
case(EModelEvent.evtMaxHp):
onMaxHp ((int)(args [0]));

break;
case(EModelEvent.evtNpcFuncHead):
onNpcFuncPic ((string)(args [0]));

break;
case(EModelEvent.evtSetHeadVisiable):
onHeadVisiable ((bool)(args [0]));

break;
case(EModelEvent.evtAnimation):
onAnimation ((EAnimName)(args [0]), (float)(args [1]), (bool)(args [2]));

break;
case(EModelEvent.evtShowBlood):
onShowBlood ((bool)(args [0]));

break;
case EModelEvent.evtFlyString:
onFlyString ((EFlyStrType)args [0], (string)args [1]);

break;
case EModelEvent.evtFlyStringHalf:
onFlyStringHalf ((EObjectHalfHintType)args [0], (string)args [1]);

break;
case EModelEvent.evtHudVisible :
onHudVisible ((bool)args [0]);

break;
case EModelEvent.evtFadeOut :
FadeOut ();

break;
case EModelEvent.evtNickName:
onNickName ((string)args [0]);

break;
case EModelEvent.evtHeadBoardType:
onHeadBoardType((EHeadBoard_Type)args[0]);
break;
case EModelEvent.evtSelect:
onSelect((uint)args[0],(bool)args[1]);
break;
}
}

public void GetHeadPosInfo(ref Vector3 pos, ref GameObject parent)
{
if (null == m_Head)
return;

m_Head.GetHeadPosInfo (ref pos, ref parent);
return;
}

private void onHudVisible(bool isVisible)
{
if (m_Head == null)
return ;

m_Head.SetVisible (isVisible);
}

private void onHeadBoardType(EHeadBoard_Type type)
{
if(mHeadBoardType == type)
return ;

mHeadBoardType = type;
}

private void onSelect(uint effectID,bool isSelect)
{
if(m_MainModel == null)
return ;

if(isSelect)
{
if(mSelectEffect == null)
mSelectEffect = new XU3dEffect(effectID);

mSelectEffect.Visible = true;
onAttachGo(ESkeleton.eMainObject,mSelectEffect.m_gameObject,Vector3.zero,Vector3.zero);
}
else
{
if(mSelectEffect == null)
return ;

mSelectEffect.Visible = false;
}
}

private void onName(string name)
{
m_Name = name;

if (null == m_Head)
return;
m_Head.SetName (m_Name);
}

private void onNickName(string str)
{
m_nNickName = str;
if (null == m_Head)
return;
m_Head.SetNickName (m_nNickName);
}

private void onModelId(uint modelId)
{
if (0 == modelId)
{
if (null != m_MainModel)
{
m_MainModel.Destroy (true);
m_MainModel = null;
if (null != m_Head)
{
Object.Destroy (m_Head.gameObject);
m_Head = null;
}
if (null != m_Half)
{
Object.Destroy (m_Half.gameObject);
m_Half = null;
}
}
}
else
{
if (null == m_MainModel)
{
m_MainModel = new XU3dModel(m_Name, modelId, ObjectParent, StartLoadHead);
}
else
{
m_MainModel.RefreshDynObject(modelId);

if ( modelId == m_MainModel.m_nId && null != mainModelLoaded )
mainModelLoaded(this);
}
}
}

private void onWeaponID(uint weaponID)
{
if (null != m_WeaponModel) {
m_WeaponModel.Destroy ();
m_WeaponModel = null;
}
m_WeaponModel = new XU3dModel ("role_weapon", weaponID,OnWeaponLoadDone);
}

public void OnWeaponLoadDone(XU3dModel self)
{
m_WeaponModel = self;

m_WeaponModel.Scale = m_MainModel.Scale;
m_MainModel.AttachU3dModel (ESkeleton.eWeapon, m_WeaponModel, ESkeleton.eMainObject);

foreach (IModelListener ls in mListenerList) {
ls.OnWeaponLoaded();
}
}

public void ReAttachWeapon()
{
if (m_WeaponModel == null)
return ;

m_MainModel.AttachU3dModel (ESkeleton.eWeapon, m_WeaponModel, ESkeleton.eMainObject);
}

public void ReAttachMount()
{
return;

if (m_MountModel == null)
return ;

ESkeleton ske = ESkeleton.eMountZuo;
if (XU3dModel.EMountModelType.eMountZhan == m_MountModel.m_mountModelType)
{
ske = ESkeleton.eMountZhan;
}
else if (XU3dModel.EMountModelType.eMountFei == m_MountModel.m_mountModelType)
{
ske = ESkeleton.eMountFei;
}
m_MainModel.ModelDirection = new Vector3(0, 180, 0);
m_MountModel.AttachU3dModel(ESkeleton.eMount, m_MainModel, ske);
onAnimation(m_curAnim, m_curAnimSpeed, false);
}

private void onPosition(Vector3 pos)
{
if (null != m_MountModel) {
m_MountModel.Position = pos;
}
else if (null != m_MainModel) {
m_MainModel.Position = pos;
}
}

private void onDirection(Vector3 dir)
{
if (null != m_MountModel) {
m_MountModel.ModelDirection = dir;
}
else if (null != m_MainModel) {
m_MainModel.ModelDirection = dir;
}
}

private void onMatColor(Color color)
{
if(m_MainModel != null)
{
m_MainModel.ChangeMatColor(color);
}
}

private void onVisible(bool b)
{
m_bIsVisible = b;
if (null != m_MountModel)
m_MountModel.Visible = b;
else if (null != m_MainModel)
m_MainModel.Visible = b;
//if (null != m_Head)
// m_Head.SetVisible (b);
if (null != m_Head)
{
m_Head.gameObject.SetActive(b);
}
}

private void onDestroy()
{
if (null != m_MountModel) {
m_MountModel.Destroy ();
m_MountModel = null;
}
if (null != m_MainModel) {
m_MainModel.Destroy ();
m_MainModel = null;
}
if (null != m_Head) {
Object.Destroy (m_Head.gameObject);
m_Head = null;
}
if (null != m_Half) {
Object.Destroy (m_Half.gameObject);
m_Half = null;
}
if (null != m_WeaponModel) {
m_WeaponModel.Destroy ();
m_WeaponModel = null;
}
}

private void onAttachGo(ESkeleton ske, GameObject go, Vector3 localPos, Vector3 localRot)
{
// 如果有坐骑, 可能会绑定到坐骑上
for (int i=0; i<m_syncSkeleton.Length; i++) {
if (ske == m_syncSkeleton [i]) {
if (null != m_MountModel) {
m_MountModel.AttachGameObject (ske, go, localPos, localRot);
}
else if (null != m_MainModel) {
m_MainModel.AttachGameObject (ske, go, localPos, localRot);
}
return;
}
}

if (null == m_MainModel)
return;
m_MainModel.AttachGameObject (ske, go, localPos, localRot);
}

private void onScale(float f)
{
if (null != m_MountModel) {
m_MountModel.Scale = Vector3.one * f;
}
else if (null != m_MainModel) {
m_MainModel.Scale = Vector3.one * f;
}
if (null != m_Head) {
m_Head.SetScale (1.0f / f);
}
if (null != m_Half) {
m_Half.SetScale (1.0f / f);
}
}

private void onHp(int nHp)
{
m_nHp = nHp;
if (null != m_Head) {
m_Head.SetHp (m_nHp, m_nMaxHp);
}
}

private void onNpcFuncPic(string spriteName)
{
m_nNpcFuncName = spriteName;
if (null != m_Head) {
m_Head.KinderIndex = index;
m_Head.SetNpcHead (spriteName);
}
}

private void onHeadVisiable(bool bVisiable)
{
m_Head.SetVisible (bVisiable);
}

private void onMaxHp(int nMaxHp)
{
m_nMaxHp = nMaxHp;
if (null != m_Head) {
m_Head.SetHp (m_nHp, m_nMaxHp);
}
}

private void onAnimation(EAnimName anim, float fSpeed, bool bIsPush)
{
m_curAnim = anim;
m_curAnimSpeed = fSpeed;
if (null != m_MountModel)
{
m_MountModel.PlayAnimation (anim, fSpeed, bIsPush);
if (null != m_MainModel)
{
if (EAnimName.Idle == anim)
{
EAnimName mAnim = m_mountIdleAnim [(int)m_MountModel.m_mountModelType - (int)XU3dModel.EMountModelType.eMountZhan];
m_MainModel.PlayAnimation (mAnim, fSpeed, bIsPush);
}
else if (EAnimName.Run == anim)
{
EAnimName mAnim = m_mountRunAnim [(int)m_MountModel.m_mountModelType - (int)XU3dModel.EMountModelType.eMountZhan];
m_MainModel.PlayAnimation (mAnim, fSpeed, bIsPush);
}
}
}
else if (null != m_MainModel)
{
m_MainModel.PlayAnimation (anim, fSpeed, bIsPush);

}
}

private void onShowBlood(bool b)
{
m_bShowBlood = b;
if (null != m_Head)
m_Head.ShowBlood (b);
}

private void onFlyString(EFlyStrType ft, string str)
{
if (null != m_Head)
m_Head.FlyString (ft, str);
}

private void onFlyStringHalf(EObjectHalfHintType ht, string str)
{
if (null != m_Half)
m_Half.FlyHalfHint (ht, str);
}

private void onMountIndex(ushort mountIndex)
{
// 使用坐骑前,先销毁上个坐骑,避免坐骑与角色之间的父子关系紊乱
if (null != m_MountModel && mountLoadFinish )
{
if (null != m_MainModel)
{
m_MainModel.Parent = m_MountModel.Parent;
m_MainModel.ModelDirection = m_MountModel.ModelDirection;
m_MainModel.m_gameObject.transform.localRotation = Quaternion.identity;
m_MainModel.Position = m_MountModel.Position;

m_MainModel.PlayAnimation (m_curAnim, m_curAnimSpeed, false);
for (int i=0; i<m_syncSkeleton.Length; i++)
m_MainModel.SyncChildObject (m_MountModel, m_syncSkeleton [i], m_syncSkeleton [i]);
if (m_MountModel.IsMainCameraAttach)
m_MainModel.AttachMainCamera (ESkeleton.eCameraBind);
}
m_MountModel.Destroy();
m_MountModel = null;
}
else if ( null != m_MountModel && !mountLoadFinish )
return;

XCfgMount cfgMount = XCfgMountMgr.SP.GetConfig (mountIndex);
if (null == cfgMount || 0 == cfgMount.ModelId)
{
return;
}
else
{
mountLoadFinish = false;
Vector3 temp = new Vector3(m_MainModel.Position.x, m_MainModel.Position.y, m_MainModel.Position.z);
m_MountModel = new XU3dModel ("_mount_" + cfgMount.MountName, cfgMount.ModelId,
(XU3dModel.EMountModelType)cfgMount.MountType, OnMountModelLoadDone);
m_MountModel.Position = temp;
}
}

public void OnMountModelLoadDone(XU3dModel self)
{
mountLoadFinish = true;
ESkeleton ske = ESkeleton.eMountZuo;
if (XU3dModel.EMountModelType.eMountZhan == self.m_mountModelType)
{
ske = ESkeleton.eMountZhan;
}
else if (XU3dModel.EMountModelType.eMountFei == self.m_mountModelType)
{
ske = ESkeleton.eMountFei;
}

self.Parent = m_MainModel.Parent;
self.ModelDirection = m_MainModel.ModelDirection;

self.AttachU3dModel (ESkeleton.eMount, m_MainModel, ske);
self.Scale = Vector3.one;
m_MainModel.Scale = Vector3.one;

m_MainModel.ModelDirection = new Vector3(0, 180, 0);

for (int i=0; i<m_syncSkeleton.Length; i++)
{
self.SyncSkeleton (m_MainModel, m_syncSkeleton [i]);
self.SyncChildObject (m_MainModel, m_syncSkeleton [i], m_syncSkeleton [i]);
}
if (m_MainModel.IsMainCameraAttach)
self.AttachMainCamera (ESkeleton.eCameraBind);

m_MountModel = self;
onAnimation (m_curAnim, m_curAnimSpeed, false);

if ( null != mountLoaded )
mountLoaded(self);
}

private void onAttachMainCamera()
{
bool success = false;
if (null != m_MountModel)
{
success = m_MountModel.AttachMainCamera (ESkeleton.eCameraBind, CAMERA_DEFAULT_POS);
}
if (null != m_MainModel && !success )
{
m_MainModel.AttachMainCamera (ESkeleton.eCameraBind, CAMERA_DEFAULT_POS);
}
}

public void _onObjectHeadReady(XObjectHead head)
{
if (null == m_MainModel || !m_MainModel.isLoaded || null != m_Head)
{
if( m_MainModel != null && m_MainModel.isLoaded )
{
Transform top1 = m_MainModel.GetSkeleton (ESkeleton.eCapsuleTop);
UIFollowTarget uiFT1 = m_Head.GetComponent<UIFollowTarget> ();
uiFT1.target = top1;
}
return;
}


GameObject child = NGUITools.AddChild (HUDRoot.go, head.gameObject);
m_Head = child.GetComponentInChildren<XObjectHead> ();
m_Head.Init ();
m_Head.KinderIndex = index;
Transform top = m_MainModel.GetSkeleton (ESkeleton.eCapsuleTop);
UIFollowTarget uiFT = child.AddComponent<UIFollowTarget> ();
uiFT.target = top;
uiFT.SelfHead = m_Head;
if (uiFT.target == null) {
Log.Write (LogLevel.WARN, "null");
}
XUtil.SetLayer (m_Head.gameObject, GlobalU3dDefine.Layer_UI_2D);
m_Head.SetName (m_Name);
m_Head.SetHp (m_nHp, m_nMaxHp);
m_Head.SetVisible (m_bIsVisible);
m_Head.ShowBlood (m_bShowBlood);
m_Head.SetNpcHead (m_nNpcFuncName);
m_Head.SetNickName(m_nNickName);

_ReFindHeadPos (m_MainModel);
}

private void StartLoadHead(XU3dModel model)
{
m_MainModel = model;
EUIPanel headType = EUIPanel.eCount;
switch (mHeadBoardType)
{
case(EHeadBoard_Type.EHeadBoard_Type_Player):
headType = EUIPanel.ePlayerHead;

break;
case(EHeadBoard_Type.EHeadBoard_Type_NPC):
headType = EUIPanel.eNpcHead;

break;
default:
headType = EUIPanel.eMonsterHead;
break;
}

if (EUIPanel.eCount != headType)
{
XEventManager.SP.SendEvent (EEvent.UI_ReqOriginal, headType, this);
}
XEventManager.SP.SendEvent (EEvent.UI_ReqOriginal, EUIPanel.eObjectHalf, this);

if ( null != mainModelLoaded )
mainModelLoaded(this);
}

private void _ReFindHeadPos(XU3dModel model)
{
if (m_Head == null)
return ;
UIFollowTarget UIFT = m_Head.GetComponent<UIFollowTarget> ();
if (UIFT == null)
return ;

UIFT.target = model.GetSkeleton (ESkeleton.eCapsuleTop);

foreach (IModelListener ls in mListenerList) {
ls.OnModelLoaded ();
}

if (LoadModelEvent != null)
LoadModelEvent (this);
}

public void _onObjectHalfReady(XObjectHalf half)
{
if (null == m_MainModel || null != m_Half)
return;

m_Half = XUtil.Instantiate<XObjectHalf> (half);
m_Half.Init ();
XUtil.SetLayer (m_Half.gameObject, m_MainModel.Layer);
m_MainModel.AttachGameObject (ESkeleton.eCapsuleHalf, m_Half.gameObject);
}

// private EBehaviourType getBehaviourType()
// {
// switch (m_xobj.ObjectType) {
// case(EObjectType.MainPlayer):
// return EBehaviourType.e_BehaviourType_MainPlayer;
//
// case(EObjectType.OtherPlayer):
// return EBehaviourType.e_BehaviourType_OtherPlayer;
//
// case(EObjectType.Monster):
// return EBehaviourType.e_BehaviourType_Monster;
//
// case(EObjectType.Npc):
// return EBehaviourType.e_BehaviourType_Npc;
//
// case(EObjectType.TransPoint):
// return EBehaviourType.e_BehaviourType_TransPoint;
//
// case(EObjectType.GatherObject):
// return EBehaviourType.e_BehaviourType_GatherObject;
// }
//
// return EBehaviourType.e_BehaviourType_Other;
// }

public Transform _getSkeleton(ESkeleton ske)
{
if (null == m_MainModel)
return null;
return m_MainModel.GetSkeleton (ske);
}

public float _animLength(EAnimName name)
{
if (null == m_MainModel)
return 0f;
return m_MainModel.AnimLength (name);
}

public void HoverIn()
{
if (m_MainModel != null)
m_MainModel.HoverIn ();

if (m_WeaponModel != null)
m_WeaponModel.HoverIn ();

if (m_MountModel != null)
m_MountModel.HoverIn ();
}

public void HoverOut()
{
if (m_MainModel != null)
m_MainModel.HoverOut ();

if (m_WeaponModel != null)
m_WeaponModel.HoverOut ();

if (m_MountModel != null)
m_MountModel.HoverOut ();
}

public void FadeOut()
{
CoroutineManager.StartCoroutine (UpdateAlpha ());
}

public IEnumerator UpdateAlpha()
{
for (int i = 0; i < 100; i++) {
if (m_MainModel != null)
m_MainModel.FadeOut (0.01f);

if (m_WeaponModel != null)
m_WeaponModel.FadeOut (0.01f);

if (m_MountModel != null)
m_MountModel.FadeOut (0.01f);

yield return 0;
}
}

public float _getRadius()
{
if (null != m_MountModel)
return m_MountModel.Radius ();
if (null != m_MainModel)
return m_MainModel.Radius ();
return 0f;
}

public EXRayMatType XRayType
{
get
{
if(m_MainModel == null)
return EXRayMatType.EXRayMatType_None;

return m_MainModel.XRayType;
}

set
{
if(m_MainModel == null)
return ;

m_MainModel.XRayType = value;
}
}

public EXRayMatType WeaponXRayType
{
get
{
if(m_WeaponModel == null)
return EXRayMatType.EXRayMatType_None;

return m_WeaponModel.XRayType;
}

set
{
if(m_WeaponModel == null)
return ;

m_WeaponModel.XRayType = value;
}
}

public void AddBehaviourListener(EBehaviourType type,IBehaviourListener listener)
{
if(m_MainModel == null)
return ;

m_MainModel.AddBehaviourListener(type,listener);
}

public void SetMoveTarget(EMoveTarget_Type type,GameObject go ,Vector3 targetPos)
{
mMoveTType = type;
if(type == EMoveTarget_Type.EMoveTarget_Object)
{
if(go == null)
return ;
m_MoveTarget = go;
}
else
{
m_MoveTargetPos = targetPos;
}

if(m_FootEffect == null)
{
m_FootEffect = new XU3dEffect(FootEffectID);
onAttachGo(ESkeleton.eMainObject,m_FootEffect.m_gameObject,Vector3.zero,Vector3.zero);
}
else
{
m_FootEffect.m_gameObject.SetActive(true);
}
}

public GameObject GetCurMoveTarget()
{
return m_MoveTarget;
}

public void CancelMoveTarget()
{
m_MoveTarget = null;
m_MoveTargetPos = Vector3.zero;
if(m_FootEffect != null)
m_FootEffect.m_gameObject.SetActive(false);

}

public void Breathe()
{
if(m_FootEffect != null)
{
Vector3 targetPos = Vector3.zero;
if(mMoveTType == EMoveTarget_Type.EMoveTarget_Object)
{
if(m_MoveTarget != null)
{
targetPos = m_MoveTarget.transform.position;
}
}
else
{
targetPos = m_MoveTargetPos;
}
XU3dModel model = m_MainModel;
if ( mountModel != null )
model = mountModel;
Vector3 deltaPos = targetPos - model.Position;
deltaPos.Normalize();
float deltaAngle = Mathf.Atan2(deltaPos.x,deltaPos.z);
m_FootEffect.Direction = new Vector3(0,Mathf.Rad2Deg * deltaAngle,0);

}
}
}

角色管理

GameObject/ObjectAttrs.cs 对象属性

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
using System;
using UnityEngine;
using XGame.Client.Packets;

public enum EObjectType
{
Begin = 0,
GameObject = 0,
Character,
Npc,
Monster,
Pet,
OtherPlayer,
MainPlayer,
Item,
TransPoint,
GatherObject,
End,
}

public class XAttrGameObject
{
internal String Name = string.Empty;
internal uint ModelId = 0;
internal Vector3 Position = Vector3.zero;
internal Vector3 Direction = Vector3.zero;
internal float Scale = 1.0f;
internal Color MatColor = Color.white;
}

// 游戏角色的属性
public class XAttrCharacter
{
internal float Speed = 0f;
internal String Title = string.Empty;
internal String NickName = string.Empty;
internal byte Sex = 0;
internal int Hp = 0;
public uint ArmourItemID = 0; // Armour 盔甲
internal uint ShowFashion = 0;
internal uint FashionId = 0;
internal uint WeaponItemID = 0;
internal uint WeaponModelID = 0;
internal XDynamicAttrMgr DynamicAttrs = new XDynamicAttrMgr ();
}

public class XAttrNpc
{
}

public class XAttrMonster
{
}

// 宠物的属性
public class XAttrPet
{
internal uint Index = 0;
internal uint PetID = 0;
internal uint ClassLevel = 0;
internal uint Race = 0;
internal uint UColor = 0;
internal uint Aptitude = 0; // 天赋
internal uint Loyal = 0;
internal uint Exp = 0;
internal uint BattlePos = 0;
internal uint WuLiValue = 0;
internal uint LingQiaoValue = 0;
internal uint TiZhiValue = 0;
internal uint ShuFaValue = 0;
}

public class XAttrPlayer
{
internal uint UColor = 0;
internal uint ClassLevel = 0;
internal ushort MountIndex = 0;
}

public class XAttrMainPlayer
{
internal long GameMoney = 0;
internal long RealMoney = 0;
internal uint Exp = 0;
internal uint BagSize = 0;
internal uint BankSize = 0;
internal uint Power = 0;
internal uint FightRemain = 0;
internal uint WuLiValue = 0;
internal uint LingQiaoValue = 0;
internal uint TiZhiValue = 0;
internal uint ShuFaValue = 0;
internal uint HealthBuyCount = 0;
internal uint VIPLevel = 0;
internal uint EatFoodCount = 0;
internal uint ShengWangValue = 0;
internal uint TotalShengWangValue =0;
internal uint DayPeiYangCount = 0;
internal uint ShowFashion = 0; // 0显示服装,1不显示服装
internal ulong GuildId = 0;
internal ulong Recharge = 0;
internal uint VipAward = 0;
// 战场布局站位
internal uint BattlePos = 0;
}

GameObject/DynamicAttrMgr.cs 动态属性管理

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
using System;
using System.Collections;
using System.Collections.Generic;
using XGame.Client.Packets;

class XDynamicAttrMgr
{
private Hashtable m_AllAttr = new Hashtable(4);

public void Update(IList<Msg_PairII> lst)
{
foreach (Msg_PairII info in lst)
{
this.Set(info.First, info.Second);
}
}

public void Set(int id, int value)
{
if (!m_AllAttr.Contains(id))
{
m_AllAttr.Add(id, value);
}
else
{
m_AllAttr[id] = value;
}
}

public int Get(EShareAttr aIndex)
{
int id = (int)aIndex;
if (m_AllAttr.Contains(id))
{
return (int)m_AllAttr[id];
}
return 0;
}

public bool Has(EShareAttr aIndex)
{
return m_AllAttr.Contains((int)aIndex);
}
}

GameObject/XGameObject.cs

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
using System;
using UnityEngine;
using XGame.Client.Packets;
using Google.ProtocolBuffers;
/* 类名: XGameObject
* 描述: 游戏中对象
* 功能:
* 1. 维护模型的创建.销毁.visible
* 2. 维护GameObject基础属性
*/

public class XGameObject : XObjectModel.IModelListener,IBehaviourListener
{
public ulong ID { get; protected set; }

public EObjectType ObjectType { get; protected set; }

private bool m_bIsVisible;
public bool IsWaitAppearData;
private float m_tmpScale = 0.0f;
public bool IsActive = true;

protected XAttrPlayer m_AttrPlayer = new XAttrPlayer();

public XGameObject (ulong id)
{
ID = id;
ObjectType = EObjectType.GameObject;
Version = 0;
m_bIsVisible = true;
IsWaitAppearData = false;
IsEnableHover = true;
}

~XGameObject ()
{
m_AttrGameObject = null;
}

public virtual void Init()
{

}

public virtual void Breathe()
{
if (0f != m_tmpScale)
{
bool b = false;
if (m_tmpScale < Scale) {
m_tmpScale += 0.08f;
if (m_tmpScale >= Scale) {
m_tmpScale = Scale;
b = true;
}
}
else if (m_tmpScale > Scale) {
m_tmpScale -= 0.08f;
if (m_tmpScale <= Scale) {
m_tmpScale = Scale;
b = true;
}
}

SendModelEvent (EModelEvent.evtScale, m_tmpScale);
if (b)
m_tmpScale = 0f;
}

if(m_ObjectModel != null)
m_ObjectModel.Breathe();

}

public virtual void OnBeginLoadLevel(int nLevelId, ESceneType sceneType)
{
} // 场景开始加载之前
public virtual void OnLevelLoaded(int nLevelId, ESceneType sceneType)
{
} // 场景加载之后(逻辑地图完成, 静态对象已生成)

public bool IsAppear { get { return null != m_ObjectModel; } }

public float DisAppearRockon { get; private set; }

public virtual EHeadBoard_Type GetHeadBoardType() { return EHeadBoard_Type.EHeadBoard_Type_None; }

// 出现, 需要告诉模型当前的属性信息
public virtual void Appear()
{
if (IsAppear)
return;
m_ObjectModel = new XObjectModel();
m_ObjectModel.mainModelLoaded += loadMainModelFinish;
m_ObjectModel.AddModelListener (this);
// 通知MainPlayer出现了一个GameObject
XLogicWorld.SP.MainPlayer.OnObjectAppear (ObjectType, this);
SendModelEvent (EModelEvent.evtVisible, m_bIsVisible);
SendModelEvent (EModelEvent.evtName, Name);
SendModelEvent (EModelEvent.evtHeadBoardType, GetHeadBoardType());
SendModelEvent (EModelEvent.evtModelId, ModelId);
SendModelEvent (EModelEvent.evtPosition, Position);
SendModelEvent (EModelEvent.evtDirection, Direction);
SendModelEvent (EModelEvent.evtScale, Scale);
}

public void loadMainModelFinish(XObjectModel model)
{
SendModelEvent(EModelEvent.evtMountIndex, m_AttrPlayer.MountIndex);
}

public virtual void GetHeadPosInfo(ref Vector3 pos, ref GameObject parent)
{
m_ObjectModel.GetHeadPosInfo (ref pos, ref parent);
return;
}

public virtual void OnModelLoaded()
{

}

public virtual void OnWeaponLoaded()
{

}

// 消失
public virtual void DisAppear()
{
if (null == m_ObjectModel)
return;

// SendModelEvent (EModelEvent.evtMountIndex, 0u);
SendModelEvent (EModelEvent.evtDestroy);
m_ObjectModel = null;
DisAppearRockon = Time.time;
}

// 设置属性
public virtual void SetAppearData(object data)
{
}

public void SetHudVisible(bool isVisible)
{
SendModelEvent (EModelEvent.evtHudVisible, isVisible);
}

#region 模型
protected XObjectModel m_ObjectModel = null;

public XObjectModel ObjectModel {
get{ return m_ObjectModel; }
}

public void SendModelEvent(EModelEvent evt, params object[] args)
{
if (null == m_ObjectModel)
return;
m_ObjectModel.HandleEvent (evt, args);
}

// 设置模型是否可见
public bool Visible {
get { return m_bIsVisible; }
set {
if (m_bIsVisible != value) {
m_bIsVisible = value;
SendModelEvent (EModelEvent.evtVisible, value);
}
}
}

// 获取模型插槽
public Transform GetSkeleton(ESkeleton ske)
{
if (null == m_ObjectModel)
return null;
return m_ObjectModel._getSkeleton (ske);
}

// 取模型的一个动画时长
public float AnimLength(EAnimName anim)
{
if (null == m_ObjectModel)
return 0f;
return m_ObjectModel._animLength (anim);
}

// 取模型半径, 包围盒半径 * scale_x
public float Radius()
{
if (null == m_ObjectModel)
return 0f;
return m_ObjectModel._getRadius ();
}

// 在模型头顶以特定样式飞一行字
public void FlyString(EFlyStrType ft, string str)
{
if (null == m_ObjectModel)
return ;
m_ObjectModel.HandleEvent (EModelEvent.evtFlyString, ft, str);
}

// 在模型的腰部位置以特定样式飞一行字
public void FlyStringHalf(EObjectHalfHintType ht, string str)
{
if (null == m_ObjectModel)
return ;
m_ObjectModel.HandleEvent (EModelEvent.evtFlyStringHalf, ht, str);
}

// 绑定一个GameObject到特定骨骼上
public void AttachGo(ESkeleton ske, GameObject go)
{
AttachGo (ske, go, Vector3.zero, Vector3.zero);
}

// 绑定一个GameObject到特定骨骼上, 并设定相对位置
public void AttachGo(ESkeleton ske, GameObject go, Vector3 localPosition, Vector3 localRotation)
{
if (null == go)
return;
SendModelEvent (EModelEvent.evtAttachGo, ske, go, localPosition, localRotation);
}

public void OnCancelSelect()
{
SendModelEvent(EModelEvent.evtSelect,(uint)0,false);
}

#endregion

#region 属性
private XAttrGameObject m_AttrGameObject = new XAttrGameObject ();

public uint Version { get; protected set; }

public string Name
{
get
{ return m_AttrGameObject.Name; }
set {
if (m_AttrGameObject.Name == value)
return;
m_AttrGameObject.Name = value;
SendModelEvent (EModelEvent.evtName, value);
XEventManager.SP.SendEvent (EEvent.Attr_Name, this, value);
}
}

public uint ModelId
{
get { return m_AttrGameObject.ModelId; }
set
{
if (m_AttrGameObject.ModelId == value)
return;
m_AttrGameObject.ModelId = value;
SendModelEvent (EModelEvent.evtModelId, value);
XEventManager.SP.SendEvent (EEvent.Attr_ModelId, this, value);
}
}

public Vector3 Position
{
get { return m_AttrGameObject.Position; }
set
{
if (m_AttrGameObject.Position == value)
return;
m_AttrGameObject.Position = value;
SendModelEvent (EModelEvent.evtPosition, value);
}
}

public Vector3 Direction
{
get { return m_AttrGameObject.Direction; }
set
{
if (m_AttrGameObject.Direction == value)
return;
m_AttrGameObject.Direction = value;
SendModelEvent (EModelEvent.evtDirection, value);
}
}

public Color MatColor
{
get { return m_AttrGameObject.MatColor; }
set
{
if (m_AttrGameObject.MatColor == value)
return;
m_AttrGameObject.MatColor = value;
SendModelEvent (EModelEvent.evtMatColor, value);
}
}

// 整体缩放(头顶面板, 坐骑模型, 本体模型等等一起缩放)
public float Scale {
get { return m_AttrGameObject.Scale; }
set {
if (0f == Scale || m_AttrGameObject.Scale == value)
return;
m_tmpScale = Scale;
m_AttrGameObject.Scale = value;
}
}

public bool IsEnableHover { get; set; }

#endregion


#region IBehaviourListener
public virtual float GetClickDistance()
{
return 0f;
}

public virtual void OnMouseDown(int mouseCode, Vector3 clickPoint)
{
}

public virtual void OnMouseUp(int mouseCode)
{
}

public virtual void OnMouseUpAsButton(int mouseCode)
{
}

public virtual void OnControllerColliderHit(ControllerColliderHit hit)
{
}

public virtual void OnMouseEnter()
{
if (!IsEnableHover || m_ObjectModel == null)
return ;

m_ObjectModel.HoverIn ();

}

public virtual void OnMouseExit()
{
if (!IsEnableHover || m_ObjectModel == null)
return ;
m_ObjectModel.HoverOut ();
}
#endregion
}

GameObject/XCharacter.cs

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
using System;
using UnityEngine;
using XGame.Client.Packets;
using System.Collections.Generic;
// 影响模型显示的元素
public enum EModelCtrlType
{
eModelCtrl_ByBuff, // buff影响模型
eModelCtrl_ByFashion, // 时装影响模型
eModelCtrl_ByArmour, // 装备影响模型
eModelCtrl_Original, // 原始模型
eModelCtrl_End,
}

/* 类名: XCharacter
* 描述: 客户端所有角色对象的基类
* 功能:
* 1. 角色基础行为状态机: 待机/死亡/战斗/移动/跳跃/打坐
* 2. 角色基础属性与动态属性
* 3. 物品
*/
public class XCharacter : XGameObject
{
public static readonly float DEFAULT_RUN_SPEED = 5.0f;

public XCharacter (ulong id)
: base(id)
{
ObjectType = EObjectType.Character;
initBehaviourSM ();
initItemMgr ();
initBuffOper ();
Speed = DEFAULT_RUN_SPEED;
}

~XCharacter ()
{
m_BehaviourSM = null;
m_AttrCharacter = null;
ItemManager = null;
BuffOper = null;
}

public override void Breathe()
{
base.Breathe ();
m_BehaviourSM.Breathe ();
BuffOper.Breathe ();
}

// 将角色位置矫正到地面
public void PushOnTerrain()
{
Vector3 posNow = Position;
XLogicWorld.SP.SceneManager.FixExactHeight (ref posNow);
Position = posNow;
}

public override void OnLevelLoaded(int nLevelId, ESceneType sceneType)
{
m_BehaviourSM.OnEvent ((int)EStateEvent.esLevelLoaded, nLevelId, sceneType);
}

public override void Appear()
{
if (IsAppear)
return;
base.Appear ();
SendModelEvent (EModelEvent.evtTitle, Title);
SendModelEvent (EModelEvent.evtNickName, NickName);
SendModelEvent (EModelEvent.evtHp, Hp);
SendModelEvent (EModelEvent.evtMaxHp, MaxHp);
//SendModelEvent(EModelEvent.evtWeaponId, WeaponModelId);
((XCharStateBase)m_BehaviourSM.CurrentState).OnAppear ();
BuffOper.Appear ();
}

public override void DisAppear()
{
base.DisAppear ();
BuffOper.Disappear ();
}

#region 角色基础行为状态机
protected XStateMachince m_BehaviourSM;

protected virtual void initBehaviourSM()
{
m_BehaviourSM = new XStateMachince (new XCharStateIdle (this));
m_BehaviourSM.RegState (new XCharStateSit (this));
m_BehaviourSM.RegState (new XCharStateDead (this));
m_BehaviourSM.RegState (new XCharStateFight (this));
m_BehaviourSM.RegState (new XCharStateMove (this));
}

// 线段移动
public bool SegmentMoveTo(Vector3 toPos, float speed, XCharStateMove.OnMoveDone cb, EAnimName anim)
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esMoveTo, EProtoMoveType.eMoveType_Segment, toPos, speed, cb, anim);
}

public bool Rotato(Vector3 toPos)
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esRotateTo, toPos);
}

// 滑行
public bool SlideMoveTo(Vector3 toPos, float dir, float speed, XCharStateMove.OnMoveDone cb)
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esMoveTo, EProtoMoveType.eMoveType_Slide, toPos, dir, speed, cb);
}

// 原地踏步
public bool StepMove(float speed, float dir)
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esMoveTo, EProtoMoveType.eMoveType_Step, speed, dir);
}

// 停止移动(XZ)
public bool StopMove()
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esStopMove);
}

// 从当前点起跳, 处理整个跳跃过程
public bool Jump(XCharStateMove.OnJumpDone cb)
{
return Jump (Position.x, Position.z, 0f, cb);
}

// 起跳(给起跳点和跳跃时间, 忽略time之前的跳跃过程)
public bool Jump(float x, float z, float time, XCharStateMove.OnJumpDone cb)
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esJump, x, z, time, cb);
}

public bool JumpOver()
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esJumpOver);
}

public void Idle()
{
m_BehaviourSM.TranslateToState((int)EStateId.esIdle);
}

public virtual void ForceSetPosition(Vector3 pos, Vector3 dir)
{
Position = pos;
Direction = dir;
m_BehaviourSM.OnEvent ((int)EStateEvent.esStopMove);
}

public virtual void OnEnterSit()
{

}

public virtual void OnExitSit()
{

}

// 进入生产, 高32位: 采集or制造, 低32位: 采集物ID or 配方ID
public bool StartProduct(Int64 data)
{
if (0 == data)
return false;

EProductCareerType pType = (EProductCareerType)(data >> 32);

int nId = (int)data;
switch (pType)
{
case EProductCareerType.eProductCareerType_Gather:
{
XCfgGatherObject cfgGO = XCfgGatherObjectMgr.SP.GetConfig (nId);
if (null == cfgGO)
return false;
XCfgProductCareer cfgPC = XCfgProductCareerMgr.SP.GetConfig (cfgGO.NeedCareer, 1);
StartProduct ((EAnimName)cfgPC.AnimName);
}
break;

case EProductCareerType.eProductCareerType_Produce:
{
return StartProduct (EAnimName.Idle);
}
break;

default:
break;
}
return false;
}

// 进入生产, 参数1: 生产动画 (生产状态嵌入在Idle里面)
public bool StartProduct(EAnimName anim)
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esStartProduct, anim);
}

// 退出生产
public bool QuitProduct()
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esQuitProduct);
}

// 进入战斗
public bool StartFight()
{
if(m_BehaviourSM.OnEvent((int)EStateEvent.esStartFight))
{
SendModelEvent(EModelEvent.evtShowBlood, true);
return true;
}
return false;
}

// 退出战斗
public bool QuitFight()
{
if (m_BehaviourSM.OnEvent ((int)EStateEvent.esQuitFight)) {
SendModelEvent (EModelEvent.evtShowBlood, false);
return true;
}
return false;
}

// 播放动画
public bool PlayAnimation(EAnimName anim)
{
return PlayAnimation (anim, 1.0f, false);
}

public bool PlayAnimation(EAnimName anim, float fSpeed)
{
return PlayAnimation (anim, fSpeed, false);
}

public bool PushAnimation(EAnimName anim)
{
return PlayAnimation (anim, 1.0f, true);
}

public bool PushAnimation(EAnimName anim, float fSpeed)
{
return PlayAnimation (anim, fSpeed, true);
}

public bool PlayAnimation(EAnimName anim, float fSpeed, bool bIsPush)
{
return m_BehaviourSM.OnEvent ((int)EStateEvent.esAnimation, anim, fSpeed, bIsPush);
}

// 直接播放动画, 这个接口非原创者不要调用 by WuZhenqiang
public void _playAnimation(EAnimName anim, float fSpeed, bool bIsPush)
{
SendModelEvent (EModelEvent.evtAnimation, anim, fSpeed, bIsPush);
}
#endregion


#region 物品=============================================================================================================================
public XItemManager ItemManager { get; private set; }

private void initItemMgr()
{
ItemManager = new XItemManager (this);
}

public bool CanSellItem(uint boxType, short pos)
{
return ItemManager.CanSellItem(boxType, pos);
}

public int GetItmeCount(uint itemId)
{
return ItemManager.GetItemByDataID(itemId);
}
#endregion

#region Buff
public XBuffOper BuffOper { get; private set; }

private void initBuffOper()
{
BuffOper = new XBuffOper (this);
}
#endregion

#region 角色属性
protected XAttrCharacter m_AttrCharacter = new XAttrCharacter ();

public float Speed {
get { return m_AttrCharacter.Speed; }
set
{
if (m_AttrCharacter.Speed != value) {
float oldSpeed = Speed;
m_AttrCharacter.Speed = value;
m_BehaviourSM.OnEvent ((int)EStateEvent.esSpeed, Speed, oldSpeed);
}
}
}

public string Title {
get { return m_AttrCharacter.Title; }
set {
if (m_AttrCharacter.Title != value) {
m_AttrCharacter.Title = value;
SendModelEvent (EModelEvent.evtTitle, value);
}
}
}

public virtual string NickName {
get { return m_AttrCharacter.NickName; }
set
{
if (m_AttrCharacter.NickName != value) {
m_AttrCharacter.NickName = value;
SendModelEvent (EModelEvent.evtNickName, value);
}
}
}

public byte Sex {
get { return m_AttrCharacter.Sex; }
set {
if (m_AttrCharacter.Sex != value) {
m_AttrCharacter.Sex = value;
}
}
}

public int Hp {
get { return m_AttrCharacter.Hp; }
set
{
if(m_AttrCharacter.Hp != value)
{
if (value < 0)
{
m_AttrCharacter.Hp = 0;
BuffOper.OnDead();
this.OnDead();
}
else if (value > MaxHp)
{
m_AttrCharacter.Hp = MaxHp;
}
else
{
m_AttrCharacter.Hp = value;
}

SendModelEvent(EModelEvent.evtHp, m_AttrCharacter.Hp);
//m_BehaviourSM.OnEvent((int)EStateEvent.esHp, m_AttrCharacter.Hp);
XEventManager.SP.SendEvent(EEvent.Attr_Hp, this, m_AttrCharacter.Hp);
}
}
}

public int MaxHp
{
get { return DynGet (EShareAttr.esa_MaxHp); }
set
{
if (MaxHp != value) {
DynSet (EShareAttr.esa_MaxHp, value);
SendModelEvent (EModelEvent.evtMaxHp, value);
}
}
}

public virtual int Level {
get { return DynGet (EShareAttr.esa_Level); }
set {
if (Level != value) {
DynSet (EShareAttr.esa_Level, value);
}
}
}

public virtual uint ArmourItemID
{
get
{
return m_AttrCharacter.ArmourItemID;
}
set
{
if (m_AttrCharacter.ArmourItemID != value)
{
m_AttrCharacter.ArmourItemID = value;
XCfgItem cfgItem = XCfgItemMgr.SP.GetConfig (ArmourItemID);
uint id = 0;
if (cfgItem != null &&
cfgItem.ItemType == (ushort)EItem_Type.EITEM_TYPE_ARMOR &&
cfgItem.EquipPos == (int)EQUIP_SLOT_TYPE.EQUIP_SLOT_ARMOUR)
{
id = cfgItem.ArmourID;
}
if ( m_AttrCharacter.ShowFashion == 1 ||
m_AttrCharacter.FashionId == 0 )
SetModel (EModelCtrlType.eModelCtrl_ByArmour, id);
XEventManager.SP.SendEvent (EEvent.Attr_ArmourItemID, this, value);
}
}
}

public virtual uint FashionId
{
get
{
return m_AttrCharacter.FashionId;
}
set
{
if (m_AttrCharacter.FashionId != value)
{
m_AttrCharacter.FashionId = value;
XCfgItem cfgItem = XCfgItemMgr.SP.GetConfig(FashionId);
uint id = 0;
if (cfgItem != null &&
cfgItem.ItemType == (ushort)EItem_Type.EITEM_TYPE_ARMOR &&
cfgItem.EquipPos == (int)EQUIP_SLOT_TYPE.EQUIP_SLOP_FASHION)
{
id = cfgItem.ArmourID;
}
if ( XLogicWorld.SP.MainPlayer.ShowFashion == 0 && id > 0 )
SetModel (EModelCtrlType.eModelCtrl_ByFashion, id);
else
ArmourItemID = ArmourItemID;

XEventManager.SP.SendEvent(EEvent.Attr_ArmourItemID, this, value);
}
}
}

public uint WeaponModelId
{
get { return m_AttrCharacter.WeaponModelID; }
set
{
if(m_AttrCharacter.WeaponModelID != value)
{
m_AttrCharacter.WeaponModelID = value;
SendModelEvent(EModelEvent.evtWeaponId, value);
XEventManager.SP.SendEvent(EEvent.Attr_WeaponItemID, this, value);
}

}
}

protected virtual void OnDead()
{

}

public int DynGet(EShareAttr aIndex)
{
return m_AttrCharacter.DynamicAttrs.Get (aIndex);
}

public void DynSet(EShareAttr aIndex, int value)
{
if (DynGet (aIndex) != value)
{
m_AttrCharacter.DynamicAttrs.Set ((int)aIndex, value);
XEventManager.SP.SendEvent (EEvent.Attr_Dynamic, this, aIndex, value);
}
}

public void UpdateDynAttrs(IList<Msg_PairII> lst)
{
foreach (Msg_PairII info in lst)
{
this.DynSet ((EShareAttr)info.First, info.Second);
}
}
#endregion

public bool IsDead { get { return Hp <= 0; } }

// 角色模型显示
private EModelCtrlType m_eCurModelType = EModelCtrlType.eModelCtrl_Original;
private uint[] m_ModelIdArr = new uint[(int)EModelCtrlType.eModelCtrl_End];

public void SetModel(EModelCtrlType ct, uint modelId)
{
if (ct >= EModelCtrlType.eModelCtrl_End
|| m_ModelIdArr [(int)ct] == modelId)
return;

m_ModelIdArr [(int)ct] = modelId;
if (ct < m_eCurModelType)
{
if (modelId > 0)
{
ModelId = modelId;
m_eCurModelType = ct;
return;
}
}
else if (ct == m_eCurModelType)
{
if (modelId > 0) {
ModelId = modelId;
return;
}
else
{
for (EModelCtrlType i = m_eCurModelType + 1; i < EModelCtrlType.eModelCtrl_End; i++)
{
uint id = m_ModelIdArr [(int)i];
if (id > 0)
{
ModelId = id;
m_eCurModelType = i;
return;
}
}
}
}
}
}

GameObject/XPlayer.cs

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
using System;
using UnityEngine;
using XGame.Client.Packets;
using Google.ProtocolBuffers;

/* 类名: XPlayer
* 描述: 客户端所有玩家对象的基类
* 功能:
* 1. 维护玩家基础属性
* 2. 响应服务器过来的消息 开始移动.停止移动.跳跃.坐下
*/

public class XPlayer : XCharacter
{
public XPlayer(ulong id)
: base(id)
{
ObjectType = EObjectType.OtherPlayer;
IsEnableHover = true;
}

~XPlayer()
{
m_AttrPlayer = null;
}

public override void Appear()
{
base.Appear();
SendModelEvent(EModelEvent.evtWeaponId, WeaponModelId);
SendModelEvent(EModelEvent.evtUColor, UColor);
}

public override void DisAppear ()
{
base.DisAppear ();
XEventManager.SP.SendEvent(EEvent.UI_Hide,EUIPanel.eTargetInfo);
}

public override void OnModelLoaded()
{
base.OnModelLoaded();

m_ObjectModel.ReAttachMount();
m_ObjectModel.AddBehaviourListener(EBehaviourType.e_BehaviourType_OtherPlayer,this);
}

public override EHeadBoard_Type GetHeadBoardType() { return EHeadBoard_Type.EHeadBoard_Type_Player; }

public override void SetAppearData (object data)
{
SC_PlayerAppearData msg = data as SC_PlayerAppearData;
if (null == msg)
{
return;
}

//--4>TODO: 考虑同步数据进行分类, 使用公用结构, 给子类调用
Vector3 pos = Position;
Version = msg.Version;
if (msg.HasName) Name = msg.Name;
if (msg.HasTitle) Title = msg.Title;
if (msg.HasPosX) pos.x = msg.PosX;
if (msg.HasPosZ) pos.z = msg.PosZ;
Position = pos;
PushOnTerrain();
if (msg.HasDirection) Direction = new Vector3(0, msg.Direction, 0);
if (msg.HasModel) SetModel(EModelCtrlType.eModelCtrl_Original, msg.Model);
if (msg.HasColor) UColor = msg.Color;
if (msg.HasSex) Sex = (byte)msg.Sex;
if (msg.HasClass) DynSet(EShareAttr.esa_Class, (byte)msg.Class);
if (msg.HasClassLevel) ClassLevel = msg.ClassLevel;
if (msg.HasLevel) Level = (int)msg.Level;
if (msg.HasRunSpeed) Speed = msg.RunSpeed;
if (msg.HasMountIndex) m_AttrPlayer.MountIndex = (ushort)msg.MountIndex;
if (msg.HasArmourItemID)
ArmourItemID = msg.ArmourItemID;
else
ArmourItemID = 0;

if (msg.HasWeaponItemID)
WeaponItemID = msg.WeaponItemID;
else
WeaponItemID = 0;
if (msg.HasShowFashion) ShowFashion = msg.ShowFashion;
if (msg.HasFashionId) FashionId = msg.FashionId;
if (msg.HasNickNameID)
{
if(msg.NickNameID !=0)
{
XCfgNickName infodata = XCfgNickNameMgr.SP.GetConfig(msg.NickNameID);
if(infodata!= null)
{
try
{
string colorname = XGameColorDefine.Quality_Color[infodata.ColorID];
this.NickName =string.Format("{0}{1}",colorname,infodata.NickName);
}
catch
{
Log.Write(LogLevel.ERROR,"Xplayer, the index is out of Quality_Color num");
}
}
}
else
{
this.NickName = "";
}
}

// xz移动状态
if(msg.HasMoveType)
{
switch((EProtoMoveType)msg.MoveType)
{
case(EProtoMoveType.eMoveType_Stand):
break;

case(EProtoMoveType.eMoveType_Segment):
SegmentMoveTo(new Vector3(msg.TargetX, 0.0f, msg.TargetZ), Speed, null,EAnimName.Run);
break;

case(EProtoMoveType.eMoveType_Slide):
SlideMoveTo(new Vector3(msg.TargetX, 0.0f, msg.TargetZ), Direction.y, Speed, null);
break;

case(EProtoMoveType.eMoveType_Step):
StepMove(Speed, Direction.y);
break;
}
}

// 跳跃状态
if(msg.HasJumpTime && msg.JumpTime >= 0)
{
Jump(msg.JumpX, msg.JumpZ, msg.JumpTime / 1000f, null);
}

// DynAttr
foreach(Int64 dynAttr in msg.DynAttrList)
{
int key = (int)(dynAttr >> 32);
int val = (int)(dynAttr);
DynSet((EShareAttr)key, val);
}

// buff
if(msg.BuffArrList.Count > 0)
{
BuffOper.Clear();
foreach(UInt64 buff64 in msg.BuffArrList)
{
uint nBuffId = (uint)(buff64 >> 32);
byte btBuffLevel = (byte)(buff64);
BuffOper.AddBuff(nBuffId, btBuffLevel, 0, true, 0);
}
}

// product
if(msg.HasProduct)
StartProduct(msg.Product);
}

// 这个函数用来校准其他玩家的真实位置和客户端的显示位置
private void correctPosition(Vector3 pos)
{
// 如果误差大于1米, 需要矫正一下
if(XUtil.CalcDistanceXZ(Position, pos) > 1.0f)
{
Position = pos;
}
}

public override void OnEnterSit()
{

}

public override void OnExitSit()
{

}

public void StartSit()
{
m_BehaviourSM.OnEvent((int)EStateEvent.esSit);
}

public void EndSit()
{
m_BehaviourSM.OnEvent((int)EStateEvent.esCancelSit);
}

public void On_SC_StartMove(SC_StartMove msg)
{
Vector3 fromPos = new Vector3(msg.FromX, 0f, msg.FromZ);
correctPosition(fromPos);
switch((EProtoMoveType)msg.MoveType)
{
case(EProtoMoveType.eMoveType_Stand):
break;

case(EProtoMoveType.eMoveType_Segment):
SegmentMoveTo(new Vector3(msg.ToX, 0.0f, msg.ToZ), Speed, null,EAnimName.Run);
break;

case(EProtoMoveType.eMoveType_Slide):
SlideMoveTo(new Vector3(msg.ToX, 0.0f, msg.ToZ), msg.Dir, Speed, null);
break;

case(EProtoMoveType.eMoveType_Step):
StepMove(Speed, msg.Dir);
break;
}
}

public void On_SC_StopMove(SC_StopMove msg)
{
Vector3 pos = new Vector3(msg.PosX, 0f, msg.PosZ);
correctPosition(pos);
StopMove();
}

public void On_SC_Jump(SC_Jump msg)
{
Vector3 pos = new Vector3(msg.PosX, 0f, msg.PosZ);
correctPosition(pos);
Jump(null);
}

public void On_SC_JumpOver(SC_JumpOver msg)
{
Vector3 pos = new Vector3(msg.PosX, 0f, msg.PosZ);
correctPosition(pos);
JumpOver();
}

public void On_SC_Sit(SC_Sit msg)
{
// Vector3 pos = new Vector3(msg.PosX, msg.PosY, msg.PosZ);
// correctPosition(pos);
StartSit();
}

public void On_SC_StopSit(SC_StopSit msg)
{
EndSit();
}

#region 属性

public virtual int Class // 职业
{
get { return DynGet(EShareAttr.esa_Class); }
set
{
if(Class != value)
{
DynSet(EShareAttr.esa_Class, value);
}
}
}

public virtual float Grow
{
get { return DynGet(EShareAttr.esa_Grow) / Define.CONFIG_RATE_BASE; }
set
{
if(Grow != value)
{
DynSet(EShareAttr.esa_Grow, (int)(value * Define.CONFIG_RATE_BASE));
}
}
}


public uint UColor
{
get { return m_AttrPlayer.UColor; }
set
{
if(m_AttrPlayer.UColor != value)
{
m_AttrPlayer.UColor = value;
SendModelEvent(EModelEvent.evtUColor, value);
}
}
}

public uint ClassLevel
{
get { return m_AttrPlayer.ClassLevel; }
set
{
if(m_AttrPlayer.ClassLevel != value)
{
m_AttrPlayer.ClassLevel = value;
}
}
}

public ushort MountIndex
{
get { return m_AttrPlayer.MountIndex; }
set
{
if(m_AttrPlayer.MountIndex != value)
{
m_AttrPlayer.MountIndex = value;
SendModelEvent(EModelEvent.evtMountIndex, value);
}
}
}

public override uint ArmourItemID
{
set
{
//--4>: 直接刷新模型, 因为下线再上线时逻辑数据是一致的, 而模型必须重置
//if (m_AttrCharacter.ArmourItemID != value)
{
m_AttrCharacter.ArmourItemID = value;

//临时显示自己的强化显示效果
//--------------------------------------------------
byte strengthenLevel = 0;
uint colorLevel = 0;
XCfgItem cfgItem = XCfgItemMgr.SP.GetConfig(value);
XItem item = ItemManager.GetItem((uint)EItemBoxType.Equip,(short)EQUIP_POS.EQUIP_POS_ARMOUR);
if(item != null && cfgItem != null)
{
strengthenLevel = (byte)item.mEquipAttr.mStrengthenLevel;
if(cfgItem.IsRandom > 0)
colorLevel = (uint)item.mEquipAttr.mColor;
else
colorLevel = cfgItem.QualityLevel;
}
//----------------------------------------------------

// 刷新显示模型(铠甲模型或者角色裸模)

int JobClass = DynGet(EShareAttr.esa_Class);
if (cfgItem != null &&
cfgItem.ItemType == (ushort)EItem_Type.EITEM_TYPE_ARMOR &&
cfgItem.EquipPos == (int)EQUIP_SLOT_TYPE.EQUIP_SLOT_ARMOUR &&
(m_AttrCharacter.ShowFashion == 1 || FashionId == 0) )
{
//临时显示自己的强化显示效果
//--------------------------------------------------
int appearLevel = 0;

XCfgStrengthen cfgStrengthen = XItemManager.GetStrengthenCfg(colorLevel,strengthenLevel);

if(cfgStrengthen == null)
{
Log.Write(LogLevel.ERROR,"cant find strengthen cfg");
return ;
}

if(cfgStrengthen != null)
appearLevel = cfgStrengthen.AppearLevel;
//--------------------------------------------------
uint tempModelID = XItemManager.GetArmourID(cfgItem.ArmourID,appearLevel,Sex,JobClass);
if(tempModelID != 0)
{
Log.Write(LogLevel.DEBUG,"Cur Player Model ID is {0}",tempModelID);
ModelId = tempModelID;
}
}
else
{
if ( m_AttrCharacter.ShowFashion == 0 && FashionId > 0 )
{
FashionId = FashionId;
}
else
{
uint md = 0;
XCfgPlayerBase playerBase = XCfgPlayerBaseMgr.SP.GetConfig((byte)JobClass);
if(playerBase != null)
{
if (Sex == (byte)EShareSex.eshSex_Male)
{
md = playerBase.MaleModel;
}
else if (Sex == (byte)EShareSex.eshSex_Female)
{
md = playerBase.FemaleModel;
}
}
if (md > 0)
{
Log.Write(LogLevel.DEBUG,"Cur Player Model ID is {0}",md);
ModelId = md;
}
}
}
}
}
}

public override uint FashionId
{
set
{
m_AttrCharacter.FashionId = value;

XCfgItem cfgItem = XCfgItemMgr.SP.GetConfig(value);
int JobClass = DynGet(EShareAttr.esa_Class);
if (cfgItem != null &&
cfgItem.ItemType == (ushort)EItem_Type.EITEM_TYPE_ARMOR &&
cfgItem.EquipPos == (int)EQUIP_SLOT_TYPE.EQUIP_SLOP_FASHION &&
m_AttrCharacter.ShowFashion == 0)
{
int appearLevel = 1;

uint tempModelID = XItemManager.GetArmourID(cfgItem.ArmourID, appearLevel, Sex, JobClass);
if(tempModelID != 0)
{
Log.Write(LogLevel.DEBUG,"Cur Player Model ID is {0}",tempModelID);
ModelId = tempModelID;
}
}
else
{
ArmourItemID = ArmourItemID;
}
}
}

public uint ShowFashion
{
get { return m_AttrCharacter.ShowFashion;}
set
{
if(m_AttrCharacter.ShowFashion != value)
{
m_AttrCharacter.ShowFashion = value;
if ( 0 == value && FashionId > 0)
{
FashionId = FashionId;
}
else
{
ArmourItemID = ArmourItemID;
}
}
}
}

// public uint WeaponModelId
// {
// get { return m_AttrCharacter.WeaponModelID; }
// set
// {
// if(m_AttrCharacter.WeaponModelID != value)
// {
// m_AttrCharacter.WeaponModelID = value;
// SendModelEvent(EModelEvent.evtWeaponId, value);
// XEventManager.SP.SendEvent(EEvent.Attr_WeaponItemID, this, value);
// }
//
// }
// }

public uint WeaponItemID
{
get { return m_AttrCharacter.WeaponItemID; }
set
{
//if(m_AttrCharacter.WeaponItemID != value)
{
m_AttrCharacter.WeaponItemID = value;

XCfgItem cfgItem = XCfgItemMgr.SP.GetConfig(m_AttrCharacter.WeaponItemID);

//临时显示自己的强化显示效果
//--------------------------------------------------
byte strengthenLevel = 0;
uint colorLevel = 0;
XItem item = ItemManager.GetItem((uint)EItemBoxType.Equip,(short)EQUIP_POS.EQUIP_POS_WEAPON);
if(item != null)
{
strengthenLevel = (byte)item.mEquipAttr.mStrengthenLevel;
colorLevel = (uint)item.mEquipAttr.mColor;
}
//----------------------------------------------------
int JobClass = DynGet(EShareAttr.esa_Class);
if (cfgItem != null && cfgItem.ItemType == (ushort)EItem_Type.EITEM_TYPE_WEAPON && cfgItem.EquipPos == (int)EQUIP_SLOT_TYPE.EQUIP_SLOT_WEAPON)
{
//临时显示自己的强化显示效果
//--------------------------------------------------
int appearLevel = 0;
XCfgStrengthen cfgStrengthen = XItemManager.GetStrengthenCfg(colorLevel,strengthenLevel);

if(cfgStrengthen == null)
{
Log.Write(LogLevel.ERROR,"cant find strengthen cfg");
return ;
}

if(cfgStrengthen != null)
appearLevel = cfgStrengthen.AppearLevel;
//--------------------------------------------------
uint tempModelID = XItemManager.GetArmourID(cfgItem.ModelId,appearLevel,Sex,JobClass);
WeaponModelId = tempModelID;
}
else
{
XCfgPlayerBase playerBase = XCfgPlayerBaseMgr.SP.GetConfig((byte)JobClass);
if(playerBase != null)
{
WeaponModelId = playerBase.DefaultWeapon;
}
}
}


}
}

public override void OnMouseDown(int mouseCode, Vector3 clickPoint)
{
XEventManager.SP.SendEvent(EEvent.ObjSel_SetData,Name,Level,ID);
XEventManager.SP.SendEvent(EEvent.UI_Show,EUIPanel.eTargetInfo);
}

#endregion
}

Audio

GameBehaviour/XU3dAudio.cs 没有继承MonoBehavior

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
using UnityEngine;
using System.Collections;
using resource;

public class XU3dAudio : XU3dDynObject
{
// 加载完成后执行的回调函数
// 这个委托需要外界调用的来写具体的方法
public delegate void OnAudioLoadDone(XU3dAudio self);

private OnAudioLoadDone m_loadDoneCallBack = null;

private AudioClip m_AudioClip = null;

public uint ID
{
get { return m_nId; }
}

public AudioClip audioClip
{
get { return m_AudioClip; }
}

// 构造函数
public XU3dAudio(uint nId)
{
RefreshDynObject(nId);
}

public XU3dAudio(uint nId, OnAudioLoadDone loadDoneFunction)
{
m_loadDoneCallBack = loadDoneFunction;
// 加载音效
RefreshDynObject(nId);
}

public override void RefreshDynObject(uint id)
{
if (m_nId == id)
return;

m_nId = id;
doRefreshDynObject();
}

private void doRefreshDynObject()
{
NewGameObject("Audio_" + m_nId);
m_DynObject = XResourceManager.GetResource(XResourceAudio.ResTypeName, m_nId);

if (null == m_DynObject)
{
Log.Write(LogLevel.Warn, "XU3dAudio, not found resource: {0}", m_nId);
return;
}

if(m_DynObject.IsLoadDone())
{
LoadCompleted(m_DynObject.MainAsset.DownLoad);
} else
{
if (m_DynObject != null)
m_DynObject.ResLoadEvent -= LoadCompleted;

XResourceManager.StartLoadResource(XResourceAudio.ResTypeName, m_nId);
m_DynObject.ResLoadEvent += new XResourceBase.LoadCompletedDelegate(LoadCompleted);
}

private void LoadCompleted( DownLoadItem itemLoad)
{
#if RES_DEBUG
AudioClip go = itemLoad.go as AudioClip;
#else
AudioClip go = itemLoad.ab.mainAsset as AudioClip;
#endif

onAudioDone(go);
}

private void onAudioDone(AudioClip audio)
{
if(null == audio)
{
Log.Write(LogLevel.Warn, "XU3dAudio, wrong resource: {0}", m_nId);
return;
}

m_AudioClip = Object.Instantiate(audio) as AudioClip;

if (null != m_loadDoneCallBack)
{
m_loadDoneCallBack(this);
}
}
}
}

GameBehaviour/XAudio.cs

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
using UnityEngine;
using System.Collections;

public class XAudio : MonoBehaviour
{
// 外界传入
// AudioClip的id
public int m_iAudioID = 0;

// 外界传入
// 音乐是否循环可以设置
public bool m_bLoop = false;

private XU3dAudio m_u3dAudio = null;

void Start()
{
m_u3dAudio = new XU3dAudio((uint)m_iAudioID, onAudioLoaded);
}

// 加完后音效后执行
private void onAudioLoaded(XU3dAudio audio)
{
AudioSource audioSource = gameObject.AddComponent<AudioSource>();

audioSource.loop = m_bLoop;

// 给AudioSource组件设置音效clip
audioSource.clip = audio.audioClip;
audioSource.Play();
}
}

资源加载

Resource/XDownloadItem.cs

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
namespace resource
{
using System;
using System.Collections.Generic;
using UnityEngine;

#if RES_DEBUG
using UnityEditor;
#endif

public class DownLoadItem : IDisposable
{
// 路径这些都设置为私有
private string _back_server_path = "http://localhost/WebPlayer/"; // 备份路径
private string _original_src_path = "http://localhost/WebPlayer/"; // 原始路径
private float _time_start; // 下载开始时间
private bool _use_cache; // 使用使用缓存
private static bool ServerRejectPostRequest = true; // 服务器是否拒绝post请求
// end

public AssetBundle ab;
public string act_url = string.Empty; // 最后的执行路径
public object data;
public string error; // 错误的信息
public bool hasError; // 是否有错误
public bool IsDone; // 是否完成
public int priority; // 优先级
public int retryTimes; // 重试时间

public int size; // 文件大小
public string url; // 地址
public int version; // 版本
public WWW www;
public UnityEngine.Object go;

// 加载完成事件,只有自己可以调用
// LoadCompletedDelegate是事件类型
// LoadCompletedEvent是事件类型的变量
public delegate void LoadCompletedDelegate(DownloadItem item);
public event LoadCompletedDelegate LoadCompletedEvent;
public bool IsAddDelegate = false;

// 构造函数
// 初始化字段
public DownloadItem(string url, int version, int size, int priority, int tryTimes)
{
this.url = url;
this.version = version;
this.size = size;
this.priority = priority;
this.IsDone = false;
this.retryTimes = tryTimes;
}

// 给外界
// 触发加载完成事件
public void _FireLoadCompleted()
{
if (this.LoadCompletedEvent != null)
{
this.LoadCompletedEvent(this);
this.LoadCompletedEvent = null;
}
}

// 给外界调用,是否完成
// 判断是否完成,不是判断是否正确加载
// 完成之后也可能有错误
public bool CheckIsDone()
{
if (this.www != null)
{
if (this.www.isDone)
{
// 有错误
if (!string.IsNullOrEmpty(this.www.error))
{
if (this.www.error.Contains("rewind wasn't possible"))
{
Debug.Log("http resonse error, change POST to GET. error:" + this.www.error);
ServerRejectPostRequest = true;
}

string error = this.www.error;
if (this.Retry())
{
return false;
}
this.hasError = true;
this.error = error;
return true;
}

// 不使用缓存或者www.assetBundle为空成立一个的话就进行第2个判断
// 第2个判断是www请求返回有值
if ((!this._use_cache || (this.www.assetBundle == null)) && !string.IsNullOrEmpty(this.www.text))
{
// Mathf.Min 返回两个或更多值中最小的值。
string str2 = this.www.text.Substring(0, Mathf.Min(this.www.text.Length, 300));

if (str2.ToLower().Contains("<html"))
{
Debug.Log("http resonse error:" + str2);
if (this.Retry())
{
return false;
}
this.hasError = true;
this.error = "Download Error! " + this.www.url + "\n" + this.www.text;
return true;
}
}
return true;
}

if ((this.www.progress != 0f) || ((Time.time - this._time_start) <= 10f))
{
return false;
}

if (this.Retry())
{
return false;
}
// 超时记录日志
this.hasError = true;
this.error = string.Format("Timeout, start:{0}, now:{1}, pass:{2}", this._time_start, Time.time, Time.time - this._time_start);
}
return true;
}

// 是否可以重试
private bool Retry()
{
Debug.LogWarning(string.Format("DownloadItem.Retry, retryTimes:{0}, url:{1}", this.retryTimes, this.url));
// 清除之前的www
if (this.www != null)
{
this.www.Dispose();
this.www = null;
}
// 重试时间用完了
if (this.retryTimes <= 0)
{
return false;
}
this.retryTimes--;
this.version++;
if (this.retryTimes <= 2)
{
this.Start(this._use_cache, true);
}
else
{
this.Start(this._use_cache);
}
return true;
}

public void Start(bool useCache)
{
this.Start(useCache, false);
}

// 给_use_cache,act_url,www,_time_start等字段赋值
// 然后开始加载
public void Start(bool useCache, bool use_back_server)
{
#if RES_DEBUG
go = AssetDatabase.LoadMainAssetAtPath("Assets/" + this.url);
#else
if (this.www != null)
{
throw new InvalidOperationException();
}

this._use_cache = useCache;
if (useCache)
{
// 不使用备份路径
if (!use_back_server)
{
string str;
// 加上版本号
if(this.version == 0)
str = this.url;
else
str = !this.url.StartsWith("http://") ? this.url : (this.url + "_" + this.version + ".asset");
// 记录日志
object[] args = new object[] { string.Format("LoadFromCacheOrDownload, url:{0}, version:{1}", str, this.version) };
Log.AddTempLog(args);
// 前期准备做完,给字段赋值
this.act_url = str;
// version Version of the AssetBundle.
this.www = WWW.LoadFromCacheOrDownload(str, this.version);
}else
{
this.DownloadByBackupServer();
}
}else if (!use_back_server)
{
if ((Config.LANG == "cn") && !ServerRejectPostRequest) // 可以使用post请求
{
WWWForm form = new WWWForm();
form.AddField("ver", this.version);

string str2 = !this.url.StartsWith("http://") ? this.url : (this.url + "_" + this.version + ".asset");
// 更改act_url实际执行字段
this.act_url = str2;
this.www = new WWW(this.url, form);
}else // get请求
{
string url;
if(this.version == 0)
url = this.url;
else
url = !this.url.StartsWith("http://") ? this.url : (this.url + "_" + this.version + ".asset");
this.act_url = url;
this.www = new WWW(url);
}
}else
{
this.DownloadByBackupServer();
}
this._time_start = Time.time;
#endif
}

// 使用备份路径
// 给act_url和www字段赋值
private void DownloadByBackupServer()
{
// 不是http请求就不要加版本信息ver参数
string url = !this.url.StartsWith("http://") ? this.url : (this.url + "?ver=" + this.version);
this.act_url = this.GetBackServerUrl(url);
this.www = new WWW(this.act_url);
}

// 返回备份路径
private string GetBackServerUrl(string url)
{
if (url.Contains(this._original_src_path))
{
Debug.Log("Download From backup server " + url);
return url.Replace(this._original_src_path, this._back_server_path);
}
return url;
}

// 给外界调用
// 是否全部加载完
public static bool IsAllDone(IEnumerable<DownloadItem> list)
{
// 得到枚举器
IEnumerator<DownloadItem> enumerator = list.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
DownloadItem current = enumerator.Current;
if (!current.IsDone)
{
return false;
}
}
}
finally
{
if (enumerator == null)
{
}
enumerator.Dispose();
}
return true;
}

// 给外界调用
// 获取现在加载了多少
// 一个可枚举类型作为参数
public static float GetLoadingProgress(IEnumerable<DownloadItem> list)
{
int num;
int num2;
float num3;
GetLoadingProgress(list, out num, out num2, out num3);
return num3;
}

/// <summary>
/// 得到加载进度
/// </summary>
/// <param name="list"></param>
/// <param name="bytesLoaded">已经加载的byte</param>
/// <param name="bytesTotal">总量</param>
/// <param name="prog">进度,需要算出来</param>
public static void GetLoadingProgress(IEnumerable<DownloadItem> list, out int bytesLoaded, out int bytesTotal, out float prog)
{
int num = 0;
int num2 = 0;
bool flag = true;
IEnumerator<DownloadItem> enumerator = list.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
DownloadItem current = enumerator.Current;
if (current.size > 0)
{
num2 += current.size;
if (current.www != null)
{
num += !current.IsDone ? ((int)(current.size * current.www.progress)) : current.size;
}
}
flag = flag && current.IsDone;
}
}
finally
{
if (enumerator == null)
{
}
enumerator.Dispose();
}
bytesLoaded = num;
bytesTotal = num2;
prog = !flag ? ((num2 != 0) ? (((float)bytesLoaded) / ((float)bytesTotal)) : 0f) : 1f;
}

// 在.NET的对象中实际上有两个用于释放资源的函数:Dispose和Finalize。Finalize的目的是用于释放非托管的资源,而Dispose是用于释放所有资源,包括托管的和非托管的。
// 释放对象资源的接口是IDisposable
// 继承这个接口需要的实现如下
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (this.www != null)
{
if (disposing)
{
}
AssetBundleDestroyer.Add(this.ab);
this.www.Dispose();
this.www = null;
}
}

~DownloadItem()
{
this.Dispose(false);
}
}
}

Resource/XDownloadManager.cs

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
namespace resource
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
using System.Net;

// 静态工具类
public static class XDownloadManager
{
private static Dictionary<string, WeakReference> cache = new Dictionary<string, WeakReference>();

private static int CompareDownloadItem(DownloadItem left, DownloadItem right)
{
return left.priority - right.priority;
}

public static bool CacheAuthorized = false;
public static bool hasError = false;
public static bool hasItemDone = false;
public static string LastErrorMsg = null;
public static string LastErrorUrl = null;

private static List<DownloadItem> loading = new List<DownloadItem>();

public static int maxLoading = 5;
private static bool needSort;
public static int sizeLoaded = 0;
private static List<DownloadItem> tmpList = new List<DownloadItem>();
public static int totalLoaded = 0;
private static List<DownloadItem> waiting = new List<DownloadItem>();

public static bool CachingAuthorize(string name, string domain, long size, int expiration, string signature)
{
CacheAuthorized = true;
return CacheAuthorized;
}

public static void Cancel(DownloadItem item)
{
waiting.Remove(item);
}

public static void CancelAll()
{
waiting.Clear();
List<DownloadItem> list = DebugGetAllDownloads();

foreach (DownloadItem item in list)
{
if (item.www != null)
{
item.www.Dispose();
}
}
list.Clear();
}

public static List<DownloadItem> DebugGetAllDownloads()
{
List<DownloadItem> list = new List<DownloadItem>();
foreach (KeyValuePair<string, WeakReference> pair in cache)
{
DownloadItem target = pair.Value.Target as DownloadItem;
if (target != null)
{
list.Add(target);
}
}
return list;
}

public static void DebugGetDownloadInfo(out int numItems, out int numLoading, out int numWaiting)
{
int num = 0;
foreach (KeyValuePair<string, WeakReference> pair in cache)
{
if (pair.Value.Target is DownloadItem)
{
num++;
}
}
numItems = num;
numLoading = loading.Count;
numWaiting = waiting.Count;
}

public static string GetDomainFromUrl(string url)
{
Match match = Regex.Match(url, @"(?<=://)[a-zA-Z\.0-9]+(?=\/)");
return ((match == null) ? null : match.Value.ToString());
}

public static DownloadItem GetDownload(string url)
{
return GetDownload(url, 0, 0, 0);
}

public static DownloadItem GetDownload(string url, int version, int size, int priority)
{
string key = url;
string realResName = key + '_' + version.ToString();
DownloadItem target = null;
if (cache.ContainsKey(realResName))
{
WeakReference reference = cache[realResName];
target = reference.Target as DownloadItem;
if (target != null)
{
if ((!target.IsDone && !loading.Contains(target)) && !waiting.Contains(target))
{
waiting.Add(target);
needSort = true;
}
return target;
}
}
int tryTimes = !IsImportant(url) ? 5 : 5;
target = new DownloadItem(url, version, size, priority, tryTimes);
waiting.Insert(0, target);
needSort = true;
cache[realResName] = new WeakReference(target);
return target;
}

// 这个url是否是重要的
private static bool IsImportant(string url)
{
url = url.ToLower();
if (url.Contains("?"))
{
char[] separator = new char[] { '?' };
url = url.Split(separator)[0];
}
return (((url.EndsWith(".scene") || url.EndsWith(".config")) || url.EndsWith(".shield")) || url.EndsWith(".csv.gz"));
}

public static string GetIpsFromUrl(string url)
{
if (!url.StartsWith("http://"))
{
return string.Empty;
}
string str = null;
string domainFromUrl = GetDomainFromUrl(url);
if (domainFromUrl == null)
{
return str;
}
try
{
IPAddress[] hostAddresses = Dns.GetHostAddresses(domainFromUrl);
if (hostAddresses.Length <= 0)
{
return str;
}

return "";
}
catch (Exception exception)
{
return exception.ToString();
}
}

public static string GetLoadErrorDetail()
{
return (!hasError ? string.Empty : string.Format("Load Error, url:{0}\nmsg:{1}", LastErrorUrl, LastErrorMsg));
}

public static void Init(bool bAutoUpdate)
{
return ;
if (bAutoUpdate)
{
CoroutineManager.StartCoroutine(Loop());
}
}

private static bool IsAssetBundle(string url)
{
return true;


url = url.ToLower();
if (url.Contains("?"))
{
char[] separator = new char[] { '?' };
url = url.Split(separator)[0];
}
return ((((url.EndsWith(".ab") || url.EndsWith(".asset")) || (url.EndsWith(".scene") || url.EndsWith(".lightmap"))) || url.EndsWith(".aio")) || url.EndsWith(".config"));
}
}
}

Resource/XResourceBase.cs

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
namespace resource
{
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SingleDependAsset
{
public uint AssetID;
public uint Version;
public uint Size;
public string ResPath;
public DownloadItem DownLoad;

// 资源下载完成的通知,只应该有1次,不应该出现多次加载资源的请求。
// 对于请求一个正在加载的资源,靠外部的Resource类来处理这种问题
public delegate void SDALoadCompletedDelegate(DownloadItem item);

public SDALoadCompletedDelegate LoadCompletedEvent;

// 对外提供的方法
// 调用这个函数就是在调用委托
public void LoadCompleted(DownloadItem item)
{
if(LoadCompletedEvent != null)
LoadCompletedEvent(item);
}

// 构造函数
public SingleDependAsset(uint id, uint version, uint size)
{
AssetID = id;
Version = version;
Size = size;
}

public bool IsLoadDone()
{
if(DownLoad == null)
return false;

return DownLoad.IsDone;
}

public virtual void Load(string path)
{
DownLoad = XDownloadManager.GetDownload(path + AssetID.ToString(),(int)Version,(int)(Size),0);
DownLoad.LoadCompletedEvent += LoadCompleted;
}
}
}

Resource/XResourceManager.cs

1
2


特效

FxMaker/NcEffect/NcDestroyEvent.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using UnityEngine;

// 用于捕捉特效的销毁时机
public class NcDestroyEvent : MonoBehaviour
{
public delegate void OnDestroyEvt();

public OnDestroyEvt onDestroyEvt = null;

public void OnDestroy()
{
if (null != onDestroyEvt)
{
onDestroyEvt();
onDestroyEvt = null;
}
}
}

System/XUtil.cs 工具类

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
using System;
using UnityEngine;

class XUtil
{
public static readonly char[] CONFIG_VECTOR3_SEPARATOR = new char[]{';'};

public static Vector3 String2Vector3(string strPoint)
{
Vector3 pt = new Vector3();
if (string.IsNullOrEmpty(strPoint) == false)
{
string[] sepStr = strPoint.Split(CONFIG_VECTOR3_SEPARATOR);
try
{
pt.x = sepStr.Length > 0 ? float.Parse(sepStr[0]) : 0f;
pt.y = sepStr.Length > 1 ? float.Parse(sepStr[1]) : 0f;
pt.z = sepStr.Length > 2 ? float.Parse(sepStr[2]) : 0f;
}
catch (System.Exception ex)
{
Log.Write(LogLevel.WARN, "String2Vector3 for {0}: {1}", strPoint, ex.ToString());
}
}
return pt;
}

public static float CalcDistanceXZ(Vector3 pos1, Vector3 pos2)
{
return new Vector3(pos1.x - pos2.x, 0, pos1.z - pos2.z).magnitude;
}

public static bool IsInRange<T>(T value, T vBegin, T vEnd) where T : IComparable
{
return value.CompareTo(vBegin) >= 0 && value.CompareTo(vEnd) < 0;
}

public static bool NotInRange<T>(T value, T vBegin, T vEnd) where T : IComparable
{
return !IsInRange<T>(value, vBegin, vEnd);
}

public static readonly float DEFAULT_TRIGGER_DISTANCE = 3.0f;
public static bool IsTrigger(Vector3 pos1, Vector3 pos2)
{
return IsTrigger(pos1, pos2, DEFAULT_TRIGGER_DISTANCE);
}

public static bool IsTrigger(Vector3 posTarget)
{
return IsTrigger(posTarget, DEFAULT_TRIGGER_DISTANCE);
}

public static bool IsTrigger(Vector3 posTarget, float dist)
{
if (XLogicWorld.SP.MainPlayer == null)
{
return false;
}
return IsTrigger(posTarget, XLogicWorld.SP.MainPlayer.Position, dist);
}

public static bool IsTrigger(Vector3 pos1, Vector3 pos2, float dist)
{
return CalcDistanceXZ(pos1, pos2) <= dist;
}

public static T Instantiate<T>(T original) where T : MonoBehaviour
{
if(null == original)
return null;

GameObject go = Instantiate(original.gameObject);
if(null == go)
return null;

return go.GetComponent<T>();
}

public static GameObject Instantiate(GameObject original, Transform parent, Vector3 localPosition, Vector3 localRocation)
{
if(null == original) return null;
GameObject go = GameObject.Instantiate(original) as GameObject;
go.name = original.name;
go.transform.parent = parent;
go.transform.localPosition = localPosition;
go.transform.localRotation = Quaternion.Euler(localRocation);
return go;
}

public static GameObject Instantiate(GameObject original, Transform parent)
{
return Instantiate(original, parent, Vector3.zero, Vector3.zero);
}

public static GameObject Instantiate(GameObject original)
{
GameObject go = Instantiate(original, original.transform.parent, original.transform.localPosition, original.transform.localRotation.eulerAngles);
go.transform.localScale = original.transform.localScale;
return go;
}

/// <summary>
/// 给一个对象设置layer
/// GetComponentsInChildren包括自身
/// </summary>
/// <param name="go">要设置的对象</param>
/// <param name="go">要设置的层</param>
public static void SetLayer(GameObject go, int go)
{
Transform[] trans = go.GetComponentsInChildren<Transform>(true);
for(int i = 0; i < trans.Length; i++)
trans[i].gameObject.layer = layer;
}
// 给总秒数, 返回时间描述字符串, n为单位个数(用来忽略尾数)
public static string GetTimeStrByInt(int val, int n)
{
int s = val % 60; val /= 60;
int m = val % 60; val /= 60;
int h = val % 24; val /= 24;

int tn = 0;
string str = "";
bool bd = false;
if(val > 0)
{
str += val + XStringManager.SP.GetString(1003);
bd = true; tn++;
}
if(0 < n && tn >= n) return str;

bool bh = false;
if(bd || h > 0)
{
str += h + XStringManager.SP.GetString(1004);
bh = true; tn++;
}

if(0 < n && tn >= n) return str;
if(bh || m > 0)
{
str += m + XStringManager.SP.GetString(1005);
tn++;
}
if(0 < n && tn >= n) return str;

str += s + XStringManager.SP.GetString(1006);
return str;
}

// 给总秒数, 返回时间描述字符串, n为单位个数(用来忽略尾数)
public static string GetTimeStrByInt(int val, int n)
{
int s = val % 60; val /= 60;
int m = val % 60; val /= 60;
int h = val % 24; val /= 24;

int tn = 0;
string str = "";
bool bd = false;
if(val > 0)
{
str += val + XStringManager.SP.GetString(1003);
bd = true; tn++;
}
if(0 < n && tn >= n) return str;

bool bh = false;
if(bd || h > 0)
{
str += h + XStringManager.SP.GetString(1004);
bh = true; tn++;
}

if(0 < n && tn >= n) return str;
if(bh || m > 0)
{
str += m + XStringManager.SP.GetString(1005);
tn++;
}
if(0 < n && tn >= n) return str;

str += s + XStringManager.SP.GetString(1006);
return str;
}
}

XEventDefine.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System;

public enum EEvent
{
Begin,
#region 常用事件
MainPlayer_EnterGame, // 主角进入游戏
#endregion

#region Packet Message
Msg_Server_Return, // 服务器返回消息
#endregion

End,
}

Event/XEventManager.cs

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
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using XGame.Client.Base.Pattern;

public class XEventManager : XSingleton<XEventManager>
{
public delegate void XGlobalEventHandler(EEvent evt, params object[] args);

// HashSet<T>中的值不能重复且没有顺序。
// HashSet<T>的容量会按需自动添加。
private HashSet<XGlobalEventHandler>[] m_AllGlobalHandler;

public XEventManager()
{
m_AllGlobalHandler = new HashSet<XGlobalEventHandler>[(int)EEvent.End];

for(int i = 0; i < m_AllGlobalHandler.Length; i++)
{
m_AllGlobalHandler[i] = new HashSet<XGlobalEventHandler>();
}
}

public void Init()
{

}

public void AddHandler(XGlobalEventHandler handler, params EEvent[] events)
{
foreach(EEvent e in events)
{
m_AllGlobalHandler[(int)e].Add(handler);
}
}

public void DelHandler(EEvent e, XGlobalEventHandler handler)
{
m_AllGlobalHandler[(int)e].Remove(handler);
}

public void ClearHandler(EEvent e)
{
m_AllGlobalHandler[(int)e].Clear();
}

public void ClearAllHandler()
{
for(int i=0; i<m_AllGlobalHandler.Length; i++)
{
this.ClearHandler((EEvent)i);
}
}

public void SendEvent(EEvent e, params object[] args)
{
foreach (XGlobalEventHandler handler in m_AllGlobalHandler[(int)e])
{
handler(e, args);
}
}
}

技能</span>

配置文件

配置文件放在Assets/Other/Config/Skill文件夹下,总共有三个配置文件,分别是SkillBase.txt,SkillLevel.txt,SkillOper.txt。都是策划使用Excel配置,然后通过工具转换成txt和生成类。

SkillBase.txt

1
2
3
SkillID Name    FuncType    LevelLimit  Class   AttackTarget    UseWay  SkillTime   AttackAnim  AttackAnimSpeed AttackEffectDelay   AttackEffectID  AttackEffectBind    IsFollowBone    AttackEffectNum AttackEffectLife    TranslateDelay  UseObject   BulletID    BulletSrcBind   BulletTgtBind   BulletRate  BulletVelocity  BulletFlyTrack  RegionEffectID  DefeatDelay HitEffectID HitEffectBind   HitEffectNum    AttackShockID   AttackShockDelay    HitShockID  ShowCutSceneAnimation
11001 神力 0 10 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
11002 巧劲 0 10 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

SkillLevel.txt

1
2
3
SkillID SkillEffectType SkillLevel  LearnLevel  Kill    UseRegion   TextLearn   TextEffect  TextUpgrade ReviveRate  SuckBloodRate   SummonID    MoraleValue CRIRate CRIHPRate   AttackCount AttackTime_3_0  AttackEffect_3_0    AttackDamageRate_3_0    AttackEffectBind_3_0    AttackTime_3_1  AttackEffect_3_1    AttackDamageRate_3_1    AttackEffectBind_3_1    AttackTime_3_2  AttackEffect_3_2    AttackDamageRate_3_2    AttackEffectBind_3_2
1 1 1 1 0 0 学习技能1-1 基础攻击力100%效果 基础攻击力100%效果+20点附加伤害 0.3 0.3 990 30 5000 9000 1 0.1 100 3000 0 0.3 200 3000 0 0.3 300 4000 0
1 1 2 1 0 0 学习技能1-1 基础攻击力100%效果+20点附加伤害 基础攻击力100%效果+40点附加伤害 0.3 0.3 990 30 5000 9000 1 0.1 100 3000 0 0.3 200 3000 0 0.3 300 4000 0

SkillOper.txt

1
2
3
Class   SkillID SkillLevel  PreID   PreLevel    PosX    PosY    ClassLevel  SkillPoint  FieldID StarSprite  NotActiveSprite
1 10001 1 0 0 12.7 86.8 1 1 1 1003.11320004 11100166
1 10001 2 0 0 12.7 86.8 1 2 1 1003.11320004 11100166

读取配置

txt横排的,读取不容易,肯定需要专门的类。

\GameConfig\XCfgSkillBase.cs

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

//============================================
//--4>:
// Exported by ExcelConfigExport
//
// 此代码为工具根据配置自动生成, 建议不要修改
//
//============================================
using System;
using UnityEngine;

partial class XCfgSkillBaseMgr : CCfg1KeyMgrTemplate<XCfgSkillBaseMgr, ushort, XCfgSkillBase> { };

partial class XCfgSkillBase : ITabItemWith1Key<ushort>
{
public static readonly string _KEY_SkillID = "SkillID";
public static readonly string _KEY_Name = "Name";
public static readonly string _KEY_FuncType = "FuncType";
public static readonly string _KEY_LevelLimit = "LevelLimit";
public static readonly string _KEY_Class = "Class";
public static readonly string _KEY_AttackTarget = "AttackTarget";
public static readonly string _KEY_UseWay = "UseWay";
public static readonly string _KEY_SkillTime = "SkillTime";
public static readonly string _KEY_AttackAnim = "AttackAnim";
public static readonly string _KEY_AttackAnimSpeed = "AttackAnimSpeed";
public static readonly string _KEY_AttackEffectDelay = "AttackEffectDelay";
public static readonly string _KEY_AttackEffectID = "AttackEffectID";
public static readonly string _KEY_AttackEffectBind = "AttackEffectBind";
public static readonly string _KEY_IsFollowBone = "IsFollowBone";
public static readonly string _KEY_AttackEffectNum = "AttackEffectNum";
public static readonly string _KEY_AttackEffectLife = "AttackEffectLife";
public static readonly string _KEY_TranslateDelay = "TranslateDelay";
public static readonly string _KEY_UseObject = "UseObject";
public static readonly string _KEY_BulletID = "BulletID";
public static readonly string _KEY_BulletSrcBind = "BulletSrcBind";
public static readonly string _KEY_BulletTgtBind = "BulletTgtBind";
public static readonly string _KEY_BulletRate = "BulletRate";
public static readonly string _KEY_BulletVelocity = "BulletVelocity";
public static readonly string _KEY_BulletFlyTrack = "BulletFlyTrack";
public static readonly string _KEY_RegionEffectID = "RegionEffectID";
public static readonly string _KEY_DefeatDelay = "DefeatDelay";
public static readonly string _KEY_HitEffectID = "HitEffectID";
public static readonly string _KEY_HitEffectBind = "HitEffectBind";
public static readonly string _KEY_HitEffectNum = "HitEffectNum";
public static readonly string _KEY_AttackShockID = "AttackShockID";
public static readonly string _KEY_AttackShockDelay = "AttackShockDelay";
public static readonly string _KEY_HitShockID = "HitShockID";
public static readonly string _KEY_ShowCutSceneAnimation = "ShowCutSceneAnimation";

public ushort SkillID { get; private set; } // 技能ID
public string Name { get; private set; } // 技能名称
public int FuncType { get; private set; } // 技能功能类型
public int LevelLimit { get; private set; } // 等级上限
public byte Class { get; private set; } // 职业许可
public int AttackTarget { get; private set; } // 攻击目标
public int UseWay { get; private set; } // 作用方式
public float SkillTime { get; private set; } // 技能时间
public int AttackAnim { get; private set; } // 施展动画
public float AttackAnimSpeed { get; private set; } // 施展动画速率
public float AttackEffectDelay { get; private set; } // 攻击特效延时(1.0s)
public int AttackEffectID { get; private set; } // 攻击特效ID
public int AttackEffectBind { get; private set; } // 攻击特效绑点
public int IsFollowBone { get; private set; } // 特效是否跟随骨骼运动
public int AttackEffectNum { get; private set; } // 攻击特效数量
public float AttackEffectLife { get; private set; } // 攻击特效生存时长
public float TranslateDelay { get; private set; } // 技能传递延时(s)
public int UseObject { get; private set; } // 作用对象
public int BulletID { get; private set; } // 子弹ID
public int BulletSrcBind { get; private set; } // 子弹发射源绑定点
public int BulletTgtBind { get; private set; } // 子弹发射目标绑定点
public float BulletRate { get; private set; } // 子弹缩放比率
public float BulletVelocity { get; private set; } // 子弹飞行速度
public float BulletFlyTrack { get; private set; } // 子弹的飞行轨迹(H/W)
public int RegionEffectID { get; private set; } // 区域特效ID
public float DefeatDelay { get; private set; } // 生效延时(1.0s)
public int HitEffectID { get; private set; } // 命中特效ID
public int HitEffectBind { get; private set; } // 命中特效绑点
public int HitEffectNum { get; private set; } // 命中特效数量
public int AttackShockID { get; private set; } // 攻击时震屏特效索引
public float AttackShockDelay { get; private set; } // 攻击震屏特效延时
public int HitShockID { get; private set; } // 被击时震屏特效索引
public int ShowCutSceneAnimation { get; private set; } // 播放特殊场景动画

public XCfgSkillBase()
{
}

public ushort GetKey1() { return SkillID; }

public bool ReadItem(TabFile tf)
{
SkillID = tf.Get<ushort>(_KEY_SkillID);
Name = tf.Get<string>(_KEY_Name);
FuncType = tf.Get<int>(_KEY_FuncType);
LevelLimit = tf.Get<int>(_KEY_LevelLimit);
Class = tf.Get<byte>(_KEY_Class);
AttackTarget = tf.Get<int>(_KEY_AttackTarget);
UseWay = tf.Get<int>(_KEY_UseWay);
SkillTime = tf.Get<float>(_KEY_SkillTime);
AttackAnim = tf.Get<int>(_KEY_AttackAnim);
AttackAnimSpeed = tf.Get<float>(_KEY_AttackAnimSpeed);
AttackEffectDelay = tf.Get<float>(_KEY_AttackEffectDelay);
AttackEffectID = tf.Get<int>(_KEY_AttackEffectID);
AttackEffectBind = tf.Get<int>(_KEY_AttackEffectBind);
IsFollowBone = tf.Get<int>(_KEY_IsFollowBone);
AttackEffectNum = tf.Get<int>(_KEY_AttackEffectNum);
AttackEffectLife = tf.Get<float>(_KEY_AttackEffectLife);
TranslateDelay = tf.Get<float>(_KEY_TranslateDelay);
UseObject = tf.Get<int>(_KEY_UseObject);
BulletID = tf.Get<int>(_KEY_BulletID);
BulletSrcBind = tf.Get<int>(_KEY_BulletSrcBind);
BulletTgtBind = tf.Get<int>(_KEY_BulletTgtBind);
BulletRate = tf.Get<float>(_KEY_BulletRate);
BulletVelocity = tf.Get<float>(_KEY_BulletVelocity);
BulletFlyTrack = tf.Get<float>(_KEY_BulletFlyTrack);
RegionEffectID = tf.Get<int>(_KEY_RegionEffectID);
DefeatDelay = tf.Get<float>(_KEY_DefeatDelay);
HitEffectID = tf.Get<int>(_KEY_HitEffectID);
HitEffectBind = tf.Get<int>(_KEY_HitEffectBind);
HitEffectNum = tf.Get<int>(_KEY_HitEffectNum);
AttackShockID = tf.Get<int>(_KEY_AttackShockID);
AttackShockDelay = tf.Get<float>(_KEY_AttackShockDelay);
HitShockID = tf.Get<int>(_KEY_HitShockID);
ShowCutSceneAnimation = tf.Get<int>(_KEY_ShowCutSceneAnimation);
return true;
}
}

数据实体

Skill文件夹下有SkillManager、XSkill、XSkillDefine三个脚本文件。

XSkillDefine.cs 技能,技能等级,技能操作数据实体文件,定义了三个类,定义对应的字段存储从txt读取出来的数据。

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using XGame.Client.Packets;

public enum ESkillUseObject // 技能作用对象
{
eSuseObject_Single = 0; // 单体
eSuseObject_Region, // 区域
}

public enum EBattleSkillType
{
Battle_Skill_Normal, // 普攻
Battle_Skill_Treat, // 治疗
Battle_Skill_Special, // 绝招
Battle_Skill_Num // Battle_Skill_Num用于计数,最后一个肯定是前面的总和
}


public class XSkillLevelDefine
{
// 文本
public string TextLearn; // 学习文本
public string TextEffect; // 效果文本
public string TextUpgrade; // 升级文本

// 状态
public byte Level; // 技能等级
public uint LearnLevel; // 技能学习等级
public ESkillUseRegion useRegion; // 作用区域
public uint AnglerValue;

public uint AttackCount;
public float[] AttackTime = new float[3];
public ESkeleton[] HitEffectBind = new ESkeleton[3];
public int[] HitEffectID = new int[3];
}

public class XSkillDefine
{
public string Name; // 技能名称

// 状态
public ushort ID; // 技能ID
public ESkillFuncType FuncType; // 技能功能类型
public int LevelLimit; // 技能等级上限
public ESkillAttackTarget AttackTargetType; //攻击目标类型(1前排2后排3自身)

// 条件
public byte Class; // 学习职业

// 攻击
public float SkillTime; // 技能时间
public ESkillUseWay UseWay; // 技能作用方式
public EAnimName AttackAnim; // 施展动画
public float AttackAnimSpeed; // 施展动画速率
public float AttackEffectDelay; // 起手特效释放时间点
public int AttackEffectID; // 起手特效ID
public ESkeleton AttackEffectBind; // 起手特效绑定点
public uint IsFollowBone; // 是否跟随骨骼运动
public int AttackEffectNum; // 起手特效数量
public float AttackEffectLife; // 起手特效生存周期
public float TranslateDelay; // 技能效果开始传递延时
public ESkillUseObject UseObject; // 技能作用对象


public int BulletID; // 子弹ID
public ESkeleton BulletSrcBind; // 子弹发射源绑定点
public ESkeleton BulletTgtBind; // 子弹发射目标绑定点
public float BulletRate; // 子弹缩放比例
public float BulletVelocity; // 子弹飞行速率
public float BulletFlyTrack; // 子弹飞行轨迹
public int RegionEffectID; // 区域特效ID
public float DefeatDelay; // 生效延时
public int HitEffectID; // 被击特效ID
public ESkeleton HitEffectBind; // 被击特效绑定点
public int HitEffectNum; // 被击特效数量
public int AttackShockID; // 攻击时震屏特效索引
public float AttackShockDelay; // 攻击震屏特效延时
public int HitShockID; // 被击时震屏特效索引

// SortedList 类代表了一系列按照键来排序的键/值对
/*
SortedList sList = new SortedList();
sList.Add(1,"d");
sList.Add(2,"c");
sList.Add(3,"b");
sList.Add(4,"a");
//结果为d c b a,所以可知是按键排序,而非值排序
*/
// 给SkillManager调用,填充
// 等级对应一个等级类
public SortedList<byte, XSkillLevelDefine> Levels = new SortedList<byte, XSkillLevelDefine>();

// 此技能可不可以学取决于角色等级
public int CanLearn(byte byteLevel)
{
if (null == XLogicWorld.SP.MainPlayer)
return -1;

if (!Levels.ContainsKey(byteLevel))
return -1;

// 职业不对不能学
// if (Class > 0 && XLogicWorld.SP.MainPlayer.DynGet(EShareAttr.esa_Class) != Class)
// return -1;

// 根据等级得到等级类
XSkillLevelDefine level = Levels[byteLevel];

if(null == level)
return -1;

if (level.LearnLevel > XLogicWorld.SP.MainPlayer.Levels)
return 1;

return 0;
}

public uint GetAnger(byte level)
{
if(null == XLogicWorld.SP.MainPlayer)
return 0;

if(!Levels.ContainsKey(level))
return 0;

XSkillLevelDefine levelDefine = Levels[level];
if(null == levelDefine)
return 0;

return levelDefine.AnglerValue;
}

public uint GetLearnLevel(byte level)
{
if(null == XLogicWorld.SP.MainPlayer)
return 0;

if(!Levels.ContainsKey(level))
return 0;

XSkillLevelDefine levelDefine = Levels[level];
if(null == levelDefine)
return 0;

return levelDefine.LearnLevel;
}
}

public class XSkillOper
{
public ushort ID; // 技能ID
public byte Level; // 技能等级
public byte Class; // 职业
public ushort PreID; // 前置技能ID
public byte PreLevel; // 前置技能等级

public float PosX;
public float PosY;

public uint ClassLevel; // 学习阶段
public uint SkillPoint; // 技能点消耗
public byte FieldID; // 技能栏ID
public uint AtlasID; // 图集ID
public string SpriteName; // 精灵名称
public string NotLearnSpriteName;

public int CanLearn()
{
if(null == XLogicWorld.SP.MainPlayer)
return -1;

if(SkillManager.SP.m_uSkillPoint < SkillPoint)
return 1;

if(SkillManager.SP.GetActiveSkill(PreID) < PreLevel)
return 2;

if(XLogicWorld.SP.MainPlayer.DynGet(EShareAttr.esa_Class) != Class)
return -1;

XSkillDefine SkillDef = SkillManager.SP.GetSkillDefine((ushort)ID);

if(null == SkillDef)
return -1;

XSkillLevelDefine SkillLevel = SkillDef.Levels[Level];

if(null == SkillLevel)
return -1;

if(SkillLevel.LearnLevel > XLogicWorld.SP.MainPlayer.Level)
return -1;

return 0;
}
}

管理

读取配置然后给实体类赋值。

SkillManager.cs

1
2


\Skill\XSkill.cs

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
using UnityEngine;
using System.Collections.Generic;
using XGame.Client.Packets;

/*
* 运行中技能, 只用于技能表现,修改的时候,要保证能不依赖其他,能单独使用
*/
public class XSkill
{
public bool isLucky { get;set; }
public bool IsMultiAttack = false;
private XSkillDefine m_SkillDef = null; // 技能数据实体类
private XSkillLevelDefine m_SkillLevel = null; // 技能等级数据实体类
private XCharacter Attacker { get;set; } // 攻击者
private XCharacter MainTarget { get;set; } // 主要目标
private List<XCharacter> mTargetList = new List<XCharacter>(); // 攻击列表
private float mCurRunTime; // 目前运行时间
private uint mSKillID; // 技能ID
private uint mSkillLevel; // 技能等级
private bool mIsActive; // 是否激活
public float SkillTotalTime { get; private set; } // 技能总时间
public XBattlePosition TargetBattlePos {get;set;} // 目标战斗位置

// 表现列表
private List<SkillDisplay_Base> mDisplayList = new List<SkillDisplay_Base>();
// 伤害列表
private List<SkillDisplay_Base> mDamageList = new List<SkillDisplay_Base>();
// buff效果综合
public XBuffDisplayMulti m_BuffDisplayMulti = null;

public XSkill()
{
Attacker = null;
mCurRunTime = 0;
mSKillID = 0;
mSkillLevel = 0;
mIsActive = false;
SkillTotalTime = 0.0f;
}

/*
LParam 的低十六位是鼠标的x坐标,高十六位是y坐标
(int)m.LParam & 0xFFFF 意思是取得LParam的低十六位
(int)m.LParam >> 16 & 0xFFFF 意思是将LParam右移十六位,再取得低十六位,即取了原来LParam的高十六位
*/
// 高16位为技能ID, 低16位是技能等级
public uint SkillID
{
get
{
return mSKillID;
}
set
{
if (value > 0)
{
mSKillID = value >>16;
mSkillLevel = value & 0xffff;
m_SkillDef = SkillManager.SP.GetSkillDefine((ushort)mSKillID);
m_SkillLevel = m_SkillDef.Levels[(byte)mSkillLevel];

if (m_SkillLevel == null)
{
Log.Write(LogLevel.ERROR, "skill Level = null");
}
}
}
}

// 得到技能ID
public uint SkillLevelID
{
get
{
return mSkillLevel;
}
}

/// <summary>
/// 得到特效位置
/// 给XU3dEffect的对象属性赋值
/// </summary>
/// <param name="effect">特效</param>
/// <param name="rot">向量</param>
public void GetEffectPos(XU3dEffect effect, Vector3 rot)
{
if (m_SkillLevel.useRegion == ESkillUseRegion.eSUseRegion_Total)
{
Vector3 pos = BattleDisplayMgr.GetFighterPos(TargetBattlePos.Group, 5);
effect.Position = pos;
effect.Direction = Quaternion.Euler(rot).eulerAngles;
return;
}
}

// 初始化技能表现
public void InitSkillDisplay()
{
if (m_SkillDef == null)
return;

SkillTotalTime = m_SkillDef.SkillTime;


}
}

Battle/SkillDisplay.cs 技能表现

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
using System.Collections.Generic;
using UnityEngine;

// 技能表现事件
public enum SkillDisplay_Event
{
SkillDisplay_Event_None,
SkillDisplay_Event_Effect,
SkillDisplay_Event_Bullet,
SkillDisplay_Event_Sound,
SkillDisplay_Event_ID,
SkillDisplay_Event_Shake,
SkillDisplay_Event_Num,
}

// 技能表现基类
public class SkillDisplay_Base
{
public SkillDisplay_Event SelfType {get; protected set;}

public float DoTime{ get; set; }
public XSkill CurSkill { get; set; }
protected bool IsPlayed = false;

public SkillDisplay_Base(XSkill skill)
{
CurSkill = skill;
SelfType = SkillDisplay_Event.SkillDisplay_Event_None;
}

public virtual void Init(){}

public virtual bool CreateSkillDisplay()
{
return false;
}

public virtual void DestroySkillDisplay(){}

public virtual void UpdateSkillDisplay(float runTime, float deltaTime)
{
if (IsPlayed)
return;

float nowTime = runTime + deltaTime;

if (runTime <= DoTime && nowTime > DoTime)
CreateSkillDisplay();
}

}

外观模式

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
using System;
using XGame.Client.Packets;
using Google.ProtocolBuffers;
using UnityEngine;
using resource;

class XLogicWorld
{
private static XLogicWorld m_this = new XLogicWorld();
public static XLogicWorld SP { get { return m_this; } }

#region Propertys
public Login LoginProc { get; private set; }
public XNetworkManager NetManager { get; private set; }
public XObjectManager ObjectManager { get; private set; }
public XSceneManager SceneManager { get; private set; }
public XSubSceneManager SubSceneManager { get; private set; }
public SkillManager SkillManager { get; private set; }
public XQuestManager QuestManager { get; private set; }
public XPetManager PetManager { get; private set; }
public XAuctionManager AuctionManager { get; private set; }
public XMainPlayer MainPlayer { get; private set; }
public XMailManager MailManager { get; private set; }
public XShanHTManager ShanHT { get; private set; }
#endregion

private XLogicWorld()
{
m_this = this;

LoginProc = new Login();
NetManager = new XNetworkManager();
ObjectManager = new XObjectManager();
SceneManager = new XSceneManager();
SubSceneManager = new XSubSceneManager();
SkillManager = new SkillManager();
QuestManager = new XQuestManager();
PetManager = new XPetManager();
AuctionManager = new XAuctionManager();
MainPlayer = new XMainPlayer(0);
MailManager = new XMailManager();

ShanHT = new XShanHTManager();

SceneManager.Init();
}

~XLogicWorld()
{
OnDestroy();
}
}

Battle

Battle/XBattleDefine.cs

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
using System;
using XGame.Client.Packets;

enum EBattleObjecType
{
ebot_Begin = 0,
ebot_Player = ebot_Begin, // 玩家
ebot_Monster, // 怪物
ebot_Magic, // 法宝
ebot_Pet, // 宠物
ebot_End,
};

public class XBattleDefine
{
public static readonly int BATTLE_MAGIC_POS = 0;
public static readonly int BATTLE_POS_COUNT = (9+1);
}

public class XBattlePosition
{
public EBattleGroupType Group { get; private set; }
public uint Position { get; private set; }

public uint ToUInt()
{
return (((uint)Group) << 5) | Position;
}

public static bool IsValid(EBattleGroupType e, uint pos)
{
if (e < EBattleGroupType.eBattleGroup_Begin || e >= EBattleGroupType.eBattleGroup_End)
{
return false;
}
if (pos < 0 || pos >= XBattleDefine.BATTLE_POS_COUNT)
{
return false;
}
return true;
}

public override string ToString()
{
return string.Format("BattlePosition {0}-{1}", Group, Position);
}

private XBattlePosition(EBattleGroupType e, uint pos)
{
Group = e;
Position = pos;
}

public static XBattlePosition Create(EBattleGroupType e, uint pos)
{
if (XBattlePosition.IsValid(e, pos))
{
return new XBattlePosition(e, pos);
}
return null;
}

public static XBattlePosition Create(uint netPos)
{
uint nGroup = netPos >> 5;
// 网络包位置信息保存8位, 1-5 保存位置信息, 6-8 保存分组信息
uint pos = netPos & 0x1F;
return Create((EBattleGroupType)nGroup, pos);
}
}

Battle/XBattleObject.cs

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
using System;
using UnityEngine;

// 战斗场景中的一个对象
public class XBattleObject : XPlayer
{
protected XBattlePosition m_curBattlePos = null;

public bool m_bIsSummon = false; // summon 召唤

public XBattlePosition curBattlePos
{
get{ return m_curBattlePos; }
set{ m_curBattlePos = value; }
}

public XBattleObject()
: base(0)
{

}

protected override void OnDead()
{
if (true == m_bIsSummon)
return;

BattleDisplayerMgr.SP.DeadSoul( this );
}

// Morale 士气
public bool IsFullMorale { get;set; }
}

public class XBattlePlayer : XBattleObject
{
private uint m_uiSoulValue = 0;

public uint SoulValue
{
get
{
return m_uiSoulValue;
}
set
{
m_uiSoulValue = value;
m_uiSoulValue = Math.Min(m_uiSoulValue,12 );
}
}

public XBattlePlayer()
{
ObjectType = EObjectType.OtherPlayer;
}
}

public class XBattleMonster : XBattleObject
{
public XBattleMonster()
{
ObjectType = EObjectType.Monster;
}
}

public class XBattlePet : XBattleObject
{
public XBattlePet()
{
ObjectType = EObjectType.Pet;
}
}

Battle/BattleDisplayerMgr.cs 代表一场战斗的表现

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
using XGame.Client.Packets;
using System.Collections.Generic;
using XGame.Client.Base.Pattern;
using UnityEngine;

public class BattleDisplayerMgr : XSingleton<BattleDisplayerMgr>
{
public static readonly float BATTLE_UNIT_SIZE = 3.5f; // 战斗单位间距
public static readonly float BATTLE_ROUND_INTERVAL = 1.0f; // 回合之间相距2s
public static readonly float BATTLE_GROUP_OFFSET = 4.0f; // 左右战斗群体距离中心点的距离
public static readonly uint GRID_EFFECT_ID = 900026;

// 战斗摄像机相对于中心点的偏移
public static readonly Vector3 BATTLE_CAMERA_OFFSET = new Vector3(26.06129f, 24.24784f, -30.4854f);
// 视角FOV是指镜头所能覆盖的范围,物体超过这个角就不会被收在镜头里,一个摄像机镜头能涵盖多大范围的景物,通常以角度来表示,这个角度就叫镜头的视角FOV。
public static readonly float BATTLE_CAMERA_FOV = 20.0f;

public float PlaySpeed { get;set; }
public bool IsDirectOver = false;

private XBattlePosition m_MainPlayerPos = null;

public XBattlePosition MainPlayerPos
{
get{ return m_MainPlayerPos; }
set{ m_MainPlayerPos = value; }
}

public BattleDisplayerMgr()
{
XEventManager.SP.AddHandler(FightSubBlood, EEvent.FightHead_Show_Sub_Blood);
XEventManager.SP.AddHandler(ResetMaxFightBlood, EEvent.FightHead_Show_ReSet_Max_Blood);

XEventManager.SP.AddHandler(FightAnimStart, EEvent.Fight_Anim_Start );
XEventManager.SP.AddHandler(FightAnimEnd, EEvent.Fight_Anim_End );
}

public int LeftBloodValue { get;set; }
public int RightBloodValue { get;set; }
public int LeftBattleValue { get;set; }
public int RightBattleValue { get;set; }

private int CurLeftBloodValue;
private int CurRightBloodValue;

private XU3dEffect[] mEffectList = new XU3dEffect[XBattleDefine.BATTLE_POS_COUNT * (int)EBattleGroupType.eBattleGroup_End];

public void SetBloodValue(uint left, uint right)
{
LeftBloodValue = (int)left;
RightBloodValue = (int)right;

CurLeftBloodValue = LeftBloodValue;
CurRightBloodValue = RightBloodValue;
}
}

\Client\Assets\Scripts\Battle\XBattleManager.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System;
using XGame.Client.Packets;
using UnityEngine;
using System.Collections.Generic;
using XGame.Client.Base.Pattern;

public enum EBattleState
{
Invalid, // 无效
Loading, // 加载中
Fighting, // 战斗中
Leaving, // 离开
}

//该对象本身,只做接收消息,设置数据,具体表现都交由BattleDisplayerMgr来处理
//将一场战斗的表现完全与逻辑独立开来,方便录像,以及引擎调用

Camera

GameLogic/XCameraLogic.cs

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
using UnityEngine;
using System.Collections;
using XGame.Client.Base.Pattern;

// 主摄像机逻辑
public class XCameraLogic : XSingleton<XCameraLogic>
{
public Camera mainCamera { get;private set; }
private Transform m_MotherTransform = null;
private Vector3 m_MotherPos = Vector3.zero;

// 主摄像机在一个矩形平面内运动,以下保存着摄像机相对矩形信息
private float m_LocalY = 0f; // Attach的时候的Y轴相对坐标
private float m_LocalDis = 0f; // Attach的时候的X,Z平面相对距离

private Vector3 m_relaPosition = Vector3.zero;
private float m_fWheelDelta = 0f;
private float m_fWaitWD = 0f;
private GameObject m_CamDemo = null;

private Vector3 m_v3CamPosTarget = Vector3.zero;
public bool IsEnableCameraCollide = false;

public XCameraLogic()
{
mainCamera = Camera.main;
m_CamDemo = new GameObject("camera temp");
m_CamDemo.transform.parent = mainCamera.transform.parent;
m_CamDemo.transform.position = mainCamera.transform.position;
m_CamDemo.transform.rotation = mainCamera.transform.rotation;

Object.DontDestroyOnLoad(mainCamera);
Object.DontDestroyOnLoad(m_CamDemo);
}

private Vector3 relaPosition
{
set{ m_relaPosition = value; }
}

public float WheelDelta
{
get{ return m_fWheelDelta; }
set{ m_fWheelDelta = value; }
}

public void Breathe()
{
if (0f != m_fWaitWD)
{
bool w = m_fWaitWD > 0;
float fd = Time.deltaTime * LogicApp.SP.UserDefine.mainCameraCurveSpeed;
if (!w) fd *= -1;
m_fWaitWD -= fd;
if (w != (m_fWaitWD > 0) || !scroll(fd))
m_fWaitWD = 0f;
}
}
}

CoroutineManager

CoroutineManager/CoroutineManager.cs 协程管理器

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
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using UnityEngine;

public class CoroutineBehaviour : MonoBehaviour
{
}

public static class CoroutineManager
{

private class CoroutineInfo
{
public string desc;
public WeakReference obj;
}

private static MonoBehaviour mMain;
private static CoroutineBehaviour mPrivate;
private static List<CoroutineInfo> routines = new List<CoroutineInfo>();

// 函数以Debug开头表示调试用
public static int DebugGetCoroutineCount()
{
return routines.Count;
}

public static string DumpCoroutines()
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("DumpCoroutines\n", new object[0]);
int num = 0;
foreach (CoroutineInfo info in routines)
{
if (info.obj.IsAlive)
{
object target = info.obj.Target;
num++;
builder.AppendFormat(" {0}: {1}\n", target, info.desc);
}
}
builder.AppendFormat(" count: {0}\n", num);
return builder.ToString();
}

public static void Init(MonoBehaviour main)
{
mMain = main;
}

// 如果定义了编译符号,那么编译器会包含所有调用这个方法的代码,这和普通方法没有什么区别
// 如果没有定义编译符号,那么编译器会忽略代码中这个方法的所有调用
[Conditional("ENABLE_TRACE")]
private static void MiniszieRoutineList()
{
int num = 0;
while (num < routines.Count)
{
CoroutineInfo item = routines[num];
if (!item.obj.IsAlive)
{
routines.Remove(item);
}
else
{
num++;
}
}
}

public static Coroutine StartCoroutine(IEnumerator routine)
{
return StartCoroutine(routine, false);
}

public static Coroutine StartCoroutine(IEnumerator routine, bool bDestroyWhenLoadLevel)
{
if (!bDestroyWhenLoadLevel)
{
return mMain.StartCoroutine(routine);
}
if (mPrivate == null)
{
mPrivate = new GameObject("CoroutineManager").AddComponent<CoroutineBehaviour>();
}
return mPrivate.StartCoroutine(routine);
}
}
0%