目录
射线在游戏开发中,应用非常广泛,所以掌握射线非常重要。
列如:判断角色是否着地,可以向角色脚下发射射线,判断是否接触地面。
注意:各种射线检测都是以物理系统为基础的。射线需要与碰撞体和触发器配合才能发挥出作用。
射线与视线一样会被障碍物阻挡并且射线不仅可以有长度,还可以有粗细和形状,列如球形射线,盒子射线和胶囊体射线。方法都大同小异。
常用的直线射线类型用类型Ray表示,Ray包含了起点origin跟方向direction的定义,起点和方向都用Vector3类型表示,前者是一个坐标,后者是一个表示方向的向量。
Vector3 origin = transform.position;
Vector3 direction = Vector3.down;
Ray ray = new Ray(origin, direction);
在游戏中发射一条射线,最常用的是physics.Raycast()和physics.RaycastAll(),前者只能检测一个碰撞体而被返回,后者可以一起检测多个碰撞体。我们先讲讲Raycast(),常用的重载方法如下
bool raycast =Physics.Raycast(ray.origin,ray.direction,out RaycastHit hitInfo,float maxDistance,int layerMask);
这里有五个参数,第一个是发射起点,第二个是发射方向,第三个是发射距离,第四个是射线碰撞信息,第五个是发射图层,只检测指定图层,而忽略其他图层,最后返回值bool是是否击中某个碰撞体或者触发器。其中,前两个参数是必须,后三个参数根据我们的需要可加可不加。
我们再重点讲讲第三个参数RaycastHit,若没有这个参数,我们的返回值仅仅只是“是否碰到了物体”,而无法确定碰撞点在哪,也不知道碰撞体是哪一个。射线检测其实有着非常丰富的碰撞信息,如可以获得其碰撞坐标,信息,以及法线。这些丰富的信息都被保存在RaycastHit结构体中。
综合用法演示如下:
//声明变量,用于保存信息
RaycastHit hitInfo;
//发射射线,起点是当前物体位置,方向是世界前方
if(Physics.Raycast(transform.position,Vector3.forward,out hitInfo))
{
//如果碰到物体,运行此处,返回的是bOOl值
//获取碰撞点坐标
Vector3 point = hitInfo.point;
//获取对方碰撞体组件
Collider coll = hitInfo.collider;
//获取对方的Transgorm组件
Transform trans = hitInfo.transform;
//获取对方的物体名称
string name = hitInfo.collider.name;
//获取碰撞点的法线向量
Vector3 normal = hitInfo.normal;
}
注意,2D游戏跟3D游戏获取碰撞体的方式有些不一样,具体对比如下
//声明变量,将碰撞信息直接赋值给变量
RaycastHit2D hitInfo=Physics2D.Raycast(transform.position,Vector3.forward);
//发射射线,起点是当前物体位置,方向是世界前方
if(hitInfo.collider != null)
{
//如果检测的碰撞体不为空,运行此处。
//获取碰撞点坐标
Vector3 point = hitInfo.point;
//获取对方碰撞体组件
Collider coll = hitInfo.collider;
//获取对方的Transgorm组件
Transform trans = hitInfo.transform;
//获取对方的物体名称
string name = hitInfo.collider.name;
//获取碰撞点的法线向量
Vector3 normal = hitInfo.normal;
}
前面我们提到了Raycast()跟RaycastAll的区别,,区别是前者只能检测一个碰撞体便返回,后者是能可以获取到射线沿途碰到的所有信息(在指定图层内)。我们以2D为例,差异看图

如图,圆形物体发射的射线被绿色碰撞体阻挡,无法到达蓝色碰撞体,所以此时射线只能检测绿色图层,但不能检测蓝色碰撞体,那我们怎么能即检测绿色碰撞体又能检测蓝色碰撞体。这时就需要我们使用Physics,RaycastAll(),该函数的返回值是RaycastHit数组。重载方式如下:
RaycastHit[] hit = Physics.RaycastAll(Vector3 origin,Vector3 direction,float maxDistance,int LayerMask);
利用此函数,我们便可以实现同时检测绿色,蓝色两个碰撞体,效果如下
例子代码,仅供参考
RaycastHit2D[] hitInfo = Physics2D.RaycastAll(ray.origin,ray.direction,10f,LayerMask.GetMask("ground","war"));
for(i=0;i<hitInfo.Length;i++)
{
Debug.DrawLine( ray.origin,hitInfo[i].point ,Color.red);
Debug.Log(hitInfo[i].collider.name);
}
其中介绍一一个小知识,这里获取图层的方法是LayerMask.GetMask(),这里可获得一个图层或者多个图层
例如获得Ground,player,obstacle者三个层,代码如下
int mask = layerMask.GetMask("ground","player","obstacle");
有时候需要检测一个空间的范围,例如炸弹爆炸时,范围十米之内的物体都会受到波及,那么这里需要的不是一条射线,而是一个半径为10米的球形区域。物理系统也提供了这类函数,它们均已Physics。Overlap开头,这里以球形区域为例:
Collider[] collider = overlapSphere(Vector3 position,float radius,int LayerMask);
第一个参数是位置,第二个参数是范围距离,第三个是图层,且该返回值是collider。
利用Debug调试
在游戏开发中,射线的调试方法非常重要,可以将看不见的射线以可视化的形式表现出来,方便我们查看数据是否正确。这个方法是使用Debug.DrawLine()函数和Debug.DrawRay().

效果图可以看上面,都有涉及使用到。需要说明的是在默认的情况下,该辅助线仅在编辑器的场景窗口可见,如果要在game窗口看到,则需要单机Game窗口右上角的Gizmos开关。
利用Gizmos
调用OnDrawGizmos()函数或OnDrawGizmosSelected,它们同样都可以用来绘制辅助图标。区别在于
函数OnDrawGizmos()在程序一运行就执行,之后每帧都在执行,
函数OnDrawGizmosSelected()在鼠标点击到脚本挂载的物体的身上的时候运行,不管有多少父类对象,它都会执行。
这里推荐使用OnDrawGizmosSelected()
范例如下
private void OnDrawGizmosSelected()
{
Gizmos.DrawLine(Vector3 from, Vector3 to);
Gizmos.DrawRay((Vector3 from, Vector3 direction);
}
可在scence窗口查看辅助线,同样想在game窗口可以看到,则需要单机Game窗口右上角的Gizmos开关。
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t