メニュー
• Dynamic Maze Generation: Random maze layout for each playthrough
• Dual Control Modes: Switch between button input and accelerometer-based motion control
• Smart Enemy AI: A* pathfinding algorithm for adaptive chasing
• Scalable Design: Adjustable difficulty levels and customizable themes
Preview
• Objective: Escape maze while evading AI enemies
• Core Mechanics:
• Green sprite: Player
• Red sprite: Chasing enemy
• Gold sprite: Exit
• Blue tiles: Impassable walls
Full Implementation
// ===== Global Config ===== enum SpriteKind { Player, Enemy, Exit } // Maze parameters let mazeWidth = 10; let mazeHeight = 8; let cellSize = 16; // ===== Maze Generation ===== function generateMaze(): number[][] { let maze: number[][] = []; // Prim's algorithm implementation (abbreviated) return maze; } // ===== Game Elements ===== let maze = generateMaze(); let player = sprites.create(img` . . . . . . 7 7 7 . . 7 9 7 . . 7 7 7 . . . . . . `, SpriteKind.Player); let enemy = sprites.create(img` . . 2 . . . 2 2 2 . 2 2 4 2 2 . 2 2 2 . . . 2 . . `, SpriteKind.Enemy); let exit = sprites.create(img` . . 5 . . . 5 5 5 . 5 5 d 5 5 . 5 5 5 . . . 5 . . `, SpriteKind.Exit); // ===== Control Logic ===== // Toggle control mode with A button let useAccelerometer = false; controller.A.onEvent(ControllerButtonEvent.Pressed, () => { useAccelerometer = !useAccelerometer; info.showScore("Mode: " + (useAccelerometer ? "Motion" : "Buttons")); }); // Player movement game.onUpdate(() => { if (useAccelerometer) { player.x += input.acceleration(Dimension.X) / 20; player.y += input.acceleration(Dimension.Y) / 20; } else { player.x += controller.dx() * 2; player.y += controller.dy() * 2; } // Wall collision if (tiles.tileAtLocationIsWall(tiles.getTileLocation(player.x, player.y))) { player.x -= controller.dx() * 2; player.y -= controller.dy() * 2; music.playTone(131, 200); } }); // Enemy AI pathfinding game.onUpdateInterval(1000, () => { let path = scene.aStarPath(enemy, player); if (path.length > 0) { enemy.follow(path[0]); } }); // Win condition sprites.onOverlap(SpriteKind.Player, SpriteKind.Exit, () => { game.over(true); });
function generateMaze(): number[][] { // Initialize full-wall maze let maze = []; for (let y = 0; y < mazeHeight; y++) { maze.push([]); for (let x = 0; x < mazeWidth; x++) { maze[y].push(1); // 1=wall, 0=path } } // Random starting point let startX = Math.randomRange(1, mazeWidth-2); let startY = Math.randomRange(1, mazeHeight-2); maze[startY][startX] = 0; // Path carving logic (abbreviated) return maze; }
• Heuristic: Manhattan distance h(n) = |x1-x2| + |y1-y2|
• Cost calculation: f(n) = g(n) + h(n)
• Optimization: Path step limitation prevents lag
MODE | CODE IMPLEMENTATION | Sensitivity Parameter |
---|---|---|
Button Control | controller.dx()/dy() | Multiplier (2) |
Motion Control | input.acceleration() | Divisor (20) |
Classroom Activities
1. Algorithm Workshop
Task: Modify maze generation rules to create symmetrical layouts
Concepts: Recursive algorithms, 2D array manipulation
2. Physics Integration
Task: Calculate movement speed using accelerometer data
Formula: v = Δposition / Δtime
3. Pixel Art Design
Task: Create theme-based sprites using Piskel
Requirements: 16x16 pixels, thematic consistency (space/forest/castle)
Difficulty Level System
info.onStart(() => { let difficulty = game.askForNumber("Choose difficulty (1-5)", 1); mazeWidth = 6 + difficulty * 2; mazeHeight = 4 + difficulty * 2; });
Dynamic Environment
// Regenerate maze every 30 seconds game.onUpdateInterval(30000, () => { tiles.setTilemap(generateMaze()); info.changeScoreBy(10); // Bonus points });
Issue 1: Enemy Stuck in Corners
Solution: Add pathfinding tolerance
let path = scene.aStarPath(enemy, player, { stepLimit: 50 // Limit search steps });
Issue 2: Low Motion Sensitivity
Adjustment: Modify acceleration divisor
player.x += input.acceleration(Dimension.X) / 15; // Increased sensitivity
Maze Algorithm Visualizer: MazeGenerator.net
Pixel Art Assets: OpenGameArt.org
Pathfinding Reference: Artificial Intelligence: A Modern Approach Chapter 3