Click here to Skip to main content
Click here to Skip to main content

A Simple Snake Game: Engerek

, 9 Feb 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
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.cs This is our main form.
Game.cs This is the main game class. It includes all snake's properties.
Joystick.cs This one includes joystick class (Directx.DirectInput).
LinkedList.cs Includes linked list class that is used for storing snake nodes.
/sounds Includes sound files *
/fonts Includes font files
/pictures Includes 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.

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:

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.

//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:

/*********************** 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)

Share

About the Author

Okan Kocyigit

Turkey Turkey
No Biography provided

Comments and Discussions

 
GeneralMy vote of 3 PinmemberAnas Tasadduq31-May-14 7:50 
GeneralMy vote of 1 PinmemberAnas Tasadduq31-May-14 7:49 
GeneralAwesome Pinmemberbilal7869929-Mar-13 10:15 
BugLoaderLock was detected? Pinmembersupernorb26-Mar-13 4:05 
GeneralRe: LoaderLock was detected? Pinmembercoolprarun28-Aug-13 22:24 
GeneralRe: LoaderLock was detected? PinmemberMember 102626039-Sep-13 9:57 
GeneralMy vote of 5 Pinmembergeekbond15-Oct-12 5:15 
GeneralMy vote of 5 PinmemberReza Ahmadi17-May-12 1:54 
GeneralMy vote of 5 PinmemberHimanshu R Sachdeva12-Jan-12 4:41 
GeneralMy vote of 5 PinmemberReelix23-Feb-11 1:24 
QuestionXNA? PinmemberReelix23-Feb-11 1:23 
AnswerRe: XNA? PinmemberOkan Kocyigit23-Feb-11 2:00 
GeneralCool I did snakes a while back too, fun isn't it PinmvpSacha Barber9-Feb-11 22:32 
GeneralRe: Cool I did snakes a while back too, fun isn't it Pinmemberocanal10-Feb-11 2:42 
GeneralRe: Cool I did snakes a while back too, fun isn't it PinmvpSacha Barber11-Feb-11 4:14 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 9 Feb 2011
Article Copyright 2011 by Okan Kocyigit
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid