{ "widgettype": "VBox", "options": { "width": "100%", "height": "100%", "css": "filler" }, "subwidgets": [ { "widgettype": "HBox", "options": { "padding": "8px 12px", "gap": "8px", "alignItems": "center", "borderBottom": "1px solid #e5e7eb" }, "subwidgets": [ { "widgettype": "Text", "options": { "text": "🎮 游戏工作台", "cfontsize": 1.2, "fontWeight": "bold", "halign": "left" } }, { "widgettype": "Button", "id": "wb_new_game", "options": { "label": "+ 新建游戏" }, "binds": [ { "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "var pw=new bricks.PopupWindow({title:'新建游戏',cwidth:32,cheight:10,auto_open:true,id:'wb_ng_popup'});var vb=new bricks.VBox({padding:'12px',gap:'10px'});var inp=new bricks.UiText({name:'wb_ng_name',placeholder:'游戏名称',cwidth:28});var chk=new bricks.UiCheck({name:'wb_ng_shared',value:false,label:'世界共享'});vb.add_widget(inp);vb.add_widget(chk);var bt=new bricks.Button({label:'创建游戏',css:'primary'});bt.bind('click',function(){var n=inp.resultValue();if(!n||!n.trim())return;var b=new URLSearchParams();b.append('name',n.trim());b.append('description',chk.resultValue()?'shared':'independent');fetch('/scense_game/game/api/game_create.dspy',{method:'POST',body:b}).then(function(r){return r.json()}).then(function(r){var ms=bricks.getWidgetById('wb_msg',bricks.app);if(ms)ms.set_text(r.success?'✔ 游戏已创建,世界已自动建立':'✘ '+(r.message||'创建失败'));var w=bricks.getWidgetById('wb_ng_popup',bricks.app);if(w){w.dismiss();w.destroy()};var t=bricks.getWidgetById('wb_tree',bricks.app);if(t&&t.container){t.container.clear_widgets();t.get_children_data(t)}})});vb.add_widget(bt);pw.content_w.add_widget(vb);setTimeout(function(){var el=inp.dom_element?inp.dom_element.querySelector('input,textarea'):null;if(el)el.focus()},300)" } ] }, { "widgettype": "Text", "id": "wb_msg", "options": { "text": "选择对象树节点开始编程", "color": "#6b7280", "halign": "left" } }, { "widgettype": "Filler" }, { "widgettype": "Button", "id": "wb_test", "options": { "label": "▶ 测试(新窗口运行demo)", "css": "primary" }, "binds": [ { "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "var t=bricks.getWidgetById('wb_tree',bricks.app);var wid='';var gid='';if(t&&t.selected_node){var u=t.selected_node.user_data||{};gid=wb_state.game_id||'';if(u.obj_type==='world')wid=u.real_id;else{var w=t.container?null:null;var sel=t.selected_node;while(sel&&sel.parent_widget){if(sel.user_data&&sel.user_data.obj_type==='world'){wid=sel.user_data.real_id;break}sel=sel.parent_widget}}}if(!wid){var ms=bricks.getWidgetById('wb_msg',bricks.app);if(ms)ms.set_text('请先选中一个世界节点再测试');return}window.open('/scense_demo/demo_viewer.ui?world_id='+encodeURIComponent(wid)+'&game_id='+encodeURIComponent(gid),'_blank')" } ] } ] }, { "widgettype": "HBox", "options": { "css": "filler", "width": "100%" }, "subwidgets": [ { "widgettype": "VBox", "options": { "width": "280px", "borderRight": "1px solid #e5e7eb", "padding": "8px" }, "subwidgets": [ { "widgettype": "HBox", "options": { "gap": "6px", "alignItems": "center", "marginBottom": "6px" }, "subwidgets": [ { "widgettype": "Text", "options": { "text": "对象树", "fontWeight": "bold", "halign": "left" } }, { "widgettype": "Filler" }, { "widgettype": "Button", "options": { "label": "+场景", "css": "small" }, "binds": [ { "wid": "self", "event": "click", "actiontype": "script", "target": "self", "params": { "add_type": "scene", "scene_id": "", "hint": "新场景将加入当前游戏的世界下" }, "script": "window.wb_state=window.wb_state||{};var wb_state=window.wb_state;window.wb_add_type=params.add_type;window.wb_add_scene_id=params.scene_id||'';var pw=new bricks.PopupWindow({title:params.add_type==='scene'?'添加场景':'添加实体',cwidth:28,cheight:8,auto_open:true,id:'wb_add_popup'});var vb=new bricks.VBox({padding:'12px',gap:'10px'});var inp=new bricks.UiText({name:'wb_add_name',placeholder:'输入名称',cwidth:24});vb.add_widget(new bricks.Text({text:params.hint,halign:'left'}));vb.add_widget(inp);var bt=new bricks.Button({label:'添加',css:'primary'});bt.bind('click',function(){window.wb_state=window.wb_state||{};var wb_state=window.wb_state;var inp=bricks.getWidgetById('wb_add_name',bricks.app);var name=inp?inp.resultValue():'';if(!name||!name.trim()){return}var b=new URLSearchParams();b.append('game_id',wb_state.game_id||'');b.append('scene_id',wb_add_scene_id||'');b.append('name',name.trim());var url=wb_add_type==='scene'?'/scense_game/game/api/scene_add.dspy':'/scense_game/game/api/entity_add.dspy';fetch(url,{method:'POST',body:b}).then(function(r){return r.json()}).then(function(r){var ms=bricks.getWidgetById('wb_msg',bricks.app);if(ms)ms.set_text(r.success?'✔ 已添加':'✘ '+(r.message||'添加失败'));var w=bricks.getWidgetById('wb_add_popup',bricks.app);if(w){w.dismiss();w.destroy()};var t=bricks.getWidgetById('wb_tree',bricks.app);if(t&&t.container){t.container.clear_widgets();t.get_children_data(t)}})});vb.add_widget(bt);pw.content_w.add_widget(vb);setTimeout(function(){var el=inp.dom_element?inp.dom_element.querySelector('input,textarea'):null;if(el)el.focus()},300)" } ] }, { "widgettype": "Button", "options": { "label": "+实体", "css": "small" }, "binds": [ { "wid": "self", "event": "click", "actiontype": "script", "target": "self", "params": { "add_type": "entity", "scene_id": "", "hint": "选中场景节点则加入该场景,否则为世界级实体" }, "script": "window.wb_state=window.wb_state||{};var wb_state=window.wb_state;window.wb_add_type=params.add_type;window.wb_add_scene_id=(window.wb_state&&window.wb_state.obj_type==='scene')?window.wb_state.obj_id:(params.scene_id||'');var pw=new bricks.PopupWindow({title:params.add_type==='scene'?'添加场景':'添加实体',cwidth:28,cheight:8,auto_open:true,id:'wb_add_popup'});var vb=new bricks.VBox({padding:'12px',gap:'10px'});var inp=new bricks.UiText({name:'wb_add_name',placeholder:'输入名称',cwidth:24});vb.add_widget(new bricks.Text({text:params.hint,halign:'left'}));vb.add_widget(inp);var bt=new bricks.Button({label:'添加',css:'primary'});bt.bind('click',function(){window.wb_state=window.wb_state||{};var wb_state=window.wb_state;var inp=bricks.getWidgetById('wb_add_name',bricks.app);var name=inp?inp.resultValue():'';if(!name||!name.trim()){return}var b=new URLSearchParams();b.append('game_id',wb_state.game_id||'');b.append('scene_id',wb_add_scene_id||'');b.append('name',name.trim());var url=wb_add_type==='scene'?'/scense_game/game/api/scene_add.dspy':'/scense_game/game/api/entity_add.dspy';fetch(url,{method:'POST',body:b}).then(function(r){return r.json()}).then(function(r){var ms=bricks.getWidgetById('wb_msg',bricks.app);if(ms)ms.set_text(r.success?'✔ 已添加':'✘ '+(r.message||'添加失败'));var w=bricks.getWidgetById('wb_add_popup',bricks.app);if(w){w.dismiss();w.destroy()};var t=bricks.getWidgetById('wb_tree',bricks.app);if(t&&t.container){t.container.clear_widgets();t.get_children_data(t)}})});vb.add_widget(bt);pw.content_w.add_widget(vb);setTimeout(function(){var el=inp.dom_element?inp.dom_element.querySelector('input,textarea'):null;if(el)el.focus()},300)" } ] } ] }, { "widgettype": "VScrollPanel", "options": { "css": "filler" }, "subwidgets": [ { "widgettype": "Tree", "id": "wb_tree", "options": { "dataurl": "{{entire_url('/scense_game/workbench/api/tree.dspy')}}", "method": "POST", "idField": "id", "textField": "text", "select_only": true, "title": "" }, "binds": [ { "wid": "self", "event": "node_selected", "actiontype": "script", "target": "self", "script": "window.wb_state=window.wb_state||{};var wb_state=window.wb_state;var t=bricks.getWidgetById('wb_tree',bricks.app);if(!event.params||!event.params.id)return;var ot=event.params.obj_type||'';var oid=event.params.real_id||'';var lbl=bricks.getWidgetById('wb_cur_obj',bricks.app);if(lbl)lbl.set_text(({'game':'🎮 游戏','world':'🌍 世界','scene':'🎬 场景','entity':'📦 实体'})[ot]+' · '+event.params.text);wb_state.obj_type=ot;wb_state.obj_id=oid;wb_state.game_id=(ot==='game')?oid:(event.params.game_id||wb_state.game_id);var es=bricks.getWidgetById('wb_event_sel',bricks.app);var evt=es?es.resultValue():'event_start';if(!oid)return;var b=new URLSearchParams();b.append('obj_type',ot);b.append('obj_id',oid);b.append('trigger_event',evt);fetch('/scense_game/workbench/api/load_script.dspy',{method:'POST',body:b}).then(function(r){return r.json()}).then(function(r){var ed=bricks.getWidgetById('wb_code',bricks.app);if(ed&&r.success){ed.set_value(r.data?r.data.content:'')}})" } ] } ] } ] }, { "widgettype": "VBox", "options": { "css": "filler", "padding": "10px", "gap": "8px" }, "subwidgets": [ { "widgettype": "HBox", "options": { "gap": "10px", "alignItems": "center" }, "subwidgets": [ { "widgettype": "Text", "id": "wb_cur_obj", "options": { "text": "未选择对象", "fontWeight": "bold", "halign": "left" } }, { "widgettype": "UiCode", "id": "wb_event_sel", "options": { "name": "wb_event_sel", "data": [ { "value": "event_start", "text": "事件:开始" }, { "value": "event_click", "text": "事件:点击" }, { "value": "event_timer", "text": "事件:定时" }, { "value": "event_collision", "text": "事件:碰撞" } ], "valueField": "value", "textField": "text", "cwidth": 10 } }, { "widgettype": "Filler" }, { "widgettype": "Button", "options": { "label": "校验" }, "binds": [ { "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "var ms=bricks.getWidgetById('wb_msg',bricks.app);var ed=bricks.getWidgetById('wb_code',bricks.app);var code=ed?ed.get_value():'';var b=new URLSearchParams();b.append('content',code);fetch('/script_engine/api/validate_script.dspy',{method:'POST',body:b}).then(function(r){return r.json()}).then(function(r){if(ms)ms.set_text(r.success!==false?'✔ 语法校验通过':'✘ '+(r.error||r.message||'校验失败'))})" } ] }, { "widgettype": "Button", "options": { "label": "💾 保存脚本", "css": "primary" }, "binds": [ { "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "window.wb_state=window.wb_state||{};var wb_state=window.wb_state;var ms=bricks.getWidgetById('wb_msg',bricks.app);if(!wb_state.obj_id){if(ms)ms.set_text('先在左侧树选择对象');return}var es=bricks.getWidgetById('wb_event_sel',bricks.app);var evt=es?es.resultValue():'event_start';var ed=bricks.getWidgetById('wb_code',bricks.app);var code=ed?ed.get_value():'';var b=new URLSearchParams();b.append('obj_type',wb_state.obj_type);b.append('obj_id',wb_state.obj_id);b.append('game_id',wb_state.game_id||'');b.append('trigger_event',evt);b.append('content',code);fetch('/scense_game/workbench/api/save_script.dspy',{method:'POST',body:b}).then(function(r){return r.json()}).then(function(r){if(ms)ms.set_text(r.success?'✔ 脚本已保存':'✘ '+(r.message||'保存失败'))})" } ] } ] }, { "widgettype": "CodeEditor", "id": "wb_code", "options": { "css": "filler", "mode": "python", "value": "# 选择左侧对象后,为它的事件编写逻辑脚本" } } ] } ] } ] }