这是我在上次做一个简陋的rpg小游戏的一些遗留问题,最近学了ES6的 Promise,并准备把项目用到的知识复习一遍(第一次写这种文章,如果文章有什么问题欢迎大家指出,或私信我)
canvas图片加载
canvas添加图片的方式:
/* drawImage()* /
因为素材的原因所以使用了drawImage方法
游戏的素材都来自rpgmaker,在steam上可以购买到正版!!
如果我们想取到图中的一个方格添加到canvas上就要使用drawImage方法
/***
cont是获取到的画笔,
img是你要添加的图片
0,192 前两个数字是你想在你所需要的的图片上开始截图的位置
48,48 也就是你要截多少截多大
0,0 是你把图片添加到canvas上的起点坐标从哪开始画
48,48 是在canvas要画多大多少(是你截取的图片在canvas缩放大小)
***/
使用方法是:cont.drawImage(img,0,192,48,48,0,0,48,48);
那么我们来试一下这个方法
//获取画布和画笔
let canv = document.getElementById("canvas");
let cont = canv.getContext('2d');
//建立一个图片对象
let floor1 = new Image();
floor1.src = 'img/Dungeon_A5.png';
cont.drawImage(floor1, 0, 192, 48, 48, 0, 0, 48, 48);
在写了这样的代码后图片并没有出来
在查找资料时我了解到:图片是一个资源请求,在js加载中,自然有一个图片加载的时间,极大可能在图片未加载时就调用了drawImage,所以图片无法显示,
解决方法:
1.使用定时器异步加载:
setTimeout(function(){
cont.drawImageimg, 0, 192, 48, 48, 0, 0, 48, 48);
},1000)
2.img.onload事件在图片加载过后在执行drawImage方法进行绘图
img.onload=function(){
cont.drawImage(img, 0, 192, 48, 48, 0, 0, 48, 48);
}
完整的代码:
//获取画布和画笔
let canv = document.getElementById("canvas");
let cont = canv.getContext('2d');
//建立一个图片对象作为开始游戏的背景
let floor1 = new Image();
floor1.src = 'img/Dungeon_A5.png';
floor1.onload=function(){
cont.drawImage(floor1, 0, 192, 48, 48, 0, 0, 48, 48);
}
如果说这是我们的进入游戏的主界面,我们想给这个图片添加个标题,那么
//获取画布和画笔
let canv = document.getElementById("canvas");
let cont = canv.getContext('2d');
//建立一个图片对象作为开始游戏的背景
let img = new Image();
img.src = 'img/Dragon.png';
img.onload=()=>{
cont.drawImage(img, 0, 0, 816, 624, 0, 0, 1000, 800);
}
//标题
cont.beginPath();
cont.font = '80px 楷体';
cont.fillStyle = "black";
cont.fillText('勇者斗恶龙', 330, 200);
cont.closePath();
这种方法出现了问题,文字并没有显示当我们在注释掉img.onload这段代码时发现图片正常显示了,那么这个问题,无论你是使用定时器加载图片还是.onload加载图片,他都是一个异步代码,而异步代码是在同步代码之后执行的,所以下面的文字其实是绘制了的,不过他被后面的图片所遮盖了
解决方法
方法很简单只要把文字绘制的代码放入img.onload里面就可以,在图片加载后在执行绘制图片和文字
//获取画布和画笔
let canv = document.getElementById("canvas");
let cont = canv.getContext('2d');
//建立一个图片对象作为开始游戏的背景
let img = new Image();
img.src = 'img/Dragon.png';
img.onload=()=>{
cont.clearRect(0, 0, 1000, 800);
cont.drawImage(img, 0, 0, 816, 624, 0, 0, 1000, 800);
//标题
cont.beginPath();
cont.font = '80px 楷体';
cont.fillStyle = "black";
cont.fillText('勇者斗恶龙', 330, 200);
cont.closePath();
}
let canv = document.getElementById("canvas");
let cont = canv.getContext('2d');
//建立一个图片对象作为开始游戏的背景
let floor1 = new Image();
floor1.src = 'img/Dungeon_A5.png';
floor1.οnlοad=function(){
cont.drawImage(floor1, 0, 192, 48, 48, 0, 0, 48, 48);
}
//标题
cont.beginPath();
cont.font = '80px 楷体';
cont.fillStyle = "black";
cont.fillText('勇者斗魔王', 330, 200);
cont.closePath();
结果:
所以可以证明上面的观点:绘制图片在绘制文字之后执行的所以要将绘制文字放在异步代码里。
drawImage的平铺问题
用上面的一块小图制作地板,上面我们截取的图片是一个小方块,我们玩得rpg游戏都是由这些小方块拼成的,那么我想用这一个小图片块铺满背景把他当我的地板让我的小人可以在上面行走,要怎么做呢?
这个方法是我在网上学到的:
建立一个小的canvas,用drawImage将图片添加到小的canvas上,然后使用createPattern方法把小的canvas平铺到大的canvas上面
createPatten方法
使用方法:
/***
canv:你要添加的图片或者元素
repeat:默认,向水平和垂直方向平铺
***/
context.createPattern(canv,“repeat”);
这个方法和drawImage:
draImage方法可以精确地获取这个图片的大小适用于这种图片素材的提取,但是drawImage却没办法进行平铺,createPatten可以进行平铺却不能适用于这种图片素材
//获取画布和画笔
let canv = document.getElementById("canvas");
let cont = canv.getContext('2d');
//建立第一个页面所需要的的图片对象
let floor1 = new Image();
floor1.src = 'img/Dungeon_A5.png';
floor1.onload=()=>{
//创建一个新的小画布
var canvs = document.createElement("canvas");
canvs.width = 48;
canvs.height = 48;
var conts = canvs.getContext('2d');
// 把图片添加到小画布上
conts.drawImage(floor1, 0, 192, 48, 48, 0, 0, 48, 48);
//把小画布平铺到大画布上
var bg = cont.createPattern(canvs, "repeat");
cont.fillStyle = bg;
cont.fillRect(0, 0, 1000, 800);
}