[源码下载]
作者: webabcd
介绍
使用 Silverlight 3.0(c#) 开发一个贪吃蛇游戏
玩法
W/S/A/D 或 ↑/↓/←/→ 控制蛇的移动
在线DEMO
思路
1、贪吃蛇的每一段为 16×16 像素,场景为 640×480 像素,也就说网格为 40×30 个,每个网格的边长为 16
2、食物的出现位置以及贪吃蛇的运动方向的改变都要在相关的网格内进行
3、贪吃蛇的运动用即时运算的方法计算,当贪吃蛇运动到网格内(蛇某一段的像素位置%网格的边长<蛇在某时间单位下的移动偏移量)时做如下工作:修正蛇的位置使其正好在网格内,更新蛇的每一段的运动方向,判断是否吃到了食物、是否发生了碰撞等
4、贪吃蛇的每一段的运动方向的修改:蛇头的运动方向根据用户的操作改变,蛇的每一段的运动方向设置为此段的前一段的运动方向(计算时要从尾部向头部逐段计算)(注:运动方向的改变要在蛇移动到网格内时进行。其中如果蛇的某一段移动到了网格内,则表明其它各段都在网格内)
关键代码
游戏人生Silverlight(6) - 贪吃蛇[Silverlight 3.0(c#)]
作者: webabcd
介绍
使用 Silverlight 3.0(c#) 开发一个贪吃蛇游戏
玩法
W/S/A/D 或 ↑/↓/←/→ 控制蛇的移动
在线DEMO
思路
1、贪吃蛇的每一段为 16×16 像素,场景为 640×480 像素,也就说网格为 40×30 个,每个网格的边长为 16
2、食物的出现位置以及贪吃蛇的运动方向的改变都要在相关的网格内进行
3、贪吃蛇的运动用即时运算的方法计算,当贪吃蛇运动到网格内(蛇某一段的像素位置%网格的边长<蛇在某时间单位下的移动偏移量)时做如下工作:修正蛇的位置使其正好在网格内,更新蛇的每一段的运动方向,判断是否吃到了食物、是否发生了碰撞等
4、贪吃蛇的每一段的运动方向的修改:蛇头的运动方向根据用户的操作改变,蛇的每一段的运动方向设置为此段的前一段的运动方向(计算时要从尾部向头部逐段计算)(注:运动方向的改变要在蛇移动到网格内时进行。其中如果蛇的某一段移动到了网格内,则表明其它各段都在网格内)
关键代码
/*
* 游戏的核心算法
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using System.Threading;
namespace YYSnake.Core
{
public partial class Main : UserControl
{
private int _columns; // 网格列数
private int _rows; // 网格行数
private Dictionary<Body, CellPoint> _bodies = new Dictionary<Body, CellPoint>(); // 贪吃蛇每一段的集合
private Dictionary<Bean, CellPoint> _beans = new Dictionary<Bean, CellPoint>(); // 豆的集合
private Dictionary<Skin, CellPoint> _skins = new Dictionary<Skin, CellPoint>(); // 蜕下来的皮的集合
private List<CellPoint> _emptyCells = new List<CellPoint>(); // 空网格的集合
private bool _enabled = false; // 游戏是否运行
private double _dt = 0.01; // 多少毫秒计算一次
private int _decimals = 1; // 计算小数时所保留的小数位
private double _speed = 80; // 蛇的运行速度
private Direction _moveDirection = Direction.Up; // 蛇的运行方向
private int _selfLength = 5; // 蛇的最小长度
private int _beansCount = 5; // 豆的最大出现数量
private int _ateCapacity = 10; // 食量(超过则蜕皮)
private bool _needRaiseAteEvent = false; // 在“蛇头所处位置进入了网格点区域内”时是否需要触发吃豆事件
private int _needBeansCount = 0; // 还需要增加的豆的数量
Random _random = new Random();
public Main()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Main_Loaded);
}
void Main_Loaded( object sender, RoutedEventArgs e)
{
this.Width = App.Width; // 640
this.Height = App.Height; // 480
_columns = ( int)(Width / App.CellSize); // 40
_rows = ( int)(Height / App.CellSize); // 30
// 防止动画飞出去
RectangleGeometry rg = new RectangleGeometry();
rg.Rect = new Rect(0, 0, App.Width, App.Height);
LayoutRoot.Clip = rg;
bg.Width = App.Width;
bg.Height = App.Height;
ripple.RippleBackground = bg;
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
_enabled = false;
canvasBean.Children.Clear();
canvasSnake.Children.Clear();
canvasSkin.Children.Clear();
_beans.Clear();
_bodies.Clear();
_skins.Clear();
_emptyCells.Clear();
for ( int i = 0; i < _columns; i++)
{
for ( int j = 0; j < _rows; j++)
{
_emptyCells.Add( new CellPoint(i, j));
}
}
_moveDirection = Direction.Up;
InitSnake();
}
/// <summary>
/// 蛇的初始化
/// </summary>
private void InitSnake()
{
InitHead();
for ( int i = 0; i < _selfLength - 1; i++)
AddTail();
for ( int i = 0; i < _beansCount; i++)
AddBean();
}
/// <summary>
/// 蛇头的初始化
/// </summary>
private void InitHead()
{
Body head = new Body(BodyType.Head);
head.MoveDirection = _moveDirection;
CellPoint point = new CellPoint(( int)(_columns / 2), ( int)(_rows / 2));
head.SetValue(Canvas.LeftProperty, point.X * App.CellSize);
head.SetValue(Canvas.TopProperty, point.Y * App.CellSize);
_bodies.Add(head, point);
canvasSnake.Children.Add(head);
}
/// <summary>
/// 增加一个尾巴
/// </summary>
private void AddTail()
{
var prevBody = _bodies.Last().Key;
var prevBodyPoint = _bodies.Last().Value;
Body tail = new Body(BodyType.Tail);
tail.MoveDirection = prevBody.MoveDirection;
CellPoint tailPoint = new CellPoint(prevBodyPoint.X, prevBodyPoint.Y);
switch (prevBody.MoveDirection)
{
case Direction.Up:
tail.SetValue(Canvas.LeftProperty, ( double)prevBody.GetValue(Canvas.LeftProperty));
tail.SetValue(Canvas.TopProperty, ( double)prevBody.GetValue(Canvas.TopProperty) + App.CellSize);
tailPoint.Y++;
break;
case Direction.Down:
tail.SetValue(Canvas.LeftProperty, ( double)prevBody.GetValue(Canvas.LeftProperty));
tail.SetValue(Canvas.TopProperty, ( double)prevBody.GetValue(Canvas.TopProperty) - App.CellSize);
tailPoint.Y--;
break;
case Direction.Left:
tail.SetValue(Canvas.LeftProperty, ( double)prevBody.GetValue(Canvas.LeftProperty) + App.CellSize);
tail.SetValue(Canvas.TopProperty, ( double)prevBody.GetValue(Canvas.TopProperty));
tailPoint.X++;
break;
case Direction.Right:
tail.SetValue(Canvas.LeftProperty, ( double)prevBody.GetValue(Canvas.LeftProperty) - App.CellSize);
tail.SetValue(Canvas.TopProperty, ( double)prevBody.GetValue(Canvas.TopProperty));
tailPoint.X--;
break;
}
tailPoint = CorrectCellPoint(tailPoint);
_bodies.Add(tail, tailPoint);
canvasSnake.Children.Add(tail);
}
/// <summary>
/// 增加一个豆
/// </summary>
private void AddBean()
{
if (_needBeansCount < _beansCount)
_needBeansCount++;
}
private DateTime _prevAddBeanDateTime = DateTime.Now;
* 游戏的核心算法
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using System.Threading;
namespace YYSnake.Core
{
public partial class Main : UserControl
{
private int _columns; // 网格列数
private int _rows; // 网格行数
private Dictionary<Body, CellPoint> _bodies = new Dictionary<Body, CellPoint>(); // 贪吃蛇每一段的集合
private Dictionary<Bean, CellPoint> _beans = new Dictionary<Bean, CellPoint>(); // 豆的集合
private Dictionary<Skin, CellPoint> _skins = new Dictionary<Skin, CellPoint>(); // 蜕下来的皮的集合
private List<CellPoint> _emptyCells = new List<CellPoint>(); // 空网格的集合
private bool _enabled = false; // 游戏是否运行
private double _dt = 0.01; // 多少毫秒计算一次
private int _decimals = 1; // 计算小数时所保留的小数位
private double _speed = 80; // 蛇的运行速度
private Direction _moveDirection = Direction.Up; // 蛇的运行方向
private int _selfLength = 5; // 蛇的最小长度
private int _beansCount = 5; // 豆的最大出现数量
private int _ateCapacity = 10; // 食量(超过则蜕皮)
private bool _needRaiseAteEvent = false; // 在“蛇头所处位置进入了网格点区域内”时是否需要触发吃豆事件
private int _needBeansCount = 0; // 还需要增加的豆的数量
Random _random = new Random();
public Main()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Main_Loaded);
}
void Main_Loaded( object sender, RoutedEventArgs e)
{
this.Width = App.Width; // 640
this.Height = App.Height; // 480
_columns = ( int)(Width / App.CellSize); // 40
_rows = ( int)(Height / App.CellSize); // 30
// 防止动画飞出去
RectangleGeometry rg = new RectangleGeometry();
rg.Rect = new Rect(0, 0, App.Width, App.Height);
LayoutRoot.Clip = rg;
bg.Width = App.Width;
bg.Height = App.Height;
ripple.RippleBackground = bg;
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
_enabled = false;
canvasBean.Children.Clear();
canvasSnake.Children.Clear();
canvasSkin.Children.Clear();
_beans.Clear();
_bodies.Clear();
_skins.Clear();
_emptyCells.Clear();
for ( int i = 0; i < _columns; i++)
{
for ( int j = 0; j < _rows; j++)
{
_emptyCells.Add( new CellPoint(i, j));
}
}
_moveDirection = Direction.Up;
InitSnake();
}
/// <summary>
/// 蛇的初始化
/// </summary>
private void InitSnake()
{
InitHead();
for ( int i = 0; i < _selfLength - 1; i++)
AddTail();
for ( int i = 0; i < _beansCount; i++)
AddBean();
}
/// <summary>
/// 蛇头的初始化
/// </summary>
private void InitHead()
{
Body head = new Body(BodyType.Head);
head.MoveDirection = _moveDirection;
CellPoint point = new CellPoint(( int)(_columns / 2), ( int)(_rows / 2));
head.SetValue(Canvas.LeftProperty, point.X * App.CellSize);
head.SetValue(Canvas.TopProperty, point.Y * App.CellSize);
_bodies.Add(head, point);
canvasSnake.Children.Add(head);
}
/// <summary>
/// 增加一个尾巴
/// </summary>
private void AddTail()
{
var prevBody = _bodies.Last().Key;
var prevBodyPoint = _bodies.Last().Value;
Body tail = new Body(BodyType.Tail);
tail.MoveDirection = prevBody.MoveDirection;
CellPoint tailPoint = new CellPoint(prevBodyPoint.X, prevBodyPoint.Y);
switch (prevBody.MoveDirection)
{
case Direction.Up:
tail.SetValue(Canvas.LeftProperty, ( double)prevBody.GetValue(Canvas.LeftProperty));
tail.SetValue(Canvas.TopProperty, ( double)prevBody.GetValue(Canvas.TopProperty) + App.CellSize);
tailPoint.Y++;
break;
case Direction.Down:
tail.SetValue(Canvas.LeftProperty, ( double)prevBody.GetValue(Canvas.LeftProperty));
tail.SetValue(Canvas.TopProperty, ( double)prevBody.GetValue(Canvas.TopProperty) - App.CellSize);
tailPoint.Y--;
break;
case Direction.Left:
tail.SetValue(Canvas.LeftProperty, ( double)prevBody.GetValue(Canvas.LeftProperty) + App.CellSize);
tail.SetValue(Canvas.TopProperty, ( double)prevBody.GetValue(Canvas.TopProperty));
tailPoint.X++;
break;
case Direction.Right:
tail.SetValue(Canvas.LeftProperty, ( double)prevBody.GetValue(Canvas.LeftProperty) - App.CellSize);
tail.SetValue(Canvas.TopProperty, ( double)prevBody.GetValue(Canvas.TopProperty));
tailPoint.X--;
break;
}
tailPoint = CorrectCellPoint(tailPoint);
_bodies.Add(tail, tailPoint);
canvasSnake.Children.Add(tail);
}
/// <summary>
/// 增加一个豆
/// </summary>
private void AddBean()
{
if (_needBeansCount < _beansCount)
_needBeansCount++;
}
private DateTime _prevAddBeanDateTime = DateTime.Now;
本文转自webabcd 51CTO博客,原文链接:http://blog.51cto.com/webabcd/345618
,如需转载请自行联系原作者