zoukankan      html  css  js  c++  java
  • 初学Direct X(8) ——碰撞检测

    初学Direct X(8)

    ——碰撞检测

    真正让一个游戏鹤立鸡群的是程序对碰撞的响应有多好,这里介绍两种检测的方法:
    1) 基于边框的碰撞检测
    2) 基于距离的碰撞检测

    1. 基于边框的碰撞检测

    1.1 实现的基础

    我们将要检测的两个物体(位图)视为两个矩形,在此基础之上,检测两矩形是否有重叠区域。若存在重叠区域,则发生了碰撞;反之则没有。检测两矩形是否有重叠到了Windows API,即IntersectRect,它的定义如下:

    BOOL IntersectRect(
      _Out_       LPRECT lprcDst,
      _In_  const RECT   *lprcSrc1,
      _In_  const RECT   *lprcSrc2
    );
    

    lprcDst储存了lprcSrc1lprcSrc2重叠的矩形区域,但是我们并不关心这个,只关心此函数的返回值。若存在重叠区域,返回值为非0;反之为0。
    据此可以实现碰撞检测的函数如下:(关于SPRITE的定义参见这儿

    bool Collision(SPRITE sprite1, SPRITE sprite2){
    	RECT rect1;
    	rect1.left = (long)sprite1.x;
    	rect1.top = (long)sprite1.y;
    	rect1.right = (long)sprite1.x + sprite1.width * sprite1.scaling;
    	rect1.bottom = (long)sprite1.y + sprite1.height * sprite1.scaling;
    
    	RECT rect2;
    	rect2.left = (long)sprite2.x;
    	rect2.top = (long)sprite2.y;
    	rect2.right = (long)sprite2.x + sprite2.width * sprite2.scaling;
    	rect2.bottom = (long)sprite2.y + sprite2.height * sprite2.scaling;
    
    	RECT dest; //ignored
    	return IntersectRect(&dest, &rect1, &rect2);
    }
    

    1.2 实现

    我们实现一个宇宙飞船在小行星中飞行的场景,其中小行星是不断运动的。居然用到了物体检测,而且显然场景中不止一个物体了,此时我们需要用一个结构体(或者类)来表达一个物体,就像下面这样:
     

    //sprite structure
    struct SPRITE
    {
    	float x, y; 				// 在窗口中显示的位置
    	int frame, columns;     	// 在位图表中的位置信息
    	int width, height;      	// 同上,单位位图的尺寸
    	float scaling, rotation; 	// 放缩比,旋转角度
    	int startframe, endframe; 	// 在位图表中的位置信息
    	int starttime, delay;     	// 用于帧率显示
    	int direction;           	// 帧数前进单位
    	float velx, vely;        	// 位移单位
    	D3DCOLOR color;
    
    	SPRITE()
    	{
    		frame = 0;
    		columns = 1;
    		width = height = 0;
    		scaling = 1.0f;
    		rotation = 0.0f;
    		startframe = endframe = 0;
    		direction = 1;
    		starttime = delay = 0;
    		velx = vely = 0.0f;
    		color = D3DCOLOR_XRGB(255, 255, 255);
    	}
    };
    

    在声明完一个物体结构体时,我们需要加载位图:

    fatship.tga
    fatship.tga

    asteroid.tga
    asteroid.tga

    // 全局变量
    SPRITE ship, asteroid1, asteroid2;
    LPDIRECT3DTEXTURE9 imgShip;
    LPDIRECT3DTEXTURE9 imgAsteroid;
    
    --------------------------------
    --------------------------------
    
    // Game_Init()
    // 初始化物体,包括运动状态以及在窗口中显示位置
    imgShip = LoadTexture("fatship.tga");
    imgAsteroid = LoadTexture("asteroid.tga");
    //set properties for sprites
    ship.x = 450;
    ship.y = 300;
    ship.width = ship.height = 128;
    
    asteroid1.x = 50;
    asteroid1.y = 200;
    asteroid1.width = asteroid1.height = 60;
    asteroid1.columns = 8;
    asteroid1.startframe = 0;
    asteroid1.endframe = 63;
    asteroid1.velx = -2.0f;
    
    asteroid2.x = 900;
    asteroid2.y = 500;
    asteroid2.width = asteroid2.height = 60;
    asteroid2.columns = 8;
    asteroid2.startframe = 0;
    asteroid2.endframe = 63;
    asteroid2.velx = 2.0f;
    
    --------------------------------
    --------------------------------
    
    // Game_Run()
    // 检测外设的输入
    if (Key_Down(DIK_W))
    {
    	ship.y -= 1.0f;
    	if (ship.y < 0) 
    		ship.y = 0;
    }
    if (Key_Down(DIK_S))
    {
    	ship.y += 1.0f;
    	if (ship.y > SCREENH - ship.height)
    		ship.y = SCREENH - ship.height;
    }
    //小行星和飞船的移动
    asteroid1.x += asteroid1.velx;
    // 到达边界,返回
    if (asteroid1.x < 0 || asteroid1.x > SCREENW - asteroid1.width)
    	asteroid1.velx *= -1;
    Sprite_Animate(asteroid1.frame, asteroid1.startframe, asteroid1.endframe, asteroid1.direction, asteroid1.starttime, asteroid1.delay);
    
    asteroid2.x += asteroid2.velx;
    // 到达边界,返回
    if (asteroid2.x < 0 || asteroid2.x > SCREENW - asteroid2.width)
    	asteroid2.velx *= -1;
    Sprite_Animate(asteroid2.frame, asteroid2.startframe, asteroid2.endframe, asteroid2.direction, asteroid2.starttime, asteroid2.delay);
    // 碰撞检测,若发生了碰撞,则会使得小行星反方向返回
    if (Collision(ship, asteroid1))
    		asteroid1.velx *= -1;
    if (Collision(ship, asteroid2))
    		asteroid2.velx *= -1;
    
    // 将各个物体按照计算出来的位置绘制到屏幕上
    if (d3ddev->BeginScene()){
    
    	spriteobj->Begin(D3DXSPRITE_ALPHABLEND);
    
    	Sprite_Transform_Draw(imgShip, ship.x, ship.y, ship.width, ship.height, ship.frame, ship.columns);
    
    	Sprite_Transform_Draw(imgAsteroid, asteroid1.x, asteroid1.y, asteroid1.width, asteroid1.height, asteroid1.frame, asteroid1.columns);
    
    	Sprite_Transform_Draw(imgAsteroid, asteroid2.x, asteroid2.y, asteroid2.width, asteroid2.height, asteroid2.frame, asteroid2.columns);
    
    	spriteobj->End();
    
    	d3ddev->EndScene();
    	d3ddev->Present(NULL,NULL,NULL,NULL);
    }
    

    下面是运行结果:


    白线表示的是小行星运行的范围

    2. 2. 基于距离的碰撞检测

    2.1 实现的基础

    将俩物体视为两个圆,圆心分别为(X0,Y0),(X1,Y1),半径分别为R0,R1,若满足:

    dist < R0+R1
    (dist 为俩圆心的距离:sqrt((X0 - X1)^2 + (Y0 - Y1)^2))

    则可以判定俩物体发生了碰撞 ,据此实现的判定函数如下:

    bool CollisionD(SPRITE sprite1, SPRITE sprite2)
    {
        double radius1, radius2;
    	
    	// 将宽和高中较长的一条边做为半径,以确保包围住物体
        //calculate radius 1
        if (sprite1.width > sprite1.height)
            radius1 = (sprite1.width * sprite1.scaling) / 2.0;
        else
            radius1 = (sprite1.height * sprite1.scaling) / 2.0;
    
        //center point 1
        double x1 = sprite1.x + radius1;
        double y1 = sprite1.y + radius1;
        D3DXVECTOR2 vector1(x1, y1);
    
        //calculate radius 2
        if (sprite2.width > sprite2.height)
            radius2 = (sprite2.width * sprite2.scaling) / 2.0;
        else
            radius2 = (sprite2.height * sprite2.scaling) / 2.0;
    
        //center point 2
        double x2 = sprite2.x + radius2;
        double y2 = sprite2.y + radius2;
        D3DXVECTOR2 vector2(x2, y2);
    
        //calculate distance
        double deltax = vector1.x - vector2.x;
        double deltay = vector2.y - vector1.y;
        double dist = sqrt((deltax * deltax) + (deltay * deltay));
    
        //return distance comparison
        return (dist < radius1 + radius2);
    }
    

    2.2 实现

    对照2.1中的实现,只需要将原来的碰撞检测函数替换为如下即可:

    if (CollisionD(ship, asteroid1))
    	asteroid1.velx *= -1;
    
    if (CollisionD(ship, asteroid2))
    	asteroid2.velx *= -1;
    
  • 相关阅读:
    HTTP协议详解
    loadrunner性能测试步骤
    LR工作原理
    性能测试相关术语
    敏捷测试的方法和实践
    究竟什么是敏捷测试
    避免沙堆建楼 做好软件安全测试
    软件安全测试新武器 ——浅谈基于Dynamic Taint Propagation的测试技术
    软件安全测试的几个原则
    安全性测试--CSRF攻击
  • 原文地址:https://www.cnblogs.com/leihui/p/8951178.html
Copyright © 2011-2022 走看看