< VB DirectX8 2D Games Sample >
< 비주얼베이직 다이렉트8을 이용한 2D 게임 만들기>
이 글은 비주얼베이직 초보들을 위한 것이다.
비베로 윈도우 프로그램 코딩은 대충 하겠는데 게임 만드는 법을 모르겠다고?
그런 당신을 위해 다이렉트X8이 준비되어있다.
첨부된 소스를 받아서 VB 6.0으로 불러와서 실행시켜 보자.
다이렉트X8은 다이렉트X7와 사용의 구조가 다르다.
오히려 다이렉트X9와 가깝다.
나타나는 모습은 비슷하지만 다이렉트X8부터는 3D가 기본이 되면서,
3D상에 평면을 그리고 그 평면 위에 그림을 찍어내는 방식을 쓴다.
<이 소스를 이해하는 법>
우선 다이렉트X8에 대해 기초가 없는 사람들을 위하여
소스를 붙여보겠다.
1. Form1의 Form_load() 부분 소스
|
Private Sub Form_Load() ‘미리 그림관련 변수들 넣어둔다. ‘——————————————– FULLSCREEN = False Form1.Show ‘DirectX 초기화 ‘게임 시작전 준비할것들. ‘기타 초기화 ‘Main Loop
Do While True If GetTickCount – Start > 25 Then ‘1초에 40번 Loop |
(1) FULLSCREEN = False
이 부분을 True로 하면 화면은 전체화면으로 실행된다.
설정상 800 * 600 해상도로 되어있는데, 나중에 소스를 고치면 수정가능하다. ex 800,600 -> 640, 480
(2) Do While
다이렉트X8로 만든 게임들은 Do문이 끊임없이 돌아가게 되는데,
따라서 화면상의 그림이 지속적으로 끊김없이 뜨는 것이다.
아마 게임을 만들려고, Form상에 그래픽박스를 그려다가 좌표를 옮기면 뚝뚝 끊어지는 현상과는
전혀 차원이 다를 것이다.
중요한것은 여기서 Render 부분 안쪽만 고쳐주면 게임이 수정된다.
2. Form1의 Render() 부분 소스
|
Private Sub Render() FullScreenClear RGB(255, 0, 0) ‘배경 파란색으로 비우고, D3DDev.BeginScene SpriteObject.Begin ‘그림 시작 ‘———-”———-”———-”———-”———-”———-‘ ‘배경위의 반투명 출력 ‘작은 사람1 출력 ‘캐릭터2 출력(500번) ‘———-”———-”———-”———-”———-”———-‘ SpriteObject.End ‘그림 끝 D3DDev.EndScene DrawAll ‘화면 그림 |
여기서 다른 부분은 아직 볼 필요가없고, 점섬 밑에 부분을 보자.
배경 출력, 배경위의 반투명 출력… 등으로 주석이 달려있다.
각 줄마다 Drawing 함수가 있는데, 그림을 출력하려고 만들어둔 것이다.
사용법은,
Call Drawing(출력할 x좌표, 출력할 y좌표, 스프라이트 변수명, 그림의 x좌표, 그림의 y좌표, 그림의 폭, 그림의 높이)
이다.
소스의 각 숫자들을 조금씩 바꿔서 실행해보며 이해해보자.
3. 이해하는 순서
소스는 총 4개로 나뉘어있는데
폼 Form1 소스, 모듈 Draw 소스, 모듈 Music 소스, 모듈 Sound 소스이다.
우선적으로 Form1 소스를 이해하도록 하며, 그중에서도 Render 부분 소스를 이해하도록 하자.
숫자를 몇개 바꾸거나, 일정부분을 주석처리하면서 실행해보면 쉽게 배울 수 있다.
Music, Sound 부분은 필요하다면 기억한다. Music는 Midi파일을 재생하는데 필요하고,
Sound는 Wav파일 재생에 필요하다.
필요없다면 이 모듈 두개는 삭제한다음 실행할 때 오류나는 부분만 지워내도 좋다.
다음으로 Draw부분을 이해해보자. 이해하기 힘들것이다.
왜냐하면 이 부분은 나도 이해가 안간다.
소스를 전부 이해할 필요는 절대 없다. 부분적으로 쓸 부분만 찾아서 쓰면 되는 것이다.
Draw 모듈 중에서도 Public Sub LoadImageFiles(), Public Sub ScreenShutdown(),
스프라이트 선언부 만 이해해도 좋다.
간단히 설명해서, 새로운 그림파일을 게임에 삽입하고 싶은가? 아래대로 해보라.
(1) ‘스프라이트 선언부’ 에 아래처럼 추가한다. 그냥 그림을 기억하는데 필요한 변수라고 이해하자.
Public DDS1 As Direct3DTexture8
(2) ‘Public Sub LoadImageFiles()’ 에 아래처럼 추가한다. 그리고 폴더안에 새그림.bmp를 넣는다.
Set DDS1 = LoadTexture(App.Path & “\새그림.bmp”)
(3) ‘Public Sub ScreenShutdown()’ 에 아래처럼 추가한다. 종료할때 메모리를 정리해줄 것이다.
Set DDS1 = Nothing
Draw 모듈에서 손 볼 것은 끝났다. From1로 가자.
(4) Form1의 ‘Private Sub Render()’ 의 점선 사이에 아래와 같이 넣는다.
Call Drawing(30, 30, DDS1, 40, 40, 50, 50, False)
이 함수의 뜻은, 화면의 30,30 좌표에 그림을 찍으라는 것이다.
DDS1(새그림.bmp)의 그림이 40,40부터 가로 50, 세로 50 만큼 잘려서 입력될 것이다.
Drawing 함수는 내가 임의로 만든 변수인데,
만약 별로인것 같다면 Drawing 함수의 안쪽을 이해한 후 지우고 자체적으로 활용해도 좋다.
4. 이소스로 당신이 할 수 있는것
1. DX8을 이용해 화면에 맵과 캐릭터를 찍어낸다.
2. 반투명 출력을 한다. (그 외 알파블랜드 기능들은 추가가 안되어있다. 혹시 이 소스 기반으로 추가해주실 분있으면 공유해요)
3. 음악재생, 사운드 재생을 한다.
4. 이해 못해도 좋다. 써라! 아마추어 게임을 만들자!
이런 소스가 별거 아니라고 생각할 수가 있는데,
날이 갈수록 VB 소스를 얻기 어려워지고, 돌아다니는 소스들도 고수용이 많다.
이 마당에 막상 소스를 얻어도 너무 부분적인 소스여서 막상 실행이 안된다거나
이해하기 어렵도록 복잡하거나 방대하다.
비주얼 베이직 초보들은 모두 힘내시길.
(소스 수정, 소스 무단배포, 소스 활용 자유)
* 사실 이 소스는 내가 만든게 아니라, 여러 사람들의 유용한 소스들을 짜깁기한 것이다.
실제 프로그래밍 할때도 뭐든지 자신이 만들려고 할게 아니라,
복사할 수 있는건 하는게 효율적이다.
* 본 소스에 는 아래와 같은 내용이 들어있습니다. (명령어나 함수로 검색하는 이들을 위해)
‘<폼 Form1.frm>
Private Declare Function GetTickCount Lib “kernel32” () As Long ‘1ms 시계 (1/1000초)
Private Declare Function GetKeyState Lib “user32” (ByVal nvirkey As Long) As Integer
Dim xxx, yyy
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Shutdown
End Sub
Public Sub Shutdown()
‘모든 오브젝트 정리 후 종료
ScreenShutdown
SoundShutdown
MusicShutdown
End
End Sub
Private Sub Form_Load()
‘미리 그림관련 변수들 넣어둔다.
‘기본 값 사용
VctScl.X = 1 ‘1배
VctScl.Y = 1 ‘1배
VctRot.X = 0 ‘스프라이트 중심이어야 함
VctRot.Y = 0 ‘스프라이트 중심이어야 함
RotAng = 0 ‘0도 회전 = 회전 없음
‘——————————————–
FULLSCREEN = False
Form1.Show
‘DirectX 초기화
InitDirectX3D_Screen hwnd
InitDirectXSound hwnd
InitDirextXMusic hwnd
‘게임 시작전 준비할것들.
‘이미지 불러오기, 사운드 불러오기
LoadImageFiles
LoadSoundFiles
‘기타 초기화
Call PlayMusic(App.Path & “\Music99.MID”) ‘음악켠다
‘Main Loop
Static Start As Long
Start = GetTickCount()
Do While True
If GetTickCount – Start > 25 Then ‘1초에 40번
KeyState
Render
DoEvents
Start = GetTickCount
End If
Loop
End Sub
Private Sub Render()
FullScreenClear RGB(255, 0, 0) ‘배경 파란색으로 비우고,
D3DDev.BeginScene
SpriteObject.Begin ‘그림 시작
‘———-”———-”———-”———-”———-”———-‘
‘배경 출력
Call Drawing(0, 0, DDSTiles, 0, 0, 800, 600, False)
‘배경위의 반투명 출력
Call Drawing(50, 50, DDSTiles, 0, 0, 400, 300, True)
‘작은 사람1 출력
Call Drawing(0, 0, DDSSprite, 0, 0, 50, 50, False)
‘캐릭터2 출력(500번)
For i = 1 To 500
Call Drawing(xxx + i, yyy + i, DDSSprite, 50, 50, 50, 50, False)
Next i
‘———-”———-”———-”———-”———-”———-‘
SpriteObject.End ‘그림 끝
D3DDev.EndScene
DrawAll ‘화면 그림
End Sub
‘키입력
Private Sub KeyState()
If GetKeyState(vbKeyRight) < 0 Then
xxx = xxx + 10
End If
If GetKeyState(vbKeyLeft) < 0 Then
xxx = xxx – 10
End If
If GetKeyState(vbKeyUp) < 0 Then
yyy = yyy – 10
End If
If GetKeyState(vbKeyDown) < 0 Then
yyy = yyy + 10
Call PlaySound(SoundList(0), False, False) ‘사운드 켠다
End If
If GetKeyState(vbKeyEscape) < 0 Then
bEnd = True
End If
End Sub
‘<모듈 Draw.bas>
‘DirectX 화면 출력
Option Explicit
Option Base 0 ‘배열 0부터 시작
‘화면 크기
Public Const SCREENWIDTH As Long = 800
Public Const SCREENHEIGHT As Long = 600
Public FULLSCREEN As Boolean
Private DX As New DirectX8
Private D3DX As New D3DX8
Private D3D As Direct3D8
Private Dispmode As D3DDISPLAYMODE
Public D3DDev As Direct3DDevice8
Public SpriteObject As D3DXSprite
‘표면 선언들
Private BackBuffer As Direct3DSurface8 ‘2중버퍼
‘Public DDSTiles2 As Direct3DSurface8 ‘버퍼를 제외한, 나머지 표면 선언은 개인적으로 안쓰기로함
‘참고 : 화면에 표면 그리는법 (개인적으로 느려서 안쓰기로함) ‘Call ImageCopy(DDSTiles, RC, x, y)
‘스프라이트 선언부———-
Public DDSTiles As Direct3DTexture8
Public DDSSprite As Direct3DTexture8
‘——————————
‘그림관련 변수들
Public VctScl As D3DVECTOR2 ‘크기 확대(보통 사용하지 않음)
Public VctRot As D3DVECTOR2 ‘회전 중심(보통 사용하지 않음)
Public RotAng As Single ‘회전 각도(보통 사용하지 않음)
Public VctPnt As D3DVECTOR2 ‘그릴 위치
‘사각형
Public RC As Rects
Public Type Rects
Left As Long
Top As Long
Width As Long
Height As Long
End Type
Public Sub LoadImageFiles()
‘스프라이트 불러오기
Set DDSTiles = LoadTexture(App.Path & “\Background.bmp”)
Set DDSSprite = LoadTexture(App.Path & “\Char.bmp”)
‘표면 불러오기 (개인적으로 안쓰기로함)
‘Set DDSTiles2 = LoadSurface(App.Path & “\Background.bmp”, 640, 480)
End Sub
Public Sub ScreenShutdown()
‘프로그램 종료 전에 1회 실행
‘표면 및 스프라이트 삭제
Set DDSSprite = Nothing
Set DDSTiles = Nothing
‘오브젝트 삭제
Set D3DDev = Nothing
Set D3D = Nothing
Set DX = Nothing
End Sub
Public Sub FullScreenClear(lColor As Long)
‘화면 전체를 한 색상으로 칠함
‘lColor = RGB(Blue, Green, Red)
‘lColor = &HRRGGBB
D3DDev.Clear 0, ByVal 0, D3DCLEAR_TARGET, lColor, 1, 0
End Sub
Public Sub DrawAll()
‘화면에 BackBuffer의 그림을 표시함
D3DDev.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub
‘Drawing함수 쓰는법
‘(화면상 출력할 X좌표, 화면상 출력할 Y좌표, 가져올 스프라이트, 잘라낼 영역 X, 잘라낼 영역 Y, 잘라낼 영역 폭, 잘라낼 영역 높이)
Function Drawing(ByVal S_X As Long, ByVal S_Y As Long, SourceTexture As Direct3DTexture8, ByVal S_Left As Long, ByVal S_Top As Long, ByVal S_Width As Long, ByVal S_Height As Long, ByVal ALPHAv As Boolean)
Static SrcRct As DxVBLibA.RECT
SrcRct.Left = S_Left
SrcRct.Right = S_Left + S_Width
SrcRct.Top = S_Top
SrcRct.bottom = S_Top + S_Height
VctPnt.X = S_X
VctPnt.Y = S_Y
If ALPHAv = True Then
Call SpriteObject.Draw(SourceTexture, SrcRct, VctScl, VctRot, RotAng, VctPnt, D3DColorARGB(160, 255, 255, 255))
Else
Call SpriteObject.Draw(SourceTexture, SrcRct, VctScl, VctRot, RotAng, VctPnt, D3DColorARGB(255, 255, 255, 255))
End If
End Function
Public Sub MakeEmptySurface(ByRef SurfName As Direct3DSurface8, ByRef lWidth As Long, lHeight As Long)
‘빈 도화지만 만드는 곳(스크롤 버퍼 만들 때 이용)
Set SurfName = D3DDev.CreateImageSurface(lWidth, lHeight, Dispmode.Format)
If SurfName Is Nothing Then End
End Sub
Public Function LoadSurface(ByVal filename As String, ByVal Width As Long, ByVal Height As Long) As Direct3DSurface8
‘그림을 지정한 크기로 늘려서 읽어 옴
Dim surf As Direct3DSurface8 ‘임시 사용
Set LoadSurface = Nothing
Set surf = D3DDev.CreateImageSurface(Width, Height, Dispmode.Format)
If surf Is Nothing Then
MsgBox “표면 만들기 중 에러!”
Exit Function
End If
‘실제로 BMP 파일 읽는 곳
D3DX.LoadSurfaceFromFile surf, ByVal 0, ByVal 0, filename, ByVal 0, D3DX_DEFAULT, 0, ByVal 0
If surf Is Nothing Then
MsgBox filename & “읽는 중에 에러”
Exit Function
End If
Set LoadSurface = surf
End Function
Public Function LoadTexture(ByVal filename As String) As Direct3DTexture8
‘스프라이트 읽기
Dim tex As Direct3DTexture8 ‘임시 사용
Set LoadTexture = Nothing
‘실제로 그림을 읽어오는 함수
Set tex = D3DX.CreateTextureFromFileEx(D3DDev, filename, _
D3DX_DEFAULT, D3DX_DEFAULT, 1, 0, D3DFMT_UNKNOWN, _
D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, _
&HFF00FF, ByVal 0, ByVal 0)
‘&HFF00FF = 분홍색(바꿀 수 있음)
‘실제로 그림을 읽어오는 함수
If tex Is Nothing Then
MsgBox filename & “읽는 중 에러”, vbOKOnly, “Error”
Exit Function
End If
Set LoadTexture = tex
End Function
Public Sub InitDirectX3D_Screen(ByVal hwnd As Long)
‘프로그램 시작할 때 1회 실행
Set D3D = DX.Direct3DCreate()
If D3D Is Nothing Then
MsgBox “DirextX3D 만들기 중 에러!”
End
End If
‘화면 표시 장치 파라미터 설정
D3D.GetAdapterDisplayMode D3DADAPTER_DEFAULT, Dispmode
Dim d3dpp As D3DPRESENT_PARAMETERS ‘Object 설정용 변수들
d3dpp.BackBufferFormat = Dispmode.Format
d3dpp.hDeviceWindow = hwnd ‘form1의 번호
d3dpp.BackBufferCount = 1 ‘2중버퍼 1개
d3dpp.BackBufferWidth = SCREENWIDTH ‘화면 폭
d3dpp.BackBufferHeight = SCREENHEIGHT ‘화면 키
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC
d3dpp.Windowed = 1 ‘창 상태(개발용)
If FULLSCREEN = True Then d3dpp.Windowed = 0 ‘전체 화면(배포용)
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE
d3dpp.AutoDepthStencilFormat = D3DFMT_D32
‘화면 표시 장치 만들기
Set D3DDev = D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
If D3DDev Is Nothing Then
MsgBox “DirextX3D Device 만들기 중 에러!”
End
End If
‘2중버퍼(=투명레이어) 생성
Set BackBuffer = D3DDev.GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO)
‘스프라이트 그리는 객체 생성
Set SpriteObject = D3DX.CreateSprite(D3DDev)
End Sub