游戲人生Silverlight:貪吃蛇
介紹
使用 Silverlight 3.0(c#) 開(kāi)發(fā)一個(gè)貪吃蛇游戲
玩法
W/S/A/D 或 ↑/↓/←/→ 控制蛇的移動(dòng)
截圖

思路
1、貪吃蛇的每一段為 16×16 像素,場(chǎng)景為 640×480 像素,也就說(shuō)網(wǎng)格為 40×30 個(gè),每個(gè)網(wǎng)格的邊長(zhǎng)為 16
2、食物的出現(xiàn)位置以及貪吃蛇的運(yùn)動(dòng)方向的改變都要在相關(guān)的網(wǎng)格內(nèi)進(jìn)行
3、貪吃蛇的運(yùn)動(dòng)用即時(shí)運(yùn)算的方法計(jì)算,當(dāng)貪吃蛇運(yùn)動(dòng)到網(wǎng)格內(nèi)(蛇某一段的像素位置%網(wǎng)格的邊長(zhǎng)<蛇在某時(shí)間單位下的移動(dòng)偏移量)時(shí)做如下工作:修正蛇的位置使其正好在網(wǎng)格內(nèi),更新蛇的每一段的運(yùn)動(dòng)方向,判斷是否吃到了食物、是否發(fā)生了碰撞等
4、貪吃蛇的每一段的運(yùn)動(dòng)方向的修改:蛇頭的運(yùn)動(dòng)方向根據(jù)用戶的操作改變,蛇的每一段的運(yùn)動(dòng)方向設(shè)置為此段的前一段的運(yùn)動(dòng)方向(計(jì)算時(shí)要從尾部向頭部逐段計(jì)算)(注:運(yùn)動(dòng)方向的改變要在蛇移動(dòng)到網(wǎng)格內(nèi)時(shí)進(jìn)行。其中如果蛇的某一段移動(dòng)到了網(wǎng)格內(nèi),則表明其它各段都在網(wǎng)格內(nèi))
下面我們看看他的關(guān)鍵代碼都有哪些。
#p#
關(guān)鍵代碼
- 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; // 網(wǎng)格列數(shù)
 - private int _rows; // 網(wǎng)格行數(shù)
 - 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>(); // 蛻下來(lái)的皮的集合
 - private List<CellPoint> _emptyCells = new List<CellPoint>(); // 空網(wǎng)格的集合
 - private bool _enabled = false; // 游戲是否運(yùn)行
 - private double _dt = 0.01; // 多少毫秒計(jì)算一次
 - private int _decimals = 1; // 計(jì)算小數(shù)時(shí)所保留的小數(shù)位
 - private double _speed = 80; // 蛇的運(yùn)行速度
 - private Direction _moveDirection = Direction.Up; // 蛇的運(yùn)行方向
 - private int _selfLength = 5; // 蛇的最小長(zhǎng)度
 - private int _beansCount = 5; // 豆的***出現(xiàn)數(shù)量
 - private int _ateCapacity = 10; // 食量(超過(guò)則蛻皮)
 - private bool _needRaiseAteEvent = false; // 在“蛇頭所處位置進(jìn)入了網(wǎng)格點(diǎn)區(qū)域內(nèi)”時(shí)是否需要觸發(fā)吃豆事件
 - private int _needBeansCount = 0; // 還需要增加的豆的數(shù)量
 - 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
 - // 防止動(dòng)畫(huà)飛出去
 - 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>
 - /// 增加一個(gè)尾巴
 - /// </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>
 - /// 增加一個(gè)豆
 - /// </summary>
 - private void AddBean()
 - {
 - if (_needBeansCount < _beansCount)
 - _needBeansCount++;
 - }
 - private DateTime _prevAddBeanDateTime = DateTime.Now;
 - /// <summary>
 - /// 生成豆
 - /// </summary>
 - void UpdateBean()
 - {
 - if (_needBeansCount > 0 && (DateTime.Now - _prevAddBeanDateTime).TotalSeconds > 3)
 - {
 - List<CellPoint> emptyCells = GetEmptyCells();
 - if (emptyCells.Count == 0)
 - {
 - GameOver(this, EventArgs.Empty);
 - return;
 - }
 - CellPoint point = emptyCells[_random.Next(0, emptyCells.Count)];
 - Bean bean = new Bean();
 - bean.SetValue(Canvas.LeftProperty, point.X * App.CellSize);
 - bean.SetValue(Canvas.TopProperty, point.Y * App.CellSize);
 - _beans.Add(bean, point);
 - canvasBean.Children.Add(bean);
 - bean.ani.Completed += delegate
 - {
 - ripple.ShowRipple(new Point(point.X * App.CellSize + App.CellSize / 2, point.Y * App.CellSize + App.CellSize / 2));
 - player.PlayDrop();
 - };
 - _needBeansCount--;
 - _prevAddBeanDateTime = DateTime.Now;
 - }
 - }
 - private DateTime _prevDateTime = DateTime.Now;
 - private double _leftoverLength = 0d;
 - void CompositionTarget_Rendering(object sender, EventArgs e)
 - {
 - double length = (DateTime.Now - _prevDateTime).TotalSeconds + _leftoverLength;
 - while (length > _dt)
 - {
 - Update();
 - length -= _dt;
 - }
 - _leftoverLength = length;
 - _prevDateTime = DateTime.Now;
 - }
 - /// <summary>
 - /// 即時(shí)計(jì)算
 - /// </summary>
 - private void Update()
 - {
 - if (!_enabled)
 - return;
 - double offset = Math.Round(_speed * _dt, _decimals);
 - // 蛇頭所處位置進(jìn)入了網(wǎng)格點(diǎn)區(qū)域內(nèi)
 - if (Math.Abs(Math.Round((double)_bodies.First().Key.GetValue(Canvas.TopProperty) % App.CellSize, _decimals)) < offset && Math.Abs(Math.Round((double)_bodies.First().Key.GetValue(Canvas.LeftProperty) % App.CellSize, _decimals)) < offset)
 - {
 - UpdateDirection();
 - CorrectPosition();
 - UpdateBodyCell();
 - CheckEat();
 - CheckSkin();
 - CheckCollision();
 - UpdateBean();
 - if (_needRaiseAteEvent)
 - {
 - Ate(this.Ate, EventArgs.Empty);
 - _needRaiseAteEvent = false;
 - }
 - }
 - UpdatePosition();
 - }
 - /// <summary>
 - /// 蛻皮
 - /// </summary>
 - private void CheckSkin()
 - {
 - if (_bodies.Count >= _ateCapacity + _selfLength)
 - AddSkin(_ateCapacity);
 - }
 - /// <summary>
 - /// 碰撞檢測(cè)
 - /// </summary>
 - private void CheckCollision()
 - {
 - if (_skins.Any(p => p.Value == _bodies.First().Value) || _bodies.Where(p => p.Key.BodyType == BodyType.Tail).Any(p => p.Value == _bodies.First().Value))
 - {
 - _enabled = false;
 - player.PlayOver();
 - GameOver(this, EventArgs.Empty);
 - }
 - }
 - /// <summary>
 - /// 吃豆
 - /// </summary>
 - private void CheckEat()
 - {
 - // 是否有被吃的豆
 - var bean = _beans.FirstOrDefault(p => p.Value == _bodies.First().Value).Key;
 - if (bean != null)
 - {
 - _beans.Remove(bean);
 - canvasBean.Children.Remove(bean);
 - player.PlayEat();
 - AddTail();
 - AddBean();
 - _needRaiseAteEvent = true;
 - }
 - }
 - /// <summary>
 - /// 更新蛇的每一段的運(yùn)動(dòng)方向
 - /// </summary>
 - private void UpdateDirection()
 - {
 - for (int i = _bodies.Count - 1; i > -1; i--)
 - {
 - if (i == 0)
 - _bodies.ElementAt(i).Key.MoveDirection = _moveDirection;
 - else
 - _bodies.ElementAt(i).Key.MoveDirection = _bodies.ElementAt(i - 1).Key.MoveDirection;
 - }
 - }
 - /// <summary>
 - /// 更新蛇的每一段的位置
 - /// </summary>
 - private void UpdatePosition()
 - {
 - double offset = Math.Round(_speed * _dt, _decimals);
 - foreach (var body in _bodies.Keys)
 - {
 - if (body.MoveDirection == Direction.Up)
 - body.SetValue(Canvas.TopProperty, Math.Round((double)body.GetValue(Canvas.TopProperty) - offset, _decimals));
 - else if (body.MoveDirection == Direction.Down)
 - body.SetValue(Canvas.TopProperty, Math.Round((double)body.GetValue(Canvas.TopProperty) + offset, _decimals));
 - else if (body.MoveDirection == Direction.Left)
 - body.SetValue(Canvas.LeftProperty, Math.Round((double)body.GetValue(Canvas.LeftProperty) - offset, _decimals));
 - else if (body.MoveDirection == Direction.Right)
 - body.SetValue(Canvas.LeftProperty, Math.Round((double)body.GetValue(Canvas.LeftProperty) + offset, _decimals));
 - }
 - }
 - /// <summary>
 - /// 蛻指定數(shù)量的皮
 - /// </summary>
 - private void AddSkin(int count)
 - {
 - player.PlaySkin();
 - while (count > 0)
 - {
 - KeyValuePair<Body, CellPoint> body = _bodies.ElementAt(_bodies.Count - 1);
 - CellPoint skinPoint = body.Value;
 - Skin skin = new Skin();
 - skin.SetValue(Canvas.LeftProperty, skinPoint.X * App.CellSize);
 - skin.SetValue(Canvas.TopProperty, skinPoint.Y * App.CellSize);
 - _skins.Add(skin, skinPoint);
 - canvasSkin.Children.Add(skin);
 - _emptyCells.Remove(skinPoint);
 - canvasSnake.Children.Remove(body.Key);
 - _bodies.Remove(body.Key);
 - count--;
 - }
 - }
 - #region 輔助方法
 - /// <summary>
 - /// 修正指定的位置信息為整數(shù)
 - /// </summary>
 - private int CorrectPosition(double position)
 - {
 - double result;
 - double offset = Math.Round(_speed * _dt, _decimals);
 - double temp = Math.Round(position % App.CellSize, _decimals);
 - if (Math.Abs(temp) < offset)
 - result = Math.Round(position - temp);
 - else
 - result = Math.Round(position - temp) + Math.Sign(temp) * App.CellSize;
 - return (int)result;
 - }
 - /// <summary>
 - /// 修正蛇的每一段的位置為整數(shù)
 - /// </summary>
 - private void CorrectPosition()
 - {
 - foreach (Body body in _bodies.Keys)
 - {
 - double x = CorrectPosition((double)body.GetValue(Canvas.LeftProperty));
 - double y = CorrectPosition((double)body.GetValue(Canvas.TopProperty));
 - if (x == App.Width)
 - x = 0d;
 - else if (x == -App.CellSize)
 - x = App.Width - App.CellSize;
 - else if (y == App.Height)
 - y = 0d;
 - else if (y == -App.CellSize)
 - y = App.Height - App.CellSize;
 - body.SetValue(Canvas.LeftProperty, x);
 - body.SetValue(Canvas.TopProperty, y);
 - }
 - }
 - /// <summary>
 - /// 更新蛇的每一段的網(wǎng)格位置信息
 - /// </summary>
 - private void UpdateBodyCell()
 - {
 - for (int i = 0; i < _bodies.Count; i++)
 - {
 - UpdateBodyCell(_bodies.ElementAt(i).Key);
 - }
 - }
 - /// <summary>
 - /// 更新指定的 Body 的網(wǎng)格位置信息
 - /// </summary>
 - private void UpdateBodyCell(Body body)
 - {
 - CellPoint point = new CellPoint((int)((double)body.GetValue(Canvas.LeftProperty) / App.CellSize), (int)((double)body.GetValue(Canvas.TopProperty) / App.CellSize));
 - if (body.MoveDirection == Direction.Up)
 - point.Y--;
 - else if (body.MoveDirection == Direction.Down)
 - point.Y++;
 - else if (body.MoveDirection == Direction.Left)
 - point.X--;
 - else if (body.MoveDirection == Direction.Right)
 - point.X++;
 - point = CorrectCellPoint(point);
 - _bodies[body] = point;
 - }
 - /// <summary>
 - /// 修正網(wǎng)格位置
 - /// </summary>
 - private CellPoint CorrectCellPoint(CellPoint point)
 - {
 - if (point.X > _columns - 1)
 - point.X = _columns - point.X;
 - else if (point.X < 0)
 - point.X = point.X + _columns;
 - if (point.Y > _rows - 1)
 - point.Y = _rows - point.Y;
 - else if (point.Y < 0)
 - point.Y = point.Y + _rows;
 - return point;
 - }
 - /// <summary>
 - /// 獲取空網(wǎng)格集合
 - /// </summary>
 - private List<CellPoint> GetEmptyCells()
 - {
 - List<CellPoint> emptyCells = new List<CellPoint>();
 - List<CellPoint> aroundHeadCells = new List<CellPoint>();
 - CellPoint headPoint = _bodies.First().Value;
 - for (int i = -5; i < 5; i++)
 - {
 - for (int j = -5; j < 5; j++)
 - {
 - CellPoint point = new CellPoint(headPoint.X + i, headPoint.Y + j);
 - point = CorrectCellPoint(point);
 - aroundHeadCells.Add(point);
 - }
 - }
 - // skin 的占位情況因?yàn)榇_定了就不變了,所以在 AddSkin() 處計(jì)算
 - // 為了以下 LINQ 的可用,需要重寫(xiě) CellPoint 的 public override bool Equals(object obj)
 - emptyCells = _emptyCells.Where(p => !_bodies.Select(x => x.Value).Contains(p)).ToList();
 - emptyCells = emptyCells.Where(p => !_beans.Select(x => x.Value).Contains(p)).ToList();
 - emptyCells = emptyCells.Where(p => !aroundHeadCells.Contains(p)).ToList();
 - return emptyCells;
 - }
 - #endregion
 - #region 屬性
 - public Direction MoveDirection
 - {
 - set
 - {
 - Body head = _bodies.First().Key;
 - if (head.MoveDirection == Direction.Up && value == Direction.Down)
 - return;
 - if (head.MoveDirection == Direction.Down && value == Direction.Up)
 - return;
 - if (head.MoveDirection == Direction.Left && value == Direction.Right)
 - return;
 - if (head.MoveDirection == Direction.Right && value == Direction.Left)
 - return;
 - _moveDirection = value;
 - }
 - }
 - public bool Enabled
 - {
 - get { return _enabled; }
 - set { _enabled = value; }
 - }
 - public double Speed
 - {
 - get { return _speed; }
 - set { _speed = value; }
 - }
 - public int AteCapacity
 - {
 - get { return _ateCapacity; }
 - set { _ateCapacity = value; }
 - }
 - #endregion
 - #region 事件 GameOver 和 Ate
 - public event EventHandler GameOver;
 - public event EventHandler Ate;
 - #endregion
 - }
 - }
 
原文鏈接:http://www.cnblogs.com/webabcd/archive/2009/09/14/1566082.html















 
 
 









 
 
 
 