三角函数在游戏中的应用CocosCreator方向和角度的转换

最终目标
请添加图片描述
文末有源码
本文讲的基础一点,可能有些啰嗦,大佬轻喷。

数学概念

下面要引入两个数学概念,一个是正弦余弦和正切,一个是角度制和弧度制

正弦 余弦 正切

请添加图片描述
如图,在Rt△ABC中,∠C = 90°,斜边为c,长的直角边为b,短的直角边为a。

正弦
我们把∠A的对边与斜边的比叫做∠A的正弦(sine),记作sinA,即

sinA = ∠A的对边 / ∠A的斜边 = a / c

余弦
我们把∠A的邻边与斜边的比叫做∠A的余弦(cosine),记作cosA,即

cosA = ∠A的邻边 / ∠A的斜边 = b / c

正切
我们把∠A的对边与邻边的比叫做∠A的正切(tangent),记作tanA,即

tanA = ∠A的对边 / ∠A的邻边 = a / b

对于tanA有一个公式
tanA = sinA / cosA
也就是
a / b = (a / c) / (b / c)
a / b = (a / c) * (c / b)
等号右边上下两个c约掉了
也就只剩下a / b = a / b

在这里插入图片描述

在这里插入图片描述

角度制和弧度制

每个角度都有一个对应的弧度值
既然已经有角度制了,为什么还要有弧度制呢
因为代码里Math中用的三角函数都是弧度制,代码只认弧度制,不认角度制

180°角的弧度值是π

由此可以得出公式

弧度 = 角度 / 180° * π
角度 = 弧度 / π * 180°

也可以写成

弧度 = π / 180° * 角度
角度 = 180° / π * 弧度

其实都是一样的,一模一样,只是数的位置变了

仔细思考思考公式是怎么得出来的

开始写代码

只要实现小球围绕着红色中心点转悠就可以了(UI部分代码省略)
请添加图片描述
新建一个脚本取名Main,挂载到canvas上面,在脚本中声明以下属性

    @property({displayName: "小球", tooltip: "小球", type: Node})
    ball: Node = null!;

    @property({displayName: "中心红点", tooltip: "中心红点", type: Node})
    point: Node = null!;


    @property({displayName: "运动半径", tooltip: "运动半径", type: CCFloat})
    r: number = 200;

    @property({displayName: "每帧运动角度", tooltip: "每帧运动角度", type: CCFloat})
    angle_nor: number = 1;


    @property({displayName: "中心红点位置偏移量", tooltip: "中心红点位置偏移量"})
    offset: Vec2 = new Vec2(0, 0);


    // 下一帧需要运动的角度
    angle: number = 0;

PS出两个圆,拖拽到场景,设置成一大一小,为了醒目容易区分还可以改下颜色,大的取名ball,小的取名center_point
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
绑定下节点
在这里插入图片描述

接下来一直撸代码,没编辑器什么事了
先封装两个函数供自己调用
分别是角度转弧度弧度转角度
这里就用到了刚刚讲的公式
分别传入角度和弧度,经过代码计算之后返回弧度和角度

    // 角度转弧度
    angle_to_radian (angle: number): number {
        // 角度转弧度公式
        // π / 180 * 角度

        // 计算出弧度
        let radian = Math.PI / 180 * angle;
        // 返回弧度
        return(radian);
    }


    // 弧度转角度
    radian_to_angle (radian: number): number {
        // 弧度转角度公式
        // 180 / π * 弧度

        // 计算出角度
        let angle = 180 / Math.PI * radian;
        // 返回角度
        return(angle);
    }

在游戏开始时,把ball(白色大球)的坐标设置到最右边

	onLoad () {
        // 将小球的坐标设置到最右边
        this.ball.position = new Vec3(this.r, 0);
        // 设置下一帧需要运动的角度为最开始的角度
        this.angle = this.angle_nor;
    }

接着就是最主要的逻辑,全部写在update里面
先解释一下angle属性和angle_nor属性的区别,angle属性是大白球下一帧要运动的角度,不可以在编辑器进行调整,只在代码中进行修改。而angle_nor是可以在编辑器修改的,每帧运动的角度,update每执行一次angle就加上一次angle_nor,angle的值会越来越大。

如果下一帧需要运动的角度大于等于了360°,就进行取余,计算出angle的值 / 360的余数,并且将这个余数重新赋值给angle,取余这里其实没有必要写,写了和没写效果是一样的,但是写上看起来更舒服一些(至少我这么认为)

	update () {
        // log(this.angle);
        // 将每帧运动的角度计算成弧度
        let radian = this.angle_to_radian(this.angle);
        // 算出X和Y的坐标
        let x = this.r * Math.cos(radian);
        let y = this.r * Math.sin(radian);
        // 设置小球的坐标
        this.ball.position = new Vec3(x + this.offset.x, y + this.offset.y);
        // 将下一帧需要运动的角度增加
        this.angle += this.angle_nor;

        // 如果下一帧需要运动的角度大于等于了360°
        if (this.angle >= 360) {
            // 取余360   也就是说angle的值不会超过360度
        this.angle %= 360;
        }

        // 每帧更新中心红点位置
        this.point.position = new Vec3(this.offset.x, this.offset.y);
    }

update里面,首先把要旋转的角度计算成弧度,并且利用文章开头所讲的三角函数计算出大白球的坐标。

        // 算出X和Y的坐标
        let x = this.r * Math.cos(radian);
        let y = this.r * Math.sin(radian);

这两句代码就是利用三角函数计算出了小球的坐标,画个图辅助理解

在这里插入图片描述

点A绕原点O逆时针旋转30°,求出旋转后的点A’的坐标
旋转前点A的坐标是(r, 0),r是旋转半径
旋转之后得到A’,过A’向X轴做垂线交X轴于点B,连接OA’,得到Rt△A’OB
∠A’OB暂时管它叫∠α

文章开头写的三角函数,现在就用得上了,我们已知的只有半径r和∠α的角度是30°,求点A’的坐标
说是求点A’的坐标,实际上求出对边和邻边的长就可以了
点A的坐标就是(邻边, 对边)
sin α = 对边 / r
cos α = 邻边 / r

等号右边再×一个r就得到了对边和邻边的值
也就是
对边 = sin α * r
邻边 = cos α * r

在代码中可以用Math.cos()和Math.sin()传入一个角的弧度值返回这个角的余弦或正弦
这两个方法传入的参数只能是角的弧度,不能是角度
大白球的最终坐标就是(邻边长度, 对边长度)
计算出大白球最终坐标之后还要加上位置偏移量
并且更新中心红点的位置

这样就实现了小球围着中心红点转悠的功能

其实这就是角度转平面向量的一个过程
平面向量是在二维平面内既有方向(direction)又有大小(magnitude)的量
平常写代码为了方便我还封装了两个方法
分别是角度转平面向量和平面向量转角度
这个在代码中用的更多

    // 角度转向量   
    angle_to_vector (angle: number): Vec2 {
        // tan = sin / cos
        // 将传入的角度转为弧度
        let radian = this.angle_to_radian(angle);
        // 算出cos,sin和tan
        let cos = Math.cos(radian);// 邻边 / 斜边
        let sin = Math.sin(radian);// 对边 / 斜边
        let tan = sin / cos;// 对边 / 邻边
        // 结合在一起并归一化
        let vec = new Vec2(cos, sin).normalize();
        // 返回向量
        return(vec);
    }


    // !!!!!!!!其实使用Math.atan2求出弧度再转角度一样的效果
    // 向量转角度
    vector_to_angle (vector: Vec2): number {
        // 将传入的向量归一化
        let dir = vector.normalize();
        // 计算出目标角度的弧度
        let radian = dir.signAngle(new Vec2(1, 0));
        // 把弧度计算成角度
        let angle = -this.radian_to_angle(radian);
        // 返回角度
        return(angle);
    }

源代码:https://gitee.com/propertygame/cocos-creator3.x-demos/tree/master/TRF_Demo
技术交流Q群:1130122408
更多内容请关注微信公众号
请添加图片描述

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值