Dev.log(3) – postać i scena testowa

W tym wpisie skupimy się na tworzeniu postaci, którą w końcu będziemy mogli poruszać. Jak już wspominałem – gra będzie ewoluowała w trakcie tworzenia, dlatego w tym wpisie zobaczysz poruszanie postaci wraz z dodanym skokiem. W celu ukazania jak stworzyłem model poruszania się, zastosowałem czerwony prostokąt. Nie chcę później za dużo zmieniać w bohaterze, dlatego tekstura i jego animacja będzie dodana w późniejszych krokach. Zacznijmy więc od…

Modyfikacja scen

Sceny zostały trochę przebudowane i zapewnie jeszcze nie raz przejdą małe lub większe metamorfozy. Tym razem zmienił się ten fragment.

            case SPLASH_SCREEN:
                if (!splashScreen.isInitialized()) {
                    if (!splashScreen.create(&renderWindow)) {
                        return;
                    }
                }
                // Clearing render window
                renderWindow.clear(Color::Color(47, 47, 47));

                if (splashScreen.isFinished()) {
                    gameState = TEST_SCENE;
                } else {
                    splashScreen.update(deltaTimeFloat);
                    splashScreen.draw(&renderWindow);
                }
                break;

            case TEST_SCENE:
                if (!testScene.isInitialized()) {
                    if (!testScene.create(&renderWindow)) {
                        return;
                    }
                    testScene.setGameLogoPosition(splashScreen.getLogoPosition());
                    // Temp!
                    // testScene.setGameLogoPosition(Vector2f(100.0f, 50.0f));
                }

                // Clearing render window
                renderWindow.clear(Color::Color(0, 184, 245));

                if (testScene.isFinished()) {
                    gameState = EXIT_STATE;
                } else {
                    testScene.update(deltaTimeFloat);
                    testScene.draw(&renderWindow);
                }
                break;

Jest on odpowiedzialny za odpowiednie wyświetlanie scen. Od teraz każda scena tworzona jest przy jej wywołaniu. Niszczenie niepotrzebnych zostawimy sobie na później.

Przejdźmy teraz do bardziej zaawansowanej rzeczy i zostawmy te stylistyczne poprawki na później.

Postać

Postać, dla której poniekąd jesteśmy bogiem/stworzycielem, będzie prostokątem. Taki mały, zwinny maluszek, który będzie wykorzystany do testów (jak to brzmi xdd). Stworzymy trzy ruchy – w lewo, w prawo i skok. Postać ma wiele najróżniejszych parametrów życiowych, które z pewnością jeszcze się rozwiną. Podstawowe z nich to punkty życia, pozycja, rozmiar, pragnienie, głód czy ilość doświadczenia.

    string name;
    int experience;
    int life;
    int starvation;
    int thirst;
    int lifeEnergy;
    float speed;
    float maxSpeed;
    
    Vector2f position;
    Vector2f size;
    Vector2f movementVector;
    string characterTexture;

Postać ma też swoje funkcje życiowe. Z założenia musi się urodzić, przemieścić, podskoczyć, narysować i odświeżyć swoje parametry życiowe.

    void jump();
    void moveLeft();
    void moveRight();
    
    void create(string, int, int, int, int, int, Vector2f, Vector2f, string);
    void update(float deltaTime);
    void draw(RenderTarget *target);

Skoro już wiemy co nasza postać robi to teraz poruszmy ją troszkę w lewo lub w prawo!

void Character::moveLeft() {
    movementVector.x -= speed;
}

void Character::moveRight() {
    movementVector.x += speed;
}

void Character::jump() {
    if (movementVector.y == 0.0f) {
        movementVector.y -= 250.0f;
    }
}

Udało nam się poruszyć i do tego podskoczyć! Pięknie! Teraz dodajmy do tego trochę fizyki, którą stworzyłem na własny użytek. Zapewnie nie jest ona idealna, ale działa identycznie na 60 FPS czy nawet 520 FPS. Wniosek? Działa to zatwierdzam!

void Character::update(float deltaTime) {
    // Fixing X axis movement vector
    if (movementVector.x < -1.0f)
        movementVector.x += 500.0f * deltaTime;
    else if (movementVector.x > 1.0f)
        movementVector.x -= 500.0f * deltaTime;
    else
        movementVector.x = 0.0f;

    if (movementVector.x > maxSpeed)
        movementVector.x = maxSpeed;

    if (movementVector.x < -maxSpeed)
        movementVector.x = -maxSpeed;

    // Fixing Y axis movement vector
    if (movementVector.y < 200.0f)
        movementVector.y += 750.0f * deltaTime;

    // Changing position of Character
    this->position.x += movementVector.x * deltaTime * 10.0f;
    this->position.y += movementVector.y * deltaTime * 10.0f;
}

Wow, dużo tego! Jednak kiedy bardziej przyjrzysz się każdej linijce to zauważysz, że są tu ograniczenia prędkości, „wygładzanie” ruchu oraz zmiana pozycji prostokąta (znaczy Adriana, on ma imię). Czemu są tu użyte tak duże liczby? Wystarczy je zmienić by uzyskać dłuższą drogę hamowania po puszczeniu klawisza ruchu (tam gdzie jest „500.0f” w if-ie). Aby to zrobić należy zmniejszyć wartość i będziemy poruszali się jak po lodowisku.

Wartości początkowe ustaliłem metodą prób i błędów. Jeśli jesteś dobry z matematyki to możesz sobie to wyliczyć. Poniżej masz prędkość jaka jest dodawana do wektora w momencie wciśnięcia klawisza. Im mniejsza wartość tym wolniej rozpędza się bohater. Drugi parametr to maxSpeed – jak sama nazwa wskazuje, jest to prędkość maksymalna postaci.

this->speed = 20.0f;
this->maxSpeed = 80.0f;

Czy było to trudne? Nie! Najgorsza część to praca nad pseudo fizyką. Na GitHubie jest kod z dodanym ograniczeniem podłogą i ścianami, tak żeby nie dało się opuścić obszaru gry. Tak wygląda efekt końcowy wraz ze sceną testową, którą opiszę za chwilę!

Scena testowa

W celu testowania mechaniki postaci musiałem mieć pewien ekran na którym to zrobię. Stworzyłem sobie scenę testową i umieściłem w niej Adriana (nazwa kodowa).

character.create("Adrian", 0, 100, 100, 100, 100, Vector2f(150.0f, 300.0f), Vector2f(75.0f, 100.0f), "void");

Jedyne co mi potem zostało stworzyć to metodę odświeżającą update i wszystko było gotowe!

void TestScene::update(float deltaTime) {
    if (Keyboard::isKeyPressed(Keyboard::Right) || Keyboard::isKeyPressed(Keyboard::D)) {
        character.moveRight();
    }

    if (Keyboard::isKeyPressed(Keyboard::Left) || Keyboard::isKeyPressed(Keyboard::A)) {
        character.moveLeft();
    }

    if (Keyboard::isKeyPressed(Keyboard::Up) || Keyboard::isKeyPressed(Keyboard::W)) {
        character.jump();
    }

    character.update(deltaTime);
}

Podsumowanie

To by było na tyle! Stworzyliśmy bohatera Adriana, który jest czerwonym prostokątem gotowym podbijać świat. Potrafi on chodzić i skakać. W późniejszych fazach rozwoju nauczymy go paru sztuczek, damy mu jakieś ubrania, przedmioty by przygotować go na przygodę! Tymczasem wbijaj na moje social media i…

… do następnego!

#shareShare on FacebookShare on Google+Tweet about this on TwitterShare on TumblrPin on PinterestShare on LinkedInShare on VKShare on RedditEmail this to someone