?? game.cs
字號:
GenerateNextBalls();
NextStep();
// Reset step counter
stepCount = 0;
// Reset score
score = 0;
// New game
isGameOver = false;
// Unlock in any case
UnlockBoard();
}
/// <summary>
/// Saves the current player score in a hi score list.
/// </summary>
/// <param name="player">The player name.</param>
public void SaveResults(string player)
{
// Save in the high score table
if (IsRecord)
{
Records.AddRecord(player, score, stepCount);
Records.Save(RecordsFilename);
}
}
/// <summary>
/// Generates balls (position, colors) that will apper on the board at next step.
/// </summary>
public void GenerateNextBalls()
{
virtualBalls = board.GenerateVirtualBalls(ballsPerStep);
}
/// <summary>
/// Performs operation to go for the next step.
/// </summary>
/// <returns><c>true</c> if operations are succeeded, <c>false</c> if the game is over.</returns>
public bool NextStep()
{
// Remove lines that have reached a limit ballsInLine
if (!DestroyLines())
{
// Materialize virtual balls :)
for (int i = 0; i < virtualBalls.Length; i++)
{
Ball ball = virtualBalls[i];
if (board.GetBallAt(ball.X, ball.Y) != null)
{
Point newPos = board.GetRandomEmptySquare();
ball.MoveTo(newPos.X, newPos.Y);
}
board.SetBallAt(ball, ball.X, ball.Y);
FireBallAdd(ball);
}
virtualBalls = null;
// Collapse those that appeared after materializing virtual balls
DestroyLines();
// Generate following up set of balls
GenerateNextBalls();
}
// Increment step counter
stepCount++;
// Each step gives one point to score
score++;
if (virtualBalls == null)
{
// Game over
isGameOver = true;
return false;
}
return true;
}
/// <summary>
/// Moves currently selected ball to a new position.
/// <seealso cref="MoveBall(Point, Point)"/>
/// </summary>
/// <param name="pos">The position to move selected ball to.</param>
/// <returns><c>true</c> if the specified posion is free and reachable, <c>false</c> otherwise.</returns>
/// <remarks>
/// Moves currently selected ball to a certain position if possible. The animation of a
/// ball movement is started in a separate thread if this method has returned <c>true</c>.
/// </remarks>
public bool MoveTo(Point pos)
{
Ball destination = board.GetBallAt(pos.X, pos.Y);
Ball ball = board.GetSelectedBall();
if ((destination == null) && (ball != null))
{
Point[] route = board.CreateRoute(ball.Position, pos);
if (route != null)
{
// Fire move event and then move the ball to appropriate pos.
ball.Select(false);
AnimateMove(ball, route);
// ball.MoveTo(pos.X, pos.Y);
return true;
}
}
return false;
}
/// <summary>
/// Animates ball movement.
/// </summary>
/// <param name="ball">The ball to move.</param>
/// <param name="route">The ball's route.</param>
/// <remarks>
/// Launches an instance of <see cref="MoveBallWorker"/> in a separate thread to animate ball
/// movement.
/// </remarks>
protected void AnimateMove(Ball ball, Point[] route)
{
MoveBallWorker worker = new MoveBallWorker(this, ball, route);
Thread moveThread = new Thread(new ThreadStart(worker.Execute));
moveThread.Start();
}
/// <summary>
/// Moves a ball from one position to another.
/// <seealso cref="MoveTo(Point)"/>
/// </summary>
/// <param name="from">The initial ball lacation.</param>
/// <param name="to">The ball destination.</param>
/// <remarks>
/// <p>Moves a ball from position defined by <c>from</c> to posion <c>to</c>. Unlike <see cref="MoveTo(Point)"/>
/// method this one does not calculate a route to move the ball and does not start a separate thread to animate
/// movement, instead it simply transfers the ball and fires <see cref="BallMove"/> event.</p>
/// <p>This method is used by <see cref="MoveBallWorker"/> to move a ball for one step.</p>
/// </remarks>
public void MoveBall(Point from, Point to)
{
Ball ball = board.GetBallAt(from.X, from.Y);
if (ball != null)
{
board.MoveBall(from, to);
FireBallMove(ball, from, to);
}
}
/// <summary>
/// Removes all lins that were found by <see cref="DestroyFinder"/>.
/// </summary>
/// <returns><c>true</c> if <see cref="DestroyFinder"/> has found something to destroy and balls
/// were removed from the <see cref="Board"/>, <c>false</c> otherwise.</returns>
/// <remarks>
/// Removes all balls that compose lines which were found by <see cref="DestroyFinder"/>. Depending
/// on <see cref="OneByOneDestruction"/> flag it either removes balls from the
/// <see cref="Board"/> all at once and fires <see cref="BallsDelete"/> event or destroys balls
/// one by one with <see cref="DestroyBallPause"/> interval and fires <see cref="BallDelete"/> event
/// each time the ball is about to be removed from the <see cref="Board"/>.
/// </remarks>
public bool DestroyLines()
{
Ball[] ballsToDestroy = board.FindBallsToDestroy(ballsInLine);
bool hasBallsToDestroy = ballsToDestroy.Length > 0 ? true : false;
UpdateScore(ballsToDestroy.Length);
if (oneByOneDestruction)
{
foreach (Ball ball in ballsToDestroy)
{
FireBallDelete(ball);
board.DeleteBallAt(ball.X, ball.Y);
Thread.Sleep(destroyBallPause);
}
}
else if (hasBallsToDestroy)
{
FireBallsDelete(ballsToDestroy);
foreach (Ball ball in ballsToDestroy)
{
board.DeleteBallAt(ball.X, ball.Y);
}
}
return hasBallsToDestroy;
}
/// <summary>
/// Updates player's score.
/// </summary>
/// <param name="destroyedBalls">The amount of balls that were destroyed.</param>
/// <remarks>
/// <p>Updates player's score according to the amount of balls that were removed at one step.</p>
/// <p>The score is calculated according to following rules:</p>
/// <list type="bullet">
/// <item>
/// <description>For all mandatory amount of balls in line to be destroyed player receive
/// corresponding amount of points. So each ball weighs 1 point.</description>
/// </item>
/// <item>
/// <description>For the first extra-ball player receive 2 points.</description>
/// </item>
/// <item>
/// <description>Each farther extra-ball is rewarded with weight of previous
/// extra-ball plus 2 points.</description>
/// </item>
/// </list>
/// <p>For instance if <see cref="BallsInLine"/> is equal to 5 and player has hit 8
/// balls at one step he will be awarded with
/// <c>score = 5 (5 required balls) + 2 (1st extra-ball) + 4 (2nd extra-ball) + 6 (3rd extra-ball) = 17 points.</c></p>
/// </remarks>
public void UpdateScore(int destroyedBalls)
{
if (destroyedBalls >= ballsInLine)
{
// Give one for each ball from minimum
score += ballsInLine;
// Each extra ball is valued with weight of previous + 2 starting from 2
int extraValue = 2;
destroyedBalls -= ballsInLine;
while (destroyedBalls > 0)
{
score += extraValue;
extraValue += 2;
destroyedBalls--;
}
}
}
/// <summary>
/// Fires <see cref="BallAdd"/> event with a reference to this game.
/// </summary>
/// <param name="ball">The ball that has been added.</param>
public void FireBallAdd(Ball ball)
{
BallAdd(this, ball);
}
/// <summary>
/// Fires <see cref="BallDelete"/> event with a reference to this game.
/// </summary>
/// <param name="ball">The ball that is about to be deleted.</param>
public void FireBallDelete(Ball ball)
{
BallDelete(this, ball);
}
/// <summary>
/// Fires <see cref="BallsDelete"/> event with a reference to this game.
/// </summary>
/// <param name="balls">The balls that are about to be deleted.</param>
public void FireBallsDelete(Ball[] balls)
{
BallsDelete(this, balls);
}
/// <summary>
/// Fires <see cref="BallMove"/> event with a reference to this game.
/// </summary>
/// <param name="ball">The ball to move.</param>
/// <param name="oldPos">The old position of ball.</param>
/// <param name="newPos">The destination of ball.</param>
public void FireBallMove(Ball ball, Point oldPos, Point newPos)
{
BallMove(this, ball, oldPos, newPos);
}
/// <summary>
/// Fires <see cref="BallMoved"/> event with a reference to this game.
/// </summary>
/// <param name="ball">The ball that has been moved.</param>
public void FireBallMoved(Ball ball)
{
BallMoved(this, ball);
}
/// <summary>
/// Locks an access to the <see cref="Board"/>.
/// <seealso cref="UnlockBoard"/>
/// </summary>
/// <returns><c>true</c> if the <see cref="Board"/> were locked, <c>false</c>
/// in case the board were already locked by another process.</returns>
/// <remarks>
/// Trys to lock an access to the <see cref="Board"/>. It is a simple way to resolve
/// problems of concurrency access to the <see cref="Board"/> so that a player cannot
/// move another ball untill the first one didn't finished its movement.
/// </remarks>
public bool LockBoard()
{
if (isLocked)
return false;
isLocked = true;
return true;
}
/// <summary>
/// Unlocks an access to the <see cref="Board"/>.
/// <seealso cref="LockBoard"/>
/// </summary>
public void UnlockBoard()
{
isLocked = false;
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -