Canvas 3×3网格场景下角色跨区域移动实现方案求助
Got it, let's refactor your code to handle movement between that 3×3 grid of zones! Instead of smooth continuous movement, we'll make the character snap directly to the center of each zone when you press arrow keys, starting from B2.
Here's the step-by-step breakdown and modified code:
1. Define the Grid Zone Positions
First, we'll map each zone (A1, B2, etc.) to its corresponding block position on the canvas. Since your canvas is 500x400, we'll split it evenly into 3 columns and 3 rows, then calculate where each block should sit to be centered in its zone.
2. Track Current Zone
We'll add a variable to keep track of which zone the character is currently in—starting with 'B2' as you specified.
3. Rewrite Movement Logic
Instead of incrementing/decrementing block_x and block_y nonstop, we'll switch zones based on arrow key presses, and add boundary checks so you can't move outside the 3×3 grid.
Modified Full Code
<style> canvas { display:block; margin:auto; border:1px dashed black; } </style> <canvas id="canvas" width="500" height="400"></canvas> <script> (function (d, w) { var context; var block_h = 30; var block_w = 30; var WIDTH = 500; // Use fixed canvas size for consistent grid calculations var HEIGHT = 400; // Map each grid zone to its block's top-left position var gridPositions = { A1: { x: WIDTH/6 - block_w/2, y: HEIGHT/6 - block_h/2 }, A2: { x: WIDTH/2 - block_w/2, y: HEIGHT/6 - block_h/2 }, A3: { x: WIDTH*5/6 - block_w/2, y: HEIGHT/6 - block_h/2 }, B1: { x: WIDTH/6 - block_w/2, y: HEIGHT/2 - block_h/2 }, B2: { x: WIDTH/2 - block_w/2, y: HEIGHT/2 - block_h/2 }, // Starting zone B3: { x: WIDTH*5/6 - block_w/2, y: HEIGHT/2 - block_h/2 }, C1: { x: WIDTH/6 - block_w/2, y: HEIGHT*5/6 - block_h/2 }, C2: { x: WIDTH/2 - block_w/2, y: HEIGHT*5/6 - block_h/2 }, C3: { x: WIDTH*5/6 - block_w/2, y: HEIGHT*5/6 - block_h/2 } }; // Track which zone the character is currently in var currentZone = 'B2'; function init() { var canvas = d.getElementById('canvas'); context = canvas.getContext('2d'); setInterval(draw, 25); } function clearCanvas() { context.clearRect(0, 0, WIDTH, HEIGHT); } function draw() { clearCanvas(); // Draw the block at the current zone's position var pos = gridPositions[currentZone]; context.fillRect(pos.x, pos.y, block_w, block_h); } // Handle zone switching on key press function onKeyDown(evt) { // Prevent repeated movement when holding a key if (evt.repeat) return; switch(evt.keyCode) { case 39: // Right arrow switch(currentZone) { case 'A1': currentZone = 'A2'; break; case 'A2': currentZone = 'A3'; break; case 'B1': currentZone = 'B2'; break; case 'B2': currentZone = 'B3'; break; case 'C1': currentZone = 'C2'; break; case 'C2': currentZone = 'C3'; break; // A3/B3/C3 can't move right } break; case 37: // Left arrow switch(currentZone) { case 'A2': currentZone = 'A1'; break; case 'A3': currentZone = 'A2'; break; case 'B2': currentZone = 'B1'; break; case 'B3': currentZone = 'B2'; break; case 'C2': currentZone = 'C1'; break; case 'C3': currentZone = 'C2'; break; // A1/B1/C1 can't move left } break; case 38: // Up arrow switch(currentZone) { case 'B1': currentZone = 'A1'; break; case 'B2': currentZone = 'A2'; break; case 'B3': currentZone = 'A3'; break; case 'C1': currentZone = 'B1'; break; case 'C2': currentZone = 'B2'; break; case 'C3': currentZone = 'B3'; break; // A1/A2/A3 can't move up } break; case 40: // Down arrow switch(currentZone) { case 'A1': currentZone = 'B1'; break; case 'A2': currentZone = 'B2'; break; case 'A3': currentZone = 'B3'; break; case 'B1': currentZone = 'C1'; break; case 'B2': currentZone = 'C2'; break; case 'B3': currentZone = 'C3'; break; // C1/C2/C3 can't move down } break; } evt.preventDefault(); evt.stopPropagation(); } w.addEventListener("load", init, false); w.addEventListener("keydown", onKeyDown, false); })(document, window); </script>
Key Changes Explained
- Grid Position Mapping: The
gridPositionsobject calculates exactly where the block should sit to be centered in each zone—no more guesswork. - Current Zone Tracking:
currentZoneacts as our single source of truth for where the character is, making movement logic straightforward. - Key Press Handling: We use nested
switchstatements to handle every possible zone transition, and skip repeated key presses so holding an arrow key doesn't spam movements. - Simplified Drawing: The
drawfunction just grabs the current zone's position and renders the block there, no more continuous position updates.
This setup will let your character jump directly between any of the 9 zones using arrow keys, while staying within the 3×3 grid boundaries.
内容的提问来源于stack exchange,提问作者Ingus

