https://github.com/CNllb/pig_end
学号 | 姓名 | 分工 | 博客链接 |
---|---|---|---|
031902610 | 刘凌斌 | 前端界面,模型设计,游戏逻辑 | 结对编程作业 |
131901121 | 肖清江 | AI算法 | 结对编程作业 |
一、原型设计
(1.1)原型作品链接为:https://app.mockplus.cn/s/WSoYi3myuw7c
(1.2)原型开发工具:在本次结队编程作业中,我们小组采用了操作起来较为简单的Mockup工具对原型进行设计。
(1.3)原型简单说明:
(1)缺点和不足:
① 本次原型设计是由两位直男协同完成的,在审美方面或许还有较大的欠缺,希望大家批评指正。
② 作品链接中的原型作品的原型组件未进行及时更新,较为简陋,下文博客提供实现前后对比。
(2)主要页面原型和实际效果对比:、
原型和小程序实现的机型:iPhone X(812*375)
主要效果的区别产生在原型设计未导入相关字体库和相关图标,实际界面与原型在实现上存在计算误差。
登录页
① 原型:
② 实际效果:
首页:
① 原型:
② 实际效果:
对战界面:
① 原型:
② 实际效果:
(1.4)遇到的困难和解决方法:
困难:本次制作原型是我们小组第一次使用原型制作工具,在这过程中最难熬的就是想出一个好的idea,并做好颜色搭配。这对于两个理工男来说并不友好。我们也想过直接使用暴发户气息爆棚的传统斗地主风格,或者直接竖屏实现按钮点击,带出汽配城风格,但还是想着,既然要自己从0开始做一个小程序,那么不管结果如何,总要尽自己的可能,尽可能实现效果好一些。
解决方法:多次讨论之后,我们决定背道而行,将棋牌游戏打出养生的感觉,所以,在图片方面,选择了色调较为柔和的水墨山水画,再结合莫兰迪色系,调出了属于我们小组的软件设计风格。
收获:在原型开发的过程中,我们成员之间可以天马行空,可以一次次地进行犯错,颜色搭配有问题就马上更改颜色,再进行分析,这是软件开发中极为有趣的一部分,我们也开始能够理解UI小姐姐没有灵感时候的痛楚。在这过程中,我们又掌握了一个对软件开发非常有帮助的开发工具。
二、原型设计实现
简易思维导图:
(2.1)代码实现思路:
(1)网络接口的使用
-
登录接口的使用
-
在实现过程中,使用input进行账号和密码的输入,点击登录实现网络通信,成功获取用户信息
-
登录函数设置了常规输入检测,保证用户名和密码内容不为空,并对登录返回的status进行了判断。
login: function (e) { var that = this; let formData = e.detail.value; this.setData({ student_id:formData.student_id, password:formData.password }) console.log(formData); if (that.data.student_id == ""||that.data.password == "") { wx.showModal({ title: "错误", content: "用户名或密码不能为空" }); that.isname = false; that.ispass = false; } else { that.isname = true; that.ispass = true; } if (that.ispass && that.isname){ wx.request({ url: 'http://172.17.173.97:8080/api/user/login', header:{ "Content-Type":"application/x-www-form-urlencoded" }, data: formData, method: "POST", success: function (res) { console.log(res.data); if (res.data.status == 200) { that.setData({ id_token: res.data.data.token, response: res }), wx.setStorageSync('id_token', that.data.id_token), wx.navigateTo({ url: '../../pages/home/home', }) }else{ wx.showModal({ title: "错误", content: "密码或账号错误" }); } }, fail: function (res) { console.log(res.data); console.log('is failed'); console.log('获取信息失败'); } }) } }
-
-
获取房间信息的实现
getHome:function (params) {
var that = this;
wx.request({
url: 'http://172.17.173.97:9000/api/game/index',
method: "get",
data:{
page_size:that.data.page_size,
page_num:that.data.page_num,
},
header:{
"Authorization": wx.getStorageSync('id_token'),
},
success: function (res) {
console.log(res);
that.setData({
home_detail:res.data.data.games,
isOpenHome:false,
total_home:res.data.data.total,
total_pages_num:res.data.data.total_page_num
})
console.log(that.data.home_detail);
console.log(that.data.total_pages_num);
},
fail:function(err){
console.log(err)
}
})
}
- 加入房间接口实现
joinHome: function (e) {
var that = this;
console.log(e.currentTarget.dataset.uuid);
wx.request({
url: 'http://172.17.173.97:9000/api/game/'+this.data.uuid,
method: "POST",
header:{
"Authorization": wx.getStorageSync('id_token'),
"content-type":'application/json'
},
data:{
uuid:e.currentTarget.dataset.uuid
},
success: function (res) {
that.setData({
Gaming:true
})
},
fail:function(err){
console.log(err)
}
})
},
- 创建房间的接口实现
createHome: function () {
var that = this;
wx.request({
url: 'http://172.17.173.97:9000/api/game',
method: "POST",
data:{
"private":that.data.private
},
header:{
"Authorization": wx.getStorageSync('id_token'),
},
success: function (res) {
that.setData({
uuid: res.data.uuid
})
console.log(res);
console.log(that.data.uuid);
},
fail:function(err){
console.log(err)
}
})
},
(2)代码组织与内部实现设计
(3)贴出你认为重要的/有价值的代码片段,并解释
人机对战之中,AI的实现感觉比较有意思,我们小组是采用设置延时进行实现。在实现的时候,经过2000ms之后,自动实现AI的步骤,模拟较为有效
setTimeout(() => {
// 延迟后操作
that.selectWay()
}, 2000)
(4)描述你改进的思路
- 在本来的代码中,对战过程只使用一个界面进行展现,但是在传参过程中,多次造成传参错误,或者逻辑混乱的问题。
- 在这样的前提下,我们决定了重构代码,一个界面实现两次刷新,这样每个数据都能够单独处理,大大降低了发生逻辑错误的概率。
(5)展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。
- 本次结队编程项目,我们小组采用的是微信小程序进行实现,出于微信小程序的局限性,并未进行小程序代码的单独单元测试。但对各个函数进行了单独封装,并进行多次单例测试。
// 封装的抽牌函数
POP_Get_pork_1: function () {
var that = this;
this.data.last_value = this.data.now_value;
this.data.now_pork = this.data.get_pork_set.pop();
this.data.now_value = this.data.now_pork.value;
this.data.set_pork_set.push(this.data.now_pork)
switch (Math.floor((this.data.now_pork.value - 1) / 13)) {
case 0:
this.setData({
get_pork_black_peach_count: this.data.get_pork_black_peach_count - 1,
})
break;
case 1:
this.setData({
get_pork_red_heart_count: this.data.get_pork_red_heart_count - 1,
})
break;
case 2:
this.setData({
get_pork_black_flower_count: this.data.get_pork_black_flower_count - 1,
})
break;
default:
this.setData({
get_pork_red_block_count: this.data.get_pork_red_block_count - 1
})
break;
};
that.check_card_1();
that.check_winner();
this.setData({
now_pork: this.data.now_pork,
now_index: (this.data.now_index + 1) % 2,
set_pork_block: this.data.set_pork_set.length == 0 ? false : true,
get_pork_block: this.data.get_pork_set.length == 0 ? false : true,
player1_black_peach_count: this.data.player1_black_peach.length,
player1_red_heart_count: this.data.player1_red_heart.length,
player1_black_flower_count: this.data.player1_black_flower.length,
player1_red_block_count: this.data.player1_red_block.length
});
that.set_top_card_1();
if (this.data.get_pork_set.length == 0) {
this.setData({
get_pork_block: true
})
}
},
// 封装的检查牌堆函数
check_card_1: function () {
if (Math.floor((this.data.now_value - 1) / 13) == Math.floor((this.data.last_value - 1) / 13)) {
while (this.data.set_pork_set.length != 0) {
var pork_1 = this.data.set_pork_set.pop();
console.log(pork_1);
switch (Math.floor((pork_1.value - 1) / 13)) {
case 0:
this.data.player1_black_peach.push(pork_1);
break;
case 1:
this.data.player1_red_heart.push(pork_1);
break;
case 2:
this.data.player1_black_flower.push(pork_1);
break;
default:
this.data.player1_red_block.push(pork_1);
break;
}
}
this.data.last_value = null;
this.data.now_value = null;
}
},
// 封装的设置牌顶的函数
set_top_card_1: function () {
this.setData({
player1_top_black_peach: this.data.player1_black_peach.pop(),
player1_top_red_heart: this.data.player1_red_heart.pop(),
player1_top_black_flower: this.data.player1_black_flower.pop(),
player1_top_red_block: this.data.player1_red_block.pop()
})
if (this.data.player1_top_black_peach != null) {
this.data.player1_black_peach.push(this.data.player1_top_black_peach)
}
if (this.data.player1_top_red_heart != null) {
this.data.player1_red_heart.push(this.data.player1_top_red_heart)
}
if (this.data.player1_top_black_flower != null) {
this.data.player1_black_flower.push(this.data.player1_top_black_flower)
}
if (this.data.player1_top_red_block != null) {
this.data.player1_red_block.push(this.data.player1_top_red_block)
}
},
// 封装的检查对局胜利的函数
check_winner: function () {
if (this.data.get_pork_set.length == 0) {
this.setData({
Gaming: false
})
if (this.data.player1_black_peach_count + this.data.player1_red_heart_count + this.data.player1_black_flower_count + this.data.player1_red_block_count > this.data.player2_black_peach_count + this.data.player2_red_heart_count + this.data.player2_black_flower_count + this.data.player2_red_block_count) {
this.setData({
winner: this.data.player_2
})
} else {
this.setData({
winner: this.data.player_1
})
}
}
}
(2.2)贴出Github的代码签入记录,合理记录commit信息。
小组的很大的不足:小组成员欠缺日常对Github的使用习惯,没有养成及时push代码的习惯,我们的commit记录并不好
小组有设置todo的习惯,以下是我们小组的todo记录截图(使用的是“敬业签”APP):
(2.3)遇到的代码模块异常或结对困难及解决方法。
(1)在代码模块异常方面,前期的网络通信采用Postman进行模拟网络通信,和实际实现校园网通信有很大的不同,微信小程序对局域网通信的不支持也是一个很大的问题。在刚接入校园网的时候,各种报错,是真的头大。
解决办法:微信开发者工具强行不检查网络的证书和合法性,再接入校园网,成功获取信息。
(2)结队困难:首先,这是和队友的第一次合作,在实现代码的过程中,没有那么的默契。其次,两个人对各自负责的领域,了解得都不够深刻,前端对微信开发者工具的相关合法性不够了解,后端对框架不够熟练,这就造成了到处碰壁。
解决方法:通过制定todo进行计划,保证项目顺利地进行。
(2.4)评价你的队友。
-
值得学习的地方:
我的队友是个认真负责的人,能够按照计划顺利完成自己的任务,并且很有发散性思维,能够举一反三。
-
需要改进的地方:
希望队友能够给代码加上调用接口的示例代码。
(2.5)提供此次结对作业的PSP和学习进度条(每周追加)
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 12 | 12 | 前端:学习安卓开发和微信小游戏的开发;后端:考虑使用Java进行后端编程,对Java基础知识进行巩固 |
2 | 1000 | 1000 | 12 | 24 | 前端:学了一周的游戏引擎和微信小游戏开发后,果断放弃,短时间把握不住,做了无用功,第2周,对原型进行设计,并实现微信小程序界面;后端:学习使用flask框架的python后端开发; |
3 | 2500 | 3500 | 8 | 32 | 前端:实现微信小程序打牌逻辑,制作简易的人机对战;后端:完成AI的百分80代码。 |
4 | 1000 | 4500 | 10 | 42 | 前端:对代码进行封装,使得游戏的逻辑清晰明了,遗憾是,在线对战代码重构还未全部完成;后端:完成AI,并制作接口 |
三、心得
刘凌斌:
作业难度:本次作业给我带来的最大的困难应该是在游戏逻辑的实现,犯了专业性的错误,对各个操作的代码并未实现有效的封装。造成了后期代码需要重构,浪费了很多的时间;其次是对时间的规划不够合理,前期想要实现很多附属功能,后面发现附属功能还未完成,主要功能来不及实现,只能草草的实现,效果很差,这是犯的很致命的错误。
作业感想:即使本次作业完成的并不完善,但我们小组仍然会在后期将这个项目实现完全,也会开始学会习惯使用GitHub进行代码的pull和push,也借此提高自己的代码能力。
启发:制定项目需求一定要合理,要与实力相互匹配,不能好高骛远,要一直学下去,我们不会的还有很多东西。
肖清江:
作业难度: 这次作业难度我个人感觉较大,因为之前没有开放一个可以联网的功能(在线对战),只做过命令行小游戏,并且也没有做过前后端分离的工作(之前甚至分不清前后端),所以这次的作业对我挑战还是相当大的。
作业感想: 即使这次作业难度较大,但我还是尽量根据完成作业的需要去学相对应的内容。虽然起步的时候相当困难,但好在b站大学有各种各样的学习资料嘿嘿,终于还是学会了flask框架来实现后端,总而言之,完成这次作业还是相当有满足感的,尤其是看到自己的代码能给成功应用的时候!
启发: 这次给我最大的启发就是,要勇于尝试新事物,之前一直害怕学来不及,但不管如何,尽力而为,最终一定能得到收获,相信自己,勇于尝试新事物!