zoukankan      html  css  js  c++  java
  • Cocos2dx游戏开发系列笔记13:一个横版拳击游戏Demo完结篇

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


    写下这些东西的同时

    旁边放了两部电影

    周星驰的《还魂夜》

    甄子丹的《特殊身份》

    骨头听着电影读代码

    别有一番风味


    接上篇,今天继续看一下这个demo。



    ----------------------------------------------------------------------------------------------------------------------------------------------------------

     GameScene.cpp类。 

    ----------------------------------------------------------------------------------------------------------------------------------------------------------

    这个类里主要有两层,上层是控制层:HudLayer,下层是游戏层:GameLayer

    init初始化方法里有个输入更新函数:

    this->schedule(schedule_selector(GameScene::inputUpdate));

    void GameScene::inputUpdate(float dt)
    {
    	CCPoint velocity = mHudLayer->mJoystick->getVelocity();
    	//std::cout << velocity.x << std::endl;
    
    	if (velocity.x >= 0.4f || velocity.x <= -0.4f ||
    		velocity.y >= 0.4f || velocity.y <= -0.4f) {
    		mGameLayer->mHero->walkWithDirection(velocity);
    	} else if (mGameLayer->mHero->mActionState == kActionStateWalk) {
    		mGameLayer->mHero->idle();
    	}
    
    	if (attackInterval <= 0.0f) {
    		if (mHudLayer->mButtonA->getIsActive()) {
    			mGameLayer->mHero->attack();
    			attackInterval = 0.5f;
    
    			if (mGameLayer->mHero->mActionState == kActionStateAttack) {
    				CCObject* item;
    				CCARRAY_FOREACH(mGameLayer->mRobots, item) {
    					Robot* robot = dynamic_cast<Robot*>(item);
    					if (robot->mActionState != kActionStateKnockedOut) {
    						if (fabs(mGameLayer->mHero->getPositionY() - robot->getPositionY()) < 10) {
    							//std::cout << "yew" << std::endl;
    							if (mGameLayer->mHero->mAttackBox.actual.intersectsRect(robot->mHitBox.actual)) {
    								robot->hurtWithDamage(mGameLayer->mHero->mDamage);
    								//std::cout << "yew!!!!!!!!!!!!" << std::endl;
    							}
    						}
    					}
    				}
    			}
    		}
    	} else {
    		attackInterval -= dt;
    	}
    }


    通过Joystick虚拟摇杆获取速度

    CCPoint velocity = mHudLayer->mJoystick->getVelocity(); 

    如果x,y两个方向的速度大于0.4的话,主角移动。

    否则,主角原地不动。

    继续判断

    如果攻击按钮被按下,则主角进行攻击。

    if (mHudLayer->mButtonA->getIsActive())
    mGameLayer->mHero->attack();

    此时,遍历所有的robot机器人,看我们的主角击中了哪个robot,

    击中的那个(矩形相交),调用受伤方法

    robot->hurtWithDamage(mGameLayer->mHero->mDamage);

    ----------------------------------------------------------------------------------------------------------------------------------------------------------

    GameLayer 主要逻辑类

    ----------------------------------------------------------------------------------------------------------------------------------------------------------

    class GameLayer : public CCLayer
    {
    public :
    	GameLayer();
    	bool init();
    	CCTMXTiledMap* mTileMap;
    
    	void initTileMap();
    	void initHero();
    	Hero* mHero; 
    	CCSpriteBatchNode* mActors; 
    	void update(float dt); 
    	void updatePosition(float dt); 
    	void setViewpointCenter(CCPoint position);
    	CCArray* mRobots;
    	void initRobots(); 
    	void reorderActors();
    	void updateRobots(float dt);
    };

    这个类里有瓦片地图类: CCTMXTiledMap

    有主角和初始化方法:Hero* ,initHero

    有更新方法:void update(float dt),void updatePosition(float dt)

    一一看来


    初始化机器人方法:

    void GameLayer::initRobots()
    {
    	int robotCount = 50;
    	this->mRobots = new CCArray(robotCount);
    
    	for (int i = 0; i < robotCount; ++i) {
    		Robot* robot = new Robot();
    		//mActors->addChild(robot);
    		this->addChild(robot);
    		mRobots->addObject(robot);
    
    		int minX = SCREEN.width + robot->mCenterToSide;
    		int maxX = mTileMap->getMapSize().width * mTileMap->getTileSize().width 
    			- robot->mCenterToSide;
    		int minY = robot->mCenterToBottom;
    		int maxY = 3 * mTileMap->getTileSize().height + robot->mCenterToBottom;
    
    		if (rand() % 2)
    			robot->setFlipX(true);
    		robot->setPosition(
    			ccp(random_range(minX, maxX), random_range(minY, maxY)));
    		robot->mDesiredPosition = robot->getPosition();
    		robot->idle();
    	}
    }

    new一个Robot类,放到CCArray数组里。

    然后定义机器人的活动范围:即xy的最大值最小值


    如图:机器人最早出现的x位置是第二屏最近的位置,即

    SCREEN.width + robot->mCenterToSide;  //  mCenterToSide 半个机器人宽度

    最远是的位置是地图的最后边:

    mTileMap->getMapSize().width * mTileMap->getTileSize().width - robot->mCenterToSide;

    即 :tile的个数Xtile的宽度-机器人半个宽度

    最高和最低也是同理。

    然后在这个范围内随机放50个机器人。


    重新排序方法 reorderActors:

    void GameLayer::reorderActors()
    {
    	CCObject* item;
    	//CCARRAY_FOREACH(mActors->getChildren(), item)
    	CCARRAY_FOREACH(this->getChildren(), item) {
    		CCNode *node = dynamic_cast<CCNode *>(item);
    		if (node->getTag() == ACTION_SPRITE_TAG) {
    			ActionSprite *sprite = dynamic_cast<ActionSprite *>(item);
    			this->reorderChild(sprite, mTileMap->getMapSize().height * mTileMap->getTileSize().height 
    				- sprite->getPositionY());
    		}
    	}
    }

    循环所有的CCSprite,从新计算z轴,来修正遮挡关系。

    更新机器人方法:void GameLayer::updateRobots(float dt)

    		if (robot->mActionState != kActionStateKnockedOut) {
    			++alive;
    			robot->mNextDecisionTime -= dt;
    			if (robot->mNextDecisionTime <= 0.0f) {
    				distanceSQ = ccpDistanceSQ(robot->getPosition(), mHero->getPosition());
    				if (distanceSQ <= 50*50) {
    					robot->mNextDecisionTime = frandom_range(0.5f, 1.0f, 0.1f);
    					randomChoice = random_range(0, 1);
    					if (randomChoice == 0) {
    						if (mHero->getPositionX() > robot->getPositionX()) {
    							robot->setFlipX(false);
    						} else {
    							robot->setFlipX(true);
    						}
    
    						robot->attack();
    						if (robot->mActionState == kActionStateAttack) {
    							if (fabs(mHero->getPositionY() - robot->getPositionY()) < 10) {
    								if (mHero->mHitBox.actual.intersectsRect(robot->mAttackBox.actual)) {
    									mHero->hurtWithDamage(robot->mDamage);
    								}
    							}
    						}
    					} else {
    						robot->idle();
    					}
    				} else if (distanceSQ <= SCREEN.width * SCREEN.width) {
    					robot->mNextDecisionTime = frandom_range(1.0f, 1.5f, 0.1f);
    					robot->mNextDecisionTime = random_range(5, 10) * 0.1f;
    					randomChoice = random_range(0, 2);
    					if (randomChoice == 0) {
    						CCPoint moveDirection = ccpNormalize(ccpSub(mHero->getPosition(), robot->getPosition()));
    						robot->walkWithDirection(moveDirection);
    					} else {
    						robot->idle();
    					}
    				}
    			}

    这个方法大体流程是:

    如果机器人还没死,就看看到没到行动时间,到时间了,就计算下机器人和主角之前的距离:

    distanceSQ = ccpDistanceSQ(robot->getPosition(), mHero->getPosition());

    如果主角在机器人左边,机器人向左走,反之,向右边走:

    if (mHero->getPositionX() > robot->getPositionX()) { robot->setFlipX(false);

    机器人进入攻击状态,检测下主角是否在机器人的攻击范围内:

    if (mHero->mHitBox.actual.intersectsRect(robot->mAttackBox.actual)) {

    如果离的远了,就往主角那走:

    robot->walkWithDirection(moveDirection);


    定位到地图中心 

    void GameLayer::setViewpointCenter(CCPoint position)
    {
    	CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    
    	int x = GetMAX(position.x, winSize.width / 2);
    	int y = GetMAX(position.y, winSize.height / 2);
    
    	x = GetMIN(x, (mTileMap->getMapSize().width * 
    		mTileMap->getTileSize().width - winSize.width / 2));
    	y = GetMIN(y, (mTileMap->getMapSize().height * 
    		mTileMap->getTileSize().height - winSize.height / 2));
    
    	CCPoint actualPosition = ccp(x, y);
    	CCPoint centerOfView = ccp(winSize.width / 2, winSize.height / 2);
    	CCPoint viewPoint = ccpSub(centerOfView, actualPosition);
    
    	this->setPosition(viewPoint);
    }

    如果主角往右走,如果此时移动到地图中心,那么主角保持在地图的中心,但是地图往左移动。

    然后让整个地图向左移动,来表现主角向右走。this->setPosition(viewPoint);


    更新位置方法

    void GameLayer::updatePosition(float dt)
    {
    	float posX = GetMIN(mTileMap->getMapSize().width * mTileMap->getTileSize().width - mHero->mCenterToSide, 
    		GetMAX(mHero->mCenterToSide, mHero->mDesiredPosition.x));
    	float posY = GetMIN(3 * mTileMap->getTileSize().height + mHero->mCenterToBottom, 
    		GetMAX(mHero->mCenterToBottom, mHero->mDesiredPosition.y));
    
    	//std::cout << mHero->mDesiredPosition.x << std::endl;
    	mHero->setPosition(ccp(posX, posY));
    
    	CCObject* item;
    	CCARRAY_FOREACH(mRobots, item) {
    		Robot* robot = dynamic_cast<Robot*>(item);
    		posX = GetMIN(mTileMap->getMapSize().width * mTileMap->getTileSize().width - robot->mCenterToSide, 
    			GetMAX(robot->mCenterToSide, robot->mDesiredPosition.x));
    		posY = GetMIN(3 * mTileMap->getTileSize().height + robot->mCenterToBottom, 
    			GetMAX(robot->mCenterToBottom, robot->mDesiredPosition.y));
    
    		robot->setPosition(ccp(posX, posY));
    	}
    
    	this->setViewpointCenter(mHero->getPosition());
    }

    其实就是常见的2D卷轴算法,不过看起来确实费劲。

    注释掉机器人的攻击方法,然后在游戏中跑一跑,看看主角的可移动范围。

    GetMAX(mHero->mCenterToSide, mHero->mDesiredPosition.x)  这句的意思是:

    比如英雄往左边走,他能走的左的距离是mCenterToSide,也就是半个宽度,也就是

     

    float posX 是通过GetMIN取得的,他限制了你不能超过整个tile地图的最后边。

    然后把这个合法的 xy设置到hero上。



    呼呼,简简单单的分析了下游戏的主要代码。

    还有个Sneaky包暂时忽略,骨头打算另开笔记学习虚拟遥控杆。


    CCTMXTiledMap 相关的也是重点,这个等以后研究工具的时候好好看看。


    明天就是周五了,离周末越来越近了。倍感欣慰啊。

    准备休息。


    ------------------- 飞船起飞--------------------    

    Cocos2dx游戏开发系列笔记11:解刨《战神传说》完结篇

    Cocos2dx游戏开发系列笔记10:解刨《战神传说》

    Cocos2dx游戏开发系列笔记9:android手机上运行《战神传说》,并解决横竖屏即分辨率自适应问题

    Cocos2dx游戏开发系列笔记8:开搞一个射击游戏《战神传说》//就个打飞机的

    Cocos2dx游戏开发系列笔记7:一个简单的跑酷游戏《萝莉快跑》的消化(附下载)

    Cocos2dx游戏开发系列笔记6:怎样让《萝莉快跑》的例子运行在vs和手机上

    Cocos2dx游戏开发系列笔记5:继续润色《忍者飞镖射幽灵》

    Cocos2dx游戏开发系列笔记4:怎样新加一个Scene类?

    Cocos2dx游戏开发系列笔记3:牛刀小试->忍者飞镖射幽灵的Demo

    Cocos2dx游戏开发系列笔记2:一个刚创建的cocos2dx中的demo里都有什么

    Cocos2dx游戏开发系列笔记1:一个崭新的开始,cocos2dx2.2+ndkr9+Cygwin+vs2012游戏开发环境搭建

    -------------------- 飞船降落-------------------- 


    最后,骨头介绍一下陪在身边的哲哲(右边就是低调的哲哲)

    哲哲,小名 YIYI ,手工爱好者,文艺范,手艺人,《YiYiの妙舍》创始人,很有自己想法。

     


  • 相关阅读:
    [Linear Algebra] Inverse and Transpose
    使用vue-cli4快速搭建项目环境、使用webpack4打包自己的library类库、封装vue插件并发布
    Python多线程批量Ping主机IP的脚本
    rk3288 系统设置中无法正常使用wifi分析
    chrome 修改为linux的ua
    js生成用户编号(时间戳+随机数)
    【软考】信息系统开发方法
    【软考】信息安全审计
    【软考】信息系统安全等级保护
    【软考】软件测试
  • 原文地址:https://www.cnblogs.com/riasky/p/3483443.html
Copyright © 2011-2022 走看看