HTML5 Canvas編寫五彩連珠(5):尋路

來源:互聯網
上載者:User

上節主要做了動畫的實現,感覺還是比較有意思的。遊戲的效能好不好,重繪應該比較重要吧,菜鳥瞎想了下 呵呵。
本節就要做對泡泡的操作,上節後面提到了點擊泡泡後泡泡要做出閃動響應,那我們我們如何獲得被點擊了哪個泡泡呢?
其實Canvas也是html的一個元素而已,所以我們可以給Canvas加click事件。來查看click時滑鼠的座標,這樣就等得出點擊了map的哪個位置。
我們給game增加一個click方法,當Canvas點擊時調用此方法。
要實現的效果是: 當Canvas時被點擊時有幾種可能:
1、沒點到map  那就不作響應
2、點到了泡泡,那該泡泡要做出響應(閃)
3、如果之前有點擊過其他的泡泡,則取消之前的泡泡的響應(clicked.stop),如果之前的泡泡是自己,則不作響應。並把clicked作為自己,以體後面的操作。
4、如果點擊到的是空格,如果之前點擊了泡泡,那就嘗試移動這個泡泡,如果clicked為null(之前沒泡泡)那就不作任何響應。如果可以移動,則取消閃動,並清除clicked,開始移動。 

            onclick: function (e) {                var px = e.offsetX - game.map.startX;                var py = e.offsetY - game.map.startY;                if (px < 0 || py < 0 || px > game.map.width || py > game.map.height) {                    return;                }                var x = parseInt(px / game.cellWidth);                var y = parseInt(py / game.cellWidth);                var bubble = game.map.getBubble(x, y);                if (bubble.color) {                    if (this.clicked) {                        //同一個泡不做反映                        if (this.clicked.x == x && this.clicked.y == y) {                            return;                        }                        this.clicked.stop();                    }                    this.clicked = bubble;                    bubble.play();                }                else {                    if (this.clicked) {                        this.clicked.stop();                        //移動clicked                        game.map.move(this.clicked, bubble);                    }                }                //console.log("x:" + x + " y:" + y);            },

尋路的代碼還沒寫,因為這個需要考慮怎麼實現。 我絞盡腦汁終於想到了一個辦法。暫且撇開遊戲的代碼,單獨實現下兩點的尋路代碼。
先給定一個棋盤,假如如下:
1 1 1 1 1
0 0 1 0 1
0 0 1 0 1
1 0 0 1 1
要想從 最下面一行中間的點(2,3)移動到左上方的(0,1),該如何設計呢?
一個棋子能否移動,要看他相鄰的4個子是否為0,如果是0則可以移動。 所以我們可以通過遞迴來獲得所有相連的0的記錄。 這個記錄用樹結構來儲存,直到我們無法繼續探測為0的格子或到達目的地。 我們把當前的棋子的格子設為 root,他相鄰的棋子是他的孩子。這樣的話,我們會得到一棵樹的結果如下:

是不是?這樣的畫我們就可以直接看到了整個路徑(2,3 -> 1,3 -> 1,2 -> 0,2 -> 0,1)。思路很清晰,只要遞迴構建子節點就ok了。代碼如下:

    var map = [[1, 1, 1, 1, 1],[0, 0, 1, 0, 1],[0, 0, 1, 0, 1],[1, 0, 0, 1, 1]    ];    var history = [];    var goal = { "x": 0, "y": 1 }    var goalNode = null;    var getNode = function (x, y, parent) {        if (x >= map.length || y >= map.length) {            return;        }        if (map[y][x] == 1) {            return;        }        var hasNode = false;        history.forEach(function (n) {            if (n.x == x && n.y == y) {                hasNode = true;                return;            }        });        if (hasNode) {            return;        }        var node = { "x": x, "y": y, "parent": parent, child: [] };        history.push(node);        if (node.x == goal.x && node.y == goal.y) {            goalNode = node;            return node;        }        if (x - 1 >= 0 && !map[y][x - 1]) {            node.child.push(getNode(x - 1, y, node));        }        if (y - 1 >= 0 && !map[y - 1][x]) {            node.child.push(getNode(x, y - 1, node));        }        if (x + 1 < map.length && !map[y][x + 1]) {            node.child.push(getNode(x + 1, y), node);        }        if (y + 1 < map.length && !map[y + 1][x]) {            node.child.push(getNode(x, y + 1, node));        }        return node;    }    console.log(getNode(2, 3));    console.log(goalNode);

     我加了一個parent,就是指向父親的指標,那樣就不用再去遍曆這棵樹了。可以直接從goalNode的結果得到整個路徑:) 雖然偷懶,但也是要複出代價的,因為這樣走的路徑不是最短路線,比較傻,怎麼選擇最優路線呢? 最笨的方法就是 把所有的路徑都得到(深度優先遍曆樹N遍- -)然後比較。這個顯然效率不高。開始我也不知道效果會這麼差,等一運行(你運行下就知道了),我發現,是代碼寫的不好(廢話)。因為我們每次的判斷順尋都是 左上右下,這樣路徑總是這個方向探索,而最優的路徑應該是朝目標點的方向探索。 由於是遞迴尋找,所以,對當前的node和目標node進行座標的方向判斷,然後調整判斷順序,這樣是得到的才是比較短的路徑。

var child = [];var left, top, right, buttom;//最短路徑的粗略判斷就是首選目標位置的大致方向if (x - 1 >= 0 && map.isEmpty(x - 1, y))left = { "x": x - 1, "y": y };if (x + 1 < map.length && map.isEmpty(x + 1, y))right = { "x": x + 1, "y": y };if (y + 1 < map.length && map.isEmpty(x, y + 1))buttom = { "x": x, "y": y + 1 };if (y - 1 >= 0 && map.isEmpty(x, y - 1))top = { "x": x, "y": y - 1 };if (x > x2) {if (y > y2)child = [left, top, right, buttom];else if (y < y2)child = [left, buttom, right, top];elsechild = [left, top, right, buttom];}else if (x < x2) {if (y > y2)child = [right, top, left, buttom];else if (y < y2)child = [right, buttom, left, top];elsechild = [right, top, left, buttom];}else if (x == x2) {if (y > y2)child = [top, left, right, buttom];else if (y < y2)child = [buttom, left, right, top];}for (var i = 0; i < child.length; i++) {var c = child[i];if (c) node.child.push(getnode(c.x, c.y, node));}

代碼雖然寫的比較傻,但這種方式不得不說好就一個字:)

 既然尋路已經實現了,那麼下面就交給map了,map來負責讓泡泡走起來。其實就是根據路徑給泡泡著色- - ,代碼也不複雜。

            move: function (bubble, target) {                var path = this.search(bubble.x, bubble.y, target.x, target.y);                if (!path) {                    //顯示不能移動s                    alert("過不去");                    return;                }                //map開始播放當前泡的移動效果                //兩種實現方式,1、map按路徑染色,最後達到目的地 2、map產生一個臨時的bubble負責展示,到目的地後移除                //console.log(path);                var me = this;                var name = "move_" + bubble.x + "_" + bubble.y;                var i = path.length - 1;                var color = bubble.color;                game.play(name, function () {                    if (i < 0) {                        game.stop(name);                        return;                    }                    path.forEach(function (cell) {                        me.setBubble(cell.x, cell.y, null);                    });                    var currentCell = path[i];                    me.setBubble(currentCell.x, currentCell.y, color);                    i--;                }, 50);            },            search: function (x1, y1, x2, y2) {                var history = [];                var goalCell = null;                var me = this;                getCell(x1, y1, null);                if (goalCell) {                    var path = [];                    var cell = goalCell;                    while (cell) {                        path.push({ "x": cell.x, "y": cell.y });                        cell = cell.parent;                    }                    return path;                }                return null;                function getCell(x, y, parent) {                    if (x >= me.bubbles.length || y >= me.bubbles.length)                        return;                    if (x != x1 && y != y2 && !me.isEmpty(x, y))                        return;                    for (var i = 0; i < history.length; i++) {                        if (history[i].x == x && history[i].y == y)                            return;                    }                    var cell = { "x": x, "y": y, child: [], "parent": parent };                    history.push(cell);                    if (cell.x == x2 && cell.y == y2) {                        goalCell = cell;                        return cell;                    }                    var child = [];                    var left, top, right, buttom;                    //最短路徑的粗略判斷就是首選目標位置的大致方向                    if (x - 1 >= 0 && me.isEmpty(x - 1, y))                        left = { "x": x - 1, "y": y };                    if (x + 1 < me.bubbles.length && me.isEmpty(x + 1, y))                        right = { "x": x + 1, "y": y };                    if (y + 1 < me.bubbles.length && me.isEmpty(x, y + 1))                        buttom = { "x": x, "y": y + 1 };                    if (y - 1 >= 0 && me.isEmpty(x, y - 1))                        top = { "x": x, "y": y - 1 };                    if (x > x2) {                        if (y > y2)                            child = [left, top, right, buttom];                        else if (y < y2)                            child = [left, buttom, right, top];                        else                            child = [left, top, right, buttom];                    }                    else if (x < x2) {                        if (y > y2)                            child = [right, top, left, buttom];                        else if (y < y2)                            child = [right, buttom, left, top];                        else                            child = [right, top, left, buttom];                    }                    else if (x == x2) {                        if (y > y2)                            child = [top, left, right, buttom];                        else if (y < y2)                            child = [buttom, left, right, top];                    }                    for (var i = 0; i < child.length; i++) {                        var c = child[i];                        if (c) cell.child.push(getCell(c.x, c.y, cell));                    }                    return cell;                }            },

試玩地址:http://zhengliangjun.sinaapp.com/colorline.html

 後面剩下的就是判斷如何消除、加分、防止誤操作之類的內容了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.