Laya.Utils 工具类使用说明

简介

Laya.Utils 是 LayaAir 引擎提供的静态工具类,包含各种实用的辅助方法,涵盖文件路径处理、颜色转换、角度/弧度转换、数组操作、异步任务管理等功能。


目录


路径处理

getFileExtension

获取文件扩展名,自动转换为小写字母。

static getFileExtension(path: string): string

参数:

  • path: 文件路径字符串

返回值: 文件扩展名(不含点号)

示例:

// 基本用法
let ext1 = Laya.Utils.getFileExtension("image.png");        // "png"
let ext2 = Laya.Utils.getFileExtension("photo.JPG");        // "jpg"
let ext3 = Laya.Utils.getFileExtension("archive.tar.gz");   // "gz"
let ext4 = Laya.Utils.getFileExtension("no_extension");     // ""
let ext5 = Laya.Utils.getFileExtension("path/to/file.png"); // "png"

// 实际应用:根据扩展名判断文件类型
function isImageFile(path: string): boolean {
    let ext = Laya.Utils.getFileExtension(path);
    return ["png", "jpg", "jpeg", "gif", "webp"].indexOf(ext) >= 0;
}

console.log(isImageFile("avatar.png")); // true
console.log(isImageFile("document.pdf")); // false

getBaseName

获取路径中的文件名,可选择是否包含扩展名。

static getBaseName(path: string, withoutExtension?: boolean): string

参数:

  • path: 文件路径字符串
  • withoutExtension: 是否去除扩展名,默认 false

返回值: 文件名

示例:

// 获取完整文件名(含扩展名)
let name1 = Laya.Utils.getBaseName("path/to/image.png");      // "image.png"
let name2 = Laya.Utils.getBaseName("/assets/sprite.ts");      // "sprite.ts"
let name3 = Laya.Utils.getBaseName("C:\\game\\data.json");    // "data.json"

// 获取不含扩展名的文件名
let name4 = Laya.Utils.getBaseName("path/to/image.png", true);  // "image"
let name5 = Laya.Utils.getBaseName("hero.sprite.json", true);   // "hero.sprite"
let name6 = Laya.Utils.getBaseName("archive.tar.gz", true);     // "archive.tar"

// 实际应用:构建资源路径
function getTexturePath(textureName: string): string {
    let baseName = Laya.Utils.getBaseName(textureName, true);
    return `resources/textures/${baseName}.png`;
}

console.log(getTexturePath("hero.jpg")); // "resources/textures/hero.png"

replaceFileExtension

更改文件的扩展名。

static replaceFileExtension(path: string, newExt: string, excludeDot?: boolean): string

参数:

  • path: 原文件路径
  • newExt: 新扩展名
  • excludeDot: 是否排除点号,默认 false

返回值: 替换扩展名后的新路径

示例:

// 基本用法
let path1 = Laya.Utils.replaceFileExtension("image.png", "jpg");     // "image.jpg"
let path2 = Laya.Utils.replaceFileExtension("data.json", "txt");     // "data.txt"
let path3 = Laya.Utils.replaceFileExtension("photo.JPG", "webp");    // "photo.webp"

// 使用 excludeDot 参数
let path4 = Laya.Utils.replaceFileExtension("file.txt", "json", true); // "filejson"
let path5 = Laya.Utils.replaceFileExtension("file.txt", "json", false); // "file.json"

// 实际应用:生成缩略图路径
function getThumbnailPath(originalPath: string): string {
    return Laya.Utils.replaceFileExtension(originalPath, "thumb.png");
}

console.log(getThumbnailPath("uploads/photo.jpg")); // "uploads/photo.thumb.png"

角度/弧度转换

toRadian

将角度转换为弧度。

static toRadian(angle: number): number

参数:

  • angle: 角度值

返回值: 弧度值

示例:

// 基本用法
let rad1 = Laya.Utils.toRadian(0);    // 0
let rad2 = Laya.Utils.toRadian(90);   // Math.PI / 2 ≈ 1.5708
let rad3 = Laya.Utils.toRadian(180);  // Math.PI ≈ 3.1416
let rad4 = Laya.Utils.toRadian(360);  // Math.PI * 2 ≈ 6.2832

// 实际应用:使用 Math 三角函数计算
function shootBullet(angle: number, speed: number): { x: number; y: number } {
    let rad = Laya.Utils.toRadian(angle);
    return {
        x: Math.cos(rad) * speed,
        y: Math.sin(rad) * speed
    };
}

let velocity = shootBullet(45, 100);
// velocity.x ≈ 70.71, velocity.y ≈ 70.71

// 注意:Laya.Sprite.rotation 属性直接使用角度,不需要转换
// 只有使用 Math.sin/cos/tan 等三角函数时才需要 toRadian

toAngle

将弧度转换为角度。

static toAngle(radian: number): number

参数:

  • radian: 弧度值

返回值: 角度值

示例:

// 基本用法
let deg1 = Laya.Utils.toAngle(0);            // 0
let deg2 = Laya.Utils.toAngle(Math.PI / 2);  // 90
let deg3 = Laya.Utils.toAngle(Math.PI);      // 180
let deg4 = Laya.Utils.toAngle(Math.PI * 2);  // 360

// 实际应用:显示对象旋转角度
function displayRotation(sprite: Laya.Sprite): string {
    let degrees = Laya.Utils.toAngle(sprite.rotation);
    return `旋转角度: ${degrees.toFixed(1)}°`;
}

// 计算两点之间的角度
function getAngleBetweenPoints(x1: number, y1: number, x2: number, y2: number): number {
    let dx = x2 - x1;
    let dy = y2 - y1;
    return Laya.Utils.toAngle(Math.atan2(dy, dx));
}

let angle = getAngleBetweenPoints(0, 0, 1, 1); // 约 45 度

数组操作

copyArray

清空源数组,然后将另一个数组的值复制进去。

static copyArray(source: any[], array: any[]): any[]

参数:

  • source: 被清空并填充的源数组
  • array: 要复制的数组

返回值: 复制后的 source 数组

示例:

// 基本用法
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];

Laya.Utils.copyArray(arr1, arr2);
console.log(arr1); // [4, 5, 6]
console.log(arr2); // [4, 5, 6] (原数组不变)

// 实际应用:更新对象池
class GameObjectPool {
    private activeObjects: any[] = [];
    private inactiveObjects: any[] = [];

    updateActive(newObjects: any[]): void {
        Laya.Utils.copyArray(this.activeObjects, newObjects);
    }
}

// 实际应用:刷新列表数据
class ItemList {
    private items: any[] = [];

    refreshData(newItems: any[]): void {
        Laya.Utils.copyArray(this.items, newItems);
        this.updateView();
    }

    private updateView(): void {
        // 更新列表显示...
    }
}

数值解析

parseInt

安全地解析字符串为整数,空值或非数字返回 0(而非 NaN)。

static parseInt(str: string, radix?: number): number

参数:

  • str: 要解析的字符串
  • radix: 进制基数,默认 0

返回值: 解析后的整数,失败返回 0

示例:

// 与原生 parseInt 的对比
console.log(Laya.Utils.parseInt("123"));       // 123
console.log(parseInt("123"));                   // 123

console.log(Laya.Utils.parseInt(""));          // 0 (原生返回 NaN)
console.log(parseInt(""));                      // NaN

console.log(Laya.Utils.parseInt("abc"));       // 0 (原生返回 NaN)
console.log(parseInt("abc"));                   // NaN

console.log(Laya.Utils.parseInt("45.67"));     // 45
console.log(Laya.Utils.parseInt("0xFF"));      // 255

// 实际应用:解析配置文件
interface GameConfig {
    maxLevel: string;
    playerCount: string;
    difficulty: string;
}

function parseConfig(config: GameConfig): void {
    let maxLevel = Laya.Utils.parseInt(config.maxLevel);
    let playerCount = Laya.Utils.parseInt(config.playerCount);
    let difficulty = Laya.Utils.parseInt(config.difficulty);

    console.log(`最大关卡: ${maxLevel}, 玩家数: ${playerCount}, 难度: ${difficulty}`);
}

// 即使配置项缺失也不会导致 NaN
let config: GameConfig = {
    maxLevel: "10",
    playerCount: "",
    difficulty: "abc"
};
parseConfig(config);
// 输出: 最大关卡: 10, 玩家数: 0, 难度: 0

// 实际应用:安全的数值输入处理
function processUserInput(input: string): number {
    let value = Laya.Utils.parseInt(input);
    if (value <= 0) {
        console.warn("无效输入,使用默认值 1");
        return 1;
    }
    return value;
}

异步工具

sleep

异步延迟指定毫秒数。

static sleep(timeout: number): Promise<void>

参数:

  • timeout: 延迟的毫秒数

返回值: Promise,延迟结束后 resolve

示例:

// 基本用法
async function example1() {
    console.log("开始");
    await Laya.Utils.sleep(1000);
    console.log("1秒后");
}

// 实际应用:动画延迟效果
async function showTitleAnimation(sprite: Laya.Sprite): Promise<void> {
    sprite.alpha = 0;
    sprite.visible = true;

    // 渐入效果
    for (let i = 0; i <= 10; i++) {
        sprite.alpha = i / 10;
        await Laya.Utils.sleep(30);
    }
}

// 实际应用:倒计时
async function countdown(seconds: number): Promise<void> {
    for (let i = seconds; i > 0; i--) {
        console.log(`${i}...`);
        await Laya.Utils.sleep(1000);
    }
    console.log("时间到!");
}

// 实际应用:重试机制
async function fetchWithRetry<T>(
    task: () => Promise<T>,
    maxRetries: number = 3,
    delay: number = 1000
): Promise<T> {
    for (let i = 0; i < maxRetries; i++) {
        try {
            return await task();
        } catch (error) {
            if (i === maxRetries - 1) throw error;
            console.log(`重试 ${i + 1}/${maxRetries}`);
            await Laya.Utils.sleep(delay);
        }
    }
    throw new Error("获取失败");
}

until

等待条件函数返回 true,或超时后结束。

static until(predicate: () => boolean, timeout?: number): Promise<void>

参数:

  • predicate: 判断函数,返回 true 时结束等待
  • timeout: 超时时间(毫秒),可选

返回值: Promise

示例:

// 基本用法:等待资源加载完成
let resourceLoaded = false;

async function loadResource() {
    // 模拟异步加载
    Laya.timer.once(2000, this, () => {
        resourceLoaded = true;
    });
}

async function waitForResource() {
    await Laya.Utils.until(() => resourceLoaded, 5000);
    console.log("资源已加载");
}

// 实际应用:等待对象初始化
class AssetLoader {
    private isReady = false;

    load(url: string): void {
        // 开始加载...
        Laya.loader.load(url).then(() => {
            this.isReady = true;
        });
    }

    async waitReady(timeout: number = 10000): Promise<boolean> {
        try {
            await Laya.Utils.until(() => this.isReady, timeout);
            return true;
        } catch {
            return false;
        }
    }
}

runTasks

并发执行多个任务,可控制并发数量。

static runTasks<T, T2>(
    datas: Array<T2>,
    numParallelTasks: number,
    taskFunc: (data: T2, index: number) => T | Promise<T>
): Promise<T[]>

参数:

  • datas: 数据数组
  • numParallelTasks: 并发任务数
  • taskFunc: 对每个数据执行的任务函数

返回值: Promise<T[]>,包含所有任务的结果

示例:

// 基本用法:批量加载资源
async function loadImages(urls: string[]): Promise<Laya.Texture2D[]> {
    return Laya.Utils.runTasks(
        urls,
        3, // 最多同时加载 3 个
        async (url) => {
            return await Laya.loader.load(url, Laya.Texture2D) as Laya.Texture2D;
        }
    );
}

// 实际应用:批量处理玩家数据
class Player {
    async fetchStatsFromServer(): Promise<void> { /* ... */ }
    updateUI(): void { /* ... */ }
}

async function updatePlayerStats(players: Player[]): Promise<void> {
    await Laya.Utils.runTasks(
        players,
        5, // 每次处理 5 个玩家
        async (player) => {
            await player.fetchStatsFromServer();
            player.updateUI();
        }
    );
}

runAllTasks

并发执行所有任务,返回所有任务的结果(包括失败的任务)。

static runAllTasks<T, T2>(
    datas: Array<T2>,
    numParallelTasks: number,
    taskFunc: (data: T2, index: number) => T | Promise<T>
): Promise<PromiseSettledResult<T>[]>

参数:

  • datas: 数据数组
  • numParallelTasks: 并发任务数
  • taskFunc: 任务函数

返回值: Promise<PromiseSettledResult[]>

示例:

// 基本用法:批量处理,允许部分失败
async function loadAllImages(urls: string[]): Promise<void> {
    let results = await Laya.Utils.runAllTasks(
        urls,
        3,
        async (url) => {
            return await Laya.loader.load(url, Laya.Texture2D) as Laya.Texture2D;
        }
    );

    // 检查结果
    results.forEach((result, index) => {
        if (result.status === "fulfilled") {
            console.log(`${urls[index]} 加载成功`);
        } else {
            console.error(`${urls[index]} 加载失败`);
        }
    });
}

字符串工具

parseTemplate

解析模板字符串,替换占位符为实际值。

static parseTemplate(template: string, vars: Record<string, any>): string

参数:

  • template: 包含占位符的模板字符串
  • vars: 变量对象

返回值: 替换后的字符串

示例:

// 基本用法
let result1 = Laya.Utils.parseTemplate("Hello {name}!", { name: "World" });
// "Hello World!"

let result2 = Laya.Utils.parseTemplate("{greeting}, {name}!", {
    greeting: "你好",
    name: "玩家"
});
// "你好, 玩家!"

// 实际应用:生成动态消息
function generateMessage(template: string, data: any): string {
    return Laya.Utils.parseTemplate(template, data);
}

let welcomeMsg = generateMessage(
    "欢迎 {playerName}! 当前等级: {level}",
    { playerName: "勇者", level: 10 }
);
// "欢迎 勇者! 当前等级: 10"

// 实际应用:格式化日志
function formatLog(template: string, context: any): string {
    let timestamp = new Date().toISOString();
    return Laya.Utils.parseTemplate(`[${timestamp}] ${template}`, context);
}

console.log(formatLog("玩家 {name} 获得了 {exp} 经验", { name: "张三", exp: 100 }));

compareVersion

比较两个版本号字符串的大小。

static compareVersion(ver1: string, ver2: string): number

参数:

  • ver1: 版本号 1
  • ver2: 版本号 2

返回值: 负数表示 ver1 < ver2,0 表示相等,正数表示 ver1 > ver2

示例:

// 基本用法
console.log(Laya.Utils.compareVersion("1.0.0", "1.0.1"));  // < 0
console.log(Laya.Utils.compareVersion("1.0.1", "1.0.0"));  // > 0
console.log(Laya.Utils.compareVersion("1.0.0", "1.0.0"));  // 0
console.log(Laya.Utils.compareVersion("2.0.0", "1.9.9"));  // > 0

// 实际应用:检查版本更新
class VersionChecker {
    private currentVersion = "1.2.0";

    needsUpdate(latestVersion: string): boolean {
        return Laya.Utils.compareVersion(latestVersion, this.currentVersion) > 0;
    }

    checkCompatibility(requiredVersion: string): boolean {
        return Laya.Utils.compareVersion(this.currentVersion, requiredVersion) >= 0;
    }
}

let checker = new VersionChecker();
console.log(checker.needsUpdate("1.3.0")); // true
console.log(checker.checkCompatibility("1.0.0")); // true

isUUID

检查字符串是否为有效的 UUID 格式。

static isUUID(str: string): boolean

参数:

  • str: 要检查的字符串

返回值: 是否为有效 UUID

示例:

// 基本用法
console.log(Laya.Utils.isUUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")); // true
console.log(Laya.Utils.isUUID("not-a-uuid")); // false
console.log(Laya.Utils.isUUID("")); // false

几何计算

testPointInPolygon

判断一个点是否在多边形内部。

static testPointInPolygon(x: number, y: number, areaPoints: number[]): boolean

参数:

  • x: 测试点的 X 坐标
  • y: 测试点的 Y 坐标
  • areaPoints: 多边形顶点坐标数组 [x1, y1, x2, y2, …]

返回值: 点是否在多边形内

示例:

// 定义一个三角形多边形
let triangle = [
    100, 100,  // 顶点 1
    200, 100,  // 顶点 2
    150, 200   // 顶点 3
];

// 测试点是否在三角形内
console.log(Laya.Utils.testPointInPolygon(150, 150, triangle)); // true (在内部)
console.log(Laya.Utils.testPointInPolygon(50, 50, triangle));   // false (在外部)

// 实际应用:检测玩家是否在区域内
class GameZone {
    private bounds: number[];

    constructor(bounds: number[]) {
        this.bounds = bounds;
    }

    contains(x: number, y: number): boolean {
        return Laya.Utils.testPointInPolygon(x, y, this.bounds);
    }
}

// 创建一个不规则游戏区域
let dangerZone = new GameZone([
    0, 0,      // 左上
    300, 0,    // 右上
    350, 200,  // 右中
    300, 400,  // 右下
    0, 400     // 左下
]);

// 检查点是否在危险区域
if (dangerZone.contains(100, 100)) {
    console.warn("进入危险区域!");
}

其他工具

getGID

为给定的对象-方法对生成全局唯一 ID。

static getGID(target: Object | null, method?: Function | string): string

参数:

  • target: 目标对象
  • method: 方法或方法名,可选

返回值: 全局唯一 ID 字符串

示例:

class MyClass {
    method1() {}
    method2() {}
}

let obj = new MyClass();
let id1 = Laya.Utils.getGID(obj, obj.method1);
let id2 = Laya.Utils.getGID(obj, obj.method2);

console.log(id1); // 唯一 ID
console.log(id2); // 另一个唯一 ID

// 实际应用:事件处理器去重
class EventManager {
    private handlerMap = new Map<string, Function>();

    addHandler(target: Object, method: Function, callback: Function): void {
        let id = Laya.Utils.getGID(target, method);
        this.handlerMap.set(id, callback);
    }

    removeHandler(target: Object, method: Function): void {
        let id = Laya.Utils.getGID(target, method);
        this.handlerMap.delete(id);
    }
}

完整示例

以下是一个综合使用 Laya.Utils 工具类的完整示例:

export async function main() {
    await Laya.init( 800, 600 );

    // 1. 创建精灵并绘制
    let sprite = new Laya.Sprite();
    sprite.graphics.drawRect(0, 0, 100, 100, "#ff0000", null, 1);
    sprite.pos(350, 250);
    Laya.stage.addChild(sprite);

    // 2. 使用路径工具
    let texturePath = "assets/image.png";
    let ext = Laya.Utils.getFileExtension(texturePath);
    let baseName = Laya.Utils.getBaseName(texturePath, true);
    let newPath = Laya.Utils.replaceFileExtension(texturePath, "json");
    console.log("文件名:", baseName, "扩展名:", ext, "新路径:", newPath);

    // 3. 旋转动画
    let rotation = 0;
    let animate = () => {
        rotation += 2;
        if (rotation >= 360) rotation = 0;
        sprite.rotation = rotation; // Sprite.rotation 直接使用角度
        Laya.timer.frameOnce(1, null, animate);
    };
    animate();

    // 4. 使用 parseTemplate
    let message = Laya.Utils.parseTemplate(
        "精灵已旋转 {angle} 度",
        { angle: rotation }
    );
    console.log(message);

    // 5. 使用 parseInt
    let level = Laya.Utils.parseInt("10");
    console.log("当前等级:", level);

    // 6. 测试点是否在多边形内
    let polygon = [300, 200, 500, 200, 500, 400, 300, 400];
    let isInside = Laya.Utils.testPointInPolygon(400, 300, polygon);
    console.log("点在多边形内:", isInside);

    // 7. 版本比较
    let cmp = Laya.Utils.compareVersion("1.0.0", "1.0.1");
    console.log("版本比较结果:", cmp);
}

注意事项

  1. 静态方法: Utils 类的所有方法都是静态的,不需要实例化即可使用。

  2. parseInt 的安全性: 使用 Laya.Utils.parseInt() 而非原生 parseInt() 可以避免 NaN 的问题,更适合处理用户输入或配置文件。

  3. 异步操作: sleep(), until(), runTasks() 等方法返回 Promise,需要在 async 函数中使用。

  4. 在调用 Math.sin()Math.cos() 等三角函数时可以用 toRadian() 转换。

  5. 版本比较: compareVersion() 期望版本号格式为 “x.y.z” 的点分格式。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐