好家伙,飞机大战终于开始弄了

这会有很多很多复杂的东西,但是我们总要从最简单,和最基础的部分开始,

 

我们先从背景开始弄吧!

1.绘制静态背景

这里我们会用到canvas

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewprot" content="width-devic-width,initial-scale=1.0">
<title>飞机大战</title>
<style>
*{
padding: 0;
margin: 0;
}
canvas{
border: 1px solid red;
margin: auto;
}
#stage{
width: 480px;
height: 650px;
margin: auto;
}
</style>
</head>
<body>
<div id="stage">
<canvas id="canvas" width="480" height="650"></canvas>
</div>
<script>
// 1.让画笔能够绘制图片
// 1.1找到这个画布
const canvas = document.querySelector("#canvas");
// 1.2.利用这个画布初始换一个2D的画框
const context = canvas.getContext("2d"); // 2.加载这张图片
const bg = new Image();
bg.src="img/1.jpg";
/*
image 加载的图片对象
dX为图片开始绘制的左上角横坐标
dY为图片开始绘制的左上角横坐标
dWidth为图片在canvas绘制的宽度
dHeight为图片在canvas绘制的宽度
*/
//context.drawImage(Image,dX,dY,dWidth,dHeight)
context.drawImage(bg,0,0,480,650) </script>
</body>
</html>

 

然后理所当然的失败了:

于是我们来看一下代码:

会发现:

const bg = new Image();
bg.src="img/1.jpg";

这两家伙是异步代码;

我们不清楚他什么时候执行完毕

如果在绘制之前图片还没有加载还没有完毕

 

那么

context.drawImage(Image,dX,dY,dWidth,dHeight)

就只能绘制出一张空白背景了

 

所以必须等图片加载完毕后,再进行图片的绘制

 

我们的解决方案是:给它加一个”load“

 

/*

稍微提一下箭头函数:

原函数:

hello = function() {
return "Hello World!";
}

箭头函数:

hello = () => "Hello World!";

(仅有单一返回值时可以省略return)

箭头函数好东西,ES6的新特性

 

简化函数的写法,视觉上看也更直观

 */

为其增加一个addEventListener

bg.addEventListener("load",()=>{
/*
image 加载的图片对象
dX为图片开始绘制的左上角横坐标
dY为图片开始绘制的左上角横坐标
dWidth为图片在canvas绘制的宽度
dHeight为图片在canvas绘制的宽度
*/ context.drawImage(bg,0,0,480,650)
})
//首参为事件名
//二参为一个回调函数,表示加载完毕后执行的代码

 

"load"事件表示等待对象加载完毕

 

那么异步的问题就解决了

 

 

来看看效果:

 

 

 (刁图一堆)

这个时候就有人问了:

博主你是SB吗?一个<img>能搞定的为这么弄的这么麻烦,

 

诶,别急,这么弄是为了接下来的动态效果实现做铺垫

 

2.动态效果(实现向下移动)

首先确定思路:

我要让背景动起来

可以更改他渲染起点的y轴坐标(y++)

并且让它重复渲染

 

思路有了,就好办了:

我们用变量来代替参数(方便加减操作)

let x = 0;
let y = 0;

(此处为全局变量,以后会改)

 

重复渲染我们用到setInterval方法:

 

/*

    setinterval()是定时调用的函数,可按照指定的周期(以毫秒计)来调用函数或计算表达式。

 */

我们把绘制方法(drawImage)塞到这个里面

setInterval(()=>{context.drawImage(bg,x,y++,480,650);
  },10);

(这里有个小问题,y轴是指向下的?y++反而是让图片向下移动,没弄懂,待解决)

来看看效果:

 

 

但是问题又来了,在跑完一次(一次绘制完毕)之后他就没东西渲染了,又变回空白了

 

所以我们在再弄一个context.drawImage并且让他从纵坐标-650开始

     let x1 = 0;
let y1 = 0;
let x2 = 0;
let y2 = -650;

方法部分:

bg.addEventListener("load",()=>{
/*
callback: Function 表示回调函数
timeout: Number 表示每次调用函数所间隔的时间段
*/
setInterval(()=>{context.drawImage(bg,x1,y1++,480,650);
},10);
setInterval(()=>{context.drawImage(bg,x2,y2++,480,650);
},10);
})

(犯了个错误,应该把两个context.drawImage塞到同一个setInterval中,这样写不便于变量的管理) 

还是那个问题,第二张图渲染完之后,再次遇到了空白的情况

所以,我们要想办法让他循环起来

思路如下:

尝试着让两张图循环渲染

流程如下:

第一张图开始渲染,

第一张图渲染结束,

第二张图开始渲染,

第二张图渲染结束,

第二张图渲染结束后,把第一张图的y坐标设为第二张图片渲染结束时尾部的坐标

再将第二张图片的y坐标重置到初始位置

问题就结解决了

代码如下:

我们用一个if语句去充值y坐标轴:

setInterval(()=>{
context.drawImage(bg,x1,y1++,480,650);
context.drawImage(bg,x2,y2++,480,650);
if(y2===0){
y1=0;
y2=-650;
} },10);

来看看效果:

 

搞定咯:

全部代码如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewprot" content="width-devic-width,initial-scale=1.0">
<title>飞机大战</title>
<style>
*{
padding: 0;
margin: 0;
}
canvas{
border: 1px solid red;
margin: auto;
}
#stage{
width: 480px;
height: 650px;
margin: auto;
}
</style>
</head>
<body>
<div id="stage">
<canvas id="canvas" width="480" height="650"></canvas>
</div>
<script>
// 1.让画笔能够绘制图片
// 1.1找到这个画布
const canvas = document.querySelector("#canvas");
// 1.2.利用这个画布初始换一个2D的画框
const context = canvas.getContext("2d");
/* canvas画布绘制bg对象时的坐标 */
let x1 = 0;
let y1 = 0;
let x2 = 0;
let y2 = -650;
// 2.加载这张图片
const bg = new Image();
bg.src="img/4.jpg";
/*
image 加载的图片对象
dX为图片开始绘制的左上角横坐标
dY为图片开始绘制的左上角横坐标
dWidth为图片在canvas绘制的宽度
dHeight为图片在canvas绘制的宽度
*/
/*
首参为事件名
二参为一个回调函数,表示加载完毕后执行的代码
*/
bg.addEventListener("load",()=>{
/*
callback: Function 表示回调函数
timeout: Number 表示每次调用函数所间隔的时间段
*/
setInterval(()=>{
context.drawImage(bg,x1,y1++,480,650);
context.drawImage(bg,x2,y2++,480,650);
if(y2===0){
y1=0;
y2=-650;
} },10);
})
</script>
</body>
</html>

3.canvas的坐标:

这玩意跟我们平时数学上用的平面直角坐标系(笛卡尔坐标系)不同;

 它Y轴是反着来的

That's all

 

Html飞机大战(一):绘制动态背景的更多相关文章

  1. android:怎样用一天时间,写出“飞机大战”这种游戏!(无框架-SurfaceView绘制)

    序言作为一个android开发人员,时常想开发一个小游戏娱乐一下大家,今天就说说,我是怎么样一天写出一个简单的"飞机大战"的. 体验地址:http://www.wandoujia. ...

  2. canvas绘制“飞机大战”小游戏,真香!

    canvas是ArkUI开发框架里的画布组件,常用于自定义绘制图形.因为其轻量.灵活.高效等优点,被广泛应用于UI界面开发中. 本期,我们将为大家介绍canvas组件的使用. 一.canvas介绍 1 ...

  3. 500行代码,教你用python写个微信飞机大战

    这几天在重温微信小游戏的飞机大战,玩着玩着就在思考人生了,这飞机大战怎么就可以做的那么好,操作简单,简单上手. 帮助蹲厕族.YP族.饭圈女孩在无聊之余可以有一样东西让他们振作起来!让他们的左手 / 右 ...

  4. Java实现飞机大战游戏

    飞机大战详细文档 文末有源代码,以及本游戏使用的所有素材,将plane2文件复制在src文件下可以直接运行. 实现效果: 结构设计 角色设计 飞行对象类 FlyObject 战机类 我的飞机 MyPl ...

  5. 【一】仿微信飞机大战cocos2d-x3.0rc1

    參考 [偶尔e网事] 的 [cocos2d-x入门实战]微信飞机大战  cocos2dx 2.0版本号,偶尔e网事他写的很具体,面面俱到,大家很有必要看下.能够通过以下链接跳转: cocos2d-x入 ...

  6. Python小游戏之 - 飞机大战美女 !

    用Python写的"飞机大战美女"小游戏 源代码如下: # coding=utf-8 import os import random import pygame # 用一个常量来存 ...

  7. 一、利用Python编写飞机大战游戏-面向对象设计思想

    相信大家看到过网上很多关于飞机大战的项目,但是对其中的模块方法,以及使用和游戏工作原理都不了解,看的也是一脸懵逼,根本看不下去.下面我做个详细讲解,在做此游戏需要用到pygame模块,所以这一章先进行 ...

  8. Canvas:飞机大战 -- 游戏制作

    Canvas:飞机大战 最开始我们要初始化信息,我们有五个状态:游戏封面,加载状态,运行状态,游戏暂停,游戏结束. 我们还需要  得分--score,生命--life. var START = 1;/ ...

  9. Python版飞机大战

    前面学了java用java写了飞机大战这次学完python基础后写了个python版的飞机大战,有兴趣的可以看下. 父类是飞行物类是所有对象的父类,setting里面是需要加载的图片,你可以换称自己的 ...

随机推荐

  1. 2.shell脚本99乘法表

    shell脚本99乘法表 [root@localhost data]# vim cf.sh

  2. 使用Vite2+TypeScript4+Vue3技术栈,如何入手开发项目

    前言 今天,我们使用Vite2.0+Vue3+TS来试玩一下,开发一个demo项目.实战 我们,打开Vite官方网站(https://cn.vitejs.dev/). Vite (法语意为 " ...

  3. 手写一个虚拟DOM库,彻底让你理解diff算法

    所谓虚拟DOM就是用js对象来描述真实DOM,它相对于原生DOM更加轻量,因为真正的DOM对象附带有非常多的属性,另外配合虚拟DOM的diff算法,能以最少的操作来更新DOM,除此之外,也能让Vue和 ...

  4. 动态树 — Link_Cut_Tree

    [模板]动态树(Link Cut Tree) Link-cut-tree是一种维护动态森林的数据结构,在需要动态加边/删边的时候就需要LCT来维护. Link-cut-tree的核心是轻重链划分,每条 ...

  5. 详解HashMap源码解析(上)

    jdk版本:1.8 数据结构: HashMap的底层主要基于数组+链表/红黑树实现,数组优点就是查询块,HashMap通过计算hash码获取到数组的下标来查询数据.同样也可以通过hash码得到数组下标 ...

  6. XML方式配置切面

    1. 概述  一个切面中需要包含什么,才能够作用到连接点?切面中是包含通知的,通知作用到连接点需要有切入点表达式. 除了使用AspectJ注解声明切面,Spring也支持在bean配置文件中声明切面. ...

  7. Qt+ECharts开发笔记(二):Qt窗口动态调整大小,使ECharts跟随Qt窗口大小变换而变换大小

    前言   上一篇将ECharts嵌入Qt中,在开始ECharts使用之前,还有一个很重要的功能,就是在窗口变换大小的时候,ECharts的图表尺寸也要跟随Qt窗口变换大小而变换大小.   Demo演示 ...

  8. vue封装原生的可预览裁剪上传图片插件H5,PC端都可以使用

    思路:1.先做出一个上传的图片的上传区 <!-- 上传区 --> <label for="fileUp"> <div class="upBo ...

  9. ESP8266 使用 DRV8833驱动板驱动N20电机

    RT 手里这块ESP8266是涂鸦的板子,咸鱼上三块一个买了一堆,看ESP8266-12F引脚都差不多的.裸焊了个最小系统,加两个按钮(一个烧录,一个复位) 1. 准备工作 搜索过程中发现 DRV88 ...

  10. IP地址和端口号

    IP地址 IP地址:指互联网协议地址(Internet Protocol Address),俗称IP.IP地址用来给一个网络中的计算机设备做唯一的编号.加入我们吧"个人电脑"比作一 ...