最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS+Canvas實現(xiàn)貪吃蛇小游戲

 更新時間:2022年01月20日 09:14:27   作者:老馬-Max  
這篇文章介紹了JS+Canvas實現(xiàn)貪吃蛇小游戲,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

今天呢,主要和小伙伴們分享一下一個貪吃蛇游戲從構(gòu)思到實現(xiàn)的過程~因為我不是很喜歡直接PO代碼,所以只copy代碼的童鞋們請出門左轉(zhuǎn)不謝。

按理說canvas與其應(yīng)用是老生常談了,可我在準備階段卻搜索不到有用的資料(不是代碼!),所以說呢,只能自力更生 -_- 

首先是大致要考慮的東西:

1.要有蛇(沒蛇怎么叫貪吃蛇)。

2.然后要有地圖(蛇是不能上天的)。

3.不能水平\垂直掉頭(如果想掉頭,需要至少變換方位并且至少移動一格才可)。

4.食物(不然怎么貪吃)。

5.吃了食物要變長(這才是精髓)。

PS:~現(xiàn)在我回想起來,當時的確只想到這么多(⊙﹏⊙)

構(gòu)思完畢,開工!

怎么做呢?從大到小,先畫個矩形作地圖,可我覺得太丑,于是畫了一張圖出來:

context.beginPath();
var bgImg = new Image();
bgImg.src = "img/background.png";
context.drawImage(bgImg, 0, 0, 600, 600);
context.closePath();

現(xiàn)在我們有地圖了

地圖上好像缺點什么……沒錯就是禮物,所以我們現(xiàn)在生成禮物,那么問題來了:禮物最多有幾個、生成位置、何時生成。

我這里暫時定義為:最多2個、隨機位置生成、當禮物個數(shù)小于2時生成至2個。

接下來就很簡單了,上圖中,允許蛇活動的范圍是14顆樹(周圍兩顆樹是墻),然后16顆樹=600px,很容易我們得到每格多寬~

所以呢,我們只需要定義一個隨機生成1-14整數(shù)的方法就可以很輕松找到應(yīng)該生成的位置:

//隨機數(shù)
function selectfrom() {
   return Math.floor(Math.random() * 14 + 1);
}

然后再用求出的數(shù)乘以每一格子的寬度,即可求出生成的具體X坐標,因為是正方形,所以Y也一樣:

var x = selectfrom() * (600/16);
var y = selectfrom() * (600/16);

并且每得到一組禮物坐標后,都需要存儲在一個數(shù)組內(nèi)(一會兒有大用處),至于畫矩形太基礎(chǔ)我就不說了。

And Now,我們有了禮物,有了地圖,就差蛇了,那么問題又來了:出生的蛇多長、出生地、死亡方式、移動方式、轉(zhuǎn)彎方式、如何判斷吃掉了禮物、吃掉了禮物變長到哪里。

出生蛇長度:實際編寫過程中,我發(fā)現(xiàn)默認長度1和2都不能夠很好的體現(xiàn)“蛇的轉(zhuǎn)彎”,所以定義為3,并且需將蛇身所有坐標記錄在數(shù)組內(nèi)。

出生地:地圖中央或者自己定一個位置(按照格子來分),XY坐標求取方式上面已經(jīng)說過不再贅述。

死亡方式:碰到障礙,或者(吃到自己)蛇頭碰到蛇身。

移動方式:通過定義一個全局變量記錄當前方向(0、1、2、3,默認1),并且使用計時器驅(qū)動蛇運動。

轉(zhuǎn)彎方式:加入鍵盤按鍵檢測事件,當方向鍵按下的時候修改-記錄方向的全部變量即可。

如何判斷吃掉了禮物:每次蛇頭移動時,都要遍歷下禮物集合(上面有說過),如果蛇頭將要移動到的下個坐標與之重合了,則視為吃掉了禮物。

吃掉了禮物變長到哪里:直接加在頭部可能會導(dǎo)致意外的死亡,所以我決定吃到禮物后的下一次移動不消除蛇尾(最后一個元素)。

有了上面的構(gòu)思,我們可以著手定義一些可能會用到的公共變量:

var canvas = document.getElementById("mycanvas");//畫布主體
var context = canvas.getContext("2d");
var timer;//計時器
const WIDTH = canvas.width;//畫布寬
const HEIGHT = canvas.height;//畫布高
const XSUM = 16; //畫布寬分為幾格
const YSUM = 15; //畫布高分為幾格
const MAXFFOD = 2; //最大食物數(shù)量
var score = 0;//定義記錄游戲得分
var xsplit = WIDTH / XSUM; //x每一格子的寬度
var ysplit = HEIGHT / YSUM; //y每一格子的高度
var foodcount = 0; //當前食物數(shù)量
var sinak = []; //貪吃蛇坐標集
var get = []; //禮物坐標集
var MoveTo = 1; //移動方向 默認1(右)

有了這些變量,是不是發(fā)現(xiàn)很多東西都通了呢?

我們先來畫蛇:

//畫貪吃蛇
function drawsinak(sl) { //sl默認長度
    context.beginPath();
    context.fillStyle = "#000";
    var ling = 0; //貪吃蛇被打印長度
    for (var r = 0; r < sinak.length; r++) {
        context.fillRect(sinak[r].split(',')[0], sinak[r].split(',')[1], xsplit, ysplit);
        ling++;
    }
    if (ling == 0) {
        for (var i = 0; i < sl; i++) {
            context.fillRect(xsplit * (7 - i), ysplit * 6, xsplit, ysplit); //默認出生點:7,6默認中心點
            sinak.push(xsplit * (7 - i) + ',' + ysplit * 6);
        }
    }
    context.fill();
    context.closePath();
}

可以看到我將生成的蛇的坐標都計入了數(shù)組內(nèi),生成的禮物自然也要計入:

context.beginPath();
  var x = selectfrom(XSUM - 2) * xsplit;
  var y = selectfrom(YSUM - 2) * ysplit;
  context.fillStyle = "red";
  for (var i = 0; i < get.length; i++) {
      context.fillRect(get[i].split(',')[0], get[i].split(',')[1], xsplit, ysplit);
      context.fill();
      foodcount++;
  }
  if (MAXFFOD > foodcount) {
      context.fillRect(x, y, xsplit, ysplit);
      context.fill();
      foodcount++;
      get.push(x + ',' + y);
  }
  context.closePath();

接下來比較重要了,蛇的移動,以及吃到禮物和觸發(fā)死亡判斷:

//移動方法
//[c]移動方向 上右下左 0123
function sinakMove(c) {
    context.beginPath();
 
    //默認右側(cè)為頭
    var tou = sinak[0]; //頭
    var weiba = sinak[sinak.length - 1]; //尾巴
 
    var oldX = tou.split(',')[0]; //頭部舊X坐標
    var oldY = tou.split(',')[1]; //頭部舊Y坐標
 
    var newX = 0; //頭部最新X坐標
    var newY = 0; //頭部最新Y坐標
 
    //計算頭部最新XY坐標
    switch (c) {
        case 0:
            newX = oldX;
            newY = oldY - ysplit;
            break;
        case 1:
            newX = (oldX - 0) + xsplit;
            newY = oldY;
            break;
        case 2:
            newX = oldX;
            newY = (oldY - 0) + ysplit;
            break;
        case 3:
            newX = oldX - xsplit;
            newY = oldY;
            break;
    }
 
    var flag = 0; //有沒有吃到禮物 0沒有1有
 
    //如果吃到了禮物,則不消減尾部最后元素
    for (var i = 0; i < get.length; i++) {
        if (newX == get[i].split(',')[0] && newY == get[i].split(',')[1]) {
            sinak.unshift(newX + ',' + newY);
            foodcount--; //禮物計數(shù)減少1個
            get.splice(i, 1); //清空禮物
            flag = 1;
        }
    }
    //如果沒有吃到禮物,則判斷是否碰到障礙或吃到自己
    if (flag == 0) {
        for (var i = 0; i < sinak.length; i++) {
            if (newX == sinak[i].split(',')[0] && newY == sinak[i].split(',')[1]) {
                if (confirm('吃掉了自己,游戲失??!是否重新開始?')) {
                    location.reload(true);
                } else {
                    context.clearRect(0, 0, WIDTH, HEIGHT);
                }
            }
        }
        if (xsplit * (XSUM - 2) < newX || ysplit * (YSUM - 2) < newY || newX == 0 || newY == 0) {
            if (confirm('撞墻了,游戲失?。∈欠裰匦麻_始?')) {
                location.reload(true);
            }
        }
    }
 
    //如果沒有吃到禮物,那么進行普通移動
    if (flag == 0) {
        sinak.unshift(newX + ',' + newY);
        sinak.splice(sinak.length - 1, 1);
    }
 
    //畫蛇
    for (var r = 0; r < sinak.length; r++) {
        context.fillRect(sinak[r].split(',')[0], sinak[r].split(',')[1], xsplit, ysplit);
    }
    context.closePath();
}

控制蛇的方向:

//鍵盤事件
document.onkeydown = function (event) {
    var e = event || window.event || arguments.callee.caller.arguments[0];
    var move = 0; //移動方向
    if (e && e.keyCode == 37) { //左
        move = (MoveTo == 1 ? 1 : 3);
    } else if (e && e.keyCode == 38) { //上
        move = (MoveTo == 2 ? 2 : 0);
    } else if (e && e.keyCode == 39) { //右
        move = (MoveTo == 3 ? 3 : 1);
    } else if (e && e.keyCode == 40) { //下
        move = (MoveTo == 0 ? 0 : 2);
    } else if (e && e.keyCode == 32) {//暫停游戲
        clearInterval(timer);
    }
    MoveTo = move; //修改當前移動方向
};

這里做了防誤操作,當蛇正在朝向某方向移動時,直接輸入反方向是無效的。如:蛇正向右走,這時直接按←鍵是無效的,仍然往右走。

一路跟著做到這里,相信大家的貪吃蛇已經(jīng)可以正常游戲了,不過我這個做的很糙,大家可以加入一些自己的想法,比如:

計分通關(guān),通關(guān)之后通過加快蛇的移動速度來增加難度。

隨機生成多種果實,比如加速果實,雙倍成長果實等。

加入WebSocket,實現(xiàn)網(wǎng)絡(luò)版貪吃蛇。

我寫過關(guān)于WebSocket的實現(xiàn),有興趣的也可以去看看,下面是鏈接:

基于SuperSocket實現(xiàn)的WebSocket(后端)

基于SuperSocket實現(xiàn)的WebSocket(前端)

到此這篇關(guān)于JS+Canvas實現(xiàn)貪吃蛇小游戲的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • ES6 javascript中class類的get與set用法實例分析

    ES6 javascript中class類的get與set用法實例分析

    這篇文章主要介紹了ES6 javascript中class類的get與set用法,結(jié)合具體實例形式分析了ES6中類的get與set關(guān)鍵字使用方法,需要的朋友可以參考下
    2017-10-10
  • Javascript設(shè)計模式之發(fā)布訂閱模式

    Javascript設(shè)計模式之發(fā)布訂閱模式

    發(fā)布---訂閱模式又叫觀察者模式,它定義了對象間的一種一對多的關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個主題對象,當一個對象發(fā)生改變時,所有依賴于它的對象都將得到通知
    2022-12-12
  • js實現(xiàn)飛機大戰(zhàn)游戲

    js實現(xiàn)飛機大戰(zhàn)游戲

    這篇文章主要為大家詳細介紹了js實現(xiàn)飛機大戰(zhàn)游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • JS實現(xiàn)模擬風力的雪花飄落效果

    JS實現(xiàn)模擬風力的雪花飄落效果

    這篇文章主要介紹了JS實現(xiàn)模擬風力的雪花飄落效果,可在右側(cè)填入風力值點擊按鈕即可看到伴隨風力的雪花飄落效果,同時右側(cè)有實時雪花數(shù)量統(tǒng)計功能,需要的朋友可以參考下
    2015-05-05
  • JS取文本框中最小值的簡單實例

    JS取文本框中最小值的簡單實例

    這篇文章主要介紹了JS取文本框中最小值的簡單實例,有需要的朋友可以參考一下
    2013-11-11
  • 一文詳解JS中的事件循環(huán)機制

    一文詳解JS中的事件循環(huán)機制

    JavaScript是單線程的編程語言,只能同一時間內(nèi)做一件事。但是在遇到異步事件的時候,js線程并沒有阻塞,還會繼續(xù)執(zhí)行。這是因為JS有事件循環(huán)機制,本文就為大家詳細講解一下這一機制,需要的可以參考一下
    2022-03-03
  • javascript針對cookie的基本操作實例詳解

    javascript針對cookie的基本操作實例詳解

    這篇文章主要介紹了javascript針對cookie的基本操作,結(jié)合實例形式較為詳細的分析了JavaScript操作cookie的基本技巧,并給出了一個JavaScript操作cookie的完整類,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • 解決layui的table插件無法多層級獲取json數(shù)據(jù)的問題

    解決layui的table插件無法多層級獲取json數(shù)據(jù)的問題

    今天小編就為大家分享一篇解決layui的table插件無法多層級獲取json數(shù)據(jù)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • JavaScript內(nèi)存管理介紹

    JavaScript內(nèi)存管理介紹

    這篇文章主要介紹了JavaScript內(nèi)存管理介紹,本文講解了內(nèi)存生命周期、JavaScript的內(nèi)存分配、通過函數(shù)調(diào)用的內(nèi)存分配、當內(nèi)存不再需要使用時釋放等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • 微信小程序?qū)崿F(xiàn)拼圖小游戲

    微信小程序?qū)崿F(xiàn)拼圖小游戲

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)拼圖小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-10-10

最新評論

玉树县| 邳州市| 安平县| 柳河县| 图们市| 乐东| 峨眉山市| 卓尼县| 库尔勒市| 万宁市| 鄱阳县| 保定市| 凤翔县| 胶南市| 聂拉木县| 湖口县| 聂荣县| 建阳市| 会理县| 昌江| 霸州市| 清丰县| 越西县| 台中县| 枣强县| 建瓯市| 清丰县| 马山县| 陇西县| 新余市| 泰和县| 内黄县| 松桃| 霍城县| 堆龙德庆县| 徐闻县| 阿坝县| 曲靖市| 新田县| 池州市| 鄂托克旗|