cocos2d - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 技术分享 >

cocos2d

发表时间:2020-10-19

发布人:葵宇科技

浏览次数:33

[img]http://img.blog.csdn.net/20150104174030021
     迎接回来,上篇我们讲到了物理引擎中重力情况模仿以及主角考拉与地面墙壁的碰撞,信赖大年夜家已经对2D世界的物理模仿有了必定的懂得,如今我们接着讲若何让考拉动起来吧!

     [img]http://img.blog.csdn.net/20150104174527077
让考拉动起来!
    这里控制考拉移动变得异常简单,它只有向前和跳两个才能(源码中我加了考拉向后走功能,建议大年夜家本身加几个虚拟按键来实现更非富的功能)如不雅你按着屏幕左半部考拉会向前走,按住右半部考拉会跳起来(原文设定考拉不会撤退撤退-_-)。
    我们须要在Player.h里加两个成员变量:
    bool _mightAsWellJump; //可以跳跃吗?
在GameLevelLayer类里加上触摸,在.h文件里加上:
virtual void registerWithTouchDispatcher();

	void ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
	void ccTouchesMoved(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
	void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
在GameLevelLayer.cpp的init里加上(加载地图代码后)
setTouchEnabled(true);  //设置可触摸
然后写注册触摸办法
void GameLevelLayer::registerWithTouchDispatcher()
{
	CCDirector* pDirector = CCDirector::sharedDirector();
	pDirector->getTouchDispatcher()->addStandardDelegate(this, 0); //注册多点触摸
}
如今,让我们看看那三个触摸事宜吧!
void GameLevelLayer::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
	CCSetIterator iter = pTouches->begin();
	for (; iter!=pTouches->end(); iter++)
	{
		CCTouch* pTouch = (CCTouch*)(*iter);
		CCPoint touchLocation = this->convertTouchToNodeSpace(pTouch);  //把touch点地位转换为本地坐标
		if (touchLocation.x > 240)   //在屏幕最右边点,就是跳
		{
			_player->bMightAsWellJump = true;
		}
		else 
		{
			_player->bForwardMarch = true;
		}

	}
}

void GameLevelLayer::ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
	
	_player->bForwardMarch = false; //松开按键时,设置为弗成跳也不是向前状况
	_player->bMightAsWellJump = false;
}
代码一目了然,ccTouchesBegan时根据玩家按的地位决定了考拉状况是进步照样跳跃,松开按键时将这两个状况变量重置为false。
真正的角色移动是在player的update办法里进行的,看代码:

void Player::update(float delta)
{
	CCPoint gravity = ccp(0.f, -450.f);  //考拉每秒降低450个单位
	CCPoint gravityStep = ccpMult(gravity, delta); //计算在重力影响下delta时光内具体降低了若干, 即dt时光后下落速度为若干

	CCPoint forwardMove = ccp(800.f, 0.f); //进步速度,每秒进步800.f
	CCPoint forwardStep = ccpMult(forwardMove, delta);   // 1

	this->_velocity = ccpAdd(this->_velocity, gravityStep); //当前速度=当前速度+重力加快度
	this->_velocity = ccp(this->_velocity.x *0.9f, this->_velocity.y); //2
	
	if (this->bForwardMarch)
	{
		this->_velocity = ccpAdd(this->_velocity, forwardStep); //当前速度要加上向前的速度矢量
	}// 3

	CCPoint minMovement = ccp(-120.f, -350.f);
	CCPoint maxMovement = ccp(120.0f, 250.f);
	this->_velocity = ccpClamp(this->_velocity, minMovement, maxMovement); //4

	CCPoint stepVelocity = ccpMult(this->_velocity, delta); //计算下此速度下主角移动了若干

	this->_desiredPosition = ccpAdd(this->getPosition(), stepVelocity); //当前期望要去的地位=当前地位+当前速度
}
让我们来具体地看一下新增部分:
  1. 当玩家触摸进步的时刻和重力模仿类似,我们加了一个向前的推动力800.f,处理方法与重力雷同
  2. 第2步横向速度乘以0.9是模仿摩擦力效不雅,推敲下当有向前推力时玩家会向前移动,没有了呢?是不是急速停下来?那样看起来太生映了棘所以这里x轴速度每帧乘以0.9就起到了平均减速的效不雅,就像摩擦力一样
  3. 检查一下玩家是否按了前,按进步时速度上就要加上向前的推动力,就起到了向进步的效不雅了
  4. 这一步是调用了clamp是限制速度前后高低不要太大年夜,给它一个最大年夜值。之前的那句设定下落速度最大年夜值可以去掉落了。
好了运行一下,我们可以看到我们的主角小考拉如今可以进步了!

               [img]http://img.blog.csdn.net/20150104182452187
让考拉跳起来!
 跳跃是动作游戏里最明显的一个特点。我们欲望角色跳的腻滑逼真,如今让我们来实现它。
 到player类的update办法里,在if(this->_forwardMarch)语句之前加高低面代码:
if (tilePos.y > (_map->getMapSize().height-1))
{
	this->gameOver(false);
	return NULL;
}
在checkForAndResolveCollisions办法里有调用getSurroundingTilesAtPosition办法,如不雅它返回个空数组可就不妙了,所以在checkForAndResolveCollisions也要改一下,在 CCArray* tiles = this->getSurroundingTilesAtPosition(player->getPosition(), _walls);一句之后,加上
CCPoint jumpForce = ccp(0.f, 310.f);

if(this->_mightAsWellJump && this->_onGround)
{
  this->_velocity = ccpAdd(this->_velocity, jumpForce);
}
   只要加一个向上的力,角色就可以跳起来了。
    如不雅你止步于此,你会获得一个老式的雅代利式跳跃,即每次跳跃都是雷同的高度,每次你都施给玩家一个同样的力,然后等侧重力把你拉回地面来。
     这么做似乎没什么不当,如不雅你请求不高的话,然则细心不雅察一下各类风行的平台游戏,如超等马里奥,索尼克,洛克人,水上魂斗罗等,似乎玩家可以或许经由过程按键的力度来控制跳跃的高度,达到更灵活的效不雅。那是怎么做到的呢?
其实实现这个效不雅也很简单,所谓玩家按键力度不过就是按键时光的长久,按的时光长也就是施加跳跃力的时光就长,跳的当然高了,半路上桤不雅玩家不给力了,当然会跳到一半掉落链子,不过玩家有种错觉就是想特点高就使劲按着跳跃键,不想跳了松开键就是-_-
CCPoint jumpForce = ccp(0.f, 310.f);  //向上的跳跃力 玩家一向按着跳跃键时的跳跃力
	float jumpCutOff = 150.f;   //玩家没有按住跳跃键时的跳跃力

	if(this->bMightAsWellJump && this->onGround)  //如不雅当前玩家按了跳跃键并且在地上
	{
		this->_velocity = ccpAdd(this->_velocity, jumpForce); //跳跃就是加上一个向上的速度
	}
	else if (!this->bMightAsWellJump && this->_velocity.y > jumpCutOff) //玩家没有按住跳跃键,并且向上的速度已经跨越了设定的值,就限制向上跳跃速度
	{
		this->_velocity = ccp(this->_velocity.x, jumpCutOff);
	}
注释解释的很清跋扈,就不多说清楚明了。
好了,build一下run下我们的游戏吧,看吧,我们的小考拉可以自由欢腾地高低翻飞了。
    [img]http://img.blog.csdn.net/20150104215042551
跳是跳的很欢了,不过悲剧的是,它跳到最右边就彪炳屏幕,看不见了。
来修改这个问题,这个问题其实就是视点跟随,在cocos2dx上有解决这一问题的标准算法,贴出代码:
void GameLevelLayer::setViewpointCenter(cocos2d::CCPoint pos)
{
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();

	//限制角色不克不及跨越半屏
	int x = MAX(pos.x, winSize.width/2);
	int y = MAX(pos.y, winSize.height/2);

	//限制角色不克不及跑出屏幕
	x = MIN(x, (_map->getMapSize().width * _map->getTileSize().width) - winSize.width/2);
	y = MIN(y, (_map->getMapSize().height * _map->getTileSize().height) - winSize.height/2);

	CCPoint actualPosition = ccp(x, y);

	CCPoint centerOfView = ccp(winSize.width/2, winSize.height/2);
	CCPoint viewPoint = ccpSub(centerOfView, actualPosition);
	//设定一下地图的地位
	_map->setPosition(viewPoint);
}
     办法参数就是玩家考拉当前地位。这个办法可以不只能阁下跟随还能高低跟随主角,异常好用。这个办法道理在很多博客都有提到,道理其实就是地图在跟玩家做返偏向活动,大年夜家可以查阅一下其他文┞仿解释它的道理,不过我在这里不想再多说了,不是一两句能说清,我们只要会用这个办法就行了。
    我们要做的就是在GameLevelLayer类的update办法里调用就行了,可以放在update办法结尾之前,如下:
    this->setViewpointCenter(_player->getPosition());
    如今build再run一下,这回我们的小考拉再也不会跑出屏幕外了!


尝一下受伤的滋味!
在player.cpp的init办法或在构造函数里把它们设置为false
如今我们可以着手做游戏过关和GameOver的功能了。
地图里有个hazards层,这个层里放置一些考拉碰上就会挂的object。其实本质也上碰撞检测,看代码:

void GameLevelLayer::handleHazardCollisions(Player* player)
{
	CCArray *tiles = this->getSurroundingTilesAtPosition(player->getPosition(), _hazards);
	CCDictionary* dic = NULL;
	CCObject* obj = NULL;
	float x=0.f; float y = 0.f;
	int gid = 0;
	CCARRAY_FOREACH(tiles, obj)
	{
		dic = (CCDictionary*)obj;
		x = dic->valueForKey("x")->floatValue();
		y = dic->valueForKey("y")->floatValue();
		CCRect tileRect = CCRectMake(x, y, _map->getTileSize().width, _map->getTileSize().height);
		CCRect pRect= player->collisionBoundingBox();

		gid = dic->valueForKey("gid")->intValue();
		if (gid && tileRect.intersectsRect(pRect))  //如不雅有钉刺并且玩家与它产生碰壮了棘gameOver
		{
			this->gameOver(false);
		}
	}
}
代码看上倒是不是很熟悉呀,你没记错,其实就是大年夜checkAndResolveCollisions办法里拷来的,只不过没分那么多情况并且处理方法也简单了只是调用了gameOver办法,gameOver的布尔值参数为true表示游戏成功,为false就是掉败
_hazards在GameLevelLayer类也是个CCTMXLayer* 地图层类型的成员变量,在词攀类的init办法里初始化它:
_hazards = _map->layerNamed("hazards");
学完此教程后,你可以学到
剩下我们还能做什么?
然后在update办法里调用这个办法,如今update办法是这个样子:
void GameLevelLayer::update(float delta)
{
	_player->update(delta);

	this->handleHazardCollisions(_player);
	
	this->checkForAndResolveCollisions(_player);
	this->setViewpointCenter(_player->getPosition());
}
如今实现gameOver办法了,当玩家跳到harads层里的刺上时,我们会调用这个办法游戏停止,或者当玩家走到终点时,我也会调用这个办法,这个办法会显示出一个restart按钮,并在屏幕上打印出一些信息,告诉玩家你逝世了或者你赢了之类的-_-
有兴趣可到此看看: 横版格斗游戏源码
void GameLevelLayer::gameOver(bool bWon)
{
	bGameOver = true;

	CCString* gameText;
	if (bWon)
	{
		gameText = CCString::create("You Won!");
	}
	else
		gameText = CCString::create("You have Died!");

	CCLabelTTF* diedLabel = CCLabelTTF::create(gameText->getCString(), "Marker Felt", 40);
	diedLabel->setPosition(ccp(240, 200));
	CCMoveBy *slideIn = CCMoveBy::create(1.f, ccp(0, 250));
	CCMenuItemImage* replay = CCMenuItemImage::create("replay.png","replay.png","replay.png", this, menu_selector(GameLevelLayer::restartGame));

	CCArray *menuItems = CCArray::create();
	menuItems->addObject(replay);
	CCMenu *menu = CCMenu::create();
	menu->addChild(replay);
	menu->setPosition(ccp(240, -100));

	this->addChild(menu);
	this->addChild(diedLabel);

	menu->runAction(slideIn);
}
办法开首的变量bGameOver也是GameLevelLayer类新定义的一个成员变量,在init里要初始化为false,此变量表示游戏是否停止。这个变量感化是你在update办法里开首断定一下,如不雅bGameOver==true,则直接返回不要做任何事了。如下:
void GameLevelLayer::update(float delta)
{
	if(bGameOver)
		return;

	_player->update(delta);

	this->handleHazardCollisions(_player);
	
	this->checkForAndResolveCollisions(_player);
	this->setViewpointCenter(_player->getPosition());
}
如今你再编译运行,碰上钉板尝尝,会出现杯具性的终局...
[img]http://img.blog.csdn.net/20150104234824031
不要测验测验的太多,当心动物保护组织会找上你家门来(-_-这就是所谓的美式滑稽吗?)
修改一个致命BUG
还记得前面出现过当考拉掉落出地图出现的工作吗?在游戏地图里有些坑我们本意是考拉掉落下却竽暌刮戏会停止,但事实上法度榜样崩掉落了。凡是带有TILED地图的都邑出现如许的问题,只要角色走出地图界线游戏就会崩掉落,这个问题困扰了很多多少人,也包含我。其实解决这个BUG很简单,关键在tileGIDAt办法。
#include "SimpleAudioEngine.h"
此办法你打开源码实现就知道,它有个CCASSERT宏,断定出地图就会抛出异常。本来吗此办法是取地图上某处tile的gid,你都出地图了还取什么当然要抛异常啦。这里我们就在getSurroundingTilesAtPosition办法里加个断定,留意当然要在调用tileGIDAt办法之前,不让考拉出地图:


if (bGameOver) //可能玩家掉落坑里,就不处理了
	{
		return;
	}
编译再运行,把考拉掉落进坑里尝尝,发明法度榜样不再DOWN了!
Winner!
      这里我们简单点,只是断定下考拉向右走了多远就取胜
void GameLevelLayer::checkForWin()
{
	if (_player->getPositionX()>3130.0)
	{
		this->gameOver(true);
	}
}
真实游戏里我们平日在终点放置一个object,如门呀城堡小旗什么的,主角碰着就成功了可进入下一关,有兴趣的本身测验测验!
这个办法也要放到GameLevelLayer的update办法里,如下:
void GameLevelLayer::update(float delta)
{
	if(bGameOver)
		return;

	_player->update(delta);

	this->handleHazardCollisions(_player);
	this->checkForWin();
	this->checkForAndResolveCollisions(_player);
	this->setViewpointCenter(_player->getPosition());
}
运行一下,走到终点尝尝:
[img]http://img.blog.csdn.net/20150105001049297
void GameLevelLayer::gameOver(bool bWon)
{
	if (bGameOver)  //不要反复调用 
	{
		return;
	}
	bGameOver = true;
	SimpleAudioEngine::sharedEngine()->playEffect("hurt.wav");
编译运行,试一试你亲手制造的带有音乐感的游戏吧!
添加音效
在GamelevelLayer的init办法里加上:
成功了之后没有音乐怎么行,一个无声的世界可真是会令人掉望呀,来我们加些音效吧!
在GameLevelLayer.cpp和 player.cpp加上头文件如下:
   在最后,我们处理下考拉走到终点时显示成功的情况。
using namespace CocosDenshion;
SimpleAudioEngine::shareEngine()->playBackgroundMusic("level1.mp3");
在player.cpp里的update办法里断定玩家跳的处所加上音效:
if(this->bMightAsWellJump && this->onGround)  //如不雅当前玩家按了跳跃键并且在地上
	{
		this->_velocity = ccpAdd(this->_velocity, jumpForce); //跳跃就是加上一个向上的速度
		SimpleAudioEngine::sharedEngine()->playEffect("jump.wav");
	}
在GameLevelLayer.cpp的gameOver办法里也加上音效:

源码下载地址:下载
要做的还有什么,角色动画没有吧,此外还有怪物,AI, 关卡,角色状况机等等。这些都在IOS GAME三件套 Platformer Start Kit里,前面说过,本教程只是这个Start Kit的前奏曲,那真正的Platformer game是什么样的呢?
[img]http://img.blog.csdn.net/20150105003648910

[img]http://img.blog.csdn.net/20150105000307598
[img]http://gd3.alicdn.com/imgextra/i3/39772956/TB2G831bpXXXXXRXpXXXXXXXXXX_!!39772956.jpg
[img]http://gd1.alicdn.com/imgextra/i1/39772956/TB2HL71bpXXXXavXpXXXXXXXXXX_!!39772956.jpg
[img]http://gd4.alicdn.com/imgextra/i4/39772956/TB2DUo5bpXXXXb1XXXXXXXXXXXX_!!39772956.jpg
[img]http://gd2.alicdn.com/imgextra/i2/39772956/TB2MGM9bpXXXXXkXXXXXXXXXXXX_!!39772956.jpg
[img]http://gd4.alicdn.com/imgextra/i4/39772956/TB2.ds5bpXXXXcqXXXXXXXXXXXX_!!39772956.jpg
[img]http://gd3.alicdn.com/imgextra/i3/39772956/TB2RJw6bpXXXXbIXXXXXXXXXXXX_!!39772956.jpg
[img]http://gd1.alicdn.com/imgextra/i1/39772956/TB2o7c0bpXXXXaGXpXXXXXXXXXX_!!39772956.jpg[img]http://gd1.alicdn.com/imgextra/i1/39772956/TB2fuA2bpXXXXXOXpXXXXXXXXXX-39772956.jpg
怎么样?心动了吧,善于版权问题不便在此公开,有兴趣的可到此看看: 横版平台游戏源码
此外大年夜名鼎鼎的三件套之一横版格斗游戏 Beat 'Em Up Game Starter Kit 也是异常出色哦!网上公开的源码教程还不到琅绫擎的二十分之一-_-
[img]http://img.blog.csdn.net/20150105004547469
[img]http://gd4.alicdn.com/imgextra/i4/39772956/TB2EFZ1XVXXXXarXpXXXXXXXXXX_!!39772956.png
    bool _forwardMarch;  //是否向前走
[img]http://gd2.alicdn.com/imgextra/i2/39772956/TB2RcU5XVXXXXbgXXXXXXXXXXXX_!!39772956.png
[img]http://gd1.alicdn.com/imgextra/i1/39772956/TB2RXM2XVXXXXXBXpXXXXXXXXXX_!!39772956.png
[img]http://gd2.alicdn.com/imgextra/i2/39772956/TB2qGA3XVXXXXXmXpXXXXXXXXXX_!!39772956.png[img]http://gd1.alicdn.com/imgextra/i1/39772956/TB2bPA8XVXXXXaaXXXXXXXXXXXX_!!39772956.png[img]http://gd4.alicdn.com/imgextra/i4/39772956/TB2Gy.8XVXXXXafXXXXXXXXXXXX_!!39772956.png
[img]http://gd4.alicdn.com/imgextra/i4/39772956/TB2dTA1XVXXXXXLXpXXXXXXXXXX_!!39772956.png
[img]http://gd4.alicdn.com/imgextra/i4/39772956/TB2lHZ4XVXXXXc5XXXXXXXXXXXX_!!39772956.png











相关案例查看更多