关于自己动手制作小游戏游戏的一方面问题

40947人阅读
&&&&& 本文实践自 Allen Tan 的文章《》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.0.4进行学习和移植。在这篇文章,将会学习到如何制作一个简单的横版格斗过关游戏。在这当中,学习如何跟踪动画状态、碰撞盒、添加方向键、添加简单敌人AI和更多其它的。
步骤如下:
1.新建Cocos2d-win32工程,工程名为&PompaDroid&,去除&Box2D&选项,勾选&Simple Audio Engine in Cocos Denshion&选项;
2.添加游戏场景类GameScene,派生自CCScene类。添加GameLayer类和HudLayer类,派生自CCLayer类。删除HelloWorldScene.h和HelloWorldScene.cpp文件。
3.文件GameScene.h代码如下:
#pragma&once
#include&&cocos2d.h&
#include&&GameLayer.h&
#include&&HudLayer.h&
class&GameScene&:&public&cocos2d::CCScene
&&&&GameScene(void);
&&&&~GameScene(void);
&&&&virtual&bool&init();
&&&&CREATE_FUNC(GameScene);
&&&&CC_SYNTHESIZE(GameLayer*,&_gameLayer,&GameLayer);
&&&&CC_SYNTHESIZE(HudLayer*,&_hudLayer,&HudLayer);
文件GameScene.cpp代码如下:
#include&&GameScene.h&
using&namespace&cocos2d;
GameScene::GameScene(void)
&&&&_gameLayer&=&NULL;
&&&&_hudLayer&=&NULL;
GameScene::~GameScene(void)
bool&GameScene::init()
&&&&bool&bRet&=&false;
&&&&&&&&&CC_BREAK_IF(!CCScene::init());
&&&&&&&&&_gameLayer&=&GameLayer::create();
&&&&&&&&&this-&addChild(_gameLayer,&0);
&&&&&&&&&_hudLayer&=&HudLayer::create();
&&&&&&&&&this-&addChild(_hudLayer,&1);
&&&&&&&&&bRet&=&true;
&&&&}&while&(0);
&&&&return&bR
4.HudLayer类增加一个方法:
CREATE_FUNC(HudLayer);
和GameLayer类增加一个方法:
CREATE_FUNC(GameLayer);
5.修改AppDelegate.cpp文件,代码如下:
//#include&&HelloWorldScene.h&
#include&&GameScene.h&
bool&AppDelegate::applicationDidFinishLaunching()
&&&&//&create&a&scene.&it's&an&autorelease&object
&&&&//CCScene&*pScene&=&HelloWorld::scene();
&&&&CCScene&*pScene&=&GameScene::create();
6.编译运行,此时只是空空的界面。
7.下载本游戏所需资源,将资源放置&Resources&目录下;
8.用Tiled工具打开pd_tilemap.tmx,就可以看到游戏的整个地图:
地图上有两个图层:Wall和Floor,即墙和地板。去掉每个图层前的打钩,可以查看层的组成。你会发现下数第四行是由两个图层一起组成的。每个tile都是32x32大小。可行走的地板tile位于下数三行。
9.打开GameLayer.h文件,添加如下代码:
bool&init();
void&initTileMap();
cocos2d::CCTMXTiledMap&*_tileM
打开GameLayer.cpp,在构造函数,添加如下代码:
_tileMap&=&NULL;
添加如下代码:
bool&GameLayer::init()
&&&&bool&bRet&=&false;
&&&&&&&&CC_BREAK_IF(!CCLayer::init());
&&&&&&&&this-&initTileMap();
&&&&&&&&bRet&=&true;
&&&&}&while&(0);
&&&&return&bR
void&GameLayer::initTileMap()
&&&&_tileMap&=&CCTMXTiledMap::create(&pd_tilemap.tmx&);
&&&&CCObject&*pObject&=&NULL;
&&&&CCARRAY_FOREACH(_tileMap-&getChildren(),&pObject)
&&&&&&&&CCTMXLayer&*child&=&(CCTMXLayer*)pO
&&&&&&&&child-&getTexture()-&setAliasTexParameters();
&&&&this-&addChild(_tileMap,&-6);
对所有图层进行setAliasTexParameters设置,该方法是关闭抗锯齿功能,这样就能保持像素风格。
10.编译运行,可以看到地图显示在屏幕上,如下图所示:
11.创建英雄。在大多数2D横版游戏中,角色有不同的动画代表不同类型的动作。我们需要知道什么时候播放哪个动画。这里采用状态机来解决这个问题。状态机就是某种通过切换状态来改变行为的东西。单一状态机在同一时间只能有一个状态,但可以从一种状态过渡到另一种状态。在这个游戏中,角色共有五种状态,空闲、行走、出拳、受伤、死亡,如下图所示:
为了有一个完整的状态流,每个状态应该有一个必要条件和结果。例如:行走状态不能突然转变到死亡状态,因为你的英雄在死亡前必须先受伤。
12.添加ActionSprite类,派生自CCSprite类,ActionSprite.h文件代码如下:
#pragma&once
#include&&cocos2d.h&
#include&&Defines.h&
class&ActionSprite&:&public&cocos2d::CCSprite
&&&&ActionSprite(void);
&&&&~ActionSprite(void);
&&&&//action&methods
&&&&void&idle();
&&&&void&attack();
&&&&void&hurtWithDamage(float&damage);
&&&&void&knockout();
&&&&void&walkWithDirection(cocos2d::CCPoint&direction);
&&&&//scheduled&methods
&&&&void&update(float&dt);
&&&&//actions
&&&&CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*,&_idleAction,&IdleAction);
&&&&CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*,&_attackAction,&AttackAction);
&&&&CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*,&_walkAction,&WalkAction);
&&&&CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*,&_hurtAction,&HurtAction);
&&&&CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*,&_knockedOutAction,&KnockedOutAction);
&&&&//states
&&&&CC_SYNTHESIZE(ActionState,&_actionState,&ActionState);
&&&&//attributes
&&&&CC_SYNTHESIZE(float,&_walkSpeed,&WalkSpeed);
&&&&CC_SYNTHESIZE(float,&_hitPoints,&HitPoints);
&&&&CC_SYNTHESIZE(float,&_damage,&Damage);
&&&&//movement
&&&&CC_SYNTHESIZE(cocos2d::CCPoint,&_velocity,&Velocity);
&&&&CC_SYNTHESIZE(cocos2d::CCPoint,&_desiredPosition,&DesiredPosition);
&&&&//measurements
&&&&CC_SYNTHESIZE(float,&_centerToSides,&CenterToSides);
&&&&CC_SYNTHESIZE(float,&_centerToBottom,&CenterToBottom);
打开ActionSprite.cpp文件,构造函数如下:
ActionSprite::ActionSprite(void)
&&&&_idleAction&=&NULL;
&&&&_attackAction&=&NULL;
&&&&_walkAction&=&NULL;
&&&&_hurtAction&=&NULL;
&&&&_knockedOutAction&=&NULL;
各个方法实现暂时为空。以上代码声明了基本变量和方法,可以分为以下几类:
Actions:这些是每种状态要执行的动作。这些动作是当角色切换状态时,执行精灵动画和其他触发的事件。
States:保存精灵的当前动作/状态,使用ActionState类型,这个类型待会我们将会进行定义。
Attributes:包含精灵行走速度值,受伤时减少生命点值,攻击伤害值。
Movement:用于计算精灵如何沿着地图移动。
Measurements:保存对精灵的实际图像有用的测量值。需要这些值,是因为你将要使用的这些精灵画布大小是远远大于内部包含的图像。
Action methods:不直接调用动作,而是使用这些方法触发每种状态。
Scheduled methods:任何事需要在一定的时间间隔进行运行,比如精灵位置和速度的更新,等等。
新建一个头文件Defines.h,代码如下:
#pragma&once
#include&&cocos2d.h&
//&1&-&convenience&measurements
#define&SCREEN&CCDirector::sharedDirector()-&getWinSize()
#define&CENTER&ccp(SCREEN.width&/&2,&SCREEN.height&/&2)
#define&CURTIME&do&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\
&&&&timeval&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\
&&&&gettimeofday(&time,&NULL);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\
&&&&unsigned&long&millisecs&=&(time.tv_sec&*&<span style="color:#ff)&&#43;&(time.tv_usec&/&<span style="color:#ff);&\
&&&&return&(float)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\
}&while&(0)
//&2&-&convenience&functions
#define&random_range(low,&high)&(rand()&%&(high&-&low&&#43;&1))&&#43;&low
#define&frandom&(float)rand()&/&UINT64_C(0x)
#define&frandom_range(low,&high)&((high&-&low)&*&frandom)&&#43;&low
//&3&-&enumerations
typedef&enum&_ActionState&{
&&&&kActionStateNone&=&0,
&&&&kActionStateIdle,
&&&&kActionStateAttack,
&&&&kActionStateWalk,
&&&&kActionStateHurt,
&&&&kActionStateKnockedOut
//&4&-&structures
typedef&struct&_BoundingBox&{
&&&&cocos2d::CCRect&
&&&&cocos2d::CCRect&
}&BoundingB
简要说明下:
①.定义了一些便利的宏,如直接使用SCREEN获取屏幕大小;
②.定义了一些便利的函数,随机返回整型或者浮点型;
③.定义ActionState类型,这个是ActionSprite可能处在不同状态的类型枚举;
④.定义BoundingBox结构体,将用于碰撞检测。
打开GameLayer.h文件,添加如下代码:
cocos2d::CCSpriteBatchNode&*_
打开GameLayer.cpp文件,在init函数里面添加如下代码:
CCSpriteFrameCache::sharedSpriteFrameCache()-&addSpriteFramesWithFile(&pd_sprites.plist&);
_actors&=&CCSpriteBatchNode::create(&pd_sprites.pvr.ccz&);
_actors-&getTexture()-&setAliasTexParameters();
this-&addChild(_actors,&-5);
加载精灵表单,创建一个CCSpriteBatchNode。这个精灵表单包含我们的所有精灵。它的z&#20540;高于CCTMXTiledMap对象,这样才能出现在地图前。
添加Hero类,派生自ActionSprite类,添加如下代码:
CREATE_FUNC(Hero);
bool&init();
Hero类的init函数的实现如下所示:
bool&Hero::init()
&&&&bool&bRet&=&false;
&&&&&&&&CC_BREAK_IF(!ActionSprite::initWithSpriteFrameName(&hero_idle_00.png&));
&&&&&&&&int&i;
&&&&&&&&//idle&animation
&&&&&&&&CCArray&*idleFrames&=&CCArray::createWithCapacity(6);
&&&&&&&&for&(i&=&0;&i&&&6;&i&#43;&#43;)
&&&&&&&&&&&&CCSpriteFrame&*frame&=&CCSpriteFrameCache::sharedSpriteFrameCache()-&spriteFrameByName(CCString::createWithFormat(&hero_idle_%02d.png&,&i)-&getCString());
&&&&&&&&&&&&idleFrames-&addObject(frame);
&&&&&&&&CCAnimation&*idleAnimation&=&CCAnimation::createWithSpriteFrames(idleFrames,&1.0&/&12.0);
&&&&&&&&this-&setIdleAction(CCRepeatForever::create(CCAnimate::create(idleAnimation)));
&&&&&&&&this-&setCenterToBottom(39.0);
&&&&&&&&this-&setCenterToSides(29.0);
&&&&&&&&this-&setHitPoints(<span style="color:#ff.0);
&&&&&&&&this-&setDamage(20.0);
&&&&&&&&this-&setWalkSpeed(80.0);
&&&&&&&&bRet&=&true;
&&&&}&while&(0);
&&&&return&bR
我们用初始空闲精灵帧创建了英雄角色,配备了一个CCArray数组包含所有的属于空闲动画的精灵帧,然后创建一个CCAction动作播放来这个动画。以每秒12帧的速率进行播放。接下去,为英雄设置初始属性,包括精灵中心到边到底部的&#20540;。如下图所示:
英雄的每个精灵帧都在280x150像素大小的画布上创建,但实际上英雄精灵只占据这个空间的一部分。所以需要两个测量&#20540;,以便更好的设置精灵的位置。需要额外的空间,是因为每个动画精灵绘制的方式是不同的,而有些就需要更多的空间。
打开GameLayer.h文件,添加头文件声明:
#include&&Hero.h&
GameLayer类添加如下代码:
打开GameLayer.cpp文件,在构造函数添加如下代码:
_hero&=&NULL;
在init函数this-&addChild(_actors, -5);后面添加如下代码:
this-&initHero();
添加initHero方法,代码如下:
void&GameLayer::initHero()
&&&&_hero&=&Hero::create();
&&&&_actors-&addChild(_hero);
&&&&_hero-&setPosition(ccp(_hero-&getCenterToSides(),&80));
&&&&_hero-&setDesiredPosition(_hero-&getPosition());
&&&&_hero-&idle();
创建了一个英雄实例,添加到了精灵表单,并设置了设置。调用idle方法,让其处于空闲状态,运行空闲动画。返回到ActionSprite.cpp文件,实现idle方法,代码如下:
void&ActionSprite::idle()
&&&&if&(_actionState&!=&kActionStateIdle)
&&&&&&&&this-&stopAllActions();
&&&&&&&&this-&runAction(_idleAction);
&&&&&&&&_actionState&=&kActionStateI
&&&&&&&&_velocity&=&CCPointZ
这个idle方法只有当ActionSprite不处于空闲状态才能调用。当它触发时,它会执行空闲动作,改变当前状态到kActionStateIdle,并且把速度置零。
13.编译运行,可以看到英雄处于空闲状态。如下图所示:
14.出拳动作。打开Hero.cpp文件,在init函数idle animation后面,添加如下代码:
//attack&animation
CCArray&*attackFrames&=&CCArray::createWithCapacity(3);
for&(i&=&0;&i&&&3;&i&#43;&#43;)
&&&&CCSpriteFrame&*frame&=&CCSpriteFrameCache::sharedSpriteFrameCache()-&spriteFrameByName(CCString::createWithFormat(&hero_attack_00_%02d.png&,&i)-&getCString());
&&&&attackFrames-&addObject(frame);
CCAnimation&*attackAnimation&=&CCAnimation::createWithSpriteFrames(attackFrames,&1.0&/&24.0);
this-&setAttackAction(CCSequence::create(CCAnimate::create(attackAnimation),&CCCallFunc::create(this,&callfunc_selector(Hero::idle)),&NULL));
打开ActionSprite.cpp文件,实现attack方法,代码如下:
void&ActionSprite::attack()
&&&&if&(_actionState&==&kActionStateIdle&||&_actionState&==&kActionStateAttack&||&_actionState&==&kActionStateWalk)
&&&&&&&&this-&stopAllActions();
&&&&&&&&this-&runAction(_attackAction);
&&&&&&&&_actionState&=&kActionStateA
英雄只有在空闲、攻击、行走状态才能进行出拳。确保英雄正在受伤时、或者死亡时不能进行攻击。为了触发attack方法,打开GameLayer.cpp文件,在init函数添加如下代码:
this-&setTouchEnabled(true);
重载ccTouchesBegan方法,代码如下:
void&GameLayer::ccTouchesBegan(CCSet&*pTouches,&CCEvent&*pEvent)
&&&&_hero-&attack();
15.编译运行,点击屏幕进行出拳,如下图所示:
16.创建8个方向的方向键。我们需要创建虚拟的8个方向的方向键来让英雄在地图上进行移动。添加SimpleDPad类,派生自CCSprite类,SimpleDPad.h文件代码如下:
#pragma&once
#include&&cocos2d.h&
class&SimpleDP
class&SimpleDPadDelegate
&&&&virtual&void&didChangeDirectionTo(SimpleDPad&*simpleDPad,&cocos2d::CCPoint&direction)&=&0;
&&&&virtual&void&isHoldingDirection(SimpleDPad&*simpleDPad,&cocos2d::CCPoint&direction)&=&0;
&&&&virtual&void&simpleDPadTouchEnded(SimpleDPad&*simpleDPad)&=&0;
class&SimpleDPad&:&public&cocos2d::CCSprite,&public&cocos2d::CCTargetedTouchDelegate
&&&&SimpleDPad(void);
&&&&~SimpleDPad(void);
&&&&static&SimpleDPad*&dPadWithFile(cocos2d::CCString&*fileName,&float&radius);
&&&&bool&initWithFile(cocos2d::CCString&*filename,&float&radius);
&&&&void&onEnterTransitionDidFinish();
&&&&void&onExit();
&&&&void&update(float&dt);
&&&&virtual&bool&ccTouchBegan(cocos2d::CCTouch&*pTouch,&cocos2d::CCEvent&*pEvent);
&&&&virtual&void&ccTouchMoved(cocos2d::CCTouch&*pTouch,&cocos2d::CCEvent&*pEvent);
&&&&virtual&void&ccTouchEnded(cocos2d::CCTouch&*pTouch,&cocos2d::CCEvent&*pEvent);
&&&&void&updateDirectionForTouchLocation(cocos2d::CCPoint&location);
&&&&CC_SYNTHESIZE(SimpleDPadDelegate*,&_delegate,&Delegate);
&&&&CC_SYNTHESIZE(bool,&_isHeld,&IsHeld);
protected:
&&&&float&_
&&&&cocos2d::CCPoint&_
对以上的一些声明,解释如下:
radius:圆形方向键的半径。
direction:当前所按下的方向。这是一个矢量,(-1.0, -1.0)是左下方向,(1.0, 1.0)是右上方向。
delegate:方向键的委托,后续进行介绍。
isHeld:布尔&#20540;表示玩家触摸着方向键。
对于SimpleDPad类,使用了委托模式。意味着一个委托类(并非SimpleDPad),将会处理由被委托类(SimpleDPad)启动的任务。在某些你指定的点上,主要是当涉及到处理任何游戏相关的东西,SimpleDPad将会将职责传递给委托类。这使得SimpleDPad无需知道任何游戏逻辑,从而允许你在开发任何其他游戏时,可以进行重用。如下图所示:
当SimpleDPad检测到在方向键内的触摸,它会计算触摸的方向,然后发送消息到委托类指明方向。在这之后的任何事情都不是SimpleDPad所关心的了。为了实施这个模式,SimpleDPad需要至少了解其委托的有关信息,特别是将触摸方向传递给委托的方法。这是另一种设计模式:协议。可以看到SimpleDPad的委托定义了所需的方法,在这种方式中,SimpleDPad强制其委托有三个指定的方法,以便确保每当它想传递东西放到委托中时,它能调用这些方法中的任何一种。事实上,SimpleDPad也遵循一种协议,即CCTargetedTouchDelegate。当SimpleDPad被触摸时,进行处理触摸事件,而GameLayer将不会得到触摸。否则的话,在触摸方向键的时候,英雄就会出拳攻击,显然,这不是希望看到的。打开SimpleDPad.cpp文件,添加如下代码:
#include&&SimpleDPad.h&
using&namespace&cocos2d;
SimpleDPad::SimpleDPad(void)
&&&&_delegate&=&NULL;
SimpleDPad::~SimpleDPad(void)
SimpleDPad*&SimpleDPad::dPadWithFile(CCString&*fileName,&float&radius)
&&&&SimpleDPad&*pRet&=&new&SimpleDPad();
&&&&if&(pRet&&&&pRet-&initWithFile(fileName,&radius))
&&&&&&&&return&pR
&&&&&&&&delete&pR
&&&&&&&&pRet&=&NULL;
&&&&&&&&return&NULL;
bool&SimpleDPad::initWithFile(CCString&*filename,&float&radius)
&&&&bool&bRet&=&false;
&&&&&&&&CC_BREAK_IF(!CCSprite::initWithFile(filename-&getCString()));
&&&&&&&&_radius&=&
&&&&&&&&_direction&=&CCPointZ
&&&&&&&&_isHeld&=&false;
&&&&&&&&this-&scheduleUpdate();
&&&&&&&&bRet&=&true;
&&&&}&while&(0);
&&&&return&bR
void&SimpleDPad::onEnterTransitionDidFinish()
&&&&CCDirector::sharedDirector()-&getTouchDispatcher()-&addTargetedDelegate(this,&1,&true);
void&SimpleDPad::onExit()
&&&&CCDirector::sharedDirector()-&getTouchDispatcher()-&removeDelegate(this);
void&SimpleDPad::update(float&dt)
&&&&if&(_isHeld)
&&&&&&&&_delegate-&isHoldingDirection(this,&_direction);
bool&SimpleDPad::ccTouchBegan(CCTouch&*pTouch,&CCEvent&*pEvent)
&&&&CCPoint&location&=&pTouch-&getLocation();
&&&&float&distanceSQ&=&ccpDistanceSQ(location,&this-&getPosition());
&&&&if&(distanceSQ&&=&_radius&*&_radius)
&&&&&&&&this-&updateDirectionForTouchLocation(location);
&&&&&&&&_isHeld&=&true;
&&&&&&&&return&true;
&&&&return&false;
void&SimpleDPad::ccTouchMoved(CCTouch&*pTouch,&CCEvent&*pEvent)
&&&&CCPoint&location&=&pTouch-&getLocation();
&&&&this-&updateDirectionForTouchLocation(location);
void&SimpleDPad::ccTouchEnded(CCTouch&*pTouch,&CCEvent&*pEvent)
&&&&_direction&=&CCPointZ
&&&&_isHeld&=&false;
&&&&_delegate-&simpleDPadTouchEnded(this);
void&SimpleDPad::updateDirectionForTouchLocation(CCPoint&location)
&&&&float&radians&=&ccpToAngle(ccpSub(location,&this-&getPosition()));
&&&&float&degrees&=&-1&*&CC_RADIANS_TO_DEGREES(radians);
&&&&if&(degrees&&=&22.5&&&&degrees&&=&-22.5)&
&&&&&&&&//right
&&&&&&&&_direction&=&ccp(1.0,&0.0);
&&&&else&if&(degrees&&&22.5&&&&degrees&&&67.5)
&&&&&&&&//bottomright
&&&&&&&&_direction&=&ccp(1.0,&-1.0);
&&&&else&if&(degrees&&=&67.5&&&&degrees&&=&<span style="color:#ff.5)
&&&&&&&&//bottom
&&&&&&&&_direction&=&ccp(0.0,&-1.0);
&&&&else&if&(degrees&&&<span style="color:#ff.5&&&&degrees&&&<span style="color:#ff.5)
&&&&&&&&//bottomleft
&&&&&&&&_direction&=&ccp(-1.0,&-1.0);
&&&&else&if&(degrees&&=&<span style="color:#ff.5&||&degrees&&=&-<span style="color:#ff.5)
&&&&&&&&//left
&&&&&&&&_direction&=&ccp(-1.0,&0.0);
&&&&else&if&(degrees&&&-22.5&&&&degrees&&&-67.5)
&&&&&&&&//topright
&&&&&&&&_direction&=&ccp(1.0,&1.0);
&&&&else&if&(degrees&&=&-67.5&&&&degrees&&=&-<span style="color:#ff.5)
&&&&&&&&//top
&&&&&&&&_direction&=&ccp(0.0,&1.0);
&&&&else&if&(degrees&&&-<span style="color:#ff.5&&&&degrees&&&-<span style="color:#ff.5)
&&&&&&&&//topleft
&&&&&&&&_direction&=&ccp(-1.0,&1.0);
&&&&_delegate-&didChangeDirectionTo(this,&_direction);
以上方法中,onEnterTransitionDidFinish注册SimpleDPad委托类,onExit移除SimpleDPad委托类,update方法是当方向键被触摸时,传递方向&#20540;到委托类。ccTouchBegan方法检测触摸位置是否在方向键圆内,如果是,则将isHeld置为true,并更新方向&#20540;,返回true以拥有触摸事件优先权。ccTouchMoved当触摸点移动时,更新方向&#20540;。ccTouchEnded将isHeld置为false,重置方向,并通知委托触摸结束。updateDirectionForTouchLocation方法计算触摸点到方向键中心距离&#20540;,转换成角度,得到正确的方向&#20540;,然后传递&#20540;到委托。
打开HudLayer.h文件,添加头文件声明:
#include&&SimpleDPad.h&
添加如下代码:
bool&init();
CC_SYNTHESIZE(SimpleDPad*,&_dPad,&DPad);
打开HudLayer.cpp文件,添加如下代码:
HudLayer::HudLayer(void)
&&&&_dPad&=&NULL;
bool&HudLayer::init()
&&&&bool&bRet&=&false;
&&&&&&&&CC_BREAK_IF(!CCLayer::init());
&&&&&&&&_dPad&=&SimpleDPad::dPadWithFile(CCString::create(&pd_dpad.png&),&64);
&&&&&&&&_dPad-&setPosition(ccp(64.0,&64.0));
&&&&&&&&_dPad-&setOpacity(<span style="color:#ff);
&&&&&&&&this-&addChild(_dPad);
&&&&&&&&bRet&=&true;
&&&&}&while&(0);
&&&&return&bR
以上代码实例化SimpleDPad,并且添加到HudLayer上。现在GameScene同时控制GameLayer和HudLayer,但有时候想直接通过HudLayer访问GameLayer。打开GameLayer.h文件,添加头文件声明:
#include&&SimpleDPad.h&
#include&&HudLayer.h&
将GameLayer类声明修改成如下:
class&GameLayer&:&public&cocos2d::CCLayer,&public&SimpleDPadDelegate
并添加以下声明:
virtual&void&didChangeDirectionTo(SimpleDPad&*simpleDPad,&cocos2d::CCPoint&direction);
virtual&void&isHoldingDirection(SimpleDPad&*simpleDPad,&cocos2d::CCPoint&direction);
virtual&void&simpleDPadTouchEnded(SimpleDPad&*simpleDPad);
CC_SYNTHESIZE(HudLayer*,&_hud,&Hud);
以上方法的实现暂时为空。这样我们就在GameLayer中添加了HudLayer的引用,同时还让GameLayer遵循SimpleDPad所创建的协议。打开GameScene.cpp文件,在init函数this-&addChild(_hudLayer,
1);后面,添加如下代码:
_hudLayer-&getDPad()-&setDelegate(_gameLayer);
_gameLayer-&setHud(_hudLayer);
17.编译运行,可以看到左下角的虚拟方向键,如下图所示:
别试着压下方向键,英雄不会有任何反应,因为还未实现协议方法,这在将完成。
参考资料:
1.How To Make A Side-Scrolling Beat ‘Em Up Game Like Scott Pilgrim with Cocos2D – Part 1
2.如何使用cocos2d制作类&#20284;Scott Pilgrim的2D横版&#26684;斗过关游戏part1(翻译)
3.如何使用Cocos2d-x做一DNF类的游戏-part1
非常感谢以上资料,本例子源代码附加资源下载地址:
如文章存在错误之处,欢迎指出,以便改正。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1350864次
积分:17382
积分:17382
排名:第150名
原创:356篇
转载:86篇
评论:2870条
联系方式:
(1)(3)(3)(3)(1)(1)(3)(1)(1)(8)(1)(3)(2)(2)(3)(2)(3)(2)(1)(1)(2)(3)(6)(1)(4)(3)(1)(3)(5)(5)(5)(5)(1)(3)(5)(4)(4)(4)(5)(5)(1)(13)(11)(7)(5)(2)(5)(4)(5)(2)(7)(14)(18)(23)(19)(5)(35)(22)(21)(8)(10)(42)(49)2717人阅读
中国游戏行业市场分析(一)关于国内游戏制作的问题 白玉盘原创原载于《游戏批评》2000.12号
按:象血狮的失败,前导的倒闭都值得一提 图涉足游戏业的公司还有很多,不过全都铩羽而归)1.国内业界制作单位的代表是哪几家?他们各自的代表作及特点是什么? 以制作为自己主攻方向的游戏公司,在中国大陆本来不多。如果不算二○○○年才成立,并且第一个游戏还没有制作完成的那几家新公司,现今还存在的我五个指头就可以数得过来了:金山西山居、目标软件、创意鹰翔、金智塔、深智--刚好五个,而唯一从大陆游戏业发源之处走来的也只有西山居而已(目标虽然九五年就成立了,但实际上正式进入大陆游戏市场还是在九八年,在后面还要谈谈关于目标这家注册为外资的游戏公司是否算大陆游戏制作公司的事)。在网上论坛、业界人士聊天时谈到此事,一些资格老一点的玩家经常也是唏嘘不已,可能九五、九六、九七年金盘、西山居、前导、腾图、尚洋共舞国产游戏大旗时的盛况还依旧留在他们心中吧。那个时候,还有一些只制作了一个游戏或者只做了一半就退出了的公司时进时出,整个业界大约是有总数接近三十家的大陆、台湾、国外游戏制作代理公司在里面翻江倒海(其实那时的大陆游戏市场也根本不能称其为江海,充其量算个重庆嘉陵江就很不错了,只不过上面这样念起来随口一些!)。 话说回来,现在的这几家游戏制作公司既然生存了下来,那他们一定是有着自己的过人之处的,我就一家一家挨着说说: 1. 金山公司西山居游戏工作室,成立于九五年,迄今为止一共制作了六部游戏,代表作是《剑侠情缘Ⅰ、Ⅱ》。西山居最大的优势就在市场上,以求伯君为背景,国产游戏支柱的宣传定位有了先天条件,金山做市场的能力在西山居的游戏上同样表露无疑。游戏的品质一般都属于中或中下,基本上让普通游戏爱好者能接受,不过游戏音乐确算是大陆游戏之冠。在销售方式上也比较灵活,积极开拓各种套装、随机配送市场,能为可持续发展奠定一定经济基础。当然,西山居一直努力控制成本、金山不是靠游戏为生、求伯君的游戏情结等等也是西山居能从大陆游戏业发源期坚持到现在的原因。 2. 目标软件(北京)有限公司,成立于一九九五年,制作游戏的数量共为四套,前两套是为国外公司代工作品,未在大陆出版过,代表作《铁甲风暴》。目标是典型的以技术、创意站稳脚跟的技术导向公司,市场宣传能力并无特殊之处,销售方式与西山居一样也是比较灵活。因为目标的注册身份由"带括弧的北京"可以看出为外资,所以一直有人而对目标国产游戏制作者的身份表示怀疑,不过市场上基本还是以国产游戏来看待并支持《铁甲风暴》。目标按正规的说法的确是外资注册公司,但其两位投资者一位原来是英籍华人(现已入籍香港),一位是上海人,当时那家作为投资名义出现的汉文公司(在英属维吉利亚群岛注册),现已更名为"目标"并改注册地为香港。当然,它的投资对象是一个大陆游戏制作组,以大陆最早的游戏制作组中(大约是92、3年由智冠建立)的一位程序为核心组建。所以鉴于此,我觉得把目标归入大陆游戏制作公司还是有一定道理的。 3. 北京创意鹰翔科技发展有限公司,成立于九八年,制作了两个游戏,如果把他们前身"鹰翔软件工作室"在立地公司的作品加在一起为三个游戏,代表作《生死之间Ⅱ》。之所以没有把二○○○年创意鹰翔才出的游戏《独创天涯》作为其代表作,是认为虽然后一作品虽有进步,品质也还不错,但缺少了《生死之间Ⅱ》的那种独特创意之处,不能令人有眼前一亮的感觉。此公司同样较为注重技术,但作出来的作品还是略逊目标公司一筹。其作品虽是由其它公司来发行,但也可看出本身的市场宣传能力较差,没有突出自己的公司形象及游戏独特之处,今后还看创意鹰翔能不能在技术、创意上有所突破,以弥补自己市场方面的缺陷。 4. 深圳金智塔电脑软件有限公司,成立于一九九七年,自制游戏五部,代表作《江湖》。这并不是说《江湖》是它的最好游戏,恰恰相反,是它做得最差的游戏,而且还差得出了大名。这个公司是从书、杂志开始作起,第一部游戏在九九年初才推出。典型的商业化企业,可以算是大陆最看重利益的游戏制作发行公司。如果要让所有的大陆游戏公司在商业利益与游戏品质中来个二选一,其它的公司或许会考虑具体情况而有所迟疑,金智塔却一定毫不犹豫的选择商业利益。这不是在批评,市场经济中这样公司的存在是有其一定合理性的,金智塔也正是靠了这种特质在中国游戏业里生存了下来,并继续发展。 5. 北京深智软件科技有限责任公司,成立于一九九八年,自制游戏两套,其前身"八爪鱼工作室"在腾图时做过《水浒英雄传》,代表作《杀气冲天》。它在这五家中是规模最小的,如果不是正式注册了一家公司,只能算作一个游戏小组。它基本还是纯粹以一个工作室的模式在运作,各种成本也尽量想办法降到最低。现在与一家跨足游戏业的异业公司以及一家香港游戏公司进行合作,得到了一定支持,。 另外,大陆业界还有不少独立的游戏制作室以及在某些台湾、国外游戏公司里的大陆游戏制作组,包括晶天、盘古、天碁、新瑞狮、英业达这些向来在自己身份上比较含糊实际而都是台湾公司直接投资的公司,属于其它范畴,这里就不加讨论了。 2.国产游戏历史中,最卖座的游戏是哪个?你最喜欢的国产游戏是哪一个?她的成功之处在哪,哪些是值得大家借鉴的呢?    嗯,怎么说好呢!在大陆游戏业短短的五年历史中,要谈产生了最大影响力的游戏还比较好说,这最卖座的游戏……,各家游戏公司的销量声明多多少少是掺得有水的,这水多水少不是公司内部人员也不会了解,我虽然是从事过游戏公司业务工作,但对于其它公司的游戏销量也不能贸然确定,只能靠一些经验和常理来大概推测。从各种迹象和反馈信息分析,大陆自制游戏中,二○○○年发行的《剑侠情缘Ⅱ》销量应该是最好的。这原因有二:1.在前几年大陆游戏业最初期,就算比较兴盛的时候,由于不仅游戏公司自身存在极大的品质和市场经验问题,销售市场也存在容量和价格承受力的问题,自制游戏的销量最好也不会超过八万套。2.现在市场的容量和购买力远远超过了以前,金山的市场推广和渠道控制能力也今非昔比,加上价格大幅降低,品质还可以,所以在销量上就算没有金山公司自己说的那么多,也大约是超过了十一、二万套,这就能算是第一了。     《天涯孤旅》,我最喜欢的大陆自制游戏是这部大概知道的人不多的游戏,也是我唯一一套玩的时间超过了十个小时的大陆自制游戏,这属于个人感觉,没有什么可比性。《天涯孤旅》由一个在贵阳的独立游戏小组在九九年底完成,上市嘛,好像在二○○○年的下半年由智冠推出,很可惜,错过了最佳上市时机,至于为什么拖了这么我也不太清楚原因。      在这部游戏中,最让人印象深刻的地方就是各种并不非凡的创意的实现性,这也是我认为此游戏中最值得大陆自制游戏借鉴的地方。打个比方,我们在进行看电影、玩游戏……这些娱乐活动时,在某些地方常常会有一些"这儿应该这样做就更好了"的想法,不过这种想法常常也是过后就忘了。《天涯孤旅》就是把我们在玩中国武侠RPG游戏时的一些遗憾,用可以接受的办法,在游戏中实现了出来,而且游戏的整体平衡性也把握得不错。当然,由于在人员、资金、经验方面的一系列问题,游戏在很多地方也存在着比较大的不足,这些不足会直接影响到普通游戏爱好者接受程度的,希望这一些不足在它的下一部作品中能得到一定改善。 3.国内游戏业目前最缺乏的是技术、创意、销售还是资金?我们是否在能在现有基础上制作出受国人喜爱的游戏吗?    我认为都不是,最缺的应该还是管理。技术和创意需要人才用资金来实现,销售又要以实现了新技术和创意的产品来作为基础,而资金流向一般认为,是不会由行业内部的变化来决定,大多为外部环境产生重大改变后,资金主动流入。上面说的这些都只能比作是一个木偶的各个身体部位,而管理就是提起木偶让它动起来的那只手。就国内游戏公司的现状,眼前最要紧的还是如何运用正确的组织管理,把大都比较缺乏的技术、创意、销售和资金,较好的整合起来。根据各自的具体条件,作一点突破,并能"破而扩之",将自己的优势成倍放大,而不是"破了就算",那种"破了就算"的行为也是最为耗损企业活力的。    现在国内游戏业历经三年低潮后又开始发展,资金有加速流入的动向,实际并不是因为此行业在中国有了多大利润,而是潜在巨额利润可以看到的时间渐渐逼近,这可以看到的潜在巨额利润很大一部分还是由于中国网络环境改善带来的。对于这种动向,必须正视的是,资金绝不是为支持国产游戏而来,利润是它们的目的,如果因为整个业界企业大多管理混乱,造成这些新投入资金在获得利润之前就损耗殆尽,那么新一轮国内游戏业的低潮期,就会比依照经济理论预测的时间来得更早,对业界的伤害也会更大。几年前的中国游戏业、今年的中国网络业都可作殷鉴。    对于能不能在现有基础上制作出国人喜爱的游戏,一个字"能"。原因也可以用前面的观点解释,"一点突破"就可以了,这用业界发展的历程眼光来看是比较容易做到的事,作出来之后如何才是更为重要和困难的。 4.中国现在是否形成了有自己特色和强档的游戏类型与游戏系列呢?他们的简单状况是怎样的? 这如果说的中国大陆业界,那很遗憾,还没有。如今由大陆制作的游戏,在主流上基本都是跟着台湾、国外的游戏类型在走,也就是武侠RPG和即时战略。即使有一两个游戏有独特的创新,如《铁甲风暴》、《天涯孤旅》,但也还未能形成气候。在系列游戏方面,唯一一个出到第二代的也只有《剑侠情缘》而已。发展时间还太短,制作群还不够一定基数是这种情况产生的主要原因。 5.我们一直说中国悠久的历史与广博的文化是使国产游戏能够蓬勃发展的根基。但直观现实,这种所谓的文化资源是否在国产游戏中体现了呢?(我们对游戏的认识是否应该首先建立在娱乐形式这个基础上,而不是过于强调中国化、本土味、以及文化性、教育性这些非游戏本质的东西。)国产游戏是否已经走上了可以追求本土化的误区之中? 体现了的,不过根不盛,自然就叶不会茂。大陆游戏业虽然并没有形成自己独特的游戏类型,但是,不论什么外来娱乐产品类型,在其本地制作化的过程都会逐渐加入当地的文化背景,如果当地的文化有其强大的包容性时就更会凸现在作品中了。当然,这并不是赞同你问题中的第一句话,把它加在你后面接着说的话上,我觉得就比较完全了:具有让人欲罢不能的强烈娱乐性,并融入了中国悠久历史和广博文化背景的国产游戏是国内游戏业能蓬勃发展的根基。这娱乐性就是归属于娱乐产业的游戏业之根,文化当然就是叶,国内游戏业好像比较强调中国化、本土味这些"叶"的东西,实际却是因为知道自己的"根"不够,就只有暂时做一些是叶非叶的来引人瞩目罢了。 不论是美国、日本游戏业,他们最初发展时都经历了一个阶段,这个阶段主要都是靠文化、地域色彩较弱的射击 、格斗、益智等游戏扩大占领市场,然后再投入大资金另外制作一些有着较深内涵的游戏,将自己的文化背景有意无意的渐渐融入其中,以形成自己的独特、不易模仿的优势地位。这让后来才进入的其它国家游戏业产生了两种认识:一是认为游戏中文化内涵的重要性是美日游戏业成功的首要因素,因此在自己的游戏制作、宣传中也将这种文化背景放在首位;另一种看法是美日游戏并不是靠文化取胜,他们游戏的无国界性才是成功的根本。这两种认识其实都有一定道理,有各自的实用性,在能力较强公司的操作下,也都可以某种程度的促进自己发展。至于究竟是不是要用哪一种方法,就必须舍弃另一种,我看也不必,这可以由具体对象所处的具体环境来决定。智冠、大宇、西山居是RPG专业户,目标公司冲击即时战略,他们都可以一定程度的得到回报,共同在市场上为中国游戏占据一定的份额,这是中国游戏市场初期发展的现实状况。看着世界上最优秀的游戏、最繁荣的游戏市场,就不考虑自己实力,只想如何能与他们比一比的思想是要不得的,在商业社会里那些先倒下的往往也是一口就想吃个胖子的。 在国内游戏业,那些强调文化内涵的宣传,实际完全与美日游戏中的文化内涵意义大相径庭,它们的目的也不是为加大其优势,而只是为了生存。只是,我期望这种种方法仅仅只是作为一种发展的手段,目的是让中国游戏业整体实力去慢慢接近美日业界,并不希望这些手段本身就成为了目的。现在可以回答你的第二个问题:为了本土化而本土化这就是误区,为了发展而只把本地化作为自己可以运用的手段之一这就算不上误区了。  
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:936760次
积分:14537
积分:14537
排名:第220名
原创:195篇
转载:13篇
评论:1627条
(2)(1)(3)(2)(1)(1)(1)(3)(1)(1)(1)(1)(1)(1)(1)(1)(1)(2)(3)(2)(2)(1)(1)(2)(4)(2)(3)(2)(2)(1)(4)(1)(1)(2)(3)(1)(1)(1)(1)(1)(6)(2)(1)(1)(1)(1)(3)(4)(2)(1)(1)(14)(6)(2)(2)(1)(2)(2)(3)(1)(2)(1)(1)(3)(6)(15)(11)(12)(8)(10)(6)(8)(3)

我要回帖

更多关于 游戏制作 的文章

 

随机推荐