夜光序言:
凡事都有前因后果,笨鸟为什么先飞?缘于坚持不懈,勤奋练习;江郎为什么才尽?只因得意忘形,终日饱食。种豆得豆,种瓜得瓜,因果报应,环环相扣。
正文:
贪吃蛇完整的
-- 夜光项目代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 测试1
{
//夜光:定义一个方向
//枚举值类型
enum Direction
{
Left,
Right,
Up,
Down,
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 测试1
{
class Snake
{
//下面我们建立一个单例
private static Snake instance = null;
public static Snake Instance()
{
if (instance == null)
{
instance = new Snake();
}
return instance;
}
//这里,我们需要定义一个蛇的每一节
//用泛型数组
//一开始就把蛇的身体给创建出来
List<Point> body = new List<Point>();
//把蛇的方向给设置好
Direction dir = Direction.Right;
Point tail; //定义一个尾部,默认值就是(0,0)
/// <summary>
/// 用于做数据初始化
/// </summary>
public void Start()
{
//之前我们学过构造函数的吧
//。。靓仔,写一下
body.Add(new Point(4,2));
body.Add(new Point(3,2));
body.Add(new Point(2,2));
}
//判断游戏是否结束
//肯定是布尔类型
//判断依据
//1.蛇头是否撞上墙
//2.蛇头是否触碰到自己身体
private bool IsGameOver()
{
/* //我们可以抛出一个异常
throw new NotImplementedException();*/
Point head = body[0]; //蛇头的坐标
//1.蛇头是否撞上墙
if (Map.Instance().GetAt(head) == Map.Wall)
return true;
//2.蛇头是否触碰到自己身体
for(int i = 1; i < body.Count; i++)
{
if(body[i] == head)
{
return true;
}
}
return false;
}
/// <summary>
/// 夜光:处理转向判断
/// 注意:只能往蛇的前进方向的侧方向
/// 1.获取按键输入
/// 2.判定是否可以移动
/// 3.改变dir
/// </summary>
private void Turn()
{
//1.获取按键输入
if (Console.KeyAvailable)
{
ConsoleKey key = Console.ReadKey(true).Key;
//2.判定是否可以移动
if(key == ConsoleKey.LeftArrow && dir != Direction.Right)
{
dir = Direction.Left;
}
else if(key == ConsoleKey.RightArrow && dir != Direction.Left)
{
dir = Direction.Right;
}
else if (key == ConsoleKey.UpArrow && dir != Direction.Down)
{
dir = Direction.Up;
}
else if (key == ConsoleKey.DownArrow && dir != Direction.Up)
{
dir = Direction.Down;
}
}
}
/// <summary>
/// 根据蛇的移动方向dir,在地图上前行
/// </summary>
private void Move()
{
Point offset = new Point(0,0); //我们定义一个偏移的变量
//并且给他一个默认值
//夜光:我们switch一下
switch (dir)
{
case Direction.Left:
offset = new Point(-1, 0);
break;
case Direction.Right:
offset = new Point(1, 0);
break;
case Direction.Up:
offset = new Point(0, -1);
break;
case Direction.Down:
offset = new Point(0, 1);
break;
}
Point head = body[0]; //夜光(2,4)第二列第四行
// head += offset 至于怎么写,后面再说
head = head + offset;//(2,4)+(1,0) 需要写一个加运算符的重载
//夜光:插入元素
body.Insert(0, head); //插入头部
tail = body[body.Count -1]; // 增加蛇的身体
//数组减1的位置
body.RemoveAt(body.Count - 1); //删除尾巴,操作
}
/// <summary>
/// 判定蛇头位置是否有食物,如果有,则
/// 1.在地图上删除该位置的食物
/// 2.蛇的身体增加一节
/// 3.重新生成一个食物
/// </summary>
private void Eat()
{
Point head = body[0]; //我们先把蛇头位置给取出来
if(Map.Instance().GetAt(head) == Map.Food)
{
// 1.在地图上删除该位置的食物
//设置成一个空地,blank
Map.Instance().SetAt(head, Map.Blank);
// 2.蛇的身体增加一节(尾部不删除,换个思路)
body.Add(tail);
// 3.重新生成一个食物
Map.Instance().GenFood(); //直接调用这个生成食物的方法
}
}
public void Update()
{
if (IsGameOver())
return;
Turn();
Move();
Eat();
}
public void Draw()
{
for (int i=0;i<body.Count;i++)
{
//先把蛇的身体给保存下来
Point pt = body[i];
Console.SetCursorPosition(pt.x * 2, pt.y);//一个是中文格子,一个是英文格子,所以需要乘以2
//关于颜色的设置
//此处给蛇头一个单独的红色
//夜光
Console.ForegroundColor = i == 0 ? ConsoleColor.Red:ConsoleColor.Yellow;//此处设定一个判断,头部和尾部的不同颜色
//Console.BackgroundColor = ConsoleColor.Red;
//只有中文的空格,长宽才是一样的
Console.Write("●");
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 测试1
{
//我们希望s2 = s1 赋值的时候
//是把s1的内容(x,y)拷贝给s2(x,y)
//而非让s2和s1指向同一块内存
struct Point
{
public int x;
public int y;
public Point(int x, int y)
{
//学编程,明白this指向当前上方的int x
this.x = x; //把局部变量x 赋值给成员变量x
this.y = y;
}
//+运算符重载
public static Point operator +(Point p1, Point p2)
{
return new Point(p1.x + p2.x, p1.y + p2.y);
}
//-运算符重载
public static bool operator==(Point p1, Point p2)
{
return p1.x == p2.x && p1.y == p2.y;
}
//取反一下,试试
public static bool operator !=(Point p1, Point p2)
{
return !(p1 == p2);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 测试1
{ //夜光
//这个是地图类,主要用来绘制贪吃蛇地图
class Map
{
//下面我们建立一个单例
private static Map instance = null;
public static Map Instance()
{
if(instance == null)
{
instance = new Map();
}
return instance;
}
/// <summary>
/// 地图块类型
/// </summary>
/* enum TileType 想了想,做成枚举值,太麻烦,还是做成常量
{
Blank,
Wall,
Food,
}*/
public const int Blank = 0;
public const int Wall = 1;
public const int Food = 2;
private int[,] map = null; //夜光:设计思想
//设置成私有的
/// <summary>
/// 为了生成食物,定义的一个随机数
/// </summary>
private Random rnd = new Random();
public int GetAt(Point pt)
{
return map[pt.y,pt.x];
}
/// <summary>
/// 写一个让食物消失的方法
/// 没有返回值,是设定
/// </summary>
/// <param name="pt"></param>
public void SetAt(Point pt,int value)
{
map[pt.y, pt.x] = value;
}
//我们写一个生成食物的方法
//夜光:写在map类里面
/// <summary>
/// 规则:
/// 1.只能在空地上生成
/// 2.不可以在蛇的身体上生成(这个暂时不需要~~)
/// </summary>
public void GenFood()
{
Point pt;
for(; ; )
{
//这就是死循环,那么什么时候退出呢
//x和y的生成
pt.x = rnd.Next(map.GetLength(1));
pt.y = rnd.Next(map.GetLength(0));
//下面就是判断
if(GetAt(pt) == Map.Blank)
{
map[pt.y, pt.x] = Map.Food;
return;
}
}
}
/// <summary>
/// 用于做数据初始化
/// </summary>
public void Start()
{
//边缘一圈是墙
map = new int[20, 20]
{
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
};
GenFood();
}
/// <summary>
/// 存放逻辑处理(数据运算)
/// </summary>
public void Update()
{
/* //抛出异常
throw new NotImplementedException(); //未实现的异常*/
}
/// <summary>
/// 图形绘制
/// </summary>
public void Draw()
{
for(int i = 0;i < map.GetLength(0); i++) //行
{
for(int j=0;j< map.GetLength(1); j++) //列
{
Console.SetCursorPosition(j*2,i);
//关于颜色的设置
//前景色和背景色
//Console.ForegroundColor = ConsoleColor.Yellow;
switch (map[i, j])
{
case Map.Wall:
Console.BackgroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.Gray;
//只有中文的空格,长宽才是一样的
Console.Write(" ");
break;
case Map.Food:
Console.BackgroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.DarkCyan;
//只有中文的空格,长宽才是一样的
Console.Write("●");
break;
case Map.Blank:
Console.BackgroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.DarkCyan;
//只有中文的空格,长宽才是一样的
Console.Write(" ");
break;
}
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 测试1
{
class Program
{
static void Main(string[] args)
{
//夜光:我们做一个贪吃蛇的游戏
//首先,根据单例,初始化两个
Snake.Instance().Start();
Map.Instance().Start();
//之后写一个for循环
for(; ; )
{
//为什么晃得很厉害
//一帧(frame)画面
Snake.Instance().Update();
Map.Instance().Update();
Map.Instance().Draw(); //先画地图再画蛇
Snake.Instance().Draw();
//针对之前的闪烁问题
//我们可以使用休眠的方式来缓解
Thread.Sleep(100);
}
}
}
}