接着上次的界面,这次添加了武器主界面,原文出处 http://subject.9ria.com/cocos2d/index.html
现分析如下:
DefenderGameLayer.h
#ifndef __DEFENDERGAME_LAYER_H__
#define __DEFENDERGAME_LAYER_H__
#include "BaseLayer.h"
#include"math.h"
// 这个类是游戏主类
class DefenderGameLayer:public BaseLayer{
public:
static cocos2d::CCScene* scene(); //创建场景
virtual bool init(); //初始化
CREATE_FUNC(DefenderGameLayer); //创建层
virtual void onEnter(); //加载
virtual bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);//开始触摸
virtual void ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);//触摸点移动
virtual void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);//结束触摸
virtual void ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);//取消触摸
private:
bool setUpdateViews(); //创建纹理
void detectd(float tim);// 这个方法用来获取判断子弹是否相撞 是否可以获取子弹
// 武器的旋转动画执行完的时候执行这个回调函数
void weapCallBack(cocos2d::CCNode* pSend);
};
#endif
DefenderGameLayer.cpp
#include "DefenderGameLayer.h"
#include "WeaponSprite.h"
#include"math.h"
USING_NS_CC;
CCScene* DefenderGameLayer::scene(){
CCScene* scene=CCScene::create(); //创建场景
DefenderGameLayer* layer=DefenderGameLayer::create();//创建该层
scene->addChild(layer); //将层添加进场景
return scene;
}
bool DefenderGameLayer::init(){
bool isRet=false;
do
{
CC_BREAK_IF(!BaseLayer::init());
CC_BREAK_IF(!setUpdateViews());
this->schedule(schedule_selector(DefenderGameLayer::detectd),0.1f);
isRet=true;
} while (0);
return isRet;
}
bool DefenderGameLayer::setUpdateViews(){
bool isRet=false;
do
{
// 设置背景图片
CCTexture2D* ptext2dBg=CCTextureCache::sharedTextureCache()->textureForKey("gmbg/gamebg.png");
CCSprite* pSpribg=CCSprite::createWithTexture(ptext2dBg);
CC_BREAK_IF(!pSpribg);
pSpribg->setPosition(getWinCenter());
this->addChild(pSpribg,1);
//初始化武器系统
//初始化武器系统
CCTexture2D* texture=CCTextureCache::sharedTextureCache()->textureForKey("game/weapon.png");
WeaponSprite* pweapon=WeaponSprite::createWithTexture(texture);
pweapon->setAnchorPoint(ccp(0.3,0.5));
pweapon->setPosition(ccp(0,getWinSize().height/2));
this->addChild(pweapon,3,2);
pweapon->setHudu(0);
pweapon->initIdleBulletSpool(this);// 初始化 子弹系统
isRet=true;
} while (0);
return isRet;
}
void DefenderGameLayer::onEnter(){
BaseLayer::onEnter();
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(
this,//在那个类中实现触屏回调函数
0, //优先级
true);//触摸时间是否被该目标截获
}
bool DefenderGameLayer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent){
WeaponSprite* pweapon=(WeaponSprite*) this->getChildByTag(2);
CCPoint dpoint=pTouch->getLocation(); //触点坐标
CCPoint ypoint=pweapon->getPosition(); //武器坐标
float chy=dpoint.y-ypoint.y;
float chx=dpoint.x-ypoint.x;
float hud=atan(chy/chx); //计算弧度
float rota=-(hud*(180/PI));
CCActionInterval* paction= CCRotateTo::create(0.2,rota);//转过了rota的角度,是负的
CCCallFuncN *onComplete = CCCallFuncN::create(this, callfuncN_selector(DefenderGameLayer::weapCallBack));
CCSequence* pse=CCSequence::create(paction,onComplete,NULL);
pweapon->runAction(pse);//执行武器旋转和子弹旋转动作
pweapon->setHudu(-hud);//设置弧度为-hud,因为表示的是转过的角度,而不是真正的角度,顺时针为正
pweapon->setStop(true);
return true;
}
void DefenderGameLayer::weapCallBack(CCNode* pSend){
WeaponSprite* pweapon=(WeaponSprite*)pSend;
pweapon->rotateLoadedBullets(); //将子弹旋转装载
CCLOG("wobiezhixingle");
}
void DefenderGameLayer::ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent){//触摸移动和触摸时的方法效果是一样的
WeaponSprite* pweapon=(WeaponSprite*) this->getChildByTag(2);
CCPoint dpoint=pTouch->getLocation();
CCPoint ypoint=pweapon->getPosition();
float chy=dpoint.y-ypoint.y;
float chx=dpoint.x-ypoint.x;
float hud=atan(chy/chx);
float rota=-(hud*(180/PI));
CCActionInterval* paction= CCRotateTo::create(0.2,rota);
CCCallFuncN *onComplete = CCCallFuncN::create(this, callfuncN_selector(DefenderGameLayer::weapCallBack));
CCSequence* pse=CCSequence::create(paction,onComplete,NULL);
pweapon->runAction(pse);
pweapon->setStop(true);
pweapon->setHudu(-hud);
}
void DefenderGameLayer::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent){
WeaponSprite* pweapon=(WeaponSprite*) this->getChildByTag(2);//如果触摸结束则武器停止移动
pweapon->setStop(false);
}
void DefenderGameLayer::ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent){
}
void DefenderGameLayer::detectd(float tim){ //检测子弹是否碰撞,武器重新上弹
WeaponSprite* pweapon=(WeaponSprite*) this->getChildByTag(2);//得到武器精灵对象
if(pweapon->getRunBulletsPool()){
CCArray* tem=CCArray::create();
for(int i=0;i<pweapon->getRunBulletsPool()->count();i++){//子弹池的子弹数量
BulletsSprite* pbu=(BulletsSprite*) pweapon->getRunBulletsPool()->objectAtIndex(i);//取得子弹对象池的当前索引的子弹
if (pbu->boundingBox().getMinX()>=getWinSize().width||pbu->boundingBox().getMinY()<0||pbu->boundingBox().getMinY()>=getWinSize().height){
pweapon->recoverBullet(pbu); //如果子弹出界则子弹调用重新上弹方法
tem->addObject(pbu);//将子弹添加进数组
}else {
pbu->mymove();// 调用子弹移动方法
}
}
for(int j=0;j<tem->count();j++){ //
pweapon->getRunBulletsPool()->removeObject(tem->objectAtIndex(j),false);
}
tem->removeAllObjects();
}
}
BulletsSprite.h
#ifndef __BULLETS_SPRITE_H__
#define __BULLETS_SPRITE_H__
#include "cocos2d.h"
class BulletsSprite :public cocos2d::CCSprite
{
public:
BulletsSprite(void);
~BulletsSprite(void);
//virtual bool initWithTexture(cocos2d::CCTexture2D *pTexture);//初始化纹理
static BulletsSprite* createWithTexture(cocos2d::CCTexture2D *pTexture);//创建对象
inline void setMovespeed(float movespeed){//设置子弹移动速度
this->movespeed=movespeed;
}
inline float getMovespeed(){ //得到子弹移动速度
return movespeed;
}
inline void setHurt(float hurt){//设置伤害
this->hurt=hurt;
}
inline float getHurt(){//得到伤害值
return hurt;
}
cocos2d::CCPoint getMovePoint();// 这个是根据当前速度获取精灵的坐标
void mymove();// 移动函数
// 第一次被设置为弓箭的角度
CC_SYNTHESIZE(float,firstRoto,FirstRoto);//用来设置getter和setter属性
// 最后一次被弓箭的角度
CC_SYNTHESIZE(float,lastRoto,LastRoto);
private:
float movespeed;// 移动速度
float hurt;// 攻击力伤害值
};
#endif
BulletsSprite.cpp
#include "BulletsSprite.h"
#include "BaseLayer.h"
#include <cmath>
USING_NS_CC;
BulletsSprite* BulletsSprite::createWithTexture(CCTexture2D *pTexture){
BulletsSprite *pobSprite = new BulletsSprite();
if (pobSprite && pobSprite->initWithTexture(pTexture))
{
pobSprite->autorelease();
return pobSprite;
}
CC_SAFE_DELETE(pobSprite);
return NULL;
}
CCPoint BulletsSprite::getMovePoint(){
// 这里使用了 三角函数 主要是为了计算当前子弹所移动的位置
float temhud= (this->getLastRoto()*PI)/180;//将最后的弧度转换成角度
float tex= std::cos(temhud)*this->movespeed;//将速度乘以cos值得到横坐标
float tey= std::sin(temhud)*this->movespeed;
tex=std::fabs(tex);// x 方向不存在负数
return ccp(tex,-tey);//取得移动的坐标
}
void BulletsSprite::mymove(){
CCPoint cp=getMovePoint();
float x=cp.x+this->getPositionX();
float y=cp.y+this->getPositionY();//起始位置+移动的坐标
this->setPosition(ccp(x,y));//设置位置
}
BulletsSprite::BulletsSprite(void):movespeed(2)//设置速度为2,初始化firstRoto和lastRoto为0
{
this->firstRoto=0;
this->lastRoto=0;
}
BulletsSprite::~BulletsSprite(void)
{
}
WeaponSprite.h
#ifndef __WEAPON_SPRITE_H__
#define __WEAPON_SPRITE_H__
#include "cocos2d.h"
#include "BulletsSprite.h"
// 这个是武器系统 用来发射子弹
class WeaponSprite:public cocos2d::CCSprite{
public:
WeaponSprite();
~WeaponSprite();
CREATE_FUNC(WeaponSprite);//创建WeaponSprite对象
virtual bool initWithTexture(cocos2d::CCTexture2D *pTexture);//初始化纹理
static WeaponSprite* createWithTexture(cocos2d::CCTexture2D *pTexture);
cocos2d::CCArray* getIdleBullet(int cout);// 根据目前武器系 的级别获取当前子弹的数量默认级别是1个空闲的子弹
void recoverBullet(BulletsSprite* pbullet);// 回收掉一个子弹
void initIdleBulletSpool(cocos2d::CCLayer* pLayer);// 初始化子弹池
CC_SYNTHESIZE(bool,stop,Stop);
// 设置当前的武器旋转的弧度制
void setHudu(float hudu);
inline cocos2d::CCSpriteBatchNode* getBatchNode(){//得到批量穿件节点
return batchNode;
}
inline cocos2d::CCArray* getRunBulletsPool(){//得到正在运动的子弹对象池数组
return pRunBulletsPool;
}
inline cocos2d::CCArray* getLoadedArray(){//得到上膛的子弹
return loadedArray;
}
// 当武器旋转的时候 正在枪膛里面的弹药也是需要旋转的
void rotateLoadedBullets();
private:
cocos2d::CCArray* pIdleBulletsPool;// 空闲子弹池
cocos2d::CCArray* pRunBulletsPool;// 正在运行的子弹池
cocos2d::CCSpriteBatchNode* batchNode;// 批量穿件子弹 优化方法
cocos2d::CCArray* loadedArray;// 这是上膛的子弹 其实就是在弓箭上显示的子弹 这个时候的子弹是待发状态
float hudu;// 武器所旋转的弧度值
// 给武器装备子弹 cout 表示 一次上的子弹的个数
void loadedBullet(int cout=1);
void loade(float tim);
};
#endif
WeaponSprite.cpp
#include "WeaponSprite.h"
#include "BaseLayer.h"
// 定义 每个弓箭之间的间距是20
#define SPA 10
USING_NS_CC;
bool WeaponSprite::initWithTexture(CCTexture2D *pTexture){
bool bRet=false;
do
{
CC_BREAK_IF(!CCSprite::initWithTexture(pTexture));
// 初始话跑动的子弹
this->pRunBulletsPool=CCArray::create();//初始化子弹池数组
this->pRunBulletsPool->retain();//保留子弹池
//this->speed=10;
this->hudu=0;
bRet=true;
} while (0);
return bRet;
}
void WeaponSprite::initIdleBulletSpool(CCLayer* player){ //初始化空闲子弹池
// 创建50个子弹的纹理图片 这样做的目的是为了加速游戏的运行速度
CCTexture2D* texture=CCTextureCache::sharedTextureCache()->textureForKey("game/wq0.png");
batchNode = CCSpriteBatchNode::createWithTexture(texture,50);//创建50个子弹的纹理图片
batchNode->setPosition(CCPointZero);
player->addChild(batchNode,2); //将batchNode精灵对象加入该层,zOrder为2
// 初始化子弹池
pIdleBulletsPool=CCArray::create();
pIdleBulletsPool->retain();
this->loadedArray=CCArray::create();//创建上膛的子弹数组
loadedArray->retain();
this->setZOrder(1);
for(int i=0;i<50;i++){
// 创建子弹
BulletsSprite* pbullet=BulletsSprite::createWithTexture(batchNode->getTexture());
// 把子弹的坐标设置成和当前武器的坐标是一样的
pbullet->setPosition(this->getPosition());
pbullet->setAnchorPoint(ccp(0,0.5));
// 设置子弹的移动速度为50
pbullet->setMovespeed(50);
// 把子弹放到子弹池中
this->pIdleBulletsPool->addObject(pbullet);
pbullet->setVisible(false);
// 把创建好的子弹放到 CCSpriteBatchNode 让其一次渲染
batchNode->addChild(pbullet,-1);
}
this->schedule(schedule_selector(WeaponSprite::loade),1);
}
void WeaponSprite::recoverBullet(BulletsSprite* pbullet){//回收掉子弹
pbullet->setPosition(this->getPosition());//子弹回到初始位置
pbullet->setRotation(0);
pbullet->setVisible(false);//设置为不可见
pbullet->setFirstRoto(0);
pbullet->setLastRoto(0);
this->pIdleBulletsPool->addObject(pbullet);//添加到空闲子弹池
}
WeaponSprite* WeaponSprite::createWithTexture(CCTexture2D *pTexture)
{
WeaponSprite *pobSprite = new WeaponSprite();
if (pobSprite && pobSprite->initWithTexture(pTexture))
{
pobSprite->autorelease();
return pobSprite;
}
CC_SAFE_DELETE(pobSprite);
return NULL;
}
void WeaponSprite::loade(float tim){
this->loadedBullet(5); //一次上5个子弹
}
void WeaponSprite::loadedBullet(int cout){
if (this->loadedArray->count()!=cout){ //如果上膛的子弹数组的数量不等于5
CCArray* tem=this->getIdleBullet(cout);//从空闲子弹池中取得子弹
for(int i=0;i<tem->count();i++){//循环取得子弹
BulletsSprite* pbul=(BulletsSprite*)tem->objectAtIndex(i);//根据索引取得相应的子弹
this->loadedArray->addObject(pbul);//将子弹加入上膛的子弹数组
}
}
// 表示需要发射 需要把 在枪膛中的子弹添加到 发射子弹中
if(this->stop){ //如果stop函数为true则发射
if(this->loadedArray->count()>0){
this->pRunBulletsPool->addObjectsFromArray(this->loadedArray);//将枪膛中的子弹加入发射子弹数组中
for(int i=0;i<this->loadedArray->count();i++){
this->loadedArray->removeObjectAtIndex(0,false);//依次将子弹从枪膛中的子弹数组中移除
i--;
}
}
}
}
CCArray* WeaponSprite::getIdleBullet(int cout){
CCArray* ptemar=CCArray::create();
float zhuwuqi= this->hudu*180/PI; //将弧度转换成角度
for(int i=0;i<cout;i++){
CCObject* pbul=this->pIdleBulletsPool->objectAtIndex(0);//获取空闲子弹池的子弹
if(pbul){ //如果获取到了
BulletsSprite* pbullet=(BulletsSprite*)pbul;
ptemar->addObject(pbul);//将获取的子弹添加进数组
pbullet->setVisible(true);//设置子弹为可见
// 这些要特别注意在获取子弹的时候进行初始化
pbullet->setFirstRoto(0);
pbullet->setLastRoto(zhuwuqi);//设置当前的角度
pbullet->setRotation(zhuwuqi);//初始化角度
this->pIdleBulletsPool->removeObjectAtIndex(0,false);
}else {
BulletsSprite* pbullet=(BulletsSprite*)BulletsSprite::createWithTexture(batchNode->getTexture());
pbullet->setMovespeed(50);//如果没有子弹了,创建子弹精灵,并将精灵添加进batchNode
pbullet->setPosition(this->getPosition());
pbullet->setRotation(0);
pbullet->setVisible(false);
pbullet->setFirstRoto(0);
pbullet->setLastRoto(0);
batchNode->addChild(pbullet,2);
i--;
}
}
if(cout>1){
// 如果 在箭堂里面的子弹是 大于 2 的时候需要均匀的分布在 箭堂 里面 规定两个 弓箭之间的角度是20度
bool isEven=cout%2==0?true:false;// 判断箭堂里面的弓箭是不是偶数
int pair=cout/2;// 能分成几对
int temsp=(cout-1)*SPA;// 得到所有弓箭之间的夹角
for(int i=0;i<ptemar->count();i++){
BulletsSprite* pbul=(BulletsSprite*)ptemar->objectAtIndex(i);
// 表示中间哪里没有弓箭 反之刚好中间哪里有弓箭
if (isEven){ //如果是偶数个箭头
if(i<pair){ // 表示上半部分
// 旋转 计算出旋转的角度
float temro=i*SPA+SPA/2;
pbul->setRotation(-temro+zhuwuqi);
pbul->setFirstRoto(-temro);
pbul->setLastRoto(-temro+zhuwuqi);
}else{ //表示的是下半部分的角度
float temro=(i-pair)*SPA+SPA/2;
pbul->setRotation(temro+zhuwuqi);
pbul->setFirstRoto(temro+zhuwuqi);
pbul->setLastRoto(temro+zhuwuqi);
}
}else{ //如果是奇数的话,则增加一个中间箭头的角度的设置
if(i<pair){ // 表示上半部分
// 旋转 计算出旋转的角度
float temro=i*SPA+SPA;
pbul->setRotation(-temro+zhuwuqi);
pbul->setFirstRoto(-temro);
pbul->setLastRoto(-temro+zhuwuqi);
}else if (i==pair){
pbul->setRotation(zhuwuqi);
pbul->setFirstRoto(0);
pbul->setLastRoto(zhuwuqi);
}
else{
float temro=(i-pair-1)*SPA+SPA;
pbul->setRotation(temro+zhuwuqi);
pbul->setFirstRoto(temro);
pbul->setLastRoto(temro+zhuwuqi);
}
}
}
}
return ptemar;
}
void WeaponSprite::setHudu(float hudu){
this->hudu=hudu;
}
void WeaponSprite::rotateLoadedBullets(){
// 获取当前武器旋转的角度
float zhuwuqi= this->hudu*180/PI;
if(this->loadedArray){
if(this->loadedArray->count()>0){
for(int i=0;i<this->loadedArray->count();i++){
BulletsSprite* pbul=(BulletsSprite*)loadedArray->objectAtIndex(i);
float temr=pbul->getFirstRoto();
pbul->setRotation(temr+zhuwuqi);
// 设置最后当前武器最后一次的旋转角度
pbul->setLastRoto(temr+zhuwuqi);
}
}
}
}
WeaponSprite::WeaponSprite(void){
this->stop=false;
this->hudu=0;
}
WeaponSprite::~WeaponSprite() //将所有有子弹的对象全都release
{
if (this->pIdleBulletsPool)
{
this->pIdleBulletsPool->release();
}
if (this->pRunBulletsPool)
{
this->pRunBulletsPool->release();
}
if (this->loadedArray)
{
this->loadedArray->release();
}
}