您的位置:首页 > 其它

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

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

#include"MyD3D.h"
//#include<windows.h>

//窗口回调函数
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 为否,就说明撞了

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

这次由于好久不看了 感觉很简单的东西花了好长时间才弄好。。。感觉最近懵得很。。唉 慢慢来吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  DirectX9