Power-up

Power-up'ide ja perk'ide eesmärk

Power-up on termin, mis viitab mängijale ajutise eelise andmisele. Power-up'ide lisamine muudab mängu vähem etteaimatavaks ning nende otsimist saab kasutada mängija suunamiseks läbima kindlaid mänguetappe.

../_images/pacman.webp

Pacmanis “power pellet” annab Pacmanile võime vastaseid süüa.

Tavaliselt on power-up'idel ajapiiranguks:

  • konkreetne ajalimiit

  • mängija vigastada saamiseni

  • mängija surmani

Kogu mängu või taseme lõpuni kestvat eelist nimetatakse perkiks. Perkidel on tihti hierarhia ehk kõrgema taseme perk'i saamiseks peab mängijal olema madalama taseme perk.

../_images/payday.png

Payday's on perkid ostetavad, kuid tingimuseks odavama perki olemasolu.

Mõnikord lisatakse power-up'e põhiloost eraldi "boonusvoorudesse" koos lisa punktidega. Samuti võib power-up anda võime pääseda boonusvooru – näiteks lendamisvõime või üleüldse võime ligipääseda kohta, kuhu ilma lisavõimeta ei pääseks.

../_images/metroid_series.webp

Metroid series’is Morph Ball annab läbipääsu tunnelitesse ja vahedesse, kus tavasuuruses ei mahuks.

Power-up'ide kujutamine

Levinuim viis power-up'e kujutada:

  • konkreetse objektina (“söödana”), mida mängija saab korjata.

  • konkreetsete piirkondadega mängumaailmas.

  • preemiana vastase alistamise eest.

../_images/mario.webp

Super Marios power-upi kujutamine küsimärk-blokina, mis annab juurde üllatuse aspekti power-upi võimele.

Power-up'i mõju esiletõstmiseks on soovitatav kasutada visuaalseid või heliefekte, et nende toimimisele tähelepanu juhtida. Mida äratuntavam on power-up' võime selle avaldumise järgi, seda parem.

Näiteks:

  • Mängija välimuse muutmine (sätendama/vilkuma panemine).

  • Tausta või mängukeskkonna muutmine (nähtavuse parandamine pimedas labürindis, kui varem oli nähtav vaid käidud rajad, siis power-up annab hetkeks täieliku vaate labürindist).

  • Spetsiifilised heliefektid (kiirendava power-up'i puhul muusika kiirendamine).

../_images/mario2.webp

Super Marios power-upi mõju näitamine mängija suuruse muutmisega.

Tihtipeale omistatakse power-upidel otsekohene mõju (näiteks leiad tiivad ja saad siis lennata), kuid osades mängudes saab leitud power-upi panna power-upide ladusse (“Inventory’i”), mis annab mängijale vabaduse valida, millal power-up käivitada. Kui mängus on mitu erivõimega power-upi, on vaja otsustada, kas need tohivad toimida samal ajal. Kui ei, siis mitte anda võimalus selliseks olukorraks.

../_images/inventory.png

Gradius III selection bar power-upideks ehk vabadus ise valida power-upi aktiveerimine.

Power-up'ide tüübid ja mõjud

1. Ründevõime:

  • Mängija suuruse muutmine, millega kaasneb füüsiliste võimete mitmekordistumine (laiem haare ja seetõttu rohkemate kahjustuste tegemine ühe käehoobiga).

  • Mängija hävitusjõu suurendamine (rohkem haavavate kahjustuste tegemine ühe mõõgalöögiga).

  • Relvade ja eri gadget'ite lisamine (põrkekuulid, laskemoona mahutavuse suurendamine).

../_images/dragon.png ../_images/dragon2.png

Enne ja pärast power-upi, lisa gadget on lohe.

2. Kaitsevõime:

  • Kaitsekilbid (force field), mis ei lase mängijat kahjustada.

  • Mängija kloonimine segaduse tekitamiseks või NPC-de kaasamine samal eesmärgil.

../_images/sonic.png

Sonic the Hedgehog 2 kilp, mis tühistab vaenlasega kokkupõrkest tekkiva kahju.

../_images/geometry_dash.webp

Geometry Dash ogade kahjutuks tegemine.

3. Põiklemisvõime:

  • mängija kiiremaks tegemine või booster-plokid.

  • Nähtamatus või kamuflaaž (näiteks pappkastina maskeerumine). Soovitatav on mängijat mitte täiesti nähtamatuks teha, pigem vähendada läbipaistvust või jätta alles vaid mängija piirjooned.

  • Hüppevõime suurendamine või "matter surfing".

Näiteks Geometry Dashis on kiirenduse power-up booster-tsoonides. Geometry Dash video Youtubes

4. Tervise- ja eluvarud:

  • “Health bar”i pikkuse suurendamine.

  • Lisa elu "Extra life" või "1-up".

  • Ajalimiidi pikendamine mängudes, kus on ajapiirang.

../_images/aladdin.png ../_images/aladdin2.png

Disney's Aladdinis lisaelu kujutamine südamete arvu kasvamisega.

5. Ajaga manipuleerimise (nii ründe- kui ka kaitsevõime):

  • Vastaste aeglustamine.

  • Kõigi peale mängija liikumatuks muutmine.

6. Skooriboonus:

Skooriboonuse power-up annab mängijale võimaluse teenida ajutiselt rohkem punkte samade tegevuste eest. Tegemist ei ole otsese ründe- ega kaitsevõimega, vaid motivatsioonimehhanismiga, mis julgustab mängijat power-upi kehtivuse ajal aktiivsemalt tegutsema. Näiteks kui mängija saab tavaliselt vastase alistamise eest 100 punkti, siis skooriboonuse ajal saab ta 200 punkti.

Levinumad skooriboonuse tingimused:

  • Punktide korrutaja (nt x2 või x3 skoor).

  • Rohkem punkte iga tapetud vastase eest.

  • Rohkem punkte kindlate tegevuste eest (hüppamine, esemete kogumine, combo’d).

Power-down

Power-down'ide eesmärk on mängimist raskendada. Power-downide hulka kuulub:

  • Vastastele power-up'i andmine või mängija power-up'ide eemaldajad.

  • Mängija haavamine või tapmine.

  • Kontrolli keerukamaks muutmine (näiteks ainult ühes suunas liikumise lubamine või vasakule ja paremale liikumise loogika vahetamine).

Power-downi kujutamine

Power-down'e võib kujutada samal viisil nagu power-up'e (näiteks booster-bloki asemel on mürgine ala), mis lisab üllatusmomenti, kuid sellega kaasneb oht, et mängija ei pruugi power-up'ide olemasolu avastada.

../_images/mario3.webp

Super Mario mürgine seen, mis varastab mängijalt kas power-upi või tapab ta power-upi puudumisel.

Hüppe ja liikumise kahekordse kiirendamise power-upide loogika platformer-stiilis mängus

Box2D füüsikamootoris on kaks olulist meetodit keha liikumiskiiruse muutmiseks: applyForce ja applyLinearImpulse. Peamine erinevus nende vahel seisneb mõju avaldumise ajastuses: applyForce rakendab jõudu järk-järgult, luues loomulikuma kiirenduse. applyLinearImpulse rakendab impulssi koheselt, muutes liikumist viivitamatult.

  1. Kui mängus on power-upi objektid juba kujutatud ja kokkupõrke loogika loodud, siis järgmine samm on kokkupõrke korral käivitada vastava power-upi meetodi. Näiteks:

activateJumpPowerUp();
activateRunPowerUp();
  1. Järgmine tegevus on ajutisele power-upile lisada ajamuutuja, et määrata power-upi mõju peatumine. Ajamuutuja väärtuseks paneme nulli, seame sellele muutujale kestvusaja power-upi aktiveerudes ning vähendame muutuja väärtust update meetodis.

private float jumpPowerUpTimeLeft = 0;
private float runPowerUpTimeLeft = 0;

public void activateJumpPowerUp() {
    jumpPowerUpTimeLeft = 10;
}

public void activateRunPowerUp() {
    runPowerUpTimeLeft = 10;
}

public void update(float deltaTime) {
    if (jumpPowerUpTimeLeft > 0) {
        jumpPowerUpTimeLeft -= deltaTime;
    }
    if (runPowerUpTimeLeft > 0) {
        runPowerUpTimeLeft -= deltaTime;
    }
    handleInput(deltaTime);
}
  1. Hüppel kasutame applyLinearImpulse meetodit, kuna hüpe on ühekordne sündmus. Vector2 esimene väärtus tähistab horisontaalset ja teine vertikaalset impulssi. Power-upi aktiveerudes muudame hüppe tugevust.

private void doJump() {
    if (jumpPowerUpTimeLeft > 0) {
        player.getB2body().applyLinearImpulse(new Vector2(0, 7f), player.getB2body().getWorldCenter(), true);
    } else {
        player.getB2body().applyLinearImpulse(new Vector2(0, 4.5f), player.getB2body().getWorldCenter(), true);
    }
}

private float moveSpeed = 2.0f;        // tavaline max X-kiirus
private float moveSpeedBoost = 3.5f;   // power-up max X-kiirus
private float accel = 20f;            // kui kiiresti läheb target-kiiruseni
private float decel = 25f;            // kui kiiresti pidurdab nullkiiruseni

private float getMaxMoveSpeed() {
    return (runPowerUpTimeLeft > 0f) ? moveSpeedBoost : moveSpeed;
}

private float approach(float current, float target, float maxDelta) {
    if (current < target) return Math.min(current + maxDelta, target);
    return Math.max(current - maxDelta, target);
}

// Horisontaalse liikumise jaoks kasutame setLinearVelocity. Lisame ka sujuva ülemineku, et liikumine ei oleks “järsk”.
private void applyHorizontalMovement(float dt, float desiredDirection) {
    // desiredDirection: -1 (vasak), 0 (seis), 1 (parem)
    Body body = player.getB2body();

    float vx = body.getLinearVelocity().x;
    float vy = body.getLinearVelocity().y;

    float targetVx = desiredDirection * getMaxMoveSpeed();

    float rate = (desiredDirection == 0f) ? decel : accel;
    float newVx = approach(vx, targetVx, rate * dt);

    body.setLinearVelocity(newVx, vy);
}
  1. Eelnevalt loodud vertikaalse (hüppe) ja horisontaalse liikumise loogika kutsume välja meetodis, mis tegeleb klahvivajutuste jälgimisega.

    public void handleInput(float dt) {
    float desiredDirection = 0f;

    if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) desiredDirection = 1f;
    if (Gdx.input.isKeyPressed(Input.Keys.LEFT))  desiredDirection = -1f;

    if (Gdx.input.isKeyJustPressed(Input.Keys.UP) &&
            (player.getCurrentState().equals("run") || player.getCurrentState().equals("standing"))) {
        doJump();
    }

    applyHorizontalMovement(dt, desiredDirection);
}
  1. Klahvivajutuste käsitlemise loogika peame ka lisama update() meetodisse.

public void update(float deltaTime) {
    if (jumpPowerUpTimeLeft > 0) {
        jumpPowerUpTimeLeft -= deltaTime;
    }
    if (runPowerUpTimeLeft > 0) {
        runPowerUpTimeLeft -= deltaTime;
    }

    handleInput(deltaTime);
}

Kiiruse power-up ilma Box2D-ta

Kui mäng ei kasuta Box2D füüsikamootorit (top-down mäng, shooter, endless runner vms), saab kiiruse power-upi lahendada väga lihtsalt: muudame ajutiselt mängija liikumiskiirust ja taastame selle, kui taimer saab otsa.

Selle lähenemise eelised:

  • Ei vaja Box2D ega Vector2 importi.

  • Sobib väga paljudele mängutüüpidele.

  • Sama “taimeri muster” töötab ka teiste power-upide jaoks (skooriboonus, nähtamatus, kilp jne).

  1. Defineerime kiirused ja ajamuutuja

private float speedPowerUpTimeLeft = 0f;

private float baseSpeed = 200f;      // tavaline liikumiskiirus (pikslit sekundis)
private float boostedSpeed = 350f;   // kiirus power-upi ajal
  1. Power-upi aktiveerimine

Power-upi korjamisel seame taimeri kestvusele (5 sekundit). Soovi korral võib kasutada ka liitmist, et mitu korjamist pikendaks kestvust.

public void activateSpeedPowerUp() {
    speedPowerUpTimeLeft = 5f;
    // speedPowerUpTimeLeft += 5f;
}
  1. Taimeri uuendamine update() meetodis

public void update(float deltaTime) {
    if (speedPowerUpTimeLeft > 0f) {
        speedPowerUpTimeLeft -= deltaTime;
    }

    handleInput(deltaTime);
}
  1. Mängija liigutamine ilma füüsikamootorita

Liikumise puhul on oluline kasutada deltaTime-i, et kiirus oleks sama nii kiirel kui aeglasel arvutil.

public void handleInput(float dt) {
    float currentSpeed = (speedPowerUpTimeLeft > 0f) ? boostedSpeed : baseSpeed;

    if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
        playerX += currentSpeed * dt;
    }
    if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
        playerX -= currentSpeed * dt;
    }
    if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
        playerY += currentSpeed * dt;
    }
    if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
        playerY -= currentSpeed * dt;
    }
}

Kui mängus kasutatakse Sprite või Actor-it, siis võib playerX/playerY asemel muuta otse positsiooni (nt sprite.setPosition(...) või actor.moveBy(...)). Põhimõte jääb samaks: power-up muudab ajutiselt currentSpeed väärtust.

Heli kiirendamine

Kahekordse kiiruse jaoks on Sound liideses meetod setPitch(), mis tahab kahte muutujat, millest esimene on muusika instantsi id ja teiseks kiirus, milleks soovitakse muusika muuta (float).