🔥🔥春节聚餐谁买单?我用canvas写了一个抽签小助手🎊(可在线预览)

2,348 阅读4分钟

PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛

🌲🌲🌲 前言

    春节马上就要到了,又可以和许久未见的朋友们🫂一块happy🍺了。用石头剪刀布来决定这次谁买单的方式配不上我这个从大城市回来的高端切图仔,因为不够fashion👞。所以我用canvas写了一个抽签小助手,让程序来告诉我们到底谁是春节的幸运小子🎉。

🍀🍀🍀 效果展示

抽奖动图

线上预览地址: 买单小助手

Tipes: 用qq导出的gif太大了,然后压缩了一下就成这样子了,可以去在线预览地址看(使用pc浏览哦,移动端适配没搞)。

💻💻💻 代码实现

    总体来说这个小助手的实现还是很简单的,只要掌握了基础的canvas绘图然后再加上js写的一些简单的逻辑计算就能实现了。所以下面就挑几个日常工作中比较有用的说一下:

🪄绑定点击事件:

    canvas绑定点击事件只能绑定到canvas整个上面,所以当我们需要知道具体的图形是否被点击的时候,需要获取点击的坐标,再和图形的边界进行距离判断:

const clickCanvasFun = (e: MouseEvent) => {
    winning.value = 0;
    if (isClick.value) {
        isClick.value = false;
        let length = coordAll.value.length;
        for (let i = 0; i < length; i++) {
            let isMe = isMeFun(coordAll.value[i].coordTop, e);
            if (isMe) {
                // 该圆形被点击了
            } 
        }
    }
};

✍️动态绘制:

    在绘制动画线的时候,选择使用了requestAnimationFrame方法,这个方法类似于我们常用的setTimeout/setInterval,但是requestAnimationFrame不用我们手动设置时间间隔。那么requestAnimationFrame方法相比较于我们常用的setTimeout/setInterval有什么优点呢?

  • requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。
  • 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量。
  • requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销。

解释一下
    相信大家都知道60hz,由于主流的屏幕刷新率都在 60Hz,那么渲染一帧的时间就必须控制在 16ms 才能保证不掉帧。 也就是说每一次渲染都要在 16ms 内页面才够流畅不会有卡顿感,也是浏览器能实现最平滑动画的极限。
    setTimeout和setInterval的问题是,它们都不精确。作为第二个参数的延时只能保证何时把代码添加到浏览器的任务队列中,不能保证添加到任务队列就立即执行。 而且浏览器会对切入后台或者是不活跃标签中的计时器进行限流。
  requestAnimationFrame浏览器来决定回调函数的执行时机,保持最佳绘制效率,从而节省系统资源,提高系统性能,改善视觉效果。

简单使用

let canvas = document.getElementById('aa');
let context = canvas.getContext("2d");
let x = 0, y = 0;
let timer = null;
const startFun = () => {
        cancelAnimationFrame(timer); // 清除
        if (x > 200 || y > 200) {
                return
        }
        draw();
        x = x + 1;
        y = y + 1;
        timer = requestAnimationFrame(startFun);
}
const draw = () => {
        context.strokeStyle = "pink"; // 线的颜色
        context.lineWidth = 4; // 线的宽度
        context.beginPath(); // 开始绘制
        context.moveTo(x, y); // 绘制起点
        context.lineTo(x + 1, y + 1); // 绘制终点
        context.stroke(); // 描边
        context.closePath(); // 结束绘制
}
startFun();

效果展示:

requestAnimationFrame

⚡️转折点计算:

    然后就是转折点和方向的计算,在每一个号码对应的线上可以设定有几个转折点,增加游戏的趣味性。

const randerAllFun = (x: number, yt: number, yb: number, numb: number) => {
    let i = numb;
    let arr: number[] = [];
    while (i > 0) {
            let num = randerNumFun(yb - 20, yt + 20);
            if (arr.indexOf(num) == -1) {
                    // 随机数边界处理
                    arr.push(num);
                    i--;
            }
    }
    let newArr = arr.sort();
    let coordArr: CoordArrType[] = [];
    newArr.forEach((item) => {
            let obj = {
                    oneX: 0,
                    oneY: 0,
            };
            obj.oneX = x;
            obj.oneY = item;
            coordArr.push(obj);
    });
    return coordArr;
};

     同时因为转折的时候有不同的方向,还需要对转折方向进行随机处理。然后对于起始的线因为不能向左或者向右,也要做对应的边界处理以及对于速度的控制,判断线是否到达了指定的转折点。啰哩啰嗦的就偏离这篇文章的本意😅,具体的代码就不在这里面展示了,文章最后面会有代码库的地址,如果感兴趣的大佬可以去看看哦。

💐💐💐 结语

    整个小游戏的代码已经放到了gitee上面,做得比较粗糙,不过主要的功能已经实现,随机性很充足。主要用到的了canvas的基础绘图,已经使用js写一些简单的逻辑计算,最后预祝各位大佬春节快乐,在新的一年里学习进步,事业有成!🎆🎆🎆
代码地址 欢迎吐槽哦📩

心灵鸡汤:
总有一天你将破蛹而出,成长得比人们期待的还要美丽。

但这个过程会很痛,会很辛苦,有时候还会觉得灰心。

面对着汹涌而来的现实,觉得自己渺小无力。

但这,也是生命的一部分。做好现在你能做的,然后,一切都会好的。

我们都将孤独地长大,不要害怕。