使用 typescript 和 canvas 重构snow效果

前言:之前做过一个 snow 效果,但是是直接用 HTML 做的 点击此处查看 ,几个星期前,我用 typescript 和 canvas 重构了一下,
snow效果是一个很简单的效果,但是用来练手还是不错的;

  • 首先创建基本变量:
let canvas = <HTMLCanvasElement>document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let H = canvas.height = window.innerHeight;
let W = canvas.width = window.innerWidth;
ctx.fillStyle = "#53B7F6";

在获取 canvas 的 dom 时可能后报错,所以要用断言或者 let canvas:any 这样来写,不然会报错;
这里让 canvas 的长,宽分别等于浏览器视窗的长宽,颜色为蓝色,如果想做背景,可以去掉;

  • 获取图片文件:
const renderImg = (x: number = 10, y: number = 10): void => {
    ctx.drawImage(snowImg, x, y, 42, 30);
};

let readStatus: boolean = false;

let snowImg: any = new Image();
snowImg.onload = (): void => {
    readStatus = true;
};

snowImg.src = 'snow.jpg';

要记得读取图片的函数是异步执行的,所以添加一个状态,来判断图片是否已加载,而 renderImg 函数呢,就是在 canvas 上绘制图片,
他有初始值x=10,y=10,后面的42,30 是图片的大小,这个如果你换一个图片的话需要好好调节这2个数值;

  • 创建例子存储数组:
const snowNum: number = 8;

interface snowType {
    x: number,
    y: number,
    stepX: number,
    stepY: number
}


let store: snowType[] = [];

const add = (): void => {
    let num: number = snowNum * Math.random() | 0;
    while (num--) {
        store.push({
            x: Math.random() * W | 0,
            y: 0,
            stepX: (Math.random() * 5 - 2) | 0,
            stepY: ((Math.random() * 8) | 0) + 2
        })
    }
};

snowNum 的作用是每秒最多出现8片 snow,store 中存储了 snow 的坐标位置,和每秒的移动速度;

  • 渲染函数:
const render = (): void => {
    if (!readStatus) return;
    clearBg();
    let length: number = store.length;
    while (length--) {
        let {x, y, stepX, stepY}:snowType = store[length];
        renderImg(x, y);
        store[length].x += stepX;
        store[length].y += stepY;
        if (check(store[length])) {
            store.splice(length, 1);
        }
    }
};

通过坐标来渲染图片并添加移动,做出判断,当 snow 移动到浏览器底部时删除他;

  • 时间计时:
let addTime: number = 0;
let lastTime: number = 0;

const animotion = (timestamp: number = 0): void => {
    if (timestamp - lastTime > 50) {
        render();
        lastTime = timestamp;
    }
    if (timestamp - addTime > 1000) {
        add();
        addTime = timestamp;
    }
    try {
        window.requestAnimationFrame(animotion);
    } catch {
        alert('你的浏览器不支持rAF,请更新或更换浏览器')
    }
};
animotion();

之前的计时我都是拿 setInterval 来做计时器的,但是会有一个缺点,不知道大家有没碰到过,就是在 chrome 里
切换到其他页面是,数组仍在添加,但是已经停止了渲染,所以再切回来的时候,会出现一大堆的东西,而这个用 rAF 是没有的,
但是他需要较高的兼容(IE>10),不过网上已经有了用 setInterval 做兼容方法,百度一下就有了,我这里就不讲了;

最后:
demo: 点击此处查看
GitHub:https://github.com/Grewer/JsDemo/tree/master/snow

如果该文章帮到了你,还请推荐或 star;
完;

posted @ 2018-01-14 16:39  Grewer  阅读(2052)  评论(0编辑  收藏  举报