funcode之c++版弹弹堂(第一个设计实验)

lessonx.h

/

//

//

//

//

/

#ifndef _LESSON_X_H_

#define _LESSON_X_H_

//

#include <Windows.h>

 

/

//

// 游戏总管类。负责处理游戏主循环、游戏初始化、结束等工作

class CGameMain

{

private:

 const int TARGET_COUNT=3;

 int m_iGameState; // 游戏状态,0:结束或者等待开始;1:初始化;2:游戏进行中

 int m_iFireState; //开炮状态:0-等待开炮,1-炮弹飞行中

 int m_iTargetHit[3];//目标击中次数,若为3则死亡重新开始下一回合

 static const float m_fMaxRotation; //最大旋转角度=初始角度

 CAnimateSprite* m_pTarget[3]; //目标精灵数组

 float m_fGunRotation; // 炮的朝向

 float m_fGunStrength; // 炮的力度

 int m_iCalStrength; // 1 : 空格键按下中,计算力度,力度渐增。0 : 不计算力度

 static const float m_fBumbForceY; // 炮弹发射之后,给它一个向下的常力,使其形成一个抛物线弹道轨迹

 float m_fKeyUp; // 上下键是否按下的变量:1按下0弹起,用于计算角度

 float m_fKeyDown; // 上下键是否按下的变量:1按下0弹起,用于计算角度

 CSprite* m_pDandanGun; //发射炮精灵

 CTextSprite* m_pDegreeText; //角度显示精灵

 CTextSprite* m_pStrengthText; //力度显示精灵

 CSprite* m_pBumpTemplate; /模板精灵

 float m_fRoundTime;// 炮弹发射之后,等待一定时间才开始下回合

 CAnimateSprite* m_pBump[3]; /精灵数组

 CEffect* m_pBumpExplode;//爆炸效果精灵

 

 

 

public:

 CGameMain(); //构造函数

 ~CGameMain(); //析构函数  

    

 

 // Get方法

 int GetGameState() { return m_iGameState; }

 

 // Set方法

 void SetGameState( const int iState ) { m_iGameState = iState; }

 

 // 游戏主循环等

 CAnimateSprite* FindSpriteByName(const char* szName);//由精灵名字返回精灵实体的函数

 void GameMainLoop( float fDeltaTime );//

 void GameInit();

 void GameRun( float fDeltaTime );

 void GameEnd();

 void OnKeyDown(const int iKey, const int iAltPress, const int iShiftPress, const int iCtrlPress);//按下按钮的响应函数

    void OnKeyUp(const int iKey);//松开按钮的相应函数

 void OnSpriteColSprite(const char szSrcName[], const char szTarName[]);//处理精灵与精灵碰撞的函数

 void OnSpriteColWorldLimit(const char szName[], const int iColSide);//处理精灵与世界边界碰撞的函数

 void ProcessBumbHit(const int iHitState, const char* szBumbName, const char* szTargetNamee);//处理炸弹精灵和其他精灵爆炸效果显示函数

 int IsGameWin();

};

 

/

// 

extern CGameMain g_GameMain;

 

#endif // _LESSON_X_H_

lessonx.cpp

 

/
//
//
//
//
/
#include <Stdio.h>
#include "CommonClass.h"
#include "LessonX.h"

//
//
CGameMain        g_GameMain;    

//==============================================================================
//
// 大体的程序流程为:GameMainLoop函数为主循环函数,在引擎每帧刷新屏幕图像之后,都会被调用一次。

//==============================================================================
//
// 构造函数
CGameMain::CGameMain()
{
    m_iGameState            =    1;//设置游戏状态为1
    for (int i = 0; i < TARGET_COUNT; i++)
    {
        m_iTargetHit[i] = 0;//初始化击中次数为0
        m_pTarget[i] = new CAnimateSprite(CSystem::MakeSpriteName("DandanTarget", i));    
    }
        m_fGunRotation = 350.f;//初始化角度值
        m_fGunStrength = 0.f;//炮的力度
        m_iCalStrength = 0;//空格键状态
        m_fKeyDown = 0.f; 
        m_fKeyUp = 0.f;//上下键状态
        m_pDandanGun = new CSprite("DandanGun");
        m_pDegreeText = new CTextSprite("DegreeText");
        m_pStrengthText = new CTextSprite("StrengthText");
        m_pBumpTemplate = new CSprite("BumbTemplate");
        m_fRoundTime = 0.f;
        m_pBumpExplode = new CEffect("BumbExplode", "BumbExplode", 0.f);
        
}
//==============================================================================
//
// 析构函数
CGameMain::~CGameMain()
{
}

//==============================================================================
//
// 游戏主循环,此函数将被不停的调用,引擎每刷新一次屏幕,此函数即被调用一次
// 用以处理游戏的开始、进行中、结束等各种状态. 
// 函数参数fDeltaTime : 上次调用本函数到此次调用本函数的时间间隔,单位:秒
void CGameMain::GameMainLoop( float    fDeltaTime )
{
    switch( GetGameState() )
    {
        // 初始化游戏,清空上一局相关数据
    case 1:
        {
            GameInit();
            SetGameState(2); // 初始化之后,将游戏状态设置为进行中
        }
        break;

        // 游戏进行中,处理各种游戏逻辑
    case 2:
        {
            // TODO 修改此处游戏循环条件,完成正确游戏逻辑
            if(!IsGameWin())
            {
                GameRun( fDeltaTime );
            }
            else // 游戏结束。调用游戏结算函数,并把游戏状态修改为结束状态
            {                
                SetGameState(0);
                GameEnd();
            }
            //IsGameWin() 如果没有胜利输出为0, 如果胜利了输出为1;
            //!IsGameWin() 没有胜利进行GameRun, 胜利了进入else

        }
        break;

        // 游戏结束/等待按空格键开始
    case 0:
    default:
        break;
    };
}

//=============================================================================
//
// 每局开始前进行初始化,清空上一局相关数据
void CGameMain::GameInit()
{
    m_iFireState = 0;   //初始化为未开炮状态
    int iLoop = 0;
    float fPosX = 0, fPosY = 0;//坐标
    for (; iLoop < TARGET_COUNT; iLoop++) {
        m_iTargetHit[iLoop] = 0;
        fPosX = CSystem::RandomRange(0, 45);//坐标随机
        fPosY = m_pTarget[iLoop]->GetSpritePositionY();//get精灵的Y坐标
        m_pTarget[iLoop]->SpriteMoveTo(fPosX, fPosY, 40.f, 1);//AutoStop参数为1,表示移动到终点后停止下来
        m_pTarget[iLoop]->AnimateSpritePlayAnimation("DandanTargetAnimation1", 0);//动画精灵播放动画,参数:动画名字。注意不是精灵名称,
                                                                                 //播放完毕后是否恢复当前动画,返回值:是否播放成功
        m_pBump[iLoop] = new CAnimateSprite(CSystem::MakeSpriteName("DandanBumb", iLoop));
        m_pTarget[iLoop]->SetSpriteVisible(1);//显示精灵
    }
    m_fGunRotation = m_fMaxRotation;  // 炮台的初始角度为最大角度
    m_fGunStrength = 0.f;
}
//=============================================================================
//
// 每局游戏进行中
//等待开炮:炮台
//已经开炮:坚果和炮台
void CGameMain::GameRun( float fDeltaTime )//fDeltaTime:上次调用本函数到此次调用本函数的时间间隔
{//fDeltaTime时间来计算炮台的角度和发射力度,如果一直按下键盘按键,则fDeltaTime会一直增加
    if (0 == m_iFireState)//如果在等待开炮
    {
        if (m_iCalStrength)//如果空格键按下,在计算力度
        {
            m_fGunStrength += 50.f * fDeltaTime; // 50每秒
            if (m_fGunStrength > 200.f) //大炮力度的最大值
                m_fGunStrength = 200.f;
        }
        m_fGunRotation += (m_fKeyDown - m_fKeyUp) * 15.f * fDeltaTime;//因为向上度数变小,所以down-up
        if (m_fGunRotation < 280.f)        //大炮角度的最小值
            m_fGunRotation = 280.f;
        else if (m_fGunRotation > m_fMaxRotation)        // 角度超过最大值
            m_fGunRotation = m_fMaxRotation;     // 回到初始位置
        // 获取大炮炮口的挂接点作为炮弹发射点
        // float GetSpriteLinkPointPosX(const int iId ); 
        //参数 iId:链接点序号,第一个链接点为1,后面依次递加
        float fOldPosX = m_pDandanGun->GetSpriteLinkPointPosX(1);
        float fOldPosY = m_pDandanGun->GetSpriteLinkPointPosY(1);
        float fNewPosX = 0.f;
        float fNewPosY = 0.f;
        //计算出XY两个方向上的速度值
        // Static float RotationToVectorX(const float fRotation); 
        //计算某个角度对应的直线向量的X方向, 返回值 :该直线向量的X值,fRotation:角度,范围0 – 360
        float fVelocityX = CSystem::RotationToVectorX(m_fGunRotation) * m_fGunStrength;                                                                         
        float fVelocityY = CSystem::RotationToVectorY(m_fGunRotation) * m_fGunStrength;
        //获取炮弹质量:
        //float  GetSpriteMass();
        //获取精灵质量
        //返回值 :质量大小
        float    fMass = m_pBumpTemplate->GetSpriteMass();/模板精灵指向此函数
        float  fHalfTime = -fVelocityY / (m_fBumbForceY / fMass);
        float    fForceVelY = m_fBumbForceY / fMass;
        float    fTime = 0.f;
        float    fSimDelta = 0.0333f;
        for (; fTime < fHalfTime; fTime += fSimDelta)
        {
            fNewPosX = fOldPosX + fVelocityX * fSimDelta;
            fNewPosY = fOldPosY + (fVelocityY + fForceVelY * fTime) * fSimDelta;
            CSystem::DrawLine(fOldPosX, fOldPosY, fNewPosX, fNewPosY, 2.f, 0, 0, 255, 0, 255);
            fOldPosX = fNewPosX;
            fOldPosY = fNewPosY;
        //参数:起始坐标X,起始坐标Y,终点坐标X,终点坐标Y,线的粗细,大于等于1,改线所在的层,范围0 - 31,颜色,不透明度

        }
        m_pDandanGun->SetSpriteRotation(m_fGunRotation);
        m_pDegreeText->SetTextValue(m_fGunRotation);
        m_pStrengthText->SetTextValue(m_fGunStrength);
    }    
    else if(1==m_iFireState)//如果开炮了
    {
        m_fRoundTime -= fDeltaTime;// m_fRoundTime= m_fRoundTime- fDeltaTime
        if (m_fRoundTime <= 0.f)//当m_fRoundTime<=0,则等待回合时间到,重新进行初始化
        {
            m_iFireState = 0;
            m_fGunRotation = m_fMaxRotation;
            m_fGunStrength = 0.f;
            int        iLoop = 0;
            float    fPosX = 0, fPosY = 0;
            for (iLoop = 0; iLoop < TARGET_COUNT; iLoop++)
            {
                if (m_iTargetHit[iLoop] >= 3)
                    continue;
                //击中次数小于3才需要做下面的操作
                fPosX = CSystem::RandomRange(0, 45);// 每回合在X方向上,目标在0-45范围内随机移动一次
                fPosY = m_pTarget[iLoop]->GetSpritePositionY();//Y坐标不变
                m_pTarget[iLoop]->SpriteMoveTo(fPosX, fPosY, 40.f, 1);//使用SpriteMoveTo移动精灵
            }
        }

        }

}

//=============================================================================
//
// 本局游戏结束
void CGameMain::GameEnd()
{
    m_iGameState = 1;//重新跳转到初始化
}
const float CGameMain::m_fMaxRotation = 350.f;//因为fMaxRotation为const类型的变量,所有要单独初始化
const float CGameMain::m_fBumbForceY = 10.f;
void CGameMain::OnKeyDown(const int iKey, const int iAltPress, const int iShiftPress, const int iCtrlPress)
{
    if (KEY_SPACE == iKey && 2 == m_iGameState && 0 == m_iFireState)//如果按下空格键,游戏在运行并且还未开炮
    {
        m_iCalStrength = 1;// 空格键按下中,计算力度,力度渐增
    }
    if (KEY_UP == iKey)
    {
        m_fKeyUp = 1.f;
    }
    else if (KEY_DOWN == iKey)
    {
        m_fKeyDown = 1.f;
    }
}
void CGameMain::OnKeyUp(const int iKey)
{//空格键:炮台,按键,等待,炮弹
//上下键
    if (KEY_SPACE == iKey && 2 == m_iGameState && 0 == m_iFireState)//如果松开空格键,游戏在运行并且之前状态还未开炮
    {
        m_iFireState = 1;
        m_iCalStrength = 0;
        m_fRoundTime = 3.f;//更改发射状态,在炮弹未落地之前不能再次发射,设置等待3秒的回合时间:
        //获取大炮炮口的挂接点作为炮弹发射点:
        float    fPosX = m_pDandanGun->GetSpriteLinkPointPosX(1);
        float    fPosY = m_pDandanGun->GetSpriteLinkPointPosY(1);
        int        iLoop = 0;
        float    fGunRotation = m_fGunRotation - 10.f;
        float    fGunStrength = m_fGunStrength - 10.f;
        char* szName = NULL;
        for (int iLoop = 0; iLoop < 3; iLoop++)
        {
            szName = CSystem::MakeSpriteName("DandanBumb", iLoop);//获取名字
            m_pBump[iLoop] = new CAnimateSprite(szName);
            m_pBump[iLoop]->CloneSprite("BumbTemplate");//for循环,一次发射创建3个炮弹
            m_pBump[iLoop]->SetSpritePosition(fPosX, fPosY);//给炮弹设置坐标,3个炮弹的坐标都一样
            m_pBump[iLoop]->SetSpriteLinearVelocityPolar(fGunStrength, fGunRotation);//给炮弹设置速度
            m_pBump[iLoop]->SetSpriteConstantForceY(m_fBumbForceY);//给炮弹一个向下的力
            fGunRotation += 10.f;
            fGunStrength += 10.f;//下一个炮弹的速度发生改变
        }
    }
    if (KEY_UP == iKey)
    {
        m_fKeyUp = 0.f;
    }
    else if (KEY_DOWN == iKey)
    {
        m_fKeyDown = 0.f;
    }
}

CAnimateSprite* CGameMain::FindSpriteByName(const char* szName)
{
    //如果传入的参数是目标精灵的名称,则返回目标精灵实体
    if (strstr(szName, "Target"))
    {
        for (int i = 0; i < 3; i++)
            if (stricmp(szName, m_pTarget[i]->GetName()) == 0)
                return m_pTarget[i];
    }
    //如果传入的参数是炸弹精灵的名称,则返回炸弹精灵实体
    if (strstr(szName, "Bumb"))
    {
        for (int i = 0; i < 3; i++)
        {
            if (stricmp(szName, m_pBump[i]->GetName()) == 0)
                return m_pBump[i];
        }

    }
}
//处理炸弹精灵和其他精灵爆炸效果显示函数
void CGameMain::ProcessBumbHit(const int iHitState, const char* szBumbName, const char* szTargetName)
{
    CAnimateSprite* tmpBumpSprite;
    tmpBumpSprite = FindSpriteByName(szBumbName);//调用FindSpriteByName得到对应参数的精灵实体
    float    fPosX = tmpBumpSprite->GetSpritePositionX();
    float    fPosY = tmpBumpSprite->GetSpritePositionY();精灵位置
    if (1 == iHitState)//如果炸弹和目标精灵相碰撞
    {
        int iLoop = 0;
        for (iLoop = 0; iLoop < TARGET_COUNT; iLoop++)
        {
            if (stricmp(m_pTarget[iLoop]->GetName(), szTargetName) == 0)//判断是否碰到目标精灵,若碰到则击中次数加一
            {
                m_iTargetHit[iLoop]++;
                //根据目标精灵被碰撞次数,指向对应的动画效果
                if (1 == m_iTargetHit[iLoop])
                    m_pTarget[iLoop]->AnimateSpritePlayAnimation("DandanTargetAnimation2", 0);
                else
                    m_pTarget[iLoop]->AnimateSpritePlayAnimation("DandanTargetAnimation3", 0);
                // 若击中3次,则该目标精灵被隐藏
                if (m_iTargetHit[iLoop] >= 3)
                    m_pTarget[iLoop]->SetSpriteVisible(0);

                break;
            }

        }
        if (1 == iHitState || 2 == iHitState)
        {
            m_pBumpExplode->PlayEffect(fPosX, fPosY, 0.f); //如果碰撞到实体,在碰撞处播放碰撞特效
        }
        tmpBumpSprite->DeleteSprite();

    }

}
void CGameMain::OnSpriteColWorldLimit(const char szName[], const int iColSide)
{
    if (2 != m_iGameState)
        return;// 只处理游戏进行中的响应
    if (strstr(szName, "DandanBumb"))
    {
        ProcessBumbHit(0, szName, "");
    }    // 是炮弹碰到边界, 开始下次开炮

}
void CGameMain::OnSpriteColSprite(const char szSrcName[], const char szTarName[])
{
    if (2 != m_iGameState)//如果游戏没有运行则将直接退出
        return;
    //如果游戏运行,则检测碰撞的两个精灵的名称,碰撞的两个精灵一定有一个是导弹,则仅需判断另一个精灵
    if (strstr(szSrcName, "DandanBumb"))
    {
        if (strstr(szTarName, "DandanTarget"))
            ProcessBumbHit(1, szSrcName, szTarName);
        else
            ProcessBumbHit(2, szSrcName, "");

    }
    else if (strstr(szTarName, "DandanBumb"))
    {
        if (strstr(szSrcName, "DandanTarget"))
            ProcessBumbHit(1, szTarName, szSrcName);
        else
            ProcessBumbHit(2, szTarName, "");

    }

}
int CGameMain::IsGameWin()
{
    int    iLoop = 0;
    for (iLoop = 0; iLoop <TARGET_COUNT; iLoop++) 
    {
        if (m_iTargetHit[iLoop] < 3)
            return 0;
    }//如果三个都击中了3次就return1;
  return 1;
    

}

main.cpp

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#include "CommonClass.h"
#include "LessonX.h"

///
//
// 主函数入口
//
//
int PASCAL WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR     lpCmdLine,
                   int       nCmdShow)
{
    // 初始化游戏引擎
    if( !CSystem::InitGameEngine( hInstance, lpCmdLine ) )
        return 0;

    // To do : 在此使用API更改窗口标题
    CSystem::SetWindowTitle("LessonX");

    // 引擎主循环,处理屏幕图像刷新等工作
    while( CSystem::EngineMainLoop() )
    {
        // 获取两次调用之间的时间差,传递给游戏逻辑处理
        float    fTimeDelta    =    CSystem::GetTimeDelta();

        // 执行游戏主循环
        g_GameMain.GameMainLoop( fTimeDelta );
    };

    // 关闭游戏引擎
    CSystem::ShutdownGameEngine();
    return 0;
}

//==========================================================================
//
// 引擎捕捉鼠标移动消息后,将调用到本函数
void CSystem::OnMouseMove( const float fMouseX, const float fMouseY )
{
    // 可以在此添加游戏需要的响应函数

}
//==========================================================================
//
// 引擎捕捉鼠标点击消息后,将调用到本函数
void CSystem::OnMouseClick( const int iMouseType, const float fMouseX, const float fMouseY )
{
    // 可以在此添加游戏需要的响应函数

}
//==========================================================================
//
// 引擎捕捉鼠标弹起消息后,将调用到本函数
void CSystem::OnMouseUp( const int iMouseType, const float fMouseX, const float fMouseY )
{
    // 可以在此添加游戏需要的响应函数

}
//==========================================================================
//
// 引擎捕捉键盘按下消息后,将调用到本函数
// bAltPress bShiftPress bCtrlPress 分别为判断Shift,Alt,Ctrl当前是否也处于按下状态。比如可以判断Ctrl+E组合键
void CSystem::OnKeyDown( const int iKey, const bool bAltPress, const bool bShiftPress, const bool bCtrlPress )
{
    // 可以在此添加游戏需要的响应函数
    g_GameMain.OnKeyDown(iKey, bAltPress, bShiftPress, bCtrlPress);
}
//==========================================================================
//
// 引擎捕捉键盘弹起消息后,将调用到本函数
void CSystem::OnKeyUp( const int iKey )
{
    // 可以在此添加游戏需要的响应函数
    g_GameMain.OnKeyUp(iKey);
}

//===========================================================================
//
// 引擎捕捉到精灵与精灵碰撞之后,调用此函数
void CSystem::OnSpriteColSprite( const char *szSrcName, const char *szTarName )
{
    g_GameMain.OnSpriteColSprite(szSrcName, szTarName);
}

//===========================================================================
//
// 引擎捕捉到精灵与世界边界碰撞之后,调用此函数.
// iColSide : 0 左边,1 右边,2 上边,3 下边
void CSystem::OnSpriteColWorldLimit( const char *szName, const int iColSide )
{
    g_GameMain.OnSpriteColWorldLimit(szName, iColSide);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值