【Canvas】多多暴打程序员 | 七日打卡

语言: CN / TW / HK

如果您发现错误,请一定要告诉我,拯救一个辣鸡(但很帅)的少年就靠您了!\color{tomato}{如果您发现错误,请一定要告诉我,拯救一个辣鸡(但很帅)的少年就靠您了!}

背景

从前有个小女孩,叫多多,她特别讨厌程序员,于是,她决定用钱把程序员引诱过来,然后暴打一顿。。。

好吧,就是用 Canvas 做一个经典的接金子游戏,实现比较简单。

效果展示:

Canvas 基础

不了解 canvas 建议学习慕课网课程《炫丽的倒计时效果Canvas绘图与动画基础》和《Canvas绘图详解》 老师讲的很棒。

绘制图形

1、画多多

多多是个小女孩,但是小女孩比较难画,我决定用一颗心来代替。简单画个图,图中黑色的轮廓就会我要画的心形,指定左上角的坐标为 (x, y),宽度为 w*4 高度为 w*3,而 w 是指定的一个参数。

这样就可以绘制出一个心形:

let x = 0,y = 0, w = 30;
let path = [[w, 0], [2 * w, w], [3 * w, 0], [4 * w, w], [2 * w, 3 * w]];
ctx.beginPath();
ctx.moveTo(x, y + w);
for (let i = 0; i < path.length; i++) {
    ctx.lineTo(x + path[i][0], y + path[i][1]);
}
ctx.closePath();
ctx.fillStyle = 'red';
ctx.fill();
复制代码

效果如图:

2、画钱

钱的话,就简单的用矩形加文字绘制即可。

先在 (x, y) 绘制一个宽度为 w 高度为 h 的矩形。填充颜色用了渐变色。

let grd = ctx.createLinearGradient(0, 0, 0, h);
grd.addColorStop(0, '#f4cbd3');
grd.addColorStop(1, '#eb627f'); 
ctx.fillStyle = grd;
ctx.fillRect(x, y, w, h);
复制代码

然后绘制文字,设置中心对齐,然后在矩形中间开始绘制,保证了文字在矩形中间。

ctx.font = '15px Arial bold';
ctx.fillStyle = '#ffc24f';
ctx.textAlign= 'center';
ctx.textBaseline = 'middle';
ctx.fillText('¥100', x + w / 2, y + h / 2);
复制代码

效果如图:

3、画刀片

就是简单两个小矩形的拼接,左上角坐标为 (x, y) ,总宽度为 w 高度为 h 的矩形。

绘制代码

ctx.fillStyle = '#561d00';
ctx.fillRect(x, y, w / 3, h / 2);

ctx.fillStyle = 'silver';
ctx.fillRect(x + w / 3, y, w * 2 / 3, h);
复制代码

4、画程序员

直接用的图片。(emmm,有点丑,没找到好看的 QAQ)

在页面添加图片,并设置不显示。

<img src="./cxy.jpg" alt="" id="progImg" style="display: none">
复制代码

然后在 canvas 中绘制图片

let progImg = document.getElementById('progImg');
ctx.drawImage(progImg, x, y, w, h);
复制代码

鼠标事件的监听

对于程序员这个组件,希望能够监听鼠标事件,能够跟随鼠标移动。首先监听按下鼠标事件,此时拖动开始,监听鼠标移动事件,把程序员的坐标挪到鼠标的坐标。当鼠标抬起时,取消拖动。

canvas.onmousedown = (evt) => {
    drag = true;
}
canvas.onmousemove = (evt) => {
    let { offsetX, offsetY } = evt;
    if (drag) {
        // ... 设置程序员的位置 为鼠标的位置
    }
}
document.onmouseup = () => drag = false;
复制代码

相交判断

当程序员和钱相交的时候,钱消失,当程序员和刀子相交的时候,刀子消失,所以重点是判断相交。

可以发现上面的每一个图形,我都做成了矩形,可以简化这里的相交判断。如果两个矩形的横向或纵向不重叠,证明不相交。假设第一个矩形的左上角和右下角坐标为 (x1,y1)(x2,y2),第二个矩形的左上角和右下角坐标为 (x3,y3)(x4,y4),判断不重叠的条件即为:

let notOverlap = x2 < x3 || x1 > x4 || y2 < y3 || y1 > y4;
复制代码

动画

要物体移动,可以使用 setInterval 每隔一段时间,就是清空页面然后重新绘制。举例:

let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let width = canvas.width;
let height = canvas.height;
let x = 0, y = 0, w = 20;
function render() {
    context.clearRect(0, 0, width, height);
    context.fillRect(x, y, w, w);
    x++;
    y++;
}
setInterval(render, 20);
复制代码

不过还可以用 window.requestAnimationFrame() 进行优化,requestAnimationFrame 有点类似 setTimeout,不过该方法不需要设置时间间隔,而是在下一次重绘之前调用传入给该方法的动画函数。具体可以自行查阅资料。(因为其实我也不会

let render = () => {
    context.clearRect(0, 0, width, height);
    context.fillRect(x, y, w, w);
    x++;
    y++;
    requestAnimationFrame(render);
};
requestAnimationFrame(render);
复制代码

以上,加起来就可以写个小游戏了。完整代码可见:https://github.com/G-lory/front-end-practice/tree/master/canvas/duoduo_beat_programmer