学习cocos2d-x自带的SimpleGame

本文详细介绍了如何使用cocos2d-x框架创建一个简单的射击游戏。从新建项目到添加资源,再到实现游戏逻辑,包括幽灵生成、子弹发射、碰撞检测和游戏结束条件设定,逐步引导读者掌握cocos2d-x游戏开发的基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作为一个菜鸟,就得从头学起。

cocos2d-x文件目录里面自带了很多例子,其中就有一个SimpleGame。它属于射击类的小小小游戏。

开始学吧

首先新建个cocos2d-x项目,打开终端进入project-creator目录,输入:

./create_project.py -project MySimpleGame -package xxx.com -language cpp

回车,打开刚才建好的MySimpleGame项目,先加入所需的资源:

这些资源直接从自带的SimpleGame工程里面copy过来。我这里加的是HD目录下的。

进到HelloWorldScene.h,添加偷懒的宏定义并修改我们HelloWorldScene类的父类为CCLayerColor:

USING_NS_CC;
class HelloWorld : public CCLayerColor

然后在HelloWorldScene.cppinit(),保留最后的return语句,其他的删掉,为了把游戏的背景设为白色,添加代码:

    if ( !CCLayerColor::initWithColor(ccc4(255, 255, 255, 255)) )
    {
        return false;
    }
接着为类添加两个private变量:

private:
    CCSize visibleSize;
    CCPoint origin;
init()中用这两个变量保存屏幕的尺寸和坐标,再添加一个玩家精灵:

    visibleSize = CCDirector::sharedDirector()->getVisibleSize();
    origin = CCDirector::sharedDirector()->getVisibleOrigin();
    
    CCSprite *player = CCSprite::create("Player.png",CCRectMake(0, 0, 27*2, 40*2));
    player->setPosition(ccp(origin.x + player->getContentSize().width/2,origin.y + visibleSize.height/2));
    this->addChild(player);
关于屏幕的适配看这里

运行程序看看:




接下来,会随机出现一些幽灵,那么就建一个数组来保存它们,添加成员变量,再增加一个private方法addTarget生产幽灵:

    CCArray *_targets;
    void addTarget();
下一步,就是到HelloWorldScene.cpp中实现addTarget方法:

void HelloWorld::addTarget()
{
    CCSprite *target = CCSprite::create("Target.png", CCRectMake(0,0,27*2,40*2));
    //让target出现的高度随机,但不要超出边界
    float minY = target->getContentSize().height/2;
    float maxY = visibleSize.height - target->getContentSize().height/2;
    int rangeY = (int)(maxY - minY);
    int actual = (rand() % rangeY) + minY; //这就是随机产生出来的target位置高
    target->setPosition(ccp(visibleSize.width + target->getContentSize().width/2,origin.y + actual));
    this->addChild(target);
    
    //产生target的速度
    int minDuration = 2;
    int maxDuration = 4;
    int rangeDuration = maxDuration - minDuration;
    int actualDuration = (rand() % rangeDuration) + minDuration;
    
    //target在会执行的动作,其实在这里就是直线移动。
    CCFiniteTimeAction *actionMove = CCMoveTo::create((float)actualDuration, ccp(-target->getContentSize().width/2, actual));
    target->runAction(CCSequence::create(actionMove,CCCallFuncN::create(this,callfuncN_selector(HelloWorld::spriteMoveFinished))));
    target->setTag(1);
    _targets->addObject(target);
}

上面的方法中用到了spriteMoveFinished方法,这是一个回调,下面还得定义两个public方法:

    void spriteMoveFinished(CCObject *pSender);
    void gameLogic(float dt);
然后去实现它们:

void HelloWorld::gameLogic(float dt)
{
    this->addTarget();
}
void HelloWorld::spriteMoveFinished(cocos2d::CCObject *pSender)
{
    
}

接着,我们得去init()方法中,为_targets分配内存,再添加一个定时器来执行gameLogic方法:

    _targets = new CCArray();
    this->schedule(schedule_selector(HelloWorld::gameLogic),1);

运行我们的程序,就能看到幽灵出来了:




我们得发射子弹了,那就得点击屏幕,就得有Touch事件发生。

添加一个private数组存放子弹,并在init()中为它分配空间:

    CCArray *_projectiles;

    _projectiles = new CCArray;

随后我们得定义两个与Touch有关的public方法:

    void registerWithTouchDispatcher();
    virtual void ccTouchesEnded(CCSet *touches,CCEvent *event);

分别再实现它们:

void  HelloWorld::registerWithTouchDispatcher()
{
    CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this, 0);
}
void  HelloWorld::ccTouchesEnded(cocos2d::CCSet *touches, cocos2d::CCEvent *event)
{
    //获取touch的坐标
    CCTouch *touch = (CCTouch*)(touches->anyObject());
    CCPoint location = touch->getLocation();
    
    //产生子弹
    CCSprite *projectile = CCSprite::create("Projectile.png", CCRectMake(0, 0, 20*2, 20*2));
	projectile->setPosition( ccp(origin.x+20, origin.y+visibleSize.height/2) );
    
	//子弹偏移
	float offX = location.x - projectile->getPosition().x;
	float offY = location.y - projectile->getPosition().y;
    
	// 超边界,不发
	if (offX <= 0) return;
    this->addChild(projectile);
    
    //确定子弹发射位置
    float realX = origin.x+visibleSize.width + (projectile->getContentSize().width/2);
	float ratio = offY / offX;
	float realY = (realX * ratio) + projectile->getPosition().y;
	CCPoint realDest = ccp(realX, realY);
    
    //子弹能发射多远
    float offRealX = realX - projectile->getPosition().x;
	float offRealY = realY - projectile->getPosition().y;
	float length = sqrtf((offRealX * offRealX) + (offRealY*offRealY));
	float velocity = 480/1; // 480pixels/1sec
	float realMoveDuration = length/velocity;
    
    //执行动作
    projectile->runAction( CCSequence::create(
                                              CCMoveTo::create(realMoveDuration, realDest),
                                              CCCallFuncN::create(this,
                                                                  callfuncN_selector(HelloWorld::spriteMoveFinished)),
                                              NULL) );
    
    projectile->setTag(2);
	_projectiles->addObject(projectile); //子弹加入数组
}

对于registerWithTouchDispatcher的用法可以看这篇博客

运行程序,touch屏幕我们就可发射子弹了:


我们会发现,现在子弹还不能消灭幽灵,let's do it!

添加一个public方法:

    void updateGame(float dt);
然后实现:

void HelloWorld::updateGame(float dt)
{
    CCArray *projectilesToDelete = new CCArray;
    CCObject* it = NULL;
    CCObject* jt = NULL;
    CCARRAY_FOREACH(_projectiles, it)
	{
        //算出子弹框
		CCSprite *projectile = dynamic_cast<CCSprite*>(it);
		CCRect projectileRect = CCRectMake(
                                           projectile->getPosition().x - (projectile->getContentSize().width/2),
                                           projectile->getPosition().y - (projectile->getContentSize().height/2),
                                           projectile->getContentSize().width,
                                           projectile->getContentSize().height);
        
		CCArray* targetsToDelete =new CCArray;
        
        //算出打击的目标框
        CCARRAY_FOREACH(_targets, jt)
		{
			CCSprite *target = dynamic_cast<CCSprite*>(jt);
			CCRect targetRect = CCRectMake(
                                           target->getPosition().x - (target->getContentSize().width/2),
                                           target->getPosition().y - (target->getContentSize().height/2),
                                           target->getContentSize().width,
                                           target->getContentSize().height);
            
            //表示打中了目标,把这些目标加入到数组中
            if (projectileRect.intersectsRect(targetRect))
			{
				targetsToDelete->addObject(target);
			}
		}
        //移除这些被打中的目标
        CCARRAY_FOREACH(targetsToDelete, jt)
		{
			CCSprite *target = dynamic_cast<CCSprite*>(jt);
			_targets->removeObject(target);
			this->removeChild(target, true);
            
           
		}
        
		if (targetsToDelete->count() > 0)
		{
			projectilesToDelete->addObject(projectile);
		}
		targetsToDelete->release();
	}
    
    //移除打中目标的子弹
    CCARRAY_FOREACH(projectilesToDelete, it)
	{
		CCSprite* projectile = dynamic_cast<CCSprite*>(it);
		_projectiles->removeObject(projectile);
		this->removeChild(projectile, true);
	}
	projectilesToDelete->release(); //释放
}

我写了点简单的注释,有助于理解。
运行程序以后,对准幽灵发射子弹吧。

我们就会发现,幽灵永远也打不完,这样无休止的打下去,是人都会疯了。

So,我们得有个规则来判断输赢。

win:消灭5个幽灵

lose:幽灵跑到了我们的后面

好,有了规则后,就来执行吧。

首先,新建一个C++类,文件名为GameOverScene,用下面的代码替换GameOverScene.h中的代码:

#ifndef __MySimpleGame__GameOverScene__
#define __MySimpleGame__GameOverScene__

#include "cocos2d.h"
USING_NS_CC;
class GameOverLayer : public CCLayerColor
{
public:
    GameOverLayer():_label(NULL) {};
    virtual ~GameOverLayer();
    bool init();
    CREATE_FUNC(GameOverLayer);
    
    void gameOverDone();
    
    CC_SYNTHESIZE_READONLY(CCLabelTTF*, _label, Label);
};

class GameOverScene : public CCScene
{
public:
    GameOverScene():_layer(NULL) {};
    ~GameOverScene();
    bool init();
    CREATE_FUNC(GameOverScene);
    
    CC_SYNTHESIZE_READONLY(GameOverLayer*, _layer, Layer);
};

#endif /* defined(__MySimpleGame__GameOverScene__) */

上面的代码,声明了一个布景类和一个场景类,用来显示咱们输赢后的结果。

用下来的代码替换GameoverScene.cpp中的代码:

#include "GameOverScene.h"
#include "HelloWorldScene.h"

bool GameOverScene::init()
{
	if( CCScene::init() )
	{
		this->_layer = GameOverLayer::create();
		this->_layer->retain();
		this->addChild(_layer);
		
		return true;
	}
	else
	{
		return false;
	}
}

GameOverScene::~GameOverScene()
{
	if (_layer)
	{
		_layer->release();
		_layer = NULL;
	}
}


bool GameOverLayer::init()
{
	if ( CCLayerColor::initWithColor( ccc4(255,255,255,255) ) )
	{
		CCSize winSize = CCDirector::sharedDirector()->getWinSize();
		this->_label = CCLabelTTF::create("","Artial", 32);
		_label->retain();
		_label->setColor( ccc3(0, 0, 0) );
		_label->setPosition( ccp(winSize.width/2, winSize.height/2) );
		this->addChild(_label);
		
		this->runAction( CCSequence::create(
                                            CCDelayTime::create(3),
                                            CCCallFunc::create(this,
                                                               callfunc_selector(GameOverLayer::gameOverDone)),
                                            NULL));
		
		return true;
	}
	else
	{
		return false;
	}
}

void GameOverLayer::gameOverDone()
{
	CCDirector::sharedDirector()->replaceScene( HelloWorld::scene() );
}

GameOverLayer::~GameOverLayer()
{
	if (_label)
	{
		_label->release();
		_label = NULL;
	}
}

这里理解起来也没什么难度,所以我就直接用自带的代码了。

接下来,回到HelloWorldScene.h中,添加一个private变量,用来判断消灭了多少幽灵:

    int _projectilesDestroyed;
然后到HelloWorldScene.cpp的开头添加头文件:

#include "GameOverScene.h"
updateGame中找到下面的代码处:

在其后面加上代码:

            _projectilesDestroyed++;
			if (_projectilesDestroyed >= 5) //移除的目标数目>5,You Win!
			{
				GameOverScene *gameOverScene = GameOverScene::create();
				gameOverScene->getLayer()->getLabel()->setString("You Win!");
				CCDirector::sharedDirector()->replaceScene(gameOverScene);
			}

这段代码很明显,当我们消灭了5个幽灵以后,就切换到gameOverScene显示“You Win!”.

那“You Lose”去哪里了?

看一下我们的spriteMoveFinished方法,是空的,为其添加下面的代码:

    CCSprite *sprite = (CCSprite *)pSender;
	this->removeChild(sprite, true);
    
	if (sprite->getTag() == 1)  // target
	{
		_targets->removeObject(sprite);
        
		GameOverScene *gameOverScene = GameOverScene::create();
		gameOverScene->getLayer()->getLabel()->setString("You Lose");
		CCDirector::sharedDirector()->replaceScene(gameOverScene);
        
	}
	else if (sprite->getTag() == 2) // projectile
	{
		_projectiles->removeObject(sprite);
	}

早前我们分别给targetprojectile精灵设置了tag值,现在就可以用这个值来判断传过来的精灵是哪一个了。

编译运行游戏:



Yes,I‘am win.

如果有需要可以点这里下载源码,当然还可以直接看Cocos2d-x自带的SimpleGame代码,几乎是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值