diff --git a/json/game_result_list.json b/json/game_result_list.json deleted file mode 100644 index 5cc772c..0000000 --- a/json/game_result_list.json +++ /dev/null @@ -1 +0,0 @@ -{"tblname":"game_result","alias":"game_result_list","params":{"sortby":"created_at desc","logined_userorgid":"user_id","browserfields":{"fields":[{"name":"id","width":90,"frozen":true},{"name":"game_id","title":"游戏","width":120},{"name":"score","title":"得分","width":80},{"name":"duration_ms","title":"时长ms","width":90},{"name":"level","title":"关卡","width":70},{"name":"created_at","title":"结算时间","width":160}],"exclouded":["session_id","result_json"]},"editexclouded":["id","session_id","user_id","game_id","result_json","created_at"],"editable":{"new_data_url":null,"update_data_url":null,"delete_data_url":null}} \ No newline at end of file diff --git a/json/game_session_list.json b/json/game_session_list.json deleted file mode 100644 index 06f8c90..0000000 --- a/json/game_session_list.json +++ /dev/null @@ -1 +0,0 @@ -{"tblname":"game_session","alias":"game_session_list","params":{"sortby":"updated_at desc","logined_userorgid":"user_id","new_data_url":"{{entire_url('/scense/game/api/game_start.dspy')}}","update_data_url":"{{entire_url('/scense/game/api/game_save.dspy')}}","delete_data_url":"{{entire_url('/scense/game/api/game_end.dspy')}}","browserfields":{"fields":[{"name":"id","width":90,"frozen":true},{"name":"game_name","title":"游戏名称","width":140},{"name":"status","title":"状态","width":90,"uitype":"code","data":[{"value":"created","text":"已创建"},{"value":"playing","text":"进行中"},{"value":"paused","text":"已暂停"},{"value":"ended","text":"已结束"}]},{"name":"score","title":"得分","width":80},{"name":"level","title":"关卡","width":70},{"name":"elapsed_ms","title":"时长ms","width":90},{"name":"updated_at","title":"更新时间","width":160}],"exclouded":["progress_json","share_token","world_id","created_at"]},"editexclouded":["id","user_id","game_id","share_token","created_at","updated_at","ended_at","progress_json"],"editable":{"new_data_url":"{{entire_url('/scense/game/api/game_start.dspy')}}","update_data_url":"{{entire_url('/scense/game/api/game_save.dspy')}}","delete_data_url":"{{entire_url('/scense/game/api/game_end.dspy')}}"}} \ No newline at end of file diff --git a/models/game_result.json b/models/game_result.json deleted file mode 100644 index ec9e1b0..0000000 --- a/models/game_result.json +++ /dev/null @@ -1 +0,0 @@ -{"summary":[{"table":"game_result","desc":"游戏结果表","pkey":"id","primary":["id"]}],"fields":[{"name":"id","type":"varchar","length":32,"desc":"结果ID","primary":true},{"name":"session_id","type":"varchar","length":32,"desc":"会话ID"},{"name":"user_id","type":"varchar","length":32,"desc":"用户ID"},{"name":"game_id","type":"varchar","length":64,"desc":"游戏标识"},{"name":"score","type":"int","length":11,"desc":"结算得分"},{"name":"duration_ms","type":"bigint","length":20,"desc":"游戏时长毫秒"},{"name":"level","type":"int","length":11,"desc":"结束关卡"},{"name":"result_json","type":"text","desc":"结果详情JSON"},{"name":"created_at","type":"datetime","desc":"结算时间"}],"indexes":[{"name":"idx_session","fields":["session_id"]},{"name":"idx_user_game","fields":["user_id","game_id"]}],"codes":[]} \ No newline at end of file diff --git a/models/game_session.json b/models/game_session.json deleted file mode 100644 index c4c45fb..0000000 --- a/models/game_session.json +++ /dev/null @@ -1 +0,0 @@ -{"summary":[{"table":"game_session","desc":"游戏会话表","pkey":"id","primary":["id"]}],"fields":[{"name":"id","type":"varchar","length":32,"desc":"会话ID","primary":true},{"name":"user_id","type":"varchar","length":32,"desc":"用户ID"},{"name":"game_id","type":"varchar","length":64,"desc":"游戏标识"},{"name":"game_name","type":"varchar","length":128,"desc":"游戏名称"},{"name":"status","type":"varchar","length":16,"desc":"会话状态 created/playing/paused/ended"},{"name":"score","type":"int","length":11,"desc":"当前得分"},{"name":"level","type":"int","length":11,"desc":"当前关卡"},{"name":"elapsed_ms","type":"bigint","length":20,"desc":"已玩时长毫秒"},{"name":"progress_json","type":"text","desc":"进度快照JSON"},{"name":"share_token","type":"varchar","length":64,"desc":"分享令牌"},{"name":"world_id","type":"varchar","length":64,"desc":"世界ID"},{"name":"created_at","type":"datetime","desc":"创建时间"},{"name":"updated_at","type":"datetime","desc":"更新时间"},{"name":"ended_at","type":"datetime","desc":"结束时间"}],"indexes":[{"name":"idx_user_status","fields":["user_id","status"]},{"name":"idx_user_game","fields":["user_id","game_id"]},{"name":"idx_share_token","fields":["share_token"]}],"codes":[{"field":"status","table":"appcodes","valuefield":"k","textfield":"v","cond":{"parentid":"game_session_status"}}]} \ No newline at end of file diff --git a/sql/game_ddl.sql b/sql/game_ddl.sql deleted file mode 100644 index 02245b7..0000000 --- a/sql/game_ddl.sql +++ /dev/null @@ -1,42 +0,0 @@ --- 元景 W-08 游戏展示模块 DDL(scense 应用库) --- 表:game_session(游戏会话) + game_result(游戏结果) - -CREATE TABLE IF NOT EXISTS `game_session` ( - `id` VARCHAR(32) NOT NULL COMMENT '会话ID', - `game_code` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '分享码', - `world_id` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '世界ID', - `user_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '用户ID', - `org_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '组织ID', - `status` VARCHAR(16) NOT NULL DEFAULT 'created' COMMENT '状态: created/playing/paused/ended', - `score` INT NOT NULL DEFAULT 0 COMMENT '分数', - `level` INT NOT NULL DEFAULT 1 COMMENT '关卡', - `elapsed_ms` INT NOT NULL DEFAULT 0 COMMENT '已玩毫秒', - `progress_json` TEXT COMMENT '进度快照', - `share_token` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '分享令牌', - `started_at` DATETIME DEFAULT NULL COMMENT '开始时间', - `paused_at` DATETIME DEFAULT NULL COMMENT '暂停时间', - `ended_at` DATETIME DEFAULT NULL COMMENT '结束时间', - `created_at` DATETIME NOT NULL COMMENT '创建时间', - `updated_at` DATETIME NOT NULL COMMENT '更新时间', - PRIMARY KEY (`id`), - KEY `idx_game_session_user` (`user_id`,`world_id`), - KEY `idx_game_session_code` (`game_code`), - KEY `idx_game_session_status` (`status`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='游戏会话'; - -CREATE TABLE IF NOT EXISTS `game_result` ( - `id` VARCHAR(32) NOT NULL COMMENT '结果ID', - `session_id` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '会话ID', - `game_code` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '分享码', - `world_id` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '世界ID', - `user_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '用户ID', - `org_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '组织ID', - `score` INT NOT NULL DEFAULT 0 COMMENT '最终分数', - `duration_ms` INT NOT NULL DEFAULT 0 COMMENT '游戏时长毫秒', - `level` INT NOT NULL DEFAULT 1 COMMENT '到达关卡', - `result_json` TEXT COMMENT '结算明细', - `created_at` DATETIME NOT NULL COMMENT '创建时间', - PRIMARY KEY (`id`), - KEY `idx_game_result_session` (`session_id`), - KEY `idx_game_result_user` (`user_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='游戏结果'; diff --git a/wwwroot/game/api/game_end.dspy b/wwwroot/game/api/game_end.dspy deleted file mode 100644 index 00cbb71..0000000 --- a/wwwroot/game/api/game_end.dspy +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -"""W-08e/g 结束结算:写 game_result 并返回结算结果(分数/时长/关卡展示)。""" -result = {'success': False, 'data': {}} -try: - user_id = await get_user() - session_id = params_kw.get('session_id', '') - if not session_id: - result['code'] = 400 - result['error'] = '缺少 session_id' - else: - score = params_kw.get('score', None) - duration_ms = params_kw.get('duration_ms', None) - level = params_kw.get('level', None) - result_json = params_kw.get('result_json', None) - data = await game_end_session(user_id, session_id, score=score, duration_ms=duration_ms, - level=level, result_json=result_json) - result['success'] = True - result['data'] = data -except ValueError as e: - result['code'] = 400 - result['error'] = str(e) -except Exception as e: - result['error'] = str(e) -return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/game/api/game_list.dspy b/wwwroot/game/api/game_list.dspy deleted file mode 100644 index 1397987..0000000 --- a/wwwroot/game/api/game_list.dspy +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python3 -"""W-08a 游戏列表入口:游戏目录 + 历史会话 + 历史结果。""" -result = {'success': False, 'data': {}} -try: - user_id = await get_user() - games = await game_list_games(user_id) - sessions = await game_list_sessions(user_id) - results = await game_list_results(user_id) - result['success'] = True - result['data'] = {'games': games, 'sessions': sessions, 'results': results} -except Exception as e: - result['error'] = str(e) -return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/game/api/game_pause.dspy b/wwwroot/game/api/game_pause.dspy deleted file mode 100644 index bd15c05..0000000 --- a/wwwroot/game/api/game_pause.dspy +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -"""W-08c 暂停:playing -> paused。""" -result = {'success': False, 'data': {}} -try: - user_id = await get_user() - session_id = params_kw.get('session_id', '') - if not session_id: - result['code'] = 400 - result['error'] = '缺少 session_id' - else: - data = await game_pause_session(user_id, session_id) - result['success'] = True - result['data'] = data -except ValueError as e: - result['code'] = 400 - result['error'] = str(e) -except Exception as e: - result['error'] = str(e) -return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/game/api/game_restart.dspy b/wwwroot/game/api/game_restart.dspy deleted file mode 100644 index e305f98..0000000 --- a/wwwroot/game/api/game_restart.dspy +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -"""W-08f 重新开始:任意状态 -> playing,重置分数/关卡/时长/进度。""" -result = {'success': False, 'data': {}} -try: - user_id = await get_user() - session_id = params_kw.get('session_id', '') - if not session_id: - result['code'] = 400 - result['error'] = '缺少 session_id' - else: - data = await game_restart_session(user_id, session_id) - result['success'] = True - result['data'] = data -except ValueError as e: - result['code'] = 400 - result['error'] = str(e) -except Exception as e: - result['error'] = str(e) -return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/game/api/game_resume.dspy b/wwwroot/game/api/game_resume.dspy deleted file mode 100644 index ffcd793..0000000 --- a/wwwroot/game/api/game_resume.dspy +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -"""W-08d 继续:paused -> playing。""" -result = {'success': False, 'data': {}} -try: - user_id = await get_user() - session_id = params_kw.get('session_id', '') - if not session_id: - result['code'] = 400 - result['error'] = '缺少 session_id' - else: - data = await game_resume_session(user_id, session_id) - result['success'] = True - result['data'] = data -except ValueError as e: - result['code'] = 400 - result['error'] = str(e) -except Exception as e: - result['error'] = str(e) -return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/game/api/game_save.dspy b/wwwroot/game/api/game_save.dspy deleted file mode 100644 index fa91386..0000000 --- a/wwwroot/game/api/game_save.dspy +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -"""W-08j 退出保存进度:保存进度快照(不改变状态)。""" -result = {'success': False, 'data': {}} -try: - user_id = await get_user() - session_id = params_kw.get('session_id', '') - if not session_id: - result['code'] = 400 - result['error'] = '缺少 session_id' - else: - progress_json = params_kw.get('progress_json', '') - score = params_kw.get('score', None) - level = params_kw.get('level', None) - elapsed_ms = params_kw.get('elapsed_ms', None) - data = await game_save_progress(user_id, session_id, progress_json=progress_json, - score=score, level=level, elapsed_ms=elapsed_ms) - result['success'] = True - result['data'] = data -except ValueError as e: - result['code'] = 400 - result['error'] = str(e) -except Exception as e: - result['error'] = str(e) -return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/game/api/game_share.dspy b/wwwroot/game/api/game_share.dspy deleted file mode 100644 index 1c837d8..0000000 --- a/wwwroot/game/api/game_share.dspy +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -"""W-08h 分享链接:生成/解析分享令牌。action=generate|parse""" -result = {'success': False, 'data': {}} -try: - user_id = await get_user() - action = params_kw.get('action', 'generate') - if action == 'parse': - token = params_kw.get('token', '') - data = await game_parse_share(token) - else: - session_id = params_kw.get('session_id', '') - if not session_id: - result['code'] = 400 - result['error'] = '缺少 session_id' - else: - data = await game_generate_share(user_id, session_id) - result['success'] = True - result['data'] = data -except ValueError as e: - result['code'] = 400 - result['error'] = str(e) -except Exception as e: - result['error'] = str(e) -return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/game/api/game_start.dspy b/wwwroot/game/api/game_start.dspy deleted file mode 100644 index a9776b0..0000000 --- a/wwwroot/game/api/game_start.dspy +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 -"""W-08b 点击开始玩:创建/恢复会话并进入运行态(返回 session 供前端初始化运行时)。""" -result = {'success': False, 'data': {}} -try: - user_id = await get_user() - game_id = params_kw.get('game_id', '') - session_id = params_kw.get('session_id', '') - world_id = params_kw.get('world_id', '') - if not game_id: - result['code'] = 400 - result['error'] = '缺少 game_id' - else: - data = await game_start_session(user_id, game_id, session_id, world_id) - result['success'] = True - result['data'] = data -except ValueError as e: - result['code'] = 400 - result['error'] = str(e) -except Exception as e: - result['error'] = str(e) -return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/game/game.js b/wwwroot/game/game.js deleted file mode 100644 index 2467f92..0000000 --- a/wwwroot/game/game.js +++ /dev/null @@ -1,347 +0,0 @@ -/* scense 全屏游戏页交互逻辑(独立 HTML 页内脚本,允许 fetch/setInterval) - * - * 依赖: - * - runtime.js(W-10 运行时引擎 RuntimeEngine)—— 世界初始化/实体状态/脚本调度/暂停恢复 - * - /scense/game/api/*.dspy(W-08 会话与结果) - * - * 功能点:W-08b 开始玩(进入运行态) / W-08c 暂停 / W-08d 继续 / - * W-08e 结束结算 / W-08f 重新开始 / W-08g 分数结果展示 / - * W-08h 分享链接 / W-08i 玩中交互(点选实体触发脚本) / W-08j 退出保存进度 - */ -(function () { - 'use strict'; - var CFG = {gameId: '', sessionId: '', shareToken: '', worldId: ''}; - var session = null; // 当前会话 - var engine = null; // W-10 RuntimeEngine 实例 - var score = 0; - var level = 1; - var startTs = 0; - var clockTimer = null; - var statusBar = null; - - function $id(id) { return document.getElementById(id); } - - /* API 基础路径:由页面 URL 推导(/scense/game/game_play.html -> /scense) */ - function apiBase() { - return window.location.pathname.replace(/\/game\/.*$/, ''); - } - - function setStatus(t) { - if (statusBar) { statusBar.textContent = t; statusBar.className = 'hud-status ' + (t === '运行中' ? 'ok' : ''); } - } - - function api(name, params) { - return fetch(apiBase() + '/game/api/' + name + '.dspy', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify(params || {}) - }).then(function (r) { return r.json(); }); - } - - function elapsedMs() { return startTs ? (Date.now() - startTs) : 0; } - - function refreshHud() { - $id('hud_score').textContent = score; - $id('hud_level').textContent = level; - } - - function startClock() { - if (clockTimer) clearInterval(clockTimer); - clockTimer = setInterval(function () { - var s = Math.floor(elapsedMs() / 1000); - var m = Math.floor(s / 60); s = s % 60; - $id('hud_time').textContent = (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s); - }, 500); - } - - /* ---------- W-08b 开始玩:初始化会话 + 进入运行态 ---------- */ - function startGame() { - setStatus('启动中…'); - api('game_start', {game_id: CFG.gameId, session_id: CFG.sessionId || '', world_id: CFG.worldId || ''}) - .then(function (res) { - if (!res || !res.success) { setStatus('启动失败: ' + (res && res.error || '未知错误')); return; } - session = res.data.session; - CFG.sessionId = session.session_id; - CFG.shareToken = session.share_token; - CFG.worldId = session.world_id; - score = session.score || 0; - level = session.level || 1; - startTs = Date.now() - (session.elapsed_ms || 0); - refreshHud(); - startClock(); - initEngine(); // 进入 W-10 运行态 - showPanel('hud'); - setStatus('运行中'); - enableControls(true); - }); - } - - /* ---------- W-10 运行时引擎初始化(runtime.js) ---------- */ - function initEngine() { - if (typeof RuntimeEngine === 'undefined') { - setStatus('运行时引擎未加载(runtime.js),降级独立模式'); - initDegradedEngine(); - return; - } - engine = new RuntimeEngine({ - worldId: CFG.worldId, - canvas: $id('game_canvas'), - onEntityClick: onEntityClick, // W-08i 玩中交互:点选实体 - onEntityState: onEntityState, - onScriptLog: onScriptLog, - onError: onEngineError - }); - engine.initWorld(CFG.worldId).then(function (info) { - setStatus('运行中' + (info && info.degraded ? '(独立模式)' : '')); - engine.start(); - }); - } - - /* 独立模式本地引擎(后端不可用时降级,W-10i) */ - function initDegradedEngine() { - var canvas = $id('game_canvas'); - var ctx = canvas && canvas.getContext('2d'); - var entities = [ - {id: 'hero', x: 60, y: 240, w: 40, h: 40, color: '#2563EB', state: 'idle', label: '英雄'}, - {id: 'chest', x: 400, y: 200, w: 36, h: 36, color: '#D97706', state: 'idle', label: '宝箱'}, - {id: 'slime', x: 260, y: 320, w: 34, h: 34, color: '#16A34A', state: 'idle', label: '史莱姆'} - ]; - engine = { - paused: false, - entities: entities, - start: function () { this.draw(); }, - stop: function () {}, - pause: function () { this.paused = true; }, - resume: function () { this.paused = false; this.draw(); }, - restart: function () { this.paused = false; this.draw(); }, - draw: function () { - if (!ctx) return; - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.fillStyle = '#F9FAFB'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - entities.forEach(function (e) { - ctx.fillStyle = e.color; - ctx.fillRect(e.x, e.y, e.w, e.h); - ctx.fillStyle = '#111827'; - ctx.font = '12px sans-serif'; - ctx.fillText(e.label + (e.state === 'active' ? ' ★' : ''), e.x - 4, e.y - 6); - }); - }, - findEntity: function (x, y) { - for (var i = entities.length - 1; i >= 0; i--) { - var e = entities[i]; - if (x >= e.x && x <= e.x + e.w && y >= e.y && y <= e.y + e.h) return e; - } - return null; - } - }; - if (canvas) canvas.onclick = function (ev) { - if (engine.paused) return; - var r = canvas.getBoundingClientRect(); - var ex = ev.clientX - r.left, ey = ev.clientY - r.top; - var ent = engine.findEntity(ex, ey); - if (ent) onEntityClick(ent); - }; - engine.draw(); - } - - /* ---------- W-08i 玩中交互:点选实体触发脚本逻辑 ---------- */ - function onEntityClick(entity) { - if (!entity) return; - if (engine && engine.paused) { setStatus('已暂停,请先继续'); return; } - // 得分规则:点击宝箱/史莱姆得 10 分并触发实体脚本(state 变化) - score += 10; - refreshHud(); - logLine('点击实体 ' + entity.label + '(' + entity.id + ')→ 触发脚本 action,得分 +10'); - if (engine && engine.dispatchEvent) { - engine.dispatchEvent({type: 'click', entity_id: entity.id, payload: {score: 10}}); - } else if (engine && engine.entities) { - var hit = null; - for (var i = 0; i < engine.entities.length; i++) { - if (engine.entities[i].id === entity.id) { hit = engine.entities[i]; break; } - } - if (hit) { hit.state = 'active'; engine.draw && engine.draw(); } - setTimeout(function () { if (hit) { hit.state = 'idle'; engine.draw && engine.draw(); } }, 800); - } - } - - function onEntityState(e) { - logLine('实体状态: ' + (e && (e.entity_id || e.id)) + ' -> ' + (e && e.state)); - } - - function onScriptLog(msg) { - logLine('脚本: ' + (msg && msg.message || msg || '')); - } - - function onEngineError(err) { - logLine('运行时错误: ' + (err && err.message || err || '') + '(已降级继续)'); - } - - function logLine(text) { - var box = $id('game_log'); - if (!box) return; - var line = document.createElement('div'); - line.textContent = '[' + new Date().toLocaleTimeString() + '] ' + text; - box.appendChild(line); - box.scrollTop = box.scrollHeight; - while (box.children.length > 60) box.removeChild(box.firstChild); - } - - /* ---------- W-08c 暂停 ---------- */ - function pauseGame() { - if (!session) return; - api('game_pause', {session_id: CFG.sessionId}).then(function (res) { - if (!res || !res.success) { setStatus('暂停失败: ' + (res && res.error)); return; } - if (engine && engine.pause) engine.pause(); - if (clockTimer) clearInterval(clockTimer); - setStatus('已暂停'); - $id('btn_pause').style.display = 'none'; - $id('btn_resume').style.display = 'inline-block'; - }); - } - - /* ---------- W-08d 继续 ---------- */ - function resumeGame() { - if (!session) return; - api('game_resume', {session_id: CFG.sessionId}).then(function (res) { - if (!res || !res.success) { setStatus('继续失败: ' + (res && res.error)); return; } - if (engine && engine.resume) engine.resume(); - startClock(); - setStatus('运行中'); - $id('btn_pause').style.display = 'inline-block'; - $id('btn_resume').style.display = 'none'; - }); - } - - /* ---------- W-08e/g 结束结算 ---------- */ - function endGame() { - if (!session) return; - var dur = elapsedMs(); - api('game_end', { - session_id: CFG.sessionId, score: score, duration_ms: dur, level: level, - result_json: JSON.stringify({actions: 'clicks', entities: engine ? (engine.entities || []).length : 0}) - }).then(function (res) { - if (!res || !res.success) { setStatus('结算失败: ' + (res && res.error)); return; } - if (engine && engine.stop) engine.stop(); - if (clockTimer) clearInterval(clockTimer); - var r = res.data.result; - $id('result_score').textContent = r.score; - $id('result_level').textContent = r.level; - $id('result_duration').textContent = Math.round(r.duration_ms / 1000) + ' 秒'; - $id('result_time').textContent = r.created_at; - showPanel('result'); - setStatus('已结束'); - enableControls(false); - }); - } - - /* ---------- W-08f 重新开始 ---------- */ - function restartGame() { - if (!session) return; - api('game_restart', {session_id: CFG.sessionId}).then(function (res) { - if (!res || !res.success) { setStatus('重开失败: ' + (res && res.error)); return; } - score = 0; level = 1; startTs = Date.now(); - refreshHud(); - if (engine && engine.restart) engine.restart(); else if (engine && engine.start) engine.start(); - startClock(); - showPanel('hud'); - enableControls(true); - $id('btn_pause').style.display = 'inline-block'; - $id('btn_resume').style.display = 'none'; - setStatus('运行中'); - }); - } - - /* ---------- W-08h 分享链接 ---------- */ - function shareGame() { - if (!session) return; - api('game_share', {action: 'generate', session_id: CFG.sessionId}).then(function (res) { - if (!res || !res.success) { setStatus('分享失败: ' + (res && res.error)); return; } - var url = location.origin + apiBase() + '/game/game_play.html?share_token=' + res.data.share_token; - $id('share_url').value = url; - $id('share_box').style.display = 'block'; - logLine('已生成分享链接'); - }); - } - - /* ---------- W-08j 退出保存进度 ---------- */ - function saveProgress() { - if (!session) return; - api('game_save', { - session_id: CFG.sessionId, progress_json: JSON.stringify({entities: (engine && engine.entities || []).length}), - score: score, level: level, elapsed_ms: elapsedMs() - }).then(function (res) { - if (res && res.success) { logLine('进度已保存'); } - }); - } - - function exitGame() { - saveProgress(); - setTimeout(function () { window.close(); }, 400); - } - - /* ---------- 分享链接进入(W-08h 解析 token) ---------- */ - function enterByShareToken(token) { - api('game_share', {action: 'parse', token: token}).then(function (res) { - if (!res || !res.success) { setStatus('分享链接无效: ' + (res && res.error)); return; } - CFG.gameId = res.data.game_id; - CFG.sessionId = res.data.session_id; - CFG.shareToken = token; - CFG.worldId = res.data.world_id || ''; - $id('page_title').textContent = '分享进入 · ' + res.data.game_name; - setStatus('已通过分享链接进入'); - startGame(); // 复用会话进入运行态 - }); - } - - /* ---------- UI 辅助 ---------- */ - function showPanel(name) { - ['hud', 'result'].forEach(function (p) { - $id('panel_' + p).style.display = (p === name) ? 'block' : 'none'; - }); - } - - function enableControls(on) { - ['btn_pause', 'btn_resume', 'btn_end', 'btn_restart', 'btn_share', 'btn_save', 'btn_exit'] - .forEach(function (id) { var b = $id(id); if (b) b.disabled = !on; }); - } - - function bindEvents() { - $id('btn_pause').onclick = pauseGame; - $id('btn_resume').onclick = resumeGame; - $id('btn_end').onclick = endGame; - $id('btn_restart').onclick = restartGame; - $id('btn_share').onclick = shareGame; - $id('btn_save').onclick = saveProgress; - $id('btn_exit').onclick = exitGame; - $id('btn_copy').onclick = function () { - var u = $id('share_url'); - u.select(); - try { document.execCommand('copy'); setStatus('已复制分享链接'); } catch (e) { setStatus('复制失败,请手动复制'); } - }; - $id('btn_result_again').onclick = restartGame; - $id('btn_result_back').onclick = exitGame; - window.addEventListener('beforeunload', function () { saveProgress(); }); - } - - /* ---------- 启动 ---------- */ - function boot() { - var qs = new URLSearchParams(location.search); - CFG.gameId = qs.get('game_id') || ''; - CFG.sessionId = qs.get('session_id') || ''; - statusBar = $id('hud_status'); - bindEvents(); - showPanel('hud'); - enableControls(false); - var token = qs.get('share_token'); - if (token) { enterByShareToken(token); return; } - if (CFG.gameId) { startGame(); return; } - setStatus('缺少 game_id / share_token'); - } - - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', boot); - } else { - boot(); - } -})(); diff --git a/wwwroot/game/game_list.js b/wwwroot/game/game_list.js deleted file mode 100644 index 70d81f5..0000000 --- a/wwwroot/game/game_list.js +++ /dev/null @@ -1,75 +0,0 @@ -/* scense 游戏列表入口页渲染(bricks 页面内 Html 脚本区调用) */ -window.scenseGameList = (function () { - function api(url, params) { - return fetch(url, { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify(params || {}) - }).then(function (r) { return r.json(); }); - } - - function base() { - return window.location.pathname.replace(/\/game\/.*$/, ''); - } - - function statusText(s) { - var map = {created: '已创建', playing: '进行中', paused: '已暂停', ended: '已结束'}; - return map[s] || s; - } - - function renderSessions(sessions) { - var box = document.getElementById('scense_session_list'); - if (!box) return; - if (!sessions || !sessions.length) { box.innerHTML = '
暂无历史会话
'; return; } - var html = ''; - sessions.forEach(function (s) { - html += '
' + - '
' + s.game_name + ' ' + - (s.score || 0) + ' 分 / Lv.' + (s.level || 1) + '
' + - '
' + - statusText(s.status) + '' + - '
'; - }); - box.innerHTML = html; - } - - function renderResults(results) { - var box = document.getElementById('scense_result_list'); - if (!box) return; - if (!results || !results.length) { box.innerHTML = '
暂无结算记录
'; return; } - var html = ''; - results.forEach(function (r) { - html += '
' + - '' + r.game_id + ' ' + r.created_at + '' + - '' + r.score + ' 分 · Lv.' + r.level + ' · ' + - Math.round(r.duration_ms / 1000) + 's
'; - }); - box.innerHTML = html; - } - - function load() { - api(base() + '/game/api/game_list.dspy', {}).then(function (res) { - if (res && res.success && res.data) { - renderSessions(res.data.sessions); - renderResults(res.data.results); - } - }); - } - - function startGame(gameId, sessionId) { - var url = base() + '/game/game_play.html?game_id=' + encodeURIComponent(gameId || ''); - if (sessionId) url += '&session_id=' + encodeURIComponent(sessionId); - window.open(url, '_blank'); - } - - return {api: api, load: load, startGame: startGame, renderSessions: renderSessions, renderResults: renderResults}; -})(); - -(function () { - if (window.bricks && window.bricks.app) { - setTimeout(function () { window.scenseGameList && window.scenseGameList.load(); }, 300); - } -})(); diff --git a/wwwroot/game/game_play.html b/wwwroot/game/game_play.html deleted file mode 100644 index 3b9b535..0000000 --- a/wwwroot/game/game_play.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - -元景 · 游戏展示 - - - -
-
- 🎮 世界探索 Demo - 分数 0 - 关卡 Lv.1 - 时长 00:00 - 加载中… -
- - - - - - - -
-
-
- -
-
- - -
-
-
-
-
-
-
-
-

🏁 游戏结算

-
最终得分0
-
到达关卡1
-
游戏时长0 秒
-
结算时间-
-
- - -
-
-
- - - - - diff --git a/wwwroot/game/index.ui b/wwwroot/game/index.ui deleted file mode 100644 index ffe1a26..0000000 --- a/wwwroot/game/index.ui +++ /dev/null @@ -1,24 +0,0 @@ -{"widgettype": "VBox", "options": {"width": "100%", "height": "100%", "padding": "16px", "backgroundColor": "#F5F7FA"}, "subwidgets": [ - {"widgettype": "Text", "options": {"label": "元景 · 游戏展示", "fontSize": "24px", "fontWeight": "bold", "color": "#1F2937"}}, - {"widgettype": "Html", "options": {"html": "
点击「开始玩」进入全屏游戏,支持暂停/继续/结束结算/重新开始/分享/保存进度
"}}, - {"widgettype": "ResponsableBox", "options": {"gap": "14px", "minWidth": "260px"}, "subwidgets": [ - {"widgettype": "VBox", "options": {"backgroundColor": "#FFFFFF", "padding": "18px", "borderRadius": "8px", "cursor": "pointer", "boxShadow": "0 1px 3px rgba(0,0,0,0.1)"}, - "binds": [{"wid": "self", "event": "click", "actiontype": "script", "script": "window.scenseGameList && scenseGameList.startGame('world_demo')"}], - "subwidgets": [ - {"widgettype": "Text", "options": {"label": "🎮 世界探索 Demo", "fontSize": "18px", "fontWeight": "bold"}}, - {"widgettype": "Text", "options": {"label": "点击实体触发脚本逻辑的世界演示游戏(依赖 W-10 运行时)", "color": "#6B7280", "fontSize": "13px", "marginTop": "6px"}}, - {"widgettype": "Text", "options": {"label": "▶ 开始玩", "color": "#2563EB", "fontSize": "14px", "fontWeight": "bold", "marginTop": "10px"}} - ]}, - {"widgettype": "VBox", "options": {"backgroundColor": "#FFFFFF", "padding": "18px", "borderRadius": "8px", "cursor": "pointer", "boxShadow": "0 1px 3px rgba(0,0,0,0.1)"}, - "binds": [{"wid": "self", "event": "click", "actiontype": "script", "script": "window.scenseGameList && scenseGameList.startGame('click_quest')"}], - "subwidgets": [ - {"widgettype": "Text", "options": {"label": "⚡ 点击冒险", "fontSize": "18px", "fontWeight": "bold"}}, - {"widgettype": "Text", "options": {"label": "点选移动实体触发脚本逻辑的冒险小游戏", "color": "#6B7280", "fontSize": "13px", "marginTop": "6px"}}, - {"widgettype": "Text", "options": {"label": "▶ 开始玩", "color": "#2563EB", "fontSize": "14px", "fontWeight": "bold", "marginTop": "10px"}} - ]} - ]}, - {"widgettype": "Text", "options": {"label": "历史会话", "fontSize": "17px", "fontWeight": "bold", "marginTop": "22px"}}, - {"widgettype": "Html", "id": "scense_session_box", "options": {"html": "
加载中…
"}}, - {"widgettype": "Text", "options": {"label": "历史结算", "fontSize": "17px", "fontWeight": "bold", "marginTop": "18px"}}, - {"widgettype": "Html", "id": "scense_result_box", "options": {"html": "
加载中…
"}} -]}