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知识库 -> 原生JS超级马里奥(第一天) -> 正文阅读

[JavaScript知识库]原生JS超级马里奥(第一天)

这段时间心血来潮,在网上找了一大堆前端关于游戏制作的博客,诸如飞机大战、魂斗罗等,但是个人思维限制,可能想的不是很多、很全面,最终放弃了个人独立开发的打算。皇天不负有心人,最终在youtube上找到了前端关于超级马里奥的视频,链接见Super Mario In Javascript

打算两周时间,每天花点时间看一到两集,并将所看视频整理出思路和代码供大家参考,当然也会讲解一些自己探寻出来的原理,并写明注释

github链接见:ainuo5213的超级马里奥,可以从该链接获取源码和素材,我争取做到每天更新直至结束,小伙伴们也可以自己再此基础上发挥或重构

第一张实现效果图如下:

目录结构

?目录文件讲解:

1-1.json:目前存储关卡的数据,比如背景渲染的一些东西

loader.js:导入配置相关比如图片资源、关卡数据资源等

main.js:入口文件

UnitStyleSheet.js:渲染背景的类文件

Canvas裁剪图片

在此之前我需要先讲解一下canvas裁剪图片的原理,canvas.drawImage,通常传递5个数据,分别是image/video/canvas、x、y、width、height,但是另外还可以传递4个参数,用于裁剪图片,详情见HTML5 canvas drawImage() 方法,举个例子:

const canvas = document.getElementById("screen");
const context = canvas.getContext("2d");

loadImageAsync("/src/assets/tiles.png")
    .then(image => {
        canvas.getContext("2d")
            .drawImage(
                image,
                0,
                0,
                16,
                16,
                0,
                0,
                16,
                16);
    });

上述方法描述为:从(0, 0)裁剪一个16x16的图像并放置到(0,0)且16x16的一个方块内,图像显示为

?原图:

?可以看到我们能够成功将第一个方块剪切出来。

导入配置相关:

// 异步导入图片
export function loadImageAsync(url) {
    return new Promise(resolve => {
        const img = new Image();
        img.onload = function () {
            resolve(img);
        }
        img.src = url;
    });
}

// 异步导入关卡数据
export function loadLevelAsync(name) {
    return fetch(`/src/levels/${name}.json`)
        .then(r => r.json());
}

单位图像样式对象

export default class UnitStyleSheet {

    /**
     * 创建一个图像样式定义对象
     * @param {HTMLImageElement} image 背景图像
     * @param {number} width 单位图像宽度
     * @param {number} height 单位图像高度
     */
    constructor(image, width, height) {
        this.image = image;
        this.width = width;
        this.height = height;
        this.tiles = new Map();
    }

    /**
     * 存储需要裁剪的图片
     * @param {string} name 画布名称
     * @param {number} x 需要裁剪的图片x与单位高度倍数
     * @param {number} y 需要裁剪的图片y与单位高度倍数
     */
    define(name, x, y) {
        const canvas = document.createElement("canvas");
        canvas.width = this.width;
        canvas.height = this.height;

        // 裁剪图片,并存储
        canvas.getContext("2d")
            .drawImage(
                this.image,
                x * this.width,
                y * this.height,
                this.width,
                this.height,
                0,
                0,
                this.width,
                this.height);
        this.tiles.set(name, canvas);
    }

    /**
     * 画图像
     * @param {string} name 画布名称
     * @param {any} context 上下文对象
     * @param {number} x 需要画图像的x坐标
     * @param {number} y 需要画图像的y坐标
     */
    draw(name, context, x, y) {
        const canvas = this.tiles.get(name);
        context.drawImage(canvas, x, y, this.width, this.height); // drawImage第一个参数接收类型:图像、视频、画布
    }

    /**
     * 画单元格
     * @param {string} name 画布名称
     * @param {any} context 上下文对象
     * @param {number} x 需要画图像的x坐标(倍数)
     * @param {number} y 需要画图像的y坐标(倍数)
     */
    drawTile(name, context, x, y) {
        this.draw(name, context, x * this.width, y * this.height)
    }
}

入口函数:

import UnitStyleSheet from "./UnitStyleSheet.js";
import { loadImageAsync, loadLevelAsync } from "./loader.js";

// 用于绘制背景,双重循环的x和y依赖于关卡配置文件
function drawBackground(background, context, unitStyleSheet) {
    background.ranges.forEach(([x1, x2, y1, y2]) => {
        for (let x = x1; x < x2; x++) {
            for (let y = y1; y < y2; y++) {
                unitStyleSheet.drawTile(background.tile, context, x, y);
            }
        }
    })
}

const canvas = document.getElementById("screen");
const context = canvas.getContext("2d");

loadImageAsync("/src/assets/tiles.png")
    .then(image => {
        // 创建单位图像样式对象,设置单位长度,并定义裁剪起始位置来裁剪图像
        const unitStyleSheet = new UnitStyleSheet(image, 16, 16);
        unitStyleSheet.define("ground", 0, 0);
        unitStyleSheet.define("sky", 3, 23);
        loadLevelAsync('1-1')
            .then(level => {
                level.backgrounds.forEach(background => {
                    drawBackground(background, context, unitStyleSheet);
                })
            });
    });

当然油管UP主写的代码很好,思路很清晰,我自己第一次看到也觉得需要好好的理解一番,当然各位小伙伴可以去看看视频,雀食不错。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-29 16:13:51  更:2021-11-29 16:15:58 
 
开发: 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年5日历 -2024/5/20 20:39:51-

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