先来看一下界面:

游戏帮助类

class GameCore
{
//游戏地图
private int[,] map = new int[4, 4];
//合并时用到的临时数组
private int[] mergeArr = new int[4];
//空位数量
private int emptyCount = 16;
//所有空位位置
private Location[] emptyArr = new Location[16];
private Random random = new Random();
//画板
private Graphics gp = null;
//用位图做画板
private Image image = null;
// 游戏项大小
private const int ITEMSIZE = 80;
//游戏得分
private int score = 0; public bool IsChange { get; set; } /// <summary>
/// 当前得分
/// </summary>
public int Score
{
get { return score; }
} /// <summary>
/// 空位数量
/// </summary>
public int EmptyCount
{
get
{
return emptyCount;
}
} /// <summary>
/// 游戏初始化
/// </summary>
public GameCore()
{
ComputeEmptyCount();
// 初始化数组
Location loc1;
GenerateNum(out loc1); ComputeEmptyCount();
GenerateNum(out loc1);
//初始化画板
image = new Bitmap(ITEMSIZE * 4 + 5 * 8,
ITEMSIZE * 4 + 5 * 8);
gp = Graphics.FromImage(image); } #region 移动并合并相邻的相同数字 /// <summary>
/// 移动单元格数据
/// </summary>
/// <param name="direction"></param>
public void Move(string direction)
{
IsChange = false;
switch (direction)
{
case "Up": MoveUp(); break;
case "Down": MoveDown(); break;
case "Left": MoveLeft(); break;
case "Right": MoveRight(); break;
}
}
/// <summary>
/// 上移
/// </summary>
public void MoveUp()
{
//1
for (int c = 0; c < 4; c++)//列
{
for (int r = 0, index = 0; r < 4; r++)//行
{
if (map[r, c] != 0)//非零
{
mergeArr[index++] = map[r, c];//放入合并数组
}
//数字位置发生变化
if (mergeArr[r] != map[r, c])
{
IsChange = true;
}
map[r, c] = 0;//将矩阵中取走的清零 }
//2合并
MergeCell();
//3 将合并后的数据放入矩阵
for (int i = 0, r = 0; i < 4; i++)
{
if (mergeArr[i] != 0)
{
map[r++, c] = mergeArr[i];
mergeArr[i] = 0;
}
}
}
} /// <summary>
/// 下移
/// </summary>
public void MoveDown()
{
//1
for (int c = 0; c < 4; c++)//列
{
for (int r = 3, index = 0; r >= 0; r--)//行
{
if (map[r, c] != 0)//非零
{
mergeArr[index++] = map[r, c];//放入合并数组
}
if (mergeArr[3-r] != map[r, c])
{
IsChange = true;
}
map[r, c] = 0;//将矩阵中取走的清零
}
//2合并
MergeCell();
//3 将合并后的数据放入矩阵
for (int i = 0, r = 3; i < 4; i++)
{
if (mergeArr[i] != 0)
{
map[r--, c] = mergeArr[i];
mergeArr[i] = 0;
}
}
} } /// <summary>
/// 合并单元格
/// </summary>
private void MergeCell()
{
for (int i = 0; i < 3; i++)
{
if (mergeArr[i] != 0 && mergeArr[i] == mergeArr[i + 1] )
{
mergeArr[i] += mergeArr[i + 1];
score += mergeArr[i];
IsChange = true;
mergeArr[i + 1] = 0;
}
}
} /// <summary>
/// 左移
/// </summary>
public void MoveLeft()
{
//1
for (int r = 0; r < 4; r++)//行
{
for (int c = 0, index = 0; c < 4; c++)//列
{
if (map[r, c] != 0)//非零
{
mergeArr[index++] = map[r, c];//放入合并数组
}
if (mergeArr[c] != map[r, c])
{
IsChange = true;
}
map[r, c] = 0;//将矩阵中取走的清零
}
//2合并
MergeCell();
//3 将合并后的数据放入矩阵
for (int i = 0, c = 0; i < 4; i++)
{
if (mergeArr[i] != 0)
{
map[r, c++] = mergeArr[i];
mergeArr[i] = 0;
}
}
}
} /// <summary>
/// 右移
/// </summary>
public void MoveRight()
{
//1
for (int r = 0; r < 4; r++)//行
{
for (int c = 3, index = 0; c >= 0; c--)//列
{
if (map[r, c] != 0)//非零
mergeArr[index++] = map[r, c];//放入合并数组 if (mergeArr[3-c] != map[r, c])
IsChange = true; map[r, c] = 0;//将矩阵中取走的清零
}
//2合并
MergeCell();
//3 将合并后的数据放入矩阵
for (int i = 0, c = 3; i < 4; i++)
{
if (mergeArr[i] != 0)
{
map[r, c--] = mergeArr[i];
mergeArr[i] = 0;
}
}
}
} #endregion /// <summary>
/// 计算空位数量
/// </summary>
public void ComputeEmptyCount()
{
emptyCount = 0;
Array.Clear(emptyArr, 0, 16); for (int r = 0; r < 4; r++)//行
{
for (int c = 0; c < 4; c++)//列
{
if (map[r, c] == 0)
{
emptyArr[emptyCount++] = new Location(r, c);
}
}
}
} /// <summary>
/// 生成新数字
/// </summary>
public int GenerateNum(out Location location)
{
int index = random.Next(0, emptyCount);
location = emptyArr[index];
map[location.X, location.Y] = random.Next() % 10 == 0 ? 4 : 2;
return map[location.X, location.Y];
} /// <summary>
/// 判断游戏是否结束
/// </summary>
/// <returns></returns>
public bool IsGameOver()
{
ComputeEmptyCount();
//如果还有空位,游戏未结束
if (EmptyCount > 0)
return false;
//检查横纵相邻单元格中是否有相同的数字,
for (int r = 0; r < 4; r++)
{
for (int c = 0; c < 3; c++)
{
//横
if (map[r, c] == map[r, c + 1])
return false; //纵
if (map[c, r] == map[c + 1, r])
return false;
}
}
return true; } #region 绘制游戏画面
/// <summary>
/// 绘制游戏画面
/// </summary>
/// <returns></returns>
public Image DrawMap()
{
//清空画板原有内容
gp.Clear(Color.DarkGray);
for (int r = 0; r < map.GetLength(0); r++)
{
for (int c = 0; c < map.GetLength(1); c++)
{
DrawItem(r, c, GetColor(map[r, c]));
}
}
return image;
} /// <summary>
/// 通过数字从程序集资源中找图片
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
public Image GetColor(int num)
{
return Properties.Resources.
ResourceManager.
GetObject("_" + num.ToString()) as Image;
} /// <summary>
/// 绘制一个数字块
/// </summary>
/// <param name="rowindex">行索引</param>
/// <param name="columnIndex">列索引</param>
/// <param name="img">要绘制的图片</param>
private void DrawItem(int rowindex, int columnIndex, Image img)
{
//画在哪 rowindex columnindex
int x = (columnIndex + 1) * 8 + columnIndex * ITEMSIZE; int y = (rowindex + 1) * 8 + rowindex * ITEMSIZE; //绘制内容img 画多大 itemSize
gp.DrawImage(img, x, y, ITEMSIZE, ITEMSIZE);
} #endregion }

定义一个结构:

 struct Location
{
private int x;
private int y; public Location(int x, int y)
{
this.x = x;
this.y = y;
} public int X
{
get { return x; }
}
public int Y
{
get { return y; }
}
}

窗体代码:

  public partial class FrmMain : Form
{
private GameCore gameCore = null; public FrmMain()
{
InitializeComponent();
} public void DrawGameMap()
{
this.picMap.Image = gameCore.DrawMap();
} //开始游戏
private void FrmMain_Load(object sender, EventArgs e)
{
StartGame();
} private void StartGame()
{
//得分清零
lblScore.Text = "0";
gameCore = new GameCore();
DrawGameMap();
} private void btnStart_Click(object sender, EventArgs e)
{
StartGame();
} //用键盘控制游戏动作
private void FrmMain_KeyDown(object sender, KeyEventArgs e)
{
string keyString = e.KeyData.ToString();
switch (keyString)
{
case "Up":
case "Down":
case "Left":
case "Right":
gameCore.Move(keyString);
//更新游戏地图
UpdateGameMap();
break;
}
} public void UpdateGameMap()
{
//游戏流程?
//地图发生过变化
if (gameCore.IsChange)
{
//绘制游戏地图
DrawGameMap();
//刷新得分
this.lblScore.Text = gameCore.Score.ToString();
//重新计算空位
gameCore.ComputeEmptyCount();
//如果空位数大于0
if (gameCore.EmptyCount > 0)
{
//产生新数
Location loc;
int num = gameCore.GenerateNum(out loc);
//开启绘制新数的动画 异步调用
Action<int,int,int> handler = DrawNewNumber;
handler.BeginInvoke(loc.X, loc.Y, num,
null, null); } //判断游戏是否继续
if (gameCore.IsGameOver())
{
MessageBox.Show("GAME OVER");
}
} } public void DrawNewNumber(int r,int c,int num)
{
int xOfMap = (c + 1) * 8 + c * 80;
int yOfMap = (r + 1) * 8 + r * 80;
Graphics gp = this.picMap.CreateGraphics(); Image img = gameCore.GetColor(num);
//数字出现由小及大,最小宽为10  最大为80
int w = 10; while (w <= 80)
{
int x =xOfMap+ 80 / 2 - w / 2;
int y =yOfMap+ 80 / 2 - w / 2;
gp.DrawImage(img, x, y, w, w);
w += 5;
System.Threading.Thread.Sleep(10);
}
}
}

OK ,完成了。

【Winform开发2048小游戏】的更多相关文章

  1. C# 开发2048小游戏

    这应该是几个月前,闲的手痒,敲了一上午代码搞出来的,随之就把它丢弃了,当时让别人玩过,提过几条更改建议,但是时至今日,我也没有进行过优化和更改(本人只会作案,不会收场,嘎嘎),下面的建议要给代码爱好的 ...

  2. jQuery实践-网页版2048小游戏

    ▓▓▓▓▓▓ 大致介绍 看了一个实现网页版2048小游戏的视频,觉得能做出自己以前喜欢玩的小游戏很有意思便自己动手试了试,真正的验证了这句话-不要以为你以为的就是你以为的,看视频时觉得看懂了,会写了, ...

  3. Swift实战之2048小游戏

    上周在图书馆借了一本Swift语言实战入门,入个门玩一玩^_^正好这本书的后面有一个2048小游戏的实例,笔者跟着实战了一把. 差不多一周的时间,到今天,游戏的基本功能已基本实现,细节我已不打算继续完 ...

  4. 如何在CentOS上安装一个2048小游戏

    如何在centos上安装一个2048小游戏 最近在学习CentOS系统,就琢磨着玩点什么,然后我看到有人在玩2048小游戏,所有我就在想,为啥不装一个2048小游戏搞一下嘞,于是乎,我就开始工作啦 由 ...

  5. js、jQuery实现2048小游戏

    2048小游戏 一.游戏简介:  2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...

  6. 用js实现2048小游戏

    用js实现2048小游戏 笔记仓库:https://github.com/nnngu/LearningNotes 1.游戏简介 2048是一款休闲益智类的数字叠加小游戏.(文末给出源代码和演示地址) ...

  7. 2048小游戏代码解析 C语言版

    2048小游戏,也算是风靡一时的益智游戏.其背后实现的逻辑比较简单,代码量不算多,而且趣味性强,适合作为有语言基础的童鞋来加强编程训练.本篇分析2048小游戏的C语言实现代码. 前言 游戏截图:  游 ...

  8. 【转】利用 three.js 开发微信小游戏的尝试

    前言 这是一次利用 three.js 开发微信小游戏的尝试,并不能算作是教程,只能算是一篇笔记吧. 微信 WeChat 6.6.1 开始引入了微信小游戏,初期上线了一批质量相当不错的小游戏.我在查阅各 ...

  9. 使用Laya引擎开发微信小游戏(上)

    本文由云+社区发表 使用一个简单的游戏开发示例,由浅入深,介绍了如何用Laya引擎开发微信小游戏. 作者:马晓东,腾讯前端高级工程师. 微信小游戏的推出也快一年时间了,在IEG的游戏运营活动中,也出现 ...

随机推荐

  1. PTF在PET上印刷線路的注意事項

    PTF: Polymer Thick Film (聚合厚模),維基的解釋 PET: Polyethylene terephthalate (聚乙烯對苯二甲酸酯),維基的解釋 就如同大家所知道的,相較於 ...

  2. SSH25个命令 + 深入SSH端口转发细节

    OpenSSH是SSH连接工具的免费版本.telnet,rlogin和ftp用户可能还没意识到他们在互联网上传输的密码是未加密的,但SSH是加密的,OpenSSH加密所有通信(包括密码),有效消除了窃 ...

  3. Boost正则表达式库regex常用search和match示例 - 编程语言 - 开发者第2241727个问答

    Boost正则表达式库regex常用search和match示例 - 编程语言 - 开发者第2241727个问答 Boost正则表达式库regex常用search和match示例 发表回复   Boo ...

  4. paip.c++ qt 外部dll共享库的导入以及引用

    paip.c++ qt 外部dll共享库的导入以及引用 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn. ...

  5. VS2010+Visual Assist X

    以前一直用VC++6.0,配一个VA,感觉也挺好用的.今天安装了VS2010,感觉还是有点不适应.然后安装了一个 Visual Assist X,主要是VS2010下破解VA有点小麻烦,中途也出现了一 ...

  6. asp.net 网站所有请求跳转到同一个页面

    应用场景:网站维护和未开发完成时,一般需要把所有请求都跳转的一个相关说明的页面,这样用户不至于困惑这个网站是不存在还是怎么了. Solution1:使用一个名称为 app_offline.htm(名字 ...

  7. 图片的像素和Android的dp值之间的关系。

    这是一个困扰我很就得问题.今天在我的反复摸索下,总结出了一些个规律. 以下测试以魅族mx5为例. 手机参数:5.5英寸:高:1920:宽1080. /** * 获得屏幕的宽度 * * @param c ...

  8. Mschart绘制图表之X轴为时间的设置方式

    最近使用C#开发图表,比较了DirectorChart,DontNetCharting,TeeChart,最终选用微软的mschart开发,对于X轴作为时间轴探索了好久,终于实现了想要的效果. 界面效 ...

  9. 通过自定义注解反射生成SQL语句

    ----------------------------------------Program.cs---------------------------------------- using Sys ...

  10. C# List<T>中Select List Distinct()去重复

    List<ModelJD> data = myDalJD.GetAllDataList(); List<string> list= new List<string> ...