Clickmania游戏(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/clickmania-game-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 6 分钟阅读 - 2942 个词 阅读量 0Clickmania游戏(译文)
原文地址:https://www.codeproject.com/Articles/9993/Clickmania-Game
原文作者:aaccoobb
译文由本站 robot-v1.0 翻译
前言
A simple logical game
一个简单的逻辑游戏
介绍(Introduction)
我曾经踩过(I once stepped on) 下一代Clickomania(Clickomania next generation) 我来自MatthiasSchüssler,非常喜欢这款游戏,以至于我决定从零开始用C#来实现该游戏.我的版本比较简单,但是使用了很多相同的设计.我在Athlon 2000+上测试了游戏,它似乎运行顺利.(from Matthias Schüssler and liked the game so much that I decided to implement that game in C# from scratch. My version is simpler but uses a lot of the same design. I tested the game on an Athlon 2000+ and it seemed to work smoothly.)
特征(Features)
- 动画和声音(Animations and sounds)
- 保存高分(前10名)(Save the high scores (Top 10))
- 退后一步(Take back move)
对象模型(The Object Model)
我使用两个大类,(I use two big classes,) MainForm
和(and) Engine
.的(. The) MainForm
处理事件,绘图和动画,(deals with events, drawing and animation, the) Engine
包含逻辑.我也用三个(contains the logic. I also use three) struct
s,一个用于(s, one for the) Scores
(得分,玩家姓名,日期等):((Score, Player name, Date, etc.):)
public struct Scores
{
public int _iScores; // score
public string _sNames; // player name
public int _SbestMove; // his best move
public int _SballsLeft; // balls left after game over
public int _Stime; // time for that game
public string _Date; // the date he played (mm/dd/yyyy mm:ss)
public int _sTakeBacks; // how many times did he take back
// during the game
}
一个为(One for the) Ball
:(:)
public struct Ball
{
public int _icolor; // its color
public bool _exists; // does it still exist
public bool _isDisappearing; // is it in animation status
public int _vel; // velocity of animation
public int _yvel;
}
还有一个(and one for the) Turn
,其中包含有关消失的球,球的位置和移动的列的信息,因此可以收回移动:(, which contains information about the disappeared balls, their position and the moved columns, so the moves can be taken back:)
public struct Turn
{
public int _itColor; // Color of disappeared balls
public int [] _itposX; // Position
public int [] _itposY;
public int [] _column; // Disappeared columns
}
关于逻辑的一点(A Bit About the Logic)
在(On the) PictureBox
,球似乎在移动,但实际上并没有.球阵列存储8x12球.他们留在董事会.他们只改变颜色或得到(, the balls seem to move, but actually they don’t. The balls array stores 8x12 balls. They stay at their place on the board. They only change color or get the) status _exist = false
当他们应该走了.(when they are supposed to be gone.)
当玩家单击球时,它将检查它是否属于具有相同颜色的一组球.这是通过递归函数完成的:(When the player clicks on the ball, it checks if it belongs to a group of balls with the same color. This is done with a recursive function:)
private int CheckNextBall(int x, int y, int color)
{
int px, nx, py, ny;
px = (x == 0 ? 0 : x - 1); //prior X
nx = (x == 7 ? 7 : x + 1); //next X
py = (y == 0 ? 0 : y - 1); //prior Y
ny = (y == 11 ? 11 : y + 1);//next Y
int ret = 1;
// the 4 "if" statements do basically the
// same, they check if the
// neighbour of the actual ball has the same color
if((_ball[px, y]._icolor == color) && (_ball[px, y]._exists) && (px != x))
{
// make it inexistant
_ball[px, y]._exists = false;
// to animate it in the main form
_ball[px, y]._isDisappearing = true;
// save color of ball( so we can take the turn back)
_turn[_turn.GetLength(0) - 1]._itColor = color;
_X[_index] = px; // and save its position (for the same reason)
_Y[_index] = y;
_index++;
ret += CheckNextBall(px, y, color);
}
if((_ball[nx, y]._icolor == color) && (_ball[nx, y]._exists) && (nx != x))
{
_ball[nx, y]._exists = false;
_ball[nx, y]._isDisappearing = true;
_turn[_turn.GetLength(0) - 1]._itColor = color;
_X[_index] = nx;
_Y[_index] = y;
_index++;
ret += CheckNextBall(nx, y, color);
}
if((_ball[x, py]._icolor == color) && (_ball[x, py]._exists) && (py != y))
{
_ball[x, py]._exists = false;
_ball[x, py]._isDisappearing = true;
_turn[_turn.GetLength(0) - 1]._itColor = color;
_X[_index] = x;
_Y[_index] = py;
_index++;
ret += CheckNextBall(x, py, color);
}
if((_ball[x, ny]._icolor == color) && (_ball[x, ny]._exists) && (ny != y))
{
_ball[x, ny]._exists = false;
_ball[x, ny]._isDisappearing = true;
_turn[_turn.GetLength(0) - 1]._itColor = color;
_X[_index] = x;
_Y[_index] = ny;
_index++;
ret += CheckNextBall(x, ny, color);
}
return ret;
}
此功能检查四个相邻球的颜色,如果它们具有相同的颜色,则将其状态设置为消失并检查相邻球的颜色.它还会将有关颜色和位置的信息保存在(This function checks the color of the four neighboring balls, and if they have the same color, sets its state to disappearing and checks the neighbors for their colors. It also saves the information about color and position in the) Turn
struct
,这样玩家便可以根据需要收回移动.(, so that the player can take back the move if he wants to.)
动画(Animation)
这是在(This is done in the) Mainform
类,使用动画球的位置和大小的全局变量,以及(class using global variables of position and size of animated balls, and the) pictureBox.Refresh()
方法.例如,要使球出现或消失,请执行以下操作:(method. For example, to make balls appear or disappear, do the following:)
/// <summary>
/// Balls Disappear or appear
/// </summary>
/// <param name="appear"> if they are appearing or disappearing</param>
public void MakeBallsAppear(bool appear)
{
if(!appear)
{
PlayWav(1); // play a sound
// redraw all balls, but animate only thosse with appear state
// this occurs when balls that are clicked disappear
for(int i = 0; i < 12; i++)
{
_var = i;
Thread.Sleep(10); // sleep 10 ms between 2 frames
this.pictureBox1.Refresh();
}
_var = 0;
}
else
{
PlayWav(8);
// same thng here too, but balls reappaer when
// player takes a move back
for(int i = 11; i >= 0; i--)
{
_var = i;
Thread.Sleep(10);
this.pictureBox1.Refresh();
}
}
}
的(The) Paint
事件在绘制一帧时(event draws one frame when) pictureBox.Refresh()
在上面的循环中被调用.在绘制下一帧之前,我们还需要等待10毫秒,以便动画在更快的计算机上不会更快地出现:(is called in the loop above. We also wait for 10 ms before painting the next frame, so that the animations wouldn’t appear faster on faster machines:)
/// <summary>
/// here all the drawing takes place. for each
/// frame, this event is called once,
/// with a different _var, _posx or _posy
/// if an animation takes place
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 12; j++)
{
if(engine._ball[i, j]._exists)
{
g.DrawImage(_bmp[engine._ball[i, j]._icolor],
(i * 24) - _posx * engine._ball[i, j]._yvel,
(j * 24) + _posy * engine._ball[i, j]._vel,
24, 24);
}
if(engine._ball[i, j]._isDisappearing)
{
g.DrawImage(_bmp[engine._ball[i, j]._icolor],
(i * 24) + _var, (j * 24) + _var,
24 - (_var*2), 24 - (_var*2));
}
}
}
if((_gameover) && (!_gamewon))
{
// shadow of the text
g.DrawString("GAME OVER", new Font("Arial", 20),
System.Drawing.Brushes.Black,
new Point(10, 122));
g.DrawString("GAME OVER", new Font("Arial", 20),
System.Drawing.Brushes.LightBlue,
new Point(8, 120));
}
if(_gamewon)
{
// shadow of the text
g.DrawString("GAME WON", new Font("Arial", 20,
System.Drawing.FontStyle.Bold),
System.Drawing.Brushes.Black,
new Point(12, 122));
g.DrawString("GAME WON", new Font("Arial", 20,
System.Drawing.FontStyle.Bold),
System.Drawing.Brushes.Yellow,
new Point(10, 120));
}
}
声音(Sounds)
的(The) PlaySound(...)
来自的方法(method from)**winmm.dll(winmm.dll)**用于播放WAV文件:(is used to play with WAV files:)
[DllImport("winmm.dll")]
private static extern bool PlaySound( string lpszName,
int hModule, int dwFlags );
private void PlayWav(int play)
{
if(checkBox1.Checked)
{
string myFile = ".\\Sounds\\default.wav";
switch(play)
{
case 1:
myFile = ".\\Sounds\\BallDisappear.wav";
break;
case 2:
myFile = ".\\Sounds\\BallDown.wav";
break;
case 3:
myFile = ".\\Sounds\\lost.wav";
break;
case 4:
myFile = ".\\Sounds\\newgame.wav";
break;
case 5:
myFile = ".\\Sounds\\ColumnDis.wav";
break;
case 6:
myFile = ".\\Sounds\\ColumnAppear.wav";
break;
case 7:
myFile = ".\\Sounds\\BallUp.wav";
break;
case 8:
myFile = ".\\Sounds\\BallAppear.wav";
break;
case 9:
myFile = ".\\Sounds\\Won.wav";
break;
case 10:
myFile = ".\\Sounds\\illegal.wav";
break;
default:
break;
}
PlaySound(myFile, 0, 0x0003); // Play the sound
}
}
WAV文件必须在子文件夹中(The WAV files have to be in the subfolder)**声音(Sounds)**包含的文件夹(of the folder containing)Clickmania.exe(Clickmania.exe).我已经使用了游戏Half Half 2的一些声音.如果您想使用自己的声音,可以将其上传到(. I have used some sounds of the game Half Life 2. If you want to use your own sounds, you can upload them to the)**声音(sounds)**文件夹并重命名.(folder and rename them.)
分数(Scores)
所有分数都存储在一个名为(All scores are stored in a binary file called)**Scores.sco(Scores.sco)**与exe位于同一文件夹中.如果此文件不存在,它将在运行游戏时生成.该文件还包含最后一位进入前10名的用户的名称,因此,如果他再次达到前10名,则不应重新输入其姓名.要查看高分,我使用了(in the same folder as the exe. If this file does not exist, it will be generated when the game is run. This file also contains the name of the last user who reached the top 10, so he shouldn’t reenter his name if he reaches the top10 again. To view the high scores, I have used the) ListView
控制:(control:)
private void PopulateListbox()
{
string name, score;
listView1.Items.Clear(); // remove items in listview
ListViewItem [] items = new ListViewItem[10];
//DateTime date;
Color textColor = new Color();
Font font;
for(int i = 0; i < 10; i++)
{
name = (i + 1).ToString() + ":" +
" " + _MF._stScores[i]._sNames;
score = _MF._stScores[i]._iScores.ToString();
if (i == 9)name = (i + 1).ToString() + ":" +
" " + _MF._stScores[i]._sNames;
textColor = _MF._stScores[i]._SballsLeft == 0 ?
System.Drawing.Color.Blue : System.Drawing.Color.Black;
textColor = (_MF._stScores[i]._sTakeBacks == 0 &&
_MF._stScores[i]._SballsLeft == 0) ?
Color.DarkRed : textColor;
font = (textColor == Color.Black) ?
new Font("Arial", 8) : new Font("Fixedsys", 8,
(_MF._stScores[i]._sTakeBacks == 0) ?
FontStyle.Italic : FontStyle.Regular);
items[i] = new ListViewItem(new string[] {name, score,
_MF._stScores[i]._Date,
_MF._stScores[i]._Stime.ToString(),
_MF._stScores[i]._SbestMove.ToString(),
_MF._stScores[i]._SballsLeft.ToString(),
_MF._stScores[i]._sTakeBacks.ToString()},
-1, textColor, Color.White, font);
listView1.Items.Add(items[i]);
}
}
根据游戏的玩法,信息会以不同的颜色显示,例如,如果玩家没有丢球或没有回退.(Information is shown in a different color according to how the game was played, for example if the player left no balls or if he took no moves back.)
关于计划(About the Program)
这是我最早的C#实现之一,因此,如果我的代码在某些地方看起来很垃圾,请放纵自己.(This is one of my first C# implementations, so be indulgent if my code seems junk at some places.)
执照(License)
本文没有附带任何明确的许可,但可能在文章文本或下载文件本身中包含使用条款.如有疑问,请通过下面的讨论区与作者联系.(This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.) 可以找到作者可能使用的许可证列表(A list of licenses authors might use can be found) 这里(here) .(.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# WinXP Windows .NET .NET1.1 Visual-Studio VS.NET2003 Dev 新闻 翻译