unity3d 赛车游戏——复位点检测优化、反向检测、圈数检测、赛道长度计算

接着上一篇文章说

因为代码简短且思路简单

所以我就把这几个功能汇总为一篇文章

因为我之前就是做游戏外挂的

经过验证核实,**飞车的复位点检测、圈数检测就是以下的方法实现的

至于反向检测和赛道长度计算,没去深入研究,不过应该也八九不离十

在告诉大家个小秘密:

**飞车的复位点检测和圈数检测利用以下文章中的代码思路可以做出外挂

感兴趣的可以试试!我只是技术交流,不是传播外挂,别打我

复位点检测优化:

首先感谢 @太粗难进

他的原话:

“不过 你知道 高架桥么?
就是 如果大的轮船经过 会 把 桥 中间 分开。。。
飞车党 很多都喜欢 在这个断桥 中飞跃过去。

那么 如果有人掉下去了。。。
你的两个点会不会 是 桥的 两头,那么 最近的 地方 可不是路哦。
在空中。。。。”

这的确是个问题,写插件的时候没有考虑进去

但是还好,我想到一个补救的方法,且很简单

如上图,我添加了两个cube充当高架桥,中间有一个很大的空隙,赛车要从空中飞到第二块地面上

如果赛车在红色箭头所指的地方按下复位的话,按照上一篇的代码来实现赛车就会复位到空中(红色点的位置)

假设我们两个cube下方是长江,那就蛋疼了,一直重复复位,一直复位在空中。。。

还能愉快的玩耍吗,这是要迫使玩家卸载游戏的节奏呀

我的解决方法是在原有的复位方法中再加几句代码

当获取最近复位点后,从复位点位置向下发送一条射线

如果碰撞到的物体为地面,则重新计算地面与复位点的高度

这个地方有可能解释的有点迷糊,怕小伙伴们不清楚,我就在解释一下

赛车有小轿车和大货车,很明显,大货车是比小轿车要高的

比如大货车的高度是3米,坐标点是在车的中间

也就是说当一辆大货车接触地面时,地面与货车坐标点的距离是1.5米

如果我们的复位点小于1.5米,那么大货车就会和赛道重叠,然后就掉到地面底下了

当两个碰撞体重合的时候,是没有物理效果的

这样解释按100分计算不知道能不能打90分,哈哈,解释错的地方欢迎批评指正

所以为了避免这种情况发生,我们要重新计算地面与复位点的高度

接着上篇文章的代码,添加进新代码得出以下代码(#region 新添加)

代码不难,而且都有注释,我就不过多解释了,不懂的查手册

 1     /// 重置赛车 <summary>
 2     /// 重置赛车
 3     /// </summary>
 4     private void RecoverCar()
 5     {
 6         //获取距离最近的路标点
 7         WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position);
 8
 9         //下个路标点索引
10         int nextIndex = ClosestWP.Index + 1;
11
12         //最近路标点
13         Vector3 nearestPoint;
14
15         //下一个复位点索引 小于 路标点数量 - 1
16         if (nextIndex < WaypointsModelAll.Count - 1)
17         {
18             //获取两个路标点间离赛车最近的点
19             nearestPoint = NearestPoint(
20                 ClosestWP.Position,
21                 WaypointsModelAll[nextIndex].Position,
22                 transform.position);
23         }
24         else
25         {
26             //最后一个点和起点之间时取最后一个点的位置
27             nearestPoint = WaypointsModelAll[WaypointsModelAll.Count - 1].Position;
28         }
29
30
31         #region 新添加
32
33         RaycastHit[] hit;
34
35         //是否碰撞到地面
36         bool isColliderGround = false;
37
38         //向下发送射线
39         hit = Physics.RaycastAll(nearestPoint, ClosestWP.Rotation * -Vector3.up, 100f);
40
41         for (int i1 = 0; i1 < hit.Length; i1++)
42         {
43             //当碰撞到的物体为地面时
44             if (hit[i1].transform.tag == "Map_ground")
45             {
46                 isColliderGround = true;
47
48                 //计算当前路标点与地面之间的距离
49                 float temDis = Vector3.Distance(nearestPoint, hit[i1].point);
50
51                 //调整距离
52                 nearestPoint.y = nearestPoint.y - (temDis - 0.5f);
53
54                 //Debug.Log(temDis);
55
56                 //绘制高度线
57                 //Debug.DrawRay(WaypointsModelAll[i].Position, WaypointsModelAll[i].Rotation * -Vector3.up * temDis, Color.red);
58                 break;
59             }
60         }
61
62         //如果没有碰撞到地面
63         //则说明赛车下面没有地面,处于悬空状态
64         //取最近路标点为复位点
65         if (!isColliderGround)
66             nearestPoint = WaypointsModelAll[ClosestWP.Index].Position;
67
68         #endregion
69
70
71         transform.position = nearestPoint;
72         transform.rotation = Quaternion.LookRotation(ClosestWP.Rotation * Vector3.forward);
73         rigidbody.velocity = Vector3.zero;
74         rigidbody.angularVelocity = Vector3.zero;
75     }

反向检测:

介绍CarWaypoints插件的时候我有说到

就好比跑步比赛,人家都往前跑,你往后跑

就算你跑得再快,你也是最后一名,因为你跑反了

跑反不够逗比,逗比的是你跑反了还不知道

所以我们的赛车游戏需要一个反向检测,当逆向行驶时提示玩家

一开始写这个检测感觉应该挺复杂的,但是有了CarWaypoints插件变得好简单

我们选中一辆赛车,旋转Y角度,我们可以看见赛车对应着值旋转了

正确方向能不能是最近的Waypoint方向?

然后根据这个方向和赛车的方向计算得出是不是反向了?!

答案是完全可以!ok,现在看看代码

 1     /// 检测反向移动 <summary>
 2     /// 检测反向移动
 3     /// 思路如下:
 4     /// 通过Waypoint检测到离赛车最近的点
 5     /// 然后通过计算点的距离而得出是否反向
 6     /// </summary>
 7     private void isReverse()
 8     {
 9
10         WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position);//获取距离最近的路径点
11
12         //角度偏移 = 最近路径点的角度 - 赛车的角度
13         float angleOffset = ClosestWP.Rotation.eulerAngles.y - transform.eulerAngles.y;
14
15         /* 理论上来说
16          * 完全可以只写成 if(Mathf.Abs(angleOffset) >= 90f)
17          * 则判断为反向!但是实际运用时会出现问题
18          * 因为赛道是围成圈形的(首尾相连)
19          * 当赛车移动到下半圈的时候
20          * 明明是正确的方向,但是却提示反向了
21          * 所以为了避免这种情况发生,我们要用360-90=270
22          * 如果还是不理解的话debug路径点角度和赛车的角度就会发现端倪了*/
23 25         //角度偏移<=270f && 角度偏移>=90f && 刚体速度>8f
26         if (Mathf.Abs(angleOffset) <= 270f && Mathf.Abs(angleOffset) >= 90f)
27             Debug.Log("反向移动了:" + Mathf.Abs(angleOffset).ToString());
28     }

代码不多,我的注释挺多的!

先获取最近的路标点,然后根据获取最近路标点的角度 - 赛车角度 = 角度偏移

Mathf.Abs是取绝对值,如果我们对比绝对值的话,可以debug看一下这个角度偏移

运行游戏,直接复位赛车,让赛车保持正确方向

然后手动调整赛车的方向,观察角度偏移的变化

赛车面对着前方时:角度偏移大约为 0

赛车面对左方时:角度偏移大约为 -270(逐渐变大)

赛车面对右方时:角度偏移大约为-90(逐渐变小)

所以当我们得到角度偏移后,取绝对值对比是否<=270度且>=90度(理解一下正数和负数的变化,小学数学)

圈数检测:

做圈数检测我们绝对不能只在终点添加一个cube触发这么简单

因为如果只添加一个cube触发,那玩家倒车,在前进,就算一圈了

除非他是开挂可以做到这么屌爆了的功能

当然肯定会有人说,那我多添加几个cube不就行了吗?

你难道要手动添加一圈cube来触发?累不累啊

在我刚学u3d的时候我记得在游戏蛮牛看见过一个讲解关于赛车检测圈数的视频

他的方法就是在赛道上添加很多cube来触发检测圈数

这的确是一种方法,不过我是不推荐这种方法的,除非是某些特定的功能需要这样的方法

在这里我的方法依旧是使用CarWaypoints插件,轻松简单到爆

取最近路标点这个方法如果你看过前几篇文章不会陌生了吧?

将检测圈数的方法放在update中,赛车移动时他获取最近的路标点

然后将这个路标点储存在已经过路标点集合中

如果这个路标点已存在则不添加

在终点添加一个cube触发,触发时检测是否 已经过路标点集合数量 >= 最少经过路标点

如果成立则完成一圈,不成立就说明玩家在终点前(圈数起点)徘徊或者开挂

说这么多废话不如代码解释来得快,上代码:

 1     /// 检测路标点 <summary>
 2     /// 用来保存已通过的路标点
 3     /// 同样的路标点则不加入
 4     /// 冲过终点线时取数量
 5     /// 大于最少数量则算通过一圈
 6     /// </summary>
 7     private List<WaypointsModel> CheckPoints = new List<WaypointsModel>();
 8
 9     //完成圈数最少检查点
10     private int minCheckPoints = 35;
11     private int totalCircleNumber = 3;//总圈数
12     private int currentCircleNumber = 1;//当前圈数
13
14     /// 圈数检测 <summary>
15     /// 圈数检测
16     /// 思路如下:
17     /// 每一帧计算距离最近的检查点
18     /// 检查点存在则不添加,不存在则添加
19     /// 冲过终点线时取数量
20     /// 大于最少数量则算通过一圈
21     /// 然后清零 CheckPoints
22     /// </summary>
23     private void CircleNumberCheck()
24     {
25         WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position);//获取距离最近的路径点
26
27         //判断当前最近路标点是否已存在
28         for (int i = 0; i < CheckPoints.Count; i++)
29         {
30             //存在则返回
31             if (ClosestWP.Position == CheckPoints[i].Position)
32                 return;
33         }
34
35         //不存在则添加
36         CheckPoints.Add(ClosestWP);
37         //Debug.Log(ClosestWP.Index);
38     }

我们在代码中看见几个新变量,我在上文中没有提到

minCheckPoints:最小检查点数量

游戏赛道大多数都有近到,如果玩家抄近道的话,就会漏掉一些检查点

如果我一个游戏赛道的waypoints数量为40个

玩家抄近道后只能检测到35个检查点,那么检查点数量就应该设置为35

这个值是按具体情况填写的,可以先自己手动跑一局,debug出数量,然后在设置

还有两个变量不用解释了,计算圈数用的

接着是终点触发代码:

 1 void OnTriggerEnter(Collider Trigger)
 2     {
 3         //检查点数量大于最小检查点数量则算一圈
 4         if (minCheckPoints <= CheckPoints.Count)
 5         {
 6             currentCircleNumber++;
 7
 8             if (currentCircleNumber > totalCircleNumber)
 9             {
10                 Debug.Log("游戏完成");
11                 return;
12             }
13
14             Debug.Log("当前圈数:" + currentCircleNumber.ToString());
15
16             //清空检测点
17             CheckPoints.Clear();
18         }
19     }

记得触发cube勾选isTrigger

如果是计圈赛道,那么完成一圈就清空一次检测点

这样的话就可以计算新的一圈检测点了

赛道长度计算:

这个就太简单了,不多余解释,直接上代码:

 1     /// 计算赛道长度 <summary>
 2     /// 计算赛道长度
 3     /// </summary>
 4     /// <returns>返回赛道长度</returns>
 5     private float CalcTotalDis()
 6     {
 7         //把所有点和点的距离相加而得出
 8
 9         float temTotalDis = 0f;//临时总距离
10         for (int i = 0; i < WaypointsModelAll.Count; i++)
11         {
12             if (i >= WaypointsModelAll.Count - 1)
13             { temTotalDis += Vector3.Distance(WaypointsModelAll[i].Position, WaypointsModelAll[0].Position); }
14             else
15             { temTotalDis += Vector3.Distance(WaypointsModelAll[i].Position, WaypointsModelAll[i + 1].Position); }
16         }
17
18         return temTotalDis;
19     }

完整demo下载地址:http://pan.baidu.com/s/1i3ziILB

CarWaypoints插件使用介绍:http://www.cnblogs.com/shenggege/p/4295616.html

文中不足之处欢迎批评指正,如果本文对你有帮助请点一下右下角的推荐

本文链接:http://www.cnblogs.com/shenggege/p/4295986.html

时间: 2024-10-20 04:04:30

unity3d 赛车游戏——复位点检测优化、反向检测、圈数检测、赛道长度计算的相关文章

unity3d 赛车游戏——复位点检测

一直没有时间写博客 昨天我的CarWaypoints插件也告一段落了 今年没回家,过年就我一个人 挺无聊的,那就休息一天写几篇博客吧 我的代码可能很少,但是思路很重要 希望不懂的朋友别只copy代码 赛车游戏的话赛车难免会冲出跑道.掉入水坑.卡在障碍物上....等情况 那么问题来了,遇到这些情况怎么办呢? 玩家玩得好好的,难道就因为遇到这些情况要退出游戏重新进入吗? 那当然是不现实的,要是我的话果断卸载游戏 还要骂一句做游戏的人是脑残啊 我想你不希望玩家骂你是脑残吧,哈哈哈 新技能,赶快GET起

使用Unity3D 自主实战开发的赛车游戏实例,关键点记录 (六)之自动寻路及优化

一.综述 赛车游戏的敌人赛车自动寻路一般有两种方式,一种是路点寻路,另外一种就是使用Unity自带组件NavMeshAgent进行寻路了,我介绍的是后者,另外后者在水平面上的汽车寻路导航还不错,但是一旦有Y方向的爬坡.下坡等,汽车就会因为角度依然保持水平显得很不自然,并且轮胎也不会旋转,我对此进行了优化 二.NavMeshAgent 这个和NavMesh是一对,用来设置寻路的游戏对象.关于属性,我不再一一介绍,我就距我的设置来说一下: 1.AgentSize 如下图中,那个圆柱形就是NavMes

使用Unity3D的设计思想实现一个简单的C#赛车游戏场景

最近看了看一个C#游戏开发的公开课,在该公开课中使用面向对象思想与Unity3D游戏开发思想结合的方式,对一个简单的赛车游戏场景进行了实现.原本在C#中很方便地就可以完成的一个小场景,使用Unity3D的设计思想(即一切游戏对象皆空对象,拖拽组件才使其具有了活力)来实现却需要花费大量时间与精力,究竟它神奇在什么地方?本文通过实现这个小例子来看看. 一.空对象与组件 在Unity3D最常见的就是GameObject,而一个GameObject被实例化后确啥特性与行为都没有,只有当我们往其中拖拽了一

Unity3d插件SmoothMoves加载速度优化

我们游戏是使用Unity3d做的2D游戏,角色特效等都使用SmoothMoves来制作(在国内估计也算奇葩一朵吧,据说燃烧的蔬菜也是SmoothMoves作的),游戏中的所有的资源--角色.特效.技能ICON.角色ICON.音效等几乎都使用assetbundles来实现. 问题:加载一场战斗的时间大概要30s左右!!! 解决方案关键字:依赖打包.数据块共享.冗余数据剔除 优化后:5s左右 :) 1. 依赖打包 1.1 使用AssetDatabase.GetDependencies()接口可以查看

《Unity3D/2D游戏开发从0到1》正式出版发行啦

书籍信息:   书籍的名称: <Unity3D/2D 游戏开发从0到1>   书号(ISBN): 978-7-121-26239-5    出版社: 电子工业出版社   发行时间:2015年7月1日 写作背景:    2015年6月30日我收到电子工业出版社张迪老师寄来,正式发行的<Unity3D/2D游戏开发从0到1>书籍.这本凝结着大半年心血的作品让我感慨万千.   本人从事游戏.软件与教学十多年,一直梦想可以进一步服务于全国广大的游戏与软件从业开发人员.14年下半年电子工业出

《Unity3D/2D游戏开发从0到1》正式出版发行

去年个人编写的Unity书籍正式在2015年7月正式发行,现在补充介绍一下个人著作.书籍信息: 书籍的名称: <Unity3D/2D 游戏开发从0到1> 书号(ISBN): 978-7-121-26239-5 出版社: 电子工业出版社 发行时间:2015年7月1日 写作背景: 2015年6月30日我收到电子工业出版社张迪老师寄来,正式发行的<Unity3D/2D游戏开发从0到1>书籍.这本凝结着大半年心血的作品让我感慨万千. 本人从事游戏.软件与教学十多年,一直梦想可以进一步服务于

Unity3D ARPG游戏开发《最初的幻想》之第一张地图与跳跃的改善详解

前面我们终于实现了人物动画.相机控制及昼夜系统,现在继续吧,为了方便继续编写的敌人之类的脚本,所以打算今天先把第一张地图画个大概.结果,画了我好久的地图….. ≡(▔﹏▔)≡ 我对美术方面的天赋简直是惨不忍睹了…..加之地图中途画的差不多的时候Unity又崩溃了一次….忘了保存(ㄒoㄒ).于是又忙活半天….这个地图完全靠临时发挥了,第一张地图我画了好几次了,基本上每次画出来的地形之类的都完全不一样,所以就不多解释了,就上一张大概的场景图吧: 看起来好简单吧?唉……开启编辑器,这时侯如果在场景中转

Unity3D/2D游戏开发从0到1

这篇是计算机中Oracle类的优质预售推荐>>>><Unity3D/2D游戏开发从0到1> Unity3D/2D游戏开发从0到1(含DVD光盘1张) 采用 "案例化"教学思路, 以个人长期线下培训讲义为蓝本:讲解透彻.循序渐进.突出与优化游戏开发实战技巧:附有全国Unity游戏研发职位笔试面试真题集锦.Unity开发常见错误与分析.游戏开发职位简历模板 编辑推荐 按照"案例化"教学特点,全书贯穿两个重量级游戏的开发全过程讲解,让学

Unity3d程序方面的细节及优化

关于Unity3d程序方面的细节及优化 (基于移动开发) 1.每次创建的脚本对于用不到的Start(),.Update()函数都可以删除掉,尤其后者,即使什么都不做也会在更新. 2.不要做复杂的数学运算,比如开方运算Mathf.Sqrt()等,当我们求两个对象的距离的时候,可以直接自己计算求开方根上一级的运算.求三角函数也算复杂运算. 3.如果使用的Mono编辑器,在注释的时候,尽量采用英文注释(防止中文乱码) 4.Unity的每个component都在更新,脚本也算组件,所以一个对象不同的脚本