从零开始手把手教你使用javascript+canvas开发一个塔防游戏02敌人自动寻路

简介: 从零开始手把手教你使用javascript+canvas开发一个塔防游戏02敌人自动寻路

项目演示


image.png


项目演示地址:

体验一下

项目源码:

项目源码

代码结构


image.png


本节做完效果


image.png

Enemy.js

//敌人类
function Enemy(cxt,img,type,x,y,width,height){
    this.cxt = cxt;
    this.img = img;
    this.x = x;//55
    this.y = y;//0
    this.width = width;
    this.height = height;
    //敌人类型
    this.type = type;
    this.sp = 2;
    //移动的方向
    this.dir = null;
    //下个移动位置
    this.nextPosition = null;
    //记录已经走过的位置
    this.hadWalk = {};
}
Enemy.prototype = {
    //敌人在图片中对应的位置
    enemyMap : [{x:0,y:0},{x:40,y:0},{x:80,y:0},{x:120,y:0},{x:160,y:0},{x:200,y:0},{x:240,y:0},{x:280,y:0},{x:320,y:0},{x:360,y:0},
        {x:400,y:0},{x:440,y:0},{x:480,y:0},{x:520,y:0},{x:560,y:0},{x:600,y:0},{x:640,y:0},{x:680,y:0},{x:720,y:0},{x:760,y:0}],
    //画出敌人
    draw : function(){
        //冰冻中,画出冰冻图
        if(this.frozenTime > 0){
            Canvas.drawImg(this.cxt,this.img,this.enemyMap[this.type].x,this.enemyMap[this.type].y+40,this.width,this.height,this.x,this.y,this.width,this.height);
        }
        //画出正常图
        else Canvas.drawImg(this.cxt,this.img,this.enemyMap[this.type].x,this.enemyMap[this.type].y,this.width,this.height,this.x,this.y,this.width,this.height);
        //计算血量百分比
        var persen = Math.floor(this.life / this.maxLife * 100) / 2;
        //画出血量
        Canvas.fillRect(this.cxt,this.x-5,this.y-5,persen,3,"rgba(38,223,116,0.8)");
    },
    //更新敌人信息
    update : function(){
        //超出坐标
        if(this.x >= 500){
            return false;
        }
        var xIndex = parseInt(this.x / 50,10),//1
            yIndex = parseInt(this.y / 50,10);//0
        //判断是否有下个移动位置信息,或者下哥移动位置信息是否已经走到了
        if(!this.nextPosition ||
            ((this.x >= this.nextPosition.x - 5 && this.x <= this.nextPosition.x)
                && (this.y >= this.nextPosition.y - 5 && this.y <= this.nextPosition.y))
        ){
            //走到最右侧
            if(xIndex + 1 >= 10){
                xIndex = -1;
            }
            else{
                //判断往下能否走
                if(MapData[xIndex][yIndex+1] && !this.hadWalk[xIndex+"_"+(yIndex+1)]){
                    this.dir = "down";
                    yIndex += 1;
                }
                //判断往右能否走
                else if(MapData[xIndex+1][yIndex]  && !this.hadWalk[(xIndex+1)+"_"+yIndex]){
                    this.dir = "right";
                    xIndex += 1;
                }
                else if(MapData[xIndex][yIndex-1] && !this.hadWalk[xIndex+"_"+(yIndex-1)]){
                    this.dir = "up";
                    yIndex -= 1;
                }
                else if(MapData[xIndex-1][yIndex] && !this.hadWalk[(xIndex-1)+"_"+yIndex]){
                    this.dir = "left";
                    xIndex -= 1;
                }
            }
            //是否走到最右侧
            if(xIndex == -1){
                this.nextPosition = {x:500,y:yIndex*50+5};
            }
            //设置下个移动位置
            else {
                this.nextPosition = {x:xIndex*50+5,y:yIndex*50+5};
                //记录已经走过的位置
                this.hadWalk[xIndex+"_"+yIndex] = true;
            }
        }
        //移动
        switch(this.dir){
            case "down":
                this.y += this.sp;
                break;
            case "up":
                this.y -= this.sp;
                break;
            case "left":
                this.x -= this.sp;
                break;
            case "right":
                this.x += this.sp;
                break;
            default:
                break;
        }
    }
}
//更新所有敌人信息
function updateEnemy(){
    var enemy;
    for(var i=0,l=Game.enemyList.length;i<l;i++){
        enemy = Game.enemyList[i];
        if(!enemy)continue;
        enemy.update();
    }
}
//画出所有敌人
function drawEnemy(){
    var enemy;
    for(var i=0,l=Game.enemyList.length;i<l;i++){
        enemy = Game.enemyList[i];
        if(!enemy)continue;
        enemy.draw();
    }
}


game.js修改


image.png


每50次循环出一个敌人


image.png

image.png

tool.js新增


image.png


自动寻路算法解析


坐标系

向右为x轴

向下为y轴

整个地图为500*500

// 游戏对象
        var hero = {
            speed: 2, // 每秒移动的像素
            x: 55,
            y: 0,
            srcx:120,
            srcy:40,
           flood:50,
        //移动的方向
        dir:null,
        //下个移动位置
        nextPosition: null,
        //记录已经走过的位置
        hadWalk:{}
        };

英雄像素转换为网格(10*10)坐标

var xIndex = parseInt(hero.y / 50, 10),
 yIndex = parseInt(hero.x / 50, 10);

最开始时,

xIndex = 1

yIndex = 0

初始时满足!hero.nextPosition

if (!hero.nextPosition ||
                 ((hero.x >= hero.nextPosition.x - 5 && hero.x <= hero.nextPosition.x) && (hero.y >= hero.nextPosition.y - 5 && hero.y <= hero.nextPosition.y))
             )

进入后,满足往下走

else {
                //判断往下能否走
                if(MapData[xIndex][yIndex+1] && !this.hadWalk[xIndex+"_"+(yIndex+1)]){
                    this.dir = "down";
                    yIndex += 1;
                }

此时

xIndex = 1

yIndex = 1

然后,

//设置下个移动位置
                 else {
                     hero.nextPosition = {y: xIndex * 50 + 5, x: yIndex * 50 + 5};
                     //记录已经走过的位置
                     hero.hadWalk[xIndex + "_" + yIndex] = true;
                 }

hero.nextPosition = {

x:55,y:55

}

然后,

//移动
            switch(hero.dir){
                case "down":
                    hero.y += hero.speed;
                    break;
                case "up":
                    hero.y -= hero.speed;
                    break;
                case "left":
                    hero.x -= hero.speed;
                    break;
                case "right":
                    hero.x += hero.speed;
                    break;
                default:
                    break;
            }

此时,

hero = {
           speed: 2, // 每秒移动的像素
           x: 2,
           y: 55,

循环回去:

然后在hero.x未满足条件:

if (!hero.nextPosition ||
                ((hero.x >= hero.nextPosition.x - 5 && hero.x <= hero.nextPosition.x) && (hero.y >= hero.nextPosition.y - 5 && hero.y <= hero.nextPosition.y))
            )

时,有25次(50/2),跳过上面条件里的代码,直接执行以下代码:

//移动
            switch(hero.dir){
                case "down":
                    hero.y += hero.speed;
                    break;
                case "up":
                    hero.y -= hero.speed;
                    break;
                case "left":
                    hero.x -= hero.speed;
                    break;
                case "right":
                    hero.x += hero.speed;
                    break;
                default:
                    break;
            }

当再次hero.x满足条件:

if (!hero.nextPosition ||
                ((hero.x >= hero.nextPosition.x - 5 && hero.x <= hero.nextPosition.x) && (hero.y >= hero.nextPosition.y - 5 && hero.y <= hero.nextPosition.y))
            )


时,重复之前的逻辑。

如此循环。

such that


项目源码:


项目源码

目录
相关文章
|
3天前
|
JavaScript
vue中使用 HotKeys.js 教程(按键响应、快捷键开发)
vue中使用 HotKeys.js 教程(按键响应、快捷键开发)
8 0
|
3天前
|
移动开发 前端开发 JavaScript
使用JavaScript和Canvas进行绘图
Canvas是HTML5的绘图工具,借助JavaScript实现网页上的图形、图像及动画创作。通过Canvas元素和2D渲染上下文,开发者能绘制图形、处理图像、制作动画,甚至用于游戏开发。基本步骤包括获取Canvas元素、设置绘图属性、绘制形状、处理图像以及实现动画。同时,注意性能优化,如减少不必要的重绘和使用Web Workers。Canvas结合WebGL还能实现3D效果,与Web Audio API结合则能做音频可视化。分享你的Canvas经验,探讨更多创意应用!
|
5天前
|
运维 JavaScript 前端开发
前端 JS 经典:vue 开发中的 base 和 publicPath
前端 JS 经典:vue 开发中的 base 和 publicPath
12 1
|
9天前
|
JavaScript 前端开发 程序员
探索Vue.js宝库:解锁基础知识与实用技能之门(1. 数据绑定与响应式 2. 条件与循环 3. 组件化开发;1. 路由管理与导航 2. 状态管理与Vuex 3. Vue.js的生命周期)
探索Vue.js宝库:解锁基础知识与实用技能之门(1. 数据绑定与响应式 2. 条件与循环 3. 组件化开发;1. 路由管理与导航 2. 状态管理与Vuex 3. Vue.js的生命周期)
14 1
|
2天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的使命召唤游戏助手附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的使命召唤游戏助手附带文章源码部署视频讲解等
8 0
|
3天前
|
开发框架 监控 JavaScript
企业级node.js开发框架 【egg.js】 实用教程
企业级node.js开发框架 【egg.js】 实用教程
7 0
|
5天前
|
移动开发 JavaScript
thinkPHP5.0开发微信H5页面分享接口signature验证失败,signature与微信 JS 接口签名校验工具返回结果不一致
thinkPHP5.0开发微信H5页面分享接口signature验证失败,signature与微信 JS 接口签名校验工具返回结果不一致
12 0
|
JSON JavaScript 前端开发
20+个超级实用的 JavaScript 开发技巧(下)
今天来分享几个JavaScript开发技巧,希望对你有所帮助~
108 0
|
JavaScript 前端开发
20+个超级实用的 JavaScript 开发技巧(上)
今天来分享几个JavaScript开发技巧,希望对你有所帮助~
106 0
|
1天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的个人健康管理系统小程序附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的个人健康管理系统小程序附带文章源码部署视频讲解等
10 2

相关实验场景

更多