Directx9学习(九)碰撞——基于边界和基于距离

好久没有碰D3D了,生疏了太多。忘记了如何新建窗口,写到这里,下次再用的时候就可以看这个。

#include"MyD3D.h"
//#include

//窗口回调函数
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_DESTROY:
		gameOver = true;  //跳出那个消息循环 否则就算关了还会一直跑
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);
}

//winMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevinstance, LPSTR lpCmdLine, int nCmdShow)
{
	//初始化窗口设定
	WNDCLASSEX wc;
	//wc必须都初始化
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = (WNDPROC)WinProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = NULL;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszClassName = "MainWindowClass";
	wc.lpszMenuName = NULL;
	wc.hIconSm = NULL;
	RegisterClassEx(&wc);

	HWND window = CreateWindow(
		"MainWindowClass",
		"MainWindowClass",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		1024, 768,
		NULL, NULL,
		hInstance,
		NULL
	);

	if (window == 0)
		return 0;

	ShowWindow(window, nCmdShow);
	UpdateWindow(window);

	MSG message;

	//主消息循环
	while (!gameOver)
	{
		if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&message);
			DispatchMessage(&message);
		}

	}


	return message.wParam;
}

然后是初始化D3D,首先需要创建变量


LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;

然后在窗口进入主消息循环之前调用Init就可以初始化了

bool Direct3D_Init(HWND hwnd, int width, int height, bool fullScreen)
{
	d3d = Direct3DCreate9(D3D_SDK_VERSION);
	if (!d3d)
		return false;

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	//这样设置呈现参数能够保证可以创建透明的Sprite
	d3dpp.Windowed = (!fullScreen);
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferWidth = width;
	d3dpp.BackBufferHeight = height;
	d3dpp.hDeviceWindow = hwnd;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
	d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	d3dpp.EnableAutoDepthStencil = 1;

	//以呈现参数创建d3ddev
	d3d->CreateDevice(
		D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		hwnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,
		&d3ddev
	);

	if (!d3ddev)
		return false;

}


从文件装载texture,写成一个函数方便用

//从文件装载Texture
LPDIRECT3DTEXTURE9 LoadTexture(string fileName, D3DCOLOR transColor)
{
	LPDIRECT3DTEXTURE9 tex = NULL;
	D3DXIMAGE_INFO info;
	//获得图片信息
	HRESULT result = D3DXGetImageInfoFromFile(fileName.c_str(), &info);
	if (result != D3D_OK)
		return NULL;
	//从文件加载纹理
	result = D3DXCreateTextureFromFileEx(
		d3ddev,
		fileName.c_str(),
		info.Width,
		info.Height,
		1,
		D3DPOOL_DEFAULT,
		D3DFMT_UNKNOWN,
		D3DPOOL_DEFAULT,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		transColor,
		&info,
		NULL,
		&tex
	);
	if (result != D3D_OK)
		return NULL;

	return tex;
}

 然后设置矩阵:

//设置矩阵
D3DXMATRIX SetMartex(int x, int y, int width,int height, float rotation, float scaling)
{
	D3DXVECTOR2 scale(scaling, scaling);
	D3DXVECTOR2 trans(x, y);
	D3DXVECTOR2 center((float)(width*scaling) / 2, (float)(height*scaling) / 2);
	D3DXMATRIX mat;
	D3DXMatrixTransformation2D(&mat, NULL, 0, &scale, ¢er, rotation, &trans);
	return mat;
}

然后绘制带变化的Sprite

//绘制带变换的Sprite 
void DrawSpriteWithTrans(LPD3DXSPRITE _sprite,LPDIRECT3DTEXTURE9 tex, D3DXMATRIX mat,D3DCOLOR color)
{
	_sprite->SetTransform(&mat);
	//设置矩阵然后画整张图片
	_sprite->Draw(tex, NULL, NULL, NULL, color);
}

准备工作差不多就OK了,由于生疏了所以都写了一遍,没有进展。

这次首先使用基于边界的碰撞检测只是实现一个简单的,利用WINAPI IntersectRect  实现一个根据边界判断是否有碰撞的功能,不过旋转目前不会弄。按下空格键,图片1前进10个单位

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)   按键按下

bool IntersectRect(LPRECT lprcDst,RECT* rect1,RECT* rect2 ) 看后面的两个RECT是否存在交集


步骤差不多是 首先声明一个SPRITE结构,参数是:

struct SPRITE
{
	LPD3DXSPRITE m_sprite;  //Sprite
	LPDIRECT3DTEXTURE9 tex;	//Texture
	RECT collitionRect;	//碰撞矩形
	float scaling, rotation;	//旋转和缩放
	D3DCOLOR color;

	SPRITE()
	{
		color = D3DCOLOR_XRGB(255, 252, 255);
		scaling = 1.0f;
		rotation = 0.0f;
		m_sprite = NULL;
		
		tex = NULL;
	}

};

//声明两个SPRITE变量
SPRITE sp1, sp2;


然后在初始化的时候给这两个sprite初始量,定下他们的位置和贴图,由于还需要获得确定图片的长和宽,赋给两个变量,所以这里改写了LoadTexture函数,让他传入两个整形的地址并在LoadTexture中改变这两个整形让他们存储原始图片的长和宽

在初始化函数中添加:

//初始化sprite
//创建Sprite
D3DXCreateSprite(d3ddev, &sp1.m_sprite);
D3DXCreateSprite(d3ddev, &sp2.m_sprite);

int *w , *h ;  //存储原始Texture的长度和宽度
w = new int();
h = new int();
sp1.tex = LoadTexture("D:\\Personal\\Documents\\My Pictures\\c75c10385343fbf24781fe05b17eca8065388f63.jpg",D3DCOLOR_XRGB(255,255,255), w, h);
sp1.collitionRect.left = 0;
sp1.collitionRect.right = (*w)*sp1.scaling;  //长度和宽度应该乘上缩放量才是碰撞体本身的长宽
sp1.collitionRect.top = 0;
sp1.collitionRect.bottom = (*h)*sp1.scaling;	

sp2.tex = LoadTexture("D:\\Personal\\Documents\\My Pictures\\111724628725fc12aao.jpg", D3DCOLOR_XRGB(255, 255, 255), w, h);
sp2.collitionRect.left = 500;
sp2.collitionRect.right = 500 + (*w)*sp2.scaling;
sp2.collitionRect.top = 0;
sp2.collitionRect.bottom = (*h)*sp2.scaling;

然后就是在主消息循环中画图了

while (!gameOver)
	{
		if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&message);
			DispatchMessage(&message);
		}

		if (KEY_DOWN(VK_SPACE))
		{		
			//修改碰撞的位置
			if (!keyHasDown)
			{
				RECT rec;
				//判断是否会撞上
				canSP1Move = !IntersectRect(&rec, &(sp1.collitionRect), &(sp2.collitionRect));
				
				if (canSP1Move)
				{
					int w = sp1.collitionRect.right - sp1.collitionRect.left;
					sp1.collitionRect.left += 10;
					sp1.collitionRect.right = sp1.collitionRect.left + w;
					times += 10;
					//修改变换矩阵
					mat1 = SetMartex(times, 0, sp1.collitionRect.left + w, sp1.collitionRect.bottom, 0.0f, 1.0f);
					keyHasDown = true;
				}
			}
			
		}
		else
		{
			keyHasDown = false;
		}

		//清空缓存 就没有之前画的重影了 否则之前的就会一直在上面
		d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 255), 1.0F, 0);

		//绘画
		if (d3ddev->BeginScene())
		{
			sp1.m_sprite->Begin(D3DXSPRITE_ALPHABLEND);			
			DrawSpriteWithTrans(sp1.m_sprite, sp1.tex, mat1, D3DCOLOR_XRGB(255, 252, 255));
			sp1.m_sprite->End();
			
			sp2.m_sprite->Begin(D3DXSPRITE_ALPHABLEND);
			DrawSpriteWithTrans(sp2.m_sprite, sp2.tex, mat2, D3DCOLOR_XRGB(255, 252, 255));
			sp2.m_sprite->End();
			

			d3ddev->EndScene();
			d3ddev->Present(NULL, NULL, NULL, NULL);
		}

	}


然后是基于距离的:原理很简单,两个点(图片中心)的距离小于等于两个图片的半径之和的时候就撞上了。

bool Collition_Dis(D3DXVECTOR2 pos1, D3DXVECTOR2 pos2, float dis)
{
	int deltaX = pos1.x - pos2.x;
	int deltaY = pos1.y - pos2.y;
	if ((deltaX * deltaX + deltaY * deltaY) < dis*dis)
	{
		return true; //撞上
	}
	else
		return false;
}


然后是看图片是否撞上,要获得图片的长和宽

int w1 = sp1.collitionRect.right - sp1.collitionRect.left;
int w2 = sp2.collitionRect.right - sp2.collitionRect.left;
int h1 = sp1.collitionRect.bottom - sp1.collitionRect.top;
int h2 = sp2.collitionRect.bottom - sp2.collitionRect.top;

D3DXVECTOR2 vec1(sp1.collitionRect.left + (int)(0.5f*w1), sp1.collitionRect.top + (int)(0.5f*h1));
D3DXVECTOR2 vec2(sp2.collitionRect.left + (int)(0.5f*w2), sp2.collitionRect.top + (int)(0.5f*h2));

canSP1Move = !Collition_Dis(vec1, vec2, (int)((w1 + w2)*0.5f)); //如果canSP1Move 为否,就说明撞了


上面两个就是基本的碰撞检测的两种方法。

这次由于好久不看了 感觉很简单的东西花了好长时间才弄好。。。感觉最近懵得很。。唉 慢慢来吧











你可能感兴趣的:(DirectX学习)