青草久久影院-青草久久伊人-青草久久久-青草久久精品亚洲综合专区-SM双性精跪趴灌憋尿调教H-SM脚奴调教丨踩踏贱奴

17站長(zhǎng)網(wǎng)

17站長(zhǎng)網(wǎng) 首頁(yè) 編程 JavaScript 查看內(nèi)容

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

2022-10-26 19:07| 查看: 2092 |來(lái)源: 互聯(lián)網(wǎng)

今天呢,主要和小伙伴們分享一下一個(gè)貪吃蛇游戲從構(gòu)思到實(shí)現(xiàn)的過(guò)程~因?yàn)槲也皇呛芟矚g直接PO代碼,所以只copy代碼的童鞋們請(qǐng)出門左轉(zhuǎn)不謝。

今天呢,主要和小伙伴們分享一下一個(gè)貪吃蛇游戲從構(gòu)思到實(shí)現(xiàn)的過(guò)程~因?yàn)槲也皇呛芟矚g直接PO代碼,所以只copy代碼的童鞋們請(qǐng)出門左轉(zhuǎn)不謝。

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

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

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

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

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

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

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

PS:~現(xiàn)在我回想起來(lái),當(dāng)時(shí)的確只想到這么多(⊙﹏⊙)

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

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

1

2

3

4

5

context.beginPath();

var bgImg = new Image();

bgImg.src = "img/background.png";

context.drawImage(bgImg, 0, 0, 600, 600);

context.closePath();

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

地圖上好像缺點(diǎn)什么……沒(méi)錯(cuò)就是禮物,所以我們現(xiàn)在生成禮物,那么問(wèn)題來(lái)了:禮物最多有幾個(gè)、生成位置、何時(shí)生成。

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

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

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

1

2

3

4

//隨機(jī)數(shù)

function selectfrom() {

   return Math.floor(Math.random() * 14 + 1);

}

然后再用求出的數(shù)乘以每一格子的寬度,即可求出生成的具體X坐標(biāo),因?yàn)槭钦叫危訷也一樣:

1

2

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

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

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

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

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

出生地:地圖中央或者自己定一個(gè)位置(按照格子來(lái)分),XY坐標(biāo)求取方式上面已經(jīng)說(shuō)過(guò)不再贅述。

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

移動(dòng)方式:通過(guò)定義一個(gè)全局變量記錄當(dāng)前方向(0、1、2、3,默認(rèn)1),并且使用計(jì)時(shí)器驅(qū)動(dòng)蛇運(yùn)動(dòng)。

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

如何判斷吃掉了禮物:每次蛇頭移動(dòng)時(shí),都要遍歷下禮物集合(上面有說(shuō)過(guò)),如果蛇頭將要移動(dòng)到的下個(gè)坐標(biāo)與之重合了,則視為吃掉了禮物。

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

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

移動(dòng)方式:通過(guò)定義一個(gè)全局變量記錄當(dāng)前方向(0、1、2、3,默認(rèn)1),并且使用計(jì)時(shí)器驅(qū)動(dòng)蛇運(yùn)動(dòng)。

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

如何判斷吃掉了禮物:每次蛇頭移動(dòng)時(shí),都要遍歷下禮物集合(上面有說(shuō)過(guò)),如果蛇頭將要移動(dòng)到的下個(gè)坐標(biāo)與之重合了,則視為吃掉了禮物。

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

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

移動(dòng)方式:通過(guò)定義一個(gè)全局變量記錄當(dāng)前方向(0、1、2、3,默認(rèn)1),并且使用計(jì)時(shí)器驅(qū)動(dòng)蛇運(yùn)動(dòng)。

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

如何判斷吃掉了禮物:每次蛇頭移動(dòng)時(shí),都要遍歷下禮物集合(上面有說(shuō)過(guò)),如果蛇頭將要移動(dòng)到的下個(gè)坐標(biāo)與之重合了,則視為吃掉了禮物。

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

var canvas = document.getElementById("mycanvas");//畫布主體

var context = canvas.getContext("2d");

var timer;//計(jì)時(shí)器

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; //當(dāng)前食物數(shù)量

var sinak = []; //貪吃蛇坐標(biāo)集

var get = []; //禮物坐標(biāo)集

var MoveTo = 1; //移動(dòng)方向 默認(rèn)1(右)

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

我們先來(lái)畫蛇:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

//畫貪吃蛇

function drawsinak(sl) { //sl默認(rèn)長(zhǎng)度

    context.beginPath();

    context.fillStyle = "#000";

    var ling = 0; //貪吃蛇被打印長(zhǎng)度

    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); //默認(rèn)出生點(diǎn):7,6默認(rèn)中心點(diǎn)

            sinak.push(xsplit * (7 - i) + ',' + ysplit * 6);

        }

    }

    context.fill();

    context.closePath();

}

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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();

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

//移動(dòng)方法

//[c]移動(dòng)方向 上右下左 0123

function sinakMove(c) {

    context.beginPath();

  

    //默認(rèn)右側(cè)為頭

    var tou = sinak[0]; //頭

    var weiba = sinak[sinak.length - 1]; //尾巴

  

    var oldX = tou.split(',')[0]; //頭部舊X坐標(biāo)

    var oldY = tou.split(',')[1]; //頭部舊Y坐標(biāo)

  

    var newX = 0; //頭部最新X坐標(biāo)

    var newY = 0; //頭部最新Y坐標(biāo)

  

    //計(jì)算頭部最新XY坐標(biāo)

    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; //有沒(méi)有吃到禮物 0沒(méi)有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--; //禮物計(jì)數(shù)減少1個(gè)

            get.splice(i, 1); //清空禮物

            flag = 1;

        }

    }

    //如果沒(méi)有吃到禮物,則判斷是否碰到障礙或吃到自己

    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);

            }

        }

    }

  

    //如果沒(méi)有吃到禮物,那么進(jìn)行普通移動(dòng)

    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();

}

控制蛇的方向:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

//鍵盤事件

document.onkeydown = function (event) {

    var e = event || window.event || arguments.callee.caller.arguments[0];

    var move = 0; //移動(dòng)方向

    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; //修改當(dāng)前移動(dòng)方向

};

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

tag標(biāo)簽:JS+Canvas 貪吃蛇
本文最后更新于 2022-10-26 19:07,某些文章具有時(shí)效性,若有錯(cuò)誤或已失效,請(qǐng)?jiān)诰W(wǎng)站留言或聯(lián)系站長(zhǎng):17tui@17tui.com
·END·
站長(zhǎng)網(wǎng)微信號(hào):w17tui,關(guān)注站長(zhǎng)、創(chuàng)業(yè)、關(guān)注互聯(lián)網(wǎng)人 - 互聯(lián)網(wǎng)創(chuàng)業(yè)者營(yíng)銷服務(wù)中心

免責(zé)聲明:本站部分文章和圖片均來(lái)自用戶投稿和網(wǎng)絡(luò)收集,旨在傳播知識(shí),文章和圖片版權(quán)歸原作者及原出處所有,僅供學(xué)習(xí)與參考,請(qǐng)勿用于商業(yè)用途,如果損害了您的權(quán)利,請(qǐng)聯(lián)系我們及時(shí)修正或刪除。謝謝!

17站長(zhǎng)網(wǎng)微信二維碼

始終以前瞻性的眼光聚焦站長(zhǎng)、創(chuàng)業(yè)、互聯(lián)網(wǎng)等領(lǐng)域,為您提供最新最全的互聯(lián)網(wǎng)資訊,幫助站長(zhǎng)轉(zhuǎn)型升級(jí),為互聯(lián)網(wǎng)創(chuàng)業(yè)者提供更加優(yōu)質(zhì)的創(chuàng)業(yè)信息和品牌營(yíng)銷服務(wù),與站長(zhǎng)一起進(jìn)步!讓互聯(lián)網(wǎng)創(chuàng)業(yè)者不再孤獨(dú)!

掃一掃,關(guān)注站長(zhǎng)網(wǎng)微信

大家都在看

    熱門排行

      最近更新

        返回頂部
        主站蜘蛛池模板: 长篇高h肉爽文丝袜 | 国产中文字幕免费观看 | 99精品国产福利在线观看 | 亚洲 视频 在线 国产 精品 | 久久精选视频 | 日韩精品久久日日躁夜夜躁影视 | 国产精品美女久久久久AV超清 | 国产电影三级午夜a影院 | 一道精品视频一区二区 | 国产午夜亚洲精品不卡电影 | 2023国产精品一卡2卡三卡4卡 | 快播看黄片 | 爱情岛aqdlttv | 帅哥操美女 | 女人高潮了拔出来了她什么感觉 | YELLOW高清在线观看2019 | 免费观看久久 | 99久久免费热在线精品 | 精品国产乱码久久久久久上海公司 | 中文字幕无码亚洲字幕成A人蜜桃 | 欧美 日韩 无码 有码 在线 | 日本xxxx19 | 熟妇无码乱子成人精品 | 亚洲 欧美 日本 国产 高清 | 亚洲AV久久婷婷蜜臀无码不卡 | 青青青伊人 | 99久久久免费精品免费 | YELLOW免费观看完整视频 | 最近的2019中文字幕国语HD | 久久青青草视频在线观 | 渔夫床满艳史bd高清在线直播 | 九九热国产视频 | 色姊姊真舒服 | 一起碰一起噜一起草视频 | 色爱区综合激情五月综合激情 | 国内精品久久久久影院亚洲 | gv肉片视频免费观看 | 伊人草| 国产亚洲日韩在线播放不卡 | 99久久精品费精品蜜臀AV | 吃胸亲吻吃奶摸下面免费视频 |