碰撞检测(上篇)

游戏中的每个3D对象在世界坐标系里都有坐标。
技能的作用范围可能是圆形,矩形,扇形,三角形等。
那可不可以直接拿 “点”直接与这些形状进行碰撞检测呢!
如果你要的效果不是那么精确,可以允许一点点瑕疵,那么是可行的。
那么这个瑕疵是什么呢?
因为3D物体都有体积,当你肉眼都能看到你的3D模型已经在范围里面,但是为什么技能作用不到它呢?
因为实际取的是3D物体的中心点。当这个中心点真正进入技能范围内,技能才真正作用到他。
如图:中心点还在范围外

如果你不能允许,那这种方式就不适合了。我会在下篇整理更精确的方式。
这里有本书:Real-Time Collision Dectection 中文版
我上传到网盘了:
链接:http://pan.baidu.com/s/1o63VtqE 密码:d5vt
如果你能允许,那么请往下看。
1.点在三角形内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using UnityEngine;
using System.Collections;
 
/// <summary>
/// 点在三角形里面
/// </summary>
public class PointInTriangle : MonoBehaviour
{
    public Transform PointTrans;
    public float distance = 5f;
    public float angle = 30f;
 
    void Update()
    {
        Quaternion r = this.transform.rotation;
        Vector3 f0 = transform.position + (r * Vector3.forward) * distance;
        //Debug.DrawLine(transform.position, f0, Color.red);//正前方
 
        Quaternion r0 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y - angle, transform.rotation.eulerAngles.z);
        Vector3 f1 = transform.position + (r0 * Vector3.forward) * distance;
        Debug.DrawLine(transform.position, f1, Color.red);//左30度方向
 
        Quaternion r1 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + angle, transform.rotation.eulerAngles.z);
        Vector3 f2 = transform.position + (r1 * Vector3.forward) * distance;//右30度方向
        Debug.DrawLine(transform.position, f2, Color.red);
 
        Debug.DrawLine(f1, f2, Color.red);//连接成一个三角形
 
        Vector3 point = PointTrans.position;
 
        //点是否在一个三角形内
        if (MyTool.isINTriangle(point, transform.position, f1, f2))
        {
            Debug.Log("in");
        }
        else
        {
            Debug.Log("not in");
        }
    }
}

2.点在扇形内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using UnityEngine;
using System.Collections;
 
/// <summary>
/// 点在扇形里面
/// </summary>
public class PointInSector : MonoBehaviour
{
    public Transform pointTransform;
    public float distance = 5f;
    public float angle = 30f;
    void Update()
    {
        Quaternion r = this.transform.rotation;
        Vector3 f0 = transform.position + (r * Vector3.forward) * distance;
        Debug.DrawLine(transform.position, f0, Color.red);//正前方
 
        Quaternion r0 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y - angle, transform.rotation.eulerAngles.z);
        Vector3 f1 = transform.position + (r0 * Vector3.forward) * distance;
        Debug.DrawLine(transform.position, f1, Color.red);//左30度方向
 
        Quaternion r1 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + angle, transform.rotation.eulerAngles.z);
        Vector3 f2 = transform.position + (r1 * Vector3.forward) * distance;//右30度方向
        Debug.DrawLine(transform.position, f2, Color.red);
 
        Debug.DrawLine(f1, f2, Color.red);//连接成一个三角形
 
        Vector3 point = pointTransform.position;
 
        Vector3 selfVec = (f0 - this.transform.position).normalized;
        Vector3 targetVec = (pointTransform.position - this.transform.position).normalized;
        Debug.DrawLine(pointTransform.position, this.transform.position, Color.yellow);
 
        //在左右30度以内
        if (Vector3.Dot(selfVec, targetVec) > Mathf.Cos(Mathf.PI / 6.0f))
        {
            //且在周围distance范围以内,等价于在这个扇形区域!
            if ((pointTransform.position - this.transform.position).sqrMagnitude < distance * distance)
            {
                Debug.Log("in");
            }
            else
            {
                Debug.Log("not in");
            }
        }
        else
        {
            Debug.Log("out of angle");
        }
    }
}

3.点在矩形内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using UnityEngine;
using System.Collections;
 
/// <summary>
/// 点在矩形里面
/// </summary>
public class PointInRectangle : MonoBehaviour
{
    public Transform pointTransform;
    public float length = 5f;
    public float width = 5f;
 
    private float half_length;
    private float half_width;
 
    void Start()
    {
        this.half_length = this.length / 2.0f;
        this.half_width = this.width / 2.0f;
    }
 
    void Update()
    {
        Quaternion r = transform.rotation;
        Vector3 left = (transform.position + (r * Vector3.left) * this.half_length);
        Debug.DrawLine(transform.position, left, Color.red);
 
        Vector3 right = (transform.position + (r * Vector3.right) * this.half_length);
        Debug.DrawLine(transform.position, right, Color.red);
 
        Vector3 leftEnd = (left + (r * Vector3.forward) * this.width);
        Debug.DrawLine(left, leftEnd, Color.red);
 
        Vector3 rightEnd = (right + (r * Vector3.forward) * this.width);
        Debug.DrawLine(right, rightEnd, Color.red);
 
        Debug.DrawLine(leftEnd, rightEnd, Color.red);
 
        Vector3 point = pointTransform.position;
 
        //是否在矩形内
        if (MyTool.isINRect(point, leftEnd, rightEnd, right, left))
        {
            Debug.Log("in");
        }
        else
        {
            Debug.Log("not in");
        }
    }
}

工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using UnityEngine;
 
public class MyTool
{
    private static float triangleArea(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y)
    {
        return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
            - v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
    }
    public static bool isINTriangle(Vector3 point, Vector3 v0, Vector3 v1, Vector3 v2)
    {
        float x = point.x;
        float y = point.z;
 
        float v0x = v0.x;
        float v0y = v0.z;
 
        float v1x = v1.x;
        float v1y = v1.z;
 
        float v2x = v2.x;
        float v2y = v2.z;
 
        float t = triangleArea(v0x, v0y, v1x, v1y, v2x, v2y);
        float a = triangleArea(v0x, v0y, v1x, v1y, x, y) + triangleArea(v0x, v0y, x, y, v2x, v2y) + triangleArea(x, y, v1x, v1y, v2x, v2y);
 
        if (Mathf.Abs(t - a) <= 0.01f)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
 
 
    private static float Multiply(float p1x, float p1y, float p2x, float p2y, float p0x, float p0y)
    {
        return ((p1x - p0x) * (p2y - p0y) - (p2x - p0x) * (p1y - p0y));
    }
 
    public static bool isINRect(Vector3 point, Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3)
    {
        float x = point.x;
        float y = point.z;
 
        float v0x = v0.x;
        float v0y = v0.z;
 
        float v1x = v1.x;
        float v1y = v1.z;
 
        float v2x = v2.x;
        float v2y = v2.z;
 
        float v3x = v3.x;
        float v3y = v3.z;
 
        if (Multiply(x, y, v0x, v0y, v1x, v1y) * Multiply(x, y, v3x, v3y, v2x, v2y) <= 0 && Multiply(x, y, v3x, v3y, v0x, v0y) * Multiply(x, y, v2x, v2y, v1x, v1y) <= 0)
            return true;
        else
            return false;
 
    }
}
时间: 2024-10-26 17:11:36

碰撞检测(上篇)的相关文章

【COCOS2DX-游戏开发之三六】圆与未旋转矩形的碰撞检测(上篇)

我们以cocos2dx lua脚本来说明,原理才是重点 检测圆和矩形碰撞,首先要找到矩形上离圆的中心点最近的点 if circle.x < box.x then cx = box.x end 如果圆在矩形的左边,离着圆中心点最近的矩形上的点在矩形的左边边界上 elseif circle.x > box.x + box.width then cx = box.x + box.width 如果圆的中心点在矩形的右边,离着圆中心点最近的矩形上的点在矩形的右边边界上 else cx = circle.

Cocos2d-x3.2 碰撞检测--圆形

//GameScene.h #include "cocos2d.h" USING_NS_CC; class GameScene : public cocos2d::Layer { public:     static cocos2d::Scene* createScene();          virtual bool init();          virtual bool onTouchBegan(Touch *touch, Event *unused_event);     

Physics 碰撞检测回调方法出错或者没有效果解决方法

1.碰撞检测回调方法编译出错; auto *listener = EventListenerPhysicsContact::create(); listener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin,this); 在3.0rc版本中回调函数的参数变为一个,不能使用原来的两个参数; bool HelloWorld::onContactBegin(PhysicsContact& contact) { auto spr

简单圆形碰撞检测

整理以前的文件时看到之前写过的圆形的碰撞检测,简单记录下. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <canvas id="cav" width="500" height=&quo

Egret 矢量绘图、遮罩、碰撞检测

矢量绘图: 1. 为矢量绘图绘制外边 - graphics.lineStype() private createGameScene():void { console.log("Runtime start."); var myShape:egret.Shape = new egret.Shape(); myShape.graphics.lineStyle(10, 0x00ff00, 1); myShape.graphics.beginFill(0xff0000, 1); myShape.

.Net remoting方法实现简单的在线升级(上篇:更新文件)

一.前言:       最近做一个简单的在线升级Demo,使用了微软较早的.Net Remoting技术来练手. 简单的思路就是在服务器配置一个Remoting对象,然后在客户端来执行Remoting对象中的方法. 过程: (1) 读取本地dll文件的名称与版本号,与服务器的进行对比 (2) 确认需要升级的文件名称与版本号并告诉服务器,服务器将其复制到一个临时文件夹并压缩成zip (3) 将服务器的zip下载到本地的临时文件夹,并解压. 定义服务器端为UpdateServer,其配置文件为: <

XenApp_XenDesktop_7.6实战篇之二十:Linux Virtual Desktop 1.0(上篇)

Linux Virtual Desktop 1.0在CitrixXenDesktop 7.6 Feature Pack 2中于2015年6月30日已经正式发布了,目前Linux Virtual Desktop 1.0只支持发布共享桌面,暂不支持发布独立桌面和应用程序.本章节将介绍和演示CitrixXenDesktop 7.6 Linux Virtual Desktop 1.0的整个过程,本次使用的Linux系统为Red Hat Enterprise Linux Server 6.6.整个Linu

比较全面的MySQL优化参考(上篇)

转自:http://imysql.com/2015/05/24/mysql-optimization-reference-1.shtml 本文整理了一些MySQL的通用优化方法,做个简单的总结分享,旨在帮助那些没有专职MySQL DBA的企业做好基本的优化工作,至于具体的SQL优化,大部分通过加适当的索引即可达到效果,更复杂的就需要具体分析了,可以参考本站的一些优化案例或者联系我,下方有我的联系方式.这是上篇. 1.硬件层相关优化 1.1.CPU相关 在服务器的BIOS设置中,可调整下面的几个配

显示对象的像素级碰撞检测

mc2.gotoAndStop(1); var bmd1 = new BitmapData(mc1.width, mc1.height, true, 0); bmd1.draw(mc1); var bmd2 = new BitmapData(mc2.width, mc2.height, true, 0); bmd2.draw(mc2); stage.addEventListener(Event.ENTER_FRAME,frameFunc); function frameFunc(e:Event)