前言
最近做了一个 H5 小游戏,游戏的玩法是小汽车抢停车位,需要手指拖拽小汽车躲避障碍快速进入停车位。
最终效果
在线预览
扫码跳过视频体验小游戏
制作思路
游戏复杂的部分可能就是小红车和障碍物的碰撞检测,因为地图不是固定的,会有不同的游戏地图。刚开始想把障碍物切成一块一块的,然后给几种排列方式,但需要测量很多数据,觉得还是有些复杂。
之前 小建老师 和我提到过很多次用 getImageData()
实现的神奇功能,之后我用 getImageData()
实现了点击涂色,觉得这个方法确实神奇且好用,所以这次碰撞检测也用 getImageData()
实现了一下。
getImageData()
getImageData()
是 canvas
的一个方法,可以读取到图片指定矩形的数据,数据指的是 rgba
数据。
思路重点
有了 getImageData()
这个方法的助攻,就可以在 PS 中新建一个透明图层,给小车行驶的路上涂上一个特定的颜色,然后小车每次移动,读取小车位置所在像素的颜色,就知道小车在不在道路上了。
开始实现
开始抠图
在 PS 中新建一个透明图层,把小车可以行驶的路上,涂上白色,给停车位涂上红色,然后保存为 png 图片。下图左侧为游戏地图,右测为对应的涂色图片,两张图片尺寸保存相同:
关键代码
碰撞检测关键:
function areaJudge(x,y){ // 传入小车的位置
return ((resolve)=>{
const canvas = document.createElement('canvas'); // 创建一个canvas,将我们涂好色的透明图片画到canvas
const ctx = canvas.getContext('2d');
canvas.width = WIDTH; // WIDTH 为图片的宽度
canvas.height = HEIGHT; // HEIGHT 为图片的高度
const path = new Image();
path.onload = ()=>{
ctx.drawImage(path,0,0);
// 参数说明:getImageData(小车x坐标,小车y坐标,获取1像素宽度的数据,获取1像素高度的数据)
// data:[r,g,b,a] 图像数据为 rgba
if(ctx.getImageData(x,y,1,1).data[3]===0){ // 获取当前像素的透明度,为 0 说明处于障碍区域
resolve(0);
}else if(ctx.getImageData(x,y,1,1).data[0]===255){// 获取当前像素的透明度,为 255 说明处于可以行驶的区域
resolve(1);
}else{ // 红色,停车位的位置
resolve(2);
}
};
path.src = psImgSrc; // psImgSrc 为我们在 ps 涂色的透明图片
});
}
复制代码
然后在小车移动的过程中,通过碰撞检测判断小车处于可行驶区域、故障区域还是停车位:
// 此处使用了 pixi.js 的 pointermove ,同理可以使用 touchmove
car.on('pointermove',(e)=>{
// 此处 car.x 为小车中心的位置,省略了计算代码
this.areaJudge(car.x,car.y).then((resolve)=>{
if(resolve===1){
// 可行驶区域
}else if(resolve===0){
// 不可行驶区域
}else{
// 车位
}
});
});
复制代码
以上,就使用 getImageData()
实现了碰撞检测。
总结
- 使用
getImageData()
可以读取图片的颜色与透明度数据,这样节省了我们页面障碍物的布局,可以少测量很多数据; - 给透明图片涂上不同的颜色来区分障碍物、可行驶路段与停车位,可以通过颜色来处理不同的逻辑;
- 本文的代码为删减的关键代码,没有考虑小车的宽高,可以在小车位置加上宽高信息,这样碰撞检测更加准确;
getImageData()
的功能很强大,可以考虑扩展到其它应用场景。
更多文章
- 查看 网易创意部 其他小伙伴的文章:github.com/f2e-netease…
- 查看我的更多文章:github.com/NalvyBoo/bl…