65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的贪吃蛇游戏:Engerek

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (16投票s)

2011年2月9日

CPOL

2分钟阅读

viewsIcon

119749

downloadIcon

17227

一个简单的贪吃蛇游戏,可以通过操纵杆和键盘控制,图形使用 C#,操纵杆控制使用 Directx

img1.jpg img2.jpg

引言

是的,又一个贪吃蛇游戏,如果你还没有厌倦的话。你一定见过很多用不同语言编写的贪吃蛇游戏。但是你有没有见过一个可以用键盘和操纵杆同时控制的贪吃蛇游戏?是的,这就是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 设置为-50005000,这意味着轴按钮的值可以是最大 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 日:初始帖子
© . All rights reserved.