Windows Mobile 版 Reversi






4.86/5 (4投票s)
使用 Compact Framework 开发的 Windows Mobile 版黑白棋游戏。
引言
我们将使用 C# 和 .NET Compact Framework 3.5 为 Windows Mobile 创建一个黑白棋游戏克隆。Compact Framework 是 .NET Framework 的一个子集,用于运行 Windows CE 的设备。使用 Compact Framework 开发应用程序与开发普通 Windows 应用程序的方式非常相似。 使用 CF,整个应用程序在几个小时内就完成了编写。
背景
黑白棋是一个古老的游戏,由 Lewis Waterman 于 1883 年创建。游戏在 8x8 的棋盘上进行,棋盘上有 64 个棋子,一面是黑色,一面是白色。游戏开始时,棋盘中心有 4 个棋子,两个黑色和两个白色。每个玩家轮流将棋子放在棋盘上。只有当移动有效时,玩家才能将棋子放在棋盘上。要使移动有效,必须有一个相邻的敌方棋子,并且在它后面有一条直线上的另一个玩家棋子。该线上的所有敌方棋子都会被翻转,并属于进行移动的玩家。下图显示了所有可能的黑色移动和受影响的棋子。
如果棋盘上没有有效的移动,则可以跳过玩家。游戏一直进行到棋盘被填满或双方玩家都没有有效的移动为止。棋盘上棋子最多的玩家获胜。您可以从这个 Wikipedia 页面了解更多关于黑白棋的信息:http://en.wikipedia.org/wiki/Reversi。
游戏代码
正如您所看到的,黑白棋是一个非常简单的游戏。游戏代码由几个文件组成,大部分操作都在 Game.cs 中。游戏棋盘是一个简单的二维字节数组。数组中的每个字节代表占据该位置的玩家。下面是用于在游戏中移动的方法。该方法采用位置和正在移动的玩家。如果移动成功,则返回 true
。如果移动有效,我们将更新棋盘上的位置并设置玩家。
public bool Move(Point position, Player player) { // Not the current players move so ignore. if (_currentPlayer != player) { return false; } // The move is outside the board. if (position.X >= _board.BoardWidth || position.Y >= _board.BoardHeight) { return false; } // Already a player in that position. if (_board[position.X, position.Y].Player != Player.NotSet) { return false; } bool validMove = false; validMove |= UpdateDirection(position, Direction.East, player); validMove |= UpdateDirection(position, Direction.North, player); validMove |= UpdateDirection(position, Direction.NorthEast, player); validMove |= UpdateDirection(position, Direction.NorthWest, player); validMove |= UpdateDirection(position, Direction.South, player); validMove |= UpdateDirection(position, Direction.SouthEast, player); validMove |= UpdateDirection(position, Direction.SouthWest, player); validMove |= UpdateDirection(position, Direction.West, player); if (validMove) { _board[position.X, position.Y] = new Position(player); TogglePlayer(); } return validMove; }
下面是 UpdateDirection
和 CheckDirection
方法。 UpdateDirection
检查当前移动是否会影响指定方向上的任何单元格。 endpoint 输出参数将具有最后一个受影响单元格的坐标。 UpdateDirection
方法调用 CheckDirection
,并将更新从移动位置到 endpoint 位置的直线上的所有单元格。 这三个方法构成了大部分游戏逻辑。
private bool UpdateDirection(Point position, Direction direction, Player player)
{
IEnumerable<Point> modifiedPositions;
Point endPoint;
if (CheckDirection(position, direction, player, out endPoint))
{
modifiedPositions = GetPositions(position, endPoint);
foreach (Point p in modifiedPositions)
{
_board[p.X, p.Y] = new Position(player, 0);
}
return true;
}
return false;
}
public bool CheckDirection(Point point, Direction direction,
Player player, out Point endPoint)
{
Point directionMod = GetDirectionModifier(direction);
int xMod = directionMod.X, yMod = directionMod.Y;
int x = point.X + xMod, y = point.Y + yMod;
Player otherPlayer = player == Player.PlayerOne ?
Player.PlayerTwo : Player.PlayerOne;
Player currentPlayer;
bool hasOther = false;
while (x > -1 && x < _board.BoardWidth &&
y > -1 && y < _board.BoardHeight)
{
// Get the current player.
currentPlayer = _board[x, y].Player;
// Got to the end and no match.
if ( currentPlayer == Player.NotSet )
{
break;
}
else if ( currentPlayer == otherPlayer )
{
hasOther = true;
}
else if ( currentPlayer == player )
{
if (hasOther)
{
endPoint = new Point(x-=xMod, y-=yMod);
return true;
}
endPoint = Point.Empty;
return false;
}
// Move to next position.
x += xMod;
y += yMod;
}
endPoint = Point.Empty;
return false;
}
渲染代码
我们使用 GDI 来渲染游戏棋盘。 为了绘制棋盘,我们只需遍历所有棋盘位置,绘制一个正方形,然后如果在当前位置有玩家,则绘制一个黑色或白色圆圈。 我们在后备缓冲区图像上绘制游戏棋盘,然后将该图像绘制到屏幕上。
const float circleReduce = .2F;
// Get the positions and board width,height
Position[] positions = _game.Board.Data;
int boardWidth = _game.Board.BoardWidth,
boardHeight = _game.Board.BoardHeight;
Rectangle positionRectangle;
int x = 0, y = 0;
// Draw the background.
TransparentControl.PaintBackground(graphics, _renderArea);
Player player;
for (int i = 0; i < positions.Length; i++)
{
// Get the position rectangle.
positionRectangle = new Rectangle(
x, y,
(int)(_positionSize.Width),
(int)(_positionSize.Height));
// Draw the grid.
graphics.DrawRectangle(new Pen(Color.Black, 2),
positionRectangle);
// Get the player.
player = positions[i].Player;
Rectangle playerPosition = positionRectangle;
// Render any circles for any positions that are occupied.
if (player != Player.NotSet)
{
playerPosition.Inflate(-(int)(positionRectangle.Width * circleReduce),
-(int)(positionRectangle.Height * circleReduce));
graphics.FillEllipse(
new SolidBrush(player == Player.PlayerOne ? Color.Black : Color.White),
playerPosition
);
}
// Move to next position.
if (i != 0 && ((i + 1) % boardWidth) == 0)
{
x = 0;
y += (int)_positionSize.Height;
}
else
{
x += (int)_positionSize.Width;
}
}
对于输入,我们订阅宿主控件的 OnClick
事件。 然后我们将屏幕坐标转换为棋盘坐标,并在游戏实例上调用 Move
方法。
Point translatedPoint = TranslatePoint(
_renderArea.PointToClient(Control.MousePosition));
private Point TranslatePoint(Point point)
{
int x = (int)((point.X) / _positionSize.Width),
y = (int)((point.Y) / _positionSize.Height);
return new Point(x, y);
}
我没有太多时间来开发 AI。 目前,计算机将进行第一次可用的移动。 以后,也许会实现一些更好的东西。
最新版本的 CF 包含 SoundPlayer
类。 我们使用此类来播放游戏声音。 有四种游戏声音:游戏开始声音、移动声音、无效移动声音和跳过回合声音。 此游戏的声音是使用 sfxr 生成的。 它是一个用于生成视频游戏声音的免费软件应用程序。 如果您需要一些游戏开发的快速声音,我建议您查看一下:http://www.cyd.liu.se/~tompe573/hp/project_sfxr.html。