1. 程式人生 > 其它 >遊戲裡的小人如何走路?百行HTML5+JS能搜尋出路徑嗎?

遊戲裡的小人如何走路?百行HTML5+JS能搜尋出路徑嗎?

用了HTML5裡的canvas. 這個"遊戲"的”玩法“是:

  1. 改迷宮折騰電腦
  2. 改程式折騰自己:-)。我自以為程式挺簡明,註釋挺多,比如:
    • // 全域性變數坑死人,這裡曾經少個var
    • // 雖然直接drawImage有時能出來,但這麼做絕對必要。坑了我好長時間。

單.HTML檔案146行,包括數張嵌入式.gif圖片和JS。下面是全部JS(112行):

ctx = gmaze.getContext('2d')

function reset_maze(){
    X = Xin.value; if(X > 32 || X < 6) X = 20
    Y = Yin.value; if
(Y > 20 || Y < 6) Y = 13 Xin.value = X; Yin.value = Y maze = new Array(); for(y = 0; y < Y; y++){ var row = new Array() // new Array(3)不是建立長度為3的陣列 for(x = 0; x < X; x++) row.push(Math.random() < 0.7 ? ' ' : 'w') maze.push(row) } maze[cx = 0][cy = 0] = 'r' //
cx,cy記錄當前機器人位置 gmaze.width = X * 32; gmaze.height = Y * 32; draw_maze() }; reset_maze() function clear_path() { for(y = 0; y < Y; y++) for(x = 0; x < X; x++){ var c = maze[y][x] if(c == 'x' || c == 'p' || c == 'r') maze[y][x] = ' ' } stepcnt = 0 } function draw_maze(){
for(y = 0; y < Y; y++) for(x = 0; x < X; x++){ var c = maze[y][x] if(c == 'r') draw_img(img_robot, x, y) else if(c == 'w') draw_img(img_wall, x, y) else if(c == 'p') draw_img(img_flag, x, y) else if(c == ' ') draw_blk('#fff', x, y) else draw_blk('#f00', x, y) } } // 雖然直接drawImage有時能出來,但這麼做絕對必要。坑了我好長時間。 function draw_img(img, x, y){ var i = new Image(); i.src = img.src i.onload = function(){ ctx.drawImage(i, x * 32, y * 32) } } function draw_blk(color, x, y){ ctx.fillStyle = color; ctx.fillRect(x * 32, y * 32, 32, 32) } // mx, my記錄滑鼠指標位置 d = document; d.addEventListener('mousemove', function(e){ mx = e.x; my = e.y }) // 畫素座標到塊座標轉換。border+wall=8+32. round() is bad, round() is wrong. function get_x() { // var x = Math.floor((mx - 40) / 32) if(x < 0 || x >= X) throw 'X超出範圍。' return x } function get_y() { var y = Math.floor((my - 40) / 32) if(y < 0 || y >= Y) throw 'Y超出範圍。' return y } d.addEventListener('mousedown', function(e){ // 可以忽略exception if(e.which != 1) return; // Not left button var x = get_x(), y = get_y() var c = maze[y][x] if(c == 'w') maze[y][x] = ' ', draw_blk('#fff', x, y) else if (c == ' ') maze[y][x] = 'w', draw_img(img_wall, x, y) }) d.addEventListener('keydown', function(e){ if (e.keyCode != 71) return // Not 'g' try{ tx = get_x(), ty = get_y() // target x, y, 全域性變數 clear_path() //alert('Searching for ' + cx + ',' + cy + ' to ' + tx + ',' + ty) ok = search(cx, cy) if(ok) maze[cy = ty][cx = tx] = 'r' else { maze[cy][cx] = 'r' alert('Please try a nearer target.') } draw_maze() } catch(e){} }) function search(x, y){ if(x == tx && y == ty) return true if(++stepcnt > 1000000) return false if(x<0 || x>=X || y<0 || y>=Y) { console.log(x, y) return false } if(maze[y][x] != ' ') { console.log(x, y, maze[y][x]) return false } maze[y][x] = 'p' var dxdy = [[0,-1],[0,1],[-1,0],[1,0]] var e_i = [1,2,3,4] // evaluation_index var i, j for(i = 0; i < 4; i++) { var a = x + dxdy[i][1], b = y + dxdy[i][0] var c = tx - a, d = ty - b var t = c * c + d * d // 距離的平方 e_i[i] = (t << 2) | i } // 預設情況下,sort方法按字母順序對元素排序。https://www.codenong.com/1063007/ e_i.sort((a, b) => a - b) for(j = 0; j < 4; j++) { i = e_i[j] & 0x3 // 全域性變數坑死人,這裡曾經少個var if(search(x + dxdy[i][1], y + dxdy[i][0])) return true } maze[y][x] = 'x'; return false }

點這裡下載HTML+JS。下面是HTML的不包含嵌入圖片的部分:

<html><meta charset="gbk"><title>走迷宮</title><style>
/* https://www.w3school.com.cn/cssref/css_selectors.asp */
* { font:12pt 'Segoe UI' }
#wall { position:absolute; left:8px; top:8px; padding:32px;
background-image:url(data:image/gif;base64,...);
}
#gmaze { cursor:hand }
#panel { float:right; top:32px }
    h6 { font:bold 14pt 'Segoe UI'; color:green; margin:1em }
    input { width:2em }
pre { display:none }
</style>
<body>
<div id="wall"><canvas id="gmaze"/></div>
<div id="panel">
    <h6>你設計一個迷宮,機器人來走</h6>
    <p style="text-align:center">
        <button onclick="reset_maze()">重新生成</button>
        <input type="text" id="Xin" value="20"/> X 
        <input type="text" id="Yin" value="17"/>的迷宮
    </p>
    <ul>
    <li>編輯: 在迷宮裡按滑鼠左鍵切換路或牆。<br>最外面的牆不能改變。</li>
    <li>按 g 鍵後,機器人會試圖走到滑鼠指標所在處。</li>
    <li style='font-size:10pt'>開啟開發人員工具後,鍵盤焦點可能不在頁面內。<br>此時可點選頁面內任意文字框把焦點切回來。<br>滑鼠雙擊容易誤操作。</li>
    </ul>
</div>