Chapter 6
6. Basic Game Design
6.1 The basic sprite system
From the previous exercise, we have a program where we could move two helicopter sprites around the screen, and outside it. There are two improvements we want to do at this point; first, we want the helicopter to stay on screen; second, we want the helicopter's ceiling fan to look like it's moving. To make it easier to accomplish similar things for the other objects we are soon going to create, we will implement some more features into the base class, and make the chopper class use these. We will also make a background class. The code now looks like this:
이전 예에서, 우리는 두개의 헬리콥터가 화면을 가로질러서 화면 밖으로 나가버리는 프로그래을 만들었다. 거기에 두개의 바꾸고 싶은것이 보인다: 첫째, 우리는 헬리콥터를 화면에 머무르게 하고 싶다. 둘째, 우리는 헬리콥터의 날개가 움직이는것 처러 보이고 싶다.(이거 맞는 번역임??) 우리가 앞으로 만들 다른 객체들에도 비슷한 내용을 적용하기 위해서, 우리는 베이스 클래스에 몇가지 기능을 더 구현할 것이다. 그리고 chopper 클래스가 베이스 클래스에 추가된 기능을 사용할 것이다. 또한, 우리는 background 클래스도 만들것이다. 이 내용을 모두 적용한 코드는 다음과 같다:
어플리케이션을 작성하는 도중에, 물론 게임도 어플리케이션의 일종이므로 예외가 아니다, 코드 구조를 바꾸고 하는것은 자주 발생하는 일이다. 우리가 지금 한것이 바로 그것이다. 우리는 RLE 스프라이트를 그리는 코드및 관련 코드를 베이스 클래스로 옮겼다. 베이스 클래스의 clippos() 는 어떤 오브젝트도 땅(ground)아래로 떨어지지 않도록 막아준다. outside()는 함수 이름처럼, 오브젝트가 (가로)화면 밖으로 빠져나갔는지 체크해준다. 가로는 우리가 게임에서 스크롤 시킬 방향이다. 뭐, 어쨌든. 그리고 chopper()는 clippos()를 오버라이드 했는데, 상하및 좌우 스크린을 벗어나지 않도록 수정했다. (참고로, 코드에서 보면 3면만 처리하도록 해 놓고, 마지막 4번째 면은 상속받은 clippos()를 호출해서 처리해 버렸다.) chopper2 는 move()를 오버라이드 해서 움직이는 방향을 반대로 했다. 따라서 animate() 를 통짜로 수정할 필요가 없어져 버렸다. 우리는 또한, draw()를 오버라이드 해서 backdrop(배경)을 그리는 클래스를 생성했고, 클래스 인스턴스를 스프라이트 리스트에 집어 넣었다. 이로인해 게임 루프가 훨씬 간단해졌다. (... 잘 이해는 안되지만, 간단해 졌다고 하니 뭐;;)
6.2 Dynamic Sprites
You might also have noticed that we have made the animate() method return a bool. This was done as a preparation for the dynamic sprites we are now going to create. If a sprite is created dynamically, it should also be deleted when it is no longer needed, to avoid running out of memory. To signal this, we will let the animate() method return TRUE when the sprite is no longer needed. So, let's try it by writing a class that will handle the lethal stuff we are going to throw at our poor enemies, and that signals that it should be deleted when it hits the ground.
당신이라면 (당연하게도) animate 메쏘드가 bool(true/false값만 가지는 타입)을 리턴하도록 했다는것을 알아차렸을 것이다. 이것은 우리가 앞으로 만들 다이나믹 스프라이트를 위해 미리 준비한 것이다. 만약 스프라이트가 동적으로 생성된다면, 스프라이트가 불필요해지면, 메모리를 낭비를 피하기위해, 삭제되어야 할것이다. 이걸 어떻게 알아차릴까? 그러기 위해서 우리는 스프라이트가 불필요해지면 animate() 메쏘드가 TRUE를 리턴하도록 할것이다. 따라서, 우리는 우리 미사일에 맞은 불쌍한 적(enemy)은 앞서 설명한 방법으로 객체를 삭제하도록 할 것이다.
Since it's a good idea to have defined the velocity at which our bombs will fall from the helicopter, we will add this somewhere at the top:
우리 헬리콥터에서 썰어지는 미사일의 속도를 define하는것은 꽤나 괜찮은 생각같다. 따라서 아래와 같은 코드를 소스의 상단부 어딘가에 적어놓을 것이다.
그리고, 우리는 weaponry(무기류) 클래스를 추가할 것이다. 이 클래스는 chopper::animate() 앞에 추가하자.
엔터가 눌렸을때 폭탄을 투하하기 위해서, chopper::animate()를 다음과 같이 수정하자.
마지막으로, 더이상 불필요한 스프라이드를 삭제하기 위해서, 우리는 메인 게임 루프에서 animation코드를 다음처럼 바꿀것이다.
이것은 현재 스프라이트를 저장해 놓고 animate()를 호출한 다음에, 리턴값이 true라면 리스트에서 제거해 버리고 다음 element로 넘어가는 것이다. 그리고 스프라이트는 삭제를 해 버린다. 리턴값이 false라면 이전에 했던거랑 동일하게 동작하는거고...
With this, the player is now able to pour out bombs at high volume, which is definitely going to be of much value against his enemies, once he gets any.
이것과 함께, 플레이어는 이제 폭탄을 떨굴수 있다. (...영어가 짧아 번역아 안되..됩니다..T^T)
6.3 Moving Bomb Launch
A somewhat unrealistic thing about the way we have launched these bombs, is their launch velocity when the helicopter is moving, which is currently absolute, and thus exactly the same as if the helicopter stood still. In our game, we want some more realism than that (even if the extreme payload of explosives the player has at his disposal is totally unrealistic), so we will make the initial bomb velocity relative to the current helicopter velocity. This also makes it much more fun to try to launch bombs as if they were projectiles by jerking the helicopter forward and upward just as the bomb is launching.
근데, 뭔가 비현실적인것이 있는데 폭탄을 떨구면 헬기의 속도에 맞춰서 곡선으로 떨어져야 한다. 근데, 우리 프로그램은 헬기가 움직이지 않더라도 폭탄은 곡선으로 떨어진다. (뭐, 물론 잔탄수가 없는것도 말이 안되는거긴 하다만..) 하여간, 그래서 우리는 비행기 속도에 맞춰서 폭탄의 초기 속도를 설정할 것이다. 이것은 게임을 좀더 재미있게 만들것이다. (...뭐 비슷한 내용인거 같다;;)
First, to accurately calculate how much the helicopter has moved (its current velocity), we will let the base class keep track of what the last position was, by its animate() method.
우선, 헬기의 속도를 계산하기 위해서(현재 속도) 우리는 베이스 클래스의 animate() 메쏘드에서 헬기의 마지막 좌표를 계속 추적할 것이다.
물론, 실제 동작하기 위해서는 상속받은 클래스에서 animate()를 호출해야 한다. chopper클래스의 animate() 메쏘드의 경우, 헬기의 속도를 폭탄의 속도에 더해줘서 헬기속도의 두배가 되도록 한다. (아.. 이것도 발번역.. T^T)
6.4 Mouse Control
Another thing that I personally find makes the program much more fun to mess with, is to control the helicopter with the mouse. This enables it to move around the screen and launch bombs with ludicrous velocities, but still, why not have all the fun we can get? Unfortunately, this means we will have to dispense with the second helicopter. The full code is now:
개인적으로 프로그램을 재미있게 할 방법으로 헬기를 마우스로 컨트롤 해보면 어떨까 하고 생각해 봤다. 이렇게 하면 헬기를 움직일수 있고 폭탄에 황당하리만한 속도를 줄수도 있다.(!!) 그렇다면, 왜 지금까지 안했을까? 불행하게도, 이것은 우리가 두번째 헬기를 만들수 없다는 것이다. (대충 '2인용 게임을 만들수 없다`. 로 해석되는데.. 흠;;)
이글루스 가든 - 하루에 한 장~ 꾸준히 번역하기
6. Basic Game Design
6.1 The basic sprite system
From the previous exercise, we have a program where we could move two helicopter sprites around the screen, and outside it. There are two improvements we want to do at this point; first, we want the helicopter to stay on screen; second, we want the helicopter's ceiling fan to look like it's moving. To make it easier to accomplish similar things for the other objects we are soon going to create, we will implement some more features into the base class, and make the chopper class use these. We will also make a background class. The code now looks like this:
이전 예에서, 우리는 두개의 헬리콥터가 화면을 가로질러서 화면 밖으로 나가버리는 프로그래을 만들었다. 거기에 두개의 바꾸고 싶은것이 보인다: 첫째, 우리는 헬리콥터를 화면에 머무르게 하고 싶다. 둘째, 우리는 헬리콥터의 날개가 움직이는것 처러 보이고 싶다.(이거 맞는 번역임??) 우리가 앞으로 만들 다른 객체들에도 비슷한 내용을 적용하기 위해서, 우리는 베이스 클래스에 몇가지 기능을 더 구현할 것이다. 그리고 chopper 클래스가 베이스 클래스에 추가된 기능을 사용할 것이다. 또한, 우리는 background 클래스도 만들것이다. 이 내용을 모두 적용한 코드는 다음과 같다:
#include <allegro.h>In the course of writing any application, and games are no exception, there are often times when parts of the code has to be rethought and rewritten. That is essentially what we have done here. We have moved the RLE sprite drawing code and some coordinate manipulation code into the base class. The base class' default clippos() makes sure no object falls below ground level. Its default outside() checks if an object is totally outside the screen in the horizontal direction, since this is the direction we want the game to scroll. chopper() overrides clippos() to keep the helicopter totally on-screen. (Note that it takes care of only three of the edges, and calls upon the inherited clippos() to take care of the fourth.) chopper2 overrides the move() method to reverse the direction moved, thus avoiding having to replace the entire animate() method. We have also created the background class that overrides the default draw() method to draw the backdrop, and put an instance of this class into the sprite list, thus simplifying the game loop even further.
#include <stl.h>
#include "tutorial.h"
#define MIN_Y 8
#define MAX_Y 180
DATAFILE*data;
BITMAP*backdrop,*framebuf;
class sprite {
protected:
fix X,Y;
RLE_SPRITE*image;
public:
sprite(fix _X,fix _Y) { X=_X; Y=_Y; image=NULL; }
sprite(fix _X,fix _Y,RLE_SPRITE*img) { X=_X; Y=_Y; image=img; }
virtual ~sprite() {}
virtual void draw(BITMAP*dest) {
draw_rle_sprite(dest,image,X,Y);
}
virtual void clippos() { if (Y+image->h>MAX_Y) Y=MAX_Y-image->h; }
virtual void move(fix DX,fix DY) { X+=DX; Y+=DY; clippos(); }
virtual void place(fix NX,fix NY) { X=NX; Y=NY; clippos(); }
virtual int outside(fix _X,fix _Y) { return (_X<-image->w)||(_X>=SCREEN_W); }
virtual bool animate() { return FALSE; }
};
typedef list<sprite*> sprite_list;
sprite_list sprites;
class background : public sprite {
public:
background() : sprite(0,MIN_Y) {}
virtual void draw(BITMAP*dest) {
blit(backdrop,dest,0,0,X,Y,backdrop->w,backdrop->h);
}
};
class chopper : public sprite {
protected:
int frame;
public:
chopper(fix _X,fix _Y)
: sprite(_X,_Y,(RLE_SPRITE*)data[TUT_CHOPPER].dat) { frame=0; }
virtual void clippos() {
if (X<0) X=0;
if (X+image->w>SCREEN_W) X=SCREEN_W-image->w;
if (Y<MIN_Y) Y=MIN_Y;
sprite::clippos();
}
virtual bool animate();
};
bool chopper::animate()
{
fix DX=0,DY=0;
if (key[KEY_LEFT]||joy_left) --DX;
if (key[KEY_RIGHT]||joy_right) ++DX;
if (key[KEY_UP]||joy_up) --DY;
if (key[KEY_DOWN]||joy_down) ++DY;
move(DX,DY);
if (frame) { image=(RLE_SPRITE*)data[TUT_CHOPPER1].dat; frame=0; }
else { image=(RLE_SPRITE*)data[TUT_CHOPPER2].dat; frame=1; }
return FALSE;
}
class chopper2 : public chopper {
public:
chopper2(fix _X,fix _Y) : chopper(_X,_Y) {}
virtual void move(fix DX,fix DY) { X-=DX; Y-=DY; clippos(); }
};
int main()
{
allegro_init();
install_keyboard();
initialise_joystick();
data=load_datafile("tutorial.dat");
set_gfx_mode(GFX_VGA,320,200,0,0);
set_palette((RGB*)data[TUT_GAMEPAL].dat);
// create 320x192 backdrop
backdrop=create_bitmap(320,192);
for (int Y=0; Y<128; Y++) hline(backdrop,0,Y,319, (Y/2)+128);
for (int Y=128; Y<192; Y++) hline(backdrop,0,Y,319, ((Y-128)/2)+192);
// create 320x200 double buffer
framebuf=create_bitmap(320,200);
clear(framebuf);
background Back;
chopper Hero(50,100);
chopper2 AnotherHero(250,50);
sprites.push_back(&Back);
sprites.push_back(&Hero);
sprites.push_back(&AnotherHero);
while (!key[KEY_ESC]) {
// draw sprites
{
sprite_list::const_iterator spr=sprites.begin();
while (spr!=sprites.end()) {
(*spr)->draw(framebuf);
spr++;
}
}
// display frame
vsync();
blit(framebuf,screen,0,0,0,0,320,200);
// animate sprites
poll_joystick();
{
sprite_list::iterator spr=sprites.begin();
while (spr!=sprites.end()) {
(*spr)->animate();
spr++;
}
}
}
return 0;
}
어플리케이션을 작성하는 도중에, 물론 게임도 어플리케이션의 일종이므로 예외가 아니다, 코드 구조를 바꾸고 하는것은 자주 발생하는 일이다. 우리가 지금 한것이 바로 그것이다. 우리는 RLE 스프라이트를 그리는 코드및 관련 코드를 베이스 클래스로 옮겼다. 베이스 클래스의 clippos() 는 어떤 오브젝트도 땅(ground)아래로 떨어지지 않도록 막아준다. outside()는 함수 이름처럼, 오브젝트가 (가로)화면 밖으로 빠져나갔는지 체크해준다. 가로는 우리가 게임에서 스크롤 시킬 방향이다. 뭐, 어쨌든. 그리고 chopper()는 clippos()를 오버라이드 했는데, 상하및 좌우 스크린을 벗어나지 않도록 수정했다. (참고로, 코드에서 보면 3면만 처리하도록 해 놓고, 마지막 4번째 면은 상속받은 clippos()를 호출해서 처리해 버렸다.) chopper2 는 move()를 오버라이드 해서 움직이는 방향을 반대로 했다. 따라서 animate() 를 통짜로 수정할 필요가 없어져 버렸다. 우리는 또한, draw()를 오버라이드 해서 backdrop(배경)을 그리는 클래스를 생성했고, 클래스 인스턴스를 스프라이트 리스트에 집어 넣었다. 이로인해 게임 루프가 훨씬 간단해졌다. (... 잘 이해는 안되지만, 간단해 졌다고 하니 뭐;;)
6.2 Dynamic Sprites
You might also have noticed that we have made the animate() method return a bool. This was done as a preparation for the dynamic sprites we are now going to create. If a sprite is created dynamically, it should also be deleted when it is no longer needed, to avoid running out of memory. To signal this, we will let the animate() method return TRUE when the sprite is no longer needed. So, let's try it by writing a class that will handle the lethal stuff we are going to throw at our poor enemies, and that signals that it should be deleted when it hits the ground.
당신이라면 (당연하게도) animate 메쏘드가 bool(true/false값만 가지는 타입)을 리턴하도록 했다는것을 알아차렸을 것이다. 이것은 우리가 앞으로 만들 다이나믹 스프라이트를 위해 미리 준비한 것이다. 만약 스프라이트가 동적으로 생성된다면, 스프라이트가 불필요해지면, 메모리를 낭비를 피하기위해, 삭제되어야 할것이다. 이걸 어떻게 알아차릴까? 그러기 위해서 우리는 스프라이트가 불필요해지면 animate() 메쏘드가 TRUE를 리턴하도록 할것이다. 따라서, 우리는 우리 미사일에 맞은 불쌍한 적(enemy)은 앞서 설명한 방법으로 객체를 삭제하도록 할 것이다.
Since it's a good idea to have defined the velocity at which our bombs will fall from the helicopter, we will add this somewhere at the top:
우리 헬리콥터에서 썰어지는 미사일의 속도를 define하는것은 꽤나 괜찮은 생각같다. 따라서 아래와 같은 코드를 소스의 상단부 어딘가에 적어놓을 것이다.
#define BOMB_LAUNCH 1Then we add the weaponry class itself. Add this before chopper::animate():
#define GRAVITY 0.1
그리고, 우리는 weaponry(무기류) 클래스를 추가할 것이다. 이 클래스는 chopper::animate() 앞에 추가하자.
class projectile : public sprite {
fix DX,DY;
int force;
public:
projectile(fix _X,fix _Y,fix _DX,fix _DY,RLE_SPRITE*img,int power)
: sprite(_X,_Y,img) { DX=_DX; DY=_DY; force=power; }
virtual bool animate() {
move(DX,DY); DY+=GRAVITY;
return Y+image->h>=MAX_Y;
}
};To launch bombs whenever Enter is pressed, change chopper::animate() to:엔터가 눌렸을때 폭탄을 투하하기 위해서, chopper::animate()를 다음과 같이 수정하자.
bool chopper::animate()Finally, to delete the sprites that are no longer needed, we need to change the animation code in the main game loop to:
{
fix DX=0,DY=0;
if (key[KEY_LEFT]||joy_left) --DX;
if (key[KEY_RIGHT]||joy_right) ++DX;
if (key[KEY_UP]||joy_up) --DY;
if (key[KEY_DOWN]||joy_down) ++DY;
move(DX,DY);
if (key[KEY_ENTER]||joy_b1) {
sprites.push_back(new projectile(X+32,Y+14,
BOMB_LAUNCH,0,(RLE_SPRITE*)data[TUT_BOMB].dat,5));
}
if (frame) { image=(RLE_SPRITE*)data[TUT_CHOPPER1].dat; frame=0; }
else { image=(RLE_SPRITE*)data[TUT_CHOPPER2].dat; frame=1; }
return FALSE;
}
마지막으로, 더이상 불필요한 스프라이드를 삭제하기 위해서, 우리는 메인 게임 루프에서 animation코드를 다음처럼 바꿀것이다.
// animate spritesThis will save the current sprite, then call animate(). If it returns true, it will remove the element from the list, move the iterator to the next element, and then delete the sprite itself; otherwise, it will move the iterator as before.
poll_joystick();
{
sprite_list::iterator spr=sprites.begin();
while (spr!=sprites.end()) {
sprite*itm=*spr;
if (itm->animate()) {
sprites.erase(spr++);
delete itm;
} else spr++;
}
}
이것은 현재 스프라이트를 저장해 놓고 animate()를 호출한 다음에, 리턴값이 true라면 리스트에서 제거해 버리고 다음 element로 넘어가는 것이다. 그리고 스프라이트는 삭제를 해 버린다. 리턴값이 false라면 이전에 했던거랑 동일하게 동작하는거고...
With this, the player is now able to pour out bombs at high volume, which is definitely going to be of much value against his enemies, once he gets any.
이것과 함께, 플레이어는 이제 폭탄을 떨굴수 있다. (...영어가 짧아 번역아 안되..됩니다..T^T)
6.3 Moving Bomb Launch
A somewhat unrealistic thing about the way we have launched these bombs, is their launch velocity when the helicopter is moving, which is currently absolute, and thus exactly the same as if the helicopter stood still. In our game, we want some more realism than that (even if the extreme payload of explosives the player has at his disposal is totally unrealistic), so we will make the initial bomb velocity relative to the current helicopter velocity. This also makes it much more fun to try to launch bombs as if they were projectiles by jerking the helicopter forward and upward just as the bomb is launching.
근데, 뭔가 비현실적인것이 있는데 폭탄을 떨구면 헬기의 속도에 맞춰서 곡선으로 떨어져야 한다. 근데, 우리 프로그램은 헬기가 움직이지 않더라도 폭탄은 곡선으로 떨어진다. (뭐, 물론 잔탄수가 없는것도 말이 안되는거긴 하다만..) 하여간, 그래서 우리는 비행기 속도에 맞춰서 폭탄의 초기 속도를 설정할 것이다. 이것은 게임을 좀더 재미있게 만들것이다. (...뭐 비슷한 내용인거 같다;;)
First, to accurately calculate how much the helicopter has moved (its current velocity), we will let the base class keep track of what the last position was, by its animate() method.
우선, 헬기의 속도를 계산하기 위해서(현재 속도) 우리는 베이스 클래스의 animate() 메쏘드에서 헬기의 마지막 좌표를 계속 추적할 것이다.
class sprite {
protected:
fix X,Y,LX,LY;
RLE_SPRITE*image;
public:
sprite(fix _X,fix _Y) { LX=X=_X; LY=Y=_Y; image=NULL; }
sprite(fix _X,fix _Y,RLE_SPRITE*img) { LX=X=_X; LY=Y=_Y; image=img; }
virtual ~sprite() {}
virtual void draw(BITMAP*dest) {
draw_rle_sprite(dest,image,X,Y);
}
virtual void clippos() { if (Y+image->h>MAX_Y) Y=MAX_Y-image->h; }
virtual void place(fix NX,fix NY) { X=NX; Y=NY; clippos(); }
virtual void move(fix DX,fix DY) { X+=DX; Y+=DY; clippos(); }
virtual int outside(fix _X,fix _Y) { return (_X<-image->w)||(_X>=SCREEN_W); }
virtual bool animate() { LX=X; LY=Y; return FALSE; }
};Of course, for this to work, the animate() method for the derived classes has to call this. The chopper class' animate() method, after adding the difference between the current and previous coordinates as the velocity to add to the bomb launch velocity, and doubling the speed of the helicopter itself, is now:물론, 실제 동작하기 위해서는 상속받은 클래스에서 animate()를 호출해야 한다. chopper클래스의 animate() 메쏘드의 경우, 헬기의 속도를 폭탄의 속도에 더해줘서 헬기속도의 두배가 되도록 한다. (아.. 이것도 발번역.. T^T)
bool chopper::animate()
{
sprite::animate();
fix DX=0,DY=0;
if (key[KEY_LEFT]||joy_left) DX-=2;
if (key[KEY_RIGHT]||joy_right) DX+=2;
if (key[KEY_UP]||joy_up) DY-=2;
if (key[KEY_DOWN]||joy_down) DY+=2;
move(DX,DY);
if (key[KEY_ENTER]||joy_b1||(mouse_b&1)) {
sprites.push_back(new projectile(X+32,Y+14,
X-LX+BOMB_LAUNCH,Y-LY,(RLE_SPRITE*)data[TUT_BOMB].dat,5));
}
if (frame) { image=(RLE_SPRITE*)data[TUT_CHOPPER1].dat; frame=0; }
else { image=(RLE_SPRITE*)data[TUT_CHOPPER2].dat; frame=1; }
return FALSE;
}
6.4 Mouse Control
Another thing that I personally find makes the program much more fun to mess with, is to control the helicopter with the mouse. This enables it to move around the screen and launch bombs with ludicrous velocities, but still, why not have all the fun we can get? Unfortunately, this means we will have to dispense with the second helicopter. The full code is now:
개인적으로 프로그램을 재미있게 할 방법으로 헬기를 마우스로 컨트롤 해보면 어떨까 하고 생각해 봤다. 이렇게 하면 헬기를 움직일수 있고 폭탄에 황당하리만한 속도를 줄수도 있다.(!!) 그렇다면, 왜 지금까지 안했을까? 불행하게도, 이것은 우리가 두번째 헬기를 만들수 없다는 것이다. (대충 '2인용 게임을 만들수 없다`. 로 해석되는데.. 흠;;)
(...진짜 발번역... 이거 제대로 번역좀 해주세요 T^T)
우리가 한것은 명확하다. install_mouse()는 PC에 마우스가 달려있지 않다면 -1을 리턴한다. mouse_x와 mouse_y는 현재 마우스의 좌표를 가지고 있다. position_mouse는 새로운 마우스 좌표를 설정한다. (keyboard나 joystick는 헬기를 움직이는데 사용된다.) 당신은 마우스 버튼을 누른채 움직이면 게임플레이에 영향을 주는 물리력을 확인할 수 있을것이다.
For more exciting gameplay, proceed to the next chapter
좀더 흥분되는(..될리가..) 게임플레이를 만들고 싶다면 다음 챕터를 보자.
ref:http://www.ping.uio.no/~ovehk/allegro/tut6.html
자, 이제부터 번역 시~작!
PS. 우왕~ 회사에서 내 인터넷 끊어버렸다. (네이버, 이글루, 레임, 루리웹 다 끊겼음. ㅋㅋ; 나, 언제 번역하냐;;)
#include <allegro.h>It is reasonably clear what we've done; install_mouse() returns -1 if a mouse is not installed; mouse_x and mouse_y contains the current mouse coordinates; position_mouse sets new coordinates (in case the keyboard or joystick was used to move the helicopter). You can now hold down the mouse button and move the mouse around to discover how the law of physics relate to gameplay (and jerky mouse motion).
#include <stl.h>
#include "tutorial.h"
#define MIN_Y 8
#define MAX_Y 180
#define BOMB_LAUNCH 1
#define GRAVITY 0.1
DATAFILE*data;
BITMAP*backdrop,*framebuf;
bool usemouse=FALSE;
class sprite {
protected:
fix X,Y,LX,LY;
RLE_SPRITE*image;
public:
sprite(fix _X,fix _Y) { LX=X=_X; LY=Y=_Y; image=NULL; }
sprite(fix _X,fix _Y,RLE_SPRITE*img) { LX=X=_X; LY=Y=_Y; image=img; }
virtual ~sprite() {}
virtual void draw(BITMAP*dest) {
draw_rle_sprite(dest,image,X,Y);
}
virtual void clippos() { if (Y+image->h>MAX_Y) Y=MAX_Y-image->h; }
virtual void place(fix NX,fix NY) { X=NX; Y=NY; clippos(); }
virtual void move(fix DX,fix DY) { X+=DX; Y+=DY; clippos(); }
virtual int outside(fix _X,fix _Y) { return (_X<-image->w)||(_X>=SCREEN_W); }
virtual bool animate() { LX=X; LY=Y; return FALSE; }
};
typedef list<sprite*> sprite_list;
sprite_list sprites;
class background : public sprite {
public:
background() : sprite(0,MIN_Y) {}
virtual void draw(BITMAP*dest) {
blit(backdrop,dest,0,0,X,Y,backdrop->w,backdrop->h);
}
};
class chopper : public sprite {
protected:
int frame;
public:
chopper(fix _X,fix _Y)
: sprite(_X,_Y,(RLE_SPRITE*)data[TUT_CHOPPER].dat) {
frame=0;
position_mouse(X,Y);
}
virtual void clippos() {
if (X<0) X=0;
if (X+image->w>SCREEN_W) X=SCREEN_W-image->w;
if (Y<MIN_Y) Y=MIN_Y;
sprite::clippos();
}
virtual bool animate();
};
class projectile : public sprite {
fix DX,DY;
int force;
public:
projectile(fix _X,fix _Y,fix _DX,fix _DY,RLE_SPRITE*img,int power)
: sprite(_X,_Y,img) { DX=_DX; DY=_DY; force=power; }
virtual bool animate() {
move(DX,DY); DY+=GRAVITY;
return Y+image->h>=MAX_Y;
}
};
bool chopper::animate()
{
sprite::animate();
if (usemouse) place(mouse_x,mouse_y);
fix DX=0,DY=0;
if (key[KEY_LEFT]||joy_left) DX-=2;
if (key[KEY_RIGHT]||joy_right) DX+=2;
if (key[KEY_UP]||joy_up) DY-=2;
if (key[KEY_DOWN]||joy_down) DY+=2;
move(DX,DY);
if (usemouse) position_mouse(X,Y);
if (key[KEY_ENTER]||joy_b1||(mouse_b&1)) {
sprites.push_back(new projectile(X+32,Y+14,
X-LX+BOMB_LAUNCH,Y-LY,(RLE_SPRITE*)data[TUT_BOMB].dat,5));
}
if (frame) { image=(RLE_SPRITE*)data[TUT_CHOPPER1].dat; frame=0; }
else { image=(RLE_SPRITE*)data[TUT_CHOPPER2].dat; frame=1; }
return FALSE;
}
int main()
{
allegro_init();
install_keyboard();
// comment out the next line if you don't want mouse
usemouse=(install_mouse()!=-1);
initialise_joystick();
data=load_datafile("tutorial.dat");
set_gfx_mode(GFX_VGA,320,200,0,0);
set_palette((RGB*)data[TUT_GAMEPAL].dat);
// create 320x192 backdrop
backdrop=create_bitmap(320,192);
for (int Y=0; Y<128; Y++) hline(backdrop,0,Y,319, (Y/2)+128);
for (int Y=128; Y<192; Y++) hline(backdrop,0,Y,319, ((Y-128)/2)+192);
// create 320x200 double buffer
framebuf=create_bitmap(320,200);
clear(framebuf);
background Back;
chopper Hero(50,100);
sprites.push_back(&Back);
sprites.push_back(&Hero);
while (!key[KEY_ESC]) {
// draw sprites
{
sprite_list::const_iterator spr=sprites.begin();
while (spr!=sprites.end()) {
(*spr)->draw(framebuf);
spr++;
}
}
// display frame
vsync();
blit(framebuf,screen,0,0,0,0,320,200);
// animate sprites
poll_joystick();
{
sprite_list::iterator spr=sprites.begin();
while (spr!=sprites.end()) {
sprite*itm=*spr;
if (itm->animate()) {
sprites.erase(spr++);
delete itm;
} else spr++;
}
}
}
return 0;
}
우리가 한것은 명확하다. install_mouse()는 PC에 마우스가 달려있지 않다면 -1을 리턴한다. mouse_x와 mouse_y는 현재 마우스의 좌표를 가지고 있다. position_mouse는 새로운 마우스 좌표를 설정한다. (keyboard나 joystick는 헬기를 움직이는데 사용된다.) 당신은 마우스 버튼을 누른채 움직이면 게임플레이에 영향을 주는 물리력을 확인할 수 있을것이다.
For more exciting gameplay, proceed to the next chapter
좀더 흥분되는(..될리가..) 게임플레이를 만들고 싶다면 다음 챕터를 보자.
ref:http://www.ping.uio.no/~ovehk/allegro/tut6.html
자, 이제부터 번역 시~작!
PS. 우왕~ 회사에서 내 인터넷 끊어버렸다. (네이버, 이글루, 레임, 루리웹 다 끊겼음. ㅋㅋ; 나, 언제 번역하냐;;)
이글루스 가든 - 하루에 한 장~ 꾸준히 번역하기


덧글