草庐IT

Html飞机大战(九): 使徒来袭 (设计敌机)

养肥胖虎 2023-03-28 原文

好家伙,本篇介绍敌机

 

好了,按照惯例我们来理一下思路:

 

我们有一个敌机类,第一步当然是实例一个敌机对象,

然后我们把这个敌机放入我们的敌机群(敌机数组)

然后是熟悉的移动和绘制

 

那我们回顾一下子弹的生成逻辑

变量: 子弹  bullet  弹夹(用来装子弹的东西)bulletList[] 

方法:装填子弹  绘制子弹 移动子弹

子弹发射的物理逻辑是很简单的:

生产第一个子弹,推入弹夹中,绘制弹夹(即绘制弹夹中的所有子弹),

生产第二个子弹,同样推入弹夹,移动第一颗子弹(应该说是改变第一颗子弹的y坐标),绘制弹夹中的所有子弹 

。。。。。。

生产第n个子弹,推入弹夹中,改变第n-1颗子弹的Y坐标,绘制弹夹中的所有子弹

 

有没有感觉到两者逻辑的相似之处

(像啊,太像了)

 

 

子弹和敌机的处理,本质上是用的是同一套逻辑

 

那么,开始干活:

 

1.配置项

这里我们会用到两种类型的配置项E1和E2

(因为我们有两种类型的敌人,大敌机和小敌机,其中e1为小敌机(血少),e2为大敌机(血厚))

先设置一个数组存放图片资源

//e1用于存放小敌机的图片素材
        const e1 = {
            live: [],
            death: [],
        }
        e1.live[0] = new Image();
        e1.live[0].src = "img/enemy1.jpg"
        e1.death[0] = new Image();
        e1.death[0].src = "img/enemy1_boom1.jpg"
        e1.death[1] = new Image();
        e1.death[1].src = "img/enemy1_boom2.jpg"
        e1.death[2] = new Image();
        e1.death[2].src = "img/enemy1_boom3.jpg"

        //e2用于存放小敌机的图片素材
        const e2 = {
            live: [],
            death: [],
        }
        e2.live[0] = new Image();
        e2.live[0].src = "img/enemy2.jpg"
        e2.death[0] = new Image();
        e2.death[0].src = "img/enemy2_boom1.jpg"

 

 

 

  

 

 

 

 (图片素材来自网络)

 

 

 

 2.敌机配置项

//小敌机
        const E1 = {
            type: 1,
            width: 57,
            height: 51,
            life: 1, //少点血,一下打死
            score: 1,
            frame: e1,
            minSpeed: 20,
            maxSpeed: 10,
        }
        //大敌机
        const E2 = {
            type: 2,
            width: 69,
            height: 95,
            life: 2,
            frame: e2,
            minSpeed: 50,
            maxSpeed: 20,
        }
minSpeed: 50,
maxSpeed: 20,
值得说明一下,这两个玩意是为了弄敌机的随机速度(更刺激一点,但实际上好像没什么感觉)
关于如何弄到一个”随机速度“,接着往下看


3.敌机类

class Enemy {

            constructor(config) {
                //敌机类型
                this.type = config.type;
                //敌机宽,高
                this.width = config.width;
                this.height = config.height;
                //敌机的初始化位置
                this.x = Math.floor(Math.random() * (480 - config.width));
                //这里我们让飞机从头部开始渲染,所以Y轴坐标自然是飞机高度的负值
                this.y = -config.height;
                //敌机生命
                this.life = config.life;
                //敌机分数
                this.score = config.score;
                //敌机图片库
                this.frame = config.frame;
                //此刻展示的图片
                this.img = null;
                //活着的证明
                this.live = true;
                // this.minSpeed = config.minSoeed;
                // this.maxSpeed = config.speed;
                //随机去生成一个速度
                this.speed = Math.floor(Math.random() * (config.minSpeed - config.maxSpeed + 1)) + config.maxSpeed;
                //最后渲染的时间
                this.lastTime = new Date().getTime();

            }
            //移动敌机
            move() {
                const currentTime = new Date().getTime();
                //
                
                if (currentTime - this.lastTime >= this.speed) {
                    // console.log("此处为this.frame"+this.frame.live[0]);
                    this.img = this.frame.live[0];
                    this.y++;
                    //时间修正
                    this.lastTime = currentTime;
                }
            }

            //渲染敌机方法
            paint(context) {
                // console.log("此处为this.img"+this.img);
                if(this.img !=null){
                    context.drawImage(this.img, this.x, this.y);  
                }
                
            }
        }

 

 

3.1.随机速度

先浅浅的说明一下

随机数方法 Math.random

 

这玩意会在[0,1)也就是在0到1之间取一个值

然后问题来了,这是一个半开半闭区间,也就是说它会取到0但是不会取到1

this.speed = Math.floor(Math.random() * (config.minSpeed - config.maxSpeed + 1)) + config.maxSpeed;

在这里我们要取的是一个10到20之间的速度由于我们向下取整

Math.floor(Math.random() * (config.minSpeed - config.maxSpeed )) + config.maxSpeed;

必然只能取得10-19之间的数


于是我们在(config.minSpeed - config.maxSpeed )中加一

变成(Math.random() * (config.minSpeed - config.maxSpeed +1))


(聪明的你一定能很快想明白,而愚蠢的我想了很久才想明白)


3.2.敌机的移动方法

move() {
                const currentTime = new Date().getTime();
                //
                
                if (currentTime - this.lastTime >= this.speed) {
                    // console.log("此处为this.frame"+this.frame.live[0]);
                    this.img = this.frame.live[0];
                    this.y++;
                    //时间修正
                    this.lastTime = currentTime;
                }
            }

移动同样的用时间判定的方式去控制速率

现在和过去的时间差大于速度,更新地址


3.3.渲染方法

paint(context) {
                // console.log("此处为this.img"+this.img);
                if(this.img !=null){
                    context.drawImage(this.img, this.x, this.y);  
                }
                
            }

嗯,非常好理解了,多加的一个if是为了防止出现空img导致报错


4.全局函数(生产敌机)

//以下三项均为全局变量
        const enemies = [];
        //敌机产生的速率
        const ENEMY_CREATE_INTERVAL = 2000;
        let ENEMY_LASTTIME = new Date().getTime();

        //全局函数 用于生产敌机
        function createComponent() {
            const currentTime = new Date().getTime();
            const forenemyTime = new Date().getTime();

            //一手经典判断
            if (currentTime - ENEMY_LASTTIME >= ENEMY_CREATE_INTERVAL) {
                //当时间满足 实例化一架敌机 放入敌机数组中
                // 小飞机 70% 中飞机30%
                //用随机数去弄概率
                //[0,99]
                //Math.random()=>[0,1)*100
                //EnemyTypeRandom产生的随机数用于判断产生不同的飞机
                let EnemyTypeRandom = Math.floor(Math.random() * 100);
                if (EnemyTypeRandom > 70) {
                    enemies.push(new Enemy(E1));
                } else if (EnemyTypeRandom < 30) {
                    enemies.push(new Enemy(E2));
                }
                console.log(enemies);
                //更新时间
                ENEMY_LASTTIME = currentTime;
            }
        }

这里同样的,我们用随机数去控制出现大/小敌机的概率

(E1,E2分别是大小敌机的配置项)


let EnemyTypeRandom = Math.floor(Math.random() * 100);
                if (EnemyTypeRandom > 70) {
            //产小敌机 enemies.push(new Enemy(E1)); }
else if (EnemyTypeRandom < 30) {
            //产大敌机 enemies.push(new Enemy(E2)); }

你细品,这个控制得还是非常巧妙的

 

5.全局函数渲染


到这里就非常简单了

这里也揭开了前面的谜底

因为敌机生成和子弹生成的逻辑太过相似

所以我们把他们放到同一个全局函数是一个非常明智的选择

//全局函数 来移动所有的子弹/敌人组件
        function judgeComponent() {
            console.log("judge被触发");
            for (let i = 0; i < hero.bulletList.length; i++) {
                hero.bulletList[i].move();
            }
            for(let i=1;i<enemies.length;i++){
                enemies[i].move();
            }
        }
        //全局函数 来绘制所有的子弹/敌人组件
        function paintComponent() {
            for (let i = 0; i < hero.bulletList.length; i++) {
                hero.bulletList[i].paint(context);
            }
            for(let i=1;i<enemies.length;i++){
                enemies[i].paint(context);
            }
        }

 

6.方法调用


case RUNNING:
                        sky.judge();
                        sky.paint(context);
                        //加载主角

                        hero.paint(context);
                        hero.shoot();
                        createComponent();
                        //子弹发射
                        judgeComponent();
                        paintComponent();
                        deleteComponent();
                        // context.drawImage(hero_frame.live[0], 0, 0);
                        break;

 


 
ok,来看看效果吧:

 

 

 

确实是非常地nice啊

 

有关Html飞机大战(九): 使徒来袭 (设计敌机)的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  4. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  5. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  6. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  7. ruby-on-rails - capybara ::ElementNotFound:无法找到 xpath "/html" - 2

    我正在学习http://ruby.railstutorial.org/chapters/static-pages上的RubyonRails教程并遇到以下错误StaticPagesHomepageshouldhavethecontent'SampleApp'Failure/Error:page.shouldhave_content('SampleApp')Capybara::ElementNotFound:Unabletofindxpath"/html"#(eval):2:in`text'#./spec/requests/static_pages_spec.rb:7:in`(root)'

  8. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  9. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  10. ruby - 如何使用 Ruby 将 CSV 文件读入 HTML 表格? - 2

    我正在尝试将一个简单的CSV文件读入HTML表格以在浏览器中显示,但我遇到了麻烦。这就是我正在尝试的:Controller:defshow@csv=CSV.open("file.csv",:headers=>true)end查看:输出:NameStartDateEndDateQuantityPostalCode基本上我只获取标题,而不会读取和呈现CSV正文。 最佳答案 这最终成为最终解决方案:Controller:defshow#OpenaCSVfile,andthenreaditintoaCSV::Tableobjectforda

随机推荐