最后一战大型moba游戏开发

思考并回答以下问题:

工作

不要拿到策划案直接就开始写,可能会出现很多问题,因为考虑问题不全面,有很多bug。要做好整体的架构和方案。

新手和老手的区别是对变量的保护做的非常多,考虑的全面。

模块化的思维方式。 如果代码给别人用的话,好不好用。

定义的常量都放在单独的常量文件中。

AssetBundle还可以继续打包压缩成7Zip。

1是架构,2是模块化思想,3是AssetBundle,都是为了减少包体大小。

代码

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

// 作用:对外提供接口用于所有管理类接口的使用

public class Facade
{
static GameObject m_GameManager;
static Dictionary<string, object> m_Managers = new Dictionary<string, object>();
private static Facade _instance;

private ResourceManager m_ResMgr;
private ObjManager m_ObjMgr;

GameObject AppGameManager
{
get
{
if (m_GameManager == null)
{
m_GameManager = GameObject.Find("GameManager");
}
return m_GameManager;
}
}

public static Facade Instance
{
get
{
if (_instance == null)
{
_instance = new Facade();
}
return _instance;
}
}

/// <summary>
/// 添加管理器
/// </summary>
public void AddManager(string typeName, object obj)
{
if (!m_Managers.ContainsKey(typeName))
{
m_Managers.Add(typeName, obj);
}
}

/// <summary>
/// 添加Unity对象
/// </summary>
public T AddManager<T>(string typeName) where T : Component
{
object result = null;
m_Managers.TryGetValue(typeName, out result);
if (null != result)
{
return (T)result;
}
Component c = AppGameManager.AddComponent<T>();
m_Managers.Add(typeName, c);
return default(T);
}

/// <summary>
/// 获取系统管理器
/// </summary>
public T GetManager<T> (string typeName) where T : class
{
if (!m_Managers.ContainsKey(typeName))
{
return default(T);
}
object manager = null;
m_Managers.TryGetValue(typeName, out manager);
return (T)manager;
}

/// <summary>
/// 删除管理器
/// </summary>
public void RemoveManager(string typeName)
{
if (!m_Managers.ContainsKey(typeName))
{
return;
}
object manager = null;
m_Managers.TryGetValue(typeName, out manager);
Type type = manager.GetType();
if(type.IsSubclassOf(typeof(MonoBehaviour)))
{
UnityEngine.Object.Destroy((Component)manager);
}
m_Managers.Remove(typeName);
}

public ResourceManager ResourceManager
{
get
{
if(m_ResMgr == null)
{
m_ResMgr = GetManager<ResourceManager>("ResourceManager");
}
return m_ResMgr;
}
}

public ObjManager ObjManager
{
get
{
if(m_ObjMgr == null)
{
m_ObjMgr = GetManager<ObjManager>("ObjManager");
}
return m_ObjMgr;
}
}
}

AppConst.cs

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

public class AppConst
{
public const int TimerInterval = 1;
public const int GameFrameRate = 30;

public const string AppName = "Game";

public const string AppPrefix = AppName + "_";

public const string ExtName = ".assetbundle";

public const string AssetDirname = "StreamingAssets";
public const string WebUrl = "http://localhost:6688";
}

Util.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
using UnityEngine;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text.RegularExpressions;

#if UNITY_EDITOR
using UnityEditor;
#endif

public class Util
{
private static List<string> luaPaths = new List<string>();

public static int Int(object o)
{
return Convert.ToInt32(o);
}

public static float Float(object o)
{
return (float)Math.Round(Convert.ToSingle(o), 2);
}

public static long Long(object o)
{
return Convert.ToInt64(o);
}

public static int Random(int min, int max)
{
return UnityEngine.Random.Range(min, max);
}

public static float Random(float min, float max)
{
return UnityEngine.Random.Range(min, max);
}

// 移除后缀
public static string Uid(string uid)
{
int position = uid.LastIndexOf('_');
return uid.Remove(0, position + 1);
}

// 获取时间
public static long GetTime()
{
TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1, 0, 0, 0).Ticks);
return (long)ts.TotalMilliseconds;
}

/// <summary>
/// 搜索子物体组件-GameObject版
/// </summary>
public static T Get<T> (GameObject go, string subnode) where T : Component
{
if (go != null)
{
Transform sub = go.transform.FindChild(subnode);
if (sub != null) return sub.GetComponent<T>();
}
return null;
}

/// <summary>
/// 搜索子物体组件-Transform版
/// </summary>
public static T Get<T> (Transform go, string subnode) where T : Component
{
if (go != null)
{
Transform sub = go.FindChild(subnode);
if (sub != null) return sub.GetComponent<T>();
}
return null;
}

/// <summary>
/// 搜索子物体组件-Component版
/// </summary>
public static T Get<T> (Component go, string subnode) where T : Component
{
return go.transform.FindChild(subnode).GetComponent<T>();
}

/// <summary>
/// 添加组件
/// </summary>
public static T Add<T> (GameObject go) where T : Component
{

if (go != null)
{
T[] ts = go.GetComponents<T>();
for(int i = 0; i < ts.Length; i++)
{
if(ts[i] != null) GameObject.Destroy(ts[i]);
}
return go.gameObject.AddComponent<T>();
}
return null;
}

/// <summary>
/// 添加组件
/// </summary>
public static T Add<T> (Transform go) where T : Component
{
return Add<T>(go.gameObject);
}

/// <summary>
/// 查找子对象
/// </summary>
public static GameObject Child(Transform go, string subnode)
{
Transform tran = go.FindChild(subnode);
if (tran == null) return null;
return tran.gameObject;
}

/// <summary>
/// 取平级对象
/// </summary>
public static GameObject Peer(GameObject go, string subnode)
{
return Peer(go.transform, subnode);
}

/// <summary>
/// 取平级对象
/// </summary>
public static GameObject Peer(Transform go, string subnode)
{
Transform tran = go.parent.FindChild(subnode);
if (tran == null) return null;
return tran.gameObject;
}

/// <summary>
/// Base64编码
/// </summary>
public static string Encode(string message)
{
byte[] bytes = Encoding.GetEncoding("utf-8").GetBytes(message);
return Convert.ToBase64String(bytes);
}

/// <summary>
/// Base64解码
/// </summary>
public static Decode(string message)
{
byte[] bytes = Convert.FromBase64String(message);
return Encoding.GetEncoding("utf-8").GetString(bytes);
}

/// <summary>
/// 判断string是否是数字
/// </summary>
public static bool IsNumeric(string str)
{
if(str == null || str.Length == 0) return false;

for(int i = 0; i < str.Length; i++)
{
if (!Char.IsNumber(str[i]))
{
return false;
}
}
return true;
}

public static string HashToMD5Hex(string sourceStr)
{
byte[] Bytes = Encoding.UTF8.GetBytes(sourceStr);

using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] result = md5.ComputeHash(Bytes);
StringBuilder builder = new StringBuilder();
for(int i = 0; i < result.Length; i++)
{
builder.Append(result[i].ToString("x2"));
}

return builder.Tostring();
}
}

public static string md5(string source)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] data = System.Text.Encoding.UTF8.GetBytes(source);
byte[] md5Data = md5.ComputeHash(data, 0, data.Length);
md5.Clear();

string destString = "";
for (int i = 0; i < md5Data.Length; i++)
{
destString += System.Convert.ToString(md5Data[i], 16).PadLeft(2, '0');
}
destString = destString.PadLeft(32, '0');
return destString;
}

public static string md5file(string file)
{
try
{
FileStream fs = new FileStream(file, FileMode.Open);
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(fs);
fs.Close();
StringBuilder sb = new StringBuilder();

for(int i= 0; i < retVal.Length; i++)
{
sb.Append(retval[i].ToString("x2"));
}

return sb.ToString();
}
catch (Exception ex)
{
throw new Exception("md5file() fail, error" + ex.Message);
}
}

public static void ClearChild(Transform go)
{
if (go ==null)
return;

for (int i = go.childCount - 1; i >= 0; i--)
{
GameObject.Destroy(go.GetChild().gameObject);
}
}

public static string GetKey(string key)
{
return AppConst.AppPrefix + "_" + key;
}

public static int GetInt(string key)
{
string name = GetKey(key);
return PlayerPrefs.GetInt(name);
}

public static bool HasKey(string key)
{
string name = GetKey(key);
return PlayerPrefs.HasKey(name);
}

public static void SetInt(strIng key, int value)
{
string name = GetKey(key);
PlayerPrefs.DeleteKey(name);
PlayerPrefs.SetInt(name, value);
}

public static string GetString(string key)
{
string name = GetKey(key) ;
return PlayerPrefs.GetString(name);
}

public static void SetString(strinq key, string value)
{
string name = GetKey(key) ;
PlayerPrefs.DeleteKey(name);
PlayerPrefs.SetString(name, value);
}

public static void RemoveData(string key)
{
string name = GetKey(key);
PlayerPrefs.DeleteKey(name);
}

public static void ClearMemory()
{
GC.Collect();
Resources.UnloadUnusedAssets();
}

public static bool IsNumber(string strNumber)
{
Regex regex = new Regex("[^0-9]");

return !regex.IsMatch(strNumber);
}

public static string DataPath
{
get
{
string name = AppConst.AppName.ToLower();
if(Application.isMobilePlatform)
return Application.persistentDataPath + "/" + game + "/";
else
return Application.dataPath + "/" + AppConst.AssetDirname + "/";
}

}

public static bool NetAvailable
{
get
{
return Application.internetReachability != NetworkReachability.NotReachable;
}

}

public static bool IsWifi
{
get
{
return Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork;
}
}

public static string AppContentPath()
{
string path = string.Empty;

switch (Application.platform)
{
case RuntimePlatform.Android:
path = "jar:file://" + Application.dataPath + "!/assets/";
break;

case RuntimePlatform.IPhonePlayer:
path = Application.dataPath + "/Raw/";
break;

default:
path = Application.dataPath + "/" + AppConst.AssetDirname + "/";
break;
}
return path;
}
}

ObjManager.cs

1
2
3
4
5
6
public class ObjManager : MonoBehaviour
{
Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();


}

ResourceManager.cs

1
2


Editor

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

public class Packager
{
public static string platform = string.Empty;
static List<string> paths = new List<string>();
static List<string> files = new List<string>();

[MenuItem("Game/Build iPhone Resource", false, 1)]
public static void BuildiPhoneResource()
{
BuildTarget target;
target = BuildTarget.iOS;
BuildAssetResource(target, false);
}

[MenuItem("Game/Build Android Resource", false, 2)]
public static void BuildAndroidResource()
{
BuildAssetResource(BuildTarget.Android, false);
}

[MenuItem("Game/Build Windows Resource", false, 3)]
public static void BuildWindowsResource()
{
BuildAssetResource(BuildTarget.StandaloneWindows64, true);
}

public static void BuildAssetResource(BuildTarget target, bool isWin)
{
string dataPath = Util.DataPath;
if(Directory.Exists(dataPath))
Directory.Delete(dataPath, true);

// string assetfile = string.Empty;

string resPath = AppDataPath + "/" + AppConst.AssetDirname + "/";
if(Directory.Exists(resPath))
Directory.CreateDirectory(resPath);

BuildPipeline.BuildAsssetBundles(resPath, BuildAsssetBundleOptions.None, target);

AssetDatabase.Refresh();
}

static string AppDataPath
{
get
{
return Application.dataPath.ToLower();
}
}

static void Recursive(string path)
{
string[] names = Directory.GetFiles(path);
string[] dirs = Directory.GetDirectories(path);

foreach (string filename in names)
{
string ext = Path.GetExtension(filename);
if (ext.Equals(".meta")) continue;
files.Add(filename.Replace('\\', '/'));
}

foreach (string dir in dirs)
{
paths.Add(dir.Replace('\\', '/'));
Recursive(dir);
}
}

static void UpdateProgress(int progress, int progressMax, string desc)
{
string title = "Processing..[" + progress + "-" + progressMax + "]";
float value = (float)progress / (float)progressMax;
EditorUtility.DisplayProgress(title, desc, value);
}
}
0%