【cocos creator】【TS】贝塞尔曲线,地图之间显示曲线,顺着曲线移动

news2024/12/23 14:13:09

参考:
https://blog.csdn.net/Ctrls_/article/details/108731313
https://blog.csdn.net/qq_28299311/article/details/104009804
在这里插入图片描述

在这里插入图片描述



const { ccclass, property } = cc._decorator;

@ccclass
export default class mapPanel extends cc.Component {
    @property(cc.Node)
    player: cc.Node = null;
    @property(cc.Node)
    build: cc.Node = null;
    @property(cc.Node)
    point: cc.Node = null;
    @property(cc.Node)
    root: cc.Node = null;

    start() {
        this.init();
    }

    init(data?) {
        data = {
            mapData: [
                { id: 1, name: "1", pos: { x: 0, y: 100 } },
                { id: 2, name: "2", pos: { x: -100, y: -100 } },
                { id: 3, name: "3", pos: { x: 200, y: -80 } },
                { id: 4, name: "4", pos: { x: 180, y: 300 } },
                { id: 5, name: "5", pos: { x: 150, y: 50 } }
            ],
            linkData: [[2, 1], [1, 4], [5, 1], [5, 3], [2, 5]],
            startPosId: 2,
            road: [2, 5, 1, 4]
        }
        data.mapData.forEach(element => {
            this.creatOneBuild(element, data.startPosId)
        });
        this.player.position = data.mapData[data.startPosId - 1].pos
        data.linkData.forEach(element => {
            this.setPoint(cc.v2(data.mapData[element[0] - 1].pos), cc.v2(data.mapData[element[1] - 1].pos))
        });
        let roadArray = []
        data.road.forEach((element) => {
            roadArray.push(data.mapData[element - 1].pos);
        })
        this.playTween(roadArray);
    }

    playTween(roadArray, moveSpeed = 0.003, time = 1.5, delayTime = 0.3, cb?) {
        let tween = cc.tween(this.player)
        let nowPos = roadArray[0]
        for (let i = 1; i < roadArray.length; i++) {
            let nextPos = roadArray[i]
            let pointArr = this.getOneroad(nowPos, nextPos, 1)
            let speed = moveSpeed
            if (pointArr.length * moveSpeed > time) speed = (time / pointArr.length)
            // if (speed > moveSpeed) speed = moveSpeed
            pointArr.forEach(element => {
                tween.to(speed, { position: element })
            });
            tween.delay(delayTime)
            nowPos = nextPos;
        }
        tween
            .call(() => {
                cb && cb()
            })
            .start();
    }

    creatOneBuild(data, nowId) {
        let build = cc.instantiate(this.build);
        build.parent = this.root;
        build.position = cc.v3(data.pos);
        build.getChildByName("name").getComponent(cc.Label).string = data.name;
        build.active = true;
        build.getChildByName("light").active = nowId == data.id;
    }

    creatOnePoint(pos: cc.Vec3) {
        let build = cc.instantiate(this.point);
        build.parent = this.root;
        build.position = pos;
        build.active = true;
    }


    /**
     * 设置点
     * @param startPoint 起点
     * @param endPoint 终点
     * @param pointDistance 小点间距
     * @param angel 弧度
     */
    setPoint(startPoint, endPoint, pointDistance = 30, angel = 60) {
        let pointArr = this.getOneroad(startPoint, endPoint, pointDistance, angel)
        pointArr.forEach(element => {
            this.creatOnePoint(element)
            console.log(element);//每个小圆点点坐标,这里进行处理
        });
    }

    /**
     * 获取n点之间路径
     * @param startPoint 起点
     * @param endPoint 终点
     * @param pointDistance 小点间距
     * @param angel 弧度
     */
    getTotalRoad(arrList, pointDistance = 30, angel = 60) {
        let pointArrTotal = []
        let nowPos = pointArrTotal.shift()
        let list = arrList;
        while (1) {
            let nextPos = list.shift()
            if (nextPos) {
                let pointArr = this.getOneroad(nowPos, nextPos, pointDistance, angel)
                pointArrTotal = pointArrTotal.concat(pointArr)
                nowPos = nextPos;
            }
            else {
                break;
            }
        }
        return pointArrTotal
    }
    /**
     * 获取两点之间路径
     * @param startPoint 起点
     * @param endPoint 终点
     * @param pointDistance 小点间距
     * @param angel 弧度
     */
    getOneroad(startPoint, endPoint, pointDistance = 30, angel = 60) {
        startPoint = cc.v2(startPoint);
        endPoint = cc.v2(endPoint);
        let distance = startPoint.sub(endPoint).mag();
        let middlePoint = cc.v2((startPoint.x + endPoint.x) / 2, (startPoint.y + endPoint.y) / 2)
        let height = Math.sin(angel * (180 / Math.PI)) * (distance / 2) * 1.5;
        cc.log(height)
        let middlePoint2 = this.findPointCInRightTriangle(startPoint, middlePoint, height);
        let number = Number((distance / pointDistance).toFixed(0));
        let pointArr = this.getBezierPoints(number, startPoint, height ? middlePoint2 : middlePoint, endPoint)
        return pointArr;
    }

    /**
     * 获取两点之间垂直平分线线上的点
     * @param startPoint 
     * @param endPoint 
     * @param bcLength 
     * @returns 
     */
    findPointCInRightTriangle(startPoint: cc.Vec2, endPoint: cc.Vec2, bcLength: number, isUP = true): cc.Vec2 | null {
        let ax = endPoint.x;
        let ay = endPoint.y;
        let bx = startPoint.x;
        let by = startPoint.y;
        // 计算向量AB  
        const dx = bx - ax;
        const dy = by - ay;

        // 计算AB的长度  
        const abLength = Math.sqrt(dx * dx + dy * dy);

        // 检查AB长度是否为零,以避免除以零的错误  
        if (abLength === 0) {
            return null; // 无法确定C点位置,因为AB长度为0  
        }

        // 计算AC的长度(利用勾股定理)  
        const acLength = Math.sqrt(bcLength * bcLength - abLength * abLength);

        // 计算向量AB的单位向量  
        const abUnitX = dx / abLength;
        const abUnitY = dy / abLength;

        // 计算向量AC,它垂直于向量AB(因为ABC是直角三角形)  
        const acUnitX = -abUnitY; // 垂直向量的x分量是原向量y分量的相反数  
        const acUnitY = abUnitX;  // 垂直向量的y分量是原向量x分量  

        // 计算点C的坐标  
        const cx = ax + acLength * acUnitX * (isUP ? -1 : 1);
        const cy = ay + acLength * acUnitY * (isUP ? -1 : 1);

        return cc.v2(cx, cy);
    }
    /**
    * 获取贝塞尔曲线上的点
    * @param {返回的点的数组长度} num 
    * @param {起点} startPoint 
    * @param {控制点} middlePoint 
    * @param {终点} endPoint 
    */
    getBezierPoints(num, startPoint, middlePoint, endPoint) {
        let pointList = [];
        let x1 = startPoint.x, y1 = startPoint.y;
        let x2 = endPoint.x, y2 = endPoint.y;
        let cx = middlePoint.x, cy = middlePoint.y;
        let t = 0;
        for (let i = 1; i < (num + 1); i++) {
            //用i当作t,算出点坐标,放入数组
            t = i / num;
            let x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * cx + Math.pow(t, 2) * x2;
            let y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * cy + Math.pow(t, 2) * y2;
            pointList.push(cc.v2(x, y))
        }
        return pointList;
    }

    // update (dt) {}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1592000.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始编写一个cmake构建脚本

简介 本文档介绍cmake构建脚本编写&#xff0c;包含的一些主要元素和命名规范。 cmake构建脚本编写步骤 cmake构建工具版本要明确 # 命令名字要小写&#xff0c;这条语句要求构建工具至少需要版本为3.12或以上 cmake_minimum_required (VERSION 3.12)工程名及库的版本号明确…

spring boot学习第十七篇:OAuth2概述及使用GitHub登录第三方网站

0. 导言 我们在浏览器上可以访问成百上千个网站&#xff0c;使用每个网站的服务一般都要先注册账号&#xff0c;那么我们为了更好地记忆&#xff0c;一般都会在多个网站使用相同的账号和密码进行注册。那么问题就来了&#xff0c;如果在你注册的网站中有某些个网站的系统设计不…

C语言-----结构体详解

前面已经向大家介绍过一点结构体的知识了&#xff0c;这次我们再来深度了解一下结构体。结构体是能够方便表示一个物体具有多种属性的一种结构。物体的属性可以转换为结构体中的变量。 1.结构体类型的声明 1.1 结构体的声明 struct tag {member-list;//结构体成员变量 }vari…

VLC-Qt实现简单的视频播放器

VLC-Qt是一个结合了Qt应用程序和libVLC的免费开源库。它提供了用于媒体播放的核心类&#xff0c;以及用于快速开发媒体播放器的GUI类。由于集成了整个libVLC&#xff0c;VLC-Qt具备了libVLC的所有特性&#xff0c; 例如&#xff1a;libVLC实例和播放器、单个文件和列表播放、音…

海山数据库(He3DB)原理剖析:浅析Doris跨源分析能力

Doris湖仓分析背景&#xff1a; Doris多数据源功能演进 Doris的生态近年来围绕湖仓分析做了较多工作&#xff0c;Doris一直在积极拓宽大数据生态的OLAP分析市场&#xff0c;Doris2.0之后为了满足湖仓分析场景&#xff0c;围绕multi-catalog、数据缓存、容错、pipeline资源管理…

LibRadtran使用教程

LibRadtran使用教程 1.简介2.基本语法规则3.例子3.1 例子13.2 例子2 1.简介 关于LibRadtran的介绍以及安装可以参考另一篇博文&#xff1a;Windows系统LibRadtran安装。这里将针对LibRadtran的基础使用&#xff0c;以及基本语法进行介绍。 2.基本语法规则 uvspec < input…

【前端】layui table表格勾选事件,以及常见模块

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《前端》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 表格勾选事…

itop4412编译内核时garbage following instruction -- `dmb ish‘ 解决方案

王德法 没人指导的学习路上磕磕绊绊太耗费时间了 今天编译4412开发板源码时报 garbage following instruction – dmb ish’ 以下是解决方案&#xff1a; 1.更新编译器 sudo apt-get install gcc-arm-linux-gnueabi 更新后修改Makefile 中编译器路径如下图 2.你以为更新完就可…

OpenHarmony实例应用:【常用组件和容器低代码】

介绍 本篇Codelab是基于ArkTS语言的低代码开发方式实现的一个简单实例。具体实现功能如下&#xff1a; 创建一个低代码工程。通过拖拽的方式实现任务列表和任务信息界面的界面布局。在UI编辑界面实现数据动态渲染和事件的绑定。 最终实现效果如下&#xff1a; 相关概念 低代…

【Blockchain】连接智能合约与现实世界的桥梁Chainlink

去中心化预言机试图实现依赖因果关系而不是个人关系的去信任和确定性结果。它以与区块链网络相同的方式实现这些结果&#xff0c;即在许多网络参与者之间分配信任。通过利用许多不同的数据源并实施不受单个实体控制的预言机系统&#xff0c;去中心化的预言机网络有可能为智能合…

【Python习题】用turtle库直角三角形,底边长150,斜边长300,底角60度,线条粗6像素,线条颜色为蓝色,填充颜色为红色

完整题干&#xff1a; &#xff08;1&#xff09;从Python官网下载Python3.7安装包&#xff0c;安装并熟悉 Python IDLE编程环境。 &#xff08;2&#xff09;在 Python IDLE Shell 窗口中编写程序计算圆的周长。 &#xff08;3&#xff09;编写程序&#xff0c;绘制如图1.10…

Java基础第十一课——类与对象(2)

由于类与对象这一部分的知识点很多&#xff0c;而且操作方法也有很多&#xff0c;所以这次将继续深入讨论一下关于类与对象中方法传参、方法重载、构造方法以及this关键字使用方面的知识。 一、方法传参 1.return关键字 return关键字作用 作用场景&#xff1a;方法内 作用…

C语言 函数——函数封装与程序的健壮性

目录 函数封装&#xff08;Encapsulation&#xff09; 如何增强程序的健壮性&#xff1f; 如何保证不会传入负数实参&#xff1f; 函数设计的基本原则 函数封装&#xff08;Encapsulation&#xff09; 外界对函数的影响——仅限于入口参数 函数对外界的影响——仅限于一个…

降额的秘密——不要挑战datasheet!

原文来自微信公众号&#xff1a;工程师看海&#xff0c;与我联系&#xff1a;chunhou0820 看海原创视频教程&#xff1a;《运放秘籍》 大家好&#xff0c;我是工程师看海。 什么是降额设计&#xff1f;我们为什么要降额&#xff1f; 额指的是额定工作状态&#xff0c;降额就是…

数据结构——单链表(C语言版)

文章目录 一、链表的概念及结构二、单链表的实现SList.h链表的打印申请新的结点链表的尾插链表的头插链表的尾删链表的头删链表的查找在指定位置之前插入数据在指定位置之后插入数据删除pos结点删除pos之后的结点销毁链表 三、完整源代码SList.hSList.ctest.c 一、链表的概念及…

基于YOLOv5s的电动车入梯识别系统(数据集+权重+登录界面+GUI界面+mysql)

本文目录 1.UI界面 2.注册登录 3.算法准确率 4.数据集 1.UI界面 本人训练的yolov5s模型&#xff0c;准确率在98.6%左右&#xff0c;可准确完成电梯内检测电动车任务&#xff0c;并搭配了GUI检测界面&#xff0c;支持权重选择、图片检测、视频检测、摄像头检测、识别结果拍照…

喜报!成都爱尔眼科医院再次获得成都市医学科技三等奖!

2024年4月10日&#xff0c;“2024年全市医疗管理和科教服务工作暨培训会”在成都市血液中心召开。会议为期一天&#xff0c;落实2024年全国、全省医政管理工作会和全省、全市卫生健康工作会等相关会议精神&#xff0c;总结2023年全市医疗管理和科教服务工作情况&#xff0c;部署…

go语言基础 -- 反射

反射的基本介绍 反射可以在运行时动态获取变量的信息&#xff0c;如变量的类型&#xff08;type&#xff09;&#xff0c;类别(kind)。如果是结构体变量&#xff0c;还可以获取到变量的字段、方法等结构体本身信息&#xff1b;通过反射&#xff0c;可以修改变量的值或调用关联…

【蓝桥杯】第十五届填空题a.握手问题

题解&#xff1a; 根据问题描述&#xff0c;总共有 50 人参加会议&#xff0c;每个人除了与自己以外的其他所有人握手一次。但有 7 个人彼此之间没有进行握手&#xff0c;而与其他所有人都进行了握手。 首先&#xff0c;计算所有人进行握手的总次数&#xff1a; 总人数为 50 …

LabVIEW电信号傅里叶分解合成实验

LabVIEW电信号傅里叶分解合成实验 电信号的分析与处理在科研和工业领域中起着越来越重要的作用。系统以LabVIEW软件为基础&#xff0c;开发了一个集电信号的傅里叶分解、合成、频率响应及频谱分析功能于一体的虚拟仿真实验系统。系统不仅能够模拟实际电路实验箱的全部功能&…