新建项目
This commit is contained in:
116
pages/create/create.js
Normal file
116
pages/create/create.js
Normal file
@@ -0,0 +1,116 @@
|
||||
const service = require("../../services/game-service");
|
||||
const { GAME_MODES, DEFAULT_SETTINGS } = require("../../utils/constants");
|
||||
|
||||
Page({
|
||||
data: {
|
||||
name: "周末藏猫猫",
|
||||
mode: DEFAULT_SETTINGS.mode,
|
||||
modes: Object.values(GAME_MODES),
|
||||
durationOptions: [15, 20, 30, 45, 60],
|
||||
durationIndex: 2,
|
||||
prepareOptions: [1, 3, 5, 8],
|
||||
prepareIndex: 1,
|
||||
maxPlayerOptions: [4, 6, 8, 10, 12, 20],
|
||||
maxPlayerIndex: 2,
|
||||
seekerOptions: [1, 2, 3, 4],
|
||||
seekerIndex: 1,
|
||||
clueOptions: [3, 5, 8, 10],
|
||||
clueIndex: 1,
|
||||
radiusOptions: [200, 300, 500, 800, 1000],
|
||||
radiusIndex: 2,
|
||||
skillsEnabled: true,
|
||||
safetyAccepted: false,
|
||||
submitting: false
|
||||
},
|
||||
|
||||
updateName(event) {
|
||||
this.setData({ name: event.detail.value });
|
||||
},
|
||||
|
||||
chooseMode(event) {
|
||||
this.setData({ mode: event.currentTarget.dataset.mode });
|
||||
},
|
||||
|
||||
onDurationChange(event) {
|
||||
this.setData({ durationIndex: Number(event.detail.value) });
|
||||
},
|
||||
|
||||
onPrepareChange(event) {
|
||||
this.setData({ prepareIndex: Number(event.detail.value) });
|
||||
},
|
||||
|
||||
onMaxPlayerChange(event) {
|
||||
const maxPlayerIndex = Number(event.detail.value);
|
||||
const maxPlayers = this.data.maxPlayerOptions[maxPlayerIndex];
|
||||
let seekerIndex = this.data.seekerIndex;
|
||||
while (
|
||||
seekerIndex > 0 &&
|
||||
this.data.seekerOptions[seekerIndex] >= maxPlayers
|
||||
) {
|
||||
seekerIndex -= 1;
|
||||
}
|
||||
this.setData({ maxPlayerIndex, seekerIndex });
|
||||
},
|
||||
|
||||
onSeekerChange(event) {
|
||||
const seekerIndex = Number(event.detail.value);
|
||||
const seekers = this.data.seekerOptions[seekerIndex];
|
||||
const maxPlayers = this.data.maxPlayerOptions[this.data.maxPlayerIndex];
|
||||
if (seekers >= maxPlayers) {
|
||||
wx.showToast({ title: "寻找者必须少于人数上限", icon: "none" });
|
||||
return;
|
||||
}
|
||||
this.setData({ seekerIndex });
|
||||
},
|
||||
|
||||
onClueChange(event) {
|
||||
this.setData({ clueIndex: Number(event.detail.value) });
|
||||
},
|
||||
|
||||
onRadiusChange(event) {
|
||||
this.setData({ radiusIndex: Number(event.detail.value) });
|
||||
},
|
||||
|
||||
onSkillsChange(event) {
|
||||
this.setData({ skillsEnabled: event.detail.value });
|
||||
},
|
||||
|
||||
onSafetyChange(event) {
|
||||
this.setData({ safetyAccepted: event.detail.value.length > 0 });
|
||||
},
|
||||
|
||||
openRules() {
|
||||
wx.navigateTo({ url: "/pages/rules/rules" });
|
||||
},
|
||||
|
||||
submit() {
|
||||
if (!this.data.name.trim()) {
|
||||
wx.showToast({ title: "请填写房间名称", icon: "none" });
|
||||
return;
|
||||
}
|
||||
if (!this.data.safetyAccepted) {
|
||||
wx.showToast({ title: "请先确认安全规则", icon: "none" });
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({ submitting: true });
|
||||
const data = this.data;
|
||||
try {
|
||||
const room = service.createRoom({
|
||||
name: data.name.trim(),
|
||||
mode: data.mode,
|
||||
durationMinutes: data.durationOptions[data.durationIndex],
|
||||
prepareMinutes: data.prepareOptions[data.prepareIndex],
|
||||
maxPlayers: data.maxPlayerOptions[data.maxPlayerIndex],
|
||||
seekerCount: data.seekerOptions[data.seekerIndex],
|
||||
clueIntervalMinutes: data.clueOptions[data.clueIndex],
|
||||
radiusMeters: data.radiusOptions[data.radiusIndex],
|
||||
skillsEnabled: data.skillsEnabled
|
||||
});
|
||||
wx.redirectTo({ url: `/pages/lobby/lobby?code=${room.code}` });
|
||||
} catch (error) {
|
||||
this.setData({ submitting: false });
|
||||
wx.showToast({ title: error.message, icon: "none" });
|
||||
}
|
||||
}
|
||||
});
|
||||
3
pages/create/create.json
Normal file
3
pages/create/create.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationBarTitleText": "创建游戏"
|
||||
}
|
||||
148
pages/create/create.wxml
Normal file
148
pages/create/create.wxml
Normal file
@@ -0,0 +1,148 @@
|
||||
<view class="page">
|
||||
<view class="eyebrow">CREATE A GAME</view>
|
||||
<view class="title">设置这场追逃</view>
|
||||
<view class="subtitle">先用推荐规则开局,之后可以在候场页继续调整。</view>
|
||||
|
||||
<view class="section-label">房间名称</view>
|
||||
<view class="input-card">
|
||||
<input
|
||||
maxlength="16"
|
||||
value="{{name}}"
|
||||
placeholder="给这场游戏起个名字"
|
||||
bindinput="updateName"
|
||||
/>
|
||||
<text>{{name.length}}/16</text>
|
||||
</view>
|
||||
|
||||
<view class="section-label">游戏模式</view>
|
||||
<view
|
||||
wx:for="{{modes}}"
|
||||
wx:key="id"
|
||||
class="mode-card {{mode === item.id ? 'selected' : ''}}"
|
||||
data-mode="{{item.id}}"
|
||||
bindtap="chooseMode"
|
||||
>
|
||||
<view class="mode-icon">{{item.icon}}</view>
|
||||
<view class="mode-main">
|
||||
<view class="mode-name">{{item.name}}</view>
|
||||
<view class="mode-description">{{item.description}}</view>
|
||||
</view>
|
||||
<view class="radio">{{mode === item.id ? '✓' : ''}}</view>
|
||||
</view>
|
||||
|
||||
<view class="section-label">基础规则</view>
|
||||
<view class="settings-card">
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{durationOptions}}"
|
||||
value="{{durationIndex}}"
|
||||
bindchange="onDurationChange"
|
||||
>
|
||||
<view class="setting-row">
|
||||
<view>
|
||||
<view class="setting-name">游戏时长</view>
|
||||
<view class="setting-hint">正式追逃阶段</view>
|
||||
</view>
|
||||
<view class="setting-value">{{durationOptions[durationIndex]}} 分钟 ›</view>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{prepareOptions}}"
|
||||
value="{{prepareIndex}}"
|
||||
bindchange="onPrepareChange"
|
||||
>
|
||||
<view class="setting-row">
|
||||
<view>
|
||||
<view class="setting-name">躲藏准备</view>
|
||||
<view class="setting-hint">寻找者原地等待</view>
|
||||
</view>
|
||||
<view class="setting-value">{{prepareOptions[prepareIndex]}} 分钟 ›</view>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{maxPlayerOptions}}"
|
||||
value="{{maxPlayerIndex}}"
|
||||
bindchange="onMaxPlayerChange"
|
||||
>
|
||||
<view class="setting-row">
|
||||
<view>
|
||||
<view class="setting-name">人数上限</view>
|
||||
<view class="setting-hint">至少 4 人开局</view>
|
||||
</view>
|
||||
<view class="setting-value">{{maxPlayerOptions[maxPlayerIndex]}} 人 ›</view>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{seekerOptions}}"
|
||||
value="{{seekerIndex}}"
|
||||
bindchange="onSeekerChange"
|
||||
>
|
||||
<view class="setting-row">
|
||||
<view>
|
||||
<view class="setting-name">初始寻找者</view>
|
||||
<view class="setting-hint">建议约占总人数 1/4</view>
|
||||
</view>
|
||||
<view class="setting-value">{{seekerOptions[seekerIndex]}} 人 ›</view>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{clueOptions}}"
|
||||
value="{{clueIndex}}"
|
||||
bindchange="onClueChange"
|
||||
>
|
||||
<view class="setting-row">
|
||||
<view>
|
||||
<view class="setting-name">位置线索</view>
|
||||
<view class="setting-hint">只广播模糊区域</view>
|
||||
</view>
|
||||
<view class="setting-value">每 {{clueOptions[clueIndex]}} 分钟 ›</view>
|
||||
</view>
|
||||
</picker>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{radiusOptions}}"
|
||||
value="{{radiusIndex}}"
|
||||
bindchange="onRadiusChange"
|
||||
>
|
||||
<view class="setting-row">
|
||||
<view>
|
||||
<view class="setting-name">活动半径</view>
|
||||
<view class="setting-hint">原型暂以文字展示</view>
|
||||
</view>
|
||||
<view class="setting-value">{{radiusOptions[radiusIndex]}} 米 ›</view>
|
||||
</view>
|
||||
</picker>
|
||||
<view class="setting-row no-border">
|
||||
<view>
|
||||
<view class="setting-name">启用角色技能</view>
|
||||
<view class="setting-hint">雷达、静默等轻量能力</view>
|
||||
</view>
|
||||
<switch
|
||||
color="#1d6b4f"
|
||||
checked="{{skillsEnabled}}"
|
||||
bindchange="onSkillsChange"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<checkbox-group class="safety-check" bindchange="onSafetyChange">
|
||||
<label>
|
||||
<checkbox value="accepted" color="#1d6b4f" />
|
||||
<text>我已确认场地安全,并同意</text>
|
||||
<text class="link" catchtap="openRules">《户外游戏安全规则》</text>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
|
||||
<button
|
||||
class="primary-button"
|
||||
loading="{{submitting}}"
|
||||
disabled="{{submitting}}"
|
||||
bindtap="submit"
|
||||
>
|
||||
创建房间
|
||||
</button>
|
||||
</view>
|
||||
129
pages/create/create.wxss
Normal file
129
pages/create/create.wxss
Normal file
@@ -0,0 +1,129 @@
|
||||
.input-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10rpx 26rpx;
|
||||
background: #fffdf7;
|
||||
border: 2rpx solid rgba(23, 35, 29, 0.1);
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
.input-card input {
|
||||
flex: 1;
|
||||
height: 86rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.input-card text {
|
||||
color: #8b938e;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.mode-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 22rpx;
|
||||
margin-bottom: 18rpx;
|
||||
padding: 26rpx;
|
||||
background: #fffdf7;
|
||||
border: 3rpx solid transparent;
|
||||
border-radius: 26rpx;
|
||||
}
|
||||
|
||||
.mode-card.selected {
|
||||
border-color: #1d6b4f;
|
||||
background: #f2f8ef;
|
||||
}
|
||||
|
||||
.mode-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 74rpx;
|
||||
height: 74rpx;
|
||||
background: #d9ef72;
|
||||
border-radius: 22rpx;
|
||||
font-size: 36rpx;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.mode-main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mode-name {
|
||||
font-size: 29rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.mode-description {
|
||||
margin-top: 8rpx;
|
||||
color: #68726c;
|
||||
font-size: 23rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.radio {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 42rpx;
|
||||
height: 42rpx;
|
||||
border: 2rpx solid #9ba39e;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.selected .radio {
|
||||
background: #1d6b4f;
|
||||
border-color: #1d6b4f;
|
||||
}
|
||||
|
||||
.settings-card {
|
||||
padding: 0 26rpx;
|
||||
background: #fffdf7;
|
||||
border-radius: 28rpx;
|
||||
}
|
||||
|
||||
.setting-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 120rpx;
|
||||
border-bottom: 2rpx solid rgba(23, 35, 29, 0.07);
|
||||
}
|
||||
|
||||
.setting-row.no-border {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.setting-name {
|
||||
font-size: 27rpx;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.setting-hint {
|
||||
margin-top: 7rpx;
|
||||
color: #8b938e;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.setting-value {
|
||||
color: #1d6b4f;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.safety-check {
|
||||
margin: 32rpx 4rpx;
|
||||
color: #68726c;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.safety-check checkbox {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #1d6b4f;
|
||||
}
|
||||
Reference in New Issue
Block a user