学做婴儿衣服的网站,公司建设网站价格多少,深圳网站建设专家,网站建设 科技公司示例 在线体验地址五子棋#xff0c;记得一定要再拉个人才能对战
本期难点
1、完成了五子棋的布局#xff0c;判断游戏结束 2、基本的在线对战 3、游戏配套im(这个im的实现#xff0c;请移步在线im)
下期安排
1、每步的倒计时设置 2、黑白棋分配由玩家自定义 3、新增旁观…示例 在线体验地址五子棋记得一定要再拉个人才能对战
本期难点
1、完成了五子棋的布局判断游戏结束 2、基本的在线对战 3、游戏配套im(这个im的实现请移步在线im)
下期安排
1、每步的倒计时设置 2、黑白棋分配由玩家自定义 3、新增旁观者 4、悔棋 5、自行创建一盘棋局
感兴趣的还请点个免费的收藏与关注后续会一直跟进这个系列
前端部分五子棋布局与游戏输赢判断
templatediv classflex-wrap flex-justify-betweendiv classgobang-main!-- {{ userdata._id }}{{ gameBase }} --步数 {{ currentStep }} 我方{{ getQi }}el-button v-ifisAdmin clickclearGame 清空游戏 /el-button!-- 下棋区 --game :listgobangList :configconfig clickHandleclickHandle/game!-- el-button v-ifisGameOver isAdmin clickreloadGame 重新开始 /el-button --/div!-- im区 --ImrefimRefv-ifgame_im_id:style{ width: 440px }:isShowLeftfalse:gobang_idgobang_id:game_im_idgame_im_idroom_baseinforoom_baseinfoget_game_contentget_game_contentget_gb_infoget_gb_infodel_gobangdel_gobang/Im/div
/templatescript
import Im from /views/blog/im/index.vue
import { baseURL } from /plugins/config.js
import { get_gobang_list, post_gobang, get_gobang, del_gobang } from /api/data.js
import game from ./game.vue
export default {components: {Im,game,},data() {return {isGameOver: false,page: list,gameBase: {_id:,status: ,max: 10,max_move_time: 0,all_time: 0,hei_user_id: ,bai_user_id: ,im_romm_id:},gobangMembers: [], // 五子棋游戏成员列表room_id: ,gobangList: [],config: {type: 1, // 1为白棋 2为黑棋line: 15, // 棋盘线条数width: 36,},first: true,}},computed: {...Vuex.mapState([userdata]),...Vuex.mapGetters([isAdmin]),gobang_id() {return this.gameBase._id},game_im_id() {return this.gameBase.im_romm_id},// 当前步数currentStep() {let result 0this.gobangList.forEach((item) {item.forEach((itey) {if (itey.step_number 0) {result 1}})})return result},getQi() {// 自己是黑棋还是白棋let { _id } this.userdataif (_id this.gameBase.bai_user_id) {return 白棋}if (_id this.gameBase.hei_user_id) {return 黑棋}return 观众},step_content() {// 具体下的内容 1白字 2黑子const obj {白棋: 1,黑棋: 2,}return obj[this.getQi] || 0},},created() {this.init()},methods: {del_gobang() {// 清空数据// this.gobangList []// this.isGameOver false// this.gameBase {// status: ,// max: 10,// max_move_time: 0,// all_time: 0,// hei_user_id: ,// bai_user_id: ,// }location.reload()},clearGame() {this.$confirm(确定要清空游戏吗).then((res) {this.$refs.imRef.send_msg({room_id: this.room_id,specialType: 3,gobang_id: this.gobang_id,})}).catch(() {})},// 黑棋先行一人一只下isShould() {let { currentStep, gobangList, step_content } this// 黑棋个数let heiNumber 0// 白棋个数let baiNumber 0// 遍历棋盘gobangList.forEach((aaa) {aaa.forEach((item) {if (item.step_content 1) {baiNumber 1}if (item.step_content 2) {heiNumber 1}})})// 判断现在下的步数的奇数还是偶数let isOdd currentStep % 2if (step_content 1) {// 白棋return isOdd 1}if (step_content 2) {// 黑棋return isOdd 0}},clickHandle({ x, y }) {let {step_content,room_id,gobang_id,userdata: { _id: author_id },currentStep,isGameOver,} thisif (isGameOver) {return this.$message.warning(游戏已结束)}// 只有棋手才能下棋if (![1, 2].includes(step_content)) return// 判断是否该下子if (!this.isShould()) {return this.$message.warning(请等待对方落子)}let obj {room_id,specialType: 2,gobang_id,gobang_member_id: author_id,step_number: currentStep 1,step_content,x,y,author_id,}this.$refs.imRef.send_msg(obj, () {})},room_baseinfo({ gobangMembers, room_id }) {this.gobangMembers Array.isArray(gobangMembers) ? gobangMembers : []this.room_id room_id || },initConfigList() {// 生成一个二维数组let { line } this.configfor (let i 0; i line; i) {this.gobangList.push([])for (let j 0; j line; j) {this.gobangList[i].push({x: i,y: j,step_content: 0, // 0: 空 1: 白 2: 黑})}}},async init() {this.initConfigList()let res nulltry {res await get_gobang_list()} catch (err) {return}if (res.data || this.isArray(res.data.data)) {if (res.data.data.length 0) {let res await post_gobang({game_name: 五子棋,}).catch(() {return {}})if (!res.data || !this.isObject(res.data.data)) returnObject.assign(this.gameBase,res.data.data)}if (res.data.data.length) {Object.assign(this.gameBase,res.data.data[0])}}// 获取现有的对局信息get_gobang({ gobang_id: this.gobang_id }).then((res) {if (res.data this.isArrayLength(res.data.data)) {let arr res.data.datathis.gobangList this.gobangList.map((aaa) {aaa aaa.map((item) {let { x, y } itemarr.find((itey) {let { step_content, step_number, gobang_member_id } iteyif (itey.x x 1 itey.y y 1 step_content) {Object.assign(item, {step_content,step_number,gobang_member_id,})return true}})return item})return aaa})console.log(this.gobangList)}}).catch(() {})},get_game_content(row) {this.gobangList this.gobangList.map((aaa) {aaa aaa.map((item) {let { x, y } itemlet { step_content, step_number, gobang_member_id } rowif (row.x x 1 row.y y 1 step_content) {Object.assign(item, {step_content,step_number,gobang_member_id,})}return item})return aaa})this.checkWin()},get_gb_info(row) {this.gameBase Object.assign(this.gameBase, row)console.log(get_gb_info,this.gameBase)},// 判断是否胜利 需要知道哪种棋子胜利checkWin() {// if(this.first) returnthis.first false// 判断当前棋盘是否有五子连珠let { line } this.configlet { gobangList: list } thislet type 0 // 0: 没有胜利 1: 白棋胜利 2: 黑棋胜利 3: 平局// 判断横向for (let i 0; i line; i) {for (let j 0; j line - 4; j) {if (list[i][j].step_content ! 0 list[i][j].step_content list[i][j 1].step_content list[i][j].step_content list[i][j 2].step_content list[i][j].step_content list[i][j 3].step_content list[i][j].step_content list[i][j 4].step_content) {type list[i][j].step_contentbreak}}}// 判断纵向for (let i 0; i line; i) {for (let j 0; j line - 4; j) {if (list[j][i].step_content ! 0 list[j][i].step_content list[j 1][i].step_content list[j][i].step_content list[j 2][i].step_content list[j][i].step_content list[j 3][i].step_content list[j][i].step_content list[j 4][i].step_content) {type list[j][i].step_contentbreak}}}// 判断左斜for (let i 0; i line - 4; i) {for (let j 0; j line - 4; j) {if (list[i][j].step_content ! 0 list[i][j].step_content list[i 1][j 1].step_content list[i][j].step_content list[i 2][j 2].step_content list[i][j].step_content list[i 3][j 3].step_content list[i][j].step_content list[i 4][j 4].step_content) {type list[i][j].step_contentbreak}}}// 判断右斜for (let i 0; i line - 4; i) {for (let j 4; j line; j) {if (list[i][j].step_content ! 0 list[i][j].step_content list[i 1][j - 1].step_content list[i][j].step_content list[i 2][j - 2].step_content list[i][j].step_content list[i 3][j - 3].step_content list[i][j].step_content list[i 4][j - 4].step_content) {type list[i][j].step_contentbreak}}}// 判断是否平局let flag truefor (let i 0; i line; i) {for (let j 0; j line; j) {if (list[i][j].step_content 0) {flag falsebreak}}}// 如果是平局if (flag) {type 3}const obj {1: 白棋胜利,2: 黑棋胜利,3: 平局,}if (obj[type]) {this.$message.success(obj[type])this.isGameOver true}},},
}
/scriptstyle langscss scoped/styleexpress代码
Gobang 为五子棋基本设置表 GobangMember 五子棋对战与观战人表 GobangItem 每一步的对战信息表
const { io } require(../../tool/socket.js);
const { AuthorInfo } require(../../mod/author/author_info);
const { ImRoom } require(../../mod/game/im_room.js);
const { ImRoomSys } require(../../mod/game/im_room_sys.js);
const { ImRoomMember } require(../../mod/game/im_room_member.js);
const { Game } require(../../mod/game/game.js);
const { GameList } require(../../mod/game/game_list.js);
const { Gobang } require(../../mod/game/gobang.js);
const { GobangMember } require(../../mod/game/gobang_member.js);
const { GobangItem } require(../../mod/game/gobang_item.js);let allSocket {};// 监听客户端的连接
io.on(connection, function (socket) {allSocket[socket.id] socket;// 监听用户掉线socket.on(disconnect, async () {// 更新用户状态let user await ImRoomMember.findOneAndUpdate({ socket_id: socket.id },{ status: 2 });if (user) {delete allSocket[user.im_room_id];// 这是触发的方法数组默认只有im的人员信息变化const funStatus [members_change];// 对于五子棋游戏相关退出房间操作try {let res await GobangMember.findOneAndUpdate({ socket_id: socket.id },{ status: 2 });// TODO: 这儿存在性能问题if (res.n 1) {funStatus.push(gobang_members_change);}} catch (err) {console.log(err);}// 向房间的用户同步信息sendMsgToRoom(user.im_room_id, null, funStatus);}});// 监听加入房间socket.on(join_room, async (data) {if (!global.isObject(data)) {resMsg(加入房间参数错误, 400);return;}// game_id 是游戏id只有游戏才需要传入let { user_id, room_id, gobang_id } data;if (!user_id) {resMsg(用户id不能为空, 400);return;}let user await AuthorInfo.findOne({ _id: user_id });if (!user) {resMsg(用户不存在, 400);return;}if (!room_id) {resMsg(房间id不能为空, 400);return;}let room await ImRoom.findOne({ _id: room_id, status: 1 });if (!room) {resMsg(房间不存在, 400);return;}let { max, status } room;if (status ! 1) {resMsg(房间未开放, 300);return;}// 查找所有加入该房间并且状态为在线的用户let members await ImRoomMember.find({im_room_id: room_id,status: 1,}).countDocuments();if (members max) {resMsg(房间已满, 300);return;}// 查找用户是否已经加入过该房间let oldUser await ImRoomMember.findOne({im_room_id: room_id,author_id: user_id,});if (!oldUser) {let res await new ImRoomMember({im_room_id: room_id,author_id: user_id,author_type: 2,created_time: getCurrentTimer(),updated_time: getCurrentTimer(),status: 1,socket_id: socket.id,}).save();if (!res) {resMsg(加入房间失败, 400);return;}} else {await ImRoomMember.updateOne({ im_room_id: room_id, author_id: user_id },{ socket_id: socket.id, status: 1 });}// 这是触发的方法数组默认只有im的人员信息变化const funStatus [members_change];// 对于五子棋游戏相关加入房间操作if (gobang_id) {let game await Gobang.findOne({ _id: gobang_id });if (!game) {resMsg(游戏不存在, 400);return;}// 查找用户是否已经加入过该游戏let oldUser await GobangMember.findOne({gobang_id,author_id: user_id,});if (!oldUser) {let res await new GobangMember({gobang_id,author_id: user_id,created_time: getCurrentTimer(),updated_time: getCurrentTimer(),status: 1,socket_id: socket.id,user_type: 3,}).save();if (!res) {resMsg(加入游戏失败, 400);return;}} else {try {await GobangMember.updateOne({ gobang_id, author_id: user_id },{ socket_id: socket.id, status: 1 });} catch (error) {console.log(err, err);}}// 查看是否需要更新游戏基本信息-黑棋与白棋let gameInfo await Gobang.findOne({ _id: gobang_id });if (gameInfo) {let { bai_user_id, hei_user_id } gameInfo;// 查看用户是否在线let baiUser await GobangMember.findOne({author_id: bai_user_id,gobang_id,});let heiUser await GobangMember.findOne({author_id: hei_user_id,gobang_id,});console.log(111,heiUser,baiUser)if (!heiUser) {await Gobang.updateOne({ _id: gobang_id }, { hei_user_id: user_id });} else if (!baiUser) {await Gobang.updateOne({ _id: gobang_id }, { bai_user_id: user_id });}}funStatus.push(get_gb);funStatus.push(gobang_members_change);}// 房间信息改变,向房间内所有在线用户推送房间信息sendMsgToRoom(room_id, null, funStatus, gobang_id);});// 主动推出登录socket.on(live_room, async (data) {let { room_id, user_id, gobang_id } data;// 更新用户状态let user await ImRoomMember.findOneAndUpdate({ im_room_id: room_id, author_id: user_id },{ status: 2 });if (user) {delete allSocket[user.socket_id];// 这是触发的方法数组默认只有im的人员信息变化const funStatus [members_change];if (gobang_id) {// 对于五子棋游戏相关退出房间操作try {await GobangMember.findOneAndUpdate({ gobang_id, author_id: user_id },{ status: 2 });} catch (err) {console.log(err);}funStatus.push(gobang_members_change);}// 向房间的用户同步信息sendMsgToRoom(room_id, null, funStatus, gobang_id);}});// 发送消息socket.on(send_msg, async (data) {if (!global.isObject(data)) return;// time是时长// specialType 默认1 im的发送消息2 五子棋的发送下棋消息 3 五子棋发送清空数据消息let {room_id,author_id,content,msg_type 1,time 0,poster ,video_width ,video_height ,specialType 1,gobang_id,gobang_member_id,step_number,step_content 0,x,y,} data;if (specialType 3) {// 有关五子棋的消息if (!gobang_id || !room_id) {resMsg(清空数据消息有字段缺失, 400, err, socket);return;}let gobang await Gobang.findOneAndDelete({ _id: gobang_id });if (!gobang) {resMsg(删除失败, 400, err, socket);return;}let { im_romm_id } gobang;// 删除人员await ImRoomMember.deleteMany({ gobang_id: gobang_id });// 删除对局信息await GobangItem.deleteMany({ gobang_id: gobang_id });// 删除聊天室await ImRoom.deleteOne({ _id: im_romm_id });// 删除聊天记录await ImRoomSys.deleteMany({ im_romm_id });// 删除聊天成员信息await ImRoomMember.deleteMany({ im_romm_id });console.log(111)sendMsgToRoom(room_id, null, [del_gobang], gobang_id);return}if (specialType 2) {// 有关五子棋的消息console.log(data);if (!room_id ||!gobang_id ||!gobang_member_id ||!gobang_member_id ||!step_number ||!x ||!y ||!author_id) {resMsg(下棋消息有字段缺失, 400, err, socket);return;}if (![1, 2].includes(step_content)) {resMsg(观众不能下棋, 400, err, socket);return;}let oldGb await GobangItem.findOne({gobang_id,step_number,});if (oldGb) {resMsg(您已经下过棋了, 400);return;}try {let newGb await new GobangItem({gobang_id,gobang_member_id: author_id,step_number,created_time: getCurrentTimer(),updated_time: getCurrentTimer(),step_content,x,y,}).save();sendMsgToRoom(room_id, newGb, [], gobang_id);} catch (err) {console.log(err);resMsg(保存步数失败, 400);return;}return;}if (!content) {resMsg(请输入内容, 400);return;}// 判断用户是否存在if (!author_id) {resMsg(用户id不能为空, 400);return;}let user await AuthorInfo.findOne({ _id: author_id });if (!user) {resMsg(用户id不能为空, 400);return;}// 判断房间是否存在if (!room_id) {resMsg(房间id不能为空, 400);return;}let room await ImRoom({ _id: room_id, status: 1 });if (!room) {resMsg(房间未开放, 400);return;}if (!content) {resMsg(消息内容不能为空, 400);return;}// 保存消息let params {im_room_id: room_id,author_id: author_id,content: content,msg_type,created_time: getCurrentTimer(),updated_time: getCurrentTimer(),};if (time) {params.time time;}if (msg_type 4) {if (poster) {params.poster poster;}if (video_width) {params.video_width video_width;}if (video_height) {params.video_height video_height;}}let room_sys await new ImRoomSys(params).save();if (!room_sys) {resMsg(保存消息失败, 400);return;}// 找出对应的成员信息let userinfo await AuthorInfo.findOne({ _id: author_id },{username: 1,header_img: 1,});if (!userinfo) {resMsg(用户信息不存在, 400);return;}room_sys.author_id userinfo;sendMsgToRoom(room_id, room_sys);});/*** 向一个房间内的所有在线用户推送房间的基本信息* row 本次聊天信息* name 触发事件的小别名* **/async function sendMsgToRoom(room_id, row null, names [], game_id ) {if (!room_id) return;// 找出全部在线的成员let members await ImRoomMember.find({im_room_id: room_id,status: 1,},{ socket_id: 1 });if (!members || members.length 0) return;let sockets members.map((item) item.socket_id);// 找出房间信息let room (await ImRoom.findOne({ _id: room_id, status: 1 })) || {};// 查找出当前房间的总消息数let roomSysCount await ImRoomSys.find({im_room_id: room_id,}).countDocuments();let res {data: room,roomSysCount,msg: 房间信息已更新,};if (names.length 0) {// 去重names [...new Set(names)];for (let i 0; i names.length; i) {const item names[i];switch (item) {case members_change:// 人员状态有变化let roomMembers await ImRoomMember.find({ im_room_id: room_id },{ author_id: 1, status: 1, room_username: 1 }).populate(author_id, username header_img).exec();res.roomMembers roomMembers;break;case gobang_members_change:// 五子棋人员状态有变化let gobangMembers await GobangMember.find({ gobang_id: game_id }).populate(author_id, username header_img).exec();Object.assign(res, {gobangMembers,});break;case get_gb:// 获取游戏的基本信息let gameInfo await Gobang.findOne({ _id: game_id });if (gameInfo) {res.gb_info gameInfo;}break;case del_gobang:res.is_del_gobang true;break;}}}if (global.isObject(row)) {if (game_id) {// 五子棋消息res.game_content row;} else {// im有新消息res.content row;}}sockets.forEach((item) {let socket allSocket[item];if (socket) {resMsg(res, 200, room_baseinfo, socket);}});}// 获取当前时间戳function getCurrentTimer() {return Date.now();}// 统一返回消息function resMsg(msg, code 400, name err, _socket) {let obj {code,};if (code 200) {obj.msg 操作成功;obj.data msg;} else {obj.msg msg;}socket _socket ? _socket : socket;socket.emit(name, obj);}
});