Laya 扩展Math类(待补充)

本文介绍了一套专为游戏开发设计的数学工具箱,涵盖随机数生成、向量操作、角度转换、几何计算等功能。通过具体实例展示了如何在游戏场景中应用这些数学函数,如角色定位、路径寻找、物体旋转等。
import Vector4 = Laya.Vector4;
import Vector2 = Laya.Vector2;
import Camera = Laya.Camera;
import Vector3 = Laya.Vector3;
import Point = Laya.Point;

export default class MathE {

    /**
     * 取 [ min , max ) 范围的随机数
     * @param min 
     * @param max 
     * @param isInt 
     */
    public static range(min: number, max: number, isInt: boolean = false): number {
        if (max < min) {
            console.error(`[MathE].range(): 错误的输入! [${min},${max})`);
            return null;
        }

        if (!isInt) {
            return (min + (max - min) * Math.random());
        } else {
            return Math.floor(min + (max - min) * Math.random());
        }
    }

    /**
     * 从一个数组里面随机取一些值[min, max)
     * @param min 范围区间
     * @param max 范围区间
     * @param n 取多少
     */
    public static randomArray(min: number, max: number, n: number): Array<number> {
        if (max < min || n <= 0 || n > max - min) {
            console.error(`[MathE].randomArray(): 错误的输入! [${min},${max}], 数量 ${n}`);
            return null;
        }

        let arr: Array<number> = new Array<number>();
        let result: Array<number> = new Array<number>();
        for (let i = min; i < max; i++) {
            arr.push(i);
        }

        for (let j = 0; j < n; j++) {
            let r: number = MathE.range(0, arr.length, true);
            result.push(arr[r]);
            arr.splice(r, 1);
        }

        return result;
    }

    /**
     * 从p1到p2的方向单位向量
     * @param p1 
     * @param p2 
     */
    public static normalizeM2(p1: { r: number, c: number } | any, p2: { r: number, c: number } | any): { x: number, y: number } {
        let x = p2.c - p1.c;
        let y = p2.r - p1.r;
        var d = Math.sqrt(x * x + y * y);
        if (d > 0) {
            var id = 1.0 / d;
            x *= id;
            y *= id;
        }

        return { x: x, y: y }
    }

    /**
 * 从p1到p2的方向单位向量
 * @param p1 
 * @param p2 
 */
    public static normalize(p1: { x: number, y: number } | any, p2: { x: number, y: number } | any): { x: number, y: number } {
        let x = p2.x - p1.x;
        let y = p2.y - p1.y;
        var d = Math.sqrt(x * x + y * y);
        if (d > 0) {
            var id = 1.0 / d;
            x *= id;
            y *= id;
        }

        return { x: x, y: y }
    }

    /**
     * 二维平面上 两点之间的距离
     * @param p1 点1
     * @param p2 点2
     */
    public static distanceV2(p1: { x: number, y: number } | any, p2: { x: number, y: number } | any): number {
        return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
    }

    /**
     * 二维矩阵中上 两点之间的距离,默认两个点之间的距离为1
     * @param p1 点1
     * @param p2 点2
    */
    public static distanceM2(p1: {r:number, c:number}, p2: {r:number, c:number}): number {
        return Math.sqrt(Math.pow(p1.r - p2.r, 2) + Math.pow(p1.c - p2.c, 2));
    }

    /**
     * 根据开始位置和结束位置返回从开始位置到结束位置的朝向角度
     * @param startPoint 开始位置
     * @param endPoint 结束位置
     * @returns 从开始位置朝向结束位置的角度0 - 360
     */
    public static angle(startPoint: Point | { x, y }, endPoint: Point | { x, y }): number {
        if (startPoint.x == endPoint.x && startPoint.y == endPoint.y) return 0;
        let r = 0;
        let xOffset = (endPoint.x - startPoint.x);
        let yOffset = -(endPoint.y - startPoint.y);

        if (xOffset > 0) {
            if (yOffset > 0) { // 第一象限
                r = Math.atan(xOffset / yOffset) * 180 / Math.PI;
            } else { // 第四象限
                r = Math.atan(-yOffset / xOffset) * 180 / Math.PI + 90;
            }
        } else {
            if (yOffset > 0) { // 第二象限
                r = 360 - Math.atan(-xOffset / yOffset) * 180 / Math.PI;
            } else { // 第三象限
                r = Math.atan(-xOffset / -yOffset) * 180 / Math.PI + 180;
            }
        }

        return r;
    }

    /**
     * 将角度转换为 0 - 360 之间
     * @param rot 
     */
    public static formatRot(rot:number): number {
        return ((rot % 360) + 360) % 360;
    }

    /**
     * 获取一个接近的2D旋转角度
     * @param currRot 
     * @param deltaRot 要旋转的角度
     * @param tarRot 
     */
    public static getNearerRot(currRot:number, deltaRot:number, tarRot:number): number {
        currRot = this.formatRot(currRot);
        deltaRot = this.formatRot(deltaRot);
        // tarRot = this.formatRot(tarRot);
        let tarTempRot = this.formatRot(tarRot);

        if(deltaRot >= 180) return tarRot;

        let interval = Math.abs(tarTempRot - currRot); // 两个
        if(interval < 180) {
            if(interval <= deltaRot) return tarRot;

            if(tarTempRot > currRot) {
                return currRot + deltaRot;
            } else {
                return currRot - deltaRot;
            }
        } else {
            if(interval - 180 <= deltaRot) return tarRot;

            if(tarTempRot > currRot) {
                return this.formatRot(currRot - deltaRot);
            } else {
                return this.formatRot(currRot + deltaRot);
            }
        }
    }

    /**
     * 两个数中的最小数
     * @param a 
     * @param b 
     */
    public static min(a: number, b: number): number {
        return a < b ? a : b;
    }

    /**
     * 两个数中的最大数
     * @param a 
     * @param b 
     */
    public static max(a: number, b: number): number {
        return a > b ? a : b;
    }

    /**
     * 打印二维向量的字符串
     * @param output 二维向量
     */
    public static logV2(output: Laya.Point): void {
        if (!output) {
            MathE.error();
        }

        console.log(`(${output.x.toFixed(2)},${output.y.toFixed(2)})`);
    }

    /**
     * 打印三维向量的字符串
     * @param output 三维向量
     */
    public static logV3(output: Laya.Vector3): void {
        if (!output) {
            MathE.error();
        }

        console.log(`(${output.x.toFixed(2)},${output.y.toFixed(2)},${output.z.toFixed(2)})`);
    }

    /**
     * 输入警告
     */
    public static error(): void {
        console.error(`[MathE].*(): 错误的输入! `);
    }

    /**
     * 求两个直线的方程的交点 ax + bx + c = 0, 下面两个三维向量分别存放参数a,b,c
     * @param line0 直线方程参数
     * @param line1 直线方程参数
     */
    public static pointOfIntersection(line0: Laya.Vector3, line1: Laya.Vector3): Laya.Point {
        let a0: number = line0.x; let b0: number = line0.y; let c0: number = line0.z;
        let a1: number = line1.x; let b1: number = line1.y; let c1: number = line1.z;
        let x: number = (c1 * b0 - c0 * b1) / (a0 * b1 - a1 * b0);
        let y: number = - a0 / b0 * x - c0 / b0;

        return new Laya.Point(x, y);
    }

    /**
     * 随机一个正负1,用来做随机正反方向,位置或者数字等
     */
    public static symbol(): number {
        return Math.random() > 0.5 ? 1 : -1;
    }

    /**
     * 正方形的对角线长度
     * @param side 边长
     */
    public static diagonalSquare(side: number): number {
        return Math.sqrt(2 * side * side);
    }

    /**
     * 3D坐标对应的2D坐标
     * @param camera 摄像机
     * @param position 3D位置
     * @returns 2D屏幕上的位置
     */
    public static v3PosTo2DPos(camera: Camera, position: Vector3): Vector2 {
        let outPos: Vector4 = new Vector4();
        camera.viewport.project(position, camera.projectionViewMatrix, outPos);
        return new Vector2(outPos.x, outPos.y);
    }

    /**
     * 根据一个2D物体的角度, 返回该角度对应的单位向量
     * @param angle 2D物体的角度
     * @returns 
     */
    public static angleToV2(angle: number): Point {
        angle = angle < 0 ? (angle - (360 * Math.floor(angle / 360))) : angle % 360;
        if (angle == 0) return new Point(0, -1);
        if (angle == 90) return new Point(1, 0);
        if (angle == 180) return new Point(0, 1);
        if (angle == 270) return new Point(-1, 0);

        let a = angle / 180 * Math.PI;
        if (angle <= 90) {
            return new Point(Math.sin(a), -Math.cos(a));
        } else if (angle <= 180) {
            a -= Math.PI / 2;
            return new Point(Math.cos(a), Math.sin(a));
        } else if (angle <= 270) {
            a -= Math.PI;
            return new Point(-Math.sin(a), Math.cos(a));
        } else if (angle <= 360) {
            a -= Math.PI * (3 / 2);
            return new Point(-Math.cos(a), -Math.sin(a));
        }
    }

    /**
     * 反转
     * @param x 
     */
    static reverse(x: number): number {
        let MAX: number = 2147483647;
        let MIN: number = -2147483648;

        let sign: number = 1; // 记录当前整数的符号
        if (x < 0) { // 将x变为正整数处理
            sign = -1;
            x = -x;
        }

        let result: number = 0;
        while (x) {
            result = (x % 10) + result * 10;
            x = Math.floor(x / 10);
        }
        result *= sign;
        return result > MAX || result < MIN ? 0 : result;
    }

    /**
     * 字符串转数组,返回一个数组
     * @param strToArrBool 字符串转数组 true   数组转字符串 false
     * @param str 传入字符串
     * @param splitStr 需要切割的特殊字符 例如: , . | 。等
     */
    public static StrToArr(strToArrBool, str: string, splitStr, arr): any {
        if (strToArrBool) {
            //字符串转数组
            if (str != null) {
                return str.split(splitStr);
            } else {
                return [];
            }
        } else {
            //数组转字符串
            let str = "";
            for (let index = 0; index < arr.length; index++) {
                if (index == arr.length - 1) {
                    str += arr[index];
                } else {
                    str += arr[index] + splitStr;
                }
            }
            return str;
        }
    }
    public static readonly AllStr: string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    /**
     * 获取一个随机字符串
     * @param len 长度
     */
    static getRandomStr(len: number): string {
        let str: string = "";
        let l: number = MathE.AllStr.length;
        for (let i: number = 0; i < len; i++) {
            str += MathE.AllStr.charAt(MathE.range(0, l, true));
        }
        return str;
    }

    /**
     * 二分查找
     * @param nums 
     * @param target 
     */
    static binarySearch(nums: Array<number>, target: number): number {
        if (target < nums[0] || target > nums[nums.length - 1]) return -1;
        let left: number = 0;
        let right: number = nums.length - 1;
        let middle: number = 0;
        while (left <= right) {
            middle = Math.floor((left + right) / 2);
            if (nums[middle] == target) {
                return middle;
            } else {
                if (nums[middle] > target) {
                    right = middle - 1;
                } else {
                    left = middle + 1;
                }
            }
        }
        return -1;
    }

    /**
     * 
     * @param str 
     * @param size 
     * @returns 
     */
    static hashFunc(str, size) {
        //1.定义hashCode变量
        var hashCode = 0

        //2.霍纳算法,来计算 hashCode的值
        for (var i = 0; i < str.length; i++) {
            hashCode = 37 * hashCode + str.charCodeAt(i) //获取编码
        }
        //3.取余状态
        var index = hashCode % size

        return index
    }

    /**
     * 2阶贝塞尔曲线函数
     * @param p0 初始点
     * @param p1 初始点与目标点之间找寻的一个控制点
     * @param p2 目标点
     * @param obj 做运动的对象
     * @param time 时间变化 0-1
     */
    public static TwoBsier(p0, p1, p2, obj, time) {
        let x1 = p0.x + (p1.x - p0.x) * time;
        let y1 = p0.y + (p1.y - p0.y) * time;
        let x2 = p1.x + (p2.x - p1.x) * time;
        let y2 = p1.y + (p2.y - p1.y) * time;
        obj.x = x1 + (x2 - x1) * time;
        obj.y = y1 + (y2 - y1) * time;
        if (time < 1) {
            return true
        } else {
            return false;
        }
    }

    /**
     * 返回两点之间的中心点
     * @param p1 值1
     * @param p2 值2
     * @returns 返回值。number类型
    */
    public static TwoPointMidPos(p1, p2): number {
        if (p1 > 0 && p2 > 0) {
            return Math.min(p1, p2) + ((Math.max(p1, p2) - Math.min(p1, p2)) * 0.5);
        } else {
            if (p1 <= 0 && p2 <= 0) {
                return Math.max(p1, p2) + ((Math.min(p1, p2) - Math.max(p1, p2)) * 0.5);
            } else {
                if (p1 > 0) {
                    //p2 < 0
                    return (p1 - (p2 * -1)) * 0.5;
                }
                if (p2 > 0) {
                    //p1 < 0
                    return (p2 - (p1 * -1)) * 0.5;
                }
            }
        }
    }

    /** 获取0-1的概率里的一个数 */
    public static getRandomNum(rateType) {
        let randomNumber = Math.random();
        let startRate = 0;
        for (let num in rateType) {
            let rateTmp = rateType[num];
            if (randomNumber > startRate && randomNumber <= startRate + rateTmp) {
                return parseInt(num);
            }
            startRate += rateTmp;
        }
        return 10;
    }

    /** 判断该数字是否在某个范围内, 如果在直接返回该值, 否则返回边界值*/
    public static inRange(num: number, min: number, max: number): number {
        if (num < min) {
            return min;
        } else if (num > max) {
            return max;
        } else {
            return num;
        }
    }

    /**
     * 获取贝塞尔曲线的点的集合
     * @param points 点的集合, 至少包含起点和终点
     * @param num 想要生成多少点
     * @returns 
    */
    public static getCurvePointsInNum(points: Array<any>, num: number): Array<any> {
        let result: Array<any> = new Array<any>();
        for (let i: number = 0; i < num; i++) {
            let t: number = i / (num - 1);
            let point = this.getKeyPoint(points, t);
            result.push(point);
        }
        return result;
    }

    public static getKeyPoint(points: Array<any>, t: number): any {
        if (points.length > 1) {
            let dirs: Array<any> = new Array<any>();
            for (let i: number = 0; i < points.length - 1; i++) {
                dirs.push({
                    x: points[i + 1].x - points[i].x,
                    y: points[i + 1].y - points[i].y
                });
            }
            let points2: Array<any> = new Array<any>();
            for (let j: number = 0; j < dirs.length; j++) {
                points2.push({
                    x: points[j].x + dirs[j].x * t,
                    y: points[j].y + dirs[j].y * t
                });
            }
            return this.getKeyPoint(points2, t);
        } else {
            return { x: points[0].x, y: points[0].y };
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值