Html飞机大战(九): 使徒来袭 (设计敌机)
好家伙,本篇介绍敌机
好了,按照惯例我们来理一下思路:
我们有一个敌机类,第一步当然是实例一个敌机对象,
然后我们把这个敌机放入我们的敌机群(敌机数组)
然后是熟悉的移动和绘制
那我们回顾一下子弹的生成逻辑
变量: 子弹 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飞机大战(九): 使徒来袭 (设计敌机)的更多相关文章
- 一、利用Python编写飞机大战游戏-面向对象设计思想
相信大家看到过网上很多关于飞机大战的项目,但是对其中的模块方法,以及使用和游戏工作原理都不了解,看的也是一脸懵逼,根本看不下去.下面我做个详细讲解,在做此游戏需要用到pygame模块,所以这一章先进行 ...
- 飞机大战编写以及Java的面向对象总结
面向对象课程完结即可编写一个简单的飞机大战程序.我觉得我需要总结一下 飞机大战中类的设计: 父类:FlyingObject(抽象类) 接口:Award .Enemy 子类:Hero.Bullet.Ai ...
- cocos2dx 3.0 飞机大战
因为课程须要.然后又水平有限.所以写了个飞机大战.加上不会画画.所以图片资源也是从微信apk解压出来的,设计思路參考的偶尔e网事. 闲话不说.先讲一下设计.大体上一共分为3个场景.场景以下是Layer ...
- 微信5.0 Android版飞机大战破解无敌模式手记
微信5.0 Android版飞机大战破解无敌模式手记 转载: http://www.blogjava.net/zh-weir/archive/2013/08/14/402821.html 微信5.0 ...
- web版canvas做飞机大战游戏 总结
唠唠:两天的时间跟着做了个飞机大战的游戏,感觉做游戏挺好的.说是用html5做,发现全都是js.说js里一切皆为对象,写的最多的还是函数,都是函数调用.对这两天的代码做个总结,希望路过的大神指点一下, ...
- MFC实现简单飞机大战(含游戏声音)
1 实验内容 本实验主要是实现简单的飞机大战游戏,包含游戏声音.碰撞后爆炸效果,有大小敌机等.所用到的知识点如下: 1.贴图技术 2.飞机类.子弹类实现 3.位图移动 4.碰撞判断,实现爆炸效果 5. ...
- 微信小游戏 demo 飞机大战 代码分析 (一)(game.js, main.js)
微信小游戏 demo 飞机大战 代码分析(一)(main.js) 微信小游戏 demo 飞机大战 代码分析(二)(databus.js) 微信小游戏 demo 飞机大战 代码分析(三)(spirit. ...
- Cocos2d-x 3.0final 终结者系列教程16-《微信飞机大战》实现
看到cocos2d-x推出了3.1版本号,真是每月一次新版本号,速度. 另一个好消息就是http://cn.cocos2d-x.org/上线了,祝贺!啥时候把我的视频和教程放上去呢?!! . 视频下载 ...
- 【Web前端Talk】无聊吗?写个【飞机大战】来玩吧(上篇)
01前言介绍 微信小游戏是基于微信客户端的游戏,它即点即玩,无需下载安装,体验轻便,可以和微信内的好友一起玩,比如PK.围观等,享受小游戏带来的乐趣.那如何开发一款属于自己的小游戏呢? 源码地址: h ...
随机推荐
- ssh隧道连接的方式连接数据库
最好用xshell做隧道连接,其他工具没接触过过 1.先新建一个会话 2.点进刚刚建好的连接,右击属性 3.点进隧道,添加,输入映射到本地的配置 4.完成之后用数据库连接工具连接即可 参考连接: ht ...
- CSCMS代码审计
很久之前审的了. 文章首发于奇安信攻防社区 https://forum.butian.net/share/1626 0x00 前言 CSCMS是一款强大的多功能内容管理系统,采用php5+mysql进 ...
- 物联网?快来看 Arduino 上云啦
作者:HelloGitHub-Anthony 这里是 HelloGitHub 推出的讲解开源硬件开发平台 Arduino 的系列教程. 第一篇:Arduino 介绍和开发环境搭建 第二篇:制作温湿度显 ...
- WPF开发随笔收录-报警闪烁效果实现
一.前言 工作中目前经手的项目是医疗相关的监护软件,所以会涉及到一些报警效果的实现,今天在这里就简单分享一下实现方式 二.正文 1.实现的方式比较的简单,就是通过一个Border控件,然后搭配Data ...
- DotNET程序员面向API编程的正确姿势
原文:https://blog.csdn.net/u013201439/article/details/49981071 补充:按照步骤成功加载文档后,选择索引可以快速发现相关的内容,如图
- UiPath文本操作Get Full Text的介绍和使用
一.Get Full Text操作的介绍 使用Get Full Text(获取全文本 )屏幕抓取方法从指示的UI元素中提取字符串及其信息 二.Get Full Text在UiPath中的使用 1. 打 ...
- 利用laravel-echo主动向服务端发送消息,实现在线状态管理
之前在网上翻了半天,也没有找到关于如何 通过laravel-echo主动发送消息 和 在laravel-websockets中自定义控制器 的文章或教程.无奈之下只能翻laravel-echo和lar ...
- 本机通过IP地址连接Ubuntu18.04+ on Vmware
一.Vmware-顶部菜单栏-编辑-虚拟网络编辑器: 点一下 添加一个NAT模式的网络:要记住名称,比如这里我的是VMnet8 子网ip可以自己写,建议全程就都按我这个写,后续方便校对. 点一下 NA ...
- S32K148-CAN收发
最近在搞一个转换板开发,大概意思把CAN信号转换成SPI信号,方案有两种:1)通过硬件电路直接把信号的bit位一位一位移给两个集成芯片:2)通过MCU接收CAN信号,再把信号变量转换成SPI信号发送给 ...
- SpringBoot配置文件读取过程分析
整体流程分析 SpringBoot的配置文件有两种 ,一种是 properties文件,一种是yml文件.在SpringBoot启动过程中会对这些文件进行解析加载.在SpringBoot启动的过程中, ...
