Greenfoot
| m (→Náhodná čísla:  Doplnění) |  (Přidání ukázky: Game over! s textovým aktérem.) | ||
| (Není zobrazeno 29 mezilehlých verzí od 1 uživatele.) | |||
| Řádka 1: | Řádka 1: | ||
| − | [[Category:VSE]][[Category:Informatika]][[Category:Programování]] | + | [[Category:VSE]][[Category:Informatika]][[Category:Programování]][[Category:Java]][[Category:Greenfoot]] | 
| + | |||
| == Co je to Greenfoot? == | == Co je to Greenfoot? == | ||
| − | |||
| − | |||
| − | + | Greenfoot je framework pro tvorbu jednoduchých 2D her, postavený na programovacích jazycích Java a Stride (my zde využíváme jazyk Java). | |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ; Princip funkce | |
| − | * | + | * Vzhled hry popisuje třída, která musí být potomkem třídy <code>World</code>. Předpokládejme, že se bude jmenovat <code>HraWorld</code>, ale název si můžeme vymyslet. | 
| − | * | + | * Na hrací ploše jsou aktéři (''actor''). | 
| − | * | + | * Chování aktérů je popsáno třídami, které jsou potomky třídy <code>Actor</code>. | 
| − | * | + | * Aktéři jsou vizuálně zastoupeni obrázkem, který vybíráme při vytvoření třídy aktéra. | 
| − | + | ; Průběh hry: | |
| + | # Vytvoří se instance třídy <code>HraWorld</code> (resp. jak jsme nazvali svého potomka třídy <code>World</code>). | ||
| + | # Spustí se konstruktor třídy <code>HraWorld</code>. | ||
| + | # A dále se opakuje: | ||
| + | ## Zavolá se metoda <code>act()</code> na svět (potomka třídy <code>HraWorld</code>). | ||
| + | ## Zavolá se metoda <code>act()</code> pro všechny aktéry. | ||
| − | ==  | + | |
| + | |||
| + | == Vytváření aktérů == | ||
| + | ; Příprava instance aktéra | ||
| + | * Prvky ve hře (postavy atd.) jsou třídy, které jsou potomky třídy <code>Actor</code>. | ||
| + | * Jejich instance vytváříme stejně jako vždy v Javě: operátorem <code>new</code>. | ||
| + | |||
| + | ;Umístění instance aktéra na plochu: | ||
| + | * Metoda <code>World.addObject(Actor actor, int x, int y)</code>. | ||
| + | * Umístí aktéra na pozici (x, y) | ||
| + | |||
| + | ; Odstranění aktéra z plochy | ||
| + | * Metoda <code>World.removeObject(Actor actor)</code>. | ||
| + | |||
| + | <div class="Priklad"> | ||
| + | Příklad — Vytvoření aktéra třídy <code>Panacek</code> a umístění na souřadnice (200, 150). | ||
| + |   public class MojeHra extends World { | ||
| + |   ... | ||
| + |   public void MojeHra() { | ||
| + |     ... | ||
| + |     Panacek panacek = new Panacek(); | ||
| + |     this.addObject(panacek, 200, 150); | ||
| + |     ... | ||
| + |   } | ||
| + | </div> | ||
| + | |||
| + | |||
| + | |||
| + | == Nastavení pozice aktéra == | ||
| Máme dvě varianty ovládání prvku (actora): | Máme dvě varianty ovládání prvku (actora): | ||
| − | *turn()  | + | ; Relativní pozicování | 
| − | * | + | * <code>turn(int oKolik)</code> ... otáčí o daný počet stupňů ve směru hodinových ručiček | 
| − | * | + | * <code>move(int delka)</code> ... pokročí vpřed o daný počet dílků ve směru, do kterého je otočen | 
| − | ** | + | * <code>setRotation(int uhel)</code> ... natočí prvek do daného směru (0 je směr vpravo, po směru hodinových ručiček) | 
| − | ** | + | * <code>turnTowards(int x, int y)</code> ... natočí prvek směrem k zadaným souřadnicím. | 
| − | *Příklad  | + | ; Absolutní pozicování | 
| + | * <code>setLocation(int x, int y)</code> | ||
| + | ** přesune prvek na zadané souřadnice | ||
| + | ** obvykle je třeba uložit si souřadnice. | ||
| + | ; Příklad: vytvoření metody <code>move(int dx, int dy)</code> | ||
| + |     public void act()  | ||
| + |     { | ||
| + |         this.move(3,-1); | ||
| + |     } | ||
| + | |||
| + |     private void move(int dx, int dy) { | ||
| + |         int cilX = this.getX()+dx; | ||
| + |         int cilY = this.getY()+dy; | ||
| + |         this.turnTowards(cilX, cilY); | ||
| + |         this.setLocation(cilX, cilY); | ||
| + |     } | ||
| + | |||
| + | |||
| + | == Změna obrázku aktéra == | ||
| + | Ke změně obrázku slouží metody: | ||
| + |  Actor.setImage(GreenfootImage novyObrazek) | ||
| + |  Actor.setImage(String cestaKNovemuObrazku) | ||
| + | |||
| + | Pokud zadáme cestu k obrázku, obrázek se hledá v podsložce <tt>images</tt> složky s projektem. | ||
| + | |||
| + | ; Příklad 1) Otočení vlevo či vpravo | ||
| + |  class Panacek extends Actor | ||
| + |      GreenfootImage imgVlevo = new GreenfootImage("imgVlevo.png"); | ||
| + |      // ... | ||
| + |      public void act() { | ||
| + |          // ... | ||
| + |          if (Greenfoot.isKeyDown("left")) { | ||
| + |              this.setLocation(this.getX()-1, this.getY()); | ||
| + |              this.setImage(imgVlevo); | ||
| + |          } | ||
| + |          // ... | ||
| + |      } | ||
| + |  } | ||
| + | |||
| + | |||
| + | |||
| + | === Aktér s textovým popisem === | ||
| + | Pokud chceme místo obrázku aktéra zobrazit text, využijeme alternativní konstruktor třídy <code>GreenfootImage</code>: | ||
| + |      GreenfootImage imgVlevo = new GreenfootImage("Vlevo!", 50, Color.RED, Color.YELLOW); | ||
| + | Zbytek kódu zůstává stejný. Jen potřebujeme navíc do hlavičky (úplně na začátek kódu třídy aktéra) doplnit k importu tříd knihovny <code>Greenfoot</code> i import třídy <code>java.awt.Color</code>: | ||
| + |     import Greenfoot.*; | ||
| + |     '''import java.awt.Color;''' | ||
| + |     ... | ||
| + | |||
| + | <div class="Priklad"> | ||
| + | ; Příklad — „Game over!“ | ||
| + | * Připravme si hlášení „Game over!“, které zobrazíme na konci hry. | ||
| + | |||
| + | Třída GameOver: | ||
| + | |||
| + |  import Greenfoot.*; | ||
| + |  import java.awt.Color; | ||
| + | |||
| + |  /** Třída GameOver bude reprezentovat aktéra, který bude fungovat jako  | ||
| + |   * textové hlášení. | ||
| + |   */ | ||
| + |  public class GameOver { | ||
| + |      public GameOver() { | ||
| + |          GreenfootImage imgGameOver = new GreenfootImage("Vlevo!", 50, Color.YELLOW, Color.BLUE); | ||
| + |          this.setImage(imgGameOver); | ||
| + |      } | ||
| + |  } | ||
| + | |||
| + | |||
| + | Ukončení hry: | ||
| + | |||
| + |  import Greenfoot.*; | ||
| + | |||
| + |  /** Třída Panáček - po srážce s kamenem ukončí hru. */ | ||
| + |  public class Panacek { | ||
| + |      public void act() { | ||
| + |          if (this.isTouching(Kamen.class)) { | ||
| + |              World svet = this.getWorld(); | ||
| + |              ''// Přidej hlášení "Game over!"'' | ||
| + |              svet.addObject('''new GameOver()''', svet.getWidth()/2, svet.getHeight/2); | ||
| + |              ''// Ukonči hru:'' | ||
| + |              '''Greenfoot.stop();''' | ||
| + |          } | ||
| + |      } | ||
| + |  } | ||
| + | |||
| + | Samozřejmě panáček toho může dělat víc a třídy se můžou jmenovat jinak. | ||
| + | </div> | ||
| + | |||
| + | |||
| == Reakce na klávesy == | == Reakce na klávesy == | ||
| − | + | === Stisk klávesy (napsání písmenka) === | |
| − | * | + | <code>String Greenfoot.getKey()</code> | 
| − | * | + | * Vrací <code>null</code>, když nebyla stisknuta žádná klávesa. | 
| + | * Odpovídá tomu, jak píše písmenka textový editor. | ||
| + | * Pokud uživatel drží stisknutou klávesu déle, pak: | ||
| + | *# Pošle se jedno písmeno, | ||
| + | *# nějakou dobu se počká a neposílá se nic, | ||
| + | *# pak se začne opakovaně vysílat písmeno, dokud uživatel klávesu nepustí, nebo  | ||
| + | * Speciální klávesy: | ||
| + | ** <code>"space"</code> ... mezerník | ||
| + | ** <code>"up"</code>, <code>"down"</code>, <code>"right"</code>, <code>"left"</code> ... šipky | ||
| + | ** <code>"F1"</code>,... funkční klávesy | ||
| − | + | ; Příklad: Pohyb podle kláves | |
|   String vstup = Greenfoot.getKey(); |   String vstup = Greenfoot.getKey(); | ||
|   if (vstup != null) { |   if (vstup != null) { | ||
| Řádka 46: | Řádka 173: | ||
|   } |   } | ||
| − | == Náhodná čísla == | + | === Detekce, zda uživatel drží klávesu === | 
| + | <code>boolean Greenfoot.isKeyDown(String klavesa)</code> | ||
| + | * Pokud uživatel drží klávesu delší dobu, zůstane platná pořád. | ||
| + | * Takto lze detekovat stisk více kláves zároveň, nemusí to však být tak spolehlivé. | ||
| + | |||
| + | === Funkční klávesy === | ||
| + | * Tímto způsobem můžeme detekovat i stisk funkčních kláves ''Control'' a ''Shift''. | ||
| + | * Kódy pro tyto klávesy jsou <code>"control"</code> a <code>"shift"</code>. | ||
| + | * Pokud tedy chceme detekovat kombinaci <code><Ctrl>+<Shift>+<S></code>, pak píšeme: | ||
| + |  String pismeno = Greenfoot.getKey(); | ||
| + |  if (Greenfoot.isKeyDown("control") && Greenfoot.isKeyDown("shift") && "s".equals(pismeno)) { | ||
| + |     ''... co se má stát ... '' | ||
| + |  } | ||
| + | |||
| + | === Jak detekovat pouze písmena a čísla? === | ||
| + | * Občas bychom chtěli reagovat pouze na alfanumerické znaky (písmena a čísla). | ||
| + | * K tomu můžete použít jednoduchý trik — většina funkčních kláves má totiž kódy z více písmen. Můžeme tedy využít toho, že když je funkční kód klávesy jen jedno písmeno, považujeme ho za alfanumerický znak: | ||
| + |  String pismeno = Greenfoot.getKey(); | ||
| + |  if (pismeno.lenght() == 1) { | ||
| + |     ''... co se má stát ... '' | ||
| + |  } | ||
| + | |||
| + | == Zjištění pozice myši == | ||
| + |  <code>MouseInfo Greenfoot.getMouseInfo()</code> | ||
| + | * Vrací instanci třídy <code>MouseInfo</code>. | ||
| + | * <code>MouseInfo</code> nese informace o: | ||
| + | ** Pozici X a Y kurzoru: <code>int MouseInfo.getX()</code>, <code>int MouseInfo.getY()</code> | ||
| + | ** Stisku tlačítek,... | ||
| + | |||
| + | ; Příklad: Pohyb aktéra za myší | ||
| + |  public void act() { | ||
| + |      MouseInfo mi = Greenfoot.getMouseInfo(); | ||
| + |      int x = mi.getX(); | ||
| + |      int y = mi.getY(); | ||
| + |      int vzdalenost = (int) Math.sqrt(Math.pow(x-this.getX(),2)+Math.pow(y-this.getY(),2)); | ||
| + | |||
| + |      if (vzdalenost > 0) { | ||
| + |          this.turnTowards(x, y); | ||
| + |          this.move(Math.min(vzdalenost, 5)); | ||
| + |          this.setRotation(0); | ||
| + |      } | ||
| + |  } | ||
| + | |||
| + | |||
| + | |||
| + | == Další tipy == | ||
| + | |||
| + | === Náhodná čísla === | ||
| ; Standardní řešení Javy: | ; Standardní řešení Javy: | ||
| * <code>Math.random()</code> ... vrací čísla z intervalu <0, 1) | * <code>Math.random()</code> ... vrací čísla z intervalu <0, 1) | ||
| Řádka 54: | Řádka 228: | ||
| ** Vrací čísla z množiny {0, 1, ..., limit-1}. | ** Vrací čísla z množiny {0, 1, ..., limit-1}. | ||
| − | ==  | + | === Okraj obrazovky === | 
| − | *  | + | * Pro detekci, zda je aktér na okraji obrazovky, můžeme použít metodu <code>isAtEdge()</code>. | 
| + |  if (this.isAtEdge()) { | ||
| + |      this.turn(180); | ||
| + |  } | ||
| − | ==  | + | === Objekty mimo obrazovku === | 
| − | + | * Pokud v konstruktoru světa (třída <code>World</code>) použijete volitelný parametr, můžete povolit umístění objektů mimo obrazovku. | |
| − | + |  public class MyWorld extends World | |
| − | + |   { | |
| − | + |      public MyWorld() | |
| − | + |      { | |
| + |          super(600, 400, 1, '''false''');  | ||
| + |      } | ||
| + |  } | ||
| − | ==  | + | == Zjištění kolize aktérů ve hře == | 
| + | * Ke zjištění kolizí slouží metody ve třídě <tt>Actor</tt>, které se jmenují <code>get''XXX''Object''YYY''</code>. | ||
| + | * Metod je hodně, ale chovají se podobně: | ||
| + |  '''get'''OneIntersecting'''Object'''(class) | ||
| + | * Vrátí jeden kolidující objekt. | ||
| + | * Řeší kolizi jen objektů té třídy, kterou zadáme jako parametr. | ||
| + | * Pokud chceme, aby řešil kolize s objekty libovolné třídy, zadáme jako parametr <code>null</code>. | ||
| + |  '''get'''Intersecting'''Object'''s(class) | ||
| + | * Vrátí seznam všech objektů, kolidujících s aktérem. | ||
| + |  '''get'''One'''Object'''AtOffset(int dx, int dy, class) | ||
| + | * Vrátí jednoho aktéra z aktérů vzdálených nejvýše (dx, dy)(viz dále). | ||
| + |  ... | ||
| + | |||
| + | ; Výběr třídy objektů | ||
| + | * Pokud zadáte parametr typu <tt>class</tt>, bere v potaz pouze objekty zadaného typu. Pokud zadáme <code>null</code>, berou se v potaz všechny objekty. | ||
| + | |||
| + | Příklad: | ||
| + |  List<Actor> seznam = this.getIntersectingObjects(null);  | ||
| + | * Bere v potaz všechny typy aktérů. Může se jednat o aktéry různých typů (instance různých tříd). | ||
| + |  List<Jablko> seznam = this.getIntersectingObjects(Jablko.class); | ||
| + | * Detekuje pouze kolidující aktéry třídy <code>Jablko</code>, všechny ostatní objekty ignoruje!  | ||
| + | |||
| + | ; Návratová hodnota | ||
| + | Tyto metody vrací buď: | ||
| + | * první kolidující objekt daného typu nebo <code>null</code> když nekoliduje žádný objekt daného typu: | ||
| + |  private void vyresKolidujici() { | ||
| + |     Predmet predmet = (Predmet) this.getOneIntersectingObject(Predmet.class);  | ||
| + |     if (predmet != null) { | ||
| + |        ''... Co se má dít, třeba: ...'' | ||
| + |        this.getWorld().removeObject(predmet); | ||
| + |     } | ||
| + |  } | ||
| + | * nebo seznam (může být prázdný) všech kolidujících objektů daného typu: | ||
| + |  private void vyresKolidujici() { | ||
| + |     List<Actor> seznam = this.getIntersectingObjects(null);  | ||
| + |     for (Actor prvek : seznam) { | ||
| + |        prvek.aplikuj(this); | ||
| + |     } | ||
| + |  } | ||
| + | |||
| + | <div class="Poznamka"> | ||
| + | Pokud vrací metoda seznam kolidujících objektů, pak musíme importovat třídu <code>java.util.List</code> tím, že napíšeme úplně na začátek: | ||
| + | |||
| + |  import java.util.List; | ||
| + | </div> | ||
| + | |||
| + | ; Filtr | ||
| + | * intersecting objects ... objekty, které se prolínají se stávajícím (došlo ke kolizi) | ||
| + | * objects at offset ... objekty, které jsou v dané vzdálenosti (dx, dy) od stávajícího objektu | ||
| + | |||
| + | == Práce s prostředím hry (World) == | ||
| + | |||
| + | === Nastavení pozadí hrací plochy === | ||
| + | * Obrázek na pozadí prostředí/světa změníme metodou: | ||
| + |  World.setBackground(GreenfootImage obrazek) | ||
| + | * Tuto metodu můžeme zavolat například v konstruktoru našeho potomka třídy <code>World</code>. | ||
| + | |||
| + | === Přepínání prostředí/světů v Greenfootu === | ||
| + | * Pokud potřebujete přepnout hru do jiného prostředí (světa), máte k dispozici metodu: | ||
| + |  Greenfoot.setWorld(World ''novySvet'') | ||
| + | <div class="Priklad"> | ||
| + | Příklad: | ||
| + | 1. krok: Upravte třídu MyWorld: | ||
| + |  public class MyWorld extends World  | ||
| + |  { | ||
| + |  	int citac = 0; | ||
| + |  	int konec = 300; | ||
| + |  	public MyWorld() | ||
| + |  	{ | ||
| + |  		super(600, 400, 1);  | ||
| + |  	} | ||
| + |  	public void act() { | ||
| + |  		System.out.println("Zbývá: "+(this.konec-this.citac)); | ||
| + |  		this.citac++; | ||
| + |  		if (this.citac > this.konec)  | ||
| + |  		{ | ||
| + |  			Greenfoot.setWorld(new DruhySvet()); | ||
| + |  		} | ||
| + |  	} | ||
| + |  } | ||
| + | 2. krok: Vytvořte druhou instanci třídy World, které nastavte jako pozadí některý obrázek ze záložky Backgrounds: | ||
| + |  public class DruhySvet extends World  | ||
| + |  { | ||
| + |  	public MyWorld() | ||
| + |  	{ | ||
| + |  		super(600, 400, 1);  | ||
| + |  	}  | ||
| + |  } | ||
| + | Po spuštění hry by hra měla chvíli čekat a pak by se mělo změnit pozadí — dojde ke změně prostředí hry (world). | ||
| + | </div> | ||
| + | |||
| + | |||
| + | |||
| + | == Úkol: Zkuste si vytvořit hru! == | ||
| * Vytvořte hru, na které ukážete ty prvky práce v Greenfootu, které jsme si ukázali výše. | * Vytvořte hru, na které ukážete ty prvky práce v Greenfootu, které jsme si ukázali výše. | ||
| + | |||
| + | <div class="Priklad"> | ||
| + | Přikládám [https://www.facebook.com/events/558069520954069/?ref=22 pár nápadů pro inspiraci] z projektů řešených na [http://www.oauh.cz Obchodní akademii Uherské Hradiště - obor Informační technologie]. | ||
| + | </div> | ||
| + | |||
| + | |||
| + | == Související stránky == | ||
| + | * [[Greenfoot: Řešení častých úloh]] | ||
| + | * Máte-li probém se spouštěním aplikací na webu Greenfoot.org, zkuste: [[Spouštění appletů]]. | ||
| + | |||
| + | |||
| + | |||
| + | == Zdroje == | ||
| + | * Existují velmi rozsáhlá fóra (v angličtině), popisující řešení problémů v Greenfootu. Zkuste ve vyhledávači najít: <code>greenfoot ''téma-které-hledáte''</code>. | ||
| + | * Dokumentaci tříd najdete na adrese [http://www.greenfoot.org/files/javadoc/ Greenfoot.org → Javadoc] | ||
Aktuální verze z 18. 5. 2020, 09:08
| Obsah | 
Co je to Greenfoot?
Greenfoot je framework pro tvorbu jednoduchých 2D her, postavený na programovacích jazycích Java a Stride (my zde využíváme jazyk Java).
- Princip funkce
-  Vzhled hry popisuje třída, která musí být potomkem třídy World. Předpokládejme, že se bude jmenovatHraWorld, ale název si můžeme vymyslet.
- Na hrací ploše jsou aktéři (actor).
-  Chování aktérů je popsáno třídami, které jsou potomky třídy Actor.
- Aktéři jsou vizuálně zastoupeni obrázkem, který vybíráme při vytvoření třídy aktéra.
- Průběh hry
-  Vytvoří se instance třídy HraWorld(resp. jak jsme nazvali svého potomka třídyWorld).
-  Spustí se konstruktor třídy HraWorld.
-  A dále se opakuje:
-  Zavolá se metoda act()na svět (potomka třídyHraWorld).
-  Zavolá se metoda act()pro všechny aktéry.
 
-  Zavolá se metoda 
Vytváření aktérů
- Příprava instance aktéra
-  Prvky ve hře (postavy atd.) jsou třídy, které jsou potomky třídy Actor.
-  Jejich instance vytváříme stejně jako vždy v Javě: operátorem new.
- Umístění instance aktéra na plochu
-  Metoda World.addObject(Actor actor, int x, int y).
- Umístí aktéra na pozici (x, y)
- Odstranění aktéra z plochy
-  Metoda World.removeObject(Actor actor).
Příklad — Vytvoření aktéra třídy Panacek a umístění na souřadnice (200, 150).
 public class MojeHra extends World {
 ...
 public void MojeHra() {
   ...
   Panacek panacek = new Panacek();
   this.addObject(panacek, 200, 150);
   ...
 }
Nastavení pozice aktéra
Máme dvě varianty ovládání prvku (actora):
- Relativní pozicování
-  turn(int oKolik)... otáčí o daný počet stupňů ve směru hodinových ručiček
-  move(int delka)... pokročí vpřed o daný počet dílků ve směru, do kterého je otočen
-  setRotation(int uhel)... natočí prvek do daného směru (0 je směr vpravo, po směru hodinových ručiček)
-  turnTowards(int x, int y)... natočí prvek směrem k zadaným souřadnicím.
- Absolutní pozicování
-  setLocation(int x, int y)- přesune prvek na zadané souřadnice
- obvykle je třeba uložit si souřadnice.
 
- Příklad
-  vytvoření metody move(int dx, int dy)
   public void act() 
   {
       this.move(3,-1);
   }
   
   private void move(int dx, int dy) {
       int cilX = this.getX()+dx;
       int cilY = this.getY()+dy;
       this.turnTowards(cilX, cilY);
       this.setLocation(cilX, cilY);
   }
Změna obrázku aktéra
Ke změně obrázku slouží metody:
Actor.setImage(GreenfootImage novyObrazek) Actor.setImage(String cestaKNovemuObrazku)
Pokud zadáme cestu k obrázku, obrázek se hledá v podsložce images složky s projektem.
- Příklad 1) Otočení vlevo či vpravo
class Panacek extends Actor
    GreenfootImage imgVlevo = new GreenfootImage("imgVlevo.png");
    // ...
    public void act() {
        // ...
        if (Greenfoot.isKeyDown("left")) {
            this.setLocation(this.getX()-1, this.getY());
            this.setImage(imgVlevo);
        }
        // ...
    }
}
Aktér s textovým popisem
Pokud chceme místo obrázku aktéra zobrazit text, využijeme alternativní konstruktor třídy GreenfootImage:
    GreenfootImage imgVlevo = new GreenfootImage("Vlevo!", 50, Color.RED, Color.YELLOW);
Zbytek kódu zůstává stejný. Jen potřebujeme navíc do hlavičky (úplně na začátek kódu třídy aktéra) doplnit k importu tříd knihovny Greenfoot i import třídy java.awt.Color:
import Greenfoot.*; import java.awt.Color; ...
- Příklad — „Game over!“
- Připravme si hlášení „Game over!“, které zobrazíme na konci hry.
Třída GameOver:
import Greenfoot.*;
import java.awt.Color;
/** Třída GameOver bude reprezentovat aktéra, který bude fungovat jako 
 * textové hlášení.
 */
public class GameOver {
    public GameOver() {
        GreenfootImage imgGameOver = new GreenfootImage("Vlevo!", 50, Color.YELLOW, Color.BLUE);
        this.setImage(imgGameOver);
    }
}
Ukončení hry:
import Greenfoot.*;
/** Třída Panáček - po srážce s kamenem ukončí hru. */
public class Panacek {
    public void act() {
        if (this.isTouching(Kamen.class)) {
            World svet = this.getWorld();
            // Přidej hlášení "Game over!"
            svet.addObject(new GameOver(), svet.getWidth()/2, svet.getHeight/2);
            // Ukonči hru:
            Greenfoot.stop();
        }
    }
}
Samozřejmě panáček toho může dělat víc a třídy se můžou jmenovat jinak.
Reakce na klávesy
Stisk klávesy (napsání písmenka)
String Greenfoot.getKey()
-  Vrací null, když nebyla stisknuta žádná klávesa.
- Odpovídá tomu, jak píše písmenka textový editor.
-  Pokud uživatel drží stisknutou klávesu déle, pak:
- Pošle se jedno písmeno,
- nějakou dobu se počká a neposílá se nic,
- pak se začne opakovaně vysílat písmeno, dokud uživatel klávesu nepustí, nebo
 
-  Speciální klávesy:
-  "space"... mezerník
-  "up","down","right","left"... šipky
-  "F1",... funkční klávesy
 
-  
- Příklad
- Pohyb podle kláves
String vstup = Greenfoot.getKey();
if (vstup != null) {
   if (vstup.equals("right")) {
      this.setRotation(0);
   } else if (vstup.equals("left")) {
      this.setRotation(180);
   } else if (vstup.equals("up")) {
      this.setRotation(-90);
   } else if (vstup.equals("down")) {
      this.setRotation(90);
   }
   this.move(1);
}
Detekce, zda uživatel drží klávesu
boolean Greenfoot.isKeyDown(String klavesa)
- Pokud uživatel drží klávesu delší dobu, zůstane platná pořád.
- Takto lze detekovat stisk více kláves zároveň, nemusí to však být tak spolehlivé.
Funkční klávesy
- Tímto způsobem můžeme detekovat i stisk funkčních kláves Control a Shift.
-  Kódy pro tyto klávesy jsou "control"a"shift".
-  Pokud tedy chceme detekovat kombinaci <Ctrl>+<Shift>+<S>, pak píšeme:
String pismeno = Greenfoot.getKey();
if (Greenfoot.isKeyDown("control") && Greenfoot.isKeyDown("shift") && "s".equals(pismeno)) {
   ... co se má stát ... 
}
Jak detekovat pouze písmena a čísla?
- Občas bychom chtěli reagovat pouze na alfanumerické znaky (písmena a čísla).
- K tomu můžete použít jednoduchý trik — většina funkčních kláves má totiž kódy z více písmen. Můžeme tedy využít toho, že když je funkční kód klávesy jen jedno písmeno, považujeme ho za alfanumerický znak:
String pismeno = Greenfoot.getKey();
if (pismeno.lenght() == 1) {
   ... co se má stát ... 
}
Zjištění pozice myši
MouseInfo Greenfoot.getMouseInfo()
-  Vrací instanci třídy MouseInfo.
-  MouseInfonese informace o:-  Pozici X a Y kurzoru: int MouseInfo.getX(),int MouseInfo.getY()
- Stisku tlačítek,...
 
-  Pozici X a Y kurzoru: 
- Příklad
- Pohyb aktéra za myší
public void act() {
    MouseInfo mi = Greenfoot.getMouseInfo();
    int x = mi.getX();
    int y = mi.getY();
    int vzdalenost = (int) Math.sqrt(Math.pow(x-this.getX(),2)+Math.pow(y-this.getY(),2));
    
    if (vzdalenost > 0) {
        this.turnTowards(x, y);
        this.move(Math.min(vzdalenost, 5));
        this.setRotation(0);
    }
}
Další tipy
Náhodná čísla
- Standardní řešení Javy
-  Math.random()... vrací čísla z intervalu <0, 1)
- Řešení Greenfootu
- Pro hry je často potřeba generovat celá čísla. Pro zjednodušení je tedy v Greenfootu metoda:
-  Greenfoot.getRandomNumber(int limit)- Vrací čísla z množiny {0, 1, ..., limit-1}.
 
Okraj obrazovky
-  Pro detekci, zda je aktér na okraji obrazovky, můžeme použít metodu isAtEdge().
if (this.isAtEdge()) {
    this.turn(180);
}
Objekty mimo obrazovku
-  Pokud v konstruktoru světa (třída World) použijete volitelný parametr, můžete povolit umístění objektů mimo obrazovku.
public class MyWorld extends World
{
    public MyWorld()
    {
        super(600, 400, 1, false); 
    }
}
Zjištění kolize aktérů ve hře
-  Ke zjištění kolizí slouží metody ve třídě Actor, které se jmenují getXXXObjectYYY.
- Metod je hodně, ale chovají se podobně:
getOneIntersectingObject(class)
- Vrátí jeden kolidující objekt.
- Řeší kolizi jen objektů té třídy, kterou zadáme jako parametr.
-  Pokud chceme, aby řešil kolize s objekty libovolné třídy, zadáme jako parametr null.
getIntersectingObjects(class)
- Vrátí seznam všech objektů, kolidujících s aktérem.
getOneObjectAtOffset(int dx, int dy, class)
- Vrátí jednoho aktéra z aktérů vzdálených nejvýše (dx, dy)(viz dále).
...
- Výběr třídy objektů
-  Pokud zadáte parametr typu class, bere v potaz pouze objekty zadaného typu. Pokud zadáme null, berou se v potaz všechny objekty.
Příklad:
List<Actor> seznam = this.getIntersectingObjects(null);
- Bere v potaz všechny typy aktérů. Může se jednat o aktéry různých typů (instance různých tříd).
List<Jablko> seznam = this.getIntersectingObjects(Jablko.class);
-  Detekuje pouze kolidující aktéry třídy Jablko, všechny ostatní objekty ignoruje!
- Návratová hodnota
Tyto metody vrací buď:
-  první kolidující objekt daného typu nebo nullkdyž nekoliduje žádný objekt daného typu:
private void vyresKolidujici() {
   Predmet predmet = (Predmet) this.getOneIntersectingObject(Predmet.class); 
   if (predmet != null) {
      ... Co se má dít, třeba: ...
      this.getWorld().removeObject(predmet);
   }
}
- nebo seznam (může být prázdný) všech kolidujících objektů daného typu:
private void vyresKolidujici() {
   List<Actor> seznam = this.getIntersectingObjects(null); 
   for (Actor prvek : seznam) {
      prvek.aplikuj(this);
   }
}
Pokud vrací metoda seznam kolidujících objektů, pak musíme importovat třídu java.util.List tím, že napíšeme úplně na začátek:
import java.util.List;
- Filtr
- intersecting objects ... objekty, které se prolínají se stávajícím (došlo ke kolizi)
- objects at offset ... objekty, které jsou v dané vzdálenosti (dx, dy) od stávajícího objektu
Práce s prostředím hry (World)
Nastavení pozadí hrací plochy
- Obrázek na pozadí prostředí/světa změníme metodou:
World.setBackground(GreenfootImage obrazek)
-  Tuto metodu můžeme zavolat například v konstruktoru našeho potomka třídy World.
Přepínání prostředí/světů v Greenfootu
- Pokud potřebujete přepnout hru do jiného prostředí (světa), máte k dispozici metodu:
Greenfoot.setWorld(World novySvet)
Příklad: 1. krok: Upravte třídu MyWorld:
public class MyWorld extends World 
{
	int citac = 0;
	int konec = 300;
	public MyWorld()
	{
		super(600, 400, 1); 
	}
	public void act() {
		System.out.println("Zbývá: "+(this.konec-this.citac));
		this.citac++;
		if (this.citac > this.konec) 
		{
			Greenfoot.setWorld(new DruhySvet());
		}
	}
}
2. krok: Vytvořte druhou instanci třídy World, které nastavte jako pozadí některý obrázek ze záložky Backgrounds:
public class DruhySvet extends World 
{
	public MyWorld()
	{
		super(600, 400, 1); 
	} 
}
Po spuštění hry by hra měla chvíli čekat a pak by se mělo změnit pozadí — dojde ke změně prostředí hry (world).
Úkol: Zkuste si vytvořit hru!
- Vytvořte hru, na které ukážete ty prvky práce v Greenfootu, které jsme si ukázali výše.
Přikládám pár nápadů pro inspiraci z projektů řešených na Obchodní akademii Uherské Hradiště - obor Informační technologie.
Související stránky
- Greenfoot: Řešení častých úloh
- Máte-li probém se spouštěním aplikací na webu Greenfoot.org, zkuste: Spouštění appletů.
Zdroje
-  Existují velmi rozsáhlá fóra (v angličtině), popisující řešení problémů v Greenfootu. Zkuste ve vyhledávači najít: greenfoot téma-které-hledáte.
- Dokumentaci tříd najdete na adrese Greenfoot.org → Javadoc
