三角函数在游戏中的应用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
更多内容请关注微信公众号

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345