📄 mopoidball.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 + -