[SDL] SDL Box2D Collision Contact Point & Normal Vector - Box2D 충돌 지점과 법선 벡터
C, C++ 2024. 1. 31. 00:40 |반응형
오브젝트가 충돌한 포인트를 확인해 보자.
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
#include <iostream>
#include "SDL.h"
#include "box2d/box2d.h"
class DebugDrawer : public b2Draw
{
public:
DebugDrawer(SDL_Renderer* renderer) {
this->renderer = renderer;
}
private:
SDL_Renderer* renderer;
void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {}
void DrawPoint(const b2Vec2& p, float size, const b2Color& color) {}
void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {
SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
SDL_FRect* rect = new SDL_FRect{ vertices[0].x, vertices[0].y, vertices[1].x
- vertices[0].x, vertices[3].y - vertices[0].y };
SDL_RenderDrawRectF(renderer, rect);
}
void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) {}
void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) {}
void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) {}
void DrawTransform(const b2Transform& xf) {}
};
int main(int argc, char* argv[]) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_RESIZABLE);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Surface* playerSurface = SDL_LoadBMP("player.bmp");
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, playerSurface);
// World 정의
b2Vec2 gravity(0.0f, 9.8f);
b2World world(gravity);
// DebugDraw 정의
DebugDrawer* debugDrawer = new DebugDrawer(renderer);
debugDrawer->SetFlags(b2Draw::e_shapeBit | b2Draw::e_jointBit |
b2Draw::e_centerOfMassBit | b2Draw::e_aabbBit | b2Draw::e_pairBit);
world.SetDebugDraw(debugDrawer);
// Player 정의
b2BodyDef playerBodyDef;
playerBodyDef.type = b2_dynamicBody;
playerBodyDef.position.Set(0.0f, 0.0f);
playerBodyDef.linearVelocity = b2Vec2(50.0f, 0.0f);
playerBodyDef.angularVelocity = 0.2f;
b2Body* playerBody = world.CreateBody(&playerBodyDef);
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox((float)playerSurface->w / 2, (float)playerSurface->h / 2);
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
fixtureDef.restitution = 0.5f;
playerBody->CreateFixture(&fixtureDef);
// Ground 정의
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0.0f, 400.0f);
b2Body* groundBody = world.CreateBody(&groundBodyDef);
b2PolygonShape groundBox;
groundBox.SetAsBox(500.0f, 0.0f);
SDL_Rect groundRect = { 0, 400, 500, 10 };
groundBody->CreateFixture(&groundBox, 0.0f);
// Wall 정의
b2BodyDef wallBodyDef;
wallBodyDef.position.Set(300.0f, 0.0f);
b2Body* wallBody = world.CreateBody(&wallBodyDef);
b2PolygonShape wallBox;
wallBox.SetAsBox(0.0f, 480.0f);
SDL_Rect wallRect = { 300, 0, 10, 480 };
wallBody->CreateFixture(&wallBox, 0.0f);
float timeStep = 1.0f / 500.0f;
int velocityIterations = 6;
int positionIterations = 2;
SDL_Event event;
bool quit = false;
while (!quit) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
quit = true;
break;
case SDL_KEYDOWN:
printf("Key pressed: %s\n", SDL_GetKeyName(event.key.keysym.sym));
if (event.key.keysym.sym == SDLK_SPACE) {
playerBody->SetTransform(b2Vec2(0.0f, 0.0f), 0.0f);
playerBody->SetLinearVelocity(b2Vec2(50.0f, 0.0f));
playerBody->SetAngularVelocity(0.2f);
}
if (event.key.keysym.sym == SDLK_ESCAPE)
quit = true;
break;
default:
break;
}
}
world.Step(timeStep, velocityIterations, positionIterations);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
// Ground 그리기
SDL_SetRenderDrawColor(renderer, 220, 140, 20, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(renderer, &groundRect);
// Wall 그리기
SDL_SetRenderDrawColor(renderer, 64, 64, 64, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(renderer, &wallRect);
// Player 그리기
b2Vec2 playerPosition = playerBody->GetPosition();
SDL_Rect destRect = { (int)playerPosition.x - playerSurface->w / 2,
(int)playerPosition.y - playerSurface->h / 2, playerSurface->w, playerSurface->h };
SDL_RendererFlip flip = SDL_FLIP_NONE;
float angle = playerBody->GetAngle() * (180 / (float)M_PI);
SDL_RenderCopyEx(renderer, texture, NULL, &destRect, angle, NULL, flip);
// DebugDraw 그리기
world.DebugDraw();
// 가장 마지막에 contact point 그리기
SDL_SetRenderDrawColor(renderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
for (b2Contact* contact = world.GetContactList(); contact; contact = contact->GetNext()) {
for (int i = 0; i < contact->GetManifold()->pointCount; i++)
{
b2Vec2 point = contact->GetFixtureA()->GetBody()->GetWorldPoint(
contact->GetManifold()->points[i].localPoint);
SDL_FRect rect = { point.x - 5, point.y - 5, 10, 10 };
SDL_RenderFillRectF(renderer, &rect);
}
}
// A very important point to note if you do this, is that the existence of a contact in these
// lists does not mean that the two fixtures of the contact are actually touching - it only means
// their AABBs are touching. If you want to know if the fixtures themselves are really touching
// you can use IsTouching() to check.
SDL_RenderPresent(renderer);
}
delete debugDrawer;
SDL_DestroyTexture(texture);
SDL_FreeSurface(playerSurface);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
|
코드를 입력하고 빌드한다.
이제 검은색으로 법선 벡터 그리는 코드를 추가하자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 가장 마지막에 contact point & 법선 벡터 그리기
for (b2Contact* contact = world.GetContactList(); contact; contact = contact->GetNext()) {
for (int i = 0; i < contact->GetManifold()->pointCount; i++)
{
b2Vec2 point = contact->GetFixtureA()->GetBody()->GetWorldPoint(
contact->GetManifold()->points[i].localPoint);
SDL_FRect rect = { point.x - 5, point.y - 5, 10, 10 };
SDL_SetRenderDrawColor(renderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRectF(renderer, &rect);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderDrawLineF(renderer, point.x, point.y,
point.x + contact->GetManifold()->localNormal.x * 20, point.y + contact->GetManifold()->localNormal.y * 20);
}
}
// A very important point to note if you do this, is that the existence of a contact in these
// lists does not mean that the two fixtures of the contact are actually touching - it only means
// their AABBs are touching. If you want to know if the fixtures themselves are really touching
// you can use IsTouching() to check.
|
코드를 수정하고 빌드한다.
속도(velocity) 벡터는 아래와 같은 코드로 표시할 수 있다.
1
2
3
4
|
SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
b2Vec2 position = playerBody->GetPosition();
SDL_RenderDrawLineF(renderer, position.x, position.y,
position.x + playerBody->GetLinearVelocity().x * 10, position.y + playerBody->GetLinearVelocity().y * 10);
|
※ 참고
반응형
'C, C++' 카테고리의 다른 글
[SDL] SDL 2D Camera - 2D 카메라 (0) | 2024.02.01 |
---|---|
[SDL] SDL Box2D Add Collision Shape - Box2D 충돌 감지 (1) | 2024.01.30 |
[SDL] SDL Box2D DebugDraw - 디버그 드로우 (1) | 2024.01.30 |
[SDL] SDL Box2D Collision - Box2D 충돌 (1) | 2024.01.30 |
[SDL] SDL Box2D - 물리 라이브러리 (0) | 2024.01.27 |