先来看一下界面:

游戏帮助类

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. keil MDK编译器警告和错误详解(不定期更新)

    工作后从单片机转成ARM,刚开始用ADS1.2编译器,用了一段时间,因为我接手的项目的老程序正是用ADS编译的,部门也大都在用.在学单片机的时候用的是keil c51编译器,ads和这个编译器在易用性 ...

  2. Delphi下URL汉字编码解码的两个函数

    //汉字URL编码函数function URLEncode(const S: string; const InQueryString: Boolean): string;var  Idx: Integ ...

  3. WPF 路径和几何图形

    原文 http://www.cnblogs.com/laoyang999/archive/2012/11/23/2783734.html 继承自Shap类的形状有:Rectangle.Ellipse. ...

  4. 960 grid 使用

    去官网下载960 grid,解压后可以看到css下面有如下文件: 960.css是一个综合性文件.我们要引入960 ,reset和text 3 个文件. 一般情况下调用: <link rel=” ...

  5. java 书籍推荐 JavaEE程序员必读图书大推荐

    java 书籍推荐 JavaEE程序员必读图书大推荐 转自:http://www.cnblogs.com/xlwmin/articles/2192775.html 下面是我根据多年的阅读和实践经验,给 ...

  6. API之IP地址查询---权威的IP地址查询接口集合

    原文地址:http://yushine.iteye.com/blog/1717586 推荐实用IP138 http://www.baidu.com/s?wd=IP&rsv_spt=1& ...

  7. 关于Qt的灵异错误

    今天用Qt编写了一个小程序,在运行的时候会报如下错误: ******SgAppenderImpl::SetImeSdkVer_begin ******SgAppenderImpl::SetImeSdk ...

  8. SQL 语句整理

    1.       /*  SQL CASE 语句写法 * SELECT TABLE1.USER_ID, TABLE1.COMP_CODE, TABLE1.DEPT_CODE, TABLE1.USER_ ...

  9. JVM学习之GC常用算法

    出处:博客园左潇龙的技术博客--http://www.cnblogs.com/zuoxiaolong,多谢分享 GC策略解决了哪些问题? 既然是要进行自动GC,那必然会有相应的策略,而这些策略解决了哪 ...

  10. jsp获取枚举的值

    Struts2的Action传回页面一个list,页面迭代这个list,获取下拉框的值,获取过来是枚举类型. 在jsp页面获取枚举的常量值和枚举的值的例子如下: jsp页面: <td >状 ...