📄 mopoidball.cpp
字号:
/*
========================================================================
Name : MopoidBall.cpp
Author :
Copyright :
Description : Handles the ball of the Mopoid game.
License :
========================================================================
*/
#include "MopoidBall.h"
// --- TBall
// -----------------------------------------------------------------------
TBall::TBall()
:
iPos(0,0),
iPosNew(0,0),
iVx(0.0),
iVy(0.0),
iSettings(NULL)
{}
// -----------------------------------------------------------------------
void TBall::SetSettingsPointer(CMopoidSettings* aSettings)
{
iSettings = aSettings;
}
// -----------------------------------------------------------------------
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 + iSettings->iBallSizeHalf.iWidth > iSettings->iGameRect.iBr.iX)
{
// Reflect at right wall
iXnew = iSettings->iGameRect.iBr.iX - iSettings->iBallSizeHalf.iWidth;
BounceX();
collision = ETrue;
}
else if (iXnew - iSettings->iBallSizeHalf.iWidth < iSettings->iGameRect.iTl.iX)
{
// Reflect at left wall
iXnew = iSettings->iGameRect.iTl.iX + iSettings->iBallSizeHalf.iWidth;
BounceX();
collision = ETrue;
}
if (iYnew - iSettings->iBallSizeHalf.iHeight < iSettings->iGameRect.iTl.iY)
{
// Reflect at top
iYnew = iSettings->iGameRect.iTl.iY + iSettings->iBallSizeHalf.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 + iSettings->iBallSizeHalf.iHeight) >= aPanel.iPos.iY) &&
((iYnew - iSettings->iBallSizeHalf.iHeight) < aPanel.iPos.iY + iSettings->iPanelSizeHalf.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 + iSettings->iBallSizeHalf.iWidth > aPanel.iX) &&
(iXnew - iSettings->iBallSizeHalf.iWidth < aPanel.iX + iSettings->iPanelSize.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 = -( (TReal)(aPanel.iX + iSettings->iPanelSizeHalf.iWidth) - iX ) / ((TReal)iSettings->iPanelSizeHalf.iWidth * iSettings->iPanelReflection);
// 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 - iSettings->iBallSizeHalf.iHeight;
}
}
return collision;
}
// -----------------------------------------------------------------------
TBrick::TBrickType TBall::CheckBrickCollisionL(CMopoidGrid* aGrid, TReal aStep, TCollisionOffset aSide)
{
TPoint checkPos(iPosNew);
if (aSide == ELeft)
checkPos.iX -= iSettings->iBallSizeHalf.iWidth;
else if (aSide == ERight)
checkPos.iX += iSettings->iBallSizeHalf.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->HitBrickAtPosL(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 > iSettings->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 > iSettings->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 + iSettings->iPanelSize.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 < iSettings->iBallSpeedMaxX)
iVx += (iSettings->iBallSpeedAccX * ((iVx > 0.0) ? 1.0 : -1.0) );
}
// -----------------------------------------------------------------------
void TBall::SpeedUpY()
{
// Speed up the ball a tiny bit
if (iVy < iSettings->iBallSpeedMaxY)
iVy += (iSettings->iBallSpeedAccY * ((iVy > 0.0) ? 1.0 : -1.0) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -