Cocos2d-x格斗小游戏(七) 攻击碰撞检测

1、本篇介绍玩家人物出拳攻击机器人,机器人受伤,血量减少,最后死亡。关键就是如何确定玩家精灵出拳是否击中了机器人。本例使用简单的矩形碰撞检测来实现该过程。下面接前一篇文章继续项目:


2、前面说过,玩家精灵和机器人都有5种状态(分别是Normal、Walk、Attack、Hurt和Dead),对应5个动作。这5个动作需要5个函数来加载这些动作所需的图片,并创建相应的动作。然后,在合理的地方调用这些动作。

      这些动作的实现大同小异,直接将代码贴出:

(1)首先是父类SpriteActions中定义的5个动作的调用函数:

SpriteActions.h

// 5种动作相应的调用函数
	void Normal();
	void Walk_WithDirection(cocos2d::CCPoint direction);
	void Attack();
	void Hurt_WithDamage(float damage);
	void Dead();

	// 5种动作
	CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _normalAction, NormalAction);
	CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _walkAction, WalkAction);
	CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _attackAction, AttackAction);
	CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _hurtAction, HurtAction);
	CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _deadAction, DeadAction);

SpriteActions.cpp(其中的有些变量是后添加的,暂时用不到,如果编译不过可以先注释掉,只保留Normal中类似的3句即可)

void SpriteActions::Normal()
{
	// 停止所有动作
	this->stopAllActions();
	// 执行正常状态的动作
	this->runAction(_normalAction);
	// 修改当前状态
	_spriteState = STATE_NORMAL;
}

void SpriteActions::Walk_WithDirection(cocos2d::CCPoint direction)
{
	if (_spriteState == STATE_NORMAL)
	{
		this->stopAllActions();
		this->runAction(_walkAction);
		_spriteState = STATE_WALK;
	}

	if (_spriteState == STATE_WALK)
	{
		_velocity = ccp(direction.x * _walkSpeed, direction.y * _walkSpeed);
		if(_velocity.x >= 0)
		{
			this->setScaleX(1.0);  // 翻转精灵
		}
		else
		{
			this->setScaleX(-1.0);
		}
	}
}

void SpriteActions::Attack()
{
	if (_spriteState == STATE_NORMAL || _spriteState == STATE_WALK || _spriteState == STATE_ATTACK)
	{
		this->stopAllActions();
		this->runAction(_attackAction);
		_spriteState = STATE_ATTACK;
	}
}

void SpriteActions::Hurt_WithDamage(float damage)
{
	if (_spriteState != STATE_ATTACK)
	{
		this->stopAllActions();
		this->runAction(_hurtAction);
		_spriteState = STATE_HURT;
		_HP -= damage;

		if (_HP <= 0)
		{
			this->Dead();
		}
	}
}

void SpriteActions::Dead()
{
	this->stopAllActions();
	this->runAction(_deadAction);
	_HP = 0;
	_spriteState = STATE_DEAD;
}

(2)创造5种动作,因为玩家精灵和机器人的5个动作是不一样的(主要是加载的动作图片不一样),所以要在SpritePlayer和SpriteRobot中分别实现(注:SpritePlayer和SpriteRobot是继承于SpriteActions类的,而SpriteActions类继承于CCSprite):

SpritePlayer.h

#pragma once
#include "cocos2d.h"
#include "SpriteActions.h"
class SpritePlayer : public SpriteActions
{
public:
	SpritePlayer(void);
	~SpritePlayer(void);

	bool init();
	CREATE_FUNC(SpritePlayer);

	// 加载Normal动作的图片
	bool loadNormalAnimation();
	// 加载Walk动作图片
	bool loadWalkAnimation();
	// 加载Attack动作图片
	bool loadAttackAnimation();
	// 加载Hurt动作图片
	bool loadHurtAnimation();
	// 加载Dead动作图片
	bool loadDeadAnimation();
};

SpritePlayer.cpp

#include "SpritePlayer.h"
USING_NS_CC;

SpritePlayer::SpritePlayer(void)
{
}


SpritePlayer::~SpritePlayer(void)
{
}


bool SpritePlayer::init()
{
	bool bRct = false;

	do 
	{
		CC_BREAK_IF(! SpriteActions::initWithSpriteFrameName("hero_idle_00.png"));
		CC_BREAK_IF(! loadNormalAnimation());
		CC_BREAK_IF(! loadWalkAnimation());
		CC_BREAK_IF(! loadAttackAnimation());
		CC_BREAK_IF(! loadHurtAnimation());
		CC_BREAK_IF(! loadDeadAnimation());

		bRct = true;
	} while (0);

	return bRct;
}

bool SpritePlayer::loadNormalAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pNormalFrames = NULL;
		pNormalFrames = CCArray::createWithCapacity(6);
		CC_BREAK_IF(! pNormalFrames);
		for (int i = 0; i < 6; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("hero_idle_%02d.png", i)->
				getCString());
			pNormalFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
			CC_BREAK_IF(! pSpriteFrame);
		}
		CCAnimation *pNormalAnimation = NULL;
		pNormalAnimation = CCAnimation::createWithSpriteFrames(pNormalFrames, 1.0 / 12.0);
		CC_BREAK_IF(! pNormalAnimation);
		this->setNormalAction(CCRepeatForever::create(CCAnimate::create(pNormalAnimation)));

		bRct = true;
	} while (0);

	return bRct;
}

bool SpritePlayer::loadWalkAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pWalkFrames = NULL;
		pWalkFrames = CCArray::createWithCapacity(8);
		CC_BREAK_IF(! pWalkFrames);
		for (int i = 0; i < 8; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("hero_walk_%02d.png", i)->
				getCString());
			pWalkFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
			CC_BREAK_IF(! pSpriteFrame);
		}
		CCAnimation *pWalkAnimation = NULL;
		pWalkAnimation = CCAnimation::createWithSpriteFrames(pWalkFrames, 1.0 / 12.0);
		CC_BREAK_IF(! pWalkAnimation);
		this->setWalkAction(CCRepeatForever::create(CCAnimate::create(pWalkAnimation)));

		bRct = true;
	} while (0);

	return bRct;
}

bool SpritePlayer::loadAttackAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pAttackFrames = NULL;
		pAttackFrames = CCArray::createWithCapacity(3);
		CC_BREAK_IF(! pAttackFrames);
		for (int i = 0; i < 3; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("hero_attack_00_%02d.png", i)->
				getCString());
			CC_BREAK_IF(! pSpriteFrame);
			pAttackFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
		}
		CCAnimation *pAttackAnimation = NULL;
		pAttackAnimation = CCAnimation::createWithSpriteFrames(pAttackFrames, 1.0 / 24.0);
		CC_BREAK_IF(! pAttackAnimation);
		this->setAttackAction(CCSequence::create(CCAnimate::create(pAttackAnimation), CCCallFunc::create(this, callfunc_selector(SpritePlayer::Normal)), NULL));  // 出拳动作执行一次后,变为Normal动作

		bRct = true;
	} while (0);

	return bRct;
}

bool SpritePlayer::loadHurtAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pHurtFrames = NULL;
		pHurtFrames = CCArray::createWithCapacity(3);
		CC_BREAK_IF(! pHurtFrames);
		for (int i = 0; i < 3; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("hero_hurt_%02d.png", i)->
				getCString());
			CC_BREAK_IF(! pSpriteFrame);
			pHurtFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
		}
		CCAnimation *pHurtAnimation = NULL;
		pHurtAnimation = CCAnimation::createWithSpriteFrames(pHurtFrames, 1.0 / 12.0);
		CC_BREAK_IF(! pHurtAnimation);

		this->setHurtAction(CCSequence::create(CCAnimate::create(pHurtAnimation), CCCallFunc::create(this, callfunc_selector(SpritePlayer::Normal)), NULL));  // 出拳动作执行一次后,变为Normal动作

		bRct = true;
	} while (0);

	return bRct;
}

bool SpritePlayer::loadDeadAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pDeadFrames = NULL;
		pDeadFrames = CCArray::createWithCapacity(5);
		CC_BREAK_IF(! pDeadFrames);
		for (int i = 0; i < 5; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("hero_knockout_%02d.png", i)->
				getCString());
			CC_BREAK_IF(! pSpriteFrame);
			pDeadFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
		}
		CCAnimation *pDeadAnimation = NULL;
		pDeadAnimation = CCAnimation::createWithSpriteFrames(pDeadFrames, 1.0 / 12.0);
		CC_BREAK_IF(! pDeadAnimation);
		this->setDeadAction(CCSequence::create(CCAnimate::create(pDeadAnimation), CCBlink::create(2.0, 10.0), NULL));  // 出拳动作执行一次后,变为Normal动作

		bRct = true;
	} while (0);

	return bRct;
}

SpriteRobot.h

#pragma once
#include "cocos2d.h"
#include "SpriteActions.h"
class SpriteRobot : public SpriteActions
{
public:
	SpriteRobot(void);
	~SpriteRobot(void);

	bool init();
	CREATE_FUNC(SpriteRobot);

	// 加载Normal动作的图片
	bool loadNormalAnimation();
	// 加载Walk动作图片
	bool loadWalkAnimation();
	// 加载Attack动作图片
	bool loadAttackAnimation();
	// 加载Hurt动作图片
	bool loadHurtAnimation();
	// 加载Dead动作图片
	bool loadDeadAnimation();
};

SpriteRobot.cpp

#include "SpriteRobot.h"
USING_NS_CC;

SpriteRobot::SpriteRobot(void)
{
}
SpriteRobot::~SpriteRobot(void)
{
}

bool SpriteRobot::init()
{
	bool bRct = false;

	do 
	{

		CC_BREAK_IF(! SpriteActions::initWithSpriteFrameName("robot_idle_00.png"));

		CC_BREAK_IF(! loadNormalAnimation());
		CC_BREAK_IF(! loadWalkAnimation());
		CC_BREAK_IF(! loadAttackAnimation());
		CC_BREAK_IF(! loadHurtAnimation());
		CC_BREAK_IF(! loadDeadAnimation());

		bRct = true;
	} while (0);

	return bRct;
}

bool SpriteRobot::loadNormalAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pNormalFrames = NULL;
		pNormalFrames = CCArray::createWithCapacity(5);
		CC_BREAK_IF(! pNormalFrames);
		for (int i = 0; i < 5; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("robot_idle_%02d.png", i)->
				getCString());
			CC_BREAK_IF(! pSpriteFrame);
			pNormalFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
		}
		CCAnimation *pNormalAnimation = NULL;
		pNormalAnimation = CCAnimation::createWithSpriteFrames(pNormalFrames, float(1.0 / 12.0));
		CC_BREAK_IF(! pNormalAnimation);
		this->setNormalAction(CCRepeatForever::create(CCAnimate::create(pNormalAnimation)));

		bRct = true;
	} while (0);

	return bRct;
}

bool SpriteRobot::loadWalkAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pWalkFrames = NULL;
		pWalkFrames = CCArray::createWithCapacity(6);
		CC_BREAK_IF(! pWalkFrames);
		for (int i = 0; i < 6; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("robot_walk_%02d.png", i)->
				getCString());
			CC_BREAK_IF(! pSpriteFrame);
			pWalkFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
		}
		CCAnimation *pWalkAnimation = NULL;
		pWalkAnimation = CCAnimation::createWithSpriteFrames(pWalkFrames, float(1.0 / 12.0));
		CC_BREAK_IF(! pWalkAnimation);
		this->setWalkAction(CCRepeatForever::create(CCAnimate::create(pWalkAnimation)));

		bRct = true;
	} while (0);

	return bRct;
}

bool SpriteRobot::loadAttackAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pAttackFrames = NULL;
		pAttackFrames = CCArray::createWithCapacity(5);
		CC_BREAK_IF(! pAttackFrames);
		for (int i = 0; i < 5; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("robot_attack_%02d.png", i)->
				getCString());
			CC_BREAK_IF(! pSpriteFrame);
			pAttackFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
		}
		CCAnimation *pAttackAnimation = NULL;
		pAttackAnimation = CCAnimation::createWithSpriteFrames(pAttackFrames, float(1.0 / 24.0));
		CC_BREAK_IF(! pAttackAnimation);
		//this->setAttackAction(CCRepeatForever::create(CCAnimate::create(pAttackAnimation))); // 注意:不是重复执行了
		this->setAttackAction(CCSequence::create(CCAnimate::create(pAttackAnimation), CCCallFunc::create(this, callfunc_selector(SpriteRobot::Normal)), NULL));  // 出拳动作执行一次后,变为Normal动作

		bRct = true;
	} while (0);

	return bRct;
}

bool SpriteRobot::loadHurtAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pHurtFrames = NULL;
		pHurtFrames = CCArray::createWithCapacity(3);
		CC_BREAK_IF(! pHurtFrames);
		for (int i = 0; i < 3; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("robot_hurt_%02d.png", i)->
				getCString());
			CC_BREAK_IF(! pSpriteFrame);
			pHurtFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
		}
		CCAnimation *pHurtAnimation = NULL;
		pHurtAnimation = CCAnimation::createWithSpriteFrames(pHurtFrames, float(1.0 / 12.0));
		CC_BREAK_IF(! pHurtAnimation);

		this->setHurtAction(CCSequence::create(CCAnimate::create(pHurtAnimation), CCCallFunc::create(this, callfunc_selector(SpriteRobot::Normal)), NULL));  // 出拳动作执行一次后,变为Normal动作

		bRct = true;
	} while (0);

	return bRct;
}

bool SpriteRobot::loadDeadAnimation()
{
	bool bRct = false;

	do 
	{
		CCArray *pDeadFrames = NULL;
		pDeadFrames = CCArray::createWithCapacity(5);
		CC_BREAK_IF(! pDeadFrames);
		for (int i = 0; i < 5; i++)
		{
			CCSpriteFrame *pSpriteFrame = NULL;
			pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->
				spriteFrameByName(CCString::createWithFormat("robot_knockout_%02d.png", i)->
				getCString());
			CC_BREAK_IF(! pSpriteFrame);
			pDeadFrames->addObject(pSpriteFrame); // 别忘了添加到数组中
		}
		CCAnimation *pDeadAnimation = NULL;
		pDeadAnimation = CCAnimation::createWithSpriteFrames(pDeadFrames, float(1.0 / 12.0));
		CC_BREAK_IF(! pDeadAnimation);
		this->setDeadAction(CCSequence::create(CCAnimate::create(pDeadAnimation), CCBlink::create(2.0, 10.0), NULL));  // 出拳动作执行一次后,变为Normal动作

		bRct = true;
	} while (0);

	return bRct;
}


3、OK,现在动作都有了,问题剩下何时调用这些动作。分以下几点说明:

(1)玩家精灵的默认状态为Normal(循环执行左右晃动动作);

(2)当点击虚拟方向键不松开时,玩家精灵执行Walk动作(双腿交替);

(3)当点击窗口其它区域(非方向键)时,玩家精灵执行Attack动作(出拳);

(4)以上3个动作都是玩家精灵的,我们已经在前面的文章中实现了,下面我们介绍机器人的动作。

(5)因为机器人的动作只实现了Normal动作(上下抖动以及排气),所以现在机器人不会动,不会攻击。

(6)本文要实现的效果是:玩家精灵出拳攻击机器人,机器人执行相应的Hurt(受伤)动作,当机器人的HP小于零时,机器人执行Dead(死亡)动作。


4、为了确定玩家精灵出拳Attack后是否击中了机器人,可以用一个简单的碰撞检测来实现:


(1)我们可以定义这样一个结构,包含两个CCRect型变量:bodyRect(身体矩形)和 punchesRect(出拳矩形);

可以定义在GameDefines.h中:

typedef struct _SurroundRect
{
	cocos2d::CCRect bodyRect;      // 身体的矩形区域
	cocos2d::CCRect punchesRect;   // 出拳的矩形区域
}SurroundRect;

(2)只要将玩家精灵的punchesRect和机器人的bodyRect进行碰撞检测,就能确定玩家精灵是否击中了机器人。

(3)现在只需要获取玩家精灵punchesRect的位置和机器人bodyRect的位置就行了。

(4)显然,玩家精灵是会移动的,punchesRect的位置是不断改变的,而机器人目前是不会移动的。玩家要控制玩家精灵走到机器人边上,然后出拳,这样才符合常理。

(5)因为我们移动玩家精灵是通过在计时器中调用setPosition函数实现的,所以可以重载setPosition这个函数,在

原有功能上执行一个更新bodyRect和punchesRect的函数。

(6)因为SpritePlayer和SpriteRobot都需要更新bodyRect和punchesRect的位置,所以在父类SpriteActions中重载setPosition函数。

(7)具体如何确定bodyRect和punchesRect,实际上是基于精灵当前的位置坐标(getPosition)换算出来的,矩形的width和hight不会变,只是矩形左下角(原点)的坐标不断改变。


5、下面是具体实现:

(1)SpriteActions.h(别忘了包含GameDefines.h)

// 精灵的大小
	CC_SYNTHESIZE(cocos2d::CCSize, _spriteSize, SpriteSize);
	// 出拳的矩形范围
	CC_SYNTHESIZE(cocos2d::CCRect, _punshesRect, PunchesRect);

	// 碰撞检测矩形
	CC_SYNTHESIZE(SurroundRect, _collisionDetectionRect, CollosionDetectionRect);

	// 更新
	void updateSurroundedRect();
	// 重载
	void setPosition(const cocos2d::CCPoint& pos);

(2)SpriteActions.cpp

void SpriteActions::updateSurroundedRect()
{
	const CCPoint ptNow = this->getPosition();
	
	_collisionDetectionRect.bodyRect.origin = ccp(ptNow.x - this->getSpriteSize().width / 2, ptNow.y - this->getSpriteSize().height / 2); // 原点
	_collisionDetectionRect.bodyRect.size.width = this->getSpriteSize().width;
	_collisionDetectionRect.bodyRect.size.height = this->getSpriteSize().height;

	_collisionDetectionRect.punchesRect = this->getPunchesRect();

	if (this->getScaleX() == 1.0)
	{
		_collisionDetectionRect.punchesRect.origin = ccp(ptNow.x + this->getSpriteSize().width / 2, ptNow.y);
	}
	else
	{
		_collisionDetectionRect.punchesRect.origin = ccp(ptNow.x - this->getSpriteSize().width / 2, ptNow.y);
	}
} 


void SpriteActions::setPosition(const cocos2d::CCPoint& pos)
{
	CCSprite::setPosition(pos);
	this->updateSurroundedRect();
}

(3)另外,碰撞矩形的长和宽是测量值,血量,速度等属性值需要在init函数中设置,同样定义在SpriteActions类中:

SpriteActions.h

// 属性
	CC_SYNTHESIZE(float, _walkSpeed, WalkSpeed);  // 速度
	CC_SYNTHESIZE(float, _HP, HP);// 伤害点
	CC_SYNTHESIZE(float, _onceDamage, OnceDamage); // 攻击力(一次攻击对方损失的HP)

(4)在SpritePlayer和SpriteRobot的init函数中分别初始化属性和碰撞矩形的大小:

SpritePlayer.cpp 

bool SpritePlayer::init()
{
	bool bRct = false;

	do 
	{
		CC_BREAK_IF(! SpriteActions::initWithSpriteFrameName("hero_idle_00.png"));
		CC_BREAK_IF(! loadNormalAnimation());
		CC_BREAK_IF(! loadWalkAnimation());
		CC_BREAK_IF(! loadAttackAnimation());
		CC_BREAK_IF(! loadHurtAnimation());
		CC_BREAK_IF(! loadDeadAnimation());

		// 设置属性
		this->setWalkSpeed(140.0);  // 速度
		this->setSpriteSize(CCSizeMake(2 * 29, 2 * 39));  // 精灵大小
		this->setHP(100);         // 血量
		this->setOnceDamage(20);  // 伤害
		this->setPunchesRect(CCRectMake(0, 0, 30, 20));  // 出拳矩形的大小

		bRct = true;
	} while (0);

	return bRct;
}

SpriteRobot.cpp

bool SpriteRobot::init()
{
	bool bRct = false;

	do 
	{

		CC_BREAK_IF(! SpriteActions::initWithSpriteFrameName("robot_idle_00.png"));

		CC_BREAK_IF(! loadNormalAnimation());
		CC_BREAK_IF(! loadWalkAnimation());
		CC_BREAK_IF(! loadAttackAnimation());
		CC_BREAK_IF(! loadHurtAnimation());
		CC_BREAK_IF(! loadDeadAnimation());

		// 设置属性
		this->setSpriteSize(CCSizeMake(2 * 29, 2 * 39));
		this->setHP(100);

		bRct = true;
	} while (0);

	return bRct;
}

(5)在GameBasicLayer中进行碰撞检测,将检测的过程封装成一个函数collisionDetection:

void GameBasicLayer::collisionDetection()
{
	if (_spritePlayer->getSpriteState() == STATE_ATTACK)
	{
		CCObject *pObj = NULL;
		CCARRAY_FOREACH(_spriteRobot, pObj)
		{
			SpriteRobot *pRobot = (SpriteRobot*)pObj;
			if (pRobot->getSpriteState() != STATE_DEAD)
			{
				if (fabsf(_spritePlayer->getPosition().y - pRobot->getPosition().y) < 10)
				{
					if (_spritePlayer->getCollosionDetectionRect().punchesRect.intersectsRect(pRobot->getCollosionDetectionRect().bodyRect))
					{
						pRobot->Hurt_WithDamage(_spritePlayer->getOnceDamage());
					}
				}
			}
		}
	}
}

函数说明:最里面的if语句进行碰撞检测,由内至外倒数第二个if语句用于实现简单的三维效果,即当玩家精灵和机器人的前后距离超过一定界限(这里为10)时(不再一个平面内),出拳后无法击中目标。


(6)最后,在触摸响应事件中调用该函数:

void GameBasicLayer::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
	_spritePlayer->Attack();

	collisionDetection();
}


6、运行效果如下:



7、待续



很高兴回答您关于C语言双人格斗小游戏的问题!为了帮助您更好地了解该游戏的开发,我将为您提供一些基本的思路和步骤。 首先,您需要选择一个合适的开发环境,比如Code::Blocks或者Dev-C++,以便编写和运行C语言代码。 接下来,您可以考虑以下几个方面来设计和实现您的双人格斗小游戏: 1. 角色选择和初始化:让玩家选择自己的角色,并初始化双方角色的属性,如血量、攻击力等。 2. 控制和输入:使用键盘输入来控制角色的移动和攻击操作。您可以使用C语言的输入函数(如scanf)来获取玩家的输入。 3. 游戏循环:使用一个循环结构来实现游戏的进行。在每一轮循环中,检测玩家的输入并更新游戏状态,最后显示结果。 4. 攻击和防御:定义角色的攻击和防御动作,并在游戏中实现。您可以使用条件语句(如if-else)来判断角色之间的攻击和防御关系,并更新双方角色的血量。 5. 游戏结束条件:当其中一方角色的血量归零时,游戏结束。您可以使用条件语句来判断并显示获胜方。 6. 图形界面:如果您希望为游戏增加一些可视化效果,您可以考虑使用图形库(如graphics.h)来绘制角色和游戏场景。 这只是一个简单的思路,您可以根据自己的需求和实际情况进行更详细的设计和开发。希望这些信息对您有所帮助!如果您有任何进一步的问题,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值