⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mopoidball.cpp

📁 一款大砖块的游戏
💻 CPP
字号:
/*
* ============================================================================
*  Name     : TBall from MopoidBall.cpp
*  Part of  : Mopoid
*  Created  : 16.01.2004 by Andreas Jakl / Mopius - http://www.mopius.com/
*  Description:
*     Handles the ball of the Mopoid game.
*  Version  : 1.02
*  Copyright: 
*     'Mopoid' is free software; you can redistribute
*     it and/or modify it under the terms of the GNU General Public License
*     as published by the Free Software Foundation; either version 2 of
*     the License, or (at your option) any later version.
* 
*     'Mopoid' is distributed in the hope that it
*     will be useful, but WITHOUT ANY WARRANTY; without even the implied
*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*     See the GNU General Public License for more details.
* 
*     You should have received a copy of the GNU General Public License
*     along with 'Mopoid'; if not, write to the Free Software
*     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
* ============================================================================
*/

#include "MopoidBall.h"

// --- TBall
// -----------------------------------------------------------------------
TBall::TBall()
:
	iPos(0,0),
	iPosNew(0,0),
	iVx(0.0),
	iVy(0.0),
	iSize(0,0),
	iSizeHalf(0,0)

{}

// -----------------------------------------------------------------------
void TBall::ConvertToPos()
{
    iX = iXnew;
    iY = iYnew;
    iPos.SetXY((TInt)iX, (TInt)iY);
}

// -----------------------------------------------------------------------
TBool TBall::Move(TReal aStep)
{
    TBool collision = EFalse;
    iXnew = iX + (iVx * aStep);
    iYnew = iY + (iVy * aStep);

    // Check collision with walls
    if (iXnew + iSizeHalf.iWidth > BORDER_RIGHT)
    {
        // Reflect at right wall
        iXnew = BORDER_RIGHT - iSizeHalf.iWidth;
        BounceX();
        collision = ETrue;
    }
    else if (iXnew - iSizeHalf.iWidth < BORDER_LEFT)
    {
        // Reflect at left wall
        iXnew = BORDER_LEFT + iSizeHalf.iWidth;
        BounceX();
        collision = ETrue;
    }
    if (iYnew - iSizeHalf.iHeight < BORDER_TOP)
    {
        // Reflect at top
        iYnew = BORDER_TOP + iSizeHalf.iHeight;
        BounceY();
        collision = ETrue;
    }

    // Also store the new position in screen coordinates as TInt's, to
    // make calculations faster.
    iPosNew.SetXY((TInt)iXnew, (TInt)iYnew);

    return collision;
}

// -----------------------------------------------------------------------
TBool TBall::CheckPanelCollision(const TPanel& aPanel, TReal aStep)
{
    TBool collision = EFalse;
    if ( ((iYnew + iSizeHalf.iHeight) >= aPanel.iPos.iY) && 
         ((iYnew - iSizeHalf.iHeight) < aPanel.iPos.iY + aPanel.iSizeHalf.iHeight) )
    {
        // We are far enough down so that a collision would be possible.
        // Check in more detail...
        // (ball going too far down will be handled elsewhere and has nothing
        // to do with panel collision!)
        if ((iXnew + iSizeHalf.iWidth > aPanel.iX) &&
            (iXnew - iSizeHalf.iWidth < aPanel.iX + aPanel.iSize.iWidth))
        {
            // Collision with panel!
            collision = ETrue;
            // Reverse vertical direction
            BounceY();
            // Get absolute speed
            TReal originalSpeed;
            Math::Sqrt(originalSpeed, iVx*iVx + iVy*iVy);
            // Set new horizontal speed
            // - at front to reverse movement: if ball hits right side of panel, move right!
            iVx = -( (aPanel.iX + aPanel.iSizeHalf.iWidth) - iX ) / ((TReal)aPanel.iSizeHalf.iWidth * PANEL_REFLECTION);
            // Normalize new speed to previous speed
            TReal newSpeed;
            Math::Sqrt(newSpeed, iVx*iVx + iVy*iVy);
            TReal scale = originalSpeed / newSpeed;
            iVy *= scale;
            iVx *= scale;
            // Move again so that we're outside of the panel and won't bounce inside of it.
            ConvertToPos();
            Move(aStep);
            // Move ball up enough so that we won't collide again in the next turn
            iYnew = aPanel.iPos.iY - iSizeHalf.iHeight;
        }
    }
    return collision;
}

// -----------------------------------------------------------------------
TBrick::TBrickType TBall::CheckBrickCollision(TMopoidGrid& aGrid, TReal aStep, TCollisionOffset aSide)
{
    TPoint checkPos(iPosNew);
    if (aSide == ELeft)
        checkPos.iX -= iSizeHalf.iWidth;
    else if (aSide == ERight)
        checkPos.iX += iSizeHalf.iWidth;

    // Check if the ball is in the area occupied by the grid.
    if (!aGrid.IsXYInGrid(checkPos))
        return TBrick::EBrickInactive;

    TBrick::TBrickType collisionWith = TBrick::EBrickInactive;

    // Get the position in the grid.
    TPoint gridPos = aGrid.ConvertXYToGrid(checkPos);
    TBool brickExists = aGrid.IsBrickAtPos(gridPos);

    if (brickExists)
    {
        // If we're in the field of a brick that exists - send a hit event to it.
        collisionWith = aGrid.GetBrickTypeAtPos(gridPos);
        aGrid.HitBrickAtPos(gridPos);

        // Determine what side we hit
        // -> Calculate offset from the side of the brick
        TPoint brickUpperLeft = aGrid.ConvertGridToXY(gridPos);
        TInt offsetX = iPosNew.iX - brickUpperLeft.iX;
        TInt offsetY = iPosNew.iY - brickUpperLeft.iY;
        // Only bounce left/right on an open side
        TBool openSide = (iVx < 0) ? !aGrid.IsBrickAtPos(gridPos.iX + 1, gridPos.iY) : !aGrid.IsBrickAtPos(gridPos.iX - 1, gridPos.iY);
        if (openSide && ((offsetX < 3 && iVx > 0) || (offsetX > aGrid.iBrickSize.iWidth - 3 && iVx < 0)))
        {
            // Check top/bottom as well
            openSide = (iVy < 0) ? !aGrid.IsBrickAtPos(gridPos.iX, gridPos.iY + 1) : !aGrid.IsBrickAtPos(gridPos.iX, gridPos.iY - 1);
            if (openSide && ((offsetY < 2 && iVy > 0) || (offsetY > aGrid.iBrickSize.iHeight - 2 && iVy < 0)))
            {
                // Ball hit a corner - reverse its direction
                BounceXY();
            }
            else
            {
                // ball hit left or right side of a panel - bounce only in x-direction
                BounceX();
            }
        }
        else
        {
            // Ball hit top or bottom of a panel - bounce in y-direction
            BounceY();
        }
        // Move again
        ConvertToPos();
        Move(aStep);
    }
    return collisionWith;
}

// -----------------------------------------------------------------------
TBool TBall::CheckDeath(const TPanel& aPanel)
{
    if ((TInt)iYnew > (aPanel.iPos.iY + aPanel.iSize.iHeight))
        // Ball is below the panel
        return ETrue;
    else
        // Ball is above the panel
        return EFalse;
}

// -----------------------------------------------------------------------
void TBall::BounceXY()
{
    BounceX();
    BounceY();
}

// -----------------------------------------------------------------------
void TBall::BounceX()
{
    iVx = -iVx;
    SpeedUpX();
}

// -----------------------------------------------------------------------
void TBall::BounceY()
{
    iVy = -iVy;
    SpeedUpY();
}

// -----------------------------------------------------------------------
void TBall::SpeedUpX()
{
    // Speed up the ball a tiny bit
    if (iVx < 15)
        iVx += (0.01 * ((iVx > 0) ? 1 : -1) );
}

// -----------------------------------------------------------------------
void TBall::SpeedUpY()
{
    // Speed up the ball a tiny bit
    if (iVy < 12)
        iVy += (0.01 * ((iVy > 0) ? 1 : -1) );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -