• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            白云哥

            身披半件長工衣,懷揣一顆地主心

             

            2010年8月12日

            C++中遍歷容器對象時需要注意的問題

            假設有這樣一個管理對象的窗口 ActorManager,其實現大概為

            class Actor;
            class ActorManager
            {
            public:
            void update()
            {
            for (actors_t::const_iterator itr = m_actors.begin(); itr != m_actors.end(); ++itr)
            {
            Actir* actor = itr->second;
            actor->update();
            }
            }

            void add(Actor* actor)
            {
            m_actors[actor->get_id()] = actor;
            }

            void remove(Actor* actor)
            {
            m_actors.erase(actor->get_id());
            }

            private:
            typedef std::map<int, Actor*> actors_t;
            actors_t m_actors;
            };

             

            而Actor類的實現是這樣:

            class Actor
            {
            public:
            void update()
            {
            // ...

            }

            有一天,在給Actor添加邏輯的時候,update函數變成了這樣

            void update()
            {
            // ...

            update_buff_effect();

            // ...
            }

             

            再往下

             

            class Actor
            {
            // ...

            private:
            void update_buff_effect()
            {
            // ...

            apply_hp(-100);
            if (get_hp() <= 0)
            {
            die();
            return;
            }

            // ...
            }

             

            然后……

             

            private:
            void die()
            {
            // ...

            ActorManager::getInstance().remove(this);

            // ...
            }
            在寫下ActorManager的時候并沒有想到會在update循環里刪除對象,而實際上卻有幾次遇到類似的問題。
            有些問題沒有這么明顯,但也都是出在遍歷容器對象的過程中,某個執行函數刪除了窗口里的對象,從而導致迭代器失效。
             
            修改的方法很簡單,給ActorManager添加一個待刪除對象列表
            在remove方法中并不真正刪除對象,而是等到update中循環結束后再刪除對象。
            代碼看起來會是這樣:
            class Actor;
            class ActorManager
            {
            public:
            void update()
            {
            m_is_looping = true;
            for (actors_t::const_iterator itr = m_actors.begin(); itr != m_actors.end(); ++itr)
            {
            Actir* actor = itr->second;
            actor->update();
            }
            m_is_looping = false;

            if (!m_removed_actors.empty())
            {
            for (removed_actors_t::const_iterator itr = m_removed_actors.begin();
            itr != m_removed_actors.end(); ++itr)
            {
            Actor* actor = *itr;
            m_actors.erase(actor->get_id());
            }
            m_removed_actors.clear();
            }
            }

            void add(Actor* actor)
            {
            m_actors[actor->get_id()] = actor;
            }

            void remove(Actor* actor)
            {
            if (!m_is_looping)
            m_actors.erase(actor->get_id());
            else
            m_removed_actors.push_back(actor);
            }

            private:
            typedef std::map<int, Actor*> actors_t;
            actors_t m_actors;

            typedef std::vector<Actor*> removed_actors_t;
            removed_actors_t m_removed_actors;
            bool m_is_looping;
            };

             

            沒有給add也加保護的原因是,不會在update函數內向ActorManager添加新對象。

            當然,有可能在其他地方會有這樣的需求,同樣也做類似的保護即可。

             

             

            問題雖然不大,但是幾次碰到類似的錯誤了。記錄之,并強制要求自己,

            在遇到會對容器內的對象做for…處理時,一定要謹慎的檢查一下remove接口。

            posted @ 2010-08-12 23:02 白云哥 閱讀(2982) | 評論 (15)編輯 收藏

            2010年8月8日

            SmartFoxServer項目完成總結

             

                總體來說,如果是想做一個比較簡單的虛擬現實服務,拿sfs來做還是很方便的,省去了前期構造服務器網絡,實現數據庫接口,數據同步等等一些基礎功能的時間,可以一上來就直奔主題,開發自己項目相關的功能.

             

                Sfs的接口封裝也比較簡單,基本上看到接口名就能知道是做什么用的,參數是什么意義,而且他的文檔也比較詳細,對于非服務器開發專業人員也比較方便.sfs的定義也主要在此,比如他最早支持的flash客戶端api.

             

                而隨著sfs的成功,也開始將目標轉向了目前新興的iphone, android, sillverlight, unity等 客戶端.這次使用c# client api做了一個winform測試程序,使用起來也是非常的方便.

             

             

                第一次拿sfs做商業項目,也還是遇到了一些問題,總結一下,另外還有一些未完善的地方,后面再花時間繼續實現.

             

             

                CustomLogin的處理在zone extension里,必須先join room才能使用xt message.所以需要先寫一個zone extension,在這里處理登錄驗證,注意驗證成功后需要向客戶端發送room list, 客戶端必須收到room list消息才能做后面的操作,這是sfs限制死了的.

             

            本來我想在extension里讓客戶端驗證成功后直接join room,未果,調試良久才發現,客戶端未收到room list,不能join room.

             

             

                Sfs的user variables只支持bool, integer, string類型,其他類型的數據不能同步.這個問題困擾了我差不多一個小時,最后在客戶端一步步跟蹤屬性同步過程時才發現,其他類型的variable都被忽略掉了.

             

                于是,為了同步float坐標數據,我不得不加上了float.toString(),數據量又大了不少.

             

             

                Sfs消息定義的方式,不要像sample里那樣,直接寫字符串名字,改用枚舉或者常量定義.每個extension name和command name都只有一個字節,在枚舉中也可以定義出128個,完全夠用.

             

                這樣可以省不少帶寬占用量,可以在client上開啟debug message開關,看一下一個簡單的消息發送會占多少字節.

             

             

                如果想同時在eclipse和netbeans下對一個項目進行開發,注意文件編碼的問題.eclipse下創建的文件默認編碼為gbk,netbeans下創建的文件默認為utf-8,而在eclipse下導入文件時他并不會自動檢測文件的編碼,所以,你需要在文件的屬性里手動設置一下編碼方式.另外,netbeans下要在文件中顯示中文字符只能使用utf-8,使用gbk會出亂碼,如果出現此類錯誤,修改一下文件編碼方式以及指定新的編碼即可.

             

             

                要關于利用IDE編譯環境.在項目最開始的一周里,我使用trace來進行調試,一次次的通過trace打印出中間變量,然后再修改代碼,再啟動服務器,再看trace信息……在我快要陷入崩潰絕望之時,終于,決定建一個好用的集成調試環境.在嘗試eclipse失敗后,我成功的在netbeans中打下了斷點,單kh步跟蹤,于是,整個世界變得清靜多了……

             

                關于如何在netbeans中調試extension,可以參考我之前的一篇文章

             

             

                sfs中服務器與客戶關通信的協議有三種:xml,json和raw string,使用json會比xml節省不少字節,但其仍然占用比較大的帶寬開銷.如果是數據交互量比較小的應用,這個問題不會太大,但對于即時戰斗類MMO來說,可能會成為一個比較大的問題.嘗試了一下使用raw string的方式傳遞結構體,但是沒找到比較好的方法,以后有機會再繼續,如果可能的話,結合google proto buffer和raw string方式,將會是一個比較好的方案.

             

             

                在處理extension message時,按照示例所提供的方法,先取出cmd,然后使用equal的方式一個個進行比較,然后轉到對應的處理函數.對于消息種類比較小的應用來說還沒發現問題,但是對于有大量自定義消息的應用,這里就需要修改一下了.

             

             

                Sfs的db extension目前看起來只能在當前線程中處理,并且是阻塞式的,暫時沒有嘗試使用多個線程操作數據庫,也沒有把數據庫操作改為異步操作.這也是未來需要進一步改進的地方.

             

             

                暫時不清楚SFS是否會為每個room開啟一個單獨的線程,或者是每個extension一個線程.如果zone里房間數比較多的話,分多個線程處理也是需要的,未來也需要繼續考慮一下多線程的問題.

             

             

                Sfs的實現是把一個room當成了一個廣播單元,這對于開房間類的游戲來說沒有問題,但是如果相用它來做MMO就需要注意一下,因為user variables的同步是以整個room為單位的,也就是當一個房間里人數達到幾百人甚至幾千人的時候,某個玩家的進入和退出房間消息,屬性修改消息的廣播量都會是巨大的.但是在沒有源碼的情況下想要修改這個不大容易,也就是限制了sfs的應用環境.

            posted @ 2010-08-08 14:16 白云哥 閱讀(10307) | 評論 (0)編輯 收藏

            2010年8月7日

            Framework Design Guidelines讀書筆記

            這本書雖然是講述.net框架設計的一些規范,不過仍然有一些通用的設計準則可以參考

             

            命名規范:

            這些只有在用于公開暴露給外界的API時才是必需的

             

            標識符大小寫規則:

            1.要把PascalCasing用于由多個單詞構成的名字空間,類型以及成員的名字

            2.要把camelCasing用于參數的名字

            3.不要把閉合形式的復合詞中每個單詞的首字母大寫,比如 callback, endpoint 等等,可以查閱英語詞典來確定復合詞是不是閉合的

            4.不要使用匈牙利命名法。原因有幾點,一是發明它的ms公司都已經明確要求在新的庫在不要使用這種命名法,二是變量名前加類型標識符是個很不好的習慣,在開發過程中有可能會隨時修改這些變量的類型定義,三是新的編輯器中不需要用m_前綴來確定其類型,不過對于內部實現的變量來說,用一個前綴也許會讓變量的查找更方便,比如用一個_前綴

            5.不要使用未被廣泛接受的首字母縮寫詞,如何確定某個縮寫詞是否眾所周知有個好方法,到google上搜索一下,如果前幾條都是你所期望的內容,那么它就是眾所周知的了

             

            關于命名:

            1.要用名詞或名詞短語來給類和結構體命名,使用PascalCasing的大小寫風格,類名字不要加 C,但是接口前需要加 I,這是個特例

            2.用形容詞短語來給接口命名,在少數情況下也可以使用名詞或名詞短語

            3.考慮在派生類的末尾使用基類的名字,比如 class FileStream : public Stream

            4.用動詞或動詞短語來命名方法,比如 int CompareTo();

            5.要用肯定性的短語(CanSeek而不是CantSeek)來命名布爾屬性,可以加Is,Can,Has等前綴,要確保使用時的測試語句讀起來通順,比如

            if (collection.Contains(item)) 就比 if (collection.IsContained(item)) 要通順得多

            此外,要優先選擇主動語態而不是被動語態,比如

            if (stream.CanSeek()) 就比 if (steam.IsSeekable()) 要強得多

            6.要用現在時和過去時來賦予事件名以之前和之后的概念,不要用Before或After這樣的前后綴,比如 Closing, Closed而不是AfterClose

             

            使用規范:

            1.優先使用集合,避免使用數組

            2.考慮使用不規則數組,而不要使用多維數組,也就是優先使用int [][] jagedArray這樣的數組,避免使用 int [,] multiDimArray這樣的類型

            3.要用最泛的類型來作為參數類型,大多數以集合為參數的成員都使用IEnumerable<T> 接口

            posted @ 2010-08-07 00:19 白云哥 閱讀(346) | 評論 (0)編輯 收藏

            2010年8月6日

            讓Bada的GlesCube11 Sample跑起來

                困擾了兩天的問題終于解決,原因只是我的顯卡驅動太老,安裝最新的驅動就一切OK了,汗

             

             

                如果你也遇到了同樣的問題,不防也試試最新的顯卡驅動,也許可以省下兩天的郁悶時間 微笑

             

                一個是在InitEGL中調用eglMakeCurrent時,會報告EGL_DEVICE_LOST錯誤,我嘗試著將這個消息忽略掉之后沒有任何問題 微笑

                另一個是在Draw中調用glGetIntegerv(GL_VIEWPORT, (GLint*)&viewPort);時返回的viewPort值是個錯誤值,我又嘗試著為viewPort直接再賦一次值,{0,0,480,800},又OK了 微笑

             

                不過這只是部分OK,Sample跑起來后我只能看到變化的背景色,cube們哪去了?

             

                翻遍了bada的forum也沒有遇到同樣的問題,只是看到幾個同樣說EGL_DEVICE_LOST錯誤的,也同樣沒有找到解決方法

             

                忽然間,我想會不會跟顯卡有關,我這新裝的win7系統還沒有裝過顯卡驅動,用的是自帶的。于是,下載,安裝,再打開bada IDE,于是,這個困擾了我兩天的問題就這么神奇般的消失了……

             

                最后,貼張運行效果圖以示紀念,雖然只是Sample的效果圖,沒有我的半行代碼,不過這也困擾了我兩天,不是么 悲傷

             

            bg

            posted @ 2010-08-06 21:30 白云哥 閱讀(345) | 評論 (0)編輯 收藏

            2010年7月22日

            使用NetBeans調試SmartFoxServer的Extension

            結束了兩個星期的用trace進行SmartFoxserver Extension調試的痛苦歷史之后,我決定再來嘗試一下怎么在IED環境下進行遠程調試。

            上一次打算在Eclipse下進行,不知道哪一個環節出錯,沒能成功,這次改用NetBeans吧,正好趕上NetBeans新版本發布,來試用一次。

             

            按照這里描述的方法,很快把Eclipse下創建的工程導入到了NetBeans下,不過遇到了點小問題,一堆的亂碼。檢查了下發現,Eclipse下創建的文件編碼為ANSI,在NetBeans下不識別其中的中文注釋,把文件改成UTF-8后問題解決,可后來我再試圖在Eclipse下打開這些文件時問題又出現了,Eclipse只識別ANSI編碼的文件?似乎不大可能吧,不過一時也沒找到解決方法,暫時放棄,改用NetBeans吧。

             

            按照論壇上的方法做就行,不過可能因為版本更新的原因,實際做的時候還是有點差別

             

            Step 1
            Download the
            Netbeans IDE for java development. (47mb SE version should be fine!)

            這一步就是這樣了


            Step 2
            Install and open Netbeans. Create a project from existing java source pointing to where your extensions are. Should be placed in src subfolder to be nice.
            (I for sure could not make it work if the source was not in a subfolder)
            Right click on project and choose properties->libraries. Add all jar files from your smartfox installation lib dir.

            在NetBeans下導入原來Eclipse創建的文件,只需要src目錄即可

            導入libraries時注意,按照這里的方法,只需要導入3個jar文件,就是這樣

            nb5


            Step 3
            Goto Files tab. Expand nbbuild.xml. Click on -post-compile target.
            Copy and paste the following code: (Note: adjust todir to point to your smartfox program extension directory)
            <copy todir="C:\Programmer\SmartFoxServerPRO_1.6.6\Server\javaExtensions">
            <fileset dir="${build.dir}/classes/"/>
            </copy>

            我的NetBeans下沒有nbbuild.xml,倒是有一個build.xml,不過里面沒內容 悲傷

            再看了下,原來引用的build-impl.xml,上面有個簡單的介紹,在build.xml里添加如下內容即可:

            <target name="-post-compile">
                    <copy todir="D:\SmartFoxServer\Server\javaExtensions">
                        <fileset dir="${build.dir}/classes/"/>
                    </copy>
            </target>

            根據你的SmartFoxServer安裝目錄進行修改即可


            Step 4
            Create a new batchfile called SmartFoxDebug?.bat
            Copy and paste the following content into it: (Again adjust to your installation directory)
            C:\Programmer\SmartFoxServerPRO_1.6.6\Server\wrapper.exe -c "C:\Programmer\SmartFoxServerPRO_1.6.6\Server\conf\wrapper.conf"

            這一步不需要,在我安裝的目錄下直接有個smarfoxService.bat批處理文件,用它就行了


            Step 5
            Add the following lines to your wrapper.conf

            Code:

            # runtimedebug
            wrapper.java.additional.3=-Xdebug
            wrapper.java.additional.4=-Xnoagent
            wrapper.java.additional.5=-Xrunjdwp:transport=dt_socket,address=8888,server=y,suspend=n

            這里的意思是要在SmartFoxServer里開戶遠程調試的監聽,在我安裝的SFS版本里原來比這多了一項配置,所以最終是這樣的:

            # Java Additional Parameters
            wrapper.java.additional.1=-server
            wrapper.java.additional.2=-Dfile.encoding=UTF-8
            wrapper.java.additional.3=-Djava.util.logging.config.file=logging.properties
            wrapper.java.additional.4=-Xdebug
            wrapper.java.additional.5=-Xnoagent
            wrapper.java.additional.6=-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n

             

            Step 6
            Choose Run->Build main project (F11) in Netbeans.
            If build is ok, click the batch file. Now select debug->attach debugger and choose port 8888. Debugger console should say "User program running".
            Now you can place breakpoints and trigger your extensions normally.

            這里就是最終我們要實現的效果了,掛接SmartFoxServer的遠程JVM進行調試,配置項在 調試(D) 下的 連接調試器(A) ,如果你跟我一樣安裝的是中文版NetBeans的話 微笑

            貼張圖,就是這樣,注意端口號,是上面配置的那個,不是SFS對客戶端連接的監聽商品號9393哦

            config

             

             

            好了,先啟動SFS,用上面說的那個批處理文件,你會看到一行提示信息,JVM遠程調試的監聽已打開

            然后連接調試器

            在NetBeans里打個斷點看看,O了



            posted @ 2010-07-22 08:12 白云哥 閱讀(1997) | 評論 (0)編輯 收藏

            2010年7月21日

            Android的無邊界程序設計理念

                無邊界程序設計理念這個提法來自于這里

                “Android的應用只是一個虛的概念,并沒有實際的入口,這個不像Window平臺上的應用程序的概念,Android更多的是提供組件(Components)的概念。突出請求和服務,突出組件個體,弱化邊界,系統的各個組件可以自由的無邊界的交流,服務請求者直接發出請求,不論這個對象在何處和屬于誰的,組件是自由獨立的個體,一個應用程序可以直接請求使用其他的應用的的組件,這個是Android應用框架設計的核心理念,其他的一切都是在為這個核心理念服務。”

                “讓程序員忽略應用的概念,甚至徹底的拋棄進程這樣的概念,程序員看到的就是一個一個的組件,應用程序員利用這些組件來架構成一個所謂的應用,那么設計者首先要考慮的是什么呢?我想應該是一個抽象的應用模型,在這個模型下產生概念和接口。”

                “Android中你可以開始一個Activity,但是沒有權利消滅一個Activity,這是個體權利的體現,個體的消滅是由系統決定的,這個就是Android中Activity蘊含的人文意義。”

             

                這段總結說的非常好,從我近期對Android開發的一些基本了解來看,也確實是這樣。在Android平臺下開發,你不需要從頭開始構建一個應用,你可以使用系統提供好的一些功能,或者是別人的應用程序中已實現的部分功能,拿來組裝自己的應用,當然,你做好的應用也可以把部分功能暴露給別人來使用。具體說來,就是Activity與Intent的使用。

             

                基于這樣一種模式,Android開發更像是堆積木,當然,這是理想狀態下的。Google最近不是就推出了一款通過web上的組件拖拽就能生成一個自定義的應用程序的工具么,當然,我只看了下介紹,還沒有機會親自體驗,不過,這終將是未來的趨勢。

                當然,這對于開發人員來說是好事,你可以更加快速的把自己的想法變成現實,你不用親力親為的去做每一件細小的事情。

                對于手機使用者來說,這同樣是好事。使用統一的Activity構建出來的應用,不論是外觀還是使用方式上都是完全統一的,用戶拿到一個新應用時基本上不會有太大的使用方面的成本。

                而對于Google來說,這當然也是好事。Google可以把他的云計算服務都做成一個個的組件,應用開發者們可以隨意組合上自己的應用中,這對于Google推廣自己的服務將會是一件非常有益的事。

             

                當然,目前來說,組件的提供還并不算完美,現在來開發一個應用,還是需要自己做很多工作,僅有少部分服務可以直接調用Google提供的Intent,而調用別人的Activity很難得到保證,比如對別人的應用的依賴,比如接口的保證,等等。另外,目前各手機廠商在定制Android時都提供了自己的UI sence,而各家也都不一樣,再加上Android原生的,這也使得UI的統一越發的難,不知道未來將會如何處理。

            posted @ 2010-07-21 08:27 白云哥 閱讀(1757) | 評論 (1)編輯 收藏

            2010年6月29日

            移動互聯網的明天

                明天一定是屬于移動互聯網的,這點已越來越不容否定。

                在移動互聯網到來的時候,能夠做點什么呢?一點不成熟的想法,簡單記錄之。

                門戶,讓每個用移動終端設備的人,不論是iphone,android這樣的智能手機,還是ipad,平板,抑或是WebOS,Google,MeGoo的上網本,他們打開設備后第一個運行的軟件,門戶軟件。

                從這里,他們可以使用移動互聯網的絕大多數服務,比如說,查找本地信息,瀏覽感興趣的新聞和博客,看看好友們的最新動向,等等。他們不需要打開瀏覽器,不需要記住一個個煩人的網址,也不需要在Google或是Baidu輸入一些精挑細選的關鍵字,他們所要做的僅僅只是打開這個門戶軟件,然后,一切盡在眼前,而且,你使用這個軟件的次數越多,他越能了解你的脾性,越來越能猜到你想干什么。

                UCWeb在這方面已經先走了很大一步。現在的ucweb已不再只是一個單一的瀏覽器,打開UC,你已能如我前面描述的那樣,完成大部分想做的事,包括新聞聚合,包括博客訂閱,包括生活信息查詢,當然也包括QQ,MSN等聊天工具的整合以及校內,開心網等入口。

                基于地理位置的信息提供,可以與娛樂相結合,做成一個集社交、生活于一身的休閑應用,你可以在這里找到你感興趣的一些信息,而且,是根據真實位置過濾好的,也就是說,你看到的絕大多數信息都會是你感興趣的。

                在機鋒上,找到一個叫幫飄信的軟件,有那么一點意思。

                還有,完全娛樂化的社區平臺,可以利益于移動互聯網的優異特性,隨時隨地都可以接入,不用花太多時間,與認識的不認識的朋友有那么一點交互,比如在地鐵上,臨睡前,辦公室開小差的時候,都可以。內容簡單但不失樂趣的娛樂小應用。

                人人網,開心網,白社會,Facebook,或者是摩爾莊園,浪漫莊園,再或者是各類三國web game,其實,這些本身都可以從智能終端設備接入,當然,除了iphone以外。不過,這些專為pc設計的娛樂平臺到了手機上還是會有些問題,包括視覺效果的問題,交互性的問題。我覺得,做一個專為移動終端平臺設計的摩爾莊園,嗯,挺有點意思。

            posted @ 2010-06-29 22:11 白云哥 閱讀(321) | 評論 (0)編輯 收藏

            2010年6月22日

            Android Tab Layout (TabHost) Tutorial的Force Close錯誤

                想搗騰一下Android開發,結果第一個問題就糾纏了好久。

                關于TabHost的大多數例子里都是把所有的Tab頁設置到了同一個Activity,而實際制作中我們希望為每個Tab頁使用一個不同的xml布局,正好Android Tutorials中有一個Tab Layout的例子,可是Google的人漏掉了很重要的一個步驟。

                例子在android-sdk目錄下 docs/resources/tutorials/views/hello-tabwidget.html

             

                按照Tutorial做完后,始終無法正確運行,嘗試著不斷修改,當把TabContent指定為xml中配置的view時就不會有問題,但我希望每個Tab頁是一個單獨的單元,有自己的xml布局,有自己的Activity類實現。終于,在繼續求助于Google之后找到了問題所在:需要為每個自己定義的Activity到AndroidManifest.xml中聲明一下,具體就是這樣:

            <activity android:name=".ArtistsActivity"></activity>
            <activity android:name=".AlbumsActivity"></activity>
            <activity android:name=".SongsActivity"></activity>

                上面的name是自己聲明的Android類名,做相應的修改即可。

             

             

                這里有一個詳細的說明:

            http://stackoverflow.com/questions/2209406/issues-with-android-tabhost-example

                Google Code上也有人貼出了這個issue,并且有解決方法:

            http://code.google.com/p/android/issues/detail?id=4183

             

              也許你也遇到了這個同樣的問題,希望能少走點彎路 :)

            posted @ 2010-06-22 08:06 白云哥 閱讀(2396) | 評論 (2)編輯 收藏

            2010年4月21日

            DOOM啟世錄的啟示

            “游戲分兩種,一種是生活中玩的,另一種是生活在其中的”這是DOOM啟世錄的第一句話。

             

            “約翰。羅梅洛,王牌程序員”羅梅洛的第一個稱號,雖然是他自封的,但絕不過譽。當然,在他遇上卡馬克后他也會變得謙虛起來。

            卡馬克,一個進過少管所,也呆過天才班的神奇小子兼只上過兩個學期大學的火箭科學家。

             

            天才程序員:

            羅梅洛在他還是孩子時,就給自己的公司取好了名字:頂級思想軟件 Capital Ideas。雷恩,另外一個聽著重金屬,看著地下漫畫,玩著游戲長大的叛逆程序員,一樣有他的公司,不過與羅梅洛一樣,也是公司里的光桿司令,他的公司叫藍山科技 Blue Mountain。

            當他們倆相遇的時候,兩個光桿司令合并成了一家新公司:深思軟件 Ideas from the Deep,也就是ID的前身。

             

            羅梅洛,卡馬克,雷恩,這三個程序員在軟盤雜志社相遇的那一天,也同樣開始了PC游戲史上的一段傳奇歷史。很快,王牌程序員就領教了天才小子的厲害。天才小子也欣賞王牌程序員身上的藝術氣質,還有他的設計創意。 

            湯姆,二十五歲的程序員,與羅梅洛一樣,也是個喜劇演員,同時也是一個優秀的游戲設計師,還是一個不錯的超現實主義漫畫家。

            艾德里安,一個黑色主題藝術家,他其實只想在軟盤雜志社做個兼職美術師,賺著比其他地方稍多點的薪水,直到他遇到了羅梅洛跟卡馬克。

            機會永遠只會留給有所準備的人,這話一點不假。

            翻一翻他們的履歷,也就不會憎惡上帝太過于眷顧這群小伙子。

             

            走出第一步:

            在那個晚上,湯姆與卡馬克山寨了超級馬里奧,卡馬克的天才技術讓另外兩位程序員不得不嘆服。

            “羅梅洛被這突如其來的驚喜驚呆了,他動彈不得,甚至站都站不起來。直到幾個小時后卡馬克回到辦公室,他才有力氣說話。他只有一件事要告訴他這個朋友,這個編程天才,這個絕配般的搭檔:

            ‘不用想了,我們走人’”

            當然,這只是羅梅洛的一句沖動話,就像他以前經常有過的那樣,不時的會沖動。

            可這一次,羅梅洛的沖動開始當真了。

            “1990年9月20號這個宿命的早晨,這個早晨對他們倆都是一個意義重要的時刻。卡馬克用他非凡的專注解決了一個迫切緊要的挑戰,羅梅洛則預見了這成果可能帶來的一切。就仿佛,卡馬克制作好調色板,然后羅梅洛用這調色板描繪出一個未來。”

            “他們已經有了一個夢幻團隊:卡馬克,天才小子和圖像領域的領頭羊;羅梅洛,游戲制作的多面手和公司的啦啦隊長;艾德里安,沉迷于黑暗主題的藝術家;湯姆,游戲設計師和超現實主義漫畫家;還有雷恩,雖然不那么令人滿意,但也還是個不錯的程序員。”

            不過沖動歸沖動,生活還要繼續。

            天才小子們的價值在還沒有被認可之前,他們也一樣要打工掙錢買盒飯。

            所以,與很多的創業團隊一樣,他們“借”用著公司的資源,做著自己的事。在那個時刻,PC機是奢侈品,想要回家自己干都是一件非常困難的事,于是,他們便在周末把公司的電腦“搬”回家去干。

            終于,指揮官基恩在他們手下誕生了。

            不過,這還只是邁出了第一步,一小步而已。這時可不能輕舉妄動。

            有句話說的好,

            公司的事再大也是小事,

            自己的事再小也是大事。

            為未來的機會作好準備,怎么去做?

            當然不是說在公司里拿著薪水卻干著自己的私事,但是,每天八小時之外的時間,有沒有好好利用起來,這也就決定了人生不同的走向。

            找對好搭檔:

            羅梅洛,卡馬克與艾德里安,可以稱作是ID的鐵三角。

            而羅梅洛與卡馬克二人又是這鐵三角里的重心所在,也是游戲合伙人搭檔的典范。

            “羅梅洛和卡馬克在性格上有個很顯著的不同,那就是他們對待時光的態度,正是這種內在秉性的差異,使他們成為最佳拍檔,也使他們無可挽回的決裂。

            卡馬克只活在當前時刻。專注,是他力量的源泉。

            羅梅洛則完全相反,他沉浸在所有時光里:過去,現在,將來。他不止是充滿激情,他還付諸行動。”

            這一靜一動的關系正好互補。

            不僅如此,卡馬克的技術與羅梅洛的創意更是天才搭檔。

            手術師約翰,被看作是地球上有史以來最牛B的程序員。

            引擎師約翰,被譽為搖滾之神,這當然不是因為他的搖滾樂。

            當卡馬克創造出了新的技術,羅梅洛總能發現這技術的應用之處,并能把他的潛力挖掘到最深。而當后來羅梅洛離開ID之后,卡馬克只能失望于他所創作出來的史上最強大的引擎,卻沒有人能來推動他。

            “盡管卡馬克從未公開表示過他懷念過去的ID,懷念羅梅洛那令人眼花繚亂的構思和設計,但卡馬克清楚地知道,現在的ID已不再是從前的ID,現在的ID已經沒有了自發的動力。”

            不過,太大的性格差異最終也會產生問題,

            “羅梅洛想要建立一個帝國,而我只想安靜的寫程序。”許多年以后,當卡馬克回憶他與羅梅洛的分離時,他這樣說道。

             

            我們所看到的,所傳誦的,永遠只是天才的故事。

            自己不是羅梅洛,當然不敢奢望能與卡馬克這樣的天才合作。

            自己也不是卡馬克,于是也找不到羅梅洛這樣的偉大設計師。

            但是,在尋找搭檔的時候,一個與自己能夠優勢互補的人會更合適。

            另外,性格上有一些差異也能讓團隊未來不至于走向一個死胡同,至于最終的決裂,這個可以進行控制。

            一定會有挫折:

            與所有充滿激情的創業團隊一樣,他們的第一次也遭遇了挫折。當他們借用公司的機器,經過幾個周末的通宵努力,把PC版的馬里奧寄給任天堂時,得到的答復卻是:小伙子們,干的不錯,但我們對PC機沒有任何興趣。

             

            沒關系,機會一定會降臨到那些有所準備的人身上。

            雖然任天堂拒絕了這幾個天才小子的熱情,但終有人能看出這群天才們的價值。

            米勒主動聯系上了羅梅洛,并向他展示了共享軟件市場的美好前景,并且給羅梅洛開出了35%的高比例分成,而且還提前為他們支付了訂金。

            把游戲按照共享軟件的模式去賣,先出一個免費的關卡,如果還想繼續玩后面的內容,那么,付錢。這種模式在現在仍然還流行著。

            由此,繼續在周末借用著公司的電腦,指揮官基恩誕生了,這是他們的第一筆收入。

            當然,在他們“借”用公司電腦的同時,他們也沒有忘了給公司做一些東西,以對得起拿的薪水,還有不引起老板的注意。也在此時,第一次出現了有人離開,雷恩,已經多次掉隊的成員,羅梅洛沒有顯示更多的寬容。

            當指揮官基恩上市以后,ID每月的收入為一萬到兩萬美元,這是在1991年,而那一年,卡馬克二十歲,羅梅洛二十三。

            最終,ID有了三位創始人:羅梅洛,卡馬克和艾德里安。

            在遇到重大選擇的時候,每個人都有自己的出發點,自己的判斷標準,應該尊重這些不同之處。雖然湯姆和杰伊一開始沒有走出來,但他們仍然是朋友,很好的朋友,每個周末仍會來ID玩玩龍與地下城。以后的日子里,他們還會走到一起。

             

            培養出默契:

            在ID正式成立后的第一個項目,德軍總部3D開發的日子里,卡馬克與羅梅洛的默契正式開始建立。

            “卡馬克不是一個多愁善感的人,他的記憶里沒有多少感情方面的東西,但他記住了這個畫面,記住了這不同尋常的一刻,以后的日子里,他愿意回想起:在一個暴雨滂沱的夜晚,羅梅洛淌過齊腰深的河水,只為了趕回來工作”

            搭檔之間的默契,正是通過這樣的小事,通過并肩作戰培養出來的。

            當然,默契也不代表任何時候都能夠統一。

            在制作德軍總部3D的過程中,ID的人第一次在游戲設計上發生了的分歧。湯姆試圖游說卡馬克給場景中添加可以縮進去的墻,而卡馬克以破壞軟件設計為由拒絕添加。當羅梅洛也試圖再次說服時,卡馬克的回應是:這件事提都不用提!

            是的,在ID這樣的夢幻團隊里,在天才程序員卡馬克那里,依然也有程序員不能做,或者不愿意做的事。程序員都是固執的,有時候帶有很明顯的偏見。

            不過,如果你能讓他自己認識到這事是應該做的,他也很樂于被你說服。最終,卡馬克在某個晚上主動做好了一個可以縮進去的墻。

             

            讓合適的人做合適的事:

            在指揮官基恩占據共享軟件排行榜首位一年之后,瑞恩來到了ID,并告訴他們,卡馬克的技術在業界是首屈一指的,公司應該有人來徹底發掘這技術的價值。最終,瑞恩成為了ID的經理。

            讓合適的人做合適的事。

            王牌程序員羅梅洛雖然是一個充滿激情的多面手,但他最在行的還是游戲業務,還是設計師,還是程序員,關于怎么打理生意,當然需要更合適的人。

            卡馬克,永遠只愛寫他的程序,永遠不在意生意那攤子爛事。

            湯姆,這時湯姆終于加入了進來,他那源源不斷的奇思妙想,使其當之無愧的成為了ID的主設計師。他也有他最重要的事要做。

            所以,找一個CEO,ID不止一次找過CEO。

            “就像所有藝術家和程序員一樣,他們不喜歡為生意上的事情煩心,他們更樂于專注于自己的領域。而且,他們越投入游戲制作,他們就越厭煩那些堆積如山的例行公事。公司需要有個新的負責人,這次,他們又主動去給自己找CEO了。他們的老朋友,杰伊,以5%的股分加入了ID。”

            理性人的思考應該是以利益最大化為目標,讓合適的人做合適的事顯然能讓利益最大化。

            當然,每一個有心做事的人,或多或少的都有一些野心,有那么一些控制欲,如何協調好這個關系,需要費點心思。

             

            每個人都是舵手:

            指揮官基恩,出自湯姆的設計,包括故事的背景,人物的形象,還有那些游戲特性。這時,卡馬克與羅梅洛忠實的做著手術師:程序員,讓湯姆的奇思妙想得以實現。

            而下一次,ID的舵手轉移到了羅梅洛身上。

            德軍總部3D,可以說是早期主視角3D游戲的最有影響力的代表作之一,這一切的靈感都來自于羅梅洛,而這天才的實現則出自卡馬克,在這個最激動人心的時刻,他們只有四個人,羅梅洛,卡馬克,湯姆和艾德里安。是的,很多名字已經成為了歷史。

            德軍總部3D的巨大成功讓ID正式獨立出來,成為一家完全獨立的工作室,自己負責從開發到發行的所有事務。但工作室成員還是那么幾位。

            到下一次,DOOM的時代,公司的重心轉到了卡馬克。

            每一個游戲制作人大概都會有一個理想中最完美的游戲,讓每個人都能實現自己的理想也許不大現實,但是,讓每個人都能充當一回舵手,帶著大家向自己指引的方向前進一段時間,這將會讓每個人都覺得自己的人生更有意義。

            但是,每個人做事的風格不一樣,這里面也會有問題。

            卡馬克的固執會把主設計師的設計文檔罵得一無是處:“游戲的故事背景,就好比色情片里的情節,雖然要有,但根本不是關鍵”,也可以隨意更改目標,讓湯姆的設計文檔變成廢紙。

            但是,羅梅洛卻能很好的找到自己的位置,充分發揮著天才程序員創造出來的東西,試驗著新引擎的特性,挖掘其潛能。

            終于,沒過多久,卡馬克向羅梅洛建議解雇湯姆,這意味著,公司將第一次出現創始人的離開。

            一個合理的保護制度:

            早在ID成立之初,他們就坐在一起討論過,所有人都誠心地同意,ID的命運,而不是他們任何人的命運,才是最重要的。無謂的內耗會給公司帶來多么致命的傷害,他們不希望ID毀于這樣的事情。

            他們達成兩點協議:首先,解雇一個持股人需要公司其他持股人的一致同意,那時,艾德里安,羅梅洛,湯姆,卡馬克是最主要的持股人,凱文和杰伊也有少量股分。其次,一旦被解雇,這個人就失去他所有的股分,公司的未來和他再沒有任何關系。

            羅梅洛希望能再給湯姆一次機會,他說服了卡馬克。可是,沒有人再能忍受湯姆,所有人都要求馬上解雇湯姆。羅梅洛只好同意。

            在全體持股人付方上,湯姆走進去的時候,大家都低頭坐在桌邊。卡馬克開口說到,公司顯然不能再這樣下去了,我們要求你離職。

            湯姆的離開需要一個繼任者,37歲的桑迪來到了ID。他接手羅梅洛的事,成了ID的游戲設計師,羅梅洛又回到了程序員,兼音效師,兼打理生意。

             

            什么時候能夠收手:

            DOOM的成功讓ID成就了事業上的輝煌,但也造成了羅梅洛與卡馬克的分離。羅梅洛不僅想把公司做大,他還有其他動機,樂趣。羅梅洛熱愛游戲,他活著就是為了玩游戲,他現在的生活就是DOOM的世界。

            卡馬克看著屏幕上閃爍的光標,沉默不語。曾經有多少個夜晚,羅梅洛就坐在他身邊,和他一起完善引擎,和他一起調試排錯,直到東方漸白。今夜,卡馬克目送著那印有“制作者”的背影消失在門口。

            創業什么時候是個頭,什么時候能夠坐享成果。畢竟這么努力是為了有更好的生活,不是每個人都能做苦行僧,當團隊有了一定的成果時,應該允許大家選擇新的生活方式,不應該太過于苛責。

            在羅梅洛離開ID后曾經評價過卡馬克,說他是苦行僧。雖然這時他的言論帶有一些偏見,但也能反應一些事實。

            “在公司有錢以后,依然把公司弄的非常簡陋,依然不懂得享受,還是日夜達旦的在那里寫他的程序,最要命的是,依然還要求別人也如他一樣。”

            應該清楚,辛苦努力的目標是什么。

            不是每個人都能讓自己的一生滿是辛苦,我想,大多數人愿意這么辛苦的根本目的還是希望能夠在不久的將來不需要再辛苦,所以,什么時候收手,這也是值得討論的。

             

            分開不一定是壞事:

            在羅梅洛忙于死亡競賽的時候,卡以克為ID擴充了兩位新人:圖形學泰斗亞伯拉什和關卡設計師麥基。

            卡馬克的苛責終于讓設計師們不堪忍受,羅梅洛撥通了好朋友湯姆的電話,打算創立一家以設計為主導的公司。麥基,也不再是神童麥基,而是孤獨者麥基。

            Quake剛結束,羅梅洛在ID的日子即將結束,卡馬克覺得他沒有盡到他的工作。雖然艾德里安試圖反對,但誰讓卡馬克才是ID的價值核心呢。如果卡馬克離開,那么ID將不復存在。

             

            卡馬克與羅梅洛之間的分歧太大了,對于什么是制作游戲以及游戲應該如何制作,他們都有各自的觀點;卡馬克認為羅梅洛已不再是程序員,羅梅洛認為卡馬克不再是玩家;卡馬克只想有一個小公司,而羅梅洛想做大。

            當卡馬克看著羅梅洛毅然轉身離去時,他沒有看到一絲留戀或悲傷,相反,他覺得這對羅梅洛是一種解脫。卡馬克相, 羅梅洛又踏上了新的征程。

            也許,每個人都有他自己對未來的期望,每個人都有他對如何做好一件事的看法,不一定能夠獲得完全的認同,求同存異,當差異實在太大時,分開其實對每個人都是最好的選擇。

            兩天后,羅梅洛在ID的辦公室告訴世界,我已決定離開ID軟件,成立一家有著不同目標的游戲公司,我不會從ID帶走任何人。

            第二天,卡馬克更新了他的日志,羅梅洛已離開ID,我會竭盡全力。

            一場死亡競賽曲終人散。

            posted @ 2010-04-21 22:50 白云哥 閱讀(501) | 評論 (1)編輯 收藏

            2010年4月19日

            如何處理好合伙之之間的關系

            Dharmesh Shah的文章原文我沒有找到,不過GameLook上的幾點精華歸納也足夠了,很值得參考。另外,這篇文章再次提到了合伙人章程這本書,可惜dangdang上依然缺貨 :(

            游戲目前已經不是個人英雄能夠全盤搞定的項目,所以,合作是必然的。當然,如果有足夠的魅力,憑著自己的個人品牌價值,或者足夠打動投資人的策劃案,直接拉來投資,然后雇傭其他人來干活,這樣就不用考慮創始人合作的問題。但是,對于絕大多數的技術創業人員來說,這還不是那么的靠譜,還是需要與合伙人一道從零開始努力。

            合伙人之間面臨的第一個問題,也是最重要,最根本的問題是如何分配利益。

            當然,你可以很容易的說,根據付出來分配收益。可事實上,這個的可操作性并不強,付出如何衡量,每個人的重要性如何界定,這都是很難量化評價的。很多時候,這大概也只能靠大家來協調,來讓每個人都能基本滿意吧。或者,有那么一兩個有魅力的合伙人,來給大家算上一筆明白賬,并且讓大家能夠相信這個未來確實是美好的。

            至少,很多人的建議都是,平均分配不是一個好主意。

            如何分配利益,我有過一個粗淺的想法。

            每個有意合作的人,拿出一個對未來三年后的最低利益期望,這個期望值要比自己在目前工作情況下,所能獲得的最大收益要高,具體高多少那就是自己的預期,另外再有一個稍高一些的期望值。我想,如果是誠心合作做事的人,這個期望值的提出不會太離譜。我也認為,有可能在這些人的期望值之間獲得一個平衡。當然,這需要協調者做比較大的努力,也許在這個過程中會有人因為不滿意而退出,但從一開始達成平衡要比將來再扯皮要好得多。

            第二個問題,如何做決策的問題。

            先不考慮在引入投資人后的投票權問題,單單只說合伙人之間。最樂觀的期望是讓每個人都能參與到決策的過程中來,讓每個人都真切的感受到自己在創業的核心里。但實際上,這實行起來可能也是不大可能,或者效率會很低下,或者引發的矛盾會更多。

            也許,一兩個強有力的決策者能讓這個過程更順暢,但是,這個決策絕對不能影響到其他每個人的利益。

            也許,找對了人,這并不會是多大的一個問題。

            然后是成員離開的問題。

            看到這一點,我又想起了DOOM啟示錄。這本書也是一本好書,我認真的翻過兩遍。如果失去了做游戲的激情,那就看看這本書吧。看看那一伙充滿激情的年輕人是怎樣走到一起,怎樣通力合作,怎樣創造出一個又一個奇跡,當然,也要看看最終他們是遇到了怎樣的問題而不得不分道揚鑣的故事。

            對于每一個合伙人,即使有一天不能再一起合作,不能同時走到最后,那也依然還是非常好的朋友。至少,當初是因為相互信任,有共同的理想與目標才走到一起的。羅梅洛和卡馬克在很多年后不也還是共同走進了那個會場么。當然,這個期望也可能太過于理想化,看看業內的情況大概就能知道,一旦離開,基本就成了對手,這還是比較好的情況。不過,期望總是美好的。

            如果真的很不幸,有人必須要離開,不管是出于怎樣的原因,主動的還是被動的,當然要保證留下來的人和留下來的項目不受損害。不論離開的這個人是誰。羅梅洛從id的離開其實也是很友好的,甚至可以說是多贏的。這種方法也未嘗不可以借鑒。

            有關每個人投入的問題。

            這個可能會比較棘手一些。尤其是當合伙人中有人面臨比較大的生活壓力時,比如有家族,有小孩。這個又涉及到另外一個問題,什么樣的人適合創業的問題。

            并不是每一個想法的實現都能一帆風順,也許這個努力奮斗的過程會相當艱難,也許在很長的一段時間里大家都只能靠在別的地方打工來生活,這時,如何去衡量每個人的付出,如何去評價每個人有多投入,會是一個更大的問題。也許,這還會給未來的利益分配埋下爭執隱患,也許,這也會成為一些人離開的直接或間接原因。但是,這也可能是一部分創業團隊的必經之路吧。

            posted @ 2010-04-19 00:46 白云哥 閱讀(559) | 評論 (0)編輯 收藏

            僅列出標題  下一頁

            導航

            統計

            常用鏈接

            留言簿(4)

            隨筆分類

            隨筆檔案

            相冊

            我的鏈接

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久精品国产亚洲AV无码麻豆 | 久久精品午夜一区二区福利| 香蕉99久久国产综合精品宅男自 | 99久久精品午夜一区二区| 91视频国产91久久久| 久久本道久久综合伊人| 熟妇人妻久久中文字幕| 久久久久久久综合综合狠狠| 狠狠色丁香久久婷婷综合| 日韩亚洲欧美久久久www综合网 | 日日噜噜夜夜狠狠久久丁香五月| 久久精品国内一区二区三区| 亚洲人AV永久一区二区三区久久| 欧洲成人午夜精品无码区久久| 精品久久久久久国产三级| 久久久久人妻一区二区三区vr| 久久精品视屏| 99久久精品免费看国产一区二区三区| 久久久久精品国产亚洲AV无码| 一本一道久久精品综合| 久久久久99精品成人片试看| 亚洲七七久久精品中文国产| 久久se精品一区二区影院 | 久久精品国产99国产精品导航| 久久成人18免费网站| 久久这里只有精品久久| 97久久国产亚洲精品超碰热| 亚洲av成人无码久久精品| 久久国产免费直播| 欧美成a人片免费看久久| 国内精品久久久久影院网站| 亚洲国产精品久久| 一级做a爰片久久毛片人呢| 精品久久久久久成人AV| 蜜臀av性久久久久蜜臀aⅴ麻豆 | 中文字幕无码久久久| 无码任你躁久久久久久| 久久大香萑太香蕉av| 色婷婷综合久久久久中文一区二区| 一级a性色生活片久久无少妇一级婬片免费放 | 亚洲色欲久久久综合网|