Uint32 SDL_GetTicks(void);아래에서 Ruby/SDL 코드가 SDL_getTicks()를 감싸 안는다.
static VALUE sdl_getTicks(VALUE mod) { return UINT2NUM(SDL_GetTicks()); }UINT2NUM 매크로는 Ruby 호출자가 사용하도록 C 리턴 타입을 Ruby Num 으로 변환하는데 사용된다. C 함수에 아무런 인자가 없다고 하더라도 이를 감싸안는 함수는 하나의 인자를 가진다는 것에 주의할 것. 객체 기반이 아니므로 인자가 전달되지 않으면 C는 함수 호출을 위해 무엇을 해야 될지를 모른다.
rb_define_module_function(mSDL, "getTicks", sdl_getTicks,0);Rb_define_module_function 메서드는 C 확장 코드를 루비 프로그래머가 사용 가능한 메서드로 대응 시킨다. 이 경우의 감싸안는 함수 sdl_getTicks()는 getTicks()로 맵핑된다. 왜 Ruby의 이름 규칙을 사용하지 않고 대소문자를 혼용하는 것일까? 라이브러리 함수를 감싸 안는 함수를 사용할 때 감싸안긴 라이브러리의 이름 규칙 사용을 좋아하는 개발자들이 있다. _를 사용하는 Ruby 스타일의 이름 규칙을 선호하는 개발자들을 위해 get_ticks는 별명 get_ticks, getTicks로 Ruby/SDL라이브러리내에 정의된다.
sprites = [] for i in 1..5 sprites << Sprite.new end sprites << MovableSp.newSprite는 임의로 움직이는 팔각형에 대한 클래스이고 MovableSp(Movable Sprite의 줄임 말)는 중앙에서 팔각형을 조종하는 클래스이다. 모든 sprite를 저장하기 위해 sprite배열을 생성한다. 처음 비디오 게임에 흥미를 갖기 시작한 이래로 나는 sprite가 판타지 게임의 숲 속의 요정과 같다고 생각했다. 나는 이 sprite가 SDL게임처럼 컨텍스트에서 사용됨을 알았으며 춤추는 요정을 표현하기 위해 왜 Sprite를 사용하지 않는지가 궁금했다. Sprite는 2D 객체에 대한 컴퓨터 그래픽의 표준 용어임을 알았고 위치는 전형적으로 프레임 사이에서 변한다.
class Sprite def initialize @x=rand(640) ... @dx=rand(11)-5 end def move @x += @dx if @x >= 640 then @dx *= -1 @x = 639 end if @x < 0 then @dx *= -1 @x = 0 end ... end def draw(screen) SDL.blitSurface($image,0,0,32,32,screen,@x,@y) end end초기화 과정에서 각 프레임에 대해 x축과 y축을 따라 Sprite의 움직이는 양을 표현하는 @dx와 @dy뿐만 아니라 sprite의 x와 y초기 좌표 또한 임의로 설정된다. move메서드는 @dx와 @dy값을 더해서 x와 y좌표에 값을 할당한다. Sprite가 화면 끝에 도달 하면(x좌표가 640과 같거나 큰 경우) Sprite의 방향을 변경하기 위해 @dx에 -1을 곱한다.(즉 x축을 기준으로 반대 방향이 설정됨). Draw 메서드에서 호출하는 SDL.blitSurface는 붉은색 팔각형을 display surface에 복사한다.
class MovableSp def initialize() @ud=@lr=0; end def move() @ud=@lr=0; @lr=-1 if SDL::Key.press?(SDL::Key::H) or SDL::Key.press?(SDL::Key::LEFT) @lr=1 if SDL::Key.press?(SDL::Key::L) or SDL::Key.press?(SDL::Key::RIGHT) @ud=1 if SDL::Key.press?(SDL::Key::J) or SDL::Key.press?(SDL::Key::DOWN) @ud=-1 if SDL::Key.press?(SDL::Key::K) or SDL::Key.press?(SDL::Key::UP) end def draw(screen) SDL.blitSurface($image, 0, 0, 32, 32, screen, 300+@lr*50,200+@ud*50) end endmove가 호출되면 @ud(위/아래)와 @lr(좌/우)를 0으로 초기화 한 다음 입력되는 화살표 키 값에 따라 @ud와 @lr값을 설정한다. draw메서드에 있는 마지막 두 인자는 MovableSp를 위한 새로운 x,y좌표를 나타낸다. 이 두 인자가 0이 되면 sprite는 화면 중앙에 그려진다. 그렇지 않은 경우 정해진 방향의 중앙으로부터 +/-50픽셀씩 움직인다.
while true while event = SDL::Event2.poll case event when SDL::Event2::Quit exit when SDL::Event2::KeyDown exit if event.sym == SDL::Key::ESCAPE end end screen.fillRect(0,0,640,480,0) SDL::Key.scan sprites.each {|i| i.move i.draw(screen) } screen.updateRect(0,0,0,0) end이 이벤트 루프는 사용자가 ESC키를 입력 하거나 x키를 입력하면 프로그램을 종료한다.(SDL::Event2::Quit이벤트는 사용자가 게임윈도우의 타이틀 바에 있는 x 버튼을 클릭하는 순간 발생한다) 각 프레임에서 move와 draw는 sprite의 각 멤버에 대해 호출된다. updateRect를 호출하면 화면이 갱신된다. 앞으로 이 글의 나머지 부분에서 이 와 같은 유형을 계속해서 보게 될 것이다. Sprite는 모양을 얼마나 변경 시키고 움직여야 되는지를 결정하고 이 이미지를 display surface에 복사한 다음 display는 이 변화를 반영하기 위해 화면을 갱신한다.
def start ... # Main loop; Loop until quit while !@@quit handle_input() # Handle keyboard input do_think() # Do calculations/thinking do_render() # Render everything ... end end def think(elapsedtime) return if elapsedtime > 100 $map.check_objs ... $entities.move(elapsedtime) $entities.collide_with($fires) $entities.collide_with($ship) $entities.collide_with($entities) $entities.collide_with($map) ... end def render $map.draw $ship.draw ... $camera.draw $fires.draw $entities.draw @console.draw @interface.draw ... endRUDL
SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp,Uint32 flags);RUDL의 DisplaySurface.new함수가 SDL_setVideoMode함수를 감싸 안고 있다. RUDL을 만든 Danny Van Bruggen은 새로운 display surface를 생성하고 호출된 SDL_setVideoMode에 결과를 리턴하는 메서드는 최소 놀람의 원칙(the principle of least surprise) 에 위배 된다고 생각했다. 그는 사용자가 새로운 DisplaySurface를 생성하면 DisplaySurface가 리턴 될 것이라고 기대한다고 생각했다. 그리고 그는 픽셀당 비트수를 표시하는 3번째 인자가 16으로 설정된 경우와 랜더링 시스템을 나타내는 마지막 인자가 SWSURFACE로 설정된 경우 4가지 인자 모드를 넘겨 줘야 한다는 것을 생각하지 못했다.
# RUDL의 setVideoMode랩퍼에 대한 간단한 호출 display = DisplaySurface.new([640,480]) # Ruby/SDL의 SetVideoMode 랩퍼에 대한 간단한 호출 display = SDL::setVideoMode(640,480,16,SDL::SWSURFACE)아래에 RUDL이 초기화 될 때 DisplaySurface.new를 랩퍼에 맵핑시키는 코드와 SDL_SetVideoMode를 감싸 안는 RUDL코드를 발췌해 놓았다.
static VALUE displaySurface_new(int argc, VALUE* argv, VALUE self) { ... surf = SDL_SetVideoMode(w, h, depth, flags); currentDisplaySurface = Data_Wrap_Struct (classDisplaySurface, 0, 0, surf); return currentDisplaySurface; }) rb_define_singleton_method(classDisplaySurface, "new", displaySurface_new, -1);RUDL로 패키징된 가장 유용한 자료들 중의 하나는 Martins Stannard가 유명한 네온 헬륨 OpenGL 튜토리얼을 Ruby로 옮겨놓은 것이다. 랜더링 시스템으로 OpenGL을 사용하지만 이벤트 처리와 같은 이외의 모든 것은 Ruby를 사용한다. RUDL에 관해 이야기를 하고 있으므로 어떤 OpenGL API가 이점과 같은지를 보여주는 것이 이치에 맞을 것이다.
display = Proc.new { GL.Clear(GL::COLOR_BUFFER_BIT| GL::DEPTH_BUFFER_BIT) GL.Color(1.0, 1.0, 1.0) GL.LoadIdentity() GL.Translate(-1.5, 0.0, -6.0) # 삼각형 그리기 GL.Begin(GL::POLYGON) GL.Color3f(1.0, 0.0, 0.0) GL.Vertex3f(0.0, 1.0, 0.0) GL.Color3f(0.0, 1.0, 0.0) GL.Vertex3f(1.0,-1.0, 0.0) GL.Color3f(0.0, 0.0, 1.0) GL.Vertex3f(-1.0,-1.0, 0.0) GL.End() GL.Translate(3.0,0.0,0.0) }
이전 글 : "풀타임 블로거" 태우씨의 "미코노미 라이프"
다음 글 : 루비로 게임 만들기 1-2
최신 콘텐츠