背景與前言
現在什么技術火?Android,ios,HTML5,人工智能,雲計算……如此多的技術,而且發展非常快,大家都很迷茫,到底要學什么呢?我也很迷茫,只能走一步算一步。
但是人總是有理想的是吧。我的理想很簡單:一步步實現我的下一個理想。大一的時候,我看了一部電影,叫《社交網絡》,那時的理想就是讓學校找我寫代碼。現在大三了,實現了這個理想,給我配了電腦,配了辦公室。下一個理想,做出一番事業,然后去母校演講。
做為一個男性,本能里應該對游戲感興趣。我也很想寫一個自己的游戲,想想,走進網吧,大家玩的都是你寫的游戲,很有成就感。
再學習了android的cocos2d-x之后,又來研究了一下html5的版本,因為這個版本是有專人維護的,所以以后也不用擔心更新問題。
從哪開始?
很多人學一個技術的時候根本不知道從哪里上手,確實,一個技術最難的應該就是入門了,只要入了門,多花點時間很容易就能掌握,這也正是中國的那句古話:師父領進門,修行在個人。
廢話了這么多,cocos2d-html5(以后簡稱cocos2d吧)怎么入門呢?首先可以看官網(http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Cocos2d-html5),他有一個名叫Getting Started with Cocos2d-html5的文章。一般有一定規模的技術或項目都有這么一個文檔,教你怎么快速的上手,那是不是照着這篇文章做就行了呢?在我寫這篇日志的時候,那篇文章的教程是一個過時的教程,也就是說看那篇文章是沒用的。(一般的項目是可以從這入門的。)
雖然教程過時了,但是它還是給我們指明了一個方向,那就是去看Hello World項目。
Hello World
我認為好的程序員應該養成這樣一個習慣:學習新技術或者開發的時候,從hello world開始。
我們下載cocos2d的包,解壓之后可以看到一個叫做HelloHTML5World的文件。這里面也就是我們第一個要研究的代碼了。
這個項目不需要服務器容器,直接打開index.html就能看到效果。效果其實很簡單,但是哪個游戲不是通過一系列的簡單效果組成的呢?好了,直接看代碼吧。
我們首先要看的是main.js,為什么首先看這個我后面會說的。
它定義了一個cocos2dApp,調用了cc.Application.extend()方法。如果有一定基礎的人應該知道extend的意思,也就是繼承。這個cocos2dApp繼承了cc.Application,關於這個類我們也不多說,用的一般不多,基本只要用到一個方法applicationDidFinishLaunching。看名字就知道,這個方法是在程序加載完成的時候調用的。
在這個方法上面還有一個ctor方法,大家可以猜猜這個方法的作用,對了,就是構造函數。
好了,我們來一步步的解析代碼吧。
首先是ctor,構造函數中傳進來一個scene,這個scene我們后面就會看到。第一步就是調用父類構造函數,這個是需要注意的,很多錯誤就是沒調用父類的構造函數造成的。下面的代碼是一系列的配置,先配置了DEBUG的模式,它是從this.config里取出來的,那這個config是從哪里來的呢?我們會注意到,HelloHTML5World文件夾下還有一個cocos2d.js。這個文件就是配置文件了。繼續往下,我們就直接看注釋吧。
1 cc.initDebugSetting();//初始化debug設置 2 cc.setup(this.config['tag']);//裝載頁面上的canvas,這個tag就是canvas的id 3 //當程序資源在讀取的時候,顯示加載動畫 4 cc.Loader.getInstance().onloading = function () { 5 cc.LoaderScene.getInstance().draw(); 6 }; 7 //加載完了之后,調用下面的方法(實際是調用的run方法) 8 cc.Loader.getInstance().onload = function () { 9 cc.AppController.shareAppController().didFinishLaunchingWithOptions(); 10 }; 11 //提前加載資源 12 cc.Loader.getInstance().preload(g_ressources); 13 再看applicationDidFinishLaunching: 14 // 獲得導演 15 var director = cc.Director.getInstance(); 16 // 設置是否顯示FPS 17 director.setDisplayStats(this.config['showFPS']); 18 // 設置幀率 19 director.setAnimationInterval(1.0 / this.config['frameRate']); 20 // run 21 director.runWithScene(new this.startScene()); 22 return true;
這個cc.Director是一個很重要的類,而且是單例的,每次使用都是getInstance(),這個類我們以后會經常使用,它可以控制游戲的很多東西。這個方法要注意的是最后一定要return true。
最后,new一個實例,傳入一個開始場景(在myapp.js中),開始程序
var myApp = new cocos2dApp(HelloWorldScene);
同學們又會找HelloWorldScene在哪。不急。我們先看cocos2d.js:
1 var d = document; 2 //這個c是一個配置對象,程度很多地方會用到 3 var c = { 4 //0表示不開debug,1表示基本debug,2表示debug全開 5 COCOS2D_DEBUG:2, 6 /** 7 * box2d和chipmunk是兩個物理引擎 8 */ 9 box2d:false, 10 chipmunk:false, 11 //顯示FPS 12 showFPS:true, 13 //幀率 14 frameRate:60, 15 loadExtension:false, 16 //canvas的id 17 tag:'helloWorld', 18 //cocos2d的存放地址 19 engineDir:'http://www.cnblogs.com/cocos2d/', 20 //單獨編譯成一個文件的話,就使用下面的配置 21 //SingleEngineFile:'', 22 //寫的js源文件 23 appFiles:[ 24 'src/resource.js', 25 'src/myApp.js' 26 ] 27 }; 28 window.addEventListener('DOMContentLoaded', function () { 29 //准備加載引擎文件 30 var s = d.createElement('script'); 31 /*********加載文件*******/ 32 //如果是打包成了單文件,則加載單文件 33 if (c.SingleEngineFile && !c.engineDir) { 34 s.src = c.SingleEngineFile; 35 } 36 //否則就啟用jsloader,加載所有的引擎文件,並且加載appFiles里的js文件和main.js 37 else if (c.engineDir && !c.SingleEngineFile) { 38 s.src = c.engineDir + 'platform/jsloader.js'; 39 } 40 else { 41 alert('You must specify either the single engine file OR the engine directory in "cocos2d.js"'); 42 } 43 //s.src = 'Packed_Release_File.js'; //只有一個打包好的文件,就只寫這句就可以了 44 //將配置存到document的ccConfig里 45 document.ccConfig = c; 46 //給script標簽加個id 47 s.id = 'cocos2d-html5'; 48 //將加載文件加到body里 49 d.body.appendChild(s); 50 });
關於這兩個文件,相信大家應該都懂了。但是總覺得,這么復雜的配置,哪里記得住啊,以后要用還得翻以前的舊代碼啊。Cocos2d已經想到了這點。解壓出來的文件中,應該有一個叫template文件夾,這個文件夾里裝的就是cocos2d初始配置的模板。
好了,正戲來了,我們來看看那個HelloWorldScene。這個東西就藏在src文件夾下的myApp.js里。HelloWorldScene在這個文件的最下面。繼承了cc.Scene這個類我們以后也會經常用,它定義了一個場景,我們要重寫onEnter事件。方法里很簡單,創建了一個HelloWorld,進行了初始化init() ,然后調用addChild方法,注意,這個方法以后會頻繁的使用,作用就是將某個對象加入到當前對象的容器中。
我們又得轉鏡頭到Helloworld,它繼承自cc.Layer,這個類我們也會經常用到,它定義了一個層。關於層的概念大家可以參考動畫片的制作,有背景層,道具層,人物層,做游戲也是這樣的,背景一層,建築一層,人物一層,界面一層,等等。
我們直接看代碼:
1 isMouseDown:false,//用於標志鼠標有沒有點下 2 helloLabel:null,//顯示的文字 3 circle:null,//上面創建的圓圈精靈 4 sprite:null,//一張圖片精靈 5 init:function () { 6 var selfPointer = this; 7 ////////////////////////////// 8 // 1. 必須先調用父類構造方法 9 this._super(); 10 ///////////////////////////// 11 // 2. 增加一個關閉菜單,點擊關閉菜單后退出程序 12 // 通過導演獲得窗口的大小 13 var size = cc.Director.getInstance().getWinSize(); 14 // 加一個關閉按鈕 15 var closeItem = cc.MenuItemImage.create( 16 "res/CloseNormal.png", 17 "res/CloseSelected.png", 18 function () { 19 history.go(-1); 20 },this);//點擊時調用后退 21 closeItem.setAnchorPoint(cc.p(0.5, 0.5)); 22 var menu = cc.Menu.create(closeItem);//用按鈕創建一個菜單,可以傳多個item 23 menu.setPosition(cc.PointZero()); 24 this.addChild(menu, 1);//加到層里 25 closeItem.setPosition(cc.p(size.width - 20, 20)); 26 ///////////////////////////// 27 // 3. 加入文字和圖片 28 // 增加一個文字,顯示 "Hello World" 29 // 創建一個label 30 this.helloLabel = cc.LabelTTF.create("Hello World", "Arial", 38); 31 // 放在屏幕正中 32 this.helloLabel.setPosition(cc.p(size.width / 2, 0)); 33 // 加到層中 34 this.addChild(this.helloLabel, 5); 35 //LazyLayer是一個很少刷新的層,用於存放類似logo或者地圖等不需要經常刷新的層 36 var lazyLayer = new cc.LazyLayer(); 37 this.addChild(lazyLayer); 38 // 設置精靈圖片 39 this.sprite = cc.Sprite.create("res/HelloWorld.png"); 40 this.sprite.setPosition(cc.p(size.width / 2, size.height / 2)); 41 this.sprite.setScale(0.5); 42 this.sprite.setRotation(180); 43 lazyLayer.addChild(this.sprite, 0); 44 var rotateToA = cc.RotateTo.create(2, 0);//旋轉動畫 45 var scaleToA = cc.ScaleTo.create(2, 1, 1);//縮放動畫 46 this.sprite.runAction(cc.Sequence.create(rotateToA, scaleToA));//運行動畫 47 this.circle = new CircleSprite();//之前寫的圓圈精靈 48 this.circle.setPosition(cc.p(40, size.height - 60)); 49 this.addChild(this.circle, 2); 50 this.circle.schedule(this.circle.myUpdate, 1 / 60);//刷新的函數和頻率 51 this.helloLabel.runAction(cc.MoveBy.create(2.5, cc.p(0, size.height - 40)));//移動動畫 52 this.setTouchEnabled(true);//!!!設置可以點擊,設置了這個才能點擊 53 this.adjustSizeForWindow();//根據窗口的大小調整自己的尺寸 54 lazyLayer.adjustSizeForCanvas();//根據canvas層調整自己的大小 55 window.addEventListener("resize", function (event) { 56 selfPointer.adjustSizeForWindow();//窗口改變大小時,調整大小 57 }); 58 return true; 59 }
其中的cc.RotateTO,cc.ScaleTo,我們以后再介紹。着重說一下cc.Sprite,這個類是用於創建一個叫精靈的東西,也許大家聽到這個詞語很奇怪,我怎么沒在游戲里看到過精靈?其實,我們控制的玩家本身就是一個精靈,游戲場景的每一個NPC,每個會移動物體都是一個精靈,精靈也是游戲中的最基礎的也是最重要的部件了。關於精靈,我以后會專門用一章來講解它的作用。
后面的方法現在還不需要用到,我們就先不了解。
src下還有一個resource.js。這是干嘛的?打開來看,我們發現它定義了一系列的資源位置和類型,這些資源在cocos2dApp的構造函數中進行預加載,大家看看就懂,我也就不啰嗦了。
結尾
關於這個cocos2d-html5的系列介紹,之后我還計划會講:
1.解析simple中的一個游戲
2.開發一個簡單的游戲
3.物理引擎的介紹
4.開發一個較復雜的游戲