把AndEngine例子中贪吃蛇游戏使用Cocos2d-x实现

用AE做了个项目后,还是决定转到cocos2d-x上来做2D,因为跨平台确实吸引人。个人觉得AE还是个很不错的2D引擎,有着JAVA一贯的简单易用。而且AE中许多概念和cocos2d-x相通,比如Entity 对应CCNode,Modifier 对应Action, Scene, Layer,都有粒子系统和物理引擎支持等。

AE自带例子中有一个贪吃蛇的例子,使用的图片资源也少,学习cocos2d-x过程中新手实践一番

一、准备:

AE 游戏例子,AndEngineExamples中位于org.andengine.examples.game.snake包中的游戏,cocos2d-x, 我下载的是cocos2d-2.1rc0-x-2.1.

二、操作:

  1. 用ccx VS的win32模板添加一个项目Snake, 这是一个HelloWorld的程序,注意:如果这个工程没有放在CCX的目录下,要自己配置包含目录,因为模板使用了$(SolutionDir)这样的路径。

2. 将AndEngineExamples\assets\mfx下的两个声音文件,game_over.ogg,munch.ogg; font下的Plok.ttf;AndEngineExamples\assets\gfx下的snake*.png, frog.png拷到resource目录下。

3. 观察原游戏目录,依次实现对应类。


首先是常量定义,这个不用说了,添加一个头文件SnakeConstants.h,如:

 
#ifndef SNAKECONSTANTS_H_
#define SNAKECONSTANTS_H_

class SnakeConstants
{
public:
	static const int CELLS_HORIZON = 16;
	static const int CELLS_VERTICAL = 12;
	static const int CELL_WIDTH = 32;
	static const int CELL_HEIGHT = CELL_WIDTH;
	static const int CAMERA_WIDTH = CELLS_HORIZON * CELL_WIDTH; 
	static const int CAMERA_HEIGHT = CELLS_VERTICAL * CELL_HEIGHT;

	static const int LAYER_COUNT = 4;

	static const int LAYER_BACKGROUND = 0;
	static const int LAYER_FOOD = 1;
	static const int LAYER_SNAKE = 2;
	static const int LAYER_UI = 3;
};
#endif  
接口ICellEntity, 添加一个ICellEntity.h

#define ICELL_ENTITY_H_
#ifndef ICELL_ENTITY_H_
class ICellEntity
{
public:
	virtual const int GetCellX() const= 0;
	virtual const int GetCellY() const= 0;

	virtual void SetCell(const ICellEntity& cell) = 0;
	virtual void SetCell(const int cellX, const int cellY) = 0;

	virtual bool IsInSameCell(const ICellEntity& cell) const = 0;

};

#endif


Direction枚举定义了方向,和方向上的移动,添加Direction.h, 注意:由于这两个引擎的坐标第y方向是相反的,所以AddToY上下方向的符号变了。

#ifndef DIRECTION_H_
#define DIRECTION_H_

#include "SnakeConstants.h"

enum Direction
{
	DIR_NULL,
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};

static int AddtoX(const Direction direction, const int dx)
{
	switch(direction)
	{
	case UP:
	case DOWN:
		return dx;
	case LEFT:
		return dx - 1;
	case RIGHT:
		return dx + 1;
	}

	return dx;
}

static int AddtoY(const Direction direction, const int dy)
{
	switch(direction) 
	{
	case LEFT:
	case RIGHT:
		return dy;
	case UP:
		return dy + 1;
	case DOWN:
		return dy - 1;
	}

	return dy;
}

static Direction Opposite(const Direction direction) 
{
	switch(direction) {
	case UP:
		return DOWN;
	case DOWN:
		return UP;
	case LEFT:
		return RIGHT;
	case RIGHT:
		return LEFT;
	default:
		return DIR_NULL;
	}
}

#endif
用ICellEntity.h接口实现CellEntity类,这个类是没有动画的,用于主角的尾巴。这里使用了继承CCSprite的方式,
class CellEntity : public ICellEntity, public CCSprite

因为ccx默认的锚点在中心,所以把位置加上格子一半,定义在中心

this->setPosition(ccp(mCellX*SnakeConstants::CELL_WIDTH+16, mCellY*SnakeConstants::CELL_HEIGHT+16));

实现一个简单帧动画的类,AnimatedCellEntity, 构造函数中显示了一种使用帧动画的方式:

	mCellX = cellx;
	mCellY = celly;

	animation = CCAnimation::create();
	CCImage* image = new CCImage();
	image->autorelease();
	image->initWithImageFile(filename);
	CCTexture2D* texture = new CCTexture2D();
	texture->initWithImage(image);
	mTileW = texture->getPixelsWide() / col;
	mTileH = texture->getPixelsHigh();

	for (int i = 0; i < col; ++i)
	{
		animation->addSpriteFrameWithTexture(texture, CCRectMake(i*mTileW, 0, mTileW, mTileH));
	}
	CCSpriteFrame* frm = ((CCAnimationFrame*)(animation->getFrames()->objectAtIndex(0)))->getSpriteFrame();

	this->initWithSpriteFrame(frm);
	animation->setDelayPerUnit(0.5f);

	mAni = CCRepeatForever::create(CCAnimate::create(animation));

	this->SetCell(cellx, celly);
void AnimatedCellEntity::Animate( const float interval )
{
	animation->setDelayPerUnit(interval);
	this->runAction(mAni);
}

用上面的两个类实现SnakeHead,SnakeTailPart

蛇头应当占两个格子,而且旋转的中心在头部的1/4处,所以要更改锚点,并放大,这点和AE还是有些不同的

	this->setAnchorPoint(ccp(0.5f, 0.75f));
	this->setScale(2.0f);
最后新建一个类,Snake继承自CCNode,其中包含一个头和一个CCArray表示尾部。
#include "cocos2d.h"
#include "Direction.h"
#include "Snake.h"
#include "SnakeTailPart.h"


Snake::Snake( const Direction dir, int cellx, int celly )
{
	m_pSnakeHead = new SnakeHead(cellx, celly);
	m_pSnakeHead->autorelease();

	this->addChild(m_pSnakeHead);
	this->SetDirection(dir);
}

void Snake::SetDirection( const Direction dirction )
{
	if(mLastMoveDirection != Opposite(dirction)) 
	{
		mDirection = dirction;
		m_pSnakeHead->SetRotation(dirction);
	}
}

Snake::~Snake()
{
//	CC_SAFE_DELETE(m_pSnakeHead);

	释放数组内的元素!, NO NEED!
	//CCObject* object;
	//CCARRAY_FOREACH(&marrTail, object)
	//{
	//	CC_SAFE_DELETE(object);
	//}

	//marrTail.removeAllObjects();
}

int Snake::GetNextX()
{
	return AddtoX(mDirection, m_pSnakeHead->GetCellX());
}

int Snake::GetNextY()
{
	return AddtoY(mDirection, m_pSnakeHead->GetCellY());
}

boolean Snake::Move()
{
	mLastMoveDirection = mDirection;

	if(m_bGrow) 
	{
		m_bGrow = false;
		/* If the snake should grow,
		* simply add a new part in the front of the tail,
		* where the head currently is. */
		SnakeTailPart* newTailPart = new SnakeTailPart(m_pSnakeHead);
		this->addChild(newTailPart);
		marrTail.insertObject(newTailPart, 0);
	} 
	else 
	{
		if(marrTail.count() > 0)
		{
			/* First move the end of the tail to where the head currently is. */
			SnakeTailPart* tailEnd = (SnakeTailPart*)marrTail.lastObject();
			marrTail.removeLastObject(false);
			tailEnd->SetCell(*m_pSnakeHead);

			marrTail.insertObject(tailEnd, 0);
		}
	}

	/* The move the head into the direction of the snake. */
	m_pSnakeHead->SetCell(GetNextX(), GetNextY());

	/* Check if head collides with tail. */
	for(int i = marrTail.count() - 1; i >= 0; i--) 
	{
		if(m_pSnakeHead->IsInSameCell(*(SnakeTailPart*)marrTail.objectAtIndex(i)))
		{
			return false;
		}
	}

	return true;
}
逻辑部分就完了。

把模板中的HelloWorldScene改为自己的SnakeScene,实现显示和触摸控制

#ifndef SNAKESCENE_H__
#define SNAKESCENE_H__

#include "cocos2d.h"
#include "SimpleAudioEngine.h"
#include "Direction.h"
#include "Snake.h"
#include "Frog.h"

class SnakeScene : public cocos2d::CCLayer
{
public:
    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    // there's no 'id' in cpp, so we recommand to return the exactly class pointer
    static cocos2d::CCScene* scene();
    
    // a selector callback
    void menuCloseCallback(CCObject* pSender);

	//四个方向
	void upCallBack(CCObject* sender);
	void downCallBack(CCObject* sender);
	void leftCallBack(CCObject* sender);
	void rightCallBack(CCObject* sender);

	//schedule
	void ScheduleTick1(float dt);
	void GameCircle(float dt);

    // implement the "static node()" method manually
    CREATE_FUNC(SnakeScene);
private:
	void SetFrogToRandomCell();
	void OnGameOver();

	void HandleNewSnakePosition();

	//声音的使用非常简洁!
	void PlayMunchSound();
	void PlayGameOverSound();
private:
	int m_nScore;
	bool m_bGameRunning;

	//分数
	CCLabelTTF* mScoreText;
	//游戏结束 
	CCLabelTTF* mGameOverText;
	//游戏开始前的文字 
	CCLabelTTF* mTitleText;
	Snake* mSnake;
	Frog* mFrog;
};

#endif 
在init中:

依照原游戏,分四层:

for(int i = 0; i < SnakeConstants::LAYER_COUNT; ++i)
{
this->addChild(CCLayer::create());
}

四个方向键:

		//4个方向键:
		CCMenuItemImage* pUpImage = CCMenuItemImage::create("u1.png", "u2.png", this, menu_selector(SnakeScene::upCallBack));
		pUpImage->setAnchorPoint(ccp(0.5, 0));
		pUpImage->setPositionY(6.0f);

		CCMenuItemImage* pDownImage = CCMenuItemImage::create("d1.png", "d2.png", this, menu_selector(SnakeScene::downCallBack));
		pDownImage->setAnchorPoint(ccp(0.5, 1));
		pDownImage->setPositionY(-6.0f);

		CCMenuItemImage* pLeftImage = CCMenuItemImage::create("b1.png", "b2.png", this, menu_selector(SnakeScene::leftCallBack));
		pLeftImage->setAnchorPoint(ccp(1, 0.5));
		pLeftImage->setPositionX(-6.0f);

		CCMenuItemImage* pRightImage = CCMenuItemImage::create("f1.png", "f2.png", this, menu_selector(SnakeScene::rightCallBack));
		pRightImage->setAnchorPoint(ccp(0, 0.5));
		pRightImage->setPositionX(6.0f);

		CCMenu* ArrowMenu = CCMenu::create(pUpImage, pDownImage, pLeftImage, pRightImage, NULL);
		ArrowMenu->setPosition(100, 100);
		layer->addChild(ArrowMenu);
游戏主循环:

schedule(schedule_selector(SnakeScene::GameCircle), 0.5f);
声音播放:

void SnakeScene::PlayMunchSound()
{
CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("munch.ogg");
}

运行后:



最后 附上源码:

src-of-demo







                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值