本次博客为是现代软件工程课程设计——黄金点游戏的第四次开发记录
阿薛 小姚
详细代码链接
项目目录
游戏规则
N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,裁判算出所有数字的平均值,然后乘以0.618 (所谓黄金分割常数),得到G值。提交的数字最靠近G(取绝对值)的同 学得到N分,离G最远的同学得到-2分,其他同学得0分。
项目需求
采用微信小程序实现,需要为用户提供便利的输入界面;
该游戏每次至少可以运行10轮以上,并能够保留各轮比赛结果;
后续在此基础上迭代开发。
设计思路
项目环境:uniapp & 微信开发者工具 1.03
项目基础:socket 编程 & Vue 架构
结果展示
登录授权
点击主页面中的"授权登录"按钮获取用户信息
如若曾经授权过(缓存中有授权信息则自动跳过本步骤)
新建房间
用户可以选择点击主页面中的"创建新房间"按钮来新建游戏房间,每个房间为独立的游戏空间
加入房间
用户也可以选择点击"进入房间"模块下的房间名称按钮,直接加入已经建立好的房间
进行游戏
用户在进入房间后可以通过在最下方的输入框中输入所选答案,确认无误后点击" ↑ 按钮"提交自己的答案,带所有用户输入完答案后将会在上方信息记录框图中显示各用户目前的累计得分
关键代码
主页面
界面部分
<template>
<view>
<view class="header">
<text class="title">Golden Point</text>
<text class="content">Challenge yourself</text>
</view>
<uni-popup ref="popup" type="dialog">
<uni-popup-dialog mode="input" placeholder="输入房间Id" title="输入" @confirm="check"></uni-popup-dialog>
</uni-popup>
<view class="bottom-box">
<button class="room-bottom" v-show="!hasUserInfo" open-type="getUserInfo" @getuserinfo="getUserInfo"> 授权登录 </button>
</view>
<view class="content" v-show="hasUserInfo">
<text class="title">新建房间</text>
<input :class='newRoomName == "" ? "input-notice uni-input" : "uni-input"' :value="newRoomName" placeholder="请输入房间名称"
@input="onInputRoomName">
<view class="bottom-box">
<text class="room-bottom" @click="open()">{{"创建新房间"}}
</text>
</view>
<text class="title">进入房间</text>
<view class="room-container">
<scroll-view scroll-y>
<view class="room-box">
<text class="room-box-item" v-for="(room, key) in roomList" :key="room.roomId" @click="onSelectRoom(room)">{{room.name}}
</text>
</view>
</scroll-view>
</view>
</view>
</view>
</template>
JavaScript部分
methods: {
onInputRoomName(event) { // 输入用户名
this.newRoomName = event.target.value;
},
open() {
this.$refs.popup.open()
},
check(done, value) {
console.log("check");
console.log(value);
this.newAddRoom = {
roomId: value,
name: this.newRoomName
};
this.roomList.push(this.newAddRoom);
console.log("roomList:");
console.log(this.roomList);
const db = wx.cloud.database({
env: 'rooms-7glacbsg9acdae52'
});
const _ = db.command
db.collection('totalRooms').doc("e62469b25fc1e8d3007d743e14cb82a2").set({
// data 传入需要局部更新的数据
data: {
RoomNumber: this.roomNum + 1,
roomInfo: this.roomList
},
success: function(res) {
console.log(res.data)
}
});
db.collection('totalRooms').add({
// data 字段表示需新增的 JSON 数据
data: {
roomId: value,
name: this.newRoomName
},
success: function(res) {
// res 是一个对象,其中有 _id 字段标记刚创建的记录的 id
console.log(res)
}
})
//this.$refs.popup.close();
done();
},
getUserInfo(infoRes) {
console.log(infoRes.target.userInfo);
uni.setStorage({ //缓存用户登陆状态
key: 'userInfo',
data: infoRes.userInfo
});
this.hasUserInfo = true;
this.nickname = infoRes.target.userInfo.nickName;
this.Avatar = infoRes.target.userInfo.avatarUrl;
},
onSelectRoom(room) { //登录
this.roomToken = {
roomId: room.roomId,
roomName: room.name,
userId: (Math.random() * 1000).toString(),
nickname: this.nickname,
avatar: this.Avatar
};
let roomTokenAsJsonString = JSON.stringify(this.roomToken)
uni.navigateTo({
url: "/pages/vue/chatroom/chatroom?roomToken=" + roomTokenAsJsonString
})
}
}
游戏房间页面
界面部分
<template>
<view class="chat-room">
<uni-popup ref="popupBottom" type="bottom">底部弹出 Popup</uni-popup>
<view class="online-avatar-container">
<view class="online-avatar-item" v-for="(user, key) in room.onlineUsers.users" :key="key"
:style="{transform:'translateX('+ (room.onlineUsers.users.length - key-1)*20 +'rpx' +')'}">
<image :src="user.avatar"></image>
</view>
<view class="online-count">{{room.onlineUsers.count}}</view>
</view>
<view class="chat-room-container">
<scroll-view class="chat-room-box" scroll-y="true" :scroll-into-view="contentPosition"
show-scrollbar="true">
<view class="message-box" v-for="(message, key) in room.messages" :key="key" :id="'message-box'+ key">
<view class="message-item">
<text class="user-name">{{message && message.senderNickname}}:</text>
<text :class="message.senderUserId == room.currentUser.id ? 'user-message self' : 'user-message' ">
{{message && message.content}}
</text>
</view>
</view>
</scroll-view>
<view class="chat-room-input">
<view style="position: relative;">
<input class="uni-input" :value="newMessageContent" placeholder="输入你的答案.." @input="onInputMessage"/>
<view class="uni-btn" @click="sendMessage(room.MessageType.CHAT, newMessageContent)">↑</view>
</view>
<image class="heart" @click=""
src="../../../static/images/check.svg"></image>
<image class="heart" @click="openPopup"
src="../../../static/images/log.svg"></image>
</view>
</view>
</view>
</template>
JavaScript部分
methods: {
onInputMessage(event) {//双向绑定消息 兼容
this.newMessageContent = event.target.value;
},
whenNewMessage(message) {//新消息监听
if (message.type == this.room.MessageType.PROP) {
this.propAnimation(parseInt(message.content))
}
setTimeout(() => {
this.contentPosition = 'message-box' + (this.room.messages.length - 1);
}, 300)
},
sendMessage(messageType, content) {//发送消息
if (content == "" && messageType == this.room.MessageType.CHAT) return;
var message = {
senderNickname: this.room.currentUser.nickname,
type: messageType,
content: content
}
this.chatRoomService.sendMessages(this.room.id, message);
this.newMessageContent = "";
},
openPopup() {//用于下一步的可视化弹窗实现
this.$refs.popupBottom.open()
}
}
socket通信
//获取实例
ChatRoomService.prototype.connectGoEasyIM = function () {
this.im = GoEasyIM.getInstance({
appkey: 'BC-a5c3bad2831e49ed8f9e25c98debb9bb',
host: 'hangzhou.goeasy.io'
});
//监听网络连接成功
this.im.on(GoEasyIM.EVENT.CONNECTED, () => {
console.log('服务器网络连接成功');
//连接成功后,更新在线用户数和用户头像
this.initialOnlineUsers(this.room.id);
});
//监听网络连接断开
this.im.on(GoEasyIM.EVENT.DISCONNECTED, () => {
console.log('服务器网络断开')
});
//监听上下线提醒
this.listenerGroupPresence();
//监听新消息
this.listenerNewMessage();
var currentUser = this.room.currentUser;
//连接服务器
this.im.connect({
id: currentUser.id,
data: {
avatar: currentUser.avatar,
nickname: currentUser.nickname
}
}).then(() => {
console.log('连接成功');
this.initialChatHistory(this.room.id);
//订阅用户上下线事件
this.subscribePresence(this.room.id);
//游戏房间消息
this.subscribeRoomMessage(this.room.id);
}).catch(e => {
console.log(e);
console.log('连接失败');
});
};
ChatRoomService.prototype.addNewMessage = function (message) {
var content = JSON.parse(message.payload.text);
var roomMessage = this.room.onlineUsers;
var currentUser = this.room.currentUser
var ifAllSubmit = 1;
var number = content.content;
console.log(message);
console.log(currentUser);
console.log(roomMessage);
console.log(number)
var countNum = 0;
var flag = 0;
if (!isNaN(number) && flag == 0){
for (var i=0;i<roomMessage.count;i++){
if (roomMessage.users[i].id == message.senderId){
roomMessage.users[i].ifsubmit = 1;
roomMessage.users[i].value = number;
break;
}
}
for (var i=0;i<roomMessage.count;i++){
if (roomMessage.users[i].ifsubmit == 0){
countNum = countNum + 1;
ifAllSubmit = 0;
}
}
if (ifAllSubmit == 1){
let messageContent = "";
var total = 0;
for (var i=0;i<roomMessage.count;i++){
total = total + parseFloat(roomMessage.users[i].value);
}
console.log("total: " + total);
var average = total / roomMessage.count;
average = average * 0.618;
console.log("average" + average);
console.log("count" + roomMessage.count);
var close = 101;
var far = 0;
var closeId = 0;
var farId = 0;
var diff = 0;
for (var i=0;i<roomMessage.count;i++){
diff = Math.abs(average - parseFloat(roomMessage.users[i].value));
console.log("value",roomMessage.users[i].value);
console.log("diff",diff);
if (diff > far){
far = diff;
farId = i;
}
if (diff < close){
close = diff;
closeId = i;
}
}
console.log("far",far);
console.log("close",close);
console.log("farId",farId);
console.log("closeId",closeId);
roomMessage.users[farId].score = roomMessage.users[farId].score - 2;
roomMessage.users[closeId].score = roomMessage.users[closeId].score + roomMessage.count;
for (var i=0;i<roomMessage.count;i++){
roomMessage.users[i].ifsubmit = 0;
messageContent = messageContent + roomMessage.users[i].nickname +": "+ roomMessage.users[i].score + "||";
}
//聊天消息
//console.log(this.room.onlineUsers);
//添加消息
let newMessage = new Message(roomMessage.users[0].id, "本轮结果: ", messageContent);
this.room.messages.push(newMessage);
let newMessage1 = new Message(roomMessage.users[0].id, "本轮结果: ", messageContent);
this.room.messages.push(newMessage);
//let newMessage = new Message(message.senderId, content.senderNickname, messageContent);
//this.room.messages.push(newMessage);
}else{
let newMessage = new Message(roomMessage.users[0].id, "等待其他玩家输入中", " 还有" + countNum +"名玩家未提交");
this.room.messages.push(newMessage);
//let newMessage = new Message(message.senderId, content.senderNickname, "等待其他玩家输入中.. " + "还有" + countNum +"名玩家未提交");
//this.room.messages.push(newMessage);
}
}else if (currentUser.id == message.senderId && flag == 0){
let newMessage = new Message(message.senderId, content.senderNickname, "请输入0-100内的自然数");
this.room.messages.push(newMessage);
}
};
//监听用户上下线
ChatRoomService.prototype.listenerGroupPresence = function () {
this.im.on(GoEasyIM.EVENT.GROUP_PRESENCE, (event) => {
//更新在线用户数
this.room.onlineUsers.count = event.groupOnlineCount;
if (event.action == 'join' || event.action == 'online') {
let userData = JSON.parse(event.userData);
//添加新用户
let user = new User(event.userId, userData.nickname, userData.avatar, "", 0, 0);
//添加在线用户,避免用户重复
if (!this.room.onlineUsers.users.find(item => item.id == event.userId)) {
this.room.onlineUsers.users.push(user);
}
//添加进入房间的消息
let message = new Message(event.userId, userData.nickname, " 进入房间", this.room.MessageType.CHAT);
this.room.messages.push(message);
} else {
let offlineUserIndex = this.room.onlineUsers.users.findIndex(item => item.id == event.userId);
if (offlineUserIndex > -1) {
//将离开的用户从onlineUsers中删掉
let offlineUser = Object.assign(this.room.onlineUsers.users[offlineUserIndex]);
this.room.onlineUsers.users.splice(offlineUserIndex, 1);
//添加离开消息
let message = new Message(offlineUser.id, offlineUser.nickname, " 离开房间", this.room.MessageType.CHAT)
this.room.messages.push(message);
}
}
this.whenOnlineUserChange(this.room.onlineUsers);
})
};
//查询和初始化在线用户列表和在线用户数
ChatRoomService.prototype.initialOnlineUsers = function (roomId) {
let self = this;
//查询最新上线的用户列表
this.im.groupHereNow(roomId)
.then(result => {
if (result.code == 200) {
let users = [];
result.content && result.content.map(function (onlineUser) {
let userData = JSON.parse(onlineUser.userData);
let user = new User(onlineUser.userId, userData.nickname, userData.avatar, "", 0, 0);
users.push(user);
});
self.room.onlineUsers = {
users: users
};
}
}).catch(e => {
if (e.code == 401) {
console.log("链接服务器功能失败");
} else {
console.log(e);
}
});
//获取游戏房间在线用户数
this.im.groupOnlineCount(roomId)
.then(result => {
this.room.onlineUsers.count = result.content.onlineCount;
}).catch(e => {
console.log(e)
})
};
//游戏房间成员上下线
ChatRoomService.prototype.subscribePresence = function (roomId) {
this.im.subscribeGroupPresence([roomId])
.then(() => {
console.log('成员上下线成功')
}).catch(e => {
console.log(e)
})
}