首页 > 其他 > 详细

Cocos2dx游戏开发笔记23:《奇怪的大冒险》源码学习,附下载

时间:2014-03-17 18:09:02      阅读:521      评论:0      收藏:0      [点我收藏+]

懒骨头(http://blog.csdn.net/iamlazybone QQ:124774397 青岛)


以后有的忙了

抽空先来一发笔记

网上找了个demo:LOGO叫奇怪的大冒险(应该是@熊同学的demo,感谢:)

源码下载:http://download.csdn.net/detail/iamlazybone/7032991

bubuko.com,布布扣


================================

VS2013+git

先容许我吐槽下vs+git,搞了半天不是文件太大就是项目导入不好用,再不然就是文件被占用不能操作。

尝试了无数次,终于ok了,下面简单列一下步骤:

bubuko.com,布布扣

VS2013+Git 步骤:
1 vs里加入远程git地址,本地git地址
2 添加cocos2dx新建项目,写好gitignore,避开几个比较大的目录,提交
3 vs里Tools->Options->Text Editor->C/C++->Advanced,在 Fallback Location 的属性组中,将"Always Use Fallback Location"设置为 true,将"Do Not Warn If Fallback Location Used" 设置为 true ,然后删除解决方案目录下的 sdf 文件和 ipch 目录
4 项目修改附加目录,新增前三个,仅适用于骨头的项目:$(EngineRoot);$(EngineRoot)cocos;$(EngineRoot)cocos\editor-support;$(EngineRoot)cocos\audio\include;$(EngineRoot)external;$(EngineRoot)external\chipmunk\include\chipmunk;$(EngineRoot)extensions;..\Classes;..;%(AdditionalIncludeDirectories) 

================================

其实骨头现在也不知道这到底是个什么demo,怎么玩

报环境:vs2013+cocos2dx 2.2 抱着学习代码的态度,就不移植到3.0了

开始搞起!

================================

首先是手绘风的欢迎界面:HelloWorldScene.cpp类:

bubuko.com,布布扣

1 播放背景音乐:

CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("Audio_bgm_startup_cg.mp3",true);

2 把四张图片加载成帧动画,2秒一张,并且让sprite1同事进行俩动画:切换和飞入动画,并且动画结束时调用本类的animateFinished方法

		CCFadeIn* fadein = CCFadeIn::create(1.0f);
		CCFadeIn* fadein2 = CCFadeIn::create(0.1f);
		//sprite1->runAction(fadein);

		CCSpriteFrame * frame0 = CCSpriteFrame::create("StageCG_bkg1_zh.png", CCRectMake(0, 0, 800, 480));
		CCSpriteFrame * frame1 = CCSpriteFrame::create("StageCG_bkg2_zh.png", CCRectMake(0, 0, 800, 480));
		CCSpriteFrame * frame2 = CCSpriteFrame::create("StageCG_bkg3_zh.png", CCRectMake(0, 0, 800, 480));
		CCSpriteFrame * frame3 = CCSpriteFrame::create("StageCG_bkg4_zh.png", CCRectMake(0, 0, 800, 480));
		CCArray* array = CCArray::createWithCapacity(4);
		array->addObject(frame0);
		array->addObject(frame1);
		array->addObject(frame2);
		array->addObject(frame3);
		CCAnimation* animation = CCAnimation::createWithSpriteFrames(array, 2.0f);

		CCFiniteTimeAction* actionMoveDone = CCCallFuncN::create(this, callfuncN_selector(HelloWorld::animateFinished));
		sprite1->runAction(CCSequence::create(CCSpawn::createWithTwoActions(fadein, CCAnimate::create(animation)), actionMoveDone, NULL));
3 加入一个menu菜单,里面有个跳过按钮: 

CCMenuItemImage *skipItem = CCMenuItemImage::create(
			"StageCG_skip_normal_zh.png",
			"StageCG_skip_pressed_zh.png",
			this,
			menu_selector(HelloWorld::skipCallback));
4 跳过和动画结束方法里的方法是一样的,都是切换MenuScene:

	CCScene *gameMenu = GameMenu::scene();
	CCDirector::sharedDirector()->replaceScene(CCTransitionJumpZoom::create(1.0f, gameMenu));


================================

下面看下GameMenu.cpp类:菜单类:

bubuko.com,布布扣

1 这里面就是简单的贴图:

CCSprite* title = CCSprite::create("Startup_lbl_title_zh.png");
		title->setPosition(ccp(size.width / 2, size.height - 135));
		addChild(title);
		CCSprite* photo_border = CCSprite::create("Startup_photo_border.png");
		photo_border->setPosition(ccp(230, 200));

		addChild(photo_border);
		CCSprite* saveher = CCSprite::create("Startup_lbl_saveher.png");
		saveher->setPosition(ccp(230, 240));

		addChild(saveher);
		CCSprite* herface = CCSprite::create("Startup_herface1.png");
		herface->setPosition(ccp(230, 180));

2 还有三个按钮:可能因为位置原因,分三个menu容器

CCMenuItemImage *startItem = CCMenuItemImage::create(
			"Startup_lbl_start_zh.png",
			"Startup_lbl_start_pressed_zh.png",
			this,
			menu_selector(GameMenu::startButtonCallback));
		CC_BREAK_IF(!startItem);

		// Place the menu item bottom-right conner.
		startItem->setPosition(ccp(435, 250));
		//this->addChild(skipItem);
		CCMenu* pMenu = CCMenu::create(startItem, NULL);
		pMenu->setPosition(CCPointZero);
		addChild(pMenu);
		//,,,,,,,,,,,,,,,,,,,,,,
		CCMenuItemImage *aboutItem = CCMenuItemImage::create(
			"Startup_lbl_about_zh.png",
			"Startup_lbl_about_pressed_zh.png",
			this,
			menu_selector(GameMenu::aboutItemCallback));
		CC_BREAK_IF(!aboutItem);

		// Place the menu item bottom-right conner.
		aboutItem->setPosition(ccp(360, 150));
		//this->addChild(skipItem);
		CCMenu* aboutItemMenu = CCMenu::create(aboutItem, NULL);
		aboutItemMenu->setPosition(CCPointZero);
		addChild(aboutItemMenu);
三个按钮分别跳转到:设置,选关,关于三个界面

void GameMenu::startButtonCallback(CCObject* pSender)
{
	CCScene *stageSelect = StageSelect::scene();
	//CCDirector::sharedDirector()->replaceScene( CCTransitionJumpZoom::create(1.0f,stageSelect));
	CCDirector::sharedDirector()->pushScene((CCTransitionSlideInR::create(1, stageSelect)));
}
void 	GameMenu::aboutItemCallback(CCObject* pSender)
{
	CCScene *setting = AboutScene::scene();
	CCDirector::sharedDirector()->pushScene(setting);
}
void 	GameMenu::optionItemCallback(CCObject* pSender)
{
	CCScene *setting = SettingScene::scene();
	CCDirector::sharedDirector()->pushScene(setting);
}

3 还有个变脸动画:最最简单的帧动画,

CCSprite* herface = CCSprite::create("Startup_herface1.png");
		herface->setPosition(ccp(230, 180));

		addChild(herface, 2);
		herface->runAction(CCRepeatForever::create(CCAnimate::create(sAnimationMgr->getAnimation(biqiSmile))));

================================
看下设置页:SettingScene.cpp 

bubuko.com,布布扣

没什么特别的,比如资源统一管理:

		if (isMusicSwitchOn)
		{
			musicSwitch->setDisplayFrame(sAnimationMgr->getSpritFrame(onkey));

		}
		else
		{
			musicSwitch->setDisplayFrame(sAnimationMgr->getSpritFrame(offkey));

		}
		if (isEffectSwitchOn)
		{
			effectSwitch->setDisplayFrame(sAnimationMgr->getSpritFrame(onkey));

		}
		else
		{
			effectSwitch->setDisplayFrame(sAnimationMgr->getSpritFrame(offkey));

		}
还有这种根据按钮位置自己判断是否按下的方式,骨头觉得这样比较麻烦:

void  SettingScene::ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
	CCSize size = CCDirector::sharedDirector()->getWinSize();
	CCTouch *touch = (CCTouch *)pTouches->anyObject();
	CCPoint	location = touch->getLocationInView();
	// touch==NULL;
	location = CCDirector::sharedDirector()->convertToGL(location);
	if (location.x > size.width / 2 + 100 - 65 && location.x<size.width / 2 + 100 + 65 && location.y>210 && location.y < 270)
	{
		if (isMusicSwitchOn)
		{
			CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();
			musicSwitch->setDisplayFrame(sAnimationMgr->getSpritFrame(offkey));
			isMusicSwitchOn = false;
			sGlobal->isMusicOn = false;

		}
================================
下面看下选关类:StageSelect.cpp 

bubuko.com,布布扣
这个类也主要是贴图,按钮,无它。

主要看看是怎样记录闯关记录的。

找了一遍,没找到加六个按钮的地方,一看资源,懂了。

bubuko.com,布布扣

那就看下回调方法吧:一个是返回按钮,一个是开始第一关按钮。

void StageSelect::backItemCallback(CCObject* pSender)
{
	CCDirector::sharedDirector()->popScene();
}
void StageSelect::stageOneItemCallback(CCObject* pSender)
{
	CCScene* game_1_1 = Game_1_1::scene();
	CCDirector::sharedDirector()->pushScene((CCTransitionSlideInR::create(0.3, game_1_1)));
}
================================

第一关是Game_1_1.cpp,走着

bubuko.com,布布扣

一个控制按钮层,一个tmx地图层,然后按键处理,然后update里碰撞检测,最后表现在界面上。

GameMap *gameMap=GameMap::gameMapWithTMXFile("TMX_1_5.tmx");

GameMap类待会仔细看看。

添加英雄和控制层:

		hero=Hero::heroWithinLayer();
		addChild(hero);
		hero->setPosition(ccp(46*3,46*9));
		ControlLayer *controlLayer=ControlLayer::create();
		addChild(controlLayer);
		controlLayer->setPosition(ccp(0,0));

根据配置来决定是否播放音乐:

		if (sGlobal->isMusicOn)
		{
			  CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("Audio_bgm_1.mp3",true);
		}
主角动画:加载张大图,然后一帧帧
CCAnimation* Game_1_1::createAnimationByState(State direction)
{
	CCTexture2D *heroTexture=CCTextureCache::sharedTextureCache()->addImage("hero.png");
	// CCSpriteFrame *frame0,*frame1,*frame2,*frame3;
	CCSpriteFrame *frame0=CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*0, 32*direction, 32, 32)); 
	CCSpriteFrame *frame1=CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*1, 32*direction, 32, 32)); 
	CCSpriteFrame *frame2=CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*2, 32*direction, 32, 32)); 
	CCSpriteFrame *frame3=CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*3, 32*direction, 32, 32)); 
	CCArray *animFrames=CCArray::createWithCapacity(4);
	animFrames->addObject(frame0);
	animFrames->addObject(frame1);
	animFrames->addObject(frame2);
	animFrames->addObject(frame3);
	CCAnimation *animation =CCAnimation::createWithSpriteFrames(animFrames,0.07f);
	//animation->initWithAnimationFrames(animFrames,0.2f,1);
	animFrames->release();
	return animation;
}
在update方法里有个产生便便和导弹并且有相关的碰撞检测检测方法。

应该是不经意间出来的东西,想起了女流的《变态人生大冒险》,还有特别的叫声。

如果主角的位置在某某某,并且还活着,那么产生一个便便对象,并且主角碰上便便就得死。

	//产生便便
	if (sGlobal->hero->getPositionX() + 50 >= 22 * 48 && shicount == 0 && sGlobal->hero->isDead == false)
	{
		shi = CCSprite::create("shi.png", CCRectMake(0, 0, 47, 57));
		shicount++;
		shi->setAnchorPoint(ccp(0, 0));
		shi->setPosition(ccp(22 * 48, 480));
		this->addChild(shi);
	}
	if (shicount == 1)
	{
		shi->setPosition(ccp(22 * 48, shi->getPositionY() - 6));
		if (shi->getPositionY() < -50)
		{
			shi->setPosition(ccp(22 * 48, 480));
		}
		CCRect herRect = CCRectMake(sGlobal->hero->getPositionX(), sGlobal->hero->getPositionY(), 45, 45);
		if (herRect.intersectsRect(CCRectMake(shi->getPositionX() + 6, shi->getPositionY() + 6, 47, 57)))
		{
			sGlobal->hero->isDead = true;
			shicount = 0;
		}
	}

================================

然后看下地图类:Gamemap.cpp

bubuko.com,布布扣

看看h文件里的定义:

	//静态方法,用于生成GameMap实例
	static GameMap* gameMapWithTMXFile(const char *tmxFile);
	//TiledMap和cocos2d-x坐标系相互转换的方法
	CCPoint tileCoordForPosition(CCPoint position);
	CCPoint positionForTileCoord(CCPoint tileCoord);
	void hideBlockAnimate(CCPoint target);
	void blockMoveFinished(CCNode *sender);
	void removeGold(CCNode *sender);
	//动画移除砖块
	void removeFloor(CCPoint point);
protected:
	//TiledMap额外的初始化方法
	void extraInit();
	//开启各图层的纹理抗锯齿
	void enableAnitiAliasForEachLayer();

构造方法里,把自己的指针赋值给全局的sGlobal

GameMap::GameMap(void)
{
	sGlobal->gameMap=this;
}

像素点跟tile的索引之间的转换

//从cocos2d-x坐标转换为Tilemap坐标
CCPoint GameMap::tileCoordForPosition(CCPoint position)
{
	int x = position.x / this->getTileSize().width;
	int y = (((this->getMapSize().height) * this->getTileSize().height) - position.y) / this->getTileSize().height;
	return ccp(x, y);
}

//从Tilemap坐标转换为cocos2d-x坐标
CCPoint GameMap::positionForTileCoord(CCPoint tileCoord)
{
	CCPoint pos =  ccp((tileCoord.x * this->getTileSize().width),
		((this->getMapSize().height - tileCoord.y) * this->getTileSize().height));
	return pos;
}
移走地板方法:removeFloor,骨头猜是地图块下沉方法,待确定

void GameMap::removeFloor(CCPoint point)
{
	int maxy = sGlobal->gameMap->getMapSize().height;
	int heroheight = sGlobal->hero->getContentSize().height;
	for (int y = maxy; y >= point.y; y--)
	{
		int id = platformDynamicLayer->tileGIDAt(point);
		if (id)
		{
			CCSprite *sprite = platformDynamicLayer->tileAt(point);
			float s = (maxy - point.y)*this->getTileSize().height + heroheight;//要走的距离
			CCMoveTo *ccmoveto = CCMoveTo::create(s / 9.0f, ccp(point.x*this->getTileSize().width, -heroheight));
			sprite->runAction(ccmoveto);
			platformDynamicLayer->removeTileAt(point);
		}
	}
}

================================

看看hero.cpp英雄类里都有什么 

下面是定义文件里的。

	//静态方法,用于创建勇士实例
	static Hero *heroWithinLayer();
	//让勇士向指定方向移动一格
	void move(int i);
	void jump();
	void animateDone(CCNode *sender);
	bool isHeroMoving;
	bool isJumpDone;
	float hspeed;
	float vspeed;
	void setLayerEmpty(CCPoint start,int width,int height);
	bool isanimate;
	//初始化方法
	bool heroInit();
	bool isDead;
	bool isWin;
	//CollisionType checkCollision(CCPoint targetosition);
	void setViewpointCenter(CCPoint p);
	CollisionType checkCollisionOnly(CCPoint heroPosition);
	CollisionType checHeadkCollision(CCPoint heroPosition);
private:
	//用于显示勇士形象的精灵
	CCSprite *heroSprite;
	//临时保存目标的Tilemap坐标
	CCPoint targetTileCoord;
	CCPoint targetPosition;
	float speed;

有些方法看起来有点费劲,代码懂,但不知道游戏里是什么效果。

由于骨头用模拟器运行这个游戏,控制不方便,所以一开始就死

所以,先改改代码作作弊,才能更好的理解代码。

比如,屏蔽掉Hero.cpp类中189行

//sGlobal->gameMap->removeFloor(targetTileCoord);

主角就掉不下去了。

再来看看这个方法:让英雄处于屏幕中间位置, void Hero::setViewpointCenter(CCPoint p)

这个方法很常用,在mtx地图中可能都会用的到。

void Hero::setViewpointCenter(CCPoint p)
{
	CCSize size = CCDirector::sharedDirector()->getWinSize();
	float x = MAX(p.x, size.width / 2);
	float y = MAX(p.y, size.height / 2);

	x = MIN(x, (sGlobal->gameMap->getMapSize().width*sGlobal->gameMap->getTileSize().width) - size.width / 2);
	y = MIN(y, (sGlobal->gameMap->getMapSize().height*sGlobal->gameMap->getTileSize().height) - size.height / 2);
	CCPoint actualPosition = ccp(x, y);
	CCPoint centerOfView = ccp(size.width / 2, size.height / 2);
	CCPoint viewPoint = ccpSub(centerOfView, actualPosition);
	int x1 = viewPoint.x;
	int y1 = viewPoint.y;
	int herox = p.x;
	int heroy = p.y;
	int thisx = this->getPositionX();
	int htisy = this->getPositionY();
	int mapSize = sGlobal->gameMap->getMapSize().width;
	int TileSize = sGlobal->gameMap->getTileSize().width;

	sGlobal->game_1_1->setPosition(viewPoint);
	int x2 = 0 - viewPoint.x;
	int y2 = 0 - viewPoint.y;
	//sGlobal->controlLayer->setPosition(ccp((float)x2,(float)y2));
	//controlSprite->setPosition(ccp((float)x2,(float)y2));
}
在移动方法里: void Hero::move(int i)

根据水平速度来判断向左右还是向右走,然后根据key来运行左右移动动画,

并且有一个结束回调方法,来复位hero的图片

		CCAnimation *animation = sAnimationMgr->getAnimation(key);
		CCFiniteTimeAction* actionMoveDone = CCCallFuncN::create(this, callfuncN_selector(Hero::animateDone));
		heroSprite->runAction(CCSequence::create(CCAnimate::create(animation), actionMoveDone, NULL));

void Hero::animateDone(CCNode *sender)
{
	isanimate = false;
	heroSprite->setDisplayFrame(sAnimationMgr->getSpritFrame(heronormalkey));
}
====================================================

再来看看这两个箱子:其中右边是隐藏的。

bubuko.com,布布扣

hero.cpp里

CollisionType Hero::checHeadkCollision(CCPoint heroPosition)
{
	CCPoint targetTileCoord = sGlobal->gameMap->tileCoordForPosition(heroPosition);
	int hideblockId = sGlobal->gameMap->getHideBlockLayer()->tileGIDAt(targetTileCoord);
	if (hideblockId)
	{
		CCPoint  startposition;
		if (sGlobal->gameMap->getHideBlockLayer()->tileGIDAt(ccp(targetTileCoord.x - 1, targetTileCoord.y)))
		{
			startposition = ccp(targetTileCoord.x - 1, targetTileCoord.y);
		}
		else
		{
			startposition = targetTileCoord;
		}
		int id = sGlobal->gameMap->getPlatformLayer()->tileGIDAt(ccp(0, 0));
		sGlobal->gameMap->getPlatformLayer()->setTileGID(id, startposition);
		sGlobal->gameMap->getPlatformLayer()->setTileGID(id, ccp(startposition.x + 1, startposition.y));
		sGlobal->gameMap->getPlatformLayer()->setTileGID(id, ccp(startposition.x + 1, startposition.y - 1));
		sGlobal->gameMap->getPlatformLayer()->setTileGID(id, ccp(startposition.x, startposition.y - 1));
		sGlobal->gameMap->hideBlockAnimate(startposition);
		return khideblock;
	}
	return kNone;
}
jump方法里:如果向上跳,速度大于0,并且检测到碰到的是khideblock:即隐藏的砖块,则停止往上跳,并且播放音效。

		if (vspeed > 0)
		{
			if (checHeadkCollision(ccp(i, targetY2)) == khideblock)
			{
				vspeed = -0.4;
				if (sGlobal->isEffectOn)
				{
					CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("Audio_gold.mp3", false);
				}
				return;
			}
		}


====================================================

控制类:ControlLayer.cpp

bubuko.com,布布扣

首先打开触摸监听 this->setTouchEnabled(true);

	void  ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
	void  ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
	void  ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
	void  update(float delta);
然后初始化按钮

	jumpSprite = CCSprite::createWithSpriteFrame(sAnimationMgr->getSpritFrame(controlJumpkey));
	jumpSprite->setPosition(ccp(size.width - 70, 45));
	addChild(jumpSprite);

开始循环

	this->scheduleUpdate();
监听按键,直接在y<90的情况下,跟据x来判断按下哪个按键。

void  ControlLayer::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
	CCTouch *touch = (CCTouch *)pTouches->anyObject();
	CCPoint	location = touch->getLocationInView();
	// touch==NULL;
	location = CCDirector::sharedDirector()->convertToGL(location);
	//左按钮
	if (location.x < 90 && location.y<90)
	{
		leftSprite->setDisplayFrame(sAnimationMgr->getSpritFrame(controlLeftPressedkey));
		leftSpriteTouched = true;
	}
	else if (location.x>90 && location.x < 180 && location.y<90)//右按钮
	{
		rightSprite->setDisplayFrame(sAnimationMgr->getSpritFrame(controlRightPressedkey));
		rightSpriteTouched = true;
	}
	if (location.x>size.width - 140 && location.y < 90)//跳
	{
		jumpSprite->setDisplayFrame(sAnimationMgr->getSpritFrame(controlJumpPressedkey));
		jumpSpriteTouched = true;
	}
}
====================================================

结束层:FailedLayer.cpp

bubuko.com,布布扣

想想也就是贴图,一个返回按钮。

出现时使用movedby方法

CCFiniteTimeAction *actionMove = CCMoveBy::create(0.9f, ccp(0, -(size.height / 2 + 200)));
哭脸动画使用 repertForever动画

	crySprite = CCSprite::createWithSpriteFrame(sAnimationMgr->getSpritFrame(cryFramekey));
	crySprite->setPosition(ccp(boxSprite->getPositionX() - 113, boxSprite->getPositionY() - 50));
	crySprite->runAction(CCRepeatForever::create(CCAnimate::create(sAnimationMgr->getAnimation(heroCry))));

============================================================

源码下载

好了,收工

其实游戏里还有很多值得学的东西,骨头就不细细研究了,再次感谢原作者熊同学。

最近有不少“正”事,游戏相关的暂缓下。


“所有的看似毫不相关的努力都不白费,总会在某个时间发挥作用的”   —— 骨头


Cocos2dx游戏开发笔记23:《奇怪的大冒险》源码学习,附下载,布布扣,bubuko.com

Cocos2dx游戏开发笔记23:《奇怪的大冒险》源码学习,附下载

原文:http://blog.csdn.net/iamlazybone/article/details/20357391

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!