html+js 實現 推箱子 貪吃蛇和簡單的飛機大戰

YangjulongTrue發表於2020-10-24

推箱子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #app{

        }
        *{
            margin: 0;
            padding: 0;
        }
        #app span{
            width: 20px;
            height: 20px;
            display: inline-block;
        }
        .person{
          background:    red;
        }
        .kong{
            background: white;
        }
        .shitu{
            background: #8c8c8c;
        }
        .yellow{
            background: yellow;
        }
        .xiaozi{
            background: burlywood;
        }
        #context{
            position: absolute;
            right: 10%;
            top: 25%;
            font-size: 50px;
            color: #00FF00;
        }
    </style>
</head>
<body onkeydown="doKeyDown(event)">
<div id="app"></div>
<canvas id="canvas"></canvas>
<div id="context"></div>
</body>
<script>
    window.onload=function(){
        // let can = document.getElementById("canvas");
        // cxt=can.getContext("2d");
        load(levels[cuindex],true);
        //3 5  j  35 1
        //  let image = new Image();
        //  image.src="3.png";
        //  image.οnlοad=function (){
        //      cxt.drawImage(image,0,35,100,100);
        //  }

    }
    let x,y,flag=0,xian;//記錄上一個值
    let maxcount,cucount=0;//最多的 值
    let cuindex=0;//當前關卡
    let conll;//克隆物件
    let map = new Map();
    let map2 = new Map();//食物 2,3
    map.set(0,"<span class=\"kong\"></span>");
    map.set(1,"<span class=\"shitu\"></span>");
    map.set(2,"<span class=\"yellow\"></span>");
    map.set(3,"<span class=\"xiaozi\"></span>");
    map.set(4,"<span class=\"person\"></span>");
    function dian(x,y,key) {
        let arr;
        switch (key) {
            case 37://左鍵頭 0
                arr=[x,y-1];
                break;
            case 38://上鍵頭 1
                arr=[x-1,y];
                break;
            case 39://右箭頭 2
                arr=[x,y+1];
                break;
            case 40://下箭頭 3
                arr=[x+1,y];
                break;
        }
        return arr;
    }
    function doKeyDown(event){
        if(event.keyCode%37<4){
        xian=event.keyCode;
        let dian1 = dian(x,y,xian);
       move(dian1[0],dian1[1]);

        }
    }
    function move(cx,cy) {
        //判斷下一步的值是什麼
       switch (levels[cuindex][cx][cy]) {
        case 0:
        case 2:
            //離開判斷 是否上一個是我 現在的 位置是否是食物
            //x y
            flag=levels[cuindex][cx][cy];
            levels[cuindex][cx][cy]=4;
            if(map2.get(x+","+y))
                levels[cuindex][x][y]=2;
            else{
                if(flag!==2){
                    levels[cuindex][x][y]=flag;
                }else{
                    levels[cuindex][x][y]=0;
                }
            }
            x=cx;
            y=cy;
            load(levels[cuindex]);
            break;
            case 3 : //是箱子
                let a = dian(cx,cy,xian);
                switch (levels[cuindex][a[0]][a[1]]) {
                    case 0:
                    case 2:
                        //flag=levels[0][cx][cy]
                        if(levels[cuindex][a[0]][a[1]]===2){
                            cucount++;
                        }
                        //判斷之前的是否為 箱子
                        if(map2.get(cx+","+cy)){
                            cucount--;
                        }
                        levels[cuindex][a[0]][a[1]]=3;
                        levels[cuindex][cx][cy]=4;
                        levels[cuindex][x][y]=flag;
                        x=cx;
                        y=cy;
                        load(levels[cuindex]);
                        break;
                }
                break;
       }
        if(cucount===maxcount){
            //替換
            levels[cuindex]=conll;
            load(levels[++cuindex],true);
        }
        else
            info();
    }
    function info() {
        document.getElementById("context").innerText="當前關卡"+cuindex+"完成了的"+cucount+"還有"+(maxcount-cucount);

    }
    function load(arr,flag){
        let byId = document.getElementById("app");
        byId.innerHTML="";
        if(flag) {//第一次 的引數設定
            conll=[arr.length];
            maxcount=0;
            cucount=0;
            map2.clear();
            info();
        }
       for (let i=0;i<arr.length;i++){
           byId.innerHTML+="<div>"
           for (let j=0;j<arr[i].length;j++){
               byId.innerHTML+=map.get(arr[i][j]);
               if(flag) {
                   if(!conll[i])
                   conll[i]=[];
                   conll[i][j]=arr[i][j];
               if(arr[i][j]===4){
                   x=i;
                   y=j;
               }
               if(arr[i][j]===2){
                   map2.set(i+","+j,true);
                       maxcount++;
                   }
               }
           }
           byId.innerHTML+="</div>"
       }
    }
    //地圖
    let levels=[];
    levels[0]=[
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,1,2,1,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,0],
        [0,0,0,0,1,1,1,3,0,3,2,1,0,0,0,0],
        [0,0,0,0,1,2,0,3,4,1,1,1,0,0,0,0],
        [0,0,0,0,1,1,1,1,3,1,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]];
    levels[1]=[
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0],
        [0,0,0,0,1,4,0,0,1,0,0,0,0,0,0,0],
        [0,0,0,0,1,0,3,3,1,0,1,1,1,0,0,0],
        [0,0,0,0,1,0,3,0,1,0,1,2,1,0,0,0],
        [0,0,0,0,1,1,1,0,1,1,1,2,1,0,0,0],
        [0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0],
        [0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0],
        [0,0,0,0,0,1,0,0,0,1,1,1,1,0,0,0],
        [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]];


    levels[2]=[
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0],
        [0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0],
        [0,0,0,1,1,3,1,1,1,0,0,0,1,0,0,0],
        [0,0,0,1,0,4,0,3,0,0,3,0,1,0,0,0],
        [0,0,0,1,0,2,2,1,0,3,0,1,1,0,0,0],
        [0,0,0,1,1,2,2,1,0,0,0,1,0,0,0,0],
        [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]];
    levels[3]=[
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0],
        [0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0],
        [0,0,0,0,1,4,3,0,1,0,0,0,0,0,0,0],
        [0,0,0,0,1,1,3,0,1,1,0,0,0,0,0,0],
        [0,0,0,0,1,1,0,3,0,1,0,0,0,0,0,0],
        [0,0,0,0,1,2,3,0,0,1,0,0,0,0,0,0],
        [0,0,0,0,1,2,2,5,2,1,0,0,0,0,0,0],
        [0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]];

</script>
</html>

貪吃蛇

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        #contie span{
            width: 20px;
            height: 20px;
            display: inline-block;
        }
        .person{
            background:    red;
        }
        .kong{
            background: #bce8f1;
        }
        .shitu{
            background: #8c8c8c;
        }
        .yellow{
            background: yellow;
        }
        .xiaozi{
            background: burlywood;
        }
        #context{
            position: absolute;
            right: 10%;
            top: 25%;
            font-size: 50px;
            color: #00FF00;
        }

    </style>
</head>
<body onkeydown="doKeyDown(event)">
<div id="contie">

</div>
</body>
<script>
    // 0 空白 1 為食物 2 為 蛇
    let arr=[];
    let max=9;
    let xiaosize=2;//小蛇長度
    let point=[{x:1,y:1},{x:1,y:2}];//小蛇點數 1.2 -->>>  1.1
    let eat={x:5,y:5};//食物位置
    let dom;//操作物件
    let postion=39;//方向
    let map = new Map();
    map.set(0,"<span class=\"kong\"></span>");
    map.set(1,"<span class=\"shitu\"></span>");
    map.set(2,"<span class=\"yellow\"></span>");
    initial();
    function initial() {
        dom=document.getElementById("contie");
        //初始化資料
        for (let i=0;i<max;i++){
            arr[i]=[];
            for (let j=0;j<max;j++)
                arr[i][j]=0;
        }
        for (let i=0;i<point.length;i++){
            arr[point[i].x][point[i].y]=2;
        }
        arr[eat.x][eat.y]=1;
        playgame();
    }
    function xuanyan() {
        dom.innerHTML="";
        for (let i=0;i<max;i++){
            for (let j=0;j<max;j++){
              dom.innerHTML+=map.get(arr[i][j]);
            }
            dom.innerHTML+="<br>";
        }
    }
    function playgame() {
        xuanyan();
        dom.hello=setInterval(function () {
            //清空上一次的座標
                    arr[point[0].x][point[0].y]=0;
                //移動 根據方向 移動 只需要改變頭和尾巴
            for (let i=0;i<point.length;i++){
                //交換 0<1<2
                // 1<2<3
                if(i+1<point.length){
                    point[i].x=point[i+1].x;
                    point[i].y=point[i+1].y;
                }else{
                    switch (postion) {
                        case 37:
                            point[xiaosize-1].y--;
                            break;
                        case 38:
                            point[xiaosize-1].x--;
                            break;
                        case 39:
                            point[xiaosize-1].y++;
                            break;
                        case 40:
                            point[xiaosize-1].x++;
                            break;
                    }
                    //監測是否碰撞到邊緣
                    if(point[xiaosize-1].x<0||point[xiaosize-1].x>=max||point[xiaosize-1].y<0||point[xiaosize-1].y>=max){
                        clearInterval(dom.hello);
                        return   alert("撞牆了");
                    }
                    if(f(point[xiaosize-1].x,point[xiaosize-1].y,xiaosize-1)){
                        clearInterval(dom.hello);
                        return   alert("吃到自己了");
                    }

                }
            }
            //吃到eat ;
            if(arr[point[xiaosize-1].x][point[xiaosize-1].y]===1){
                point.push({x:0,y:0});
                //後移一位
                for (let i=xiaosize-1;i>=0;i--){
                 point[i+1].x=point[i].x;
                point[i+1].y=point[i].y;
                }
                xiaosize++;//新增長度
                //新增尾巴
              if(point[1].x===point[2].x){
                  point[0].x=point[1].x;
                  point[0].y= point[1].y<point[2].y?point[1].y-1:point[1].y+1;
              }else{
                  point[0].y=point[1].y;
                  point[0].x= point[1].x<point[2].x?point[1].x-1:point[1].x+1;
              }
              //重新生成食物並且不能在蛇裡面
                do {
                    eat.x = parseInt(Math.random()*max);
                    eat.y = parseInt(Math.random()*max);
                } while(f(eat.x,eat.y))
                arr[eat.x][eat.y]=1;
                arr[point[0].x][point[0].y]=2;
                arr[point[xiaosize-1].x][point[xiaosize-1].y]=2;
            }else
                arr[point[xiaosize-1].x][point[xiaosize-1].y]=2;
                xuanyan();
        },300)
    }
    function doKeyDown(event){
        if(event.keyCode>36&&event.keyCode<41)
            postion=event.keyCode;
    }
    //判斷x和y是否在蛇上
    function f(x,y,flag) {
        for (let i=0;i< (flag!=null?flag:point.length);i++) {
          if(point[i].x===x&&point[i].y===y)
              return true;
        }
        return  false;
    }

</script>
</html>

簡單的飛機大戰

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>

        *{
            margin: 0;
            padding: 0;
        }
        #contie span{
            width: 20px;
            height: 20px;
            display: inline-block;
        }
        .person{
            background:    red;
        }
        .kong{
            background: #c1e2b3;
        }
        .shitu{
            background: #8c8c8c;
        }
        .yellow{
            background: yellow;
        }
        .xiaozi{
            background: burlywood;
        }
        #context{
            position: absolute;
            right: 10%;
            top: 25%;
            font-size: 50px;
            color: #00FF00;
        }
    </style>
</head>
<body onkeydown="doKeyDown(event)">
<div id="contie">

</div>
<div id="context"></div>

</body>
<script>
    //0 空氣 1 自己 2 敵人 3 自己的子彈 4 為敵人子彈
    //兩張地圖 下面為 地圖 上面為 子彈
    let arr=[];
    let two=[];
    let max=18;
    let point=[{x:max-1,y:max/2}];//預設在最下面 玩家座標
    let dom,dom2;
    let zidan;
    let diren;//敵人的集合
    let direnzidan;//敵人子彈的集合
    let dirensize=0;//敵人的數量
    let xiaom=0;//擊殺敵人數量
    let zidians=0;//子彈數量
    let xielang=4;//玩家血量
    let map = new Map();
    map.set(0,"<span class=\"kong\"></span>");
    map.set(1,"<span class=\"shitu\"></span>");
    map.set(2,"<span class=\"yellow\"></span>");
    map.set(3,"<span class=\"xiaozi\"></span>");
    map.set(4,"<span class=\"person\"></span>");
    function initial() {
        dom=document.getElementById("contie");
        dom2=document.getElementById("context");
        zidan=new Linklist();
        diren=new Linklist();
        direnzidan=new Linklist();
        //初始化資料
        for (let i=0;i<max;i++){
            arr[i]=[];
            two[i]=[];
            for (let j=0;j<max;j++){
                two[i][j]=0;
                arr[i][j]=0;
            }
        }
        //渲染玩家
        for (let i=0;i<point.length;i++){
            arr[point[i].x][point[i].y]=1;
        }
        playgame();
    }
    //新增敵人
    function creatediren() {
        diren.add(new Node(0,parseInt(Math.random()*max),2));
    }
    //敵人移動的函式
    function dirmove(node) {
        node.y=postion123(node.y);
        node.x=postion123(node.x);
        //判斷我移動的位置是否有玩家子彈
       if(two[node.x][node.y]===3){
           let s = zidan.search(node.x,node.y);
           s.x=0;//設定子彈物件不可達到
           two[node.x][node.y]=0;
           node.x=max;//設定敵人不可達到
           dirensize--;//敵人數量減
           xiaom++;
           info();
       }else //沒有死亡就隨機開火
       if(Math.random()>0.2){
           direnzidan.add(new Node(node.x+1,node.y,4));
        }
    }
    function info(str) {

    dom2.innerText="共打了"+zidians+"子彈 幹掉"+xiaom+"敵人"+xielang+"血量"+(str?str:"");

    }
    //下一步的 座標
    function postion123(x) {
        switch (x) {
            case 0:
                return 1;
            case max:
                return max-1;
            default:
               return x+(Math.random()>0.5?1:-1);
              }
    }
    //渲染函式 把 二維陣列 轉換
    function xuanyan() {
        dom.innerHTML="";
        for (let i=0;i<max;i++){
            for (let j=0;j<max;j++){
                if(two[i][j]!==0){//如果有子彈優先渲染子彈
                    dom.innerHTML+=map.get(two[i][j]);
                }else
                dom.innerHTML+=map.get(arr[i][j]);
            }
            dom.innerHTML+="<br>";
        }
    }
    function playgame() {
        info();
        xuanyan();
        let reomve={zidan:0,dzidan:0,diren:0}//記錄我要清除的數量
        dom.hello=setInterval(function () {
            if(dirensize<3){//當敵人小於3 建立
                creatediren();
                dirensize++;
            }
            //渲染玩家子彈
            zidan.Gaidian(zidan,reomve.zidan,(s)=>{
                two[s.x][s.y]=0;
                if(s.x>=1){
                    two[s.x-1][s.y]=s.data;
                    s.x--;
                }else{//小於 1 出介面
                    reomve.zidan++;
                }
            },0);
            //渲染敵人
            diren.Gaidian(diren,reomve.diren,(s)=>{
                if(s.x<max){
                    arr[s.x][s.y]=0;
                    dirmove(s);
                    if(s.x<max)
                    arr[s.x][s.y]=s.data;
                }else{
                    reomve.diren++;
                }
            },max);
            //渲染敵人子彈
            direnzidan.Gaidian(direnzidan,reomve.dzidan,(s)=>{
                if(s.x<max){// s
                    two[s.x][s.y]=0;
                    s.x++;
                    if(s.x<max){
                        two[s.x][s.y]=s.data;
                        //判斷我是否計中玩家
                       if( arr[s.x][s.y]===1){
                           xielang--;//減少血量
                           info();
                           if(xielang===0){//為0清除 遊戲結束
                               clearInterval(dom.hello);
                               info("gameover");
                           }
                       }
                    }

                }else{
                    reomve.dzidan++;
                }
            },max);
            xuanyan();
        },50)
    }
    function doKeyDown(event){
        if(event.keyCode>36&&event.keyCode<41){
            postion=event.keyCode;
            //移動玩家
            let dian1 = dian(point[0].x,point[0].y,postion);
            //不可以動
            if(dian1[0]<0||dian1[0]>=max||dian1[1]<0||dian1[1]>=max){

            }else{
                //原來的清空
                arr[point[0].x][point[0].y]=0;
                point[0].x=dian1[0];//修改點
                point[0].y=dian1[1];
                arr[point[0].x][point[0].y]=1;//更新點
            }
        }else if(event.keyCode===32){//空格發射子彈
            //在原來物件的上面給一個子彈
            zidan.add(new Node(point[0].x-1,point[0].y,3));
            zidians++;
            info();
        }
    }
    function dian(x,y,key) {
        let arr;
        switch (key) {
            case 37://左鍵頭 0
                arr=[x,y-1];
                break;
            case 38://上鍵頭 1
                arr=[x-1,y];
                break;
            case 39://右箭頭 2
                arr=[x,y+1];
                break;
            case 40://下箭頭 3
                arr=[x+1,y];
                break;
        }
        return arr;
    }
    class Node{
        constructor(x,y,data,next) {
            this.x=x;
            this.y=y;
            this.data=data;
            this.next=next;
        }
    }
    class Linklist{
        constructor() {
        this.root=null;//第一個
        this.last=null;//最後一個
        }
        add(node){
            if(this.root==null){
                this.root=node;
                this.last=node;
            }else{
                this.last.next=node;
                this.last=this.last.next;
            }
        }
        //搜尋x 和 y 返回物件
        search(x,y){
            let s=this.root;
            while(s!=null){
                if(s.x===x&&s.y===y) return s;
                s=s.next;
            }
        }
        //清理不用的物件  把 x為val 的幹掉
        remove(a,val){
            for(let i=0;i<a;i++)
            this.root=this.deleteNode(this.root,val);
            let s = this.root;
            while(s!=null){
            if(s.next==null) break;
              s=s.next;
            }
            this.last=s;
        }
        deleteNode(head, val) {
            if(head==null) return null;
            if(head.x ===val){
                return head.next;
            }
            if(head.next==null) return head;
            if(head.next.x === val){
                head.next = head.next.next;
            }else{
                head.next=this.deleteNode(head.next,val);
            }return head;
        };
        //連結串列 不可達數量 回撥 我清理的值
        Gaidian(node,xx,F,val){
            let s = node.root;
            xx=0;
            while(s!=null){
                F(s);
                s=s.next;
            }
            if(xx>10){//清理物件
                node.remove(xx,val);
            }
        }
    }
    initial();
</script>
</html>

相關文章