Obsah

Choď na pozíciu a drž formáciu

Analýza

Už v minulom roku bol pokus zapracovať držanie hráčov vo formácii. Stopy po tom sa nachádzali v kóde konkrétne na týchto miestach:

Plánovač „PlanCreateFormation“ mal však v sebe chybu, ktorá znemožňovala využitie formácií.

Rozhodli sme sa upraviť tieto existujúce kódy do funkčnej podoby, aby sme ich vedeli používať. Najprv bolo potrebné opraviť existujúci plánovač, odskúsať ako to celé funguje a nakoniec spraviť použiteľným high skill, ktorý by mohol využívať akýkoľvek plánovač.
Keďže high skill „GoTo“ slúžil len na dostatie sa hráča na pozíciu formácie, pre širšie a možno aj neskoršie využitie sme sa rozhodli z neho spraviť získať dva určité prvky. Prvým prvkom by bol high skill „GoToPosition“, ktorý by po zavolaní s parametrom súradníc umožnil presun hráča na tú pozíciu. Druhým prvkom by bola trieda poskytujúca metódu, ktorá by s využitím „GoToPosition“ poslala hráča na pozíciu vo formácii. Tento druhý prvok sme nazvali „FormationHelper“ s metódou „getHighSkillToGoToFormation“, ktorá vracia high skill „GoToPosition“ nastavený na chod do formácie.
Neskôr sme zistili, že počas vykonávania high skillu sa môže stať, že isté podmienky pri ktorých bol high skill zavolaný už neplatia a vykonávanie high skillu by bolo potrebné zrušiť. Zaviedli sme preto ďalší parameter, ktorým si high skill pravidelne kontroluje, či je stále validný. Pokiaľ high skill vyhodnotí, že už nespĺňa podmienky validity, tak pomocou „return nil“ odovzdá riadenie plánovaču.

Implemetácia

Najprv sme naimplementovali high skill „GoToPosition“. Jeho konštruktor má dva už spomínané parametre: globálna pozícia kam sa má hráč presunúť a proces valídnosti. Keď high skill volá svoju metódu „pickLowSkill“, najskôr zavolá proces valídnosti, ktorý skontroluje, či má zmysel high skill ďalej vykonávať. Ďalej nasleduje zrelativizovanie globálnej pozície na pozíciu vzhľadom na hráča pomocou Java triedy „AgentModel“ a jej metódy „reletivize“. Nasledujú volania jednotlivých low skillov zabezpečujúcich pohyb. Tu je ukážka začiatku metódy „pickLowSkill“:

def pickLowSkill
     if not @validity_proc.call
   return nil
     end

   if @target_position_global == nil
   return nil
       else
           @agentModel = Java::sk.fiit.jim.agent.models.AgentModel.getInstance
           @target_position = @agentModel.relativize(@target_position_global)
       end

Ďalej sme naimplementovali tzv. helper triedu „FormationHelper“ so statickou metódou „getHighSkillToGoToFormation“. Táto trieda umožní vrátiť plánovaču high skill, ktorý zabezpečí dopravenie hráča na pozíciu vo formácii. Jej metóda potrebuje ako parameter len proces valídnosti. V tele metódy sa potom vypočíta pozícia vo formácii a zavolá sa „GoToPosition“:

class FormationHelper

# @param validity_proc - process for calling method from plan to check
#     if GoToPosition is still valid or not
def FormationHelper.getHighSkillToGoToFormation validity_proc
    tacticalInfo = Java::sk.fiit.jim.agent.models.TacticalInfo.getInstance
   target_position = tacticalInfo.getFormPositionGlobal()
   return GoToPosition.new(target_position, validity_proc)
end
end

Príklad volania v plánovači s procesom validity takým, čo kontroluje či hráč vidí loptu, môže byť takýto:

@plan <<FormationHelper.getHighSkillToGoToFormation(Proc.new{see_ball?})

Keďže v „GoToPosition“ sa globálne súradnice relativizujú, potrebovali sme z Java triedy „TacticalInfo“ dostávať vypočítané pozície do formácie v globálnom tvare. Preto sme do „TacticalInfo“ pridali metódu „getFormPositionGlobal“:

public Vector3D getFormPositionGlobal(){
    setMyFormPosition();
    return pos;
}

Čo sa týka Java metódy „setMyFormPosition“, zistili sme, že je v nej potrebné prepočítavať súradnice vzhľadom na stranu tímu. Čiže ak má hráč pravú stranu tímu, trebalo mu v súradniciach invertovať x-ovú a y-ovú os (teda násobiť tie časti súradníc číslom -1). Taktiež bolo potrebné invertovať aj pozíciu lopty, ktorá sa nachádzala v podmienkach metódy. V metóde nižšie je vidieť, že súradnice jednotlivých pozícií vo formácii sú napevno zadané hráčovi podľa jeho poradového čísla. V budúcnosti by to bolo potrebné prerobiť napríklad tak, že hráč idúci do formácie obsadí niektorú zatiaľ neobsadenú pozíciu.

public void setMyFormPosition(){

    PositionInFormation = new Vector3D[7];
    double ball_pos = WorldModel.getInstance().getBall().getPosition().getX();
    int flip = 1;

    if (AgentInfo.side == Side.RIGHT) {
   flip = -1;
   ball_pos = ball_pos * flip;
    }

    if(ball_pos <5.5 && ball_pos> -4.5){
        PositionInFormation[0]=Vector3D.cartesian((ball_pos - 5) * flip, 0 * flip , 0);
        PositionInFormation[1]=Vector3D.cartesian((ball_pos - 1) * flip, 0 * flip, 0);
        PositionInFormation[2]=Vector3D.cartesian((ball_pos + 4) * flip, 0 * flip, 0);
        PositionInFormation[3]=Vector3D.cartesian((ball_pos - 5) * flip, -3 * flip, 0);
        PositionInFormation[4]=Vector3D.cartesian((ball_pos - 5) * flip, 3 * flip, 0);
        PositionInFormation[5]=Vector3D.cartesian((ball_pos - 1) * flip, -3 * flip, 0);
        PositionInFormation[6]=Vector3D.cartesian((ball_pos - 1) * flip, +3 * flip, 0);
    }else{
        if(ball_pos <= 0){
            PositionInFormation[0]=Vector3D.cartesian(-9 * flip, 0 * flip, 0);
            PositionInFormation[1]=Vector3D.cartesian(-5 * flip, 0 * flip, 0);
            PositionInFormation[2]=Vector3D.cartesian(0 * flip, 0 * flip, 0);
            PositionInFormation[3]=Vector3D.cartesian(-9 * flip, -4 * flip, 0);
            PositionInFormation[4]=Vector3D.cartesian(-9 * flip, 4 * flip, 0);
            PositionInFormation[5]=Vector3D.cartesian(-5 * flip, -4 * flip, 0);
            PositionInFormation[6]=Vector3D.cartesian(-5 * flip, +4 * flip, 0);
        }
        else {
            PositionInFormation[0]=Vector3D.cartesian(0 * flip, 0 * flip, 0);
            PositionInFormation[1]=Vector3D.cartesian(4 * flip, 0 * flip, 0);
            PositionInFormation[2]=Vector3D.cartesian(8 * flip, 0 * flip, 0);
            PositionInFormation[3]=Vector3D.cartesian(0 * flip, -4 * flip, 0);
            PositionInFormation[4]=Vector3D.cartesian(0 * flip, 4 * flip, 0);
            PositionInFormation[5]=Vector3D.cartesian(4 * flip, -4 * flip, 0);
            PositionInFormation[6]=Vector3D.cartesian(4 * flip, +4 * flip, 0);
        }
    }

    for(int i=0;i <7;i++){
        if(AgentInfo.playerId == i+1) {
            pos = PositionInFormation[i];
        }
    }
}