昨天苦命鸳鸯节闲得无聊,就想着能不能抄袭一下之前那个像素画的游戏,经过一下午+一晚上的研究,在昨晚终于把这个小游戏的功能集成到了我的qq机器人里面,效果如下:

这个小游戏的代码实现了以下几个基本功能:
-
可以通过指令修改置顶区域的颜色
-
颜色完全可以自定义
-
判断用户是否是过了五分钟后才再次进行颜色修改的,否则拒绝修改
-
每次修改保存一张备份图片
机器人使用了酷Q pro版(air免费版无法发送图片),和C#sdk(https://cqp.cc/t/29261)
首先,因为是要修改图片,所以我们需要先在C#工程内引入“System.Drawing”
引用完毕后,在开头加上:
using System.Drawing;
修改图片某一个像素点颜色的方法是“SetPixel”,所以构造方法如下:
public static Bitmap SetPels(Bitmap Pict, Color color, int x, int y, int w, int h)
{
//遍历矩形框内的各象素点
for (int i = x; i < x + w; i++)
{
for (int j = y; j < y + h; j++)
{
Pict.SetPixel(i, j, color);//设置当前象素点的颜色
}
}
return Pict;
}
这样就可以改变指定区域的颜色了,但是qq内发的图片不能精确到指定坐标,毕竟就只是一张图片,所以我把像素点给扩大到了17*17的大小,并且增加了新的方法:
//x,y限制0-29
private static Bitmap SetPoint(Bitmap Pict, Color color, int x, int y)
{
return SetPels(Pict, color, x * 17, y * 17, 17, 17);
}
这样就可以方便地修改指定区域了。
我们再加上一个打开文件的方法:
/// <summary>
/// 通过FileStream 来打开文件,这样就可以实现不锁定Image文件,到时可以让多用户同时访问Image文件
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static Bitmap ReadImageFile(string path)
{
FileStream fs = File.OpenRead(path); //OpenRead
int filelength = 0;
filelength = (int)fs.Length; //获得文件长度
Byte[] image = new Byte[filelength]; //建立一个字节数组
fs.Read(image, 0, filelength); //按字节流读取
System.Drawing.Image result = System.Drawing.Image.FromStream(fs);
fs.Close();
Bitmap bit = new Bitmap(result);
return bit;
}
有了这些方法,我们就可以进行测试了(提前准备好图片文件):
string picPath = @"C:\Users\Administrator\Desktop\kuqpro\data\image\pixel_game\1.bmp"; Bitmap pic = ReadImageFile(picPath); pic = SetPoint(pic, color.red, 1, 1); pic.Save(picPath);
如果不出意外的话,会在左上方出现一个红色方框,而且不是紧贴着边缘的。
我们接下来处理用户时间的问题,首先先使用xml保存配置文件,我写了以下几个方法,效率可能会很低,建议大家使用其他的方法进行替换:
static string path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
public static string xml_get(long group, string msg)
{
dircheck(group);
XElement root = XElement.Load(path + group + ".xml");
string ansall = "";
foreach (XElement mm in root.Elements("msginfo"))
{
if (msg == mm.Element("msg").Value)
{
ansall = mm.Element("ans").Value;
break;
}
}
return ansall;
}
public static void del(long group, string msg)
{
dircheck(group);
string gg = group.ToString();
XElement root = XElement.Load(path + group + ".xml");
var element = from ee in root.Elements()
where (string)ee.Element("msg") == msg
select ee;
if (element.Count() > 0)
{
element.First().Remove();
}
root.Save(path + group + ".xml");
}
public static void insert(long group, string msg, string ans)
{
if(msg.IndexOf("\r\n") < 0 & msg != "")
{
dircheck(group);
XElement root = XElement.Load(path + group + ".xml");
XElement read = root.Element("msginfo");
read.AddBeforeSelf(new XElement("msginfo",
//new XElement("group", group),
new XElement("msg", msg),
new XElement("ans", ans)
));
root.Save(path + group + ".xml");
}
}
public static void createxml(long group)
{
XElement root = new XElement("Categories",
new XElement("msginfo",
//new XElement("group", 123),
new XElement("msg", "初始问题"),
new XElement("ans", "初始回答")
)
);
root.Save(path + group + ".xml");
}
public static void dircheck(long group)
{
if (File.Exists(path + group + ".xml"))
{
//MessageBox.Show("存在文件");
//File.Delete(dddd);//删除该文件
}
else
{
//MessageBox.Show("不存在文件");
createxml(group);//创建该文件,如果路径文件夹不存在,则报错。
}
}
另外,因为我们需要统计时间差,所以我使用了timestamp来记录时间(不会用datetime?,求大佬讲解)
/// <summary>
/// DateTime时间格式转换为Unix时间戳格式
/// </summary>
/// <param name="time"> DateTime时间格式</param>
/// <returns>Unix时间戳格式</returns>
public static int ConvertDateTimeInt(System.DateTime time)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
return (int)(time - startTime).TotalSeconds;
}
于是,整段响应群消息的代码如下:
/// <summary>
/// Type=2 群消息。
/// </summary>
/// <param name="subType">子类型,目前固定为1。</param>
/// <param name="sendTime">发送时间(时间戳)。</param>
/// <param name="fromGroup">来源群号。</param>
/// <param name="fromQQ">来源QQ。</param>
/// <param name="fromAnonymous">来源匿名者。</param>
/// <param name="msg">消息内容。</param>
/// <param name="font">字体。</param>
public override void GroupMessage(int subType, int sendTime, long fromGroup, long fromQQ, string fromAnonymous, string msg, int font)
{
if (fromQQ == 80000000)
return;
// 处理群消息。
...一堆代码
else if(msg.IndexOf("pixel") == 0 && (msg.Length - msg.Replace("/","").Length) == 2)
{
string fromqqtime_get = xml_get(20, fromQQ.ToString());
int fromqqtime = 0;
try
{
fromqqtime = int.Parse(fromqqtime_get);
}
catch { }
if(ConvertDateTimeInt(DateTime.Now)-fromqqtime < 300)
{
SendMinecraftMessage(fromGroup, CQ.CQCode_At(fromQQ) + "你需要再等" + (300 - ConvertDateTimeInt(DateTime.Now) + fromqqtime) + "秒才能继续放像素点");
return;
}
string get_msg = msg.Replace("pixel", ""), getx = "", gety = "", getcolor = "";
int placex, placey;
string[] str2;
int count_temp = 0;
str2 = get_msg.Split('/');
foreach (string i in str2)
{
if (count_temp == 0)
{
getx = i.ToString();
count_temp++;
}
else if (count_temp == 1)
{
gety = i.ToString();
count_temp++;
}
else if (count_temp == 2)
{
getcolor = i.ToString();
count_temp++;
}
}
try
{
placex = int.Parse(getx) - 1;
placey = int.Parse(gety) - 1;
if (getcolor.IndexOf("#") == -1 || placex > 29 || placey > 29)
throw new ArgumentNullException("fuck wrong color");
}
catch
{
SendMinecraftMessage(fromGroup, "放置像素点时遇到未知错误,请检查颜色与坐标是否正确");
return;
}
int picCount;
try
{
picCount = int.Parse(xml_get(20, "count"));
}
catch
{
SendMinecraftMessage(fromGroup, "遇到致命性错误,请联系晨旭修复");
return;
}
try
{
string picPath = @"C:\Users\Administrator\Desktop\kuqpro\data\image\pixel_game\" + picCount + ".bmp";
Bitmap pic = ReadImageFile(picPath);
pic = SetPoint(pic, ColorTranslator.FromHtml(getcolor), placex, placey);
picCount++;
picPath = @"C:\Users\Administrator\Desktop\kuqpro\data\image\pixel_game\" + picCount + ".bmp";
pic.Save(picPath);
}
catch
{
SendMinecraftMessage(fromGroup, "遭遇未知错误");
return;
}
del(20, "count");
del(20, fromQQ.ToString());
insert(20, "count", picCount.ToString());
insert(20, fromQQ.ToString(), ConvertDateTimeInt(DateTime.Now).ToString());
SendMinecraftMessage(fromGroup, "[CQ:image,file=pixel_game\\" + picCount + ".bmp]\r\n图片修改完成!" + DateTime.Now.ToString() + CQ.CQCode_At(fromQQ));
}
...一堆代码
}
如有问题,可以在下面留言。
代码写的比较啰嗦,大佬们请耐心地看?















