200字
开发3.0两位置角度计算自定义函数
2026-02-11
2026-02-11

自定义函数脚本展示

-- ==============================================
-- 【教学版脚本】两点坐标计算旋转角度 (含物理高度补偿)
-- 适用场景:迷你世界自瞄系统、自动视角追踪、NPC看向玩家
-- 核心知识点:三维几何、三角函数应用、角度归一化、参数校验
-- ==============================================

local Script = {}

-- ==============================================
-- 第一步:开放函数声明(供外部调用的接口)
-- 教学重点:Script.openFnArgs 是迷你世界开放自定义函数的标准规范
-- ==============================================
Script.openFnArgs = {
    -- 函数名:获取两点坐标的旋转角度
    获取两点坐标的旋转角度 = {
        returnType = Mini.Vec3,       -- 返回值类型:三维向量(存角度)
        displayName = "两点算角度(水平,俯仰,0)", -- 编辑器显示名
        params = {
            ("起始位置"), Mini.Vec3,  -- 参数1:观察者坐标(如玩家)
            ("目标位置"), Mini.Vec3   -- 参数2:目标坐标(如怪物)
        },
    },
}

-- ==============================================
-- 第二步:脚本初始化(加载时执行)
-- 教学重点:OnStart 是脚本的入口函数,用于打印日志和初始化数据
-- ==============================================
function Script:OnStart()
    -- 【日志规范】使用 [Info] 标签区分日志等级,便于调试
    print("[Info] 两点坐标算旋转角度 - 教学版已加载")
    print("[教学提示] 返回值规则:Vec3(x=水平角Yaw, y=俯仰角Pitch, z=固定0)")
end

-- ==============================================
-- 第三步:工具函数 - 校验坐标有效性
-- 教学重点:防御性编程。在使用参数前,必须检查其类型和完整性,避免脚本崩溃。
-- ==============================================
---@param pos table 待检查的坐标表
---@return bool 是否为有效的 Mini.Vec3 类型
local function IsValidVec3(pos)
    -- 检查逻辑:必须是表,且包含 x, y, z 三个数字类型的键
    return type(pos) == "table" 
        and type(pos.x) == "number" 
        and type(pos.y) == "number" 
        and type(pos.z) == "number"
end

-- ==============================================
-- 第四步:工具函数 - 角度归一化
-- 教学重点:游戏内的角度通常需要限制在 [-180, 180] 或 [0, 360] 之间,防止视角异常。
-- 原理:利用取模运算 (%) 处理循环,再通过判断调整负数角度。
-- ==============================================
---@param angle number 原始角度
---@return number 归一化后的角度(范围:-180 ~ 180)
local function NormalizeAngle(angle)
    -- 第一步:取模,将角度压缩到 0 ~ 360 之间
    angle = angle % 360
    -- 第二步:转换为 -180 ~ 180 区间,符合迷你世界视角API习惯
    if angle > 180 then
        return angle - 360
    elseif angle < -180 then
        return angle + 360
    else
        return angle
    end
end

-- ==============================================
-- 第五步:核心函数 - 计算旋转角度
-- 教学重点:这是整个脚本的算法核心,分为 5 个步骤完成计算。
-- 数学基础:勾股定理(求距离)、反正切函数 math.atan(求角度)
-- ==============================================
---@param startPos Mini.Vec3 起始位置(玩家脚底坐标)
---@param targetPos Mini.Vec3 目标位置(目标脚底坐标)
---@return Mini.Vec3|nil 旋转角度 Vec3(yaw, pitch, 0),失败则返回nil
function Script:获取两点坐标的旋转角度(startPos, targetPos)
    -- 【步骤1:严格的参数校验】
    -- 如果传入的坐标是空的,或者格式不对,直接报错并返回
    if not startPos or not targetPos or not IsValidVec3(startPos) or not IsValidVec3(targetPos) then
        print("[Error] [教学提示] 参数错误:请传入有效的 Mini.Vec3 坐标")
        return nil
    end

    -- 【步骤2:解构坐标数据】
    -- 将表结构的坐标拆解为单独的变量,方便后续数学计算,提升代码可读性
    local sx, sy, sz = startPos.x, startPos.y, startPos.z -- 起始点坐标
    local tx, ty, tz = targetPos.x, targetPos.y, targetPos.z -- 目标点坐标

    -- ==============================================
    -- 【关键教学点:物理高度补偿】
    -- 问题:游戏中获取的坐标通常是“脚底”位置。如果直接计算,会导致瞄准脚底。
    -- 解决:模拟真实的视线高度。
    -- ==============================================
    local cameraHeight = 1.6 -- 迷你世界玩家相机默认高度(眼睛位置)
    local targetBodyHeight = 0.8 -- 目标身体中心高度(可根据怪物大小调整)
    
    local cameraY = sy + cameraHeight -- 修正后的观察者视线高度
    local targetCenterY = ty + targetBodyHeight -- 修正后的目标瞄准点高度

    -- 【步骤3:计算向量差值】
    -- 构建从起始点指向目标点的向量(Delta)
    local dx = tx - sx -- X轴偏移量(水平横向)
    local dz = tz - sz -- Z轴偏移量(水平纵向)
    local dy = targetCenterY - cameraY -- Y轴偏移量(垂直高度差,已补偿)

    -- 【步骤4:计算水平距离(勾股定理)】
    -- 只计算XZ平面的距离,用于后续俯仰角计算
    -- 防除零保护:如果两点重叠,设置一个极小值,避免 math.atan(inf) 报错
    local horizontalDistance = math.sqrt(dx * dx + dz * dz)
    if horizontalDistance < 0.0001 then
        horizontalDistance = 0.0001
        print("[Warn] [教学提示] 起始点与目标点重叠,已触发防除零保护")
    end

    -- ==============================================
    -- 【核心算法:水平角 (Yaw) 计算】
    -- 范围:0 ~ 360度
    -- 原理:通过反正切函数计算夹角,再根据坐标所在的象限进行修正。
    -- ==============================================
    local yaw = 0
    -- 计算邻边与对边的正切值(绝对值,先算角度大小,再定方向)
    local tanValue = math.abs(dx) / math.abs(dz)
    -- 反正切转角度:math.atan(值) 返回弧度,需乘以 180/math.pi 转为角度
    local baseAngle = math.atan(tanValue) * 180 / math.pi

    -- 【象限判断逻辑】:根据 dx 和 dz 的正负,确定最终的水平角度
    if dz < 0 and dx > 0 then
        yaw = 180 - baseAngle       -- 第二象限
    elseif dz < 0 and dx < 0 then
        yaw = 180 + baseAngle       -- 第三象限
    elseif dz > 0 and dx < 0 then
        yaw = 360 - baseAngle       -- 第四象限
    else
        yaw = baseAngle             -- 第一象限
    end

    -- ==============================================
    -- 【核心算法:俯仰角 (Pitch) 计算】
    -- 范围:-90 ~ 90度(向上为负,向下为正,符合迷你世界API)
    -- 原理:利用高度差和水平距离,计算视线与水平面的夹角。
    -- ==============================================
    local pitch = 0
    local tanH = math.abs(dy) / horizontalDistance -- 高度差与水平距离的正切值
    local basePitch = math.atan(tanH) * 180 / math.pi

    -- 方向判断:dy > 0 表示目标在上方,需要向上看(负角度)
    if dy > 0 then
        pitch = -basePitch
    else
        pitch = basePitch
    end

    -- 【步骤5:结果归一化】
    -- 将计算出的角度标准化,确保符合游戏引擎的输入要求
    yaw = NormalizeAngle(yaw)
    pitch = NormalizeAngle(pitch)

    -- 构建返回值:严格遵循 Mini.Vec3 类型定义
    local result = Mini.Vec3(yaw, pitch, 0)

    -- 【调试日志】:格式化输出,保留1位小数,便于在控制台观察数据
    print(string.format("[计算结果] [教学提示] 水平角:%.1f° | 俯仰角:%.1f°", yaw, pitch))

    return result
end

-- 脚本结束:返回脚本对象,供游戏引擎注册
return Script

脚本介绍

该脚本由AI生成,可以根据两个三维坐标点精准计算出从“起始点”看向“目标点”所需的旋转角度,并做出了一定的高度补偿用于确定瞄准的是位置中心而非下方,返回值为位置参数,X代表水平角,Y代表俯仰角,Z为零

脚本用处

可以搭配“改变玩家面向角度”动作制作自瞄效果,更多玩法等你发现!

开发3.0两位置角度计算自定义函数

评论