Click here to Skip to main content
15,884,298 members
Articles / Game Development

A Simple Snake Game: Engerek

Rate me:
Please Sign up or sign in to vote.
4.85/5 (18 votes)
9 Feb 2011CPOL2 min read 116.5K   17.2K   32   16
A simple snake game controllable both by joystick and keyboard, graphics using C#, joystick control using Directx
img1.jpg img2.jpg

Introduction

Yes, again a snake game if you aren't bored yet. You must have seen a lot of snake games created in different languages. But have you ever seen a snake game that is controllable both by keyboard and joystick? Yes, this is the difference between snake games and Engerek.

  • Game control by joystick - Microsoft.Directx.DirectInput
  • Game graphics - System.Drawing*
  • Game sounds - System.Media

Before you say anything, I have to indicate that this is my first project. Maybe you will find my coding bad, I accept all of your comments.

Ok, now we are looking at the code. The files and paths of project are as follows:

MyGame.csThis is our main form.
Game.csThis is the main game class. It includes all snake's properties.
Joystick.csThis one includes joystick class (Directx.DirectInput).
LinkedList.csIncludes linked list class that is used for storing snake nodes.
/soundsIncludes sound files *
/fontsIncludes font files
/picturesIncludes bitmap files

* If you want to enable sounds, you have to locate "menu.wav", "eated.wav" and "gameover.wav" sound files to "/sounds/" directory. the source code doesn't have sounds file because of file upload limit (6 MB).

Joystick.cs

In here, we create a joystick class. You can see the most simple Directx code in here.

C#
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;
	}		
}

That's all. As you see, we set InputRange as -5000 and 5000, this means, axis button's value can be max 5000 and min -5000. While axis button is not pressed, the value average value is -40. So how can we access joystick with this class?

Accessing axis buttons is very simple:

C#
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)

If you still didn't understand, you can look at these articles:

Game.cs

This file has our main game class. All snake properties are implemented in here.

C#
//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();
}	

You will see more code about menu design when you look at Game.cs, but that's not an important part of the game. I won't explain it.

Mygame.cs

Simply, we have a form. The form has a picturebox and timers. This is the most important element in the game. Our main timer, MyGame_timer, is looping the game. In every tick, it calls the function named Game_Playing(). Let's look at that function:

C#
/*********************** 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;			
}

That's all. I hope this will help you to understand about Directx.DirectInput and System.Draw libraries. Thanks for reading now.

History

  • 9th February, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Turkey Turkey
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 1 Pin
ioajsfdfkljsf22-Dec-14 8:42
ioajsfdfkljsf22-Dec-14 8:42 
GeneralMy vote of 3 Pin
Anas Tasadduq31-May-14 6:50
Anas Tasadduq31-May-14 6:50 
GeneralMy vote of 1 Pin
Anas Tasadduq31-May-14 6:49
Anas Tasadduq31-May-14 6:49 
BugLoaderLock was detected? Pin
supernorb26-Mar-13 3:05
supernorb26-Mar-13 3:05 
GeneralRe: LoaderLock was detected? Pin
coolprarun28-Aug-13 21:24
coolprarun28-Aug-13 21:24 
GeneralRe: LoaderLock was detected? Pin
Member 102626039-Sep-13 8:57
Member 102626039-Sep-13 8:57 
GeneralMy vote of 5 Pin
Akinmade Bond15-Oct-12 4:15
professionalAkinmade Bond15-Oct-12 4:15 
GeneralMy vote of 5 Pin
Reza Ahmadi17-May-12 0:54
Reza Ahmadi17-May-12 0:54 
GeneralMy vote of 5 Pin
Himanshu R Sachdeva12-Jan-12 3:41
Himanshu R Sachdeva12-Jan-12 3:41 
GeneralMy vote of 5 Pin
Reelix23-Feb-11 0:24
Reelix23-Feb-11 0:24 
QuestionXNA? Pin
Reelix23-Feb-11 0:23
Reelix23-Feb-11 0:23 
AnswerRe: XNA? Pin
Okan Kocyigit23-Feb-11 1:00
Okan Kocyigit23-Feb-11 1:00 
GeneralCool I did snakes a while back too, fun isn't it Pin
Sacha Barber9-Feb-11 21:32
Sacha Barber9-Feb-11 21:32 
GeneralRe: Cool I did snakes a while back too, fun isn't it Pin
Okan Kocyigit10-Feb-11 1:42
Okan Kocyigit10-Feb-11 1:42 
GeneralRe: Cool I did snakes a while back too, fun isn't it Pin
Sacha Barber11-Feb-11 3:14
Sacha Barber11-Feb-11 3:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.