Html飞机大战(一):绘制动态背景
好家伙,飞机大战终于开始弄了
这会有很多很多复杂的东西,但是我们总要从最简单,和最基础的部分开始,
我们先从背景开始弄吧!
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