|
|
@@ -58,9 +58,9 @@
|
|
|
|
|
|
<!-- Blockly工作区 -->
|
|
|
<div class="blockly-section">
|
|
|
- <div class="toolbox-section">
|
|
|
+ <div class="toolbox-section" style="display: none;">
|
|
|
<h2>工具箱</h2>
|
|
|
- <div id="toolbox" style="display: none;">
|
|
|
+ <div id="toolbox">
|
|
|
<!-- 移动控制积木 -->
|
|
|
<category name="移动控制" colour="%{BKY_MOTION_HUE}">
|
|
|
<block type="move_forward"></block>
|
|
|
@@ -84,7 +84,7 @@
|
|
|
<block type="controls_repeat_ext">
|
|
|
<value name="TIMES">
|
|
|
<shadow type="math_number">
|
|
|
- <field name="NUM">5</field>
|
|
|
+ <field name="NUM"></field>
|
|
|
</shadow>
|
|
|
</value>
|
|
|
</block>
|
|
|
@@ -95,34 +95,19 @@
|
|
|
<category name="数学" colour="%{BKY_MATH_HUE}">
|
|
|
<block type="math_number"></block>
|
|
|
<block type="math_arithmetic"></block>
|
|
|
- <block type="math_single"></block>
|
|
|
- </category>
|
|
|
-
|
|
|
- <!-- 文本输出积木 -->
|
|
|
- <category name="文本" colour="%{BKY_TEXTS_HUE}">
|
|
|
- <block type="text"></block>
|
|
|
- <block type="text_length"></block>
|
|
|
- <block type="text_print"></block>
|
|
|
</category>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="workspace-section">
|
|
|
<h2>工作区</h2>
|
|
|
- <div id="blocklyDiv"></div>
|
|
|
<div class="controls">
|
|
|
<button id="runCode" @click="runCode">运行代码</button>
|
|
|
<button @click="clearWorkspace">清空工作区</button>
|
|
|
<button @click="resetPlayer">重置玩家</button>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <div class="output-section">
|
|
|
- <h2>输出</h2>
|
|
|
- <div class="controls">
|
|
|
- <button @click="clearOutput">清空输出</button>
|
|
|
- </div>
|
|
|
- <pre id="output">{{ output }}</pre>
|
|
|
+ <div id="blocklyDiv"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -136,6 +121,7 @@ import { ArrowLeftBold } from '@element-plus/icons-vue';
|
|
|
import * as Blockly from "blockly";
|
|
|
import 'blockly/msg/zh-hans';
|
|
|
import { javascriptGenerator } from "blockly/javascript";
|
|
|
+import mapBackgroundImage from '@/assets/images/blockly/mapGame.png';
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
@@ -144,15 +130,15 @@ const gameState = reactive({
|
|
|
// 地图配置信息
|
|
|
mapConfig: {
|
|
|
// 地图背景图片路径
|
|
|
- background: '@/assets/images/room.png',
|
|
|
+ background: mapBackgroundImage,
|
|
|
// 每个瓦片的尺寸(像素)
|
|
|
- tileSize: 50,
|
|
|
+ tileSize: 167,
|
|
|
},
|
|
|
|
|
|
// 玩家相关状态
|
|
|
player: {
|
|
|
// 玩家当前位置坐标
|
|
|
- position: { x: 1, y: 1 },
|
|
|
+ position: { x: 2, y: 2 },
|
|
|
// 玩家当前朝向:0=上, 1=右, 2=下, 3=左
|
|
|
direction: 1,
|
|
|
// 是否正在发生碰撞
|
|
|
@@ -172,19 +158,14 @@ const gameState = reactive({
|
|
|
// 地图数据信息
|
|
|
mapData: {
|
|
|
// 游戏起点位置
|
|
|
- startPoint: { x: 1, y: 1 },
|
|
|
+ startPoint: { x: 2, y: 2 },
|
|
|
// 游戏终点位置
|
|
|
- endPoint: { x: 3, y: 1 },
|
|
|
+ endPoint: { x: 3, y: 3 },
|
|
|
// 地图上所有可行走的点坐标集合
|
|
|
walkablePoints: [
|
|
|
- { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 3, y: 1 }, { x: 4, y: 1 }, { x: 5, y: 1 },
|
|
|
- { x: 1, y: 2 }, { x: 5, y: 2 },
|
|
|
- { x: 1, y: 3 }, { x: 2, y: 3 }, { x: 3, y: 3 }, { x: 4, y: 3 }, { x: 5, y: 3 },
|
|
|
- { x: 1, y: 4 }, { x: 3, y: 4 }, { x: 5, y: 4 },
|
|
|
- { x: 1, y: 5 }, { x: 2, y: 5 }, { x: 3, y: 5 }, { x: 4, y: 5 }, { x: 5, y: 5 },
|
|
|
- { x: 1, y: 6 }, { x: 5, y: 6 },
|
|
|
- { x: 1, y: 7 }, { x: 2, y: 7 }, { x: 3, y: 7 }, { x: 4, y: 7 }, { x: 5, y: 7 },
|
|
|
- { x: 6, y: 7 }, { x: 7, y: 7 }, { x: 8, y: 7 }
|
|
|
+ { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 3, y: 1 },
|
|
|
+ { x: 2, y: 2 }, { x: 3, y: 2 },
|
|
|
+ { x: 1, y: 3 }, { x: 3, y: 3 },
|
|
|
]
|
|
|
}
|
|
|
});
|
|
|
@@ -225,17 +206,22 @@ function isWalkable(x, y) {
|
|
|
// 计算点的样式
|
|
|
function getPointStyle(point) {
|
|
|
return {
|
|
|
- left: point.x * tileSize.value + 'px',
|
|
|
- top: point.y * tileSize.value + 'px'
|
|
|
+ left: point.x * tileSize.value - tileSize.value + 'px',
|
|
|
+ top: point.y * tileSize.value - tileSize.value + 'px',
|
|
|
+ width: tileSize.value + 'px',
|
|
|
+ height: tileSize.value + 'px'
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// 计算玩家样式
|
|
|
const playerStyle = computed(() => ({
|
|
|
- left: playerPosition.value.x * tileSize.value + 'px',
|
|
|
- top: playerPosition.value.y * tileSize.value + 'px',
|
|
|
+ left: playerPosition.value.x * tileSize.value - tileSize.value + 'px',
|
|
|
+ top: playerPosition.value.y * tileSize.value - tileSize.value + 'px',
|
|
|
transform: `rotate(${playerDirection.value * 90}deg)`,
|
|
|
- '--player-rotation': `${playerDirection.value * 90}deg` // 添加CSS变量
|
|
|
+ '--player-rotation': `${playerDirection.value * 90}deg`,
|
|
|
+ width: (tileSize.value * 0.8) + 'px',
|
|
|
+ height: (tileSize.value * 0.8) + 'px',
|
|
|
+ margin: (tileSize.value * 0.1) + 'px'
|
|
|
}));
|
|
|
|
|
|
// 显示游戏消息
|
|
|
@@ -414,12 +400,32 @@ function initBlockly() {
|
|
|
const toolbox = document.getElementById('toolbox');
|
|
|
workspace = Blockly.inject('blocklyDiv', {
|
|
|
toolbox: toolbox,
|
|
|
- theme: Blockly.Themes.Classic,
|
|
|
+ collapse: true,
|
|
|
+ comments: true,
|
|
|
+ disable: false, // 设为false以允许编辑
|
|
|
+ maxBlocks: Infinity,
|
|
|
+ trashcan: true,
|
|
|
+ horizontalLayout: false,
|
|
|
+ toolboxPosition: 'start',
|
|
|
+ css: true,
|
|
|
+ media: 'https://unpkg.com/blockly/media/',
|
|
|
+ rtl: false,
|
|
|
+ scrollbars: true,
|
|
|
+ sounds: false, // 禁用声音以提高性能
|
|
|
+ oneBasedIndex: true,
|
|
|
grid: {
|
|
|
spacing: 20,
|
|
|
length: 3,
|
|
|
- colour: '#ccc',
|
|
|
+ colour: "#ccc",
|
|
|
snap: true
|
|
|
+ },
|
|
|
+ zoom: {
|
|
|
+ controls: true,
|
|
|
+ wheel: true,
|
|
|
+ startScale: 1.0,
|
|
|
+ maxScale: 3,
|
|
|
+ minScale: 0.3,
|
|
|
+ scaleSpeed: 1.2
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
@@ -503,8 +509,7 @@ async function move(direction) {
|
|
|
if (isWalkable(newX, newY)) {
|
|
|
// 使用平滑移动动画
|
|
|
await smoothMoveTo(newX, newY);
|
|
|
- output.value += `${moveType}到: (${newX}, ${newY})
|
|
|
-`;
|
|
|
+ output.value += `${moveType}到: (${newX}, ${newY})\n`;
|
|
|
|
|
|
// 检查是否到达终点
|
|
|
if (newX === endPoint.value.x && newY === endPoint.value.y) {
|
|
|
@@ -586,14 +591,12 @@ window.turnAround = async function() {
|
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
};
|
|
|
|
|
|
-
|
|
|
// 添加一个变量来跟踪当前执行的代码
|
|
|
let currentExecutionPromise = null;
|
|
|
let executionAbortController = null;
|
|
|
// 运行代码
|
|
|
const runCode = async () => {
|
|
|
try {
|
|
|
-
|
|
|
await resetPlayer();
|
|
|
|
|
|
// 创建新的AbortController用于取消执行
|
|
|
@@ -674,11 +677,6 @@ const clearWorkspace = () => {
|
|
|
showGameMessage('工作区已清空', 'info');
|
|
|
};
|
|
|
|
|
|
-// 清空输出
|
|
|
-const clearOutput = () => {
|
|
|
- output.value = '// 输出将显示在这里\n';
|
|
|
-};
|
|
|
-
|
|
|
// 重置玩家位置和状态
|
|
|
const resetPlayer = () => {
|
|
|
// 取消任何正在执行的代码
|
|
|
@@ -724,6 +722,11 @@ onUnmounted(() => {
|
|
|
@return math.div($px, 750) * 100vw;
|
|
|
}
|
|
|
|
|
|
+//将tileSize属性绑定到CSS变量上
|
|
|
+:root {
|
|
|
+ --tile-size: v-bind('tileSize + "px"');
|
|
|
+}
|
|
|
+
|
|
|
.map-game-container {
|
|
|
position: fixed;
|
|
|
top: 0;
|
|
|
@@ -819,7 +822,7 @@ onUnmounted(() => {
|
|
|
.map-background {
|
|
|
position: relative;
|
|
|
width: 500px;
|
|
|
- height: 400px;
|
|
|
+ height: 500px;
|
|
|
margin: 0 auto;
|
|
|
border: 2px solid #ddd;
|
|
|
border-radius: 8px;
|
|
|
@@ -831,32 +834,28 @@ onUnmounted(() => {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
object-fit: cover;
|
|
|
- opacity: 0.7;
|
|
|
+ //opacity: 0.7;
|
|
|
}
|
|
|
|
|
|
/* 可行走区域样式 */
|
|
|
.walkable-point {
|
|
|
- position: absolute;
|
|
|
- width: 50px;
|
|
|
- height: 50px;
|
|
|
- background-color: rgba(52, 152, 219, 0.2);
|
|
|
- border: 1px solid rgba(52, 152, 219, 0.5);
|
|
|
- box-sizing: border-box;
|
|
|
+ //position: absolute;
|
|
|
+ //background-color: rgba(52, 152, 219, 0.2);
|
|
|
+ //border: 1px solid rgba(52, 152, 219, 0.5);
|
|
|
+ //box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
/* 起点和终点样式 */
|
|
|
.start-point,
|
|
|
.end-point {
|
|
|
- position: absolute;
|
|
|
- width: 50px;
|
|
|
- height: 50px;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- font-weight: bold;
|
|
|
- color: white;
|
|
|
- text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.7);
|
|
|
- border-radius: 5px;
|
|
|
+ //position: absolute;
|
|
|
+ //display: flex;
|
|
|
+ //justify-content: center;
|
|
|
+ //align-items: center;
|
|
|
+ //font-weight: bold;
|
|
|
+ //color: white;
|
|
|
+ //text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.7);
|
|
|
+ //border-radius: 5px;
|
|
|
}
|
|
|
|
|
|
.start-point {
|
|
|
@@ -870,9 +869,6 @@ onUnmounted(() => {
|
|
|
/* 玩家样式 */
|
|
|
.player {
|
|
|
position: absolute;
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- margin: 5px;
|
|
|
background-image: url('@/assets/images/xiaozhi.png');
|
|
|
background-size: contain;
|
|
|
background-repeat: no-repeat;
|
|
|
@@ -979,6 +975,7 @@ onUnmounted(() => {
|
|
|
background: rgba(248, 249, 250, 0.82);
|
|
|
padding: 15px;
|
|
|
border-radius: 15px;
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
|
|
|
.workspace-section h2 {
|
|
|
@@ -999,7 +996,7 @@ onUnmounted(() => {
|
|
|
.controls {
|
|
|
display: flex;
|
|
|
gap: 10px;
|
|
|
- margin-top: 15px;
|
|
|
+ margin: 15px 0px;
|
|
|
flex-wrap: wrap;
|
|
|
}
|
|
|
|