TweeJump
这篇教程简单描述了如何使用Cocos2d-XNA来制作一个简单的WP7游戏。你可以按照教程一步步来,或者干脆直接跳到文章的最后,下载SimpleGame。
下载并安装Cocos2d-XNA
- 你可以从下面的链接来下载Cocos2d-XNA的源文件
Cocos2d-XNA主要文件作用:
install-template-mscs.msi:模板安装程序
cocos2d-xna:主项目
CocosDenshion:声音音效
Cocos2d.Framework、Cocos2d.Content.Pipeline.Importers:支持文本类型资源(*.fnt、*.tmx、*.plist)
HelloCocos2d:示例工程
Tests :功能演示
- 安装模板
Next Next ..完成安装中间如果有出现用户账户控制提示选择是然后继续Next..完成安装
接下来就能够创建cocos2d-xna工程了。
Hello, Cocos2D-XNA!
启动cocos2d-xna.sln 添加新项目选择XNA Game Studio 4.0节点底下的 Cocos2d-xna Application,给项目起个名字叫TweeJump。
Ok后,这里会弹出一个对话框
我们确认就好了选择ok (OpenXLive是Windows Phone 7上的游戏竞技和社交网络SNS平台,允许开发者以最小的工作量为自己的游戏增加游戏竞技服务和社交网络SNS功能。OpenXLive是由Fulcrum Mobile Networks, Inc.开发运营的。同类的应用还有iPhone上的OpenFeint和Plus+等。)www.openxlive.com
我们将创建好的工程设置为启动项,如下图:
F5运行,Cocos2D-XNA的HelloWorld程序,启动游戏账号售卖模拟器,程序运行界面如下:
默认工程里面只有一个场景HelloWorldScene,除了多了大厅、积分榜、成就和示例代码HelloCocos2d没有什么不同。
cocos2d是按照scene的概念组织的,游戏是由多个scene切换完成的。游戏场景一般是指在某个时刻能独立运行的部分,其中包括可见的游戏角色,地形和不可见的逻辑脚本等。例如,一个游戏的某个特定关卡,游戏菜单和过场动画等,都是一个独立的场景。cocos2d中的场景又由不同的层(CCLayer)组成。 TweeJump需要主菜单(MainMenu)、游戏画面(Game)、游戏结束画面(GameOver)三个scene来完成我们的游戏逻辑,游戏的流程如下:进入游戏>>主菜单选单play>>游戏画面开始游戏>>游戏结束呼出GameOver画面>> again>>游戏画面。
Cocos2d-XNA基础介绍
下面介绍一下TweeJump中主要用到的Cocos2d-XNA的类。
CCDirector负责管理场景和切换场景游戏暂停等。
CCNode是Cocos2d-XNA中最重要的对象。CCNode的addChild()方法,我个人认为是最重要的方法。它充当了一个容器的角色可以addChild进去无数个节点,但每个节点只有一个父节点,同时他可以执行回调函数和CCAction有postion,scale,rotation等等属性。
CCLayer,它是CCNode的子类,层是一个可以绘制的区域.可以将ui,sprite等对象添加到其中。
CCMenu从CClayer派生而来,可以处理输入消息,CCMenu包含多个CCMenuItem对象,在接收到输入消息之后,根据触摸位置,将输入消息分发到相应MenuItem,执行回调函数,CCMenu还提供一个对齐菜单项的功能
CCSprite, 可以看成是某一时刻,一个2D的图片的一个剪辑部分
添加我们游戏的背景
TweeJump游戏中的背景都是蓝天白云,为了重用我们把它提取成父类Main,主菜单MainMenu、游戏画面Game、结束画面GameOver只要继承它就蓝天白云了。
在Main中涂写画画出萌萌的蓝天白云,为了方便管理游戏中用到的类都尽量建到Classes文件夹中,新建类Main:
让Main继承CCLayer并重写init()方法
public class Main : CCLayer
{
//调整素材比例
public const float sy = 1.666666666666667f;
public const float sx = 1.5f;
public static void Scale(CCNode sprite)
{
sprite.scaleY = sy;
sprite.scaleX = sx;
}
public override bool init()
{
if (!base.init())
{
return false;
}
//@todo
return true;
}
}
先把蓝天贴到@todo哪里:
CCSpriteBatchNodespriteManager=CCSpriteBatchNode.batchNodeWithFile("Images/sprites", 10);
addChild(spriteManager, -1, (int)tags.kSpriteManager);
CCSpritebackground=CCSprite.spriteWithTexture(spriteManager.Texture, newCCRect(0, 0, 320, 480));
spriteManager.addChild(background);
Scale(background);
background.position=newCCPoint(240, 400);
//this.initClouds(); 初始化云
//this.schedule(step); 让云变得可爱点
把tags枚举放到类的外面
public enum tags
{
kSpriteManager = 0,
kBird,
kScoreLabel,
kCloudsStartTag = 100,//数值的意义是分出段来
kPlatformsStartTag = 200,
kBonusStartTag = 300
}
虽然只是添加了蓝天但还是先来看下效果吧,运行前需要修改下Scene的入口点。在
AppDelegate.cs中的applicationDidFinishLaunching()方法里找到下面代码并修改它:
// create a scene. it's an autorelease object
CCScene pScene = TweeJumpScene.scene();
//run
pDirector.runWithScene(pScene);
现在需要把pScene实例化为我们的Main,但是不好的事情是我们的Main.cs是一个CCLayer并不是CCScene,实现代码如下:
CCScene pScene = CCScene.node();
pScene.addChild(Tweejump.Classes.MainMenu.node());
在Main.cs里还需要添加node()方法用来调用init()方法完成初始化工作
publicstaticnewCCLayernode()
{
Mainret=newMain ();
if (ret.init())
{
returnret;
}
returnnull;
}
F5运行,这也太丑了吧。
因为在游戏中默认是横屏,所以需要在applicationDidFinishLaunching()里加上这句话将屏幕设置为竖屏:
pDirector.deviceOrientation = ccDeviceOrientation.CCDeviceOrientationPortrait;
蓝天贴图ok,解开我们的注释、去掉文字说明、再把云画上去Main我们的背景就ok了。
直接贴代码有点长了为了显得有技术含量少贴,详细查看源代码(cocos2d简单性很容易上手)。
privatevoidinitClouds()
{
currentCloudTag= (int)tags.kCloudsStartTag;
while (currentCloudTag< (int)tags.kCloudsStartTag+kNumClouds)
{
this.initCloud();
currentCloudTag++;
}
this.resetClouds();
}
initClouds()方法他完成了云朵的初始化工作initClouds()里面调用了KNumClouds =12次initCloud()该方法从3块云中随机出块,之后又调用resetClouds()完成云位置初始化,具体方法看源文件。
Main.cs注册了spriteManager并把它添加到了Main这个CCLayer中(addChild()方法),在需要的地方取出spriteManager.Texture的某一部分保存到CCSprite里形成一个新的CCSprite对象,再spriteManager.addChild(CCSprite:) 交给spriteManage统一管理。
在使用的时候通过spriteManager.getChildByTag(tag:)取出相应的sprite进行position的赋值等达到我们需要的贴图或者移动、action等等(position的位置是图片中心点的位置);所以给每个Sprite指定一个唯一而有规则的tag是很重要很方便的(枚举tags的作用)。
通过getChildByTag在spriteManager中遍历需要的sprite进行赋值的操作查看源代码resetXXXX()方法。不光是Main.cs的,在Game中你也能找到initXXXX() resetXXXX()方法。
源代码Solution Explorer截图:
主菜单和结束画面
跳过。。。略过。。。Main.cs总算是水完了,下面来一起学习下Menu和Label的使用,你可以使用它们轻松的完成Tweejump或者你自己游戏的主菜单和GameOver(如果你的游戏不十分复杂的话)。
MainMenu.cs和GameOver.cs都继承自Main.cs因为老爸是李刚的优势已经有了蓝天和白云作为背景。再加上Menu、Labe、Sprite,不废话了下面看下是如何的简单就行了。
重复上面的步骤重写init()添加node()方法,在init()里面贴上下面的代码
CCMenuItem button1 = CCMenuItemImage.itemFromNormalImage(@"Images\loginButton", @"Images\loginButton", this, loginCallback);
Scale(button1);
CCMenuItem button2 = CCMenuItemImage.itemFromNormalImage(@"Images\playButton", @"Images\playButton", this, playCallback);
Scale(button2);
CCMenuItem button3 = CCMenuItemImage.itemFromNormalImage(@"Images\aboutButton", @"Images\aboutButton", this, aboutCallback);
Scale(button3);
CCMenu menu = CCMenu.menuWithItems(button1, button2, button3);
menu.alignItemsVerticallyWithPadding(15f);
menu.position = new CCPoint(240, 257);
this.addChild(menu);
CCMenuItemImage.itemFromNormalImage()前两个参数分别是按下前和按下时的图片资源 (CCSprite),最后一个参数为按下后的回调函数,格式: void Callback(CCObject sender){}。画上我们游戏的Logo补全回调函数的响应,把runWithScene()替换成MainMenu,效果图如下。
GameOver.cs中最终得分的显示是由CCLabelBMFont来实现的,它可以让你的字很个性很酷,贴代码:
CCLabelBMFont scoreLabel =CCLabelBMFont.labelWithString(currentScore.ToString(),
"Fonts/bitmapFont");
scoreLabel.scaleX = sx * 1.5f;
scoreLabel.scaleY = sy * 1.5f;//素材太小了,忽略忽略
addChild(scoreLabel, 5, (int)tags.kScoreLabel);
scoreLabel.position = new CCPoint(240, 450);
游戏效果图,Label3961还不错的分数吧。
bitmapFont是资源文件bitmapFont.fnt如果没有在属性里设置Content Impoter为Text Importer, Content Processor为TextProcessor将会出现编译错误。打开这个文件可以看到它是由等号连接的key value对。把目光放在char id=上32 48 …分别代表空格0123456789,每个char id后的属性描述了这个char在bitmapFont.png上空格0123456789的位置。
.fnt文件和相应的.png文件有相应的位置关系,必须遵循不能改变。.fnt文件同级目录下必须有一个Images文件盛放与之对应的.png文件。
游戏控制-重力感应
这个版本的cocos2d-xna是没有封装重力感应的,我用的是XNA中自带的重力感应,因为Accelerometer它也是事件驱动所以很搭不会出现不兼容的现象,应该在以后版本中也不会对它封装了吧。
1添加Microsoft.Devices.Sensors引用
2创建Accelerometer对象,3注册Accelerometer对象的CurrentValueChanged事件,4启动Accelerometer对象Start()方法来启动重力感应监听。
在注册的事件处理方法中可以通过e.SensorReading.Acceleration.X和e.SensorReading.Acceleration.Y,e.SensorReading.Acceleration.Z来访问当前的加速度的三维偏移值。这里我要提的只有一个,很多教程里都是注册Accelerometer对象的ReadingChanged事件,当你使用的是Windows Phone 7.1 SDK时,VS会提示你ReadingChanged已经过时,当然你是可以用,但是还是建议你使用CurrentValueChanged。TimeBetweenUpdates属性会影响到两次触发CurrentValueChanged事件的时间间隔,所以如果你要设置重力感应的感应时间间隔的话最好还是使用CurrentValueChanged。详细见源代码Game.cs的init()。
集成OpenXLive SDK
OpenXLive的功能:
积分榜
让全世界都知道你是这个游戏中的最强者!积分榜,用来记录你的游戏成绩,让你和全世界的玩家分享你超凡的游戏成绩。
· 游戏成就
一个个游戏成就,像一枚枚勋章,记录了你在游戏中的成长历程。篝火边,用成就,告诉你的朋友,你是如何成为游戏中最强的勇士。
· 社交网络
告诉你,这世界上还有多少兄弟姐妹和你一起在游戏中奋战。找到他们,和他们成为好友,一起开始一段冒险的路程。
· 个人中心
这里有你过去、现在和将来的故事。你的积分、你的成就、你玩过的游戏、你的好友,这是你值得珍藏的一页。
· 云存储
不想让别人发现你在游戏中的秘密?把它放在云端吧。你可以在任何地方,打开尘封的秘密。
· 游戏公告
告诉你游戏中发生的大事件,比如,你成为了NO.1。
如果你在前面的
勾选上了OpenXLive sdk,新建项目中就会我们添加好了引用就可以很方便的使用它。
熟悉XNA的朋友会发现其实我们的游戏引擎Cocos2d-XNA就是一个GameComponent而我们的OpenXLive SDK也是一个GameComponent,打开我们的主游戏类Game1源代码中叫GameMain,就是找到继承于Microsoft.Xna.Framework.Game的类。
对比我们项目TweeJump和示例程序HelloCocos2d的Game1.cs文件,多的几句代码就是集成OpenXLive的方式。
Game1类中字段
//#error Please full your game Secret Key in below code
private string APISecretKey = "Y8eUF6f5xXEGSuw3DkKntbhQ";
XLiveFormManager manager;
Game1构造函数中吧XLiveFormManager实例并Add到Component中
// Create XLive FormManager
manager = new XLiveFormManager(this, APISecretKey);
manager.OpenSession();
// Add XLive FormManager in Components
Components.Add(manager);
这里需要注意的是OpenXLive的GameComponents的Add必须放在Cocos2d-xna的游戏引擎的GameComponents之前。
在LoadContent()里加载资源给OpenXLive SDK UI添加背景和退出UI的事件。
Texture2D background = this.Content.Load<Texture2D>(@"images\OpenXLive");
manager.Background = background;
manager.UIExitingEvent += new EventHandler(manager_UIExiting);
void manager_UIExiting(object sender, EventArgs e)
{
CCDirector.sharedDirector().runningScene.visible = true;
}
如果在新建项目的时候你勾选了OpenXLive SDK这些代码都是默认添加到Game1.cs中的。
下面以MainMenu为例教你在游戏中使用OpenXLive SDK。
init()方法中创建一个按钮
CCMenuItemImage Lobby = CCMenuItemImage.itemFromNormalImage(
@"images\Lobby", @"images\Lobby1", this,
new SEL_MenuHandler(LobbyCallback));
Lobby.position = new CCPoint(0, 20);
CCMenu LMenu = CCMenu.menuWithItems(Lobby);
LMenu.position = new CCPoint(240, 60);
QQ号回调方法:
public virtual void LobbyCallback(CCObject pSender)
{
CCDirector.sharedDirector().pause();
CCDirector.sharedDirector().runningScene.visible = false;
OpenXLive.Forms.XLiveFormFactory.Factory.ShowForm("Lobby");
}
OpenXLive.Forms.XLiveFormFactory.Factory.ShowForm("Lobby");show出我们需要的窗体这里是Lobby,除了”Lobby”还有"Startup"、"Leaderboard"、"Achievements"、"Logon"、"MyCenter"、"FirendsList"、"OnlinePlayer"、"Pause"、 "OpenXLiveGames"。
TweeJump源代码中使用了"Achievements"、"Leaderboard"、"Lobby"这三个常用功能。在Show出窗体后务必把游戏暂停当前Scene隐藏。在回来的时候也务必把游戏开始当前Scene显示。
void manager_UIExitingEvent(object sender, EventArgs e)
{
CCDirector.sharedDirector().runningScene.visible = true;
CCDirector.sharedDirector().resume();
}