IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 100行内实现简易版的 Canvas 渲染器 -> 正文阅读

[JavaScript知识库]100行内实现简易版的 Canvas 渲染器

很多时候,我们可能只是为了简单实现几张图或者些简单场景。但是可能是对游戏引擎不熟悉也可能是觉得为了个小东西引个引擎很没必要。这个时候就特别需要一个灵活轻便的工具包可能来完成这件事,今天就特别写一个。

该渲染器使用起来非常简单,他帮助开发者完成两大机制

1、节点分层,开发者可以先操作 docu 元素一样操作节点

2、自动渲染,开发者不必关心,图像何时渲染,在哪里渲染

不过该渲染器并没有实现具体的渲染操作,而是直接把 canvas.getContext("2d") 对象开放给开发者,让其自由发挥。这个渲染器需要开发者对 canvas API 有一定了解

使用教程如下

/创建舞台    
let stage = new CanvasRender(document.body.querySelector("canvas"));

对,就这么一行代码就搞定了渲染器,他会自动渲染。剩下的就是在舞台中添加节点即可

渲染器中提供了一个基础类【Container?】,所有节点皆需继承这个类,才能被渲染器识别

如下

class Sprite extends Container {
    constructor(url, x, y, w, h) {
        super()
        this.load = false;
        this.img = new Image();
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.img.crossOrigin = "*";
        this.img.onload = () => this.load = true;
        this.img.src = url;
    }
    // 这和方法就是具体渲染什么到场景中的操作。具体有开发者自己写
    // 这个方法是自动调用的,不用管
    draw(gb) {
        if(this.load) gb.drawImage(this.img, this.x, this.y, this.w, this.h);
    }
}
// 创建一个背景
let bg = new Sprite("./350.jpg", 0, 0, 700, 350);
/// 添加背景节点到场景中
stage.appendChild(bg);

代码写到这里页面就可以出现一个背景了?

该基础类【Container?】还可以作为容器节点存在

// 创建一个背景
let bg = new Sprite("./350.jpg", 0, 0, 700, 350);
// 创建球
let qiu1 = new Sprite(atlas.getFrameUrl("asd/1.png"), 100, 100, 100, 100);
// 创建球
let qiu2 = new Sprite(atlas.getFrameUrl("asd/7.png"), 100, 200, 100, 100);
// 创建一个容器
let qius = new Container();
/// 添加背景节点到场景中
stage.appendChild(bg);
/// 添加球1节点到球组中
qius.appendChild(qiu1);
/// 添加球2节点到球组中
qius.appendChild(qiu2);
/// 添加一组球节点到场景中
stage.appendChild(qius);

这样场景就会变成这样

此外基础类中还提供一些节点的基础方法

// 把自己删掉
qiu1.remove();
// 隐藏或显示,如果节点下有子节点则连同子节点也会隐藏
qiu1.display = true;
// 调整层级,这个值越大显示的越靠前。默认按照 appendChild 的顺序显示,最后 appendChild 显示在最前面
qiu1.index = 99;

怎么样!?是不是很简单,下边就是全部的代码

/*
 * @Author: Summer
 * @LastEditors: Summer
 * @Description: 
 * @Date: 2022-04-21 16:11:02 +0800
 * @LastEditTime: 2022-04-28 15:29:14 +0800
 * @FilePath: \test\index2.js
 */

class EventClass extends Event {
    constructor(type, data) {
        super(type);
        this.data = data;
    }
}

// 渲染节点基类
class Container extends EventTarget {
    id = crypto.randomUUID();
    started = false;
    index = 1; // 层级,越大越靠前
    children = [];
    parent = null;
    display = true;
    x = 0;
    y = 0;
    w = 0;
    h = 0;

    on = this.addEventListener;
    once(type, callback) { this.addEventListener(type, callback, { once: true }) }
    emit(type, data) { this.dispatchEvent(new EventClass(type, data)) }

    appendChild(node) {
        node.parent = this;
        node.index = this.children.length + 1;
        this.children.push(node);
    }
    remove() {
        if (this.parent) for (let i = 0, l = this.parent.children.length; i < l; i++)
            if (this.parent.children[i] == this) {
                this.parent.children.splice(i, 1); break;
            }
    }
    start() {
        // 第一次加载时
    }
    /**
     * 渲染方法
     * @param {*} gb getContext("2d") 
     */
    draw(gb) {
        // 具体怎么渲染,自己决定
        // 这套工具只保证了渲染的层级
    }
}
/**
 * 舞台
 */
class CanvasRender extends Container {
    static STATUS = { Play: 1, Pause: 0 };
    statuc = CanvasRender.STATUS.Pause;
    constructor(canvas) {
        super()
        this.w = canvas.width;
        this.h = canvas.height;
        this.canvas = canvas
        this.gb = this.canvas.getContext("2d");
        this.play(); // 启动渲染
    }
    render() {
        if (this.statuc == CanvasRender.STATUS.Play) {
            this.gb.clearRect(0, 0, this.canvas.width, this.canvas.height)
            let stack = [this];
            while (stack.length) { // 利用深度优先搜索确保层级正确
                let node = stack.pop();
                if (!node.started) { node.canvas = this.canvas; node.start(); node.started = true; }
                if (node.display) {
                    node.children.sort((a, b) => b.index - a.index).forEach(ele => stack.push(ele));
                    node.draw(this.gb);
                }
            }
            requestAnimationFrame(this.render.bind(this));
        }
    }

    play() { this.statuc = CanvasRender.STATUS.Play; this.render(); return this; }
    pause() { this.statuc = CanvasRender.STATUS.Pause; return this; }
}


  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-30 08:37:40  更:2022-04-30 08:39:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:51:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码