简单的贪吃蛇游戏:Engerek






4.85/5 (16投票s)
一个简单的贪吃蛇游戏,可以通过操纵杆和键盘控制,图形使用 C#,操纵杆控制使用 Directx


引言
是的,又一个贪吃蛇游戏,如果你还没有厌倦的话。你一定见过很多用不同语言编写的贪吃蛇游戏。但是你有没有见过一个可以用键盘和操纵杆同时控制的贪吃蛇游戏?是的,这就是Engerek与其他贪吃蛇游戏的不同之处。
- 操纵杆游戏控制 -
Microsoft.Directx.DirectInput
- 游戏图形 -
System.Drawing*
- 游戏声音 -
System.Media
在你说任何话之前,我必须说明这是一个我的第一个项目。也许你会觉得我的代码很糟糕,我接受你们所有的评论。
好的,现在我们来看代码。项目的的文件和路径如下
MyGame.cs | 这是我们的主窗体。 |
Game.cs | 这是主游戏类。它包含贪吃蛇的所有属性。 |
Joystick.cs | 这个包含操纵杆类(Directx.DirectInput )。 |
LinkedList.cs | 包含用于存储贪吃蛇节点的链表类。 |
/sounds | 包含声音文件 * |
/fonts | 包含字体文件 |
/pictures | 包含位图文件 |
* 如果你想启用声音,你必须将“menu.wav”、“eated.wav”和“gameover.wav”声音文件放在“/sounds/”目录下。由于文件上传限制(6 MB),源代码中没有声音文件。
Joystick.cs
在这里,我们创建一个joystick
类。你可以在这里看到最简单的 Directx 代码。
class joysticks
{
public static Device joystick;
public static JoystickState state;
public static void InitDevices() //Function of initialize device
{
//create joystick device.
foreach (DeviceInstance di in Manager.GetDevices(
DeviceClass.GameControl,
EnumDevicesFlags.AttachedOnly))
{
joystick = new Device(di.InstanceGuid);
break;
}
if (joystick == null)
{
//Throw exception if joystick not found.
}
//Set joystick axis ranges.
else {
foreach (DeviceObjectInstance doi in joystick.Objects)
{
if ((doi.ObjectId &
(int)DeviceObjectTypeFlags.Axis) != 0)
{
joystick.Properties.SetRange(
ParameterHow.ById,
doi.ObjectId,
new InputRange(-5000, 5000));
}
}
joystick.Properties.AxisModeAbsolute = true;
joystick.SetCooperativeLevel
(null,CooperativeLevelFlags.NonExclusive |
CooperativeLevelFlags.Background);
//Acquire devices for capturing.
joystick.Acquire();
state = joystick.CurrentJoystickState;
}
}
public static void UpdateJoystick() // Capturing from device joystick
{
//Get Joystick State.
if(joystick!=null)
state = joystick.CurrentJoystickState;
}
}
就这样。正如你所见,我们将InputRange
设置为-5000和5000,这意味着轴按钮的值可以是最大 5000和最小 -5000。当轴按钮未按下时,平均值为 -40。那么我们如何使用这个类访问操纵杆呢?
访问轴按钮非常简单
if(joysticks.state.X > -40) //pressing x+ (right button)
else if(joysticks.state.X < -40) //pressing x- (left button)
if(joysticks.state.Y > -40) //pressing y+ (up button)
else if(joysticks.state.Y < -40) //pressing x+ (down button)
如果你仍然不明白,可以参考这些文章
Game.cs
这个文件包含我们的主游戏类。贪吃蛇的所有属性都实现在这里。
//I won't write all variables here, you can understand what's it's purpose.
// as we use you will understand also. I will write about function
public void Load_Graphic() //creating a bmp that have a black background.
{
bmp = new Bitmap(game_width,game_height);
graph = Graphics.FromImage(bmp);
graph.FillRectangle(back_color,0,0,game_width,game_height);
}
public void Add_Snake_Node(int x,int y) //add node to snake when it eat a bait.
{
graph.FillRectangle(snake_skin_color,x*node_length,
y*node_length,node_length,node_length);
graph.FillRectangle(snake_body_color,x*node_length,
y*node_length,node_length-node_border_length,node_length-node_border_length);
}
public void Delete_Snake_Node(int x, int y) //delete node by coordinate.
{
graph.FillRectangle(back_color,x*node_length,
y*node_length,node_length,node_length);
}
//assign direction of snake
public void Move_Snake_Left()
{
node_x--;
}
public void Move_Snake_Right()
{
node_x++;
}
public void Move_Snake_Up()
{
node_y--;
}
public void Move_Snake_Down()
{
node_y++;
}
//control to bait if it's on the same coordinate with wall or snake body.
public bool Control_Bait_Coordinate()
{
Node temp_x = snake_area_x.first;
Node temp_y = snake_area_y.first;
for(int i= snake_area_x.length;i>0;i--)
{
if((bait.X == temp_x.value) && (bait.Y == temp_y.value))
return true;
else
{
temp_x = temp_x.next;
temp_y = temp_y.next;
}
}
temp_x = wall_area_x.first;
temp_y = wall_area_y.first;
for(int j= wall_area_x.length;j>0;j--)
{
if((bait.X == temp_x.value) && (bait.Y == temp_y.value))
return true;
else
{
temp_x = temp_x.next;
temp_y = temp_y.next;
}
}
return false;
}
// getting a random coordinate for bait.
public void Find_Coordinate_For_Bait()
{
Random rnd = new Random();
bait.X = rnd.Next(1,game_width/node_length-1);
bait.Y = rnd.Next(1,game_height/node_length-1);
bait_bool = true;
}
// put a bait by coordinate
public void Add_New_Bait(int x, int y)
{
if(!Control_Bait_Coordinate())
{
graph.FillRectangle(bait_skin_color,x*node_length,y*node_length,
node_length,node_length);
graph.FillRectangle(bait_body_color,x*node_length,y*node_length,
node_length-node_border_length,node_length-node_border_length);
}
else bait_bool=false;
}
//control for "did snake eat the bait"
public bool Did_Snake_Eat_The_Bait()
{
if((node_x == bait.X) && (node_y==bait.Y))
return true;
else
return false;
}
//control for "did snake crash byself"
public bool Did_Snake_Crash_Byself(int temp_route)
{
int x = node_x*node_length;
int y = node_y*node_length;
try
{
if (temp_route == 4) {
if (bmp.GetPixel(x + node_length/2, y + node_length/2) ==
bmp.GetPixel(x + node_length/2 - node_length, y + node_length/2))
{
return true;
}
if(bmp.GetPixel(x + node_length/2 - node_length, y +
node_length/2) == new Pen(wall_body_color).Color)
{
return true;
}
}
if (temp_route == 2) {
if (bmp.GetPixel(x + node_length/2, y + node_length/2) ==
bmp.GetPixel(x + node_length/2 + node_length ,
y + node_length/2))
{
return true;
}
if(bmp.GetPixel(x + node_length/2 + node_length , y +
node_length/2) == new Pen(wall_body_color).Color)
{
return true;
}
}
if (temp_route == 1) {
if (bmp.GetPixel(x + node_length/2, y + node_length/2) ==
bmp.GetPixel(x + node_length/2, y +
node_length/2 - node_length))
{
return true;
}
if(bmp.GetPixel(x + node_length/2, y + node_length/2 -
node_length) == new Pen(wall_body_color).Color)
{
return true;
}
}
if (temp_route == 3) {
if (bmp.GetPixel(x + node_length/2, y + node_length/2) ==
bmp.GetPixel(x + node_length/2, y +
node_length/2 + node_length))
{
return true;
}
if(bmp.GetPixel(x + node_length/2, y + node_length/2 +
node_length) == new Pen(wall_body_color).Color)
{
return true;
}
}
}
catch (Exception e) { string str = e.Message.ToString(); return false; }
return false;
}
// putting wall node by coordinate
public void Add_Wall_Node(int x1,int y1,int x2,int y2)
{
if(x1==x2)
{
while(y1<=y2)
{
graph.FillRectangle(wall_skin_color,x1*node_length,
y1*node_length,node_length,node_length);
graph.FillRectangle(wall_body_color,x1*node_length,
y1*node_length,node_length-node_border_length,
node_length-node_border_length);
wall_area_x.Add_Node(x1);
wall_area_y.Add_Node(y1);
y1++;
}
}
else if(y1==y2)
{
while(x1<=x2)
{
graph.FillRectangle(wall_skin_color,x1*node_length,
y1*node_length,node_length,node_length);
graph.FillRectangle(wall_body_color,x1*node_length,
y1*node_length,node_length-node_border_length,
node_length-node_border_length);
wall_area_x.Add_Node(x1);
wall_area_y.Add_Node(y1);
x1++;
}
}
}
// play sound when snake eat a bait.
public void Eated_Sound()
{
if(sound_control == "on" && File.Exists(sound_eated.SoundLocation) )
sound_eated.Play();
}
// play sound while user on menu.
public void Main_Menu_Sound()
{
if(sound_control == "on" && File.Exists(sound_eated.SoundLocation))
sound_menu.Play();
}
// play sound when snake eat a bait.
public void Gameover_Sound()
{
if(sound_control == "on" && File.Exists(sound_eated.SoundLocation))
sound_gameover.Play();
}
当你查看Game.cs时,你将看到更多关于菜单设计的代码,但那不是游戏的重要部分。我不会解释它。
Mygame.cs
简单来说,我们有一个窗体。该窗体有一个PictureBox和计时器。这是游戏中最重要的元素。我们的主计时器MyGame_timer
循环游戏。在每次刻度中,它调用名为Game_Playing()
的函数。让我们看看这个函数
/*********************** THE MAIN GAME FUNCTION ***********************/
// All controls and snake movements are implemented in here.
public bool Game_Playing()
{
lb_level.Text = "LEVEL-" + mygame.game_level.ToString();
lb_point.Text = mygame.point.ToString() + "/" + mygame.level_point.ToString();
if(mygame.point >= mygame.level_point)
{
//for loading the next level
Clear_Level();
return true;
}
if(mygame.Did_Snake_Crash_Byself(mygame.snake_route)) // control if snake
// crashed to byself or wall
{
MyGame_timer.Enabled = false;
wait_timer.Enabled = true;
mygame.wait_time = 20;
return true;
}
/*Snake route is setting in here */
if(mygame.snake_route == 1) mygame.Move_Snake_Up();
else if(mygame.snake_route == 2) mygame.Move_Snake_Right();
else if(mygame.snake_route == 3) mygame.Move_Snake_Down();
else if(mygame.snake_route == 4) mygame.Move_Snake_Left();
/*Adding new node to snake*/
mygame.Add_Snake_Node(mygame.node_x,mygame.node_y);
mygame.snake_area_x.Add_Node(mygame.node_x);
mygame.snake_area_y.Add_Node(mygame.node_y);
mygame.snake_route_temp= mygame.snake_route;
if(!mygame.eated) {
mygame.Delete_Snake_Node(mygame.snake_area_x.first.value,
mygame.snake_area_y.first.value);
mygame.snake_area_x.Delete_First_Node();
mygame.snake_area_y.Delete_First_Node();
}
else mygame.eated = false;
if(!mygame.bait_bool) {
mygame.Find_Coordinate_For_Bait();
if(!mygame.Control_Bait_Coordinate())
{
mygame.Add_New_Bait(mygame.bait.X,mygame.bait.Y);
}
}
/* control if snake eated the bait */
if(mygame.Did_Snake_Eat_The_Bait())
{
mygame.Eated_Sound();
mygame.Find_Coordinate_For_Bait();
if(!mygame.Control_Bait_Coordinate())
{
mygame.Add_New_Bait(mygame.bait.X,mygame.bait.Y);
}
else mygame.bait_bool=false;
mygame.eated = true;
mygame.point +=10;
if(MyGame_timer.Interval > 40)
MyGame_timer.Interval--;
}
pictureBox1.Image = mygame.bmp;
pictureBox1.Refresh();
if((mygame.node_x > (mygame.game_width/mygame.node_length-1)) &&
mygame.snake_route==2)
{
mygame.node_x = 0;
mygame.Add_Snake_Node(mygame.node_x,mygame.node_y);
mygame.snake_area_x.Add_Node(mygame.node_x);
mygame.snake_area_y.Add_Node(mygame.node_y);
if(!mygame.eated)
{
mygame.Delete_Snake_Node(mygame.snake_area_x.first.value,
mygame.snake_area_y.first.value);
mygame.snake_area_x.Delete_First_Node();
mygame.snake_area_y.Delete_First_Node();
}
else mygame.eated = false;
}
else if(mygame.node_x < 0 && mygame.snake_route==4)
{
mygame.node_x = (mygame.game_width/mygame.node_length-1);
mygame.Add_Snake_Node(mygame.node_x,mygame.node_y);
mygame.snake_area_x.Add_Node(mygame.node_x);
mygame.snake_area_y.Add_Node(mygame.node_y);
if(!mygame.eated)
{
mygame.Delete_Snake_Node(mygame.snake_area_x.first.value,
mygame.snake_area_y.first.value);
mygame.snake_area_x.Delete_First_Node();
mygame.snake_area_y.Delete_First_Node();
}
else mygame.eated = false;
}
if((mygame.node_y > (mygame.game_height/mygame.node_length-1)) &&
mygame.snake_route==3)
{
mygame.node_y = 0;
mygame.Add_Snake_Node(mygame.node_x,mygame.node_y);
mygame.snake_area_x.Add_Node(mygame.node_x);
mygame.snake_area_y.Add_Node(mygame.node_y);
if(!mygame.eated)
{
mygame.Delete_Snake_Node(mygame.snake_area_x.first.value,
mygame.snake_area_y.first.value);
mygame.snake_area_x.Delete_First_Node();
mygame.snake_area_y.Delete_First_Node();
}
else mygame.eated = false;
}
else if(mygame.node_y < 0 && mygame.snake_route==1)
{
mygame.node_y = (mygame.game_height/mygame.node_length-1);
mygame.Add_Snake_Node(mygame.node_x,mygame.node_y);
mygame.snake_area_x.Add_Node(mygame.node_x);
mygame.snake_area_y.Add_Node(mygame.node_y);
if(!mygame.eated)
{
mygame.Delete_Snake_Node(mygame.snake_area_x.first.value,
mygame.snake_area_y.first.value);
mygame.snake_area_x.Delete_First_Node();
mygame.snake_area_y.Delete_First_Node();
}
else mygame.eated = false;
}
return true;
}
就这样。我希望这能帮助你理解Directx.DirectInput
和System.Draw
库。现在感谢你的阅读。
历史
- 2011 年 2 月 9 日:初始帖子