using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 贪吃蛇
{
public partial class Form1 : Form
{
public Point FoodLct = new Point();//存储食物的坐标
public int snakeLen=1;//蛇的长度
public int snakeHead;//蛇头的脚标
public int SnakeMaxLength;
public Point[] snakeArr;//蛇(包含头、身)的坐标
public Point[] snakeArr1;//辅助数组
public int snakeDrt = 0;//用于判断蛇的行进方向
public int[] Drt = new int[2];
public int[] Lct = new int[2];
public Point[] snakeInflcpt;//蛇的拐点坐标
public int Ilen=0;
public bool panDuan = true;//蛇是否吃到食物
public Point[] snakeBase;//蛇的基地边界坐标
public int BaseLen;//基地边界长
public Point[] BasePt;//基地的顶点坐标
public Point[] BasePt1;//待增长的基地顶点坐标
public Point[] snakeBase1;//待增长的基地边界坐标
public Point[] SnakeAtBaseLct = new Point[2];//蛇头触碰基地边界的坐标
public Point[] WallArr = new Point[4];//围墙(蛇的活动范围)
public int n=0;public int m = 0;public int l = 0;
public int i0;public int i1;
public int[] j2= new int[2];public int[] j3 = new int[2];
public Form1()
{
InitializeComponent();
//int temp = 15;
//for (int i=snakeLen-1;i>=0;i--)
//{
// snakeArr[i].X = temp;snakeArr[i].Y = 15;
// temp += 15;
//}
timer1.Start();
}
//画一个小方块
public void DrawShape(int x,int y)
{
Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.DarkKhaki, 2);
g.DrawRectangle(pen, x, y, 15, 15);
g.FillRectangle(Brushes.Green, x, y, 15, 15);
}
//画墙砖
public void DrawWall(int x, int y)
{
Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.DarkKhaki, 2);
g.DrawRectangle(pen, x, y, 15, 15);
g.FillRectangle(Brushes.Gray, x, y, 15, 15);
}
//消除蛇身
public void CutSnake(int x, int y)
{
Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.DarkKhaki, 2);
g.DrawRectangle(pen, x, y, 15, 15);
g.FillRectangle(Brushes.DarkKhaki, x, y, 15, 15);
}
//画食物
public void DrawFood(int x,int y)
{
Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.Red, 2);
SolidBrush brush = new SolidBrush(Color.Green);
g.DrawRectangle(pen, x, y, 15, 15);
g.FillRectangle(brush, x, y, 15, 15);
}
//蛇行进
public void Forward(int drt)
{
Point temp;
if (drt != 0)
{
snakeLen += 1;
snakeHead = snakeLen - 1;
snakeArr1 = new Point[snakeLen];
for (int i = 0; i < snakeArr.Length; i++)
{
snakeArr1[i] = snakeArr[i];
}
snakeArr = new Point[snakeLen];
snakeArr = snakeArr1;
temp = snakeArr[snakeLen - 2];
switch (drt)
{
case 1: snakeArr[snakeHead].X = temp.X; snakeArr[snakeHead].Y = temp.Y - 15; break;//上
case 2: snakeArr[snakeHead].X = temp.X + 15; snakeArr[snakeHead].Y = temp.Y; break;//右
case 3: snakeArr[snakeHead].X = temp.X; snakeArr[snakeHead].Y = temp.Y + 15; break;//下
case 4: snakeArr[snakeHead].X = temp.X - 15; snakeArr[snakeHead].Y = temp.Y; break;//左
}
}
}
//时间事件
private void timer1_Tick(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
//g.Clear(Color.DarkKhaki);//清除整个画面
if(snakeDrt != 0)
{
m = m + 1;if (m == 1000) m = 0;
if (m % 2 == 1) { Drt[0] = snakeDrt; }
else Drt[1] = snakeDrt;
if(Drt[0]!=0 && Drt[1]!=0 && Drt[0]!=Drt[1])//前后两次按下的方向键不同
{
//前后两次按下的方向键不是正好相反的如"←"和"→","↑"和"↓"
if ((Drt[0] == 1 && Drt[1] == 3) || (Drt[1] == 1 && Drt[0] == 3) || (Drt[0] == 2 && Drt[1] == 4) || (Drt[1] == 2 && Drt[0] == 4)) ;
else
{
Ilen += 1;
if (Ilen == 1) { snakeInflcpt = new Point[Ilen]; snakeInflcpt[Ilen - 1] = snakeArr[snakeHead]; }
else
{
snakeArr1 = new Point[Ilen];
for (int i = 0; i < snakeInflcpt.Length; i++)
{
snakeArr1[i] = snakeInflcpt[i];
}
snakeArr1[Ilen - 1] = snakeArr[snakeHead];
snakeInflcpt = new Point[Ilen];
snakeInflcpt = snakeArr1;
}
}
}//得到拐点坐标
//蛇前进
Forward(snakeDrt);
//若碰到墙
if (CheckSnakeBodyInFrm())
{
this.timer1.Enabled = false;
MessageBox.Show("游戏结束!");
}
l = l + 1;if (l == 1000) l = 0;
if (l % 2 == 1) { j2[0] = CheckSnakeAtBaseLine(snakeArr[snakeHead].X, snakeArr[snakeHead].Y); j3[0] = CheckSnakeInBase(snakeArr[snakeHead].X, snakeArr[snakeHead].Y, snakeBase, BasePt); }
else { j2[1] = CheckSnakeAtBaseLine(snakeArr[snakeHead].X, snakeArr[snakeHead].Y); j3[1]= CheckSnakeInBase(snakeArr[snakeHead].X, snakeArr[snakeHead].Y, snakeBase, BasePt); }
//判断是否在基地内
if (j3[0] < 0 || j3[1]<0)
{
DrawShape(snakeArr[snakeHead].X, snakeArr[snakeHead].Y);//在基地外
}
//在基地内不触碰边界时,值为0
if(j3[0]>0 && j3[1]>0)
{
if (j2[0] < 0) j2[0] = 0;
else if (j2[1] < 0) j2[1] = 0;
}
if (j2[0] * j2[1] < 0)
{
if (j2[0] == BaseLen) j2[0] = 0;
else if (j2[1] == BaseLen) j2[1] = 0;
n = n + 1; if (n == 1000) n = 0;
if (n % 2 == 1)
{//蛇出基地
if (j2[0] < 0) Lct[0] = j2[1]; else Lct[0] = j2[0];
if (l % 2 == 1)
{
if (j2[0] < 0) { i0 = snakeHead - 1; SnakeAtBaseLct[0].X = snakeArr[snakeHead - 1].X; SnakeAtBaseLct[0].Y = snakeArr[snakeHead - 1].Y; }
else { i0 = snakeHead; SnakeAtBaseLct[0].X = snakeArr[snakeHead].X; SnakeAtBaseLct[0].Y = snakeArr[snakeHead].Y; }
}
else
{
if (j2[0] < 0) { i0 = snakeHead; SnakeAtBaseLct[0].X = snakeArr[snakeHead].X; SnakeAtBaseLct[0].Y = snakeArr[snakeHead].Y; }
else { i0 = snakeHead - 1; SnakeAtBaseLct[0].X = snakeArr[snakeHead - 1].X; SnakeAtBaseLct[0].Y = snakeArr[snakeHead - 1].Y; }
}
}
else
{//蛇回到基地
if (j2[0] < 0) Lct[1] = j2[1]; else Lct[1] = j2[0];
if (l % 2 == 1)
{
if (j2[0] < 0) { i1 = snakeHead - 1; SnakeAtBaseLct[1].X = snakeArr[snakeHead - 1].X; SnakeAtBaseLct[1].Y = snakeArr[snakeHead - 1].Y; }
else { i1 = snakeHead; SnakeAtBaseLct[1].X = snakeArr[snakeHead].X; SnakeAtBaseLct[1].Y = snakeArr[snakeHead].Y; }
}
else
{
if (j2[0] < 0) { i1 = snakeHead; SnakeAtBaseLct[1].X = snakeArr[snakeHead].X; SnakeAtBaseLct[1].Y = snakeArr[snakeHead].Y; }
else { i1 = snakeHead - 1; SnakeAtBaseLct[1].X = snakeArr[snakeHead - 1].X; SnakeAtBaseLct[1].Y = snakeArr[snakeHead - 1].Y; }
}
if(snakeInflcpt!=null)
{
//待增长基地的顶点坐标、边界坐标更新
BasePt1 = new Point[snakeInflcpt.Length + 2];//拐点数+进出基地的两个点
//顶点更新
BasePt1[0] = SnakeAtBaseLct[0]; int j = 0;int z = 1;
for (int i = 1; i < snakeInflcpt.Length + 1; i++)
{
int k = CheckSnakeInBase(snakeInflcpt[i - 1].X, snakeInflcpt[i - 1].Y, snakeBase, BasePt);//不在基地内部的拐点才添加进待增长顶点中
if (k < 0) { BasePt1[z] = snakeInflcpt[i - 1]; j++;z++; }
}
BasePt1[z] = SnakeAtBaseLct[1];
snakeArr1 = new Point[z+1];
for(int i=0;i<=z;i++)
{
snakeArr1[i] = BasePt1[i];
}
BasePt1 = new Point[snakeArr1.Length];BasePt1 = snakeArr1;
//BasePt1[i1 - i0 - 2] = SnakeAtBaseLct[1];
j = 0;
//边界更新
snakeBase1 = new Point[i1 - i0 - 1];
for (int i = i0 + 1; i < i1; i++)
{
snakeBase1[j] = snakeArr[i]; j++;
}
//蛇进出基地的位置相同(达到填充条件),可知该位置为基地顶点
if (Lct[0] == Lct[1])
{
int Pt=0;
for(int i = 0; i < BasePt.Length; i++)
{
if (BasePt[i] == snakeBase[Lct[0]]) { Pt = i; break; }
}
//更新基地边界和顶点
if (Lct[0] != 0)
{
int num = snakeBase1.Length + BaseLen+1;
snakeArr1 = new Point[num];
for(int i=0;i<=Lct[0];i++){ snakeArr1[i] = snakeBase[i]; }
j = 0; for (int i = Lct[0] + 1; i <=Lct[0]+snakeBase1.Length;i++) { snakeArr1[i] = snakeBase1[j];j++; }
j = Lct[0];for(int i= Lct[0] + snakeBase1.Length + 1; i < num; i++) { snakeArr1[i] = snakeBase[j];j++; }
snakeBase = new Point[num];snakeBase = snakeArr1;BaseLen = snakeBase.Length;//更新基地边界
num = BasePt1.Length + BasePt.Length-1;
snakeArr1 = new Point[num];
for(int i=0;i<Pt ;i++) { snakeArr1[i] = BasePt[i]; }
j = 0;for(int i = Pt ; i < Pt + BasePt1.Length; i++) { snakeArr1[i] = BasePt1[j];j++; }
j = Pt +1;for(int i = Pt + BasePt1.Length; i < num; i++) { snakeArr1[i] = BasePt[j];j++; }
BasePt = new Point[num];BasePt = snakeArr1;//更新基地顶点
}
snakeArr1 = new Point [BasePt1.Length - 1];
for(int i=0;i<BasePt1.Length-1;i++)
{
snakeArr1[i] = BasePt1[i];
}
BasePt1 = new Point[snakeArr1.Length]; BasePt1 = snakeArr1;
//填充包围部分
int[] snakeBaseX; int[] snakeBaseY;
snakeBaseX = new int[BasePt1.Length + 1]; snakeBaseY = new int[BasePt1.Length + 1];
for (int i = 0; i <= BasePt1.Length; i++)
{
if (i == BasePt1.Length) { snakeBaseX[i] = BasePt1[0].X; snakeBaseY[i] = BasePt1[0].Y; }
else { snakeBaseX[i] = BasePt1[i].X; snakeBaseY[i] = BasePt1[i].Y; }
}
int y = snakeBaseY.Min();int k = 0;
for(int i=y+15;i<snakeBaseY.Max();i+=15)
{
int[] xt0; int[] xt; int len = 0; xt0 = new int[1];
for ( j = 0; j < snakeBaseX.Length - 1; j++)
{
int y1 = snakeBaseY[j]; int y2 = snakeBaseY[j + 1];
int x1 = snakeBaseX[j]; int x2 = snakeBaseX[j + 1];
if ((y1 - i) * (y2 - i) < 0)//交点不是顶点,直接添加表中
{
len++;
if (len == 1) { xt0[len - 1] = x1; }
else
{
xt = new int[len];
for (k = 0; k < xt0.Length;k++)
{
xt[k] = xt0[k];
}
xt[len - 1] = x1;
xt0 = new int[len];
xt0 = xt;
}
}
if ((y1 - i) * (y2 - i) == 0 && (y1>i||y2>i))//交点为顶点,在平行线上方则添加入表中
{
len++;
if (len == 1) { xt0[len - 1] = x1; }
else
{
xt = new int[len];
for (k = 0; k < xt0.Length ; k++)
{
xt[k] = xt0[k];
}
xt[len - 1] = x1;
xt0 = new int[len];
xt0 = xt;
}
}
if ((y1 - i) * (y2 - i) ==0 && y1==y2)//边与平行线重合,将两点都加入表中
{
len+=2;
if (len == 2) { xt0 = new int[2]; xt0[len - 2] = x1;xt0[len -1]=x2; }
else
{
xt = new int[len];
for (k = 0; k < xt0.Length ; k++)
{
xt[k] = xt0[k];
}
xt[len - 2] = x1;xt[len - 1] = x2;
xt0 = new int[len];
xt0 = xt;
}
}
}
xt = new int[len];xt = xt0;
//对交点从小到大不去重进行排序
Array.Sort(xt);
//进行填充
for(j=0;j<xt.Length-1;j+=2)
{
int num = (xt[j + 1] - xt[j])/15;
for(k=15;k<num*15;k+=15)
{
DrawShape(xt[j] + k, i);
}
}
}//填充结束
}
}
}
}
//若碰到自己
int j1 = CheckInSnakeBody(snakeArr[snakeHead].X, snakeArr[snakeHead].Y);
if (j1 >= 0)
{
if (snakeInflcpt != null)
{
//修改蛇的拐点
if (j1 == 0) { snakeInflcpt = null; Ilen = 0; }
else
{
for (int i = j1 + 1; i < snakeLen; i++)
{
for (int k = 0; k < snakeInflcpt.Length; k++)
{
if (snakeArr[i] == snakeInflcpt[k])
{
Ilen = k + 1;
snakeArr1 = new Point[Ilen];
if (Ilen == 1) snakeArr1[0] = snakeArr[snakeHead];
else
{
for (int j = 0; j < Ilen; j++)
{
if (j == Ilen - 1) snakeArr1[j] = snakeArr[snakeHead];
else snakeArr1[j] = snakeInflcpt[j];
}
}
snakeInflcpt = new Point[Ilen];
snakeInflcpt = snakeArr1;
goto con;
}
}
}
}
}
con:
for (int i = j1 + 1; i < snakeLen; i++)
{
int j = CheckSnakeInBase(snakeArr[i].X, snakeArr[i].Y, snakeBase, BasePt);//判断在基地内(含边界)
if (j < 0) CutSnake(snakeArr[i].X, snakeArr[i].Y);
}
snakeLen = j1 + 1;
snakeHead = snakeLen - 1;
snakeArr1 = new Point[snakeLen];
for (int i = 0; i < snakeLen; i++)
{
snakeArr1[i] = snakeArr[i];
}
snakeArr = new Point[snakeLen];
snakeArr = snakeArr1;
//if (j1 != snakeHead )
DrawShape(snakeArr[j1].X, snakeArr[j1].Y);
}
}
//if(panDuan)
//{
// ShowFood();
// panDuan = false; ;
//}
//if(EatedFood(FoodLct))
//{
// ShowFood();
// DrawFood(FoodLct.X, FoodLct.Y);
//}
//else
//{
// DrawFood(FoodLct.X, FoodLct.Y);
//}
}
//按下方向键
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up) snakeDrt = 1;
else if (e.KeyCode == Keys.Down)
snakeDrt = 3;
else if (e.KeyCode == Keys.Right)
snakeDrt = 2;
else if (e.KeyCode == Keys.Left)
snakeDrt = 4;
}
//判断蛇头的是否撞在蛇的身上,若是,返回撞击位置的脚标
public int CheckInSnakeBody(int x,int y)
{
for (int i=0;i<snakeLen-1;i++)
{
if(x== snakeArr[i].X && y== snakeArr[i].Y)
{
return i;
}
}
return -1;
}
//判断是否撞墙
public bool CheckSnakeBodyInFrm()
{
if (this.snakeArr[snakeHead].X > WallArr[1].X-15 || this.snakeArr[snakeHead].Y > WallArr[2].Y-15 || this.snakeArr[snakeHead].X < WallArr[0].X+15 || this.snakeArr[snakeHead].Y < WallArr[0].Y+15)
return true;
else
return false;
}
//判断触碰基地边界
public int CheckSnakeAtBaseLine(int x,int y)
{
for (int i = 0; i < snakeBase.Length; i++)
{
if(x==snakeBase[i].X && y==snakeBase[i].Y)
{
if (i == 0) return BaseLen;
else return i;
}
}
return -1;
}
//判断点是否在多边形内(含边界)
public int CheckSnakeInBase(int x,int y,Point[] Line,Point[] Pt)
{
//判断是否在边界上
for(int i=0; i<Line.Length;i++)
{
if (x == Line[i].X && y == Line[i].Y) return 1;
}
//判断是否在边界内部
int[] snakeBaseX; int[] snakeBaseY;
snakeBaseX = new int[Pt.Length+1]; snakeBaseY = new int[Pt.Length+1];
for (int i = 0; i <= Pt.Length; i++)
{
if (i == Pt.Length) { snakeBaseX[i] = Pt[0].X; snakeBaseY[i] = Pt[0].Y; }
else { snakeBaseX[i] = Pt[i].X; snakeBaseY[i] = Pt[i].Y; }
}
int[] xt0;int[] xt;int len = 0; xt0 = new int[1];
//过(x,y)与y轴平行的直线与基地的每条边求交点
for (int i=0;i<snakeBaseX.Length-1;i++)
{
int y1 = snakeBaseY[i];int y2 = snakeBaseY[i + 1];
int x1 = snakeBaseX[i];int x2 = snakeBaseX[i + 1];
if ((y1-y)*(y2-y)<0)
{
len++;
if (len == 1) {xt0[len - 1] = x1; }
else
{
xt = new int[len];
for (int j = 0; j < xt0.Length; j++)
{
xt[j] = xt0[j];
}
xt[len - 1] = x1;
xt0 = new int[len];
xt0 = xt;
}
}
if ((y1 - y) * (y2 - y) == 0 && (y1>i||y2>i))
{
len++;
if (len == 1) { xt0[len - 1] = x1; }
else
{
xt = new int[len];
for (int j = 0; j < xt0.Length; j++)
{
xt[j] = xt0[j];
}
xt[len - 1] = x1;
xt0 = new int[len];
xt0 = xt;
}
}
if ((y1 - y) * (y2 - y) == 0 && y1==y2)
{
len+=2;
if (len == 1) { xt0 = new int[2]; xt0[len - 2] = x1; xt0[len - 1] = x2; }
else
{
xt = new int[len];
for (int j = 0; j < xt0.Length; j++)
{
xt[j] = xt0[j];
}
xt[len - 2] = x1;xt[len - 1] = x2;
xt0 = new int[len];
xt0 = xt;
}
}
}
xt = new int [len];xt = xt0;
//对交点从小到大进行排序
Array.Sort(xt);
for(int i=0;i<len-1;i+=2)
{
int x1 = xt[i];int x2 = xt[i + 1];
if ((x1 - x) * (x2 - x) <= 0) return 1;
}
return -1;
}
//随机显示食物
public void ShowFood()
{
Random rmd = new Random();
int x, y; ;x = rmd.Next(0, this.Width / 15) * 15;
y = rmd.Next(0, this.Height / 15) * 15;
FoodLct.X = x;
FoodLct.Y = y;
}
//判断是否吃到食物
public bool EatedFood(Point FoodLct)
{
if (snakeArr[0].X == FoodLct.X && snakeArr[0].Y == FoodLct.Y)
{
if (snakeLen < SnakeMaxLength)
{
snakeLen++;
snakeArr[snakeLen].X = snakeArr[snakeLen - 1].X;
snakeArr[snakeLen].Y = snakeArr[snakeLen - 1].Y;
}
return true;
}
else
return false;
}
//设置窗体大小和位置
private void Form1_Load(object sender, EventArgs e)
{
this.Top = 100;
this.Left = 100;
this.Width = 800;
this.Height = 627;
}
//画围墙和蛇的初始位置
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = this.CreateGraphics();
g.Clear(Color.DarkKhaki);//清除整个画面
int m = (this.Width - 45-27) / 15;
int n = (this.Height - 60-27) / 15;
WallArr[0].X = 15; WallArr[0].Y = 15;
WallArr[1].X = WallArr[0].X+m*15; WallArr[1].Y = 15;
WallArr[2].X = WallArr[1].X; WallArr[2].Y = WallArr[1].Y+n*15;
WallArr[3].X = 15; WallArr[3].Y = WallArr[2].Y;
//画四周围墙
for (int i = WallArr[0].X; i < WallArr[1].X; i += 15)
{
DrawWall(i,WallArr[0].Y);
}
for (int i = WallArr[1].Y; i < WallArr[2].Y; i += 15)
{
DrawWall(WallArr[1].X, i);
}
for (int i = WallArr[1].X; i > WallArr[0].X; i -= 15)
{
DrawWall(i, WallArr[2].Y);
}
for (int i = WallArr[2].Y; i > WallArr[0].Y; i -= 15)
{
DrawWall(WallArr[0].X, i);
}
//画蛇的初始位置和基地
snakeArr = new Point[snakeLen];
Random rmd = new Random();
int x, y; ; x = rmd.Next(WallArr[0].X/15+2, WallArr[1].X / 15-2) * 15;
y = rmd.Next(WallArr[0].Y / 15+2, WallArr[2].Y / 15-2) * 15;
snakeArr[0].X = x;snakeArr[0].Y = y;
snakeBase = new Point[8];BaseLen = 8;
snakeBase[0].X = x - 15;snakeBase[0].Y = y - 15;
snakeBase[1].X = x ; snakeBase[1].Y = y - 15;
snakeBase[2].X = x + 15;snakeBase[2].Y = y - 15;
snakeBase[3].X = x + 15;snakeBase[3].Y = y;
snakeBase[4].X = x + 15;snakeBase[4].Y = y + 15;
snakeBase[5].X = x; snakeBase[5].Y = y + 15;
snakeBase[6].X = x - 15;snakeBase[6].Y = y + 15;
snakeBase[7].X = x - 15;snakeBase[7].Y = y;
BasePt = new Point[4];
BasePt[0] = snakeBase[0];BasePt[1] = snakeBase[2];
BasePt[2] = snakeBase[4];BasePt[3] = snakeBase[6];
for(int i=0;i<8;i++)
{
DrawShape(snakeBase[i].X, snakeBase[i].Y);
}
DrawShape(snakeArr[0].X, snakeArr[0].Y);
}
}
}