尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Unity3d十字路口交通模拟实战:场景搭建、车辆控制与踩坑记录

Unity3d十字路口交通模拟实战:场景搭建、车辆控制与踩坑记录 1. 项目缘起与整体设计思路1.1 为什么选十字路口作为Unity3d模拟对象熟悉Unity3d开发的朋友应该都有这种体会上手之后最想做的不是那种单场景摆几个Cube的小Demo而是想做出一个有生命感的动态场景。车辆穿行、信号灯切换、行人与车流交织——这种动态本身就是游戏开发里最能训练基本功的素材。十字路口恰好是规则明确、元素适中、扩展性强的完美模拟对象。我从零开始做了一个Unity3d十字路口交通模拟项目目前完成的是第一版单向双车道十字路口、红绿灯自动切换、车辆自动排队与通行、行人在斑马线处等待。这套做下来大概花了一周业余时间核心逻辑不到800行C#但涉及的知识点非常全场景搭建、材质区分、动画状态机、协程计时、队列管理、碰撞检测。做一遍这个比单纯看十篇教程都值。这版内容适合什么水平的人参考我的建议是至少会用Unity3d基本界面、能自己摆场景、明白GameObject和Component的关系。如果你对C#只是刚接触代码部分也可以直接抄但每段我都写了注释花点时间读一下逻辑比复制粘贴收获大得多。1.2 技术选型从零搭建而不是用现成插件做交通模拟Unity Asset Store上其实有不少现成的交通系统插件有的做得还挺完整。但我坚持从零写原因很简单第一插件是黑盒。你在场景里拖一个节点设几个参数车就跑起来了但一旦需要改行为——比如某个方向的车在绿灯时右转需要让行直行车——你连从哪个脚本下手都不知道。自研的好处是每一行逻辑都在你手里哪里不对改哪里。第二优化可控。插件的车辆管理、路径计算经常是通用方案对移动端或中低端PC压力偏大。自研的车辆管理器可以针对当前场景量级做裁剪我的场景里同时活跃车辆控制在50辆以内用简单的队列管理比A*寻路轻太多。第三学习价值完全不同。我从做这个项目中学到的东西至少包括协程在计时场景的最佳实践、Collider触发检测和物理碰撞检测的取舍、材质渲染层级问题后面专门讲这个坑、处理外部导入模型时材质关联丢失的问题。这些经验是拖插件永远换不来的。技术栈方面用的是Unity3d 2021.3 LTS版本渲染管线用的内置管线Built-in Render Pipeline没有上URP。原因是内置管线的Shader兼容性最好各种第三方模型导进来不易出渲染异常而且这类模拟项目对画质要求并不高。如果你用的是Unity6或者2022以上版本内置管线依然保留可以放心跟着做。2. 场景搭建道路、路口与基础设施2.1 道路建模方案用贴图不用模型场景搭建的第一步是决定路怎么造。我试过两种方案大家可以直接抄结论方案A用3D建模软件Blender或3ds Max建好道路模型再导入Unity3d。优点是路面转角、弧度可控缺点是迭代慢改一次路宽要回建模软件重新导一次而且模型面数对场景性能有压力。方案B直接在Unity3d场景里用Plane拼路路面材质用贴图表现车道线。优点是改起来快用Prefab做道路段复制粘贴就行缺点是路口过渡区域需要手动处理。我最终选了方案B的变体主干道用Plane加贴图但把路口位置做成一个独立的路口Prefab用程序化的方式让四条路的网格在路口处切割对齐。这样路口区域看起来是完整的不像四块板子硬凑在一起。路面的尺寸规划是这样单条车道宽3.5米国内标准车道宽做出来视觉比例比较真实双向四车道加中间隔离带总宽16米。路口的四个方向各向外延伸40米足够容纳10辆左右的车排队。长度单位就用Unity3d默认的米物理碰撞和动画速度参数都不用额外换算。路面材质我单独处理了一下。网上找的公路贴图经常有方向性问题——贴图默认平铺方向让你看不出是沿路方向还是垂直方向。我的做法是把贴图导入后在材质面板把Tiling设成长度方向1、宽度方向4再配合Rotation旋转90度这样车道线方向就和道路行驶方向一致了。记不住哪个方向的话直接建一个测试路面看效果比脑补快。2.2 路口中心区域与斑马线的处理细节十字路口中心区域是最容易做出拼接感的地方。四条路的Plane在中心交叉处理不好会有明显的接缝或者重叠面。我用的方案是做一个单独的路口路面——大小刚好覆盖中心交叉区四个角切成45度斜角模拟真实路口的那种圆弧转弯角。路口本身不画车道线因为现实中路口中心就是干干净净的沥青路面。四个方向进路口的车道停止线位置在路面贴图里直接做出来或者用细长的Quad铺在路面上调整Y轴高度为0.01避免和路面Z-fighting。如果出现闪面把偏移量从0.01调到0.02基本都能解决。斑马线我用白色半透明材质的长条Quad排列而成。每条斑马线由8根白色条带组成条带尺寸0.5米宽、6米长间隔0.4米。在四个路口的八个人行横道位置两条路各两条都摆了。这里有个细节斑马线区域不能和道路的碰撞体冲突否则后面做行人检测时会出问题。我把斑马线Quad的Collider全部移除只保留视觉。行人等待区设置在斑马线两端的人行道上。人行道比路面高0.15米用路缘石Prefab围起来。等红绿灯的行人站在这个区域检测信号灯变量来决定是否过街。2.3 环境与辅助设施让场景有参照系路灯、树木、建筑这些不直接影响交通逻辑但能大幅提升场景的真实感和空间判断力。我在路口的四个角各放了一栋简模建筑用Cube和长方体拼的没有外部模型路两侧每隔20米放一个路灯模型——这个路灯是从Asset Store免费资源里找的低面数风格。说一个实用技巧环境物体一定要分层管理。我建了Environment空物体下面挂BuildingsStreetLightsTrees三个子物体。这样后面做光照烘焙或者性能优化时可以整层操作。另一个原因是这篇教程还有后续版本环境层如果和逻辑层混在一起改起来会非常痛苦。地面整体我加了一个大Plane铺上草地贴图Y轴在路面以下0.05米。这样路面的边缘不会因为悬空而在远处看穿帮。整体环境后来加了一盏平行光作为太阳光角度调成45度左右场景阴影效果最好。顺便把场景的Skybox从默认的灰色改成了淡蓝色渐变车身的反射效果会自然很多。3. 车辆模型与材质处理3.1 车辆模型的来源与选择车辆模型对最终观感影响最大但对代码逻辑影响最小。我一开始花了不少时间去找免费车辆模型后来发现完全没有必要把精力耗在这上面。两个够用的途径一是Unity3d Asset Store里的免费车辆包常见的主要有Simple Cars这类低多边形资源一辆车几百个面自动挡小轿车外形轮子独立出来方便做旋转动画。二是自己建模。如果会Blender用立方体拉一辆简模车其实不难——车身、车窗、轮子、车灯分几个材质就好。这样做的好处是车辆尺寸和比例完全自己掌控坏处是花时间。我用的方案是下载了一批免费低模车然后统一调整Prefab车身颜色随机换材质球的Metallic调高一点让车身有一点反光车玻璃用半透明材质。最后每辆车都加了Box Collider尺寸大致模拟真实车体1.8米宽、4.5米长、1.5米高这是车辆间碰撞检测的基础。3.2 材质透视问题的排查记录这里必须单独说一个让我查了两个晚上的渲染问题也是很多Unity3d开发都栽过的坑上层几何体透明导致下层穿帮也就是标题热搜词里提到的上层穿透看见下层。现象是这样的车辆的车窗用了半透明材质Transparent类型之后从某个角度看过去车内的座椅、方向盘直接穿透车身外板显示出来了。更诡异的是路过十字路口时停在另一条车道的车它的车窗居然把路面上的车道线显示出来了。原因不复杂Unity3d内置管线的渲染顺序是按物体距离相机的远近来排序的透明物体默认排在最后渲染。当一个透明材质和一个不透明材质在同一物体上车窗是透明的车身是不透明的透明部分会先画一遍所有不透明物体再画自己所以就出现了后面的东西透过透明面显示出来的视觉错误。解决方案有两个我都试过方案1把车窗材质改成Cutout类型镂空用一个贴图的Alpha通道做透明度。这样车窗是完全透明或完全不透明的二值化透明不参与透明队列就不会出现透视堆叠问题了。代价是车窗没有真实的玻璃折射效果看起来像贴纸。方案2用Render Queue控制。在材质面板把车窗的Custom Render Queue从Transparent3000改成Geometry2000之后的一个值比如2050。这样车窗FOV会在不透明物体渲染阶段处理并且排在普通几何体之后不再跟透明队列搅在一起。我最终选了方案2因为在车辆这个场景下玻璃既要有一定透明度透出车内装饰又不能让后面的交通参与者穿透显示。Custom Render Queue设为2050后这个效果刚好平衡。提醒一句如果你后续换到URP或HDRP管线这个队列值默认规则可能不一样URP中透明和不透明的处理方式也有差异如果换渲染管线需要重新测。3.3 外部模型导入Unity3d的注意事项做这个项目时我还尝试用SolidWorks导过几个红绿灯杆模型因为不少综艺和行业视频里确实有这种操作。SolidWorks建模精度高但模型导入Unity3d有几个固定的坑。SolidWorks导出的格式建议用STL或OBJ不要直接用SLDPRT。Unity3d并不原生支持STL需要先转换成OBJ或FBX。免费转换软件有很多我用的是Blender中转SolidWorks导出STLBlender导入再导出FBX。这样做的原因是Blender还能顺便修一下模型的面方向问题——SolidWorks的面有时候法线是反的Unity3d里显示出来就是黑色。模型导入Unity3d后Material和Texture会被打散。SolidWorks给模型的颜色不会自动变成Unity3d的材质你会看到模型整体是灰色的。解决方案是在Blender导出FBX时勾选嵌入纹理Embed Textures选项这样Blender里设置的颜色或贴图会跟随FBX一起进入Unity3d生成该模型的材质球。如果导出后还是一个空材质手动在Unity3d里给模型的Mesh Renderer重新赋材质即可。单位换算也要留意。Unity3d默认单位是米SolidWorks默认单位也是毫米如果在导入设置里没注意一个6米高的红绿灯杆会变成6000米高——直接小到看不见或大到场景都装不下。通常导入后选中模型Scale如果是100或0.01说明单位错了手动把Transform的Scale改成(0.01,0.01,0.01)或(100,100,100)来修正。3.4 车身动画与轮子旋转车辆动起来有两个层次的动画车身移动和轮子旋转。车身移动写在每辆车自己的控制器脚本里用Transform.Translate或者直接改position速度参数按实际车速换算1个单位/秒约等于3.6公里/小时。我的模拟场景里道路限速设为40公里/小时换算就是11.1米/秒。车辆在不同状态下的目标速度不同后面讲行为控制时会详细展开。轮子旋转是子物体级别的动画。我给每个轮子建了独立的子GameObject轴心设置在轮毂中心然后每帧根据车身速度旋转。旋转轴要看模型导入时的轴向——有的模型轮子的旋转轴是X轴有的是Z轴这个没法通用解决只能逐个试。偷懒的办法在Update里用transform.Rotate(Vector3.right, speed * Time.deltaTime * 30)如果方向反了改成Vector3.left即可。前轮转向车辆转弯时在第一版里没有精细做因为车辆在交叉路口转弯用的是路径点系统弧线路径是走一个圆心在路口中心的四分之一圆弧车身方向每次旋转一个角度。前轮视觉上的偏转如果强行加会跟路径曲线对不上反而显得假。这一版先不做前轮转向原因是车速较快过渡阶段轮子偏转幅度本来就不大观感可接受。4. 交通信号灯与车辆行为控制4.1 信号灯状态机与协程控制红绿灯是整个模拟的节拍器。我设计了一个简单的状态机四种状态绿灯直行、绿灯左转、黄灯、红灯。第一版简化掉左转向灯只保留绿灯、黄灯、红灯三种。状态切换用的协程Coroutine实现比Update里写倒计时要清爽得多public class TrafficLightController : MonoBehaviour { public LightObject redLight; public LightObject yellowLight; public LightObject greenLight; private float greenDuration 15f; private float yellowDuration 3f; void Start() { StartCoroutine(LightStateCycle()); } IEnumerator LightStateCycle() { while (true) { // 南北方向绿灯 SetNorthSouthGreen(); yield return new WaitForSeconds(greenDuration); // 南北方向黄灯 SetNorthSouthYellow(); yield return new WaitForSeconds(yellowDuration); // 南北方向红灯 SetNorthSouthRed(); // 东西方向绿灯 SetEastWestGreen(); yield return new WaitForSeconds(greenDuration); // 东西方向黄灯 SetEastWestYellow(); yield return new WaitForSeconds(yellowDuration); // 东西方向红灯 SetEastWestRed(); } } void SetNorthSouthGreen() { // 设置南北方向三色灯状态并同步东西方向为红灯 } }这里有个同步问题要说明东西方向和南北方向的灯是相反的——南北绿灯时东西必须是红灯。如果两个方向的控制器脚本各写各的很容易出现短暂的全绿状态那就会撞车。所以整个路口只需要一个TrafficLightController统筹所有灯用一个bool变量区分南北/东西相位不要搞四个独立的控制脚本。跨路口的同步用了Unity3d的GetComponentInChildren来访问同场景的其他灯。每个路口的灯我做了Prefab内部包含Red/Yellow/Green三个子物体每个子物体掛一个LightObject脚本里面放了灯亮时的自发光颜色和灯灭的颜色。切换状态时改材质球颜色即可不需要额外开点光源——自发光材质在场景里的视觉效果足够。这里有一个容易忽略的点灯切换时要同时更新对应的灯状态枚举供车辆查询。车辆不会直接判断视觉上的灯是亮是灭而是查这个枚举值。因为视觉状态和逻辑状态是同步改的但逻辑状态要优先保证实时性。我在TrafficLightController里维护了一个public LightPhase currentPhase车辆通过TrafficLightController.instance.currentPhase获取当前相位。4.2 车辆行为控制队列、避碰与通行逻辑车辆行为是模拟的核心。第一版里每辆车是一个独立的GameObject挂载VehicleController脚本但行为不完全是自发的——它受一个全局的VehicleManager管理。VehicleManager负责给每辆车分配目标路径并进行大致的空间规划。车辆的状态简单分五类Waiting排队等待、Approaching接近路口、Crossing正在通过路口、Leaving离开路口、Stopped永久停车或到达终点。排队逻辑用的是前车距离检测不是复杂的路径规划。每辆车在自己的Update里检查前方是否存在其他车辆检测方式是沿着车辆前进方向发射一条Raycast长度设为最小安全距离6米。如果射线命中另一辆车且目标车速度比自己慢就把自己的目标速度设为0原地等待如果前方车走了距离拉大再恢复起步。起步时候有个细节如果直接给车辆一个高速度车辆会瞬移般冲出去。真实的车辆起步有加速度第一版我加速度模型做成了恒定加速度目标速度加速度值设为3米/秒²大约和普通家用车起步差不多。每帧计算当前速度 上一帧速度 加速度 × 时间增量当速度达到目标速度后保持匀速。这里有很多人容易犯的一个错把Raycast的起点放在车辆中心点。因为车辆自己带了Collider射线从中心点发射会先命中自己的Collider导致永远检测到前方有车。正确做法是起点从车前保险杠位置局部坐标的(0,0,1)乘以车长的一半开始或者用Physics.Raycast时传入一个LayerMask把自己的层排除掉。我两种都试过推荐第一种——加一个空的射线发射点子物体在车头代码里直接引用这个子物体的世界坐标直观也不容易出错。4.3 路口通行权的判定设计车辆到达停止线时需要根据信号灯和前方路口的状况决定是否继续通行。这个通行权判定是整个模拟的灵魂。我分了两种路权优先级第一优先级信号灯。红灯时一律停车停在停止线前。停止线在场景中是一个细长的触发器Box车头碰撞到停止线Collider时检查当前相位是红灯还是绿灯。红灯则进入Waiting状态绿灯且前方路口无车则直接通过。第二优先级路口净空规则。虽然是绿灯但如果你前面的车已经堵在路口里了你不能跟着开进去——这是真实交规里的路口拥堵禁入原则。我用一个边界Collider罩住路口中心区域车辆进入该区域时如果检测到前方有车且速度为零就停在路口外等而不是把路口堵死。路口内部的路径点引导是这么做的每条进入路口的车道在进入处和驶出处各设一个路径点车辆通过路口时不是简单直线行驶而是按一个直行或转弯路径插值移动。第一版里直行车走直线右转车走四分之一圆弧。左转因为涉及对向车流互让第二版才做。右转路径的圆心在路口中心半径是车道中线的转弯半径。车辆转弯时角速度 线速度 / 半径用Quaternion.Slerp每帧旋转一个角度就出来了。注意转弯过程中要把车辆检测前方的逻辑暂时挂起否则射线检测会撞到路肩上或者别的方向的待转车导致右转车莫名其妙停下来。4.4 行人过街控制的简化实现第一版的行人逻辑做得比较简单但足够真实行人在斑马线两端的人行道上等待当对应的车流方向是红灯时行人开始沿斑马线走过街道。一个行人Prefab配一个simpleWalker脚本定义了等待状态和过街状态。行人的过街逻辑也涉及和车辆的冲突检测。为了减少第一版的复杂度我设定了一个行人专用相位在南北和东西方向都是红灯的间隙——按真实红绿灯设计来说其实不会出现这种状态但我模拟里特意加了3秒的全红时间也是真实交规里路口清空时间——行人利用这个全红间隙过街。这样行人和车辆不会在路口内互撞。如果你嫌全红时间等太久也可以让行人按本方向红灯时过街但那样会跟另一方向右转的车起冲突。第一版为了稳定优先采用全红时间过街方案简单直观观众看着也不违和。行人的动画分两帧循环站立和行走。Assets Store里免费的人物模型自带这两种动画片段我直接用了Animator Controller切状态。如果你下载的模型没有带动画也可以让行人保持滑步效果——直接把位置移动和旋转做了速度慢一点看不出来。5. 数据可视化与性能观察5.1 运行面板与实时数据输出做模拟项目不能只看画面热闹要能清楚知道每辆车在做什么、信号灯处于什么相位、当前场景的帧率如何。我在画面上加了简单的OnGUI面板实时显示几个关键指标当前相位绿灯/黄灯/红灯每条车道的车辆等待数量当前帧率FPS场景内活跃车辆总数帧率用Unity3d自带的Time.deltaTime计算每0.5秒刷新一次显示。车辆等待数量通过VehicleManager里的队列计数每辆车进入Waiting状态加一离开减一。用这个面板做调试的价值在于你能直接看到哪条路排队太长说明信号灯配时不合理或者该方向的车流量需要调高。5.2 性能优化的实际观察第一版场景里的对象数量不多60辆车的上限、20个行人、若干环境物在编辑模式下帧率大概120FPS生成Windows构建后稳定在300FPS以上。对这类模拟项目这个帧率已经远远够用。如果后续车辆数量翻倍到200辆以上要注意三个性能瓶颈一是Physics.Raycast的调用频率。每辆车每帧打一次向前射线检测200辆车就是每秒3000多次射线检测CPU开销会明显上升。可以考虑降频每辆车每隔3帧检测一次或者用Job System做并行射线检测。二是Material Property Block的使用。每辆车如果材质颜色不同直接修改Material.color会生成新的材质实例导致Draw Call增加。正确做法是用MaterialPropertyBlock设置颜色属性这样共享同一个材质但显示不同颜色。我的车辆Prefab里已经把车身材质从共享材质改成了PropertyBlock方式。三是LODLevel of Detail。远处的车辆不需要那么高的模型精度。简单做法是距离相机50米以上的车辆隐藏其车窗、内饰等细节子物体只保留外壳。我用了近距离检测每帧检查一次相机距离超过阈值就关闭子物体肉眼几乎感知不到区别但渲染负担小很多。6. 踩坑记录与问题排查实录6.1 常见问题速查表做这个项目过程中我把遇到的各类问题整理成了一张表每个都是实际验证过的新手可以直接当字典查问题现象可能原因解决办法车辆原地不动但状态不是WaitingRaycast起点在Collider内部检测到自身将射线起点放在车头子物体上或设置LayerMask排除自身层红绿灯同时出现全绿四个方向的灯各自独立计时用单一TrafficLightController统筹不要分别挂脚本车过路口时瞬间跳到对面路径点插值计算没加Time.deltaTime检查MoveTowards或Lerp是否缺失deltaTime参数车在停止线前反复起步停车停止线Collider触发点设置太靠近停车位置把触发区退后一个车位留出减速缓冲空间路面闪烁或出现黑色斑点Z-fighting路面和重叠面共面将上层路面Y轴提高0.01-0.02米车窗玻璃透视出路面或远处物体透明材质渲染队列问题将车窗材质的Custom Render Queue设为2050附近外部导入模型颜色全灰导入时材质丢失用Blender中转导出FBX勾选嵌入纹理选项行人站在斑马线上不动行人检测到了永远为真的障碍物确认斑马线区域和行人路径上没有隐藏的Collider6.2 排查车辆卡死问题的完整过程第一版调试阶段最恼人的bug之一偶尔会出现两辆车在路口中线附近对峙谁也不动。排查过程花了一整个下午。最初怀疑是射线检测误判但打印日志发现两辆车都已经在Crossing状态。那为什么会停在路口中间进一步看速度值发现两辆车都在AttemptToMove但速度始终为0。再查原来是每辆车都把自己的前方检测距离设成了6米而路口中心半径大约8米两辆车分别从南北方向进来后每一辆都检测到对方在自己前方6米内于是相互等待死锁。解决思路增加一个路口中心区域通行状态字段。VehicleManager维护一个bool值isCrossingOccupied任何车辆进入路口中心时置true驶出后置false。车辆在停止线前不仅要看信号灯还要检查这个字段如果为true就停在路口外等。只有当前车完全驶出路口、字段置false后后车才允许进入。这样就把任意两车在路口内对峙从根上杜绝了。这种死锁问题在模拟类项目里很典型值得记一笔永远不要在路口中心区域允许两辆来自不同方向的车同时商量让行一定要有一个全局仲裁者VehicleManager来拍板。6.3 协程遭遇GameObject销毁时的异常车辆到达终点后会被销毁Destroy但有些车辆的协程还在运行。协程在GameObject销毁后还会继续跑一帧直到Monobehaviour被自动禁用才会停。这会导致编辑器里出现Cancellation of coroutine failed的警告虽然不影响游戏运行但后面调试时会干扰视线。解决的规范做法车辆上挂的所有协程在OnDisable事件里全部StopAllCoroutines并在车辆进入回收逻辑之前显式调用StopAllCoroutines()再销毁。用对象池管理车辆的话这点尤其重要——对象池里的车即使不可见脚本仍然在运行协程不手动停会一直空跑。7. 实际操作记录从空白场景到第一个可运行版本7.1 分阶段开发计划执行记录我按以下几个阶段推进开发每个阶段都有明确完成标志这个拆分方式对新手很有参考价值第一阶段场景基建。搭建地面、道路、路口、停止线、斑马线完成标线贴图与材质设置。完成标志场景中能看清路网结构可以从空中俯瞰整个路口。第二阶段静态信号灯。搭好红绿灯模型完成三色切换的协程逻辑在场景中用Text显示当前相位。完成标志灯能自动切换手动切到任意相位都正确。第三阶段单方向车辆直行。先做一条车道的直行车从进入点生成匀速直线开到离开点后销毁。完成标志能看到一辆辆小车稳定排成一列从头走到尾。第四阶段多方向车辆与路口通行。加入四个方向的车流实现在停止线处检测信号灯、进入路口、通过路口、离开。完成标志四个方向的车流互不干扰信号灯切换时车辆正确响应。第五阶段行人系统。加入行人等待和全红时间过街。完成标志行人在绿灯时站在路边等待全红时有序通过斑马线。第六阶段性能打磨和细节完善。调整车辆间距、加速度参数、碰撞检测频率加入渲染队列修复、材质PropertyBlock优化。完成标志场景满负载运行下帧率至少60FPS。每个阶段我都在版本控制里打了Tag这样如果后面改崩了随时可以回退。开发Unity3d项目一定要养成这个习惯哪怕是自己一个人做——你永远不会知道下次打开工程时还能不能记得上次改了什么。7.2 关键参数配置清单红绿灯时长配置第一版数值参数数值说明南北绿灯时长15秒主干道流量较大的方向东西绿灯时长10秒支路方向减少通行时间黄灯时长3秒过渡提示全红时间3秒路口清空、行人过街窗口车辆运动参数参数数值说明直行限速11.1米/秒约40km/h路口内限速5米/秒约18km/h安全通过起步加速度3米/秒²模拟普通家用车动力制动减速度5米/秒²比加速略强够用最小安全距离6米排队时车间距停止线触发距离1米车头距停止线的停车位置这些参数都不是随手填的模拟效果好不好很大程度上取决于数值是否合理。比如车速和加速度如果加速度太大车辆起步像弹射太小排队的车半天提不起速度路口通行效率极低后面排队长度会异常。参数调整的一个实用原则每改一个参数必须从俯视视角完整跑五分钟观察是否有异常排队或车辆积压。7.3 第一版的实际运行效果评估完成第一版后我的评估结论是这个模拟已经能表现出路口交通的基本特征——周期性拥堵、队列形成与消散、信号灯控制下的间歇性放行。但从真实感角度还有明显不足左转车流缺失、车辆间变道行为缺失、行人过街过于机械。三个方向的改进优先级左转逻辑 行人行为丰富化 车辆随机变道。左转逻辑是第二版的主要内容核心问题是左转车和对向直行车之间谁让谁。真实交规里左转让直行这意味着左转车要等到对向直行车间歇足够大时才能起步。做这套逻辑时建议用状态机来管理左转车的决策过程比我在第一版里用的简单等待更加可控。如果你也想自己扩展这个项目我的建议是从车辆路径点系统下手。当前第一版的车流是固定路径模式——从A点出发到B点结束中途没有中途转弯。把路径系统升级成路网路点导航三层结构就能支持任意的转弯、变道、掉头行为。做交通模拟最终极的形态是一张完整的城市路网图每辆车都有起点和目的地自动规划路线——那基本就是一个简化版的自动驾驶仿真了。我个人做下来的体会是交通模拟的复杂度百分之八十不在怎么让车动起来而在怎么让一堆车在共享空间里不打架。单独一辆车的运动学很简单但加入交互之后规则的显式化程度直接决定了系统稳不稳定。如果你把谁先走、谁让谁、什么时候能进路口这些规则都写得明明白白车子们自然就跑得规规矩矩。如果想着差不多让它们自己判断吧那就会和我踩过的坑一样——路口中心出现两辆车面面相觑谁也不动交通瘫痪。所以写模拟系统最核心的功夫其实是在把规则清单列清楚代码只是对规则的忠实执行而已。
返回列表