信管1121,201211671117,聂双燕
第一部分:开发要求(完整要求见课程考核说明编程组和游戏说明)
- 随机显示 一个名字 与 3张相片,选择正确的相片;
- 随机显示 一张相片 与 3个名字,选择正确的名字;
第二部分:最终成果(《猜猜看》源码)
1.程序主界面,说明程序主要具备的功能,具体有学生信息的增删查改,以及依据图片猜名字和依据名字猜图片:
2.猜猜看核心界面,依据图片猜名字界面和依据名字猜图片界面:
3.学生信息的增查改界面:
4.多条学生信息的一次性删除:
5.数据库studnt表的设计:
第三部分:《猜猜看》游戏设计过程
此游戏开发由于丁老师在课堂上把原型已经设计出来,另外有物联网的同学展示过自己的作品,因此在功能设计方面没有花费很多时间,全部开发用时大约是12小时。
1.确定存储学生信息文件的载体
基于本游戏有学生信息的增删查改的操作及其他方面的综合考虑,我最终选择用数据库存储学生信息。因为用文本文件存储就不能方便对学生信息进行增删查改,并且如果用文件存储每次进行一次猜猜看就要对整个文本文件重写,而采用数据库就只需要对一条记录进行修改"总猜次数"和"猜对次数"。此环节大约用了0.5小时。
2.界面设计
每个功能的界面是自己一边动手拖拉控件一边思考设计出来的,然后通过无限多次的修改得到现在的最终成果。这个环节花费的时间比较多,因为我一开始就在修改和增加学生信息那里附有照相功能获照片,于是我在网上找到拍照开源源代码,运行出后并且做好了一整套界面设计后,我发现连接不了数据库,总是报错找不到mysql那个类包,我用了很多网上所说的方法,包括把mysql.dll复制到c:\Windows\Microsoft.NET\Framework\v2.0.50727\下等,但最终没有解决这个问题,之后我重新建立工程并试图把拍照功能移到新工程里,还是失败。因此我放弃了拍照功能并重新开始写界面。此环节大约用了5小时。
3.游戏核心功能设计
《猜猜看》游戏的核心功能是"按照片猜名字"和"按名字猜照片",首先考虑的是取怎样的随机数,我选择随机取3个在总人数范围内的int型随机数,同时取一个1或者2或者3用于确定随机选择的三个学生里要猜测的学生;然后要考虑怎样取生成三个不重复的三个随机数,这点很快就在网上找到答案了;最后要考虑在随机数与学生建立怎样的关联,一开始我建立了"数据库中自增字段’序号’"与"随机数"的直接关联关系,在之后的开发中发现当进行删除学生信息后,该序号就不能被使用,这样程序出现了问题(随机抽取了一个序号但已删除学生信息),最后我是建立了"数据库第几个记录"与"随机数"的关联。此环节大约用了2小时。
4.数据库设计
根据开发前阶段的成果,我设计出了包含5个字段(自增序号字段’num’、学生信息’idName’、照片地址’photoUrl’、猜对次数’trueNum’、总猜次数’allNum’),最终程序没有用到自增字段,由于对程序几乎没有影响并且删掉该字段要大量改动程序,因此我选择保留该自增字段。录入数据过程没有结合C#简单代码解决,纯手工录入,花费时间较多。此环节大约用了1.5小时。
5.调试与测试
剩余时间几乎花费在这个环节,重复进行调试,功能测试,和修改代码。
此环节大约用了2小时。
第四部分:开发时的学习收获(知识与技能方面)
所有的收获来源于于开发中遇到的问题,这次开发是基于C#第四次作业操作数据库的基础上进行的,所以开发中遇到较少的问题,开发中我所遇到的问题有:
1.寻找一个有特色的控件,触发"按照片猜名字"和"按名字猜照片"事件,最终选择ComboBox1控件,所以现在学会了该控件的用法,包括相关出发事件;
2.当发现"数据库中自增字段’序号’"与"随机数"的直接关联关系有问题时候,我尝试去网上寻找把数据库自增字段的值恢复到删除记录前的值方法,始终没有找到成功的办法。通过发现的问题与大量查找资料后,我知道了以前不知道的数据库知识,在以后的开发中也会在早期考虑到这个问题,避免走很多弯路;
3.在发现每次生成的三个随机数在很多时候相同时候,就在网上查资料,明白随机数生成的原理,并找到生成三个不一样的随机数的方法。过去自己也经常运用随机数,但是从来没思考过有关随机数的性质。
4.解决"数据库中自增字段’序号’"与"随机数"的直接关联关系有问题时候,我发现有很多方法可以解决这个问题,但我最终选择建立了"数据库第几个记录"与"随机数"的关联解决问题,我明白了一个开发技巧,要达到一个目的,有很多可以选择的方法。要经过一番思考后选择最佳的方法。
第五部分:开发后的感受与体会
虽然这个《猜猜看》游戏存在很大缺陷,最大缺陷是没能找到一个合适的算法满足老师的开发要求,但是当这个游戏正确地运行出来后,心里还是有种喜悦感,毕竟这个游戏是自己花费十多小时的成果。游戏缺乏一个很重要的也是很复杂的错误处理,就是对具体的错误进行处理,用一个错误提示框告诉使用者哪里错了和该怎样做,而不是只有我们开发者能看懂的错误停止,游戏终止。这个是本游戏的另一大缺陷,没有错误处理。以后我会慢慢完善这块,提示他的使用价值和可用性。
总的来说,经过这次的游戏开发,一方面我加深理解了自己已掌握的技术和知识,另一方面就是学会了自己不会的技术和知识。最终提高了自己解决问题的能力。
第六部分:核心代码解读
这里只介绍部分核心代码,还有很多相连技术没有做介绍。
1.操作数据库类Connector,具体解读见代码注释:
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using System.Data;
using System;
namespace Coursedesign
{
class Connector
{
/// <summary>
/// 建立MySql数据库连接.
/// </summary>
/// <returns>返回MySqlConnection对象</returns>
public MySqlConnection getmysqlcon()
{
string M_str_sqlcon = "server=127.0.0.1;user=root;database=tt;port=3306;password=nie;"; //根据自己的设置
MySqlConnection myCon = new MySqlConnection(M_str_sqlcon);
return myCon;
}
// 执行MySqlCommand命令
/// <summary>
/// 执行MySqlCommand命令
/// </summary>
/// <param name="M_str_sqlstr">SQL语句</param>
public void getmysqlcom(string M_str_sqlstr)
{
MySqlConnection mysqlcon = this.getmysqlcon();
mysqlcon.Open();
MySqlCommand commn = new MySqlCommand("set names utf-8", mysqlcon);
MySqlCommand mysqlcom = new MySqlCommand(M_str_sqlstr, mysqlcon);
mysqlcom.ExecuteNonQuery();
mysqlcom.Dispose();
mysqlcon.Close();
mysqlcon.Dispose();
}
/// <summary>
/// 创建一个DataTable对象,以便用于控制台及dataGridView控件输出表的内容
/// </summary>
/// <param name="M_str_sqlstr">SQL语句</param>
/// <returns>返回MySqlDataReader对象</returns>
public DataTable getsqlread(string M_str_sqlstr)
{
MySqlConnection mysqlcon = this.getmysqlcon();
mysqlcon.Open();
MySqlCommand commn = new MySqlCommand("set names utf-8", mysqlcon);
MySqlDataAdapter mda = new MySqlDataAdapter(M_str_sqlstr, mysqlcon);
DataTable dt = new DataTable();
mda.Fill(dt);
return dt;
}
//获得student表里记录总数,以便生成在范围内的三个随机数
public int getAllnum()
{
string sql = "select MAX(num) from student";
string[] strs = new string[5];
int i = 0;
DataTable dataTable =getsqlread(sql);
foreach (DataRow row in dataTable.Rows)
{
foreach (DataColumn column in dataTable.Columns)
{
strs[i] = row[column].ToString();
i++;
}
}
return Convert.ToInt32(strs[0]);
}
//获得第num个记录,即根据随机数num得到对应记录
public string[] getSinfo(int num)
{
string sql = "select * from student";
string[] strs = new string[5];
int i = 0;
int j = 1;
DataTable dataTable = getsqlread(sql);
foreach (DataRow row in dataTable.Rows)
{
if (j == num)
{
foreach (DataColumn column in dataTable.Columns)
{
strs[i] = row[column].ToString();
i++;
}
}
j++;
}
return strs;
}
}
}
2.ComboBox的触发事件,具体解读见代码注释:
//ComboBox选项的点击触发事件
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//进行"按名字猜照片"游戏
if ((comboBox1.SelectedItem).Equals("按名字猜照片"))
{
//按名字猜照片界面
SnameForm ss = new SnameForm();
ss.Show();
}
//进行"按照片猜名字"游戏
if ((comboBox1.SelectedItem).Equals("按照片猜名字"))
{
//按照片猜名字界面
PhotoForm pp = new PhotoForm();
pp.Show();
}
}
3.核心功能"按照片猜名字"(类PhotoForm)和"按名字猜照片"(类SnameForm)界面解读,两个类功能几乎一样,以解读类PhotoForm为例,具体解读见代码注释:
using System;
using System.Collections;
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 Coursedesign
{
public partial class PhotoForm : Form
{
Connector connector = new Connector();
string []ss=new string [5];
Image img;
//an,tn,ltn分别表示要猜测同学这次猜测后总猜测次数、猜测前猜对次数、猜测后猜对次数
int an, tn,ltn;
//n表示在三个随机数选择要进行的随机数
int n;
//nu表示student表中同学总数
int nu = 56;
public PhotoForm()
{
InitializeComponent();
pictureBox2.Visible = false;
pictureBox3.Visible = false;
pictureBox4.Visible = false;
label6.Visible = false;
label7.Visible = false;
label8.Text="";
label9.Text="";
label5.Visible = false;
nu = connector.getAllnum();
Hashtable hashtable = new Hashtable();
Random rm = new Random();
n = rm.Next(1,4);
int RmNum = 3;
for (int i = 1; hashtable.Count <= RmNum; i++)
{
int num = rm.Next(1,nu+1);
ss = connector.getSinfo(num);
img = Image.FromFile(@ss[2]);
//利用Hashtable防止生成的三个随机数中有相同的随机数
if (!hashtable.ContainsValue(num) && num != 0)
{
hashtable.Add(num, num);
ss = connector.getSinfo(num);
img = Image.FromFile(@ss[2]);
an = Convert.ToInt32(ss[4])+1;
tn = Convert.ToInt32(ss[3]);
ltn = tn + 1;
//把要猜测同学信息显示在相应控件
if (i == n)
{
pictureBox1.Image = img;
label5.Text = ss[1];
}
//把第一个随机抽取同学信息显示在相应控件
if (i == 1)
{
pictureBox2.Image = img;
label1.Text = ss[1];
}
//把第二个随机抽取同学信息显示在相应控件
if (i == 2)
{
pictureBox3.Image = img;
label2.Text = ss[1];
}
//把第三个随机抽取同学信息显示在相应控件
if (i == 3)
{
pictureBox4.Image = img;
label3.Text = ss[1];
}
}
}
}
//j代表第几个随机数
private void dialogMethod(int j)
{
pictureBox2.Visible = true;
pictureBox3.Visible = true;
pictureBox4.Visible = true;
label5.Visible = true;
label6.Visible = true;
label7.Visible = true;
//判断是否猜对
if (n == j)
{
updateNum(ltn,an);
DialogResult dr = MessageBox.Show("猜测正确!是否继续进行猜测??", "提示",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (dr == DialogResult.OK)
{
this.Close();
PhotoForm pp = new PhotoForm();
pp.Show();
}
else
{
this.Close();
}
}
else
{
updateNum(tn, an);
DialogResult dr = MessageBox.Show("猜测错误!是否继续进行猜测??", "提示",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (dr == DialogResult.OK)
{
this.Close();
PhotoForm pp = new PhotoForm();
pp.Show();
}
else
{
this.Close();
}
}
}
//每次猜测完后更新总猜次数和猜对次数
private void updateNum(int truenum, int allnum)
{
label8.Text = ""+allnum;
label9.Text = "" + truenum;
string sql = "update student set " +
"trueNum=" + truenum + "," + "allNum=" + allnum + " where num='" + ss[0] + "'";
connector.getmysqlcom(sql);
}
private void label1_Click(object sender, EventArgs e)
{
int j = 1;
dialogMethod(j);
}
private void label2_Click(object sender, EventArgs e)
{
int j = 2;
dialogMethod(j);
}
private void label3_Click(object sender, EventArgs e)
{
int j = 3;
dialogMethod(j);
}
}
}