1。還沒有真正的次世代網(wǎng)游,更別指望它能賺錢
好幾次有朋友問我,次世代網(wǎng)游到底是什么東西
我說,次世代網(wǎng)游就是模型至少上萬面,貼圖每張都起碼2048,法線圖,高光圖,多層蒙版一個都不能少;動態(tài)光滿天飄,還都是開著陰影的;體積云,體積霧,體積光,全都是立體的,酷;水面的反射,折射,波紋,浪花,樣樣精彩;超大型,超豪華場景,無限視野。就一個字:真實!哦不對,是兩個字,超真實。
這樣的游戲用現(xiàn)在能配到的最好的機器,跑起來FPS也一定不允許超過15,否則那就不能叫次世代了。
說白了,次世代就是你用當(dāng)下的機器完全跑不起來的游戲,要么怎么能叫“次”世代呢。
這樣的游戲,不是讓大多數(shù)玩家能玩得起來的,不是拿來賣錢的,就跟北京的商品房一樣,是給大家去追捧的。最多,會等Intel,Nvidia來給開發(fā)商返點利。嗯,我是說,大概可能估計會有的吧。
次世代的游戲其實已有不少了,比如戰(zhàn)爭機器,比如戰(zhàn)神,比如彩虹六號……但次世代的網(wǎng)游還沒有。
魔獸是次世代嗎?不是,完全不是。
永恒之塔是次世代嗎?也不是,它也還差的遠。
天下二,劍網(wǎng)三就差的更遠了。
2。真正賺錢的游戲技術(shù)都很普通
也許你會說,真正的次世代游戲都還沒有出來,你怎么就敢預(yù)言他們不能賺錢呢?
是的,我不能,如果我有未卜先知的本領(lǐng),那我早就不再需要靠做游戲來養(yǎng)活自己了。
可是,我們卻能夠看到現(xiàn)在賺錢的游戲是什么樣的,這些是明明白白擺在那里的。
魔獸世界:把這個游戲譽為國內(nèi)3D游戲的教程書完全不為過,不過你承不承認,策劃也好,程序也好,美術(shù)也好,都從這里面學(xué)到了很多東西,模仿了很多東西,在目前國內(nèi)的游戲里面,到處都能找到魔獸的影子。
可是魔獸又用到了多神奇的技術(shù)?主角模型算上所有部件,3000多面,各部件的貼圖組合在一起,512大小,沒有法線沒有高光,絕大多數(shù)還都只是一層貼圖,偶爾有一些多層混合的。地形最簡單的分塊4層混合,最簡單的lightmap。水面,把鏡頭拉遠一點都能看出來貼圖形狀。天空盒,一個普通的m2模型。
可是,魔獸所表現(xiàn)出來的整體場景效果,有哪一個游戲敢說超越呢?
天龍八部,基于開源引擎Ogre制作的典范,也因為天龍八部鼓舞了國內(nèi)好多使用Ogre開發(fā)的小團隊。
不得不承認,Ogre所使用的技術(shù)是最樸實的,樸實到我這樣一個3D新手都能拿來修修改改,做點簡單的demo。
同樣不得不承認,天龍的畫面效果確實很一般,2.5D的場景,固定的視角,輕盈的有些像紙片人的模型,可是,這并不妨礙他每月近兩億的收入。
夢幻,大話,DNF,征途,傳奇……
除了這些表面上能看到的技術(shù)以外,背后的技術(shù)是同樣的道理。
早期的單服務(wù)器,分線方式,依然沿用在現(xiàn)在很多主流的游戲服務(wù)器端,并且依然是非常賺錢的項目。而類似于BigWorld的高深架構(gòu),事實上也并沒有成功的項目。如果把天下二的商業(yè)結(jié)果跟其他項目一比較的話。
3。2D游戲比3D游戲賺錢
我一樣很認同,未來的趨勢是3D,但是,那時候賺錢的3D項目不應(yīng)該是現(xiàn)在這個樣子的。
以國內(nèi)游戲玩家的年齡及文化層次來看,要讓他們接受“右鍵旋轉(zhuǎn)朝向,左鍵旋轉(zhuǎn)視角”太過于困難,而即使是一個很熟悉3D操作模式的老玩家,進入到一個新的場景中,要分辨出“上北下南,左西右東”也是很煩人的一件事。
如何盡可能的使用上3D的表現(xiàn)力,但又避免掉目前3D游戲的復(fù)雜操作模式,這要看未來誰先能走好這一步。
但是,在3D真正應(yīng)用起來之前,目前還是2D的天下。
國內(nèi)最賺錢的夢幻,還有大話系列,同樣最高在線超過200萬的DNF、征途,還有那不應(yīng)被忘記了傳奇。
不用歷數(shù)這些名字,文化部2009網(wǎng)游行業(yè)發(fā)展報告上統(tǒng)計的結(jié)果是,2D游戲收入占整個游戲行業(yè)收入達70%多。
這也無怪乎騰迅到現(xiàn)在還在開發(fā)2D新項目,以3D起家的完美也要開2D項目,網(wǎng)易的大話到3代了還是2D,把unreal3應(yīng)用得純熟的韓國人也同樣還在制作2D游戲。
4。游戲開發(fā)并沒有什么高深的技術(shù)
首先需要明確的一點,游戲項目是工程項目,不是科研項目。
工程項目的目的是在有限的人力跟財力之下實現(xiàn)出既定的需求,而這個需求從前面的分析可以知道,要求并不高,所以,需求的實現(xiàn)過程也就并沒有多么高深。
至少在我經(jīng)歷過的項目里,沒有什么驚天地泣鬼神似的英雄人物,沒有創(chuàng)造出多么偉大的算法,我們所做的,只是使用現(xiàn)在的技術(shù),現(xiàn)有的方法,拼合成一個軟件產(chǎn)品,一個融合了程序、美術(shù)、策劃勞動力的軟件產(chǎn)品。
游戲開發(fā)的過程里,沒有,也不需要多厲害的技術(shù)高手,需要的僅僅只是有耐心,有責(zé)任心的普通技術(shù)人員。
5。游戲的賣點在內(nèi)容而不是畫面,但是畫面不夠好卻沒有機會去展現(xiàn)內(nèi)容
說這一點不是想強調(diào)到底是程序重要還是美術(shù)重要,或者是策劃更重要。這三者是缺一不可,而且哪一方弱都不行的。
我想說的是,游戲真正留住玩家靠的還是內(nèi)容。
一樣是拿現(xiàn)在賺錢的游戲來說,夢幻沒有華麗的3D場景跟畫面,天龍有3D,但沒人會說那里面有華麗的場景,DNF的2D畫面還是非常粗糙的,唯獨好一點的魔獸,但他的市場表現(xiàn)在國內(nèi)游戲里面來說,并不算太強。
但是好的畫面在最開始的幾分鐘里卻是相當(dāng)重要的,這就好比是長的帥的人能夠更吸引女孩子一樣。
也許你能用你的魅力,你的錢袋子來打動女人,但如果你穿著一件破衣服,臉上只有著殘缺美,那你后面那些魅力,那些優(yōu)點永遠沒有機會展示出來。游戲也是一樣。
至少,你的新手村一定要做到富麗堂皇。
6。游戲并不需要追求太多的游戲性,提供一個交流的平臺就行
這是我最近的感悟。
很多人玩游戲其實就是為了打發(fā)時間,我也問過很多沉迷于魔獸,沉迷于偷菜,沉迷于這些那些游戲的人,包括偶爾玩一下的,包括職業(yè)玩家,包括像我這樣,為了游戲而玩一下的人。
游戲靠什么來留住人,在這一點上達成共識并不難,那就是里面的朋友。所以,給玩家營造一個更好的交流氛圍,交流環(huán)境,做到這一點了,游戲玩法可以要多俗有多俗。
又在游戲里面,還有社區(qū)里面接觸了一些新生代的玩家們,似乎家族是一個很流行的東西。這其實可以看作是以前游戲里公會的升級版。在某個兒童游戲里,一個玩家?guī)е胰⒂^他們的家族,帶我一個個拜見他們的官員。可我并沒有看到這些官員的頭銜,于是我問,你們這些官員是怎么來的?答曰:自己封的。
就好像公園里的小道一樣,有時候,游人們會按照自己的喜好在草地上走出一些新的路來,這些路才是最合理的。
為什么不順著這些玩家的路,把這些功能做的更強大一點呢。
其實,把社群的功能做得更強大,更高級一點,那就像文明。或者做的更容易,更低齡一點,那就像過家家。不管是怎樣,應(yīng)該在系統(tǒng)里就增強了交流的便利性,甚至可以在玩家一加入到游戲中,就開始引導(dǎo)著他加入社群。只有在社群里,他才能找到家的感覺,他才會因為朋友們而留下來。
當(dāng)然,怎么找對這條路,走好這條路,可不像寫下這幾行字這么簡單。
根據(jù)文化部2009年游戲行業(yè)發(fā)展白皮書上的數(shù)據(jù),游戲運營失敗比例30%左右,游戲開發(fā)失敗比例50%左右,當(dāng)然這個是指登記注冊了公司的,其實還有更多小團隊,小工作室,直接死在了起步的路上。
單從這個比例來看,似乎創(chuàng)業(yè)的風(fēng)險還是挺大的,每一個成功活下來的公司都踩著一個或幾個死去公司的尸體。可是,相比起大家常說的,十家創(chuàng)業(yè)公司一家成功,這個比例也不算高,而且,要是再看看成功的游戲公司獲得的回報,這個風(fēng)險也就真的不大了。
說游戲創(chuàng)業(yè)的風(fēng)險不如說小創(chuàng)業(yè)團隊最終的結(jié)局。
幾個志同道合的朋友走到一起,當(dāng)然是想把事情做成功的,但是美好的期望不能保證全都能實現(xiàn),不過,即使這個過程失敗了,也不一定全都失敗,除了最好的結(jié)局之外,也還是有其他幾種可能性的。
從最好到最壞,大致有以下這么六種結(jié)局:
1。游戲在預(yù)期時間內(nèi)開發(fā)成功,并上線運營
當(dāng)然,這是最理想的結(jié)局,也是團隊組建初期給自己設(shè)定的目標。
國家政策規(guī)定,運營網(wǎng)絡(luò)游戲的公司注冊資金必須一千萬以上,另外游戲的宣傳推廣費用一般都比較高,所以如果沒有足夠的資金實力,獨立運營的可能性不大。
但是如果一切都進展順利,順利的將游戲開發(fā)完成,順利的找到了投資人,自己組建運營團隊其實是最好的選擇。因為都知道,運營才是創(chuàng)造利潤的地方。
2。游戲開發(fā)成功,但不具備獨立運營的條件,轉(zhuǎn)做單純的開發(fā)商,把產(chǎn)品代理給別人運營
如果很不幸的,沒有足夠的資金實力去運營自己的游戲,或者,創(chuàng)業(yè)伙伴們對自己運營游戲的把握都不大,也找不到一個放心的人來做,再或者,投資人不希望由開發(fā)團隊自己來運營。那么,把產(chǎn)品代理給專業(yè)的運營公司,獲得利潤分成,也是一個不錯的選擇。
其實很多的創(chuàng)業(yè)小團隊最終選擇的都是這條路,更不用說參與18計劃,贏在巨人計劃的那些團隊了,本身就是屬于投資公司旗下的。
運營畢竟不同于開發(fā),游戲開發(fā)需要解決是技術(shù)問題與團隊內(nèi)成員的合作問題,而運營面對的競爭卻有可能是血淋淋的,商場如戰(zhàn)場,沒有十足的把握與充分的資金支持,需要慎重對待。
但是代理給別人最大的一個問題是收入將受制于人,首先這個分成比例可能會并不高,另外,如果游戲比較成功了,運營公司很可能會山寨一款同樣的游戲,并把用戶引入他自己的游戲,而避免與原來的開發(fā)商分成。這樣的例子在國內(nèi)已不鮮見。
3。游戲開發(fā)過程中遇到問題,團隊加入大公司,以工作室或獨立部門方式存在
團隊最終加入大公司的情況,也并不一定是自己遇到了問題,也有可能是合作的需要。
當(dāng)創(chuàng)業(yè)團隊度過了最初的一段時間,游戲基本成形,開始大量的內(nèi)容制作的時間,將可能需要招聘大量開發(fā)人員,這時,人員的管理不像以前幾個核心人員那樣,完全靠自覺了。而創(chuàng)業(yè)的伙伴們顯然對技術(shù)的把控比對人員的把控能力要強,也許,找一家成熟的公司,由他們來處理這些人事、財務(wù)方面的瑣事要容易得多。
另外,也有可能投資人希望開發(fā)團隊能夠在自己身邊,能夠經(jīng)常看到開發(fā)成果,能夠讓自己更放心。畢竟,投進去的錢那是真金白銀,花錢的人不在身邊,心里總會有些不大放心。
還有可能就是團隊確實遇到了問題,比如資金方面的問題,找一家有實力的公司進行合作,整體并入大公司,成立一個新的部門,或者獨立工作室,繼續(xù)原來的工作。
這種一般會與公司按比例分紅,但因為公司在開發(fā)期就在支持付工資,也承擔(dān)了風(fēng)險,所以這個分紅比例不會比代理分紅高,但對于當(dāng)初創(chuàng)業(yè)的核心開發(fā)人員來說,也絕對比在公司打工強。
4。開發(fā)團隊整體被收購,繼續(xù)回到打工狀態(tài)
這種結(jié)局就已經(jīng)是不大愿意看到的了。
當(dāng)然,收購的方式也有多種,如果收購后在新公司成立部門,繼續(xù)進行原來項目的開發(fā),那與上一種情況其實相差不多,但因為是收購,支付了費用,或者是以股權(quán)方式收購的,所以開發(fā)團隊的身份會有改變,說白了,就是現(xiàn)在是純粹的打工仔,不能再談更多的條件。
不是,既然是被收購,那還是會有一點收入,讓初創(chuàng)人員有一定的回報。
5。創(chuàng)業(yè)失敗,團隊整體加入新公司,在新的公司里再繼續(xù)開發(fā)新項目
如果很不幸的,團隊最終因資金問題,或者合作問題,不得不結(jié)束創(chuàng)業(yè)的過程。
這時也還是有可能繼續(xù)博一次,比如找一家有實力的大公司,以團隊方式加盟,可以帶上以前未完成的項目,或者不帶項目。當(dāng)然,進入新公司后做什么項目,這很難再由自己決定了,另外團隊成員是否會被新公司拆散,這也不由自己控制。
但總之,團隊加盟新公司,比單打獨斗要好。
這只能算是不得已而為之的最后選擇了吧。
6。團隊失敗,解散。各回各家,各找各媽。各自回到自己的打工狀態(tài)
最壞的情況就是,創(chuàng)業(yè)過程失敗,最終團隊完全解散,或者還沒有完全解散的人也找不到合適的去處,這時只能是各回各家,各找各媽了。
進入新一輪的打工狀態(tài)。
每一個創(chuàng)業(yè)的團隊都是帶著對未來美好的憧憬開始的,并且在開始的時候也是認真在做的,但有人的地方就有江湖,也許合作的過程并不像想象的那么順暢,也許后來才發(fā)現(xiàn)投資人并不像之前承諾的那樣大方,也許,大家都錯誤的估計了自己的能力。
但是,每一個勇敢走出第一步的團隊,每一個敢于走上創(chuàng)業(yè)這條路的個人都是英雄。
至少,他們的人生有了這段經(jīng)歷而變得精彩起來,至少,他們向成功的人生方向又邁出了一步。
這比那些只會贊嘆某某游戲公司有多賺錢的人要強得多,這比那些只敢臨淵羨魚而不敢退而結(jié)網(wǎng)的人要可敬得多。
或者,走向創(chuàng)業(yè)路上第一步的時候,可以問一問自己,兩年或者三年以后,希望自己能是個什么狀態(tài)。再問一問自己,如果失敗了,最壞將是個什么狀態(tài)。然后再回身看一看現(xiàn)在的自己,現(xiàn)在是怎樣一個狀態(tài)。如果今天換到行業(yè)里最好的公司,有同等條件下最好的待遇,兩年或三年后自己將可以是怎樣的狀態(tài)。
或許,你會覺得,還是應(yīng)該走出去試一試。
好游戲的標準很難定義,往往商業(yè)上的成功與品質(zhì)上的優(yōu)秀并不是完全一致的。那就不談好游戲,說說怎么做成一款游戲吧。
做成的意思是指能夠成功上線運營,至少,保證能有個兩萬人同時在線吧,這樣,其實也就是做成了,一年還能有兩千多萬的收入,如果只是個小團隊開發(fā),那足夠收回成本并讓開發(fā)人員獲得基本滿意的回報了。只是,她可能不算好游戲而已。
游戲,雖不是軟件項目里最復(fù)雜的,但也屬于最復(fù)雜的軟件項目之一吧。倒不是說游戲程序?qū)懫饋碛卸嚯y,而是游戲項目的需求變更太頻繁,游戲項目涉及到的人員配合太復(fù)雜。
策劃的思路始終在變,朝三暮四是常事,繞個大圈又回到原點也是會有的;運營方隨時也會跟進,提出一些更有利于運營推廣的想法要求程序去實現(xiàn)。
程序、策劃、美術(shù),完全不搭邊的一群人,思維方式跟工作習(xí)慣存大巨大的差異,卻要在一起,把各自的工作揉合起來,成為最終的游戲產(chǎn)品。
這一切,說起來似乎并不復(fù)雜,但在執(zhí)行過程中一旦出現(xiàn)點小差錯,一般都是人為的一點小問題,后果基本上卻會是災(zāi)難性的,之前所付出的努力都付之東流。
但是我們又不能說這些需求的變更不應(yīng)該有。正是因為大家都在為這項目而努力,都希望做好產(chǎn)品,才會有這樣的反復(fù)。有句話說的好,好游戲是改出來的。
程序、策劃、美術(shù)的配合更是無法避免的。以前那種靠一兩個程序員單挑所有事情的時代已經(jīng)成為歷史,即使今天某個人確實有這能力,原畫畫的超級棒,3D模型做的一流好,程序還寫的讓人刮目相看,可是,時間總是有限的。今天一個優(yōu)秀的創(chuàng)意,如果等個十來年才能實現(xiàn)出來,那等到出來的那一天,也只能放進博物館了。
而且,以目前的小型MMORPG項目來看,就算是效率比較高的創(chuàng)業(yè)小團隊,就算是在一些既有代碼的基礎(chǔ)上修改來完成項目,也至少需要20到30人年的開發(fā)時間。
大概這些描述已經(jīng)給你蒙上了一層悲觀的陰影,事實上做成一款游戲的風(fēng)險其實并沒有想象的那么大。
每一個在游戲公司呆過的人都清楚,游戲開發(fā)其實也就那點事。
策劃的需求雖然總在變動,但到了今天,沒有哪個程序會硬編碼策劃們的邏輯需求。腳本的引入完全可以讓策劃們自己去配置、調(diào)試、驗證一些想法,如果能做的更進一步,提供GUI的工具讓他們更方便的去修改這些東西,那策劃們將會更少來麻煩程序。
一個稱手的工具會讓美術(shù)人員以最高的效率去制作游戲內(nèi)容。有時候你會發(fā)現(xiàn),程序只需要花上半天時間為編輯器增加一個很小的功能,卻能讓美術(shù)減少幾天的工作量。而美術(shù)花上幾分鐘時間檢查所做的東西是否符合程序制定的規(guī)范,也能讓程序兄弟們少花那兩三天的時間去調(diào)試到底是什么原因讓程序崩潰。
理想的情況下,程序給美術(shù)和策劃們制作好了工具,游戲的一切內(nèi)容,都與程序再無關(guān)。程序所要關(guān)注的,是如何讓游戲運行的更順暢,如何讓策劃配置的自由度更高,如何讓這些工具更好用,如何最大可能的減輕美術(shù)與策劃的工作量。
再加上這些相互的理解與支持,合作會變得越來越順暢,大家會更愿意為對方多付出那么一點點時間。我想,真正做到了這一點,在一些團隊里經(jīng)常會聽到的美術(shù)、策劃與程序們相互之間的抱怨也就沒有了。
當(dāng)然,這樣的情況有些過于理想化,也許這些不一定都能做到。
實際上你可能依然會在團隊里聽到程序?qū)γ佬g(shù)不遵守規(guī)范的抱怨,依然會聽到美術(shù)對工具不能完全滿足使用需求的指責(zé),依然會有策劃過來要求程序反復(fù)修改或者實現(xiàn)某個功能。
本來嘛,程序、策劃、美術(shù)工作性質(zhì)的差異,思考問題方式的差異,使得他們很難完全一致,這時,我們需要有一兩個能夠顧全到大局的人,去化解這些問題。這一兩個人的以身作則,還有他們的感染力,也在帶動著團隊的合作向著良性的方向發(fā)展。
很多時候,箭在弦上,只要有人輕撫一下,緊張局勢便可破解。很多時候,只是缺少這樣一兩個愿意主動站出來的人。每一個團隊都會有核心,所謂的核心,并不僅僅在于技術(shù)上的主導(dǎo)性,很多時候,他需要把他當(dāng)作是團隊的領(lǐng)頭人,主動承擔(dān)起這些責(zé)任。
只要找對了兩個這樣的人,我相信,小團隊要做到和諧融洽還是比較容易的。
如果順利的話,團隊成員每天都能夠看到自己所做的東西一點一點在成型,一點一點在完善,這對團隊的士氣將是很大的鼓舞,每個人都看到未來將會是怎樣。
小團隊相比大公司,優(yōu)勢在于行動迅速,但劣勢在于抗風(fēng)險能力較弱,更需要注意士氣的維持。所以,一個始終充滿激情的旗手就顯得很重要了。他不應(yīng)該離大家很遠,更不能高高在上,他就是集體的一份子,每個人都能看到的一份子。
中國的國情使得車庫文化不大可能產(chǎn)生,即使是對于小團隊來說,可是,在我們還在成長的過程中,每個人都應(yīng)該坐在一張桌子上。
我也始終認為,開發(fā)人員本身是并不復(fù)雜的,不管是程序、策劃還是美術(shù)。尤其是一些真正想做好事情的人,在大家認同的合作方式下,有共同的利益訴求,每一個理性人必將選擇通力合作,首先把項目做成功。
每一個團隊成員,尤其是核心人員,只要心里面陽光一些,再陽光一些,沒有那些所謂的辦公室政治,沒有那些所謂的圈子圈套。小團隊十來號人,只有一個圈子,就是這個集體。那么,做事情其實是應(yīng)該很順暢的。
只要找對了人,做成一款游戲,其實并不難。
游戲有多賺錢,看一下上市游戲公司的財報就知道了。http://tech.163.com/caibao,這里有國內(nèi)互聯(lián)網(wǎng)公司財報匯總,摘錄09年第四季度幾家公司的游戲業(yè)務(wù)贏利情況,見下表:
公司 | 游戲營收(萬元) | 毛利潤(萬元) | 毛利率 |
盛大 | 133600 | 80200 | 60% |
完美 | 54000 | 52600 | 86.60% |
暢游 | 48250 | 28800 | 92% |
巨人 | 27300 | 23200 | 83.90% |
當(dāng)然,這是占據(jù)了國內(nèi)游戲行業(yè)收入一大半的幾家大公司,不過就算是小公司,只要能成功讓產(chǎn)品上線,利潤率也是一樣的。
從上市公司的財報里可以看到,一般MMORPG的每活躍付費用戶平均每月貢獻收入大致在60元左右,有些游戲會高很多,有些稍低一些。也就是說,只要有2萬活躍付費用戶,以85%的利潤率來計算,扣除運營成本后的月利潤就能達到100萬。
不過,目前游戲的類型基本上都是道具收費,這樣不是每個玩游戲的人都會掏錢。按照暢游財報中披露的信息,非付費用戶向付費用戶的轉(zhuǎn)化比例為18%,其他游戲的這個比例應(yīng)該也不會相差太多,2 * 18%,月收入100萬就需要有11萬的活躍用戶。
活躍用戶的統(tǒng)計方法一般是如果該賬號在一天內(nèi)累計在線時間超過2小時,剛該玩家的活躍天數(shù)就加1,如果在線時間在半小時到2小時之間,則活躍天數(shù)加0.5,在線時間小于半小時的不算活躍天數(shù)。當(dāng)然,這是每日活躍用戶數(shù)的統(tǒng)計方法。
我們以2小時為單位,只要在每個時間單位內(nèi)有11 / 12萬用戶在線,則就達到了10萬活躍用戶。也就是說,平均在線只要不到一萬人就達到了月入100萬的目標。
這個數(shù)字基本上是可信的。可以再看一看完美的財報,完美Q4財報顯示,平均同時在線(ACU)為115.7萬人,網(wǎng)游收入為5.4億元,平均每月為1.8億,這樣每1萬平均在線貢獻的收入為 18000 / 115.7 = 155萬,這個數(shù)字比前面計算的不到一萬同時在線貢獻收入100萬還要高,這是因為完美的ARPU值比暢游高,為每月74元。
所以,每當(dāng)跟別人介紹我是做游戲時,別人都會感嘆一下,游戲啊,挺賺錢的,我也笑笑,確實是挺賺錢的。可是,如此賺錢的產(chǎn)品,開發(fā)人員的回報又有多少呢?
再來看一下上市公司的財報。依然是暢游的,“非美國通用會計準則產(chǎn)品開發(fā)費用為510萬美元,環(huán)比增長5%,同比減少12%。環(huán)比增長主要是由于聘用了更多的游戲研發(fā)人員而導(dǎo)致員工薪酬與福利費用的增加。同比減少主要是由于公司管理層獎金方案的調(diào)整——之前授予的股權(quán)激勵在IPO后價值提高,因而公司減少其現(xiàn)金獎勵。”
從這句話上可以看出來,這個研發(fā)費用不僅僅只是開發(fā)人員的工資,還包括了由于員工的相關(guān)福利,也包含了為員工所繳納的保險,公積金等費用。另外也還包括了獎金,以及股權(quán)獎勵等等。就這520萬,也只占到了營收的7%。
在公司管理層解讀財報的時候有另外一句話,“截止到2009年12月31日,共有520位工程師。地面推廣團隊中正式員工有50人,另外還有臨時雇員大約還有600人。”不知道這510萬的研發(fā)費用是否包括了上面提到的地面推廣人員和臨時雇員,暫時認為其不包含吧,假定這些錢都花在了520位開發(fā)人員身上。
另外也不知道這510萬是否包含研發(fā)相差的辦公室租金等費用,這個估計應(yīng)該包含吧。
公司為員工繳納的保險,公積金跟我們交的一樣,會占工資的20%多,辦公開支不大好算,另外福利也不好說,比如聚餐,組織出去玩等,這些不好統(tǒng)計,還不排除有一些無法統(tǒng)計到的灰色內(nèi)容。簡單一點,就算這510萬有50%最后以money的形式發(fā)到了開發(fā)人員手上吧,包括每月固定工資與獎金。這樣,平均每人每月是1600美元。
因為大部分公司的獎金都是以多發(fā)一個或者幾個月的工資形式來發(fā)放的,據(jù)說暢游每年相當(dāng)于能發(fā)16個月工資,1600 * 12 / 16 = 1200美元。平均8000元的月薪,可能大部分人會感覺到自己并沒有這么多。當(dāng)然,因為有一小部分人有股權(quán)的獎勵,他們的收入遠超過了8000 * 16,所謂20%的精英獲得了80%的利益 :) 其實也是差不多的。
如此高利潤率的游戲產(chǎn)品,到頭來生產(chǎn)者們的回報卻也還是一樣。所以,再聽到人說游戲很賺錢時,有必要好好對其解釋一番 :) 游戲確實是賺錢,可錢并不在我們這些人的口袋里。
再來看近期網(wǎng)易的大話二團隊集體離職,大明龍權(quán)開發(fā)團隊集體跳槽完美,還有華義成都差不多整個公司跳到騰訊,金山的團隊到網(wǎng)易去開發(fā)大唐,盛大的英雄年代團隊出走征途等等,這不能說是員工不夠忠誠,實在是利益分配的不合理。新的老板只要肯多拿出一個甚至半個百分點,分到開發(fā)人員的手中就是沉甸甸的誘惑了。
而且還有另外一條很重要的因素,游戲的成功與否很大程度上來自于那幾個開發(fā)人員。縱觀國內(nèi)游戲廠商,基本上都是只靠著開發(fā)團隊做的一款游戲就撐起了整個公司,讓公司擠進二線、一線游戲廠商行列,甚至靠著這一款游戲去賺美國股民的錢。當(dāng)然這種成功也有很大的偶然性。
就像一個正在創(chuàng)業(yè)路上的朋友所說,游戲是能讓你迅速從楊白勞變成黃世仁的最好選擇。當(dāng)前,前提是你不是在為別人打工。
Ogre正在開發(fā)中的版本,1.7版,引入了新的Terrain Component與Paging Component,Ogre終于開始對地形渲染進行官方的支持了。Ogre官方論壇上sinbad也提到了這個新的Terrain Component的特性及目前的進展,不過他自己也說,雖然他很希望1.7版能在今年發(fā)布,但是結(jié)果卻也很難預(yù)測 :(
曾幾何時,在Ogre中尋求更加完善的地形渲染支持是多少人都在做的事,Ogre源代碼庫中的Terrain Scene Mananger只能實現(xiàn)最基本的高度圖渲染功能,搭配一張普通texture和一張detail texture,根本無法實現(xiàn)出我們想要的真實地形效果。于是,Addon論壇上不少人也開始了為Ogre擴展地形渲染支持的工作,比較有名的是PLSM,這部分代碼經(jīng)過不少的修改,之后也被納入了Ogre的Octree Scene Manager代碼庫,不過其依然還是相當(dāng)?shù)暮喡A硗膺€有一個就是Myrddin,這里是論壇上的介紹頁面,在1.7版出來之前,這應(yīng)該是最好的地形渲染選擇了。
所以,之前使用Ogre的游戲要么自己來寫地形渲染這一塊,要么干脆就不要地形,一切皆mesh,比如最近挺火的火炬之光(Torchlight)。
其實,一切皆Mesh也并不是不可以,相反,用Mesh能夠表現(xiàn)出更加細膩真實的效果,比如場景本來就是由大師的地下城或者陡峭的山脈構(gòu)成時。就像前幾年玩過的“地牢圍攻2”。當(dāng)然,全Mesh場景的問題也是很明顯的,其需要渲染的面數(shù)太多,所以,這樣的游戲也只好采用固定的斜視角,并且打上很近的霧來減少需要渲染的對象數(shù),就如同前面提到過的兩個例子,“地牢圍攻”和“火炬之光”那樣。
從OgreSVN上checkout出來代碼,簡單看了下相關(guān)的代碼注釋,其特性還是挺讓人期待的。
首先,地形資源有了自己的文件格式,不再是以前的terrain.cfg和terrain.png或terrain.raw了,
另外,terrain和paging以Component的形式實現(xiàn),不再依賴于Scene Manager的實現(xiàn)。
然后,貼圖的混合也已基本實現(xiàn)。目前地形渲染的一個pass最多支持6層貼圖,地形渲染常用的normal map, light map, colour map,specular map都已經(jīng)支持,從其提供的幾張試驗用的截圖來看,多層混合、法線以及高光實現(xiàn)的都已經(jīng)沒有問題了。
另外還有一個額外的特性是支持運行時對地形的修改,并能在后臺線程中對地形數(shù)據(jù)進行加載和保存。
雖然這個特性在目前的游戲中都不需要,因為地形編輯一般是在場景制作的時候完成,也就是由美術(shù)人員在制作地圖時就已確定好了,在游戲中只需要將地圖文件讀出來并渲染到屏幕,游戲進行過程中也不允許對地形數(shù)據(jù)進行任何破壞和修改。
其實,從技術(shù)上來說,這并不是絕對的限制,地形及場景完全是可以破壞的,可以重建的,比如,可以讓一顆炸彈落過的地方永久的留下一個彈坑,讓火燒過的地方只留下一片殘骸,樹木及雜草都被燒毀,另外,城鎮(zhèn)與村落也不需要是美術(shù)預(yù)先編輯好的,玩家完全可以在一塊空曠的地方建起一座城來,當(dāng)然也可以把別人的一座城燒毀掉,等等。
只是,當(dāng)?shù)匦渭皥鼍案淖兒蠓?wù)器需要同步大量的數(shù)據(jù)給客戶端,并且,如何保證這些數(shù)據(jù)的完整性和一致性。這最主要的還是受限于網(wǎng)速的原因,如果網(wǎng)絡(luò)速度足夠快,我們完全可以把游戲做成瘦客戶端,甚至無客戶端,就像現(xiàn)在的flash web game一樣,客戶端總是去服務(wù)器上取最新的場景數(shù)據(jù),這樣就不再有問題了。
但是,另外一個問題可能會稍麻煩一些。當(dāng)?shù)匦魏蛨鼍案淖兒螅?wù)器端的AI相關(guān)數(shù)據(jù)會受到很大的影響,比如尋路數(shù)據(jù),不論是用nav mesh還是用waypoint,這些數(shù)據(jù)都要重新構(gòu)造,而這個構(gòu)造過程一般來說將會是漫長的,但是地形的重建卻可能會是相當(dāng)頻繁的。。。還有AI對象的出生數(shù)據(jù),等等,這都需要我們花一些精力去思考。
當(dāng)然,一切能夠想得到的問題都不會是大問題,總會有方法去解決它們。今天覺得不可能做到的事,隨著明天硬件環(huán)境的提升,新的算法的實現(xiàn),這也將成為我們在游戲中能夠親眼看到的事實。
最近在我的關(guān)注領(lǐng)域內(nèi)的消息還真不少
1。Unity2.6發(fā)布,并且將indie版免費。(當(dāng)然,之前也有30天的試用版)Unity的制作人說過一句話:如果做web,2D就用flash,3D就用Unity。雖然這是一句宣傳詞,不過,Unity也確實挺不錯。
2。Android 2.0 SDK發(fā)布,可惡的GFW,好在Android Setup Tools非常體諒我們這些墻里的人,升級工具里有個選項叫https,當(dāng)然,這是通過犧牲速度來換取的。真不明白GFW封堵sourceforge, developer.android這樣的開發(fā)者網(wǎng)站是何用意,怕國外的先進技術(shù)毒害了我們這群求知的人們?
另外,摩托的支持Android 2.0的新手機也即將發(fā)布,售價是誘人的199刀,不知道國內(nèi)有沒有渠道能夠買到。當(dāng)然,這199刀不會是跟之前的iPhone售價一樣吧。
3。一款叫做Torchlight的游戲發(fā)布,其制作人以前在北方暴雪呆過,所以,這游戲怎么玩怎么像是暗黑卡通版。另外,據(jù)說其網(wǎng)絡(luò)版在一年半后發(fā)布,國內(nèi)由完美時空代理。不過,我更加關(guān)注的是它使用Ogre渲染引擎。
4。Qt4.6正式發(fā)布,新特性確實添加的很快,想拿它來做工具試試。
這篇文章所使用的方法來源于 CuteQt博客 上的一篇文章:http://www.cuteqt.com/blog/?p=868
生成對象內(nèi)存布局所使用的方法來自于vc8編譯器一個未公開的參數(shù),即 /d1 reportSingleClassLayoutXXX或者 /d1 reportAllClassLayout,MSDN上關(guān)于這個的簡單說明及示例可以見這里:http://blogs.msdn.com/vcblog/archive/2007/05/17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022.aspx
一般來說用reportSingleClassLayout,因為reportAllClassLayout會生成許多中間類的結(jié)果,干擾我們的分析。
按照上面博客中介紹的方法,一步步來跟蹤各種虛函數(shù)使用情況下的對象內(nèi)存布局,可以很直觀的看到虛函數(shù)是怎樣分布的,各種繼承情況下虛函數(shù)是又是怎樣生成的,等等。
一點簡單的總結(jié):
1。以前常說的,因為虛函數(shù)的使用,使得類多了一個vtable指針,大小增加了4字節(jié),其實是不完全正確的。因為一個class內(nèi)可能會有多個虛表的存在,比如當(dāng)有多個帶虛函數(shù)的父類時。
2。多個虛函數(shù)在虛表里的順序由其定義順序決定。如果是從多個父類派生來的,則這多個虛表的順序由父類的申明順序而定。
3。多繼承情況下的同名虛函數(shù)處理使用了一種叫做thunk的技術(shù),這樣通過不同的基類調(diào)用同名的虛函數(shù)時,都會調(diào)用到相同的函數(shù)體內(nèi)。
4。虛基類的實現(xiàn)多了一個vbi表,記錄的是虛基類中的虛函數(shù)表地址信息。同時在派生類中計算好了到這個vbi表的偏移,這樣虛基類里的虛函數(shù)在菱形繼承關(guān)系的派生類中就只有了一份實現(xiàn)。
5。使用的時候其實不必要意這些細節(jié)問題,編譯器在生成函數(shù)調(diào)用代碼時已經(jīng)幫我們處理好了,即這個函數(shù)在哪個虛表中,是第幾個虛函數(shù),最終也就是要做多少個字節(jié)的偏移。
不得不承認,QT在Nokia的懷抱中越活越滋潤,如長成的少女一般越來越漂亮。
程序速度越來越快,Nokia QT推出的第一個版本運行速度比原來快了近一半,而即將推出的4.6版還將把圖形渲染底層重寫,以進一步提升運行速度。
平臺支持范圍也越來越廣:S60手機平臺的支持,當(dāng)然,這是Nokia收購QT的最主要目標吧,最新的Windows7和Max OS X以及更多的Unix平臺的支持,讓QT無孔不入。
完全獨立的IDE:QT Creator,雖然說用慣了VS IDE之后在剛接觸這個Creator時有很多的不習(xí)慣,但QT要做到更大可能的跨平臺支持,有一個統(tǒng)一的IDE和編譯環(huán)境也是必要的,另外,Nokia也提供了Addons以以VS或者Eclipse IDE集成。并且,在新的1.3版Creator上還將使用一個叫做jom的程序來代替VS默認使用的nmake程序,最終應(yīng)該將會完全擺脫VS吧。
使用硬件加速的OpenVG實現(xiàn)以達到高速的矢量圖形繪制,Nokia打算無視Flash的存在?當(dāng)然,這與“實現(xiàn)自己的Creator”,“使用自己的jom代替nmake”一樣,所有的技術(shù)都要自己來DIY。或許,只有把所有的技術(shù)都掌握在自己手上才是最可靠的。
對觸控系統(tǒng)的支持是未來所有操作系統(tǒng)都必須要具備的,包括Windows7,包括iPhone,包括Android,QT4.6在這一塊上也不甘落后。
QT的野心從其博客上的一篇文章似乎能夠看出點端倪。做游戲,這個跟QT以前所專注的GUI開發(fā)八桿子也打不著的領(lǐng)域也要囊括進來,那還有什么東西的出現(xiàn)是你所不敢想象的呢?
也許,這就是未來的軟件開發(fā)大平臺。
或者,正如QT的一個博客站名一樣:QT Everywhere!
DXSAS : DirectX Standard Annotations and Semantics,DirectX引入的一項在Shader代碼與應(yīng)用程序之間進行數(shù)據(jù)綁定的規(guī)范,當(dāng)出到0.8時被廣泛用于各種應(yīng)用程序中,后來從MS的產(chǎn)品線中神秘消失,有關(guān)DXSAS的規(guī)范文檔被從MSDN中移除,只留下幾頁引用說明。。。
簡單來說,當(dāng)我們在DX中使用Shader的時候,我們會使用一個常量表來設(shè)置各種參數(shù)值,其中最重要的當(dāng)屬世界變換矩陣了。這在用DX寫游戲程序時沒有問題,但是在其他一些Shader編輯工具中問題就出來了,如何設(shè)置這些變量?當(dāng)然,每種工具可以提供自己的方法,比如現(xiàn)在Max,Maya都提供了自己的方法在Shader中綁定世界變換矩陣,但問題是每種工具提供的方法都不一樣,這樣寫出來的Shader文件就麻煩了。。。
于是,MS這時站出來,提出了一個標準:DXSAS。這是目前還能找到的DXSAS的一段描述:
Standard annotations and semantics (DXSAS) provide a method of using shaders in a standard way that enables shaders to be used with tools, applications, and game engines. DXSAS defines a set of semantics and annotations that are attached to host application values and effect parameters for the purpose of sharing effects.
地址:http://msdn.microsoft.com/en-us/library/bb173004(VS.85).aspx
有標準是好事,而且我們也能看到,大量的Shader工具及游戲引擎也使用到了SAS,比如FXComposer,比如RenderMonkey,比如CryEngine。。。當(dāng)然,各工具可能對SAS都會有自己的擴展,但大部分還都是按照標準來的。
可是,為什么MS突然就將這標準移除了。。。而且,沒有任何理由的。。。以至于FXComposer1.8版本以前的文檔中附帶的SAS描述章節(jié)也跟著一并刪除,我在FXComposer2.5上找遍了整個手冊也沒找到這個 WorldViewProjection 從哪里來,翻遍了MSDN上HLSL有關(guān)的內(nèi)容也沒有看到這幾個關(guān)鍵字。無奈Google之,原來受此困惑的人還真不少。
好在,Nvidia推出了一份新的文檔,描述SAS的使用方法,或許Nvidia也很困惑,“which came from DirectX 9, and are sometimes hard to find”。。。但是新的FXComposer手冊中對這些只字未提卻是我仍然很困惑的,對于像我這樣的一個新手來說,完全不可能知道這些東西是如何來的,如何去找這些Semantics的定義。
Nvidia網(wǎng)站上的SAS說明文檔:http://developer.nvidia.com/object/using_sas.html
以及FXComposor官方論壇上置頂?shù)年P(guān)于SAS文檔的說明貼,當(dāng)時我竟然沒看到這個置頂貼 :( http://developer.nvidia.com/forums/index.php?showtopic=1358
其他人提出的一些相關(guān)疑問:
http://developer.nvidia.com/forums/index.php?showtopic=750
http://developer.nvidia.com/forums/index.php?showtopic=31
http://developer.nvidia.com/forums/index.php?showtopic=1061
http://developer.nvidia.com/forums/index.php?showtopic=1347
http://developer.nvidia.com/forums/index.php?showtopic=1394
留下這些記錄,也許有跟我一樣的初哥們,少點困惑 :)
看到CppBlog上翻譯的一篇游戲主循環(huán),想起之前也看到過一篇類似的文章,因為筆記本上第一篇記錄就是這個主循環(huán)的簡短翻譯,對比了一下,發(fā)現(xiàn)這篇文章對實現(xiàn)細節(jié)的描述更多一些,也發(fā)上來與大家共享。
這篇文章最早是出現(xiàn)在flipcode的論壇上,地址在這里,后來有人整理了一下,并添加了更多的描述,也就是下面的內(nèi)容。原貼地址在這里。
文章中關(guān)于網(wǎng)絡(luò)的描述是指局域網(wǎng)環(huán)境下的情況,另外這個主循環(huán)也沒有考慮到windows環(huán)境下與Windows Message Loop的結(jié)合,如果是應(yīng)用在windows環(huán)境下,可以再參考下這里,把兩者結(jié)合基本上就差不多了。
翻譯并未嚴格遵照原文,為了讀起來流暢,很多句子都是按照我個人的理解來描述。
This article is about a way of structuring a game's main loop. It includes techniques for handling view drawing with interpolation for smooth animation matched to the frame-rate with fixed-step game logic updating for deterministic game logic. A lot of this is still pretty much a work-in-progress as I muddle my way through, learning better ways of doing things or new tricks to add to my bag, so please bear with me.
這篇文章描述的是如何組織游戲主循環(huán)的一種方法。內(nèi)容包括了如何處理平滑的動畫繪制,并且能夠根據(jù)當(dāng)前幀率做正確的動畫插值,另外還要保證固定的游戲邏輯更新幀率,以確保游戲邏輯的計算結(jié)果是確定的。
這些內(nèi)容的實現(xiàn)有很多都還在進行中,我也在不斷地學(xué)習(xí)更好的方法,以及將一些新的技巧添加進來,所以,希望能夠給我一些耐心與寬容。
The heart of a game, any game, is the game loop. This is where the action takes place, where the guns fire and the fireball spells fly. In some games, the concept of the game loop may be diffused among different components or game states, which implement their own version of the game loop to be exectued at the proper time, but the idea is still there.
任何游戲的核心都是游戲主循環(huán)。游戲的動作執(zhí)行、子彈的射擊以及火球魔法的飛行等等都是在這里實現(xiàn)。
在一些游戲中,你可能會找不到一個唯一的游戲主循環(huán),取而代之的是,你會在一些組件及狀態(tài)機中找到各個不同版本的主循環(huán)。
其實這個原理也是一樣的,只不過是把原來的一個主循環(huán)拆分成了多個,這樣可以控制游戲在不同的時間及狀態(tài)下執(zhí)行不同的循環(huán)過程。
The game loop is just that: a loop. It is a repeating sequence of steps or actions which are executed in a timely and (hopefully) efficient manner, parceling out CPU time to all of the myriad tasks the game engine is required to perform: logic, physics, animation, rendering, handling of input. It must be constructed in a deterministic, predictable fashion so as to give expected behavior on a wide array of hardware configurations. Classic failures in this regard include old pre-Pentium DOS-based games that were synchronized to run well on old hardware, but which did not have the controls in place to control the speed on newer hardware, and consequently ran so rapidly that they became unplayable on new hardware. With such a broad diversity of hardware as now exists, there must be tighter controls on the game loop to keep it running at a consistent speed, while still taking advantage of more powerful hardware to render smoother animation at higher framerates.
簡單來說,游戲主循環(huán)就是一個循環(huán)過程。
在這個不斷重復(fù)執(zhí)行的過程中,我們需要把CPU時間按照一定的規(guī)則分配到不同的任務(wù)上,這些任務(wù)包括:邏輯、物理、動畫、渲染、輸入處理等等。
游戲的主循環(huán)必須保證是以一種確定的、可預(yù)測的方式來執(zhí)行,這樣才能在大量的不同硬件配置環(huán)境下都得到我們所期望的相同行為。
以前的DOS游戲曾經(jīng)出現(xiàn)過這樣的問題,它們在舊的硬件上運行的很好,但是放到新的硬件上以后就失去控制了,游戲的運行速度變的如此之快,以至于根本無法去玩它。
現(xiàn)在市場上存在這么多的硬件種類,所以就必須要緊緊地控制住游戲的主循環(huán),保證他們以一個固定的速度運行,但同時又能獲得這些強大的硬件所帶來的好處:以盡可能高的幀率來渲染出更平滑的動畫。
Older games frequently tied the rendering of the view very closely to the game loop, drawing the view exactly once per logic update and waiting for a signal from the display system indicating a vertical retrace period, when the electron gun in the CRT monitor was resetting after drawing the screen. This synchronized loops to a predictable rate based on the refresh rate of the monitor, but with the advent of customizable refresh settings this leads again to unpredictable loop behavior. Retrace synchronization is still useful, especially to avoid visual artifacts when rendering the view, but is less useful as a means for synchronizing the game logic updating, which may require finer control.
以前的游戲經(jīng)常將渲染過程與游戲循環(huán)緊密地綁在一起,首先執(zhí)行一次邏輯更新,然后繪制畫面,接著等待顯示系統(tǒng)觸發(fā)一個垂直同步信號,之后就是下一輪循環(huán)周期:邏輯更新、渲染、等待……周而復(fù)始。
這種同步的循環(huán)方法在顯示器的刷新率可預(yù)測的情況下是有效的,但是當(dāng)可以自定義刷新率以后,這種行為又變得不可預(yù)測了。
垂直同步仍然是有用的,尤其是在避免畫面的渲染出現(xiàn)撕裂的情況下,但是用來同步游戲的邏輯更新就沒多大用了,這時可能需要更好的控制方法。
The trick, then, is to separate game logic from rendering, and perform them in two separate sub-systems only marginally tied to each other. The game logic updates at it's own pace, and the rendering code draws the screen as fast as it possibly with the most accurate, up-to-date data the logic component can provide.
這種方法就是將游戲邏輯更新與屏幕渲染過程分離開,將他們放到兩個分離的子系統(tǒng)中去處理,只是在需要的時候才與另一個打交道。
游戲的邏輯更新嚴格按照計劃來執(zhí)行,但是屏幕渲染則以它所能達到的最大速率來進行。
The system I am accustomed to using is based on a Tip of the Day ( http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-MainLoopTimeSteps&forum=totd&id=-1 ) posted to http://www.flipcode.com by Javier Arevalo. It implements a loop wherein the game logic is set to update a fixed number of times per second, while the rendering code is allowed to draw as rapidly as possible, using interpolation to smooth the transition from one visual frame to the next.
這里描述的方法基于Javier Arevalo發(fā)表在flipcode Tip of the Day 上的代碼來實現(xiàn)。
在這個游戲主循環(huán)里,游戲邏輯更新被設(shè)置為每秒執(zhí)行固定次數(shù),但同時渲染代碼被允許執(zhí)行盡可能多次,并且還使用了插值來使得兩個渲染幀之間的動畫變化盡可能的平滑。
Briefly, here is the code. I will then attempt in my own crude fashion to explain the workings, though I suggest you check out the original tip at the above link to read Javier's explanation, as well as the forum posts accompanying it which offer up insights and suggestions on how the performance of the loop may be improved.
閑話少說,下面首先是代碼,然后我會簡單的按我的方式描述一下代碼的工作原理,同時我建議你閱讀一下上面鏈接地址所給出的內(nèi)容,其中有Javier的解釋,并且論壇上的回貼也有一些不錯的內(nèi)容,包括別人的評論和一些關(guān)于如何提高效率的建議。
(注:flipcode論壇早就已經(jīng)關(guān)閉,上面的鏈接地址已經(jīng)失效,flipcode上只保留有一些優(yōu)秀內(nèi)容的archives,在這里能找到這篇原文,其中包括Javier的解釋)
time0 = getTickCount();
do
{
time1 = getTickCount();
frameTime = 0;
int numLoops = 0;
while ((time1 - time0) > TICK_TIME && numLoops < MAX_LOOPS)
{
GameTickRun();
time0 += TICK_TIME;
frameTime += TICK_TIME;
numLoops++;
}
IndependentTickRun(frameTime);
// If playing solo and game logic takes way too long, discard pending time.
if (!bNetworkGame && (time1 - time0) > TICK_TIME)
time0 = time1 - TICK_TIME;
if (canRender)
{
// Account for numLoops overflow causing percent > 1.
float percentWithinTick = Min(1.f, float(time1 - time0)/TICK_TIME);
GameDrawWithInterpolation(percentWithinTick);
}
}
while (!bGameDone);
Structurally, the loop is very simple. The above snippet of code can encapsulate the entire workings of your game.
從結(jié)構(gòu)上來說,這個主循環(huán)非常簡單。上面的代碼片段基本上能夠囊括你的游戲的整個工作過程。
First of all, the main loop portion is embodied as the do{} while(!bGameDone); block. This causes the loop to run endlessly, until some game condition indicates that it is finished and it is time to exit the program, at which point the loop ends and the game can be properly shut down. Each time through the loop, we perform game logic updates, input updating and handling, and rendering. Now, for a breakdown of the sections of the loop.
首先,主循環(huán)的執(zhí)行過程被包在do…while循環(huán)塊中,這使得游戲主循環(huán)將永不結(jié)束地運行,直到游戲明確地被告知需要結(jié)束并且退出程序時為止。
在每次進入循環(huán)的時候,我們會執(zhí)行游戲邏輯的更新,輸入更新與處理,還有渲染。接下來,把循環(huán)分為幾個片段來描述。
time1 = getTickCount();
frameTime = 0;
int numLoops = 0;
while ((time1 - time0) > TICK_TIME && numLoops < MAX_LOOPS)
{
GameTickRun();
time0 += TICK_TIME;
frameTime += TICK_TIME;
numLoops++;
}
This portion is the game logic update sequence that forces the game logic (physics updates, object motion, animation cycling, etc...) to update a set number of times per second. This rate is controlled by the TICK_TIME constant, which specifies the number of milliseconds the logic update is supposed to represent in real time. It probably won't take that long to perform, in which case the update won't be performed again until enough time has passed. For example, with TICK_TIME=40, each logic represents 40 milliseconds, thus forcing the code to update game objects at a rate of 25 times per second.
這部分代碼處理游戲邏輯的更新,并且強制要求游戲邏輯每秒執(zhí)行固定次數(shù)。
游戲的邏輯處理包括物理更新、對象行為、動畫循環(huán)等等。更新速率通過TICK_TIME常量指定,其含義為兩次邏輯更新的時間間隔,即經(jīng)過TICK_TIME后應(yīng)該再次進行更新,而不是說一次邏輯更新要持續(xù)這么長時間。
例如,TICK_TIME = 40,其含義為每次游戲邏輯更新后表現(xiàn)40毫秒,這將使得每秒游戲?qū)ο髸桓?5次。
The logic is encapsulated in it's own while loop. It is possible during a given frame that game logic will take too long. If a logic update cycle goes overtime, we can delay rendering for a bit to give ourselves a little extra time to catch up. The while loop will continue to process game logic updates until we are no longer overtime, at which point we can go ahead and continue on with drawing the view. This is good for handling the occasional burp in logic updating, smoothing out the updates and keeping them consistent and deterministic; but in the case that the logic repeatedly goes overtime, it is possible to accumulate more time-debt than the loop can handle. Thus, the MAX_LOOPS constant is in place to dictate a maximum number of times the loop can repeat to try to catch up. It will force the loop to dump out periodically to handle other tasks such as input handling and rendering. A loop that is constantly running at the MAX_LOOPS limit runs like hell and is about as responsive as a tractor with four flat tires, but at least it keeps the loop operating, allowing the user to pass input to terminate the program. Without the MAX_LOOPS failsafe, it would be entirely possible for a slow computer to lock up with no way to exit as it chokes on the loop, trying to catch up but getting further and further behind.
邏輯更新的代碼被包在他自己的while循環(huán)中。
可能在某一幀里游戲邏輯的處理時間會非常長,甚至?xí)瑫r,這時我們可以稍稍暫停一下屏幕的渲染,使得游戲邏輯更新能夠在這段時間里趕上來。
這個while循環(huán)就是用來讓游戲邏輯繼續(xù)更新,直到我們不再超時,之后我們繼續(xù)游戲的主循環(huán)并且進行屏幕渲染。這可以很好地處理突發(fā)的邏輯更新超時,使得我們的更新更加平滑,并保證邏輯的一致性和可預(yù)測性。
但是如果游戲邏輯處理持續(xù)地超時,甚至使得我們的主循環(huán)無法處理過來,這時MAX_LOOPS將會起到作用,他將使游戲控制權(quán)從邏輯更新中跳出來,去執(zhí)行如輸入處理和屏幕渲染等其他任務(wù)。
MAX_LOOP常量限制了這里的while循環(huán)用來追趕邏輯處理時間時最多能重復(fù)的次數(shù)。這樣當(dāng)游戲真的出現(xiàn)完全無法處理完邏輯更新的時候,用戶也有機會結(jié)束程序。
如果沒有MAX_LOOP的檢測,很有可能會出現(xiàn)一臺很慢的電腦試圖追上邏輯處理時間,但是卻越追越遠,而又沒有機會退出這個過程,最后陷在了這個死循環(huán)中……
IndependentTickRun(frameTime);
This section is where input is gathered, events are pumped from the event queue, interface elements such as life bars are updated, and so forth. Javier allows for passing how much time the logic updates took, which can be used for updating on-screen clock or timer displays and the like if necessary. I've never found occasion to use it, but I regularly pass it anyway on the off-chance I'll need it someday. frameTime basically gives the amount of time that was spent in the logic loop performing updates.
這部分代碼用來處理用戶輸入的捕獲,事件會從事件隊列中被取出來處理,界面元素,如血條等,會在這里被更新,還有其他類似的處理。
Javier在這里留了一個frameTime參數(shù),用來指明邏輯更新所花的時間。可以用這個值來更新游戲屏幕上的時鐘或定時器等類似信息。
雖然我目前還沒有找到機會用它,但我還是習(xí)慣性地把它帶上了,也許某天我會需要。
In order for the game loop to run predictably, you should not modify anything in this step that will affect the game logic. This portion of the loop does not run at a predictable rate, so changes made here can throw off the timing. Only things that are not time-critical should be updated here.
為了使游戲循環(huán)的運行是可預(yù)測的,你不應(yīng)該在這里修改任何可能影響游戲邏輯的東西,因為此部分在游戲主循環(huán)中的執(zhí)行次數(shù)是不可預(yù)測的,所以在這里只能做一些時間無關(guān)的更新。
// If playing solo and game logic takes way too long, discard pending time.
if (!bNetworkGame && (time1 - time0) > TICK_TIME) time0 = time1 - TICK_TIME;
This is where we can shave off our time debt if MAX_LOOPS causes us to dump out of the logic loop, and get things square again--as long as we are not running in a network game. If it is a single-player game, the occasional error in the timing of the game is not that big of a deal, so sometimes it might be simpler when the game logic overruns it's alloted time to just discard the extra time debt and start fresh. Technically, this makes the game "fall behind" where it should be in real time, but in a single player game this has no real effect. In a network game, however, all computers must be kept in synchronization, so we can't just cavalierly discard the pending time. Instead, it sticks around until the next time we enter the logic update loop, where the loop has to repeat itself that many more times to try to catch up. If the time burp is an isolated instance, this is no big deal, as with one or two cycle overruns the loop can catch up. But, again, if the logic is consistently running overtime, the performance of the game will be poor and will lag farther and farther behind. In a networked game, you might want to check for repeated bad performance and logic loop overruns here, to pinpoint slow computers that may be bogging the game down and possibly kick them from the game.
當(dāng)由于滿足了MAX_LOOP條件而跳出邏輯循環(huán)時,可以在這里減掉多加的上TICK_TIME時間,并且只在單機游戲時才這樣做。
如果是在單機游戲中,偶爾出現(xiàn)時間上的錯誤是不會有什么大問題的,所以當(dāng)游戲邏輯執(zhí)行超時后也沒有多大關(guān)系,我們簡單的把多花的時間減掉,然后重新開始。從技術(shù)上來說,這會使得游戲有一點點時間上的落后,但在單機游戲里這不會有什么實際的影響。
但是在網(wǎng)絡(luò)游戲中這樣做卻不行,所有連網(wǎng)的電腦都必須要保持時間上的同步。
在網(wǎng)絡(luò)游戲中,如果某臺電腦落后了,他應(yīng)該保持其落后的狀態(tài),然后在下一次進入邏輯更新循環(huán)時,自己讓自己多重復(fù)幾次,以便追趕上來。
如果時間延遲只是個孤立事件,這將不會有多大問題,經(jīng)過一兩次超速就會追趕上來,但是如果游戲邏輯更新總是超時,游戲的表現(xiàn)將會非常糟糕,并且最終將會越來越滯后。
在網(wǎng)絡(luò)游戲中,你可能需要檢查出這些持續(xù)超時,表現(xiàn)總是很差的電腦,并將這些可能拖慢整個游戲環(huán)境的電腦踢出去。
// Account for numLoops overflow causing percent > 1.
float percentWithinTick = Min(1.f, float(time1 - time0)/TICK_TIME);
GameDrawWithInterpolation(percentWithinTick);
This is where the real magic happens, in my opinion. This section performs the rendering of the view. In the case of a loop where TICK_TIME=40, the logic is updating at 25 FPS. However, most video cards today are capable of far greater framerates, so it makes no sense to cripple the visual framerate by locking it to 25 FPS. Instead, we can structure our code so that we can smoothly interpolate from one logic state to the next. percentWithinTick is calculated as a floating point value in the range of [0,1], representing how far conceptually we are into the next game logic tick.
在這里我們將進行屏幕繪制。
當(dāng)TICK_TIME = 40時,邏輯更新幀率為25FPS,但是現(xiàn)在大多數(shù)顯卡都能支持更高的渲染幀率,所以我們沒必要反而鎖定渲染幀率為25FPS。
我們可以組織我們的代碼,讓我們能夠平滑的從一個邏輯狀態(tài)到下一個狀態(tài)做插值。percentWithinTick為一個0到1之間的浮點數(shù),表示我們應(yīng)該向下一個邏輯幀走多遠。
Every object in the game has certain state regarding LastTick and NextTick. Each object that can move will have a LastPosition and a NextPosition. When the logic section updates the object, then the objects LastPosition is set to it's currentNextPostion and a new NextPosition is calculated based on how far it can move in one logic frame. Then, when the rendering portion executes, percentWithinTick is used to interpolate between these Last and Next positions:
每個可移動的對象都有LastPosition和NextPosition。邏輯更新部分的代碼在執(zhí)行時會將對象的LastPosition設(shè)置為當(dāng)前的NextPosition,再根據(jù)它每一幀所能移動的距離來計算出NextPosition。
然后,在渲染對象的時候,可以再用percentWithTick來在Last和Next位置之間進行插值。
譯注:
time0為最后一個邏輯幀所在的時間點,time1為當(dāng)前實際時間,(time1 – time0) / TICK_TIME表示當(dāng)前時間比最后一個邏輯幀所在時間超出了多少百分比,用這個百分比來向下一邏輯幀做插值。
如果機器比較快,在兩個邏輯更新時間點之間執(zhí)行了多次屏幕渲染,這樣插值就有效了。此時time0不變,time1一直在增長,可以根據(jù)增長的百分比來計算動畫應(yīng)該從最后一次執(zhí)行邏輯更新的位置向下一次邏輯更新所在的位置走多遠。
也就是上文所說的,在Last和Next位置之間進行插值。插值后的實際位置,即DrawPosition的計算方法如下:
動畫播放的插值也是類似。
DrawPosition = LastPosition + percentWithinTick * (NextPosition - LastPosition);
The main loop executes over and over as fast as the computer is able to run it, and for a lot of the time we will not be performing logic updates. During these loop cycles when no logic is performed, we can still draw, and as the loop progresses closer to the time of our next logic update, percentWithinTick will increase toward 1. The closer percentWithinTick gets to 1, the closer the a ctual DrawPosition of the object will get to NextPosition. The effect is that the object smoothly moves from Last to Next on the screen, the animation as smooth as the hardware framerate will allow. Without this smooth interpolation, the object would move in a jerk from LastPosition to NextPosition, each time the logic updates at 25FPS. So a lot of drawing cycles would be wasted repeatedly drawing the same exact image over and over, and the animation would be locked to a 25FPS rate that would look bad.
游戲的主循環(huán)以電腦所能夠達到的最大速度不停地運行,在大多數(shù)時間里,我們將不需要執(zhí)行邏輯更新。
但是在這些不執(zhí)行邏輯更新的周期里,我們?nèi)匀豢梢詧?zhí)行屏幕渲染。當(dāng)循環(huán)的進程越接近我們的下一次邏輯更新時間,percentWithinTick就接近1;percentWithinTick越接近1,DrawPosition的位置就越接近NextPosition。
最后的效果就是游戲?qū)ο笤谄聊簧下摹⑵交貜腖ast位置移動到Next位置,動作將以硬件幀率所能允許的程度盡可能的平滑。
如果沒有這個平滑插值過程,對象位置將會從上一幀所在的LastPosition直接跳到下一幀所在的位置NextPosition。大量的渲染周期都被浪費在把對象反復(fù)渲染到相同的位置上,并且動畫也只能被鎖定在25FPS,使得看起來效果非常差。
With this technique, logic and drawing are separated. It is possible to perform updates as infrequently as 14 or 15 times per second, far below the threshold necessary for smooth, decent looking visual framerate, yet still maintain the smooth framerate due to interpolation. Low logic update rates such as this are common in games such as real-time strategy games, where logic can eat up a lot of time in pathfinding and AI calculations that would choke a higher rate. Yet, the game will still animate smoothly from logic state to logic state, without the annoying visual hitches of a 15FPS visual framerate. Pretty danged nifty, I must say.
使用了這項技術(shù)之后,邏輯更新與屏幕渲染被分離開了。
這將允許我們把邏輯更新幀率降低到14或15FPS,這遠遠低于平滑的動畫渲染所需要的幀率,但是在使用動畫插值之后卻仍然能維持平滑的渲染幀率。
在實時策略類游戲中可能會使用這樣低的邏輯更新幀率,這里邏輯更新會因?qū)ぢ泛虯I計算而占用大量的時間,在這種情況下使用高的邏輯更新幀率顯然不行。
但是,游戲卻仍然能夠在不同的邏輯狀態(tài)之間做平滑的動畫過渡,不會因為只有15FPS的渲染幀率而出現(xiàn)那些令人生厭的動畫跳躍現(xiàn)象。
非常的漂亮,我不得不說。
I've created a simple program in C to demonstrate this loop structure. It requires SDL ( http://www.libsdl.org ) and OpenGL. It's a basic bouncy ball program. The controls are simple: Press q to exit the program or press SPACE to toggle interpolation on and off. With interpolation on, the loop executes exactly as described to smooth out the movement from one logic update to the next. With interpolation off, the interpolation factor percentWithinTick is always set to 1 to simulate drawing without interpolation, in essence locking the visual framerate to the 25FPS of the logic update section. In both cases, the ball moves at exactly the same speed (16 units per update, 25 updates per second), but with interpolation the motion is much smoother and easier on the eyes. Compile and link with SDL and OpenGL to see it in action: http://legion.gibbering.net/golem/files/interp_demo.c