还可以这么优雅的预加载资源?

1,192 阅读2分钟

phaser项目必须将媒体资源进行预加载

  • @description 资源配置信息
  • 所有资源采取key value对应
  • 优势: 不用将所有静态资源放在本地
  • 虽然打包完成的资源也在cdn,但构建时bundle的依赖会过多,因此拆分出来
  • 后期可以逐步分离上传至cdn
  • 本地的调用本地,cdn现存的直接引用

1.创建图片配置对象

  • 本地资源

    仅仅写入.png前的内容,后面通过require()查找静态资源

    const localImages: string[] = [
    	'img1',
    	'img2',
    	'img...'
    ]
    
  • CDN资源

    url则为资源对应调用的key,

    // 存放在CDN的资源
    const cdnImages = {
        "bg-bottom": 'https://xx.png'
    }
    
  • 加载策略

    1.创建存放图片配置的键值对对象;

    2.先拿着Images字典通过require加载服务下的资源,追加到对象中;

    3.后将cdn资源配置拼入图片配置对象;

    4.导出图片配置对象。

    // 创建图片配置对象
    let imagesConfig = {};
    
    // require()获取资源
    function url(fileName: string) {
        return require(`./images/base/${fileName}.png`)
    }
    
    // 查询本地资源字典
    localImages.forEach(item =>{
    	imagesConfig[item] = url(`${item}`)
    })
    
    // 合并cdn资源
    imagesConfig = Object.assign(imagesConfig, cdnImages)
    
    // 导出图片配置对象
    export default imagesConfig;
    
  • 完整代码

// images_config.ts

const localImages: Array<string> = [
	'img1',
	'img2',
	'img...'
];

const cdnImages = {
    "bg-bottom": 'https://xx.xx.png'
}

// 创建图片配置对象
let imagesConfig = {};

// require()获取资源
function url(fileName: string) {
    return require(`./images/${fileName}.png`)
}

// 查询本地资源字典
localImages.forEach(item =>{
	imagesConfig[item] = url(item)
})

// 合并cdn资源
imagesConfig = Object.assign(imagesConfig, cdnImages)

// 导出图片配置对象
export default imagesConfig;

2.构建资源加载器

// assets_loader.ts

class AssetsLoader {

	// 在base场景创建实例,需要传入Scene
	constructor(private scene: Phaser.Scene){
		this.scene.load.crossOrigin = 'anonymous';
	}

	// load资源
	public load(imagesConfig = {} ){
		
		const assetsHash = {
      image: imagesConfig
    }

		Object.keys(assetsHash).forEach(assetsType => {
      const assets = assetsHash[assetsType]
      Object.keys(assets).forEach(key => {
          this.scene.load[assetsType](key, assets[key])
      });
    });
	
	 // 加载完成开始绘制进度条
   this.scene.load.start()
	}
}

在基类中实例化加载器

最优的方案是在BaseScene的create()阶段调用,并挂在在该节点上,供所有继承于该父类的所有子类都可以访问。

// base_scene.ts

// 引入加载器
import AssetsLoader from 'assets_loader.ts'
// 引入图片配置文件
import imagesConfig from 'images_config.ts'

export default class BaseScene extends Phaser.Scene {

    assetsLoader: AssetsLoader

    constructor(sceneName: string) {
        super({ key: sceneName })
    }

    /**
    * @function 子类会自动执行此create声明周期, private 禁止子类覆写
    */
    private create() {
        this.assetsLoader = new AssetsLoader(this) // 传入当前scene
        this.build()
    }

    build() {
        // 执行加载操作
        this.assetsLoader.load(imagesConfig)
    }
}

3.完善静态资源配置信息和加载器

然而真实的phaser项目需要的不仅仅是image,还会出现audio、video、sprite等资源,所以下一步需要针对其他类型的媒体资源进行处理,思路和处理image相似。

处理audio资源:

// audios_config.ts

const localAudios: Array<string> = ['audio1','audio...']
const cdnAudios = {'cdn-audio': 'https://xx.xx.mp3'}
let audiosConfig = {}

function url(fileName) {
    return require(`./sounds/${fileName}.mp3`)
}

localAudios.forEach(item => {
    audiosConfig[item] = url(item)
})

audiosConfig = Object.assign(audiosConfig, cdnAudios)

export default audiosConfig

处理video资源:

// videos_config.ts

const localVideos: string[] = ['video1', 'video...']
const cdnVideos = {'cdn-video': 'https://xx.xx.mp4'}
let videosConfig = {}

function url(fileName: string) {
    return require(`./video/${fileName}.mp4`)
}

localVideos.forEach(item => {
    videosConfig[item] = url(item)
})

videosConfig = Object.assign(videosConfig, cdnVideos)

export default videosConfig

处理sprites资源:

// sprites_config.ts

function url(fileName) {
    return `./sprites/+ ${fileName}`
}

// 基础sprite
const spritesConfig = {
    'localSoundAnimas': url('sound_sprite.json'), // 本地
    'cdnSoundAnimas': 'https://xx.xx.json' // cdn
}

export default spritesConfig

通过上述步骤已将所有的资源包装成对象导出,这时该升级加载器对数据进行加载。

重写load()方法

// 加载
    public load(imagesConfig = {}, audiosConfig = {}, videosConfig = {}, spritesConfig = {}) {

        const assetsHash = {
            image: imagesConfig,
            audio: audiosConfig,
						 video: videosConfig,
            multiatlas: spritesConfig,
        }
        Object.keys(assetsHash).forEach(assetsType => {
            const assets = assetsHash[assetsType]
            Object.keys(assets).forEach(key => {
                if (assetsType == 'video') {
                    this.scene.load[assetsType](key, assets[key], 'canplay', true)
                } else {
                    this.scene.load[assetsType](key, assets[key])
                }
            })
        })
        // 加载完成开始绘制进度条
        this.scene.load.start()
    }

重写BaseScene中build()的调用,将其他三种类型的媒体资源传入

import imagesConfig from 'images_config.ts'
import audiosConfig from 'audios_config.ts'
import videosConfig from 'videos_config.ts'
import spritesConfig from 'sprites_config.ts'

build() {
   // 执行加载操作
   this.assetsLoader.load(imagesConfig, audiosConfig, videosConfig, spritesConfig);
}

最后一步检查资源是否加载成功

这样就可以快乐的在业务场景中调用预加载好的资源了。