• cocos2d-x游戏开发系列教程-超级玛丽09-怪物激活与移动


    在游戏中,很多怪物本身是会移动的,这里主要有蘑菇怪,乌龟等。

    说起怪物的移动,首先在游戏里先要考虑怪物的抽象和设计。


    在CMMonster.h中,有个类CMMonsterBasic,这个类抽象了所有的怪物,具体的怪物都是它的派生类,比如CMMonsterMushrooms蘑菇怪。


    CMMonsterBasic继承自CCNode和CMSender,所以怪物都是渲染对象,并且有消息发送功能。

    怪物基本类的接口:

    virtual bool init(CCPoint ptMonsterPos,CMMario *pMario,CMGameMap *pGameMap,CMReceiver *pReceiver); 初始化

    virtual bool OnCollisionMario() = 0;  与马里奥相撞处理

    virtual void Dead(enMonsterDeadType DeadType); 怪物死亡

    virtual bool OnCallPerFrame(float fT);  帧刷新定时调用

    void MonsterTurn(); 怪物转向,比如蘑菇怪遇到阻挡它的墙时,它会转向


    怪物类的基本数据

    CMMario                *m_pMario;   马里奥对象

    CMGameMap            *m_pGameMap; 地图对象

    enMoveDirection         m_MoveDirection;  移动方向

    bool                 m_bIsActivation;              是否激活

    float                 m_fDropSpeedPlus;     掉落加速度

    bool                 m_bIsTouched;   是否相撞


    怪物的创建:

    当游戏开始时,根据tmx地图中的标记,创建怪物对象并放置到响应位置,具体代码在CMGameMap的init函数中

    创建完怪物之后,将其加入到数组中,这些怪物刚刚创建时候,都是不激活的,也就是不会动的


    怪物的激活和移动:

    触发怪物的激活的原理在于判断怪物是不是已经进入视图,如果没有进入视图,那么怪物不需要动。但是判断是否进入视图还是很麻烦的,所以在马里奥程序里,是用马里奥和怪物的距离,来触发怪物的激活的。

    怪物的激活和移动都是在virtual bool OnCallPerFrame(float fT); 函数中,这个函数是CMGameMap的帧更新函数调用过来的,也就是说每次帧更新,每个怪物都会响应这个函数。在这个函数里,负责激活和移动,以及判断怪物和马里奥的碰撞。

    下面我们以蘑菇怪的帧更新函数来学习怪物帧更新处理。

    bool CMMonsterMushrooms::OnCallPerFrame( float fT )
    {
    	do 
    	{
    		//是否激活
    		if (m_bIsActivation==true)
    		{
    			//移动与碰撞
    			if (m_MoveDirection == enMoveLeft)
    			{
    				//用怪物左方的2个瓦片来判断移动碰撞
    				CCSprite* pTileSpriteLeftTop = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX(),getPositionY()+getContentSize().height));
    				CCSprite* pTileSpriteLeftMid = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX(),getPositionY()+getContentSize().height/2));
    				if (pTileSpriteLeftTop!=NULL || pTileSpriteLeftMid!=NULL)
    				{
    					m_MoveDirection = enMoveRight;
    				}
    				else
    				{
    					setPositionX(getPositionX()-1);
    				}
    			}
    			else if(m_MoveDirection == enMoveRight)
    			{
    				//用怪物右方的2个瓦片来判断移动碰撞
    				CCSprite* pTileSpriteRightTop = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+getContentSize().width,getPositionY()+getContentSize().height));
    				CCSprite* pTileSpriteRightMid = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+getContentSize().width,getPositionY()+getContentSize().height/2));
    				if (pTileSpriteRightTop!=NULL || pTileSpriteRightMid!=NULL)
    				{
    					m_MoveDirection = enMoveLeft;
    				}
    				else
    				{
    					setPositionX(getPositionX()+1);
    				}
    			}
    
    			//用怪物下方的三个瓦片来判断掉落碰撞
    			CCSprite* pTileSpriteBottomMid = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+boundingBox().size.width/2,getPositionY()));
    			CCSprite* pTileSpriteBottomLeft = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+COLLISION_POS_ADJUSTMENT,getPositionY()));
    			CCSprite* pTileSpriteBottomRight = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+boundingBox().size.width-COLLISION_POS_ADJUSTMENT,getPositionY()));
    			if (pTileSpriteBottomLeft!=NULL || pTileSpriteBottomMid!=NULL || pTileSpriteBottomRight!=NULL)
    			{
    				//掉落速度归零
    				m_fDropSpeedPlus = 0;
    			}
    			else
    			{
    				setPositionY(getPositionY()-m_fDropSpeedPlus);
    				//掉落加速度
    				m_fDropSpeedPlus += DROP_SPEED_PLUS;
    			}
    		}
    
    		
    
    		return (CMMonsterBasic::OnCallPerFrame(fT)||OnCollisionMario());
    	} while (false);
    	
    	CCLog("fun CMMonsterMushrooms::OnCallPerFrame Error!");
    
    	return false;
    }

    首先判断是否激活了,如果激活了那么则判断它的移动,它不需要按键驱动,按照时间移动它即可,遇到障碍物则返回。如果蘑菇怪在天上,则自然降落。


    最后调用基类的定时刷新函数和马里奥的冲突函数。基类的定时刷新函数做什么呢

    bool CMMonsterBasic::OnCallPerFrame(float fT)
    {
    	do 
    	{
    		//判断当怪物离开地图则发消息删除自己
    		if (getPositionX()<0 || getPositionY()<0)
    		{
    			TCmd_Remove_Monster* pData = new TCmd_Remove_Monster;
    			pData->pMonster = this;
    			SendMsg(enMsgMonsterDisappear,pData,sizeof(pData));
    			return true;//需要删除自己
    		}
    
    		CC_BREAK_IF(m_pMario==NULL);
    
    		//判断马里奥与当前怪物的距离,用以激活。
    		if (abs(m_pMario->getPositionX() - getPositionX())<MONSTER_ACTIVE_DISTANCE)
    		{
    			m_bIsActivation = true;
    		}
    
    		return false;//不需要删除自己
    	} while (false);
    	CCLog("fun CMMonsterBasic::OnCallPerFrame Error!");
    	return false;
    }

    基类的函数主要要做的事情是:

    1)如果怪物离开地图,则自杀。自杀是通过发送消息给地图类,让地图类杀掉本对象

    2)如果怪物与马里奥的距离小于某个值,则激活,激活的意思就是这个怪物开始运动了



  • 相关阅读:
    Linq to DataTable 左连接
    关于值类型和引用类型
    静态页生成
    技术是什么?
    关于GC垃圾回收的原理
    ADO.NET编程之美----数据访问方式(面向连接与面向无连接)
    Unity3d连接SQL Server数据库出现SocketException: 使用了与请求的协议不兼容的地址错误
    JAVA/GUI程序之记事本
    面试常见题
    unsafe
  • 原文地址:https://www.cnblogs.com/new0801/p/6177206.html
Copyright © 2020-2023  润新知