javascript開發(fā)植物大戰(zhàn)僵尸

簡介

這是我給社團學弟寫的一個小demo芙沥,一個簡易版植物大戰(zhàn)僵尸诲祸,基本上涉及了不少簡單而且重要的小知識,對學習前端入門應該還是有些幫助的而昨,現(xiàn)在我?guī)Т蠹襾矸治龇治鲞@個小demo

github地址:https://github.com/likaixuan/record/blob/master/demo/植物大戰(zhàn)僵尸

`8BSJ`5T~SW$RW)0B%G{$V0.png

demo實現(xiàn)的功能點

1.掉落星星救氯、點擊吃掉星星增加積分

2.購買植物并放置在草地上、購買需要支付一定的星星歌憨、星星余額不足不能購買星星

3.植物與僵尸有血量着憨、射速、護甲值一類的屬性

4.定時發(fā)送炮彈务嫡、產(chǎn)生僵尸甲抖、炮彈觸碰僵尸與僵尸觸碰植物時,會經(jīng)過自身屬性轉(zhuǎn)換傷害心铃、根據(jù)血量不同展示
不同的狀態(tài)圖片

布局

貼一下代碼

@charset "utf-8";
            body,
            ul {
                padding: 0px;
                margin: 0px;
            }
            /*地圖*/
            
            #map {
                position: relative;
                width: 1400px;
                height: 600px;
                background: url(1.jpg);
            }
            /*路*/
            
            #road {
                position: absolute;
                z-index: 2;
                left: 250px;
                top: 200px;
                background: url(8.png);
                width: 755px;
                height: 110px;
                z-index: 10;
            }
            /*植物*/
            
            #road .plant {
                position: absolute;
                width: 50px;
                height: 50px;
                top: 0px;
                bottom: 0px;
                margin: auto 0px;
            }
            /*僵尸*/
            
            #road .createZombies {
                position: absolute;
                height: 128px;
                width: 66px;
                top: 0px;
                bottom: 0px;
                right: 0px;
                margin: auto 0px;
                z-index: 1000;
            }
            /*子彈*/
            
            #road .bullet {
                position: absolute;
                width: 35px;
                height: 35px;
                top: 0px;
                bottom: 0px;
                margin: auto 0px;
                z-index: 1001;
            }
            /*道具欄*/
            
            #props {
                position: absolute;
                bottom: 0px;
                left: 100px;
                z-index: 1000;
                background: gainsboro;
                list-style: none;
                text-align: center;
            }
            
            #props li {
                position: relative;
                display: inline-block;
                height: 50px;
                width: 50px;
            }
            
            #props li span {
                position: absolute;
                padding: 2px;
                right: 2px;
                top: 2px;
                border-radius: 100%;
                background: gold;
            }
            
            #props li img {
                border: 2px solid gray;
                height: 100%;
                width: 100%;
                cursor: pointer;
            }
            
            #props li img.action {
                border: 3px solid green;
            }
            /*星星數(shù)量*/
            
            #star-number {
                position: absolute;
                z-index: 1000;
                height: 50px;
                width: 50px;
                border-radius: 50px;
                text-align: center;
                line-height: 50px;
                background: gold;
                color: white;
                font-weight: 900;
                font-size: 20px;
            }
            /*降落星星*/
            
            .star {
                position: absolute;
                width: 50px;
                height: 50px;
                z-index: 1000;
            }

代碼的注釋也很清楚了准谚、我的思路就是給容器div一個背景圖片,也就是咱們看到的地圖去扣,然后道具欄呀柱衔、草地呀都是通過定位的方式去搞定的

JS

掉落星星
//降落星星
            setInterval(function() {
                //創(chuàng)建一個img標簽
                var img = document.createElement("img");
                //給img標簽賦值上我們寫的star class
                img.className = "star";
                //將圖片地址賦值給src
                img.src = "star.gif"

                map.appendChild(img);
                //隨機生成img的水平位置 而且不能超出地圖
                img.style.left = Math.random() * (map.offsetWidth - img.offsetWidth) + 'px';
                setInterval(function() {
                    img.style.top = img.offsetTop + 5 + "px";
                    //碰到地圖邊界 刪除img
                    if(img.offsetTop >= map.offsetHeight - img.offsetHeight) {
                        map.removeChild(img);
                    }
                }, 100);

            }, starTimer);

就是間隔一段時間創(chuàng)建一個星星、而且星星的x軸位置是生成的隨機數(shù) 而且這個隨機數(shù)是在一個區(qū)間內(nèi)的(不能超出地圖)這個厅篓,通過offset家族的一系列屬性 我們可以判斷星星是不是掉落出界了秀存,出界就刪除這個節(jié)點。

點擊星星加分數(shù)
//事件委托
            map.onclick = function(event) {
                //當點擊時給star
                if(event.target.tagName === "IMG" && event.target.className === "star") {
                    setStar(10);
                    //誰被點擊 this就是誰 parentNode 就是 this的 父節(jié)點
                    event.target.parentNode.removeChild(event.target);

                }

            }
//設置星星數(shù) 減去傳負數(shù)羽氮、加則傳正數(shù)
            function setStar(n) {
                star += n;
                starNumber.innerText = star;
            }

這個我們需要做的就是判斷當這個星星圖片被點擊的時候去給總星數(shù)加一個數(shù)值或链、但是我們怎么知道他什么時候被點擊呢? 那么大家肯定說給這個星星添加點擊事件呀档押,那么問題來了澳盐,星星是間隔一段時間創(chuàng)建的一個祈纯,也就是說我們要給每個星星都綁定一個單擊事件,這樣其實不是最優(yōu)解叼耙,更好的辦法是我們可以對星星的父容器設置一個點擊事件

事件冒泡:就比如我們這個星星是在地圖上面的腕窥,我們點擊星星的時候它是觸發(fā)星星還是地圖的click事件呢?答案是先觸發(fā)上面的星星再觸發(fā)下面的地圖筛婉,這個其實就是事件冒泡的一個簡單理解(不懂的話可以百度簇爆、谷歌一下事件冒泡、事件捕獲)
我們通過給父節(jié)點地圖設置點擊事件爽撒,當我們點擊在地圖上方的星星時入蛆,其實也是會逐漸往下冒泡的,而我們的點擊事件會有一個默認的參數(shù) event(事件對象) 它有一個屬性 event.target 她就是當前觸發(fā)此事件的目標節(jié)點硕勿,比如我點擊在星星上 這個event.target 就是星星哨毁。所以就有了我上方的判斷,判斷是不是img標簽而且class叫star 如果點擊的是星星那么就用我們設置的setStar方法去設置總星數(shù)源武。

選擇植物
//事件委托
            map.onclick = function(event) {
                //選擇道具
                if(event.target.tagName === "IMG" && event.target.className === "plant") {
                    if(event.target.dataset.star <= star) {
                        clearStyle();
                        event.target.className = "action plant";
                        plant = event.target.cloneNode();
                    }

                }
                //當點擊時給star
                if(event.target.tagName === "IMG" && event.target.className === "star") {
                    setStar(10);
                    //誰被點擊 this就是誰 parentNode 就是 this的 父節(jié)點
                    event.target.parentNode.removeChild(event.target);

                }

            }
//清除道具選中樣式
            function clearStyle() {

                var t = props.getElementsByTagName("img");
                for(var i = 0; i < t.length; i++) {
                    t[i].className = "plant";
                }
            }

思路跟之前點擊星星一樣扼褪,用事件委托的方式去判斷哪個道具被點擊了,道具身上有自定義屬性粱栖,定義了一系列的屬性话浇,比如護甲、hp闹究、購買所需star數(shù)凳枝,上面加了一個if判斷就是為了讓總星數(shù)小于該道具star數(shù)不能選中該道具,選中的則會加一個樣式跋核,這里需要注意的一點是岖瑰,明確 html負責結(jié)構(gòu)、css負責樣式砂代、js負責控制蹋订,雖然我們可以通過js去設置這個選中邊框,但是我們最好是通過class的方式去設置樣式刻伊,讓它們各司其職

放置植物

            road.onclick = function(event) {
                //植物可擺放的區(qū)間
                if(event.offsetX > 25 && event.offsetX + 50 < this.offsetWidth) {
                    if(!!plant && event.target.className !== "action plant") {
                        plant.style.left = event.offsetX - 25 + 'px';
                        //購買植物減去相應star
                        setStar(-plant.dataset.star);
                        //放置植物
                        this.appendChild(plant);
                        //植物數(shù)組
                        plantArr.push(plant);
                        //戰(zhàn)斗力為零 不發(fā)射子彈
                        if(parseInt(plant.dataset.damage) !== 0) {
                            //創(chuàng)建子彈
                            bullet.push(createBullet(plant.dataset.speed, plant.dataset.damage, event.offsetX + 25));
                        }
                        //清除道具選中樣式
                        clearStyle();
                        //清除選中道具
                        plant = null;
                    }

                }
            }
// 生成子彈
            function createBullet(speed, damage, left) {
                /*
                 * speed 射速
                 * damage 傷害
                 */
                var img = document.createElement("img");
                img.className = 'bullet';
                //設置到創(chuàng)建的子彈標簽上
                img.dataset.speed = speed;
                img.dataset.damage = damage;
                img.style.left = left + 'px';
                img.src = '6.gif';
                road.appendChild(img);
                return img;
            }

植物不是隨便位置就能放置的露戒,給路加click就是說,我肯定會放置在這條路上捶箱,因為只有在點擊路的時候才會觸發(fā)放置操作智什、也是通過offset系列屬性去控制放置位置區(qū)間、放置成功時要減去對應的star數(shù)丁屎、并將新添加的植物添加到數(shù)組里荠锭,我們是通過一個數(shù)組來維護植物列表的、再來判斷植物的攻擊力是不是為0 為0說明是土豆一類的植物不會發(fā)射子彈晨川,否則創(chuàng)建子彈并將子彈放置到植物前方

發(fā)射子彈
// 間隔一段時間 生成一波子彈
            setInterval(function() {
                for(var i = 0; i < plantArr.length; i++) {
                    //戰(zhàn)斗力不為0
                    if(parseInt(plantArr[i].dataset.damage) !== 0) {
                        //創(chuàng)建子彈
                        bullet.push(createBullet(plantArr[i].dataset.speed, plantArr[i].dataset.damage, plantArr[i].offsetLeft + 25));
                    }
                }
            }, 9000);
            // 讓子彈飛
            setInterval(function() {
                for(var i = 0; i < bullet.length; i++) {
                    bullet[i].style.left = bullet[i].offsetLeft + parseInt(bullet[i].dataset.speed) + "px";
                    for(var j = 0; j < zombiesArr.length; j++) {
                        //打到僵尸身上了 -30的原因是 圖片有空白
                        if(bullet[i].offsetLeft + bullet[i].offsetWidth - 30 >= zombiesArr[j].offsetLeft) {
                            /*
                             * data-star 所需star數(shù)
                             * data-hp hp
                             * data-defense 防御力
                             * data-damage 攻擊力
                             * data-speed 攻速
                             */
                            if(bullet[i].offsetLeft - zombiesArr[j].offsetLeft - zombiesArr[j].offsetWidth < 5) {
                                //計算傷害
                                calcDamage(zombiesArr[j], bullet[i], '11.gif');
                                //受傷狀態(tài)
                                zombiesState(j, zombiesArr[j], zombiesArr);
                                //從地圖中刪除
                                road.removeChild(bullet[i]);
                                //從數(shù)組中刪除
                                bullet.splice(i, 1);
                                break;
                            }
                            //打到地圖外 刪除子彈
                            if(bullet[i].offsetLeft + bullet[i].offsetWidth > road.offsetWidth) {
                                bullet[i].parentNode.removeChild(bullet[i]);
                                //從數(shù)組中刪除
                                bullet.splice(i, 1);
                            }

                        }
                    }
                }
            }, 20);

子彈這方面的思路是這樣的证九,我每一段時間就在有攻擊力的植物面前產(chǎn)生子彈删豺,子彈(所有子彈存在一個數(shù)組里)會一直被定時器去控制移動,檢測到子彈與僵尸碰撞時(生成僵尸和子彈類似就不貼代碼了)愧怜,就會給僵尸減掉一定血量呀页、血量是經(jīng)過計算的、具體代碼大家可以看看github的完整示例拥坛,代碼都很簡單蓬蝶。

基本情況其實就是這樣,那么我們再來總結(jié)捋一捋

各種屬性例如血量猜惋、攻擊力都存放在html5的自定義屬性里疾党,添加的植物會放置到植物數(shù)組里、定時器添加的僵尸會放置到僵尸數(shù)組里惨奕,子彈會間隔一段時間在有攻擊力的植物面前添加一顆(其實就是定時器遍歷植物列表去添加子彈),定時器會遍歷子彈讓子彈去移動竭钝,也會遍歷僵尸讓僵尸去移動梨撞,僵尸移動到植物上,以及子彈碰到僵尸都會有一個傷害香罐,這個傷害會由我們單獨封裝的函數(shù)去計算卧波。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市庇茫,隨后出現(xiàn)的幾起案子港粱,更是在濱河造成了極大的恐慌,老刑警劉巖旦签,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件查坪,死亡現(xiàn)場離奇詭異,居然都是意外死亡宁炫,警方通過查閱死者的電腦和手機偿曙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羔巢,“玉大人望忆,你說我怎么就攤上這事「透眩” “怎么了启摄?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長幽钢。 經(jīng)常有香客問我歉备,道長,這世上最難降的妖魔是什么匪燕? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任威创,我火速辦了婚禮落午,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肚豺。我一直安慰自己溃斋,他們只是感情好,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布吸申。 她就那樣靜靜地躺著梗劫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪截碴。 梳的紋絲不亂的頭發(fā)上梳侨,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音日丹,去河邊找鬼走哺。 笑死,一個胖子當著我的面吹牛哲虾,可吹牛的內(nèi)容都是我干的丙躏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼束凑,長吁一口氣:“原來是場噩夢啊……” “哼晒旅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起汪诉,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤废恋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扒寄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鱼鼓,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年该编,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚓哩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡上渴,死狀恐怖岸梨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情稠氮,我是刑警寧澤曹阔,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站隔披,受9級特大地震影響赃份,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一抓韩、第九天 我趴在偏房一處隱蔽的房頂上張望纠永。 院中可真熱鬧,春花似錦谒拴、人聲如沸尝江。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炭序。三九已至,卻和暖如春苍日,著一層夾襖步出監(jiān)牢的瞬間惭聂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工相恃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辜纲,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓拦耐,卻偏偏與公主長得像耕腾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子揩魂,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)炮温,斷路器火脉,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • ----------------------- 頁面 1----------------------- 2013 ...
    長春傳齊3閱讀 4,545評論 0 1
  • 每天你花在朋友圈的時間應該是不少的,除了看別人的朋友圈柒啤,編輯自己的朋友圈也應該會花你不少的時間吧(偷笑~偷笑~偷...
    何貳萌閱讀 778評論 0 1