Greenfoot: Řešení častých úloh
(Osamostatnění z stránky Greenfoot.) |
(Přidáno přepínání levelů) |
||
(Není zobrazeno 10 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) { | ||
− | + | 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í == | ||
+ | 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 <code>act()</code>: | ||
+ | |||
+ | 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 == | ||
+ | * Podobně jako vyskakovací hlášení můžeme realizovat i zobrazení počítadla bodů. I 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 32: | Řádka 76: | ||
private static Pocitadlo prvniHrac = null; | private static Pocitadlo prvniHrac = null; | ||
public static Pocitadlo getInstance() { | public static Pocitadlo getInstance() { | ||
− | if ( | + | if (Pocitadlo.prvniHrac == null) { |
− | + | Pocitadlo.prvniHrac = new Pocitadlo(); | |
} | } | ||
− | return | + | return Pocitadlo.prvniHrac; |
} | } | ||
Řádka 42: | Řádka 86: | ||
'''private''' Pocitadlo() { // private kvůli Jedináčkovi | '''private''' Pocitadlo() { // private kvůli Jedináčkovi | ||
− | this. | + | this.reset(); |
+ | } | ||
+ | public int getStav() { | ||
+ | return this.stav; | ||
} | } | ||
public void setStav(int stav) { | public void setStav(int stav) { | ||
this.stav = stav; | this.stav = stav; | ||
String text = "Skóre: "+this.stav; | String text = "Skóre: "+this.stav; | ||
− | GreenfootImage obrazek = new GreenfootImage(text, 20, Color. | + | GreenfootImage obrazek = new GreenfootImage(text, 20, Color.YELLOW, Color.GRAY); |
this.setImage(obrazek); | this.setImage(obrazek); | ||
} | } | ||
public void zmenStav(int zmena) { | public void zmenStav(int zmena) { | ||
this.setStav(this.stav+zmena); | this.setStav(this.stav+zmena); | ||
+ | } | ||
+ | public void reset() { | ||
+ | this.setStav(0); | ||
} | } | ||
} | } | ||
− | + | ; Přidání počitadla na plochu | |
+ | * Přidání počitadla na plochu provedeme v konstruktoru světa (třída <code>MyWorld</code> či jiná podle toho, jak si ji pojmenujeme). | ||
− | public | + | 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 | |
+ | * Ve kterékoli třídě pak můžeme vyvolat zjištění skóre: | ||
+ | ... | ||
+ | int skore = Pocitadlo.getInstance().getStav(); | ||
+ | ; Změnu skóre provedeme: | ||
... | ... | ||
− | Pocitadlo.getInstance().setStav(10); | + | Pocitadlo.getInstance().setStav(10); ''// Nastaví nový stav na 10 bodů - bez ohledu na předchozí stav.'' |
... | ... | ||
nebo | nebo | ||
... | ... | ||
− | Pocitadlo.getInstance().zmenStav(-2); | + | 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 == | ||
+ | |||
+ | * Projekt v 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
- Podobně jako vyskakovací hlášení můžeme realizovat i zobrazení počítadla bodů. I 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ý vzor Jedináček (Singleton).
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
- Přidání počitadla na plochu provedeme v konstruktoru světa (třída
MyWorld
či jiná podle toho, jak si ji pojmenujeme).
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
- Ve kterékoli třídě pak můžeme vyvolat zjištění 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
- Projekt v 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:
Greenfoot.setWorld(new Level2World())
. - 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()); } } }