반응형

SDL과 2D Rigid Body Simulation Library Box2D를 사용해 보자.

 

아래 링크에서 Box2D를 다운로드 받고 빌드한다. (CMake를 설치하고 build.bat를 실행하면 된다)

빌드가 완료되면 비주얼 스튜디오 프로젝트를 만들고 Include, Library 디렉토리를 적당히 설정한다.

Box2D

 

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
#include <iostream>
#include "SDL.h"
#include "box2d/box2d.h"
 
int main(int argc, char* argv[]) {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED, 640480, SDL_WINDOW_RESIZABLE);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -10);
    SDL_Surface* playerSurface = SDL_LoadBMP("player.bmp");
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, playerSurface);
 
    // World 정의
    b2Vec2 gravity(0.0f, 9.8f);
    b2World world(gravity);
 
    // 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->/ 2, (float)playerSurface->/ 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 = { 040050010 };
 
    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 = { 300010480 };
 
    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, 255255255, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);
 
        // Ground 그리기
        SDL_SetRenderDrawColor(renderer, 22014020, SDL_ALPHA_OPAQUE);
        SDL_RenderFillRect(renderer, &groundRect);
 
        // Wall 그리기
        SDL_SetRenderDrawColor(renderer, 646464, SDL_ALPHA_OPAQUE);
        SDL_RenderFillRect(renderer, &wallRect);
 
        // Player 그리기        
        b2Vec2 playerPosition = playerBody->GetPosition();
        SDL_Rect destRect = { (int)playerPosition.x - playerSurface->/ 2,
            (int)playerPosition.y - playerSurface->/ 2, playerSurface->w, playerSurface->h };
        SDL_RendererFlip flip = SDL_FLIP_NONE;
        float angle = playerBody->GetAngle() * (180 / (float)M_PI);
 
        //printf("%4.2f %4.2f %4.2f\n", playerPosition.x, playerPosition.y, angle);
 
        SDL_RenderCopyEx(renderer, texture, NULL&destRect, angle, NULL, flip);
        SDL_RenderPresent(renderer);
    }
 
    SDL_DestroyTexture(texture);
    SDL_FreeSurface(playerSurface);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}
 

 

코드를 입력하고 빌드한다.

 

GIF 캡쳐 과정에서 화질이 많이 떨어졌지만 강체들의 물리 반응을 확인할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    // Player 정의
    b2BodyDef playerBodyDef;
    playerBodyDef.type = b2_dynamicBody;
    playerBodyDef.position.Set(0.0f, 0.0f);
    playerBodyDef.linearVelocity = b2Vec2(30.0f, 0.0f);
    playerBodyDef.angularVelocity = 1.0f;
    b2Body* playerBody = world.CreateBody(&playerBodyDef);
 
    //b2PolygonShape dynamicBox;
    //dynamicBox.SetAsBox((float)playerSurface->w / 2, (float)playerSurface->h / 2);
    b2CircleShape dynamicBox;
    dynamicBox.m_radius = (float)playerSurface->/ 2;
 
    b2FixtureDef fixtureDef;
    fixtureDef.shape = &dynamicBox;
    fixtureDef.density = 1.0f;
    fixtureDef.friction = 0.3f;
    fixtureDef.restitution = 0.5f;
 
    playerBody->CreateFixture(&fixtureDef);
 

 

Player 캐릭터의 충돌을 감지하는 Shape을 원으로 바꿔보자.

 

스프라이트는 사각형이지만 Circle Shape의 움직임을 보여준다.

 

※ 참고

Box2D Documentation

 

반응형
Posted by J-sean
: