3D动态路障生成

3D动态路障生成

  • 介绍
  • 设计实现
    • 1.路面创建
    • 2.空物体的创建
    • 3.Create.cs脚本创建
  • 总结

介绍

上一篇文章介绍了Mathf.Lerp的底层实现原理,这里介绍一下跑酷类游戏的动态路障生成是如何实现的。
动态路障其实比较好生成,但是难点在哪里,如果都是平面或者都是没有转弯的话还是比较好实现的,如果动态路障的实现遇到了有上坡下坡或者有转弯的地方我们如何去处理这些拐角点和上下坡的旋转和位置呢?

设计实现

简单说一下设计思路
路面的终点为坐标的原点(0,0,0),把我们的路面朝向Z轴的方向,也就是说我们生成路障时,只需要采用Z轴的深度即可。
我们在终点到起点之间创建多个空物体,这个空物体用于判断创建的路障在哪两个空物体之间,然后采用Lerp来进行插值运算,使我们在拐角处和有坡度的位置生成正确旋转与位置的路障。
生成路障时,自定义参数距离范围随机生成路障,那么它的旋转角度和高度我们可以用上述两个空物体差值运算得到。

1.路面创建

下面是我简单的用Plane拼接出来的路面终点的位置为Unity的(0,0,0)
这里我全成长度为300,也就是说图中的起点位置为(x,x,-300)
在这里插入图片描述

2.空物体的创建

在Road路面里面创建一个waypoints的空物体,将我们后面创建的空物体都放在里面,
我们可以在整个路面上创建无数个空物体,但是空物体的Z轴旋转和Y轴的高度是要跟路面保持一致的,因为我们后面要用这个空物体的position和rotation来进行插值运算得到路障的位置和旋转角度,这里空物体创建的越多,路障贴合路面的坡度和旋转就更加精准。最后创建一个Waypoints的脚本挂载到waypoints上去获取我们所有创建的空物体,可以用OnDrawGizmos()去绘制出来方便我们看。

创建的位置如下
在这里插入图片描述
这里可以看到我把每一个点的Z轴旋转角度都贴合了路面

脚本如下:

[ExecuteInEditMode]
	public class waypoints : MonoBehaviour {

    	public Transform[] points;
    	void OnDrawGizmos()
    	{
        	for (int i = 0; i < points.Length; i++)
        	{
            	Gizmos.color = Color.red;
            	Gizmos.DrawWireSphere(points[i].transform.position, 5);
        	}
    	}
	}

3.Create.cs脚本创建

using System.Collections;
	using System.Collections.Generic;
	using UnityEngine;

	public class Create : MonoBehaviour {

    /// <summary>
    /// 路障物体数组
    /// </summary>
    public GameObject[] obstacles;

    /// <summary>
    /// 路障在道路上出现的开始位置
    /// </summary>
    public float startLength = 10;

    /// <summary>
    /// 路障距上一个路障的最小距离  
    /// </summary>
    public float minLength = 10;

    /// <summary>
    /// 路障距上一个路障的最大距离  
    /// </summary>
    public float maxLength = 20;

    /// <summary>
    /// 与路面相贴合的路线上的脚本组件  
    /// </summary>
    private waypoints wayPoints;

    void Awake()
    {
        wayPoints = GameObject.Find("waypoints").GetComponent<waypoints>(); 
    }

    // Use this for initialization  
    void Start()
    {
        //创建路障
        GenerateObstacle(); 
    }

    /// <summary>
    /// 创建路障
    /// </summary>
    void GenerateObstacle()
    {
        //当前道路在场景中的起始Z坐标  
        float startZ = transform.position.z - 300;

        //当前道路在场景中的结束Z坐标  
        float endZ = transform.position.z;
        
        //将要产生路障的Z坐标
        float z = startZ + startLength;
        
        while (true)
        {
            //每隔多少米的距离产生一个路障  
            z += Random.Range(minLength, maxLength);

            //如果将要产生路障的位置超出了这条道路则退出路障产生循环,否则产生路障 
            if (z > endZ)                            
            {
                break;
            }
            else
            {
                //方法计算路障位置坐标
                Vector3 position = GetWayPos(z);
                //方法计算路障旋转坐标
                Vector3 rotation = GetWayRotate(z);
                //产生一个从路障数组里取路障的随机序数  
                int obsIndex = Random.Range(0, obstacles.Length);
                //实例化路障 
                Instantiate(obstacles[obsIndex], position, Quaternion.Euler(rotation.x, rotation.y, rotation.z)); 
            }
        }
    }

    /// <summary>
    /// 获取转折点的集合索引值
    /// </summary>
    /// <param name="z"></param>
    /// <returns></returns>
    int GetPointIndex(float z)
    {
        //在道路上设置的转折点的集合  
        Transform[] points = wayPoints.points;
        //转折点在集合中的序数号  
        int index = 0;

        for (int i = 0; i < points.Length - 1; i++)
        {
            //根据要插入路障的Z值在集合中寻找在哪两个点之间,找到后记下序数号  
            if (z >= points[i].position.z && z <= points[i + 1].position.z)
            {
                index = i;
                break;
            }
        }
        return index;
    }

    Vector3 GetWayPos(float z)
    {
        int index = GetPointIndex(z);
        //使用Lerp函数计算出插入路障处的空间坐标值  
        return Vector3.Lerp(wayPoints.points[index + 1].position, wayPoints.points[index].position, (z - wayPoints.points[index + 1].position.z) / (wayPoints.points[index].position.z - wayPoints.points[index + 1].position.z));
    }

    Vector3 GetWayRotate(float z)
    {
        int index = GetPointIndex(z);
        return Vector3.Lerp(wayPoints.points[index + 1].eulerAngles, wayPoints.points[index].eulerAngles, (z - wayPoints.points[index + 1].position.z) / (wayPoints.points[index].position.z - wayPoints.points[index + 1].position.z));
    }
    }

创建完成结果如下:
在这里插入图片描述

总结

本片文章主要讲解Mathf.Lerp()的用法,如果有不明白的可以看我上一篇文章

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RHCE9学习指南 第11章 网络配置

11.1 网络基础知识 一台主机需要配置必要的网络信息&#xff0c;才可以连接到互联网。需要的配置网络信息包括IP&#xff0c;子网掩码&#xff0c;网关和DNS。 11.1.1 IP地址 在计算机中对IP的标记使用的是32bit的二进制&#xff0c;例如&#xff0c; 11000000 10101000 00…

基于梯度和频率域的深度超分辨率新方法笔记二

一、实现方法和网络结构的剖析 1.1 网络结构 梯度校准模块(GCM)和频率感知模块&#xff08;FAM&#xff09; 1&#xff09;梯度校准模块(GCM) 1、使用梯度映射函数&#xff08;如下图所示&#xff09;&#xff0c;将RGB和LR深度图映射到梯度域 2、再梯度域中使用RGB的梯度特…

【 C语言 】 | C程序百例

【 C语言 】 | C程序百例 时间&#xff1a;2023年12月28日13:50:43 文章目录 【 C语言 】 | C程序百例1.参考2.练习 1.参考 1.【 C语言 】 | C程序百例-CSDN博客 2.100Example: C程序百例-酷勤网&#xff08;kuqin.com&#xff09;提供.pdf (gitee.com) 3.cProgram/LinuxC - 码…

IPD-PDP产品开发流程-PDT产品开发计划Charter文档模板(word)2

书接上回&#xff0c;继续为大家分享PDT的产品开发计划Charter模板的主要内容。 据华研荟了解&#xff0c;大部分国内的企业在推行IPD的时候就直接像华为一样&#xff0c;把开发计划&#xff08;任务书&#xff09;叫做Charter&#xff0c;而不翻译为中文。其实这也是一种很好…

高校怎么搭建虚拟数字人动作捕捉实训室?

如今&#xff0c;虚拟数字人市场迎来爆发风口&#xff0c;在产业推动下&#xff0c;虚拟数字人动作捕捉技术人才需求旺盛&#xff0c;高校搭建虚拟数字人动作捕捉实训室&#xff0c;可以让学生接触前沿的全身动作捕捉系统&#xff0c;能够培养具有开阔眼界和先进技术接轨的专业…

鸿蒙系列--组件介绍之其他基础组件(上)

上回介绍了基础组件中最常用的组件常用的基础组件&#xff0c;接下来还有其他基础组件 一、Blank 描述&#xff1a;空白填充组件 功能&#xff1a;在容器主轴方向上&#xff0c;具有自动填充容器空余部分的能力。只有当父组件为Row/Column时生效 子组件&#xff1a;无 Blan…

羊大师讲解,羊奶在本草纲目中的作用及其益处

羊大师讲解&#xff0c;羊奶在本草纲目中的作用及其益处 羊奶是一种传统的中药材&#xff0c;早在《本草纲目》中就被广泛记录和应用。它是从母羊妊娠后分泌出来的乳汁&#xff0c;具有丰富的营养成分和独特的药用价值。小编羊大师发现&#xff0c;羊奶被认为是一种滋补养颜、…

3D 渲染如何帮助电商促进销售?

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 3D 渲染图像因其高转化率而成为亚马逊卖家的最新趋势。它是电子商务平…

Linux iptables防火墙(一)

1.1 Linux防火墙基础 在 Internet 中&#xff0c;企业通过架设各种应用系统来为用户提供各种网络服务&#xff0c;如 Web 网站、 电子邮件系统、 FTP 服务器、数据库系统等。那么&#xff0c;如何来保护这些服务器&#xff0c;过滤企业不 需要的访问甚至是恶意的入侵呢&a…

作为开发人员掌握 GitHub Copilot:15 个提示和技巧

目录 Copilot 的炫酷用例 为您完成代码 从代码编写测试 TDD&#xff1a;通过测试编写代码 测试/模拟数据生成 从注释中编写代码 问&#xff1a;&答&#xff1a; 颜色生成 使用测量单位 自然语言翻译 自动化脚本 正则表达式 配置 命令行命令 文档和自述文本 if (true) 技巧 …

QT与MATLAB混合编程详解

写在前面&#xff1a;由于matlab和qt的环境配置复杂&#xff0c;请大家一定先根据自己电脑的路径来替换本文中的路径 本文使用环境&#xff1a; MATLAB 2022b qt 6.6 编译环境&#xff1a;MSVC2019 64位 matlab的环境还需要配置在环境变量中 此电脑&#xff08;右键&#xf…

Docker 实践之旅:项目迁移与高效部署

目录 1 引言2 初识 Docker2.1 Docker简介2.2 Docker优势 3 传统部署流程的问题4 学习 Docker 的过程5 Docker 解决项目部署的实践5.1 迁移关键服务5.2 定制化打包与快速部署 6 项目实践收获6.1 简化了部署流程6.2 节约了部署成本 7 克服难点和经验分享7.1 版本兼容性问题7.2 网…

Android Studio修改创建新布局时默认根布局

将Android Studio默认布局ConstraintLayout切换成LinearLayout 打开设置&#xff0c; Editor> File and Code Templates > Other > layoutResourceFile.xml 备注&#xff1a;创建时提示根布局仍然为ConstraintLayout&#xff0c;不用管这个&#xff0c;实际创建的…

MybatisX逆向工程方法

官方文档链接&#xff1a;MybatisX快速开发插件 | MyBatis-Plus (baomidou.com) 使用MybatisX可以快速生成mapper文件&#xff0c;实体类和service及实现 效果 方法&#xff1a;首先下载mybatisX插件 然后创建数据库信息 然后选中表&#xff0c;右键&#xff0c;点击Mybatis…

WeakMap 和 Map 的区别,WeakMap 原理,为什么能被 GC?

垃圾回收机制 我们知道&#xff0c;程序运行中会有一些垃圾数据不再使用&#xff0c;需要及时释放出去&#xff0c;如果我们没有及时释放&#xff0c;这就是内存泄露 JS 中的垃圾数据都是由垃圾回收&#xff08;Garbage Collection&#xff0c;缩写为 GC&#xff09;器自动回…

JMeter逻辑控制器之While控制器

JMeter逻辑控制器之While控制器 1. 背景2.目的3. 介绍4.While示例4.1 添加While控制器4.2 While控制器面板4.3 While控制器添加请求4.3 While控制器应用场景 1. 背景 存在一些使用场景&#xff0c;比如&#xff1a;某个请求必须等待上一个请求正确响应后才能开始执行。或者&…

Springboot整合JSP-修订版本(Springboot3.1.6+IDEA2022版本)

1、问题概述&#xff1f; Springboot对Thymeleaf支持的要更好一些&#xff0c;Springboot内嵌的Tomcat默认是没有JSP引擎&#xff0c;不支持直接使用JSP模板引擎。这个时候我们需要自己配置使用。 2、Springboot整合使用JSP过程 现在很多的IDEA版本即使创建的项目类型是WAR工…

页面左中右下布局HTML

效果如下 代码如下 <!DOCTYPE html> <html><head><title>名曲欣赏</title><meta charset"UTF-8" /><style>body {padding: 0;margin: 0;background: linear-gradient(180deg, #d7f5f2 0%, #c4f2ee 100%);}p {margin: 0;p…

学生使用什么牌子的护眼灯好?五款优秀台灯分享

在近几年&#xff0c;儿童青少年近视率非常高。很多家长认为孩子近视的原因是没有养成正确的用眼习惯&#xff0c;例如经常趴桌子写作业、眯眼看书等&#xff0c;但实际上这些坏习惯是因为没有合适的光线而导致的。所以安排一盏合适的台灯给孩子学习是非常重要的。 很多家长会选…

基于C++的类Unix文件系统

这是一个基于C的类Unix文件系统&#xff0c;有意者私信获取。 可用指令如下&#xff1a; ls - 显示当前文件夹下的内容 cd - 按照路径进入到某个文件夹下 mkdir <path/name> - 在指定路径下创建一个文件夹 create <path/name> - 在指定路径下创建一个文件 open &…