unity3d 赛车游戏——复位点检测优化、反向检测、圈数检测、赛道长度计算
接着上一篇文章说
因为代码简短且思路简单
所以我就把这几个功能汇总为一篇文章
因为我之前就是做游戏外挂的
经过验证核实,**飞车的复位点检测、圈数检测就是以下的方法实现的
至于反向检测和赛道长度计算,没去深入研究,不过应该也八九不离十
在告诉大家个小秘密:
**飞车的复位点检测和圈数检测利用以下文章中的代码思路可以做出外挂
感兴趣的可以试试!我只是技术交流,不是传播外挂,别打我
复位点检测优化:
首先感谢 @太粗难进
他的原话:
就是 如果大的轮船经过 会 把 桥 中间 分开。。。
飞车党 很多都喜欢 在这个断桥 中飞跃过去。
那么 如果有人掉下去了。。。
你的两个点会不会 是 桥的 两头,那么 最近的 地方 可不是路哦。
在空中。。。。”

如上图,我添加了两个cube充当高架桥,中间有一个很大的空隙,赛车要从空中飞到第二块地面上
如果赛车在红色箭头所指的地方按下复位的话,按照上一篇的代码来实现赛车就会复位到空中(红色点的位置)
假设我们两个cube下方是长江,那就蛋疼了,一直重复复位,一直复位在空中。。。
还能愉快的玩耍吗,这是要迫使玩家卸载游戏的节奏呀
我的解决方法是在原有的复位方法中再加几句代码
当获取最近复位点后,从复位点位置向下发送一条射线
如果碰撞到的物体为地面,则重新计算地面与复位点的高度
这个地方有可能解释的有点迷糊,怕小伙伴们不清楚,我就在解释一下
赛车有小轿车和大货车,很明显,大货车是比小轿车要高的
比如大货车的高度是3米,坐标点是在车的中间
也就是说当一辆大货车接触地面时,地面与货车坐标点的距离是1.5米
如果我们的复位点小于1.5米,那么大货车就会和赛道重叠,然后就掉到地面底下了
当两个碰撞体重合的时候,是没有物理效果的
这样解释按100分计算不知道能不能打90分,哈哈,解释错的地方欢迎批评指正
所以为了避免这种情况发生,我们要重新计算地面与复位点的高度
接着上篇文章的代码,添加进新代码得出以下代码(#region 新添加)
代码不难,而且都有注释,我就不过多解释了,不懂的查手册
/// 重置赛车 <summary>
/// 重置赛车
/// </summary>
private void RecoverCar()
{
//获取距离最近的路标点
WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position);
//下个路标点索引
;
//最近路标点
Vector3 nearestPoint;
//下一个复位点索引 小于 路标点数量 - 1
)
{
//获取两个路标点间离赛车最近的点
nearestPoint = NearestPoint(
ClosestWP.Position,
WaypointsModelAll[nextIndex].Position,
transform.position);
}
else
{
//最后一个点和起点之间时取最后一个点的位置
nearestPoint = WaypointsModelAll[WaypointsModelAll.Count - ].Position;
}
#region 新添加
RaycastHit[] hit;
//是否碰撞到地面
bool isColliderGround = false;
//向下发送射线
hit = Physics.RaycastAll(nearestPoint, ClosestWP.Rotation * -Vector3.up, 100f);
; i1 < hit.Length; i1++)
{
//当碰撞到的物体为地面时
if (hit[i1].transform.tag == "Map_ground")
{
isColliderGround = true;
//计算当前路标点与地面之间的距离
float temDis = Vector3.Distance(nearestPoint, hit[i1].point);
//调整距离
nearestPoint.y = nearestPoint.y - (temDis - 0.5f);
//Debug.Log(temDis);
//绘制高度线
//Debug.DrawRay(WaypointsModelAll[i].Position, WaypointsModelAll[i].Rotation * -Vector3.up * temDis, Color.red);
break;
}
}
//如果没有碰撞到地面
//则说明赛车下面没有地面,处于悬空状态
//取最近路标点为复位点
if (!isColliderGround)
nearestPoint = WaypointsModelAll[ClosestWP.Index].Position;
#endregion
transform.position = nearestPoint;
transform.rotation = Quaternion.LookRotation(ClosestWP.Rotation * Vector3.forward);
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
}
反向检测:
介绍CarWaypoints插件的时候我有说到
就好比跑步比赛,人家都往前跑,你往后跑
就算你跑得再快,你也是最后一名,因为你跑反了
跑反不够逗比,逗比的是你跑反了还不知道
所以我们的赛车游戏需要一个反向检测,当逆向行驶时提示玩家
一开始写这个检测感觉应该挺复杂的,但是有了CarWaypoints插件变得好简单
我们选中一辆赛车,旋转Y角度,我们可以看见赛车对应着值旋转了
正确方向能不能是最近的Waypoint方向?
然后根据这个方向和赛车的方向计算得出是不是反向了?!
答案是完全可以!ok,现在看看代码
/// 检测反向移动 <summary>
/// 检测反向移动
/// 思路如下:
/// 通过Waypoint检测到离赛车最近的点
/// 然后通过计算点的距离而得出是否反向
/// </summary>
private void isReverse()
{
WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position);//获取距离最近的路径点
//角度偏移 = 最近路径点的角度 - 赛车的角度
float angleOffset = ClosestWP.Rotation.eulerAngles.y - transform.eulerAngles.y;
/* 理论上来说
* 完全可以只写成 if(Mathf.Abs(angleOffset) >= 90f)
* 则判断为反向!但是实际运用时会出现问题
* 因为赛道是围成圈形的(首尾相连)
* 当赛车移动到下半圈的时候
* 明明是正确的方向,但是却提示反向了
* 所以为了避免这种情况发生,我们要用360-90=270
* 如果还是不理解的话debug路径点角度和赛车的角度就会发现端倪了*/
//角度偏移<=270f && 角度偏移>=90f && 刚体速度>8f
if (Mathf.Abs(angleOffset) <= 270f && Mathf.Abs(angleOffset) >= 90f)
Debug.Log("反向移动了:" + Mathf.Abs(angleOffset).ToString());
}
代码不多,我的注释挺多的!
先获取最近的路标点,然后根据获取最近路标点的角度 - 赛车角度 = 角度偏移
Mathf.Abs是取绝对值,如果我们对比绝对值的话,可以debug看一下这个角度偏移
运行游戏,直接复位赛车,让赛车保持正确方向
然后手动调整赛车的方向,观察角度偏移的变化
赛车面对着前方时:角度偏移大约为 0
赛车面对左方时:角度偏移大约为 -270(逐渐变大)
赛车面对右方时:角度偏移大约为-90(逐渐变小)
所以当我们得到角度偏移后,取绝对值对比是否<=270度且>=90度(理解一下正数和负数的变化,小学数学)
圈数检测:
做圈数检测我们绝对不能只在终点添加一个cube触发这么简单
因为如果只添加一个cube触发,那玩家倒车,在前进,就算一圈了
除非他是开挂可以做到这么屌爆了的功能
当然肯定会有人说,那我多添加几个cube不就行了吗?
你难道要手动添加一圈cube来触发?累不累啊
在我刚学u3d的时候我记得在游戏蛮牛看见过一个讲解关于赛车检测圈数的视频
他的方法就是在赛道上添加很多cube来触发检测圈数
这的确是一种方法,不过我是不推荐这种方法的,除非是某些特定的功能需要这样的方法
在这里我的方法依旧是使用CarWaypoints插件,轻松简单到爆
取最近路标点这个方法如果你看过前几篇文章不会陌生了吧?
将检测圈数的方法放在update中,赛车移动时他获取最近的路标点
然后将这个路标点储存在已经过路标点集合中
如果这个路标点已存在则不添加
在终点添加一个cube触发,触发时检测是否 已经过路标点集合数量 >= 最少经过路标点
如果成立则完成一圈,不成立就说明玩家在终点前(圈数起点)徘徊或者开挂
说这么多废话不如代码解释来得快,上代码:
/// 检测路标点 <summary>
/// 用来保存已通过的路标点
/// 同样的路标点则不加入
/// 冲过终点线时取数量
/// 大于最少数量则算通过一圈
/// </summary>
private List<WaypointsModel> CheckPoints = new List<WaypointsModel>();
//完成圈数最少检查点
;
;//总圈数
;//当前圈数
/// 圈数检测 <summary>
/// 圈数检测
/// 思路如下:
/// 每一帧计算距离最近的检查点
/// 检查点存在则不添加,不存在则添加
/// 冲过终点线时取数量
/// 大于最少数量则算通过一圈
/// 然后清零 CheckPoints
/// </summary>
private void CircleNumberCheck()
{
WaypointsModel ClosestWP = GetClosestWP(WaypointsModelAll, transform.position);//获取距离最近的路径点
//判断当前最近路标点是否已存在
; i < CheckPoints.Count; i++)
{
//存在则返回
if (ClosestWP.Position == CheckPoints[i].Position)
return;
}
//不存在则添加
CheckPoints.Add(ClosestWP);
//Debug.Log(ClosestWP.Index);
}
我们在代码中看见几个新变量,我在上文中没有提到
minCheckPoints:最小检查点数量
游戏赛道大多数都有近到,如果玩家抄近道的话,就会漏掉一些检查点
如果我一个游戏赛道的waypoints数量为40个
玩家抄近道后只能检测到35个检查点,那么检查点数量就应该设置为35
这个值是按具体情况填写的,可以先自己手动跑一局,debug出数量,然后在设置
还有两个变量不用解释了,计算圈数用的
接着是终点触发代码:
void OnTriggerEnter(Collider Trigger)
{
//检查点数量大于最小检查点数量则算一圈
if (minCheckPoints <= CheckPoints.Count)
{
currentCircleNumber++;
if (currentCircleNumber > totalCircleNumber)
{
Debug.Log("游戏完成");
return;
}
Debug.Log("当前圈数:" + currentCircleNumber.ToString());
//清空检测点
CheckPoints.Clear();
}
}
记得触发cube勾选isTrigger
如果是计圈赛道,那么完成一圈就清空一次检测点
这样的话就可以计算新的一圈检测点了
赛道长度计算:
这个就太简单了,不多余解释,直接上代码:
/// 计算赛道长度 <summary>
/// 计算赛道长度
/// </summary>
/// <returns>返回赛道长度</returns>
private float CalcTotalDis()
{
//把所有点和点的距离相加而得出
float temTotalDis = 0f;//临时总距离
; i < WaypointsModelAll.Count; i++)
{
)
{ temTotalDis += Vector3.Distance(WaypointsModelAll[i].Position, WaypointsModelAll[].Position); }
else
{ temTotalDis += Vector3.Distance(WaypointsModelAll[i].Position, WaypointsModelAll[i + ].Position); }
}
return temTotalDis;
}
完整demo下载地址:http://pan.baidu.com/s/1i3ziILB
CarWaypoints插件使用介绍:http://www.cnblogs.com/shenggege/p/4295616.html
文中不足之处欢迎批评指正,如果本文对你有帮助请点一下右下角的推荐
本文链接:http://www.cnblogs.com/shenggege/p/4295986.html
unity3d 赛车游戏——复位点检测优化、反向检测、圈数检测、赛道长度计算的更多相关文章
- unity3d 赛车游戏——复位点检测
一直没有时间写博客 昨天我的CarWaypoints插件也告一段落了 今年没回家,过年就我一个人 挺无聊的,那就休息一天写几篇博客吧 我的代码可能很少,但是思路很重要 希望不懂的朋友别只copy代码 ...
- 使用Unity3D的设计思想实现一个简单的C#赛车游戏场景
最近看了看一个C#游戏开发的公开课,在该公开课中使用面向对象思想与Unity3D游戏开发思想结合的方式,对一个简单的赛车游戏场景进行了实现.原本在C#中很方便地就可以完成的一个小场景,使用Unity3 ...
- 使用Unity3D引擎开发赛车游戏
Car Tutorial 在Unity3D的Asset Store有一个赛车的Demo —— Car Tutorial,看起来特别酷的赛车游戏Demo,不过我还没有下载下来,因为在公司下载Assets ...
- Unity创作赛车游戏的四款插件
本文,我们将介绍其中4款:Racing Game Starter Kit.GeNa 2 .NWH Vehicle Physics.Curvy Splines. Racing Game Starter ...
- Unity赛车游戏之移动
这个赛车游戏真是让我费劲脑汁啊.尤其是写这种系统化的东西. 目前漂移还没找到更好的算法,不过基本的移动还是可以做到的. 别看就光是个移动,其实也是很费事的. Unity给了个对于赛车系统很好的碰撞组件 ...
- 《Unity3D/2D游戏开发从0到1(第二版本)》 书稿完结总结
前几天,个人著作<Unity3D/2D游戏开发从0到1(第二版)>经过七八个月的技术准备以及近3个月的日夜编写,在十一长假后终于完稿.今天抽出一点时间来,给广大热心小伙伴们汇报一下书籍概况 ...
- 《Unity3D/2D游戏开发从0到1》正式出版发行
<Unity3D/2D游戏开发从0到1>正式出版发行 去年个人编写的Unity书籍正式在2015年7月正式发行,现在补充介绍一下个人著作.书籍信息: 书籍的名称: <Uni ...
- Unity3D手机游戏开发
<Unity3D手机游戏开发> 基本信息 作者: 金玺曾 出版社:清华大学出版社 ISBN:9787302325550 上架时间:2013-8-7 出版日期:2013 年8月 开本:16开 ...
- Unity的赛车游戏实现思路
unity目前版本实现赛车的技术方案主要有3种: 1.wheelCollider,设置motorTorque.brakeTorque.steerAngle来实现车子的推动和转弯,优点是上手简单,而且很 ...
随机推荐
- python数据结构-列表-建立/索引/反转
- 正确使用 Volatile 变量——Brian Goetz
本文转自:http://www.ibm.com/developerworks/cn/java/j-jtp06197.html 由Java并发大师Brian Goetz所撰写的. Java 语言中的 v ...
- OS X下安装Redis及配置开机启动
1.下载redis源码包redis-3.0.5.tar(此步骤可在图形界面下操作) 2.解压源码包 tar zxvf redis-3.0.5.tar 3.编译源码并安装 #进入源码目录 cd redi ...
- Javascript中length属性的总结
Javascript中length属性的总结 一.StringObject中的length length属性是返回字符串的字符数目. 例如: // 普通字符串 var str = " ...
- zip文件jQuery工作地点选择城市代码
效果 地址下载:http://download.csdn.net/detail/xiaoliu123586/9201925 2.效果 源码:http://download.csdn.net/detai ...
- vim自定义配色方案,图文并茂
1.先上图 下面是tcpdump的源码.颜色根据自己的喜好配置,我比较喜欢亮的颜色,看的清楚! 2.下载辅助配置文件 ...
- 双向广搜 POJ 3126 Prime Path
POJ 3126 Prime Path Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16204 Accepted ...
- 边工作边刷题:70天一遍leetcode: day 89-1
Smallest Rectangle Enclosing Black Pixels 要点:记题:这题有两个限制条件:所有black pixel是连通的(所以可以用binary search)以及给了一 ...
- 通过imeMode禁用键盘只能输入数字
var obj = document.getElementById('y'); var arr = [48,49,50,51,52,53,54,55,56,57];//数字对应的键码 obj.onke ...
- System.Net.Sockets.Socket SendAsync System.ObjectDisposedException: Cannot access a disposed object.
发生未处理的域异常! System.ObjectDisposedException: Cannot access a disposed object. Object name: 'System.Net ...