Greenfoot: Řešení častých úloh

Z MiS
(Rozdíly mezi verzemi)
Přejít na: navigace, hledání
(Výpis stavu hry, hlášky: Rozdělení na dvě části - hlášení a počítadlo.)
(Přidáno přepínání levelů)
 
(Není zobrazeno 7 mezilehlých verzí od 1 uživatele.)
Řádka 18: Řádka 18:
 
         World svet = this.getWorld();
 
         World svet = this.getWorld();
 
         if (svet != null) {
 
         if (svet != null) {
             this.getWorld().removeObject(this);
+
             getWorld().removeObject(this);
 
         }
 
         }
 
     }
 
     }
 
  }
 
  }
  
 +
<div class="Varovani">
 +
Pokud vyjmete aktéra ze světa, nelze už volat metody, které jsou závislé na poloze aktéra ve světě. Volání metod <code>getX()</code>, <code>getY()</code>, <code>getWorld()</code>, <code>isAtEdge()</code> a dalších už nyní způsobí chybu!
 +
 +
Doporučujeme proto volat <code>removeObject(...)</code> jako poslední příkaz metody <code>act()</code>.
 +
</div>
  
 
== Aktér se objeví a zmizí ==
 
== Aktér se objeví a zmizí ==
Řádka 58: Řádka 63:
 
  ...
 
  ...
 
  this.setPaintOrder(Hlaseni.class); ''// Zařídí, že se hlášení objeví nahoře nad všemi ostatními aktéry.''
 
  this.setPaintOrder(Hlaseni.class); ''// Zařídí, že se hlášení objeví nahoře nad všemi ostatními aktéry.''
  this.getWorld().addObject(new Hlaseni());
+
  this.getWorld().addObject(new Hlaseni(), 300, 200);
 
  ...
 
  ...
  
  
== Výpis stavu hry, hlášky ==
+
== Počítadlo bodů, výpis stavu hry ==
Pro výpis skóre vytváříme nového speciálního „actora“ (objekt). Protože bude počitadlo pro celý projekt nejspíš jedno (nebo třeba jedno pro každého hráče), využijeme s výhodou [[Návrhové vzory#Jedináček|návrhový vzor Jedináček (Singleton)]].
+
* Podobně jako vyskakovací hlášení můžeme realizovat i&nbsp;zobrazení počítadla bodů. I&nbsp;tady vytváříme nového speciálního „actora“ (aktéra hry).  
 +
* Protože bude počitadlo pro celý projekt nejspíš jedno (nebo třeba jedno pro každého hráče), využijeme s výhodou [[Návrhové vzory#Jedináček|návrhový vzor Jedináček (Singleton)]].
  
 
  public class Pocitadlo extends Actor
 
  public class Pocitadlo extends Actor
Řádka 70: Řádka 76:
 
     private static Pocitadlo prvniHrac = null;
 
     private static Pocitadlo prvniHrac = null;
 
     public static Pocitadlo getInstance() {
 
     public static Pocitadlo getInstance() {
         if (this.prvniHrac == null)  
+
         if (Pocitadlo.prvniHrac == null) {
             this.prvniHrac = new Pocitadlo();
+
             Pocitadlo.prvniHrac = new Pocitadlo();
 
         }
 
         }
         return this.prvniHrac;
+
         return Pocitadlo.prvniHrac;
 
     }
 
     }
 
      
 
      
Řádka 80: Řádka 86:
 
      
 
      
 
     '''private''' Pocitadlo() { // private kvůli Jedináčkovi
 
     '''private''' Pocitadlo() { // private kvůli Jedináčkovi
         this.setStav(0);
+
         this.reset();
 +
    }
 +
    public int getStav() {
 +
        return this.stav;
 
     }
 
     }
 
     public void setStav(int stav) {
 
     public void setStav(int stav) {
Řádka 96: Řádka 105:
 
  }
 
  }
  
Na plochu počítadlo přidáme:
+
; Přidání počitadla na plochu
 +
* Přidání počitadla na plochu provedeme v&nbsp;konstruktoru světa (třída <code>MyWorld</code> či jiná podle toho, jak si ji pojmenujeme).
  
  public HraWorld() {
+
  public MyWorld() {
    ...
+
    this.setPaintOrder(Pocitadlo.class);
+
    this.addObject(Pocitadlo.getInstance(), 20, 20);
+
 
     ...
 
     ...
 +
    this.addObject(Pocitadlo.getInstance(), 50, 30);
 +
    Pocitadlo.getInstance().reset(); ''// Vynulování počítadla''
 +
    ''// Pokud se na stejném místě jako počítadlo objeví jiný objekt, bude vždy pod počitadlem:''
 +
    this.setPaintOrder(Pocitadlo.class);
 
  }
 
  }
  
Vynulování počítadla na začátku hry provedeme také v&nbsp;konstruktoru světa:
+
; Zjištění aktuálního skóre
 +
* Ve kterékoli třídě pak můžeme vyvolat zjištění skóre:
 +
...
 +
int skore = Pocitadlo.getInstance().getStav();
  
public HraWorld() {
+
; Změnu skóre provedeme:
    ...
+
    Pocitadlo.getInstance().reset();
+
    ...
+
}
+
 
+
Změnu skóre pak kdekoli v projektu můžeme vyvolat:
+
 
  ...
 
  ...
 
  Pocitadlo.getInstance().setStav(10); ''// Nastaví nový stav na 10 bodů - bez ohledu na předchozí stav.''
 
  Pocitadlo.getInstance().setStav(10); ''// Nastaví nový stav na 10 bodů - bez ohledu na předchozí stav.''
Řádka 123: Řádka 131:
  
 
== Zdi ==
 
== Zdi ==
 +
 +
Pokud chceme aktérovi zakázat pohyb skrz zdi, můžeme v&nbsp;každém kroku ověřit, jestli by se tímto krokem nedostal do zdi. Pohyb povolíme pouze v&nbsp;případě, kdy na cílových souřadnicích zeď není.
 +
 +
public class Panacek extends Actor
 +
{
 +
    private int rychlost = 3;
 +
    private int okrajAkteraX = getImage().getWidth()/2;
 +
    private int okrajAkteraY = getImage().getHeight()/2;
 +
   
 +
    private void pohybMimoZdi()
 +
    {
 +
        int offsetX = 0, offsetY = 0;
 +
        int smer = 0;
 +
        if (Greenfoot.isKeyDown("left"))
 +
        {
 +
            smer = -1;
 +
            offsetX = rychlost;
 +
        }
 +
        if (Greenfoot.isKeyDown("right"))
 +
        {
 +
            smer = 1;
 +
            offsetX = rychlost;
 +
        }
 +
        if (Greenfoot.isKeyDown("down"))
 +
        {
 +
            smer = 1;
 +
            offsetY = rychlost;
 +
        }
 +
        if (Greenfoot.isKeyDown("up"))
 +
        {
 +
            smer = -1;
 +
            offsetY = rychlost;
 +
        }
 +
       
 +
        if (
 +
                getObjectsAtOffset(
 +
                        smer*(offsetX+okrajAkteraX),
 +
                        smer*(offsetY+okrajAkteraY),
 +
                        Zed.class).size() == 0
 +
            )
 +
        {
 +
            setLocation(getX()+smer*offsetX, getY()+smer*offsetY);
 +
        }
 +
    }
 +
   
 +
    public void act()
 +
    {
 +
        pohybMimoZdi();
 +
    }
 +
}
 +
 +
 +
== Přepínání levelů/obrazovek ==
 +
 +
* Projekt v&nbsp;Greenfootu může mít více světů.
 +
* Svět může reprezentovat jeden level hry, nebo také úvodní či závěrečnou obrazovku.
 +
* Přepínání světů provedete příkazem: <code>Greenfoot.setWorld(new Level2World())</code>.
 +
* Dále uvádíme příklad řešení úvodní obrazovky. Úvodní obrazovka bude samostatný svět. Pozadí si můžete namalovat či použít existující obrázek. Tlačítka na úvodní obrazovce vyřešíte jako aktéry, kteří při kliknutí aktivují další svět:
 +
 +
public class TlacitkoStart extends Actor
 +
 +
    public TlacitkoStart()
 +
    {
 +
        setImage(new GreenfootImage("Start", 80, Color.YELLOW, Color.GRAY));
 +
    }
 +
    public void act()
 +
    {
 +
        if (Greenfoot.mouseClicked(this))
 +
        {
 +
            Greenfoot.setWorld(new MyWorld());   
 +
        }
 +
    }
 +
}
 +
  
  
 
== Související stránky ==
 
== Související stránky ==
 
* [[Greenfoot]]
 
* [[Greenfoot]]

Aktuální verze z 17. 7. 2024, 08:03


Obsah

Rušení aktérů

Příklad 1) Zrušení kolidujících actorů
private void act() {
   // ...
   World svet = this.getWorld();
   List<Actor> seznam = this.getIntersectingObjects(null); 
   for (Actor prvek : seznam) {
      prvek.aplikuj(this);
      svet.removeObject(prvek);
   }
Příklad 2) Zrušení aktéra, který vyjel mimo obrazovku na levém okraji
public void act() {
    // ...
    if (this.getX() < 1) {
        World svet = this.getWorld();
        if (svet != null) {
            getWorld().removeObject(this);
        }
    }
}

Pokud vyjmete aktéra ze světa, nelze už volat metody, které jsou závislé na poloze aktéra ve světě. Volání metod getX(), getY(), getWorld(), isAtEdge() a dalších už nyní způsobí chybu!

Doporučujeme proto volat removeObject(...) jako poslední příkaz metody act().

Aktér se objeví a zmizí

Pokud chceme aktéra, který se objeví na nějakou dobu a pak zmizí, stačí si v atributu počítá, kolikrát byla zavolána metoda act():

int jakDlouhoZiji = 0;
public void act() 
{
    this.jakDlouhoZiji++;
    if (this.jakDlouhoZiji >= 200) {
        World svet = this.getWorld();
        int x = Greenfoot.getRandomNumber(svet.getWidth());
        int y = Greenfoot.getRandomNumber(svet.getHeight());
        this.setLocation(x, y);
        this.jakDlouhoZiji = 0;
    }
}


Hlášení ve hře

Někdy potřebujeme hráče upozornit na nějakou událost ve hře vyskakovacím hlášením. V Greenfootu je to nejjednodušší tak, že vyrobíte aktéra, který bude mít místo obrázku text. Tohoto aktéra potom přidáte do světa.

Třída aktéra:

public class Hlaseni
{
    public Hlaseni()
    {
        GreenfootImage banner = new GreenfootImage("Text", 30, Color.YELLOW, Color.RED);
        this.setImage(banner);  
    }
}

Umístění aktéra do světa:

...
this.setPaintOrder(Hlaseni.class); // Zařídí, že se hlášení objeví nahoře nad všemi ostatními aktéry.
this.getWorld().addObject(new Hlaseni(), 300, 200);
...


Počítadlo bodů, výpis stavu hry

public class Pocitadlo extends Actor
{
    // Implementace Jedináčka:
    private static Pocitadlo prvniHrac = null;
    public static Pocitadlo getInstance() {
        if (Pocitadlo.prvniHrac == null) {
            Pocitadlo.prvniHrac = new Pocitadlo();
        }
        return Pocitadlo.prvniHrac;
    }
    
    // A zbytek kódu:
    private int stav;
    
    private Pocitadlo() { // private kvůli Jedináčkovi
        this.reset();
    }
    public int getStav() {
        return this.stav;
    }
    public void setStav(int stav) {
        this.stav = stav;
        String text = "Skóre: "+this.stav;
        GreenfootImage obrazek = new GreenfootImage(text, 20, Color.YELLOW, Color.GRAY);
        this.setImage(obrazek);
    }
    public void zmenStav(int zmena) {
        this.setStav(this.stav+zmena);
    }
    public void reset() {
        this.setStav(0);
    }
}
Přidání počitadla na plochu
public MyWorld() {
    ...
    this.addObject(Pocitadlo.getInstance(), 50, 30);
    Pocitadlo.getInstance().reset(); // Vynulování počítadla
    // Pokud se na stejném místě jako počítadlo objeví jiný objekt, bude vždy pod počitadlem:
    this.setPaintOrder(Pocitadlo.class); 
}
Zjištění aktuálního skóre
...
int skore = Pocitadlo.getInstance().getStav();
Změnu skóre provedeme
...
Pocitadlo.getInstance().setStav(10); // Nastaví nový stav na 10 bodů - bez ohledu na předchozí stav.
...

nebo

...
Pocitadlo.getInstance().zmenStav(-2); // Sníží stav počítadla o 2 body oproti předchozímu stavu.
...

Zdi

Pokud chceme aktérovi zakázat pohyb skrz zdi, můžeme v každém kroku ověřit, jestli by se tímto krokem nedostal do zdi. Pohyb povolíme pouze v případě, kdy na cílových souřadnicích zeď není.

public class Panacek extends Actor
{
    private int rychlost = 3;
    private int okrajAkteraX = getImage().getWidth()/2; 
    private int okrajAkteraY = getImage().getHeight()/2; 
    
    private void pohybMimoZdi()
    {
        int offsetX = 0, offsetY = 0;
        int smer = 0;
        if (Greenfoot.isKeyDown("left"))
        {
            smer = -1;
            offsetX = rychlost;
        }
        if (Greenfoot.isKeyDown("right"))
        {
            smer = 1;
            offsetX = rychlost;
        }
        if (Greenfoot.isKeyDown("down"))
        {
            smer = 1;
            offsetY = rychlost;
        }
        if (Greenfoot.isKeyDown("up"))
        {
            smer = -1;
            offsetY = rychlost;
        }
        
        if (
                getObjectsAtOffset(
                        smer*(offsetX+okrajAkteraX), 
                        smer*(offsetY+okrajAkteraY), 
                        Zed.class).size() == 0
            )
        {
            setLocation(getX()+smer*offsetX, getY()+smer*offsetY);
        }
    }
    
    public void act()
    {
        pohybMimoZdi();
    }
}


Přepínání levelů/obrazovek

public class TlacitkoStart extends Actor
{   
    public TlacitkoStart()
    {
        setImage(new GreenfootImage("Start", 80, Color.YELLOW, Color.GRAY));
    }
    public void act()
    {
        if (Greenfoot.mouseClicked(this)) 
        {
            Greenfoot.setWorld(new MyWorld());    
        }
    }
}


Související stránky

Osobní nástroje
Jmenné prostory
Varianty
Akce
Výuka
Navigace
Nástroje