목차

상속을 이용하여 아이템 추가

  

스타팅 파일

코인 아이템 상속시키기

1. 목적

이번에는 생명력을 높이는 아이템을 만들 것이다. 그런데 생명력을 높이는 아이템은 이미지와 효과를 주는 것만 다를 뿐, 나머지는 코인 아이템과 동일하다. 따라서 코인 아이템을 상속시키고 부가적인 것들만 파생 함수로 만들면 된다.

2. coin.h

아래와 같이 코인을 상속받는 life라는 클래스를 만들었다.

coin.h
#pragma once
#include "raylib.h"
 
class Coin 
{
    public: 
        Coin();
        Coin(Texture2D* _image);
        void Update();
        void Draw();
        int GetPosition();
        bool GetCollision(Rectangle bRect);
        int GetAddValue();
 
    protected:
        Vector2 pos;                            // 코인 위치
        Texture2D* coinImage;        // Texture의 주소값
        Rectangle frameRec;            // 보여줄 프레임
 
        int currentFrame = 0;
        int framesCounter = 0;
        int framesSpeed = 16;            // Number of spritesheet frames shown by second
 
        int SPRITE_NUMBERS ; // 스프라이트 개수
        int speed;  // 스피드
        int addValue; // 넘겨줄 값
}; 
 
class Life : public Coin
{
    public : 
        Life(Texture2D* _image, int _sprite_numbers, int _speed, int _addValue);
};

여기서 주의할 것은, 부모클래스의 생성자인 Coin()을 반드시 선언과 정의해 줘야 한다는 것이다. 그렇지 않으면 오류가 나왔다.

왜 명시적으로만 선언해줘야 하는지는 잘 모르겠다.

2. coin.cpp

coin.cpp
#include "coin.h"
 
Coin::Coin()
{}
 
Coin::Coin(Texture2D* _image)
{
    int x = GetScreenWidth(); 
    int y = GetRandomValue(100, GetScreenHeight() - 100);
    pos = {float(x), float(y)};
 
    coinImage = _image;
 
    currentFrame = 0;
    framesCounter = 0;
    framesSpeed = 16;            // Number of spritesheet frames shown by second
 
    SPRITE_NUMBERS = 31;  // 스프라이트 개수
    speed = 2;  // 코인 스피드 
    addValue = 3;
 
    frameRec = { 0.0f, 0.0f, (float)coinImage->width / SPRITE_NUMBERS, (float)coinImage->height };
}
 
int Coin::GetAddValue()
{
    return addValue;
}
 
int Coin::GetPosition()
{
    return (int)pos.x + (float)coinImage->width / SPRITE_NUMBERS;  // 47은 코인의 너비이다. 
}
 
bool Coin::GetCollision(Rectangle bRect)
{
    Rectangle rect = {pos.x, pos.y, (float)coinImage->width / SPRITE_NUMBERS, (float)coinImage->height};
 
    return CheckCollisionRecs(bRect, rect);   
}
 
void Coin::Update()
{
    framesCounter++; 
 
    if (framesCounter >= (60/framesSpeed))   // FPS를 60으로 설정했으므로 60을 프레임스피드로 나눈다. 그러면 1초당 몇번 돌릴지 결과 값이 나온다. 
    {
        framesCounter = 0;
        currentFrame++;
 
        if (currentFrame >  SPRITE_NUMBERS) currentFrame = 0;
 
        frameRec.x = (float)currentFrame * (float)coinImage->width / SPRITE_NUMBERS;
    }
    pos.x -= speed;
}
 
void Coin::Draw()
{
    DrawTextureRec(*coinImage, frameRec, pos, WHITE);  // Draw part of the texture
}
 
 
Life::Life(Texture2D* _image, int _sprite_numbers, int _speed, int _addValue)
{
    int x = GetScreenWidth(); 
    int y = GetRandomValue(100, GetScreenHeight() - 100);
    pos = {float(x), float(y)};
 
    coinImage = _image;
 
    currentFrame = 0;
    framesCounter = 0;
    framesSpeed = 8;            // Number of spritesheet frames shown by second
 
    SPRITE_NUMBERS = _sprite_numbers;  // 스프라이트 개수
    speed = _speed;  // 코인 스피드 
    addValue = _addValue;
 
    frameRec = { 0.0f, 0.0f, (float)coinImage->width / SPRITE_NUMBERS, (float)coinImage->height };
}

Life의 생성자만 새롭게 정의해줬다. Coin의 경우에는 생성자에 텍스쳐파일의 주소만 인자로 받았는데, Life는 스프라이트 수와 코인스피드, 그리고 더하려는 밸류의 값도 줘야 하므로 인자가 4개가 되었다.

기존에는 Init()함수로 아이템을 초기화해줬는데, 굳이 그렇게 할 필요 없이 생성할 때 초기화해주면 되므로 Init()함수는 제거하고 생성자에 인자를 넣는 방식으로 교체하였다. 기존 파일을 보는 사람은 이를 유의하자.

아이템 에이전트에서 Life 호출하기

사실 별반 다를바 없다. Coin의 뒤에 Life의 배열을 일정한 확률에 따라 생성하게 만들어 주자.

이번에는 new와 delete 지시어를 써서 동적으로 호출한 것에 유의하자.

items.cpp에서 Update()메서드의 일부 코드는 다음과 같다.

        int spawn = GetRandomValue(0, 1000); // 코인이 발생할 확률 
        if (spawn < 2 && canSpawn == true) // 코인이 발생할 확률을 1000분의 10 즉 1%로 설정함
        {
            Coin* coin = new Coin(&CoinSprite);           
            coins.push_back(*coin);
            delete coin;
        }
 
        int spawnlife = GetRandomValue(0, 1000); // 코인이 발생할 확률 
        if (spawnlife < 1 && canSpawn == true) // 코인이 발생할 확률을 1000분의 10 즉 1%로 설정함
        {
            Life* life = new Life(&LifeSprite, 8, 3, 1);
            // life.Init(&LifeSprite, 8, 2, 1);
            // life->Init();
            lifes.push_back(*life);
            delete life;
        }

나머지 충돌처리와 Draw()메서드는 Coin에서 만들었떤 것을 그대로 Life에서도 가져다 쓰면 된다.

이를테면 Life 클래스서는 따로 Draw()메서드를 선언하지 않았지만 Coin클래스를 상속받으므로 다음과 같이 자연스레 쓸 수 있다.

void Items::Draw()
{
     if (coins.size() >0 ) 
     {
        for (unsigned int i = 0;i< coins.size();i++)
        {
            coins[i].Draw();
        }
     }
 
     if (lifes.size() >0 ) 
     {
        for (unsigned int i = 0;i< lifes.size();i++)
        {
            lifes[i].Draw();
        }
     }
}

결론

상속을 이용하여 아이템 추가

상속을 이용하면 공통된 로직을 반복할 필요가 없으므로 코딩 속도가 매우 빨라진다.

이런 식으로 아이템을 여러개 만들 수 있을 것이다.

지금까지의 소스파일은 아래에 첨부한다.

상속을 이용하여 다른 아이템 만들기

다음번에는 게임패드 입력을 해보겠다.

1)
그림의 크기가 너무 크기 때문에 사이즈를 조정해주어야 한다. 귀찮으면 내가 첨부해 놓은 완성 파일에서 리소스를 받아 써도 된다.