锋利的C#

  程序员博客 :: 首页 :: 新随笔 :: 订阅 :: 管理 :: 登录 ::
访问csharp的空间

随笔分类

随笔归档

个人相册

阅读排行榜

评论排行榜

最新评论

csharp 阅读(1988) 评论(1)

作者:Okan Kocyigit

下载源代码:外链网址已屏蔽www.okbase.net/file/item/22192

介绍

是的,又是一个蛇游戏,你觉得有点无聊吗?你一定见到过用不同语言创建的蛇游戏,但你可曾见过用键盘和游戏操纵杆(joystick)都能控制的蛇游戏呢?没错,这就是其它蛇游戏与Engerek之间的区别。

通过操纵杆控制游戏:Microsoft.Directx.DirectInput
游戏画面: System.Drawing*
游戏声音: System.Media

需要指出的是这是我的第一个项目,也许编码质量并不好,我接受您的所有建议。




好了,现在让我们看看代码吧,项目中的文件及路径如下:

MyGame.cs 主form.
Game.cs 游戏的主类,包含了所有蛇的属性。
Joystick.cs 操纵杆类 (Directx.DirectInput).
LinkedList.cs 存储蛇的节点的列表类。
/sounds 包含声音文件
/fonts 包含字体文件
/pictures 包含位图文件

如果想启用声音,你必须将"menu.wav", "eated.wav" 和"gameover.wav" 声音文件放到"/sounds/"目录下,文件尺寸的关系,在源码包里并没有放这几个文件。

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, 这意味着轴按钮(axis button)可以从最大的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)

如果你无法理解,可以看这些文章:
1)C#的手柄接口
2)C++中使用XInput实现Xbox 360控制器输入
3)创建DirectInput 设备对象

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
简单地说,我们有一个form。form里有一个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库。感谢您的阅读。


评论列表
sharpme
c#开发小游戏可以玩玩,稍大的游戏是不是存在性能问题?

发表评论
切换编辑模式