人生第一个上线项目总结
此时,项目公测第一天,项目组集体坐在公司值班,等待着用户反馈,鉴于之前已经做过为期半个月的内测,于是,公测的第一天晚上似乎不是多么紧张。
毕业后,就进入现在公司,开始了现在项目。历时一年,很快。快结束的现在,总觉得自己应该总结下这一年发生的事情,于是,便记在这里,供自己“回眸”。(可能更多的是从程序员的视界来看待问题。)
使用技术:服务器,Linux + Java + Oracle;客户端,Unity3D(主要NGUI).
产品框架:
服务器 | 客户端 | 网站 |
1、登录服务器L。 |
2、登录场景。 |
|
2、主要服务器H。 |
1、登录器。 3、主要场景。 |
|
3、服务器G。 4、服务器D。 5、服务器O。 |
4、主要业务群。 |
项目经过:1、练手阶段——使用Unity3D+NGUI(初次使用)。
2、第一个东西——依然NGUI,客户端,主要为各种显示逻辑,显示效果。
3、斗地主服务器——研究了一段时间的IOCP,最后因为所有服务器由Java开发,于是夭折。
4、主要场景——由外包接手过来,基本全部(除通信部分)改掉,一直到现在。
5、登录器——MFC。
6、Debug阶段。
7、内测、公测阶段。
懵懂的练手
刚进入公司的时候,老大说客户端的所有效果将会由NGUI来完成,鉴于之前我有一年(实习)使用Unity3D的经验,于是让我直接开始做客户端中的一部分——一个场景(FS)。在将NGUI2.6.3导入场景之后,此时的我是不知如何建立Sprite,不知Atlas为何物。
且摸着石头过河,看例子、群里问问。磕磕绊绊将FS所需功能、效果完成后,知晓NGUI的成员,知晓NGUI的层级。
NGUI
NGUI,Unity3D中使用最多的UI插件,因其较少的Draw Call而受到开发者的喜爱。它通过将一系列图片通过一个序列进行排列,制成Atlas。使用它可以很方便的建立图片、按钮、文字、滚动条等。(现在我的水平为会用它,能够在需求下改改他的代码,至于全部读懂,还需要时间)。
在使用NGUI前期,比较麻烦的就是层级问题,你不能单纯的通过z值来控制显示前后。自己总结了下:一个panel下的所有NGUI物体(有时候label除外)具有同一z值,通过depth来控制前后关系;一个panel里面的文字可以通过z值微调前后。多个panel的前后关系由z值控制。其他使用问题都比较简单,不再做说明。附一个之前改过的UiTextList(加入ScrollBar支持,可能后期版本需要修改使用,也可能以后版本的NGUI已经支持)。
1 //---------------------------------------------- 2 // NGUI: Next-Gen UI kit 3 // Copyright ?2011-2013 Tasharen Entertainment 4 //---------------------------------------------- 5 6 using UnityEngine; 7 using System.Collections.Generic; 8 using System.Text; 9 10 /// <summary> 11 /// Text list can be used with a UILabel to create a scrollable multi-line text field that's 12 /// easy to add new entries to. Optimal use: chat window. 13 /// </summary> 14 15 [AddComponentMenu("NGUI/UI/Text List")] 16 public class UITextList : MonoBehaviour { 17 public enum Style { 18 Text, 19 Chat, 20 } 21 22 public Style style = Style.Text; 23 public UILabel textLabel; 24 public float maxWidth = 0f; 25 public float maxHeight = 0f; 26 public int maxEntries = 50; 27 public bool supportScrollWheel = true; 28 29 // Text list is made up of paragraphs 30 protected class Paragraph { 31 public string text; // Original text 32 public string[] lines; // Split lines 33 } 34 35 protected char[] mSeparator = new char[] { '\n' }; 36 protected List<Paragraph> mParagraphs = new List<Paragraph>(); 37 protected float mScroll = 0f; 38 protected bool mSelected = false; 39 protected int mTotalLines = 0; 40 41 /// <summary> 42 /// Clear the text. 43 /// </summary> 44 45 public void Clear() { 46 mParagraphs.Clear(); 47 UpdateVisibleText(); 48 } 49 50 /// <summary> 51 /// Add a new paragraph. 52 /// </summary> 53 54 public void Add(string text) { 55 if (!isScreenLocked) Add(text, true); 56 else Add(text, false); 57 } 58 59 /// <summary> 60 /// Add a new paragraph. 61 /// </summary> 62 63 protected void Add(string text, bool updateVisible) { 64 Paragraph ce = null; 65 66 if (mParagraphs.Count < maxEntries) { 67 ce = new Paragraph(); 68 } else { 69 ce = mParagraphs[0]; 70 mParagraphs.RemoveAt(0); 71 } 72 73 ce.text = text; 74 mParagraphs.Add(ce); 75 76 if (textLabel != null && textLabel.font != null) { 77 // Rebuild the line 78 ce.lines = textLabel.font.WrapText(ce.text, maxWidth / textLabel.transform.localScale.y, 79 textLabel.maxLineCount, textLabel.supportEncoding, textLabel.symbolStyle).Split(mSeparator); 80 81 // Recalculate the total number of lines 82 mTotalLines = 0; 83 for (int i = 0, imax = mParagraphs.Count; i < imax; ++i) mTotalLines += mParagraphs[i].lines.Length; 84 } 85 86 // Update the visible text 87 if (updateVisible) { 88 UpdateVisibleText(); 89 if (null != verticalScrollBar && mTotalLines > maxLines) { 90 verticalScrollBar.gameObject.SetActive(true); 91 downBtnGo.SetActive(true); 92 upBtnGo.SetActive(true); 93 verticalScrollBar.scrollValue = 1; 94 } 95 } 96 } 97 98 /// <summary> 99 /// Automatically find the values if none were specified. 100 /// </summary> 101 102 void Awake() { 103 if (textLabel == null) textLabel = GetComponentInChildren<UILabel>(); 104 if (textLabel != null) textLabel.lineWidth = 0; 105 106 Collider col = collider; 107 108 if (col != null) { 109 // Automatically set the width and height based on the collider 110 if (maxHeight <= 0f) maxHeight = col.bounds.size.y / transform.lossyScale.y; 111 if (maxWidth <= 0f) maxWidth = col.bounds.size.x / transform.lossyScale.x; 112 } 113 114 verticalScrollBar.onChange += OnVerticalBar; 115 } 116 117 /// <summary> 118 /// Remember whether the widget is selected. 119 /// </summary> 120 121 void OnSelect(bool selected) { mSelected = selected; isNotOnScroll = !selected; } 122 123 /// <summary> 124 /// Refill the text label based on what's currently visible. 125 /// </summary> 126 127 private int maxLines; 128 protected void UpdateVisibleText() { 129 if (textLabel != null) { 130 UIFont font = textLabel.font; 131 132 if (font != null) { 133 int lines = 0; 134 maxLines = maxHeight > 0 ? Mathf.FloorToInt(maxHeight / textLabel.cachedTransform.localScale.y) : 100000; 135 int offset = Mathf.RoundToInt(mScroll); 136 137 // Don't let scrolling to exceed the visible number of lines 138 if (maxLines + offset > mTotalLines) { 139 offset = Mathf.Max(0, mTotalLines - maxLines); 140 mScroll = offset; 141 } 142 143 if (style == Style.Chat) { 144 offset = Mathf.Max(0, mTotalLines - maxLines - offset); 145 } 146 147 StringBuilder final = new StringBuilder(); 148 149 for (int i = 0, imax = mParagraphs.Count; i < imax; ++i) { 150 Paragraph p = mParagraphs[i]; 151 152 for (int b = 0, bmax = p.lines.Length; b < bmax; ++b) { 153 string s = p.lines[b]; 154 155 if (offset > 0) { 156 --offset; 157 } else { 158 if (final.Length > 0) final.Append("\n"); 159 final.Append(s); 160 ++lines; 161 if (lines >= maxLines) break; 162 } 163 }//end for(b) 164 if (lines >= maxLines) break; 165 }//end for(i) 166 textLabel.text = final.ToString(); 167 } 168 } 169 } 170 171 /// <summary> 172 /// Allow scrolling of the text list. 173 /// </summary> 174 public UIScrollBar verticalScrollBar; 175 176 /// <summary> 177 /// just showed while the msgs more than one page. 178 /// </summary> 179 public GameObject downBtnGo; 180 /// <summary> 181 /// just showed while the msgs more than one page. 182 /// </summary> 183 public GameObject upBtnGo; 184 185 /// <summary> 186 /// the screen is locked or not. 187 /// </summary> 188 private bool isScreenLocked = false; 189 190 /// <summary> 191 /// while the user don't wanna scroll the screen. 192 /// </summary> 193 /// <param name="sender"></param> 194 public void lockScreenBtnClick(GameObject sender) { 195 isScreenLocked = !isScreenLocked; 196 if (isScreenLocked) { 197 verticalScrollBar.enabled = false; 198 foreach (BoxCollider bc in verticalScrollBar.GetComponentsInChildren<BoxCollider>()) 199 bc.enabled = false; 200 downBtnGo.GetComponent<UIButton>().isEnabled = false; 201 upBtnGo.GetComponent<UIButton>().isEnabled = false; 202 } else { 203 verticalScrollBar.enabled = true; 204 foreach (BoxCollider bc in verticalScrollBar.GetComponentsInChildren<BoxCollider>()) 205 bc.enabled = true; 206 downBtnGo.GetComponent<UIButton>().isEnabled = true; 207 upBtnGo.GetComponent<UIButton>().isEnabled = true; 208 } 209 }//end lockScreenBtnClick() 210 211 void OnScroll(float val) { 212 if (isScreenLocked) return; 213 else { 214 if (mSelected && supportScrollWheel) { 215 val *= (style == Style.Chat) ? 10f : -10f; 216 mScroll = Mathf.Max(0f, mScroll + val); 217 UpdateVisibleText(); 218 219 isNotOnScroll = false; 220 221 //add by ljj. 222 //Debug.Log("scroll value on text list: " + mScroll + "total lines: " + mTotalLines + " max lines: " + maxLines); 223 if (null != verticalScrollBar && mTotalLines > maxLines) { 224 verticalScrollBar.scrollValue = (1 - (mScroll) / (mTotalLines - maxLines)); 225 } 226 } 227 }//end else. 228 } 229 230 /// <summary> 231 /// the left-down position where the textlist located. 232 /// </summary> 233 public Vector2 leftDownPosi = new Vector2(0, 60); 234 235 /// <summary> 236 /// This script may use at everywhere, but not everyone need get one name from the list. 237 /// </summary> 238 public bool isNeedGetName = false; 239 240 /// <summary> 241 /// this is the context menu after the user select one name. 242 /// </summary> 243 public GameObject contextMenuGo; 244 245 /// <summary> 246 /// while the user press the text, get one name from the label, 247 /// popup function box, like add friends or add to black list. 248 /// </summary> 249 void OnClick() { 250 return; //does not supported by the server from now on. 2014-3-19 16:54:57 251 /* 252 if (!isNeedGetName) return; 253 254 Debug.Log("world list on click"); 255 256 int crtClkNameIndex = maxLines - 257 ((int)((UICamera.lastTouchPosition.y - leftDownPosi.y) / (textLabel.cachedTransform.localScale.y * 1.375f))); 258 259 string[] eachLines = textLabel.text.Split('\n'); 260 261 if (crtClkNameIndex >= eachLines.Length) { //clicked the blank area 262 contextMenuGo.SetActive(false); 263 return; 264 } 265 266 string otherPlayerName; 267 try { 268 otherPlayerName = (eachLines[crtClkNameIndex].Split(']')[1]).Split('说')[0].Trim(); 269 } catch { 270 otherPlayerName = ""; 271 } 272 273 if (!string.IsNullOrEmpty(otherPlayerName) && "你" != otherPlayerName && "您" != otherPlayerName) { 274 contextMenuGo.SetActive(true); 275 contextMenuGo.transform.FindChild("otherNameLabel").GetComponent<UILabel>().text = otherPlayerName; 276 }//end if. 277 else { 278 contextMenuGo.SetActive(false); 279 } 280 281 Debug.Log(otherPlayerName);*/ 282 }//end OnClick() 283 284 /// <summary> 285 /// to keep drag is safe. means while the user is scrolling. he can't drag the scrollBar. 286 /// </summary> 287 private bool isNotOnScroll = true; 288 /// <summary> 289 /// while the user drag the scrollBar, update the text list. add by ljj. 290 /// </summary> 291 /// <param name="sb"></param> 292 void OnVerticalBar(UIScrollBar sb) { 293 if (isScreenLocked) return; 294 295 float y = (verticalScrollBar != null) ? verticalScrollBar.scrollValue : 0f; 296 //Debug.Log("scroll value: " + y); 297 //Debug.Log("scroll value on text list: " + mScroll + "total lines: " + mTotalLines + " max lines: " + maxLines); 298 299 if (isNotOnScroll) { 300 mScroll = (mTotalLines - maxLines) * (1 - y); 301 //Debug.Log("mScroll: " + mScroll + " max lines: " + maxLines + " scroll value: " + y); 302 UpdateVisibleText(); 303 } 304 } 305 306 /// <summary> 307 /// for the down btn which while pressed will take the text to down for one line. add by ljj. 308 /// </summary> 309 /// <param name="sender"></param> 310 public void downBtnClick(GameObject sender) { 311 Debug.Log("down btn"); 312 if (mScroll > 0) 313 --mScroll; 314 315 isNotOnScroll = false; 316 if (null != verticalScrollBar && mTotalLines > maxLines) { 317 verticalScrollBar.scrollValue = (1 - (mScroll / (mTotalLines - maxLines))); 318 } 319 UpdateVisibleText(); 320 isNotOnScroll = true; 321 }//end downBtnClick() 322 323 /// <summary> 324 /// while the user press the up btn, move the text to up for one line. 325 /// similar with the downBtnClick(). add by ljj. 326 /// </summary> 327 /// <param name="sender"></param> 328 public void upBtnClick(GameObject sender) { 329 Debug.Log("up btn"); 330 //Debug.Log("mScroll: " + mScroll + " max lines: " + maxLines + " scroll value: " + verticalScrollBar.scrollValue); 331 if (mScroll < mTotalLines - maxLines) 332 ++mScroll; 333 334 isNotOnScroll = false; 335 if (null != verticalScrollBar && mTotalLines > maxLines) { 336 verticalScrollBar.scrollValue = (1 - (mScroll / (mTotalLines - maxLines))); 337 } 338 UpdateVisibleText(); 339 isNotOnScroll = true; 340 }//end upBtnClick() 341 342 /// <summary> 343 /// while the user wanna see the next page's text, he will press this btn. add by ljj. 344 /// </summary> 345 /// <param name="sender"></param> 346 public void downPageBtnClick(GameObject sender) { 347 Debug.Log("down page btn"); 348 if (mScroll > maxLines) { 349 mScroll -= maxLines; 350 } else { 351 mScroll = 0; 352 } 353 354 isNotOnScroll = false; 355 if (null != verticalScrollBar && mTotalLines > maxLines) { 356 verticalScrollBar.scrollValue = (1 - (mScroll) / (mTotalLines - maxLines)); 357 } 358 UpdateVisibleText(); 359 isNotOnScroll = true; 360 }//end downPageBtnClick() 361 362 /// <summary> 363 /// the previous page. add by ljj. 364 /// </summary> 365 /// <param name="sender"></param> 366 public void upPageBtnClick(GameObject sender) { 367 Debug.Log("up page btn"); 368 if (mScroll < mTotalLines - maxLines - maxLines) { 369 mScroll += maxLines; 370 } else { 371 mScroll = mTotalLines - maxLines; 372 } 373 374 isNotOnScroll = false; 375 if (null != verticalScrollBar && mTotalLines > maxLines) { 376 verticalScrollBar.scrollValue = (1 - (mScroll) / (mTotalLines - maxLines)); 377 } 378 UpdateVisibleText(); 379 isNotOnScroll = true; 380 }//end upPageBtnClick() 381 }
第一个正式且将上线供客户使用
值得提提的是,在接手做这个事情的时候,在对人做事上犯了一个错误。这个东东本来之前是公司另外一哥们儿做的,一个月了,中间他又家里有事儿请了几天假。老大就把这个东东给我弄了,然后我全部重新做,用了一周时间把这个(界面显示部分,此时还未连服务器)给弄完了。没过几天他就撤了。感觉甚是对他不起。
夭折的斗地主服务器
算下来,这个也折腾了一个月吧!因为当时的我对Linux一点不了解,只会在windows上使用C++写点控制台程序。于是在那里使劲的研究IOCP,研究来研究去,倒是对服务器有了一些基本认识,多线程、线程池、共享数据、框架;对Linux有了一丢丢的认识。
现在想想,没做成的主要有这几个方面(不组合,从多种情况考虑)原因:
1、大方向没有选择正确,应该选择Linux下的C++框架or Java框架(公司服务器就是用的这个)。
2、使用C++的话,没人带,基本方向只是我自己在撞。应该多问问周围人的,比如总监,比如老大,比如服务器主程。
然后,这也只是在学校的那种学习模式,学了不用!
项目的中心——主要场景MS
MS是在我来之前外包出去的,外包需要做的东西完了之后,由我接手。回来之后由于需求变更、bug调整,直到项目上线,除了基本的背景没变之外,其他地方都被改变了。
后面加的东西,大致罗列一下:新手教学、进程间通信(socket)、活动抽奖等其他很多内容。
整个做下来,倒是对NGUI挺熟悉了,不过3D方面的内容了解的就不会太多。
登录器
使用VS2010的MFC搞定。其实算算呢,只是在网上copy了几个例子,然后把他们结合在一起形成了最后这个东西。对整个MFC的认识不会太深刻,倒是有时候会沾沾自喜——我也能用MFC做(拼)东西。
警醒自己:如果要快且好的做东西,还是需要知道底层是如何实现和制作的。
DEBUGING
这个阶段主要和公司的功能测试两个合作,主要的模式:我把产品交过去,她找问题,直接反馈给我,如果是我这里的问题我就直接改掉,或者请(在这里似乎快达到协调高度了)另外客户端程序改掉。
觉得这个阶段里面有很多地方值得改进下。可能需要我做过更多项目的时候才能总结出来点东西。
内测、公测
其时我们公司只有一个搞运营的,在上线的前几天,往往我们一大堆客户端研发去做客服和技术支持,整体感觉是有点乱,但似乎我倒是比较喜欢这种感觉,因为给别人讲解别人自己做的东西如何用,还是有那么点(真的只有一丢丢)傲娇的感觉。
这个阶段因为对MFC开发的不了解,拼出来之后,给客户用的时候,便出问题了。出现的最大的问题就是登录器的兼容问题、安全问题。
因为是使用的VS2010开发,所以经常客户电脑上出现“找不到MFCxxxx.dll”这个错误。现在想起来,当时老大确实是不容易的,给我们挡了许多事情。这个问题也找了许久,但是一直没有找出个所以然来,如果有大神知道的话,还望指点。PS:我们最后的解决方式,1、让安装登录器之前直接装一遍vcredist2010_x86.exe这个,但是很多时候会被360阻止;2、以绿色版的形式给用户,出现问题,提示用户先安装vcredist2010_x86.exe,所以这个问题就跑到客服那里去了。
有许多需要改进的地方哩!
综述:
想想看,在项目公测一个月之后的离开是不对的。当时没理解到老大说的“一个事情是需要做完的”的意思!在此抱歉!
我还是太年轻,没想清楚自己真正想要的是什么!很严重的一个问题。
最后,附上产品网站地址哈!虽然在很多地方的优化做的还不够好,但是真的可以用的,真的可以中奖的哦!