坦克大战js小游戏源码 HTML5坦克大战游戏代码(HTML+CSS+JavaScript )

HTML5坦克大战网页小游戏,完美还原小霸王学习机效果,以坦克战斗及保卫基地为主题,属于策略型类游戏。

游戏介绍

操作说明: :玩家1:wasd上左下右,space射击;玩家2:方向键,enter射击。n下一关,p上一关。

游戏的设计思路

1、要有作战区域,这有canvas 可以帮我们解决。
2、要有坦克,包括自己的、敌人的。
3、要能有子弹,包括自己的、敌人的。
4、要有炸弹。
5、我的坦克要能按键发射子弹,敌人的坦克要能连续自动发射子弹。
6、我的子弹打到敌人时子弹要消失,同时敌人爆炸并消失,不能再发子弹。
以上是游戏设计的简单思路,这是初步设计,接下来以代码来分析详细的设计过程:

一、游戏演示

在这里插入图片描述
在这里插入图片描述

二、代码目录

在这里插入图片描述

三、代码实现

<!--
 * @Author: your name
 * @Date: 2021-08-09 13:54:49
 * @LastEditTime: 2021-08-09 13:55:38
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \04a1814eae5f272fc467de30f227ca6d\index.html
-->
<!DOCTYPE html>
<html lang="zh" class="no-js demo-1">

<head>
    <title>坦克大战js小游戏源码 HTML5坦克大战游戏代码 </title>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="js/jquery.min.js"></script>
    <script src="js/Helper.js"></script>
    <script src="js/keyboard.js"></script>
    <script src="js/const.js"></script>
    <script src="js/level.js"></script>
    <script src="js/crackAnimation.js"></script>
    <script src="js/prop.js"></script>
    <script src="js/bullet.js"></script>
    <script src="js/tank.js"></script>
    <script src="js/num.js"></script>
    <script src="js/menu.js"></script>
    <script src="js/map.js"></script>
    <script src="js/Collision.js"></script>
    <script src="js/stage.js"></script>
    <script src="js/main.js"></script>
    <style type="text/css">
        #canvasDiv canvas {
            position: absolute;
        }

        #canvasDiv {
            position: absolute;
            left: 30%;
            }
    </style>
</head>
<body>
    <div class="container">
        <center>

            <head>
                <h3>操作说明:玩家1:wasd上左下右,space射击;玩家2:方向键,enter射击。n下一关,p上一关。</h3>
            </head>
        </center>
        <div class="main clearfix">
            <div id="canvasDiv">
                <canvas id="wallCanvas"></canvas>
                <canvas id="tankCanvas"></canvas>
                <canvas id="grassCanvas"></canvas>
                <canvas id="overCanvas"></canvas>
                <canvas id="stageCanvas"></canvas>
            </div>
        </div>
    </div>
</body>
</html>

1.绘制子弹

1.碰撞检测,
2.临界检测,
3.判断子弹是否碰撞了其他子弹
4.是否击中坦克

var Bullet = function(context, owner, type, dir) {
    this.ctx = context;
    this.x = 0;
    this.y = 0;
    this.owner = owner; //子弹的所属者
    this.type = type; //1、玩家  2、敌方
    /**
     * 碰撞检测
     */
    this.isHit = function() {
        if (this.isDestroyed) {
            return;
        }
        //临界检测
        if (this.x < map.offsetX) {
            this.x = map.offsetX;
            this.hit = true;
        } else if (this.x > map.offsetX + map.mapWidth - this.size) {
            this.x = map.offsetX + map.mapWidth - this.size;
            this.hit = true;
        }
        if (this.y < map.offsetY) {
            this.y = map.offsetY;
            this.hit = true;
        } else if (this.y > map.offsetY + map.mapHeight - this.size) {
            this.y = map.offsetY + map.mapHeight - this.size;
            this.hit = true;
        }
        //子弹是否碰撞了其他子弹
        if (!this.hit) {
            if (bulletArray != null && bulletArray.length > 0) {
                for (var i = 0; i < bulletArray.length; i++) {
                    if (bulletArray[i] != this && this.owner.isAI != bulletArray[i].owner.isAI && bulletArray[i].hit == false && CheckIntersect(bulletArray[i], this, 0)) {
                        this.hit = true;
                        bulletArray[i].hit = true;
                        break;
                    }
                }
            }
        }

        if (!this.hit) {
            //地图检测
            if (bulletMapCollision(this, map)) {
                this.hit = true;
            }
            //是否击中坦克
            if (this.type == BULLET_TYPE_PLAYER) {
                if (enemyArray != null || enemyArray.length > 0) {
                    for (var i = 0; i < enemyArray.length; i++) {
                        var enemyObj = enemyArray[i];
                        if (!enemyObj.isDestroyed && CheckIntersect(this, enemyObj, 0)) {
                            CheckIntersect(this, enemyObj, 0);
                            if (enemyObj.lives > 1) {
                                enemyObj.lives--;
                            } else {
                                enemyObj.distroy();
                            }
                            this.hit = true;
                            break;
                        }
                    }
                }
            }

2.检测碰撞

1.检测2个物体是否碰撞
2.坦克与地图块碰撞
3.子弹与地图块的碰撞

/**
 * 检测2个物体是否碰撞
 * @param object1 物体1
 * @param object2 物体2
 * @param overlap 允许重叠的大小
 * @returns {Boolean} 如果碰撞了,返回true
 */
function CheckIntersect(object1, object2, overlap) {
    //    x-轴                      x-轴
    //  A1------>B1 C1              A2------>B2 C2
    //  +--------+   ^              +--------+   ^
    //  | object1|   | y-轴         | object2|   | y-轴
    //  |        |   |              |        |   |
    //  +--------+  D1              +--------+  D2
    //
    //overlap是重叠的区域值
    A1 = object1.x + overlap;
    B1 = object1.x + object1.size - overlap;
    C1 = object1.y + overlap;
    D1 = object1.y + object1.size - overlap;

    A2 = object2.x + overlap;
    B2 = object2.x + object2.size - overlap;
    C2 = object2.y + overlap;
    D2 = object2.y + object2.size - overlap;

    //假如他们在x-轴重叠
    if (A1 >= A2 && A1 <= B2 ||
        B1 >= A2 && B1 <= B2) {
        //判断y-轴重叠
        if (C1 >= C2 && C1 <= D2 || D1 >= C2 && D1 <= D2) {
            return true;
        }
    }
    return false;
}

/**
 * 坦克与地图块碰撞
 * @param tank 坦克对象
 * @param mapobj 地图对象
 * @returns {Boolean} 如果碰撞,返回true
 */
function tankMapCollision(tank, mapobj) {
    //移动检测,记录最后一次的移动方向,根据方向判断+-overlap,
    var tileNum = 0; //需要检测的tile数
    var rowIndex = 0; //map中的行索引
    var colIndex = 0; //map中的列索引
    var overlap = 3; //允许重叠的大小
    //根据tank的x、y计算出map中的row和col
    if (tank.dir == UP) {
        rowIndex = parseInt((tank.tempY + overlap - mapobj.offsetY) / mapobj.tileSize);
        colIndex = parseInt((tank.tempX + overlap - mapobj.offsetX) / mapobj.tileSize);
    } else if (tank.dir == DOWN) {
        //向下,即dir==1的时候,行索引的计算需要+tank.Height
        rowIndex = parseInt((tank.tempY - overlap - mapobj.offsetY + tank.size) / mapobj.tileSize);
        colIndex = parseInt((tank.tempX + overlap - mapobj.offsetX) / mapobj.tileSize);
    } else if (tank.dir == LEFT) {
        rowIndex = parseInt((tank.tempY + overlap - mapobj.offsetY) / mapobj.tileSize);
        colIndex = parseInt((tank.tempX + overlap - mapobj.offsetX) / mapobj.tileSize);
    } else if (tank.dir == RIGHT) {
        rowIndex = parseInt((tank.tempY + overlap - mapobj.offsetY) / mapobj.tileSize);
        //向右,即dir==3的时候,列索引的计算需要+tank.Height
        colIndex = parseInt((tank.tempX - overlap - mapobj.offsetX + tank.size) / mapobj.tileSize);
    }
    if (rowIndex >= mapobj.HTileCount || rowIndex < 0 || colIndex >= mapobj.wTileCount || colIndex < 0) {
        return true;
    }
    if (tank.dir == UP || tank.dir == DOWN) {
        var tempWidth = parseInt(tank.tempX - map.offsetX - (colIndex) * mapobj.tileSize + tank.size - overlap); //去除重叠部分
        if (tempWidth % mapobj.tileSize == 0) {
            tileNum = parseInt(tempWidth / mapobj.tileSize);
        } else {
            tileNum = parseInt(tempWidth / mapobj.tileSize) + 1;
        }
        for (var i = 0; i < tileNum && colIndex + i < mapobj.wTileCount; i++) {
            var mapContent = mapobj.mapLevel[rowIndex][colIndex + i];
            if (mapContent == WALL || mapContent == GRID || mapContent == WATER || mapContent == HOME || mapContent == ANOTHREHOME) {
                if (tank.dir == UP) {
                    tank.y = mapobj.offsetY + rowIndex * mapobj.tileSize + mapobj.tileSize - overlap;
                } else if (tank.dir == DOWN) {
                    tank.y = mapobj.offsetY + rowIndex * mapobj.tileSize - tank.size + overlap;
                }
                return true;
            }
        }
    }

/**
 * 子弹与地图块的碰撞
 * @param bullet 子弹对象
 * @param mapobj 地图对象
 */
function bulletMapCollision(bullet, mapobj) {
    var tileNum = 0; //需要检测的tile数
    var rowIndex = 0; //map中的行索引
    var colIndex = 0; //map中的列索引
    var mapChangeIndex = []; //map中需要更新的索引数组
    var result = false; //是否碰撞
    //根据bullet的x、y计算出map中的row和col
    if (bullet.dir == UP) {
        rowIndex = parseInt((bullet.y - mapobj.offsetY) / mapobj.tileSize);
        colIndex = parseInt((bullet.x - mapobj.offsetX) / mapobj.tileSize);
    } else if (bullet.dir == DOWN) {
        //向下,即dir==1的时候,行索引的计算需要+bullet.Height
        rowIndex = parseInt((bullet.y - mapobj.offsetY + bullet.size) / mapobj.tileSize);
        colIndex = parseInt((bullet.x - mapobj.offsetX) / mapobj.tileSize);
    } else if (bullet.dir == LEFT) {
        rowIndex = parseInt((bullet.y - mapobj.offsetY) / mapobj.tileSize);
        colIndex = parseInt((bullet.x - mapobj.offsetX) / mapobj.tileSize);
    } else if (bullet.dir == RIGHT) {
        rowIndex = parseInt((bullet.y - mapobj.offsetY) / mapobj.tileSize);
        //向右,即dir==3的时候,列索引的计算需要+bullet.Height
        colIndex = parseInt((bullet.x - mapobj.offsetX + bullet.size) / mapobj.tileSize);
    }
    if (rowIndex >= mapobj.HTileCount || rowIndex < 0 || colIndex >= mapobj.wTileCount || colIndex < 0) {
        return true;
    }

    if (bullet.dir == UP || bullet.dir == DOWN) {
        var tempWidth = parseInt(bullet.x - map.offsetX - (colIndex) * mapobj.tileSize + bullet.size);
        if (tempWidth % mapobj.tileSize == 0) {
            tileNum = parseInt(tempWidth / mapobj.tileSize);
        } else {
            tileNum = parseInt(tempWidth / mapobj.tileSize) + 1;
        }
        for (var i = 0; i < tileNum && colIndex + i < mapobj.wTileCount; i++) {
            var mapContent = mapobj.mapLevel[rowIndex][colIndex + i];
            if (mapContent == WALL || mapContent == GRID || mapContent == HOME || mapContent == ANOTHREHOME) {
                //bullet.distroy();
                result = true;
                if (mapContent == WALL) {
                    //墙被打掉
                    mapChangeIndex.push([rowIndex, colIndex + i]);
                } else if (mapContent == GRID) {

                } else {
                    isGameOver = true;
                    break;
                }
            }
        }
    }
    //更新地图
    map.updateMap(mapChangeIndex, 0);
    return result;
}

3.绘制菜单

1.画菜单
2.画选择坦克
3.画背景
4.画选择坦克

/**
 * 游戏开始菜单
 **/

var Menu = function(context) {
    this.ctx = context;
    this.x = 0;
    this.y = SCREEN_HEIGHT;
    this.selectTank = new SelectTank();
    this.playNum = 1;
    this.times = 0;

    /**
     * 画菜单
     */
    this.draw = function() {
        this.times++;
        var temp = 0;
        if (parseInt(this.times / 6) % 2 == 0) {
            temp = 0;
        } else {
            temp = this.selectTank.size;
        }
        if (this.y <= 0) {
            this.y = 0;
        } else {
            this.y -= 5;
        }
        this.ctx.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
        this.ctx.save();
        //画背景
        this.ctx.drawImage(MENU_IMAGE, this.x, this.y);
        //画选择坦克
        this.ctx.drawImage(RESOURCE_IMAGE, POS["selectTank"][0], POS["selectTank"][1] + temp, this.selectTank.size, this.selectTank.size,
            this.selectTank.x, this.y + this.selectTank.ys[this.playNum - 1], this.selectTank.size, this.selectTank.size);
        this.ctx.restore();
    };

    /**
     * 选择坦克上下移动
     */
    this.next = function(n) {
        this.playNum += n;
        if (this.playNum > 2) {
            this.playNum = 1;
        } else if (this.playNum < 1) {
            this.playNum = 2;
        }
    };
};

4.绘制坦克

1.坦克基类
2.临界检测
3.碰撞检测
4.地图检测

/**
 * 坦克基类
 * @returns
 */
var Tank = function() {
    this.x = 0;
    this.y = 0;
    this.size = 32; //坦克的大小
    this.dir = UP; //方向0:上 1:下 2:左3:右
    this.speed = 1; //坦克的速度
    this.frame = 0; //控制敌方坦克切换方向的时间
    this.hit = false; //是否碰到墙或者坦克
    this.isAI = false; //是否自动
    this.isShooting = false; //子弹是否在运行中
    this.bullet = null; //子弹
    this.shootRate = 0.6; //射击的概率
    this.isDestroyed = false;
    this.tempX = 0;
    this.tempY = 0;
    /**
     * 碰撞检测
     */
    this.isHit = function() {
        //临界检测
        if (this.dir == LEFT) {
            if (this.x <= map.offsetX) {
                this.x = map.offsetX;
                this.hit = true;
            }
        } else if (this.dir == RIGHT) {
            if (this.x >= map.offsetX + map.mapWidth - this.size) {
                this.x = map.offsetX + map.mapWidth - this.size;
                this.hit = true;
            }
        } else if (this.dir == UP) {
            if (this.y <= map.offsetY) {
                this.y = map.offsetY;
                this.hit = true;
            }
        } else if (this.dir == DOWN) {
            if (this.y >= map.offsetY + map.mapHeight - this.size) {
                this.y = map.offsetY + map.mapHeight - this.size;
                this.hit = true;
            }
        }
        if (!this.hit) {
            //地图检测
            if (tankMapCollision(this, map)) {
                this.hit = true;
            }
        }
    
    /**
     * 射击
     */
    this.shoot = function(type) {
        if (this.isAI && emenyStopTime > 0) {
            return;
        }
        if (this.isShooting) {
            return;
        } else {
            var tempX = this.x;
            var tempY = this.y;
            this.bullet = new Bullet(this.ctx, this, type, this.dir);
            if (this.dir == UP) {
                tempX = this.x + parseInt(this.size / 2) - parseInt(this.bullet.size / 2);
                tempY = this.y - this.bullet.size;
            } else if (this.dir == DOWN) {
                tempX = this.x + parseInt(this.size / 2) - parseInt(this.bullet.size / 2);
                tempY = this.y + this.size;
            } else if (this.dir == LEFT) {
                tempX = this.x - this.bullet.size;
                tempY = this.y + parseInt(this.size / 2) - parseInt(this.bullet.size / 2);
            } else if (this.dir == RIGHT) {
                tempX = this.x + this.size;
                tempY = this.y + parseInt(this.size / 2) - parseInt(this.bullet.size / 2);
            }
    };

    /**
     * 坦克被击毁
     */
    this.distroy = function() {
        this.isDestroyed = true;
        crackArray.push(new CrackAnimation(CRACK_TYPE_TANK, this.ctx, this));
        TANK_DESTROY_AUDIO.play();
    };
};

/**
 * 玩家坦克
 * @param context 画坦克的画布
 * @returns
 */
var PlayTank = function(context) {
    this.ctx = context;
    this.lives = 3; //生命值
    this.isProtected = true; //是否受保护
    this.protectedTime = 500; //保护时间
    this.offsetX = 0; //坦克2与坦克1的距离
    this.speed = 2; //坦克的速度

    this.draw = function() {
        this.hit = false;
        this.ctx.drawImage(RESOURCE_IMAGE, POS["player"][0] + this.offsetX + this.dir * this.size, POS["player"][1], this.size, this.size, this.x, this.y, this.size, this.size);
        if (this.isProtected) {
            var temp = parseInt((500 - this.protectedTime) / 5) % 2;
            this.ctx.drawImage(RESOURCE_IMAGE, POS["protected"][0], POS["protected"][1] + 32 * temp, 32, 32, this.x, this.y, 32, 32);
            this.protectedTime--;
            if (this.protectedTime == 0) {
                this.isProtected = false;
            }
        }

    };

};
EnemyOne.prototype = new Tank();

四、web前端入门到高级(视频+源码+资料+面试)一整套 (教程)

web前端 零基础-入门到高级 (视频+源码+开发软件+学习资料+面试题) 一整套 (教程)
适合入门到高级的童鞋们入手~送1000套HTML+CSS+JavaScript模板网站
在这里插入图片描述


五、源码获取

❉ ~ 关注我,点赞博文~ 每天带你涨知识!

❉1.看到这里了就 [点赞+好评+收藏] 三连 支持下吧,你的「点赞,好评,收藏」是我创作的动力。

❉ 2.关注我 ~ 每天带你学习 :各种前端插件、3D炫酷效果、图片展示、文字效果、以及整站模板 、大学生毕业HTML模板 、期末大作业模板 、等! 「在这里有好多 前端 开发者,一起探讨 前端 Node 知识,互相学习」!

❉3.以上内容技术相关问题可以相互学习,可关注↓公Z号 获取更多源码 !

在这里插入图片描述

六、更多HTML期末大作业(成品下载)

>>>戳我>>>点击进入200例期末大作业作品

200多例 HTML5期末考核大作业源码 包含 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 军事、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他 可满足大学生网页大作业网页设计需求, 喜欢的可以下载!
在这里插入图片描述
在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐