Diskuze: Moja prvá hra - Arkanoid
V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.


public class Breaker {
private BlockBreakerPanel panel;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Breaker b = new Breaker();
b.zobraz();
}
private void zobraz() {
JFrame frame = new JFrame("Block Breaker");
frame.setSize(490, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.panel = new BlockBreakerPanel(this);
frame.add(this.panel);
frame.setVisible(true);
}
public BlockBreakerPanel getPanel() {
return this.panel;
}
}
class BlockBreakerPanel extends JPanel implements KeyListener, ActionListener {
private ArrayList<Blocks> blocks = new ArrayList<>();
private final Paddle hrac;
private final Ball ball;
private final Breaker game;
private boolean gameOver;
private int skore;
private boolean start;
public BlockBreakerPanel(Breaker game) {
setBackground(Color.BLACK);
for (int rad = 0; rad < 3; rad++) {
for (int i = 0; i < 8; i++) {
this.blocks.add(new Blocks(i * 60 + 2, rad * 40 + 5, 50, 30));
}
}
this.hrac = new Paddle(game);
this.ball = new Ball(game);
this.gameOver = false;
this.skore = 0;
this.start = false;
Timer t = new Timer(5, this);
t.start();
addKeyListener(this);
setFocusable(true);
this.game = game;
}
public void pridajBod() {
this.skore++;
}
public void jeKoniec() {
this.gameOver = true;
}
public ArrayList<Blocks> getBlocks() {
return this.blocks;
}
public Paddle getHrac() {
return this.hrac;
}
public void paint(Graphics g) {
super.paintComponent(g);
this.blocks.forEach((block) -> {
block.paint(g);
});
this.hrac.paint(g);
this.ball.paint(g);
if (!this.start) {
g.setFont(new Font("Calibri", Font.BOLD, 35));
g.setColor(Color.WHITE);
g.drawString("Pressed enter to start a game", 20, 300);
}
g.setFont(new Font("Calibri", Font.BOLD, 20));
g.setColor(Color.WHITE);
g.drawString(String.valueOf(this.skore), 450, 540);
if (this.gameOver) {
g.setFont(new Font("Calibri", Font.BOLD, 80));
g.setColor(Color.WHITE);
g.drawString("Game Over", 60, 300);
} else if (this.blocks.isEmpty()) {
this.gameOver = true;
g.setFont(new Font("Calibri", Font.BOLD, 80));
g.setColor(Color.WHITE);
g.drawString("You won", 80, 300);
}
}
private void update() {
this.ball.pohyb();
repaint();
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
this.start = true;
}
this.hrac.pressed(e.getKeyCode());
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void actionPerformed(ActionEvent e) {
if (!this.gameOver && this.start) {
this.update();
}
}
}
class Blocks {
private final int x;
private final int y;
private final int width;
private final int height;
public Blocks(int a, int b, int w, int h) {
this.x = a;
this.y = b;
this.width = w;
this.height = h;
}
public void paint(Graphics g) {
g.setColor(Color.pink);
g.drawRect(this.x, this.y, this.width, this.height);
g.fillRect(this.x, this.y, this.width, this.height);
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
}
public class Paddle {
private int x;
private final int y;
private final int width;
private final int height;
private final int posun;
private final Breaker game;
/**
*
* @param game
*/
public Paddle(Breaker game) {
this.x = 245 - (60/2);
this.y = 540;
this.width = 100;
this.height = 15;
this.posun = 10;
this.game = game;
}
public int getWidth() {
return this.width;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public void paint(Graphics g) {
g.setColor(Color.CYAN);
g.drawRect(this.x, this.y, this.width, this.height);
g.fillRect(this.x, this.y, this.width, this.height);
}
void pressed(int keyCode) {
this.kontrola();
if (keyCode == KeyEvent.VK_RIGHT) {
this.x += this.posun;
} else if (keyCode == KeyEvent.VK_LEFT) {
this.x -= this.posun;
}
}
private void kontrola() {
if ((this.x + this.width) >= 490) {
this.x = 490 - this.width;
} else if (this.x <= 0) {
this.x = 0;
}
}
}
public class Ball {
private final int PRIEMER = 20;
private int x;
private int y;
private int dx;
private int dy;
private final Breaker game;
/**
*
* @param game
*/
public Ball(Breaker game) {
this.x = 245 - (PRIEMER / 2);
this.y = 500;
this.dx = 2;
this.dy = 2;
this.game = game;
}
void paint(Graphics g) {
g.setColor(Color.PINK);
g.drawOval(this.x, this.y, PRIEMER, PRIEMER);
g.fillOval(this.x, this.y, PRIEMER, PRIEMER);
}
private void skontrolujKoliziu() {
boolean kolizia = false;
if (((this.y+PRIEMER) >= this.game.getPanel().getHrac().getY()) && ((this.x) >= this.game.getPanel().getHrac().getX()-2) && ((this.x+PRIEMER) <= (this.game.getPanel().getHrac().getX()+this.game.getPanel().getHrac().getWidth()+2))) {
kolizia = true;
} else if ((this.y + PRIEMER) >= 560) {
this.game.getPanel().jeKoniec();
return;
}
for (Blocks block : this.game.getPanel().getBlocks()) {
if ((this.y+5 <= (block.getY() + block.getHeight())) && (this.x+5 >= block.getX()) && ((this.x+PRIEMER-5) <= block.getX()+block.getWidth())) {
this.game.getPanel().getBlocks().remove(block);
kolizia = true;
this.game.getPanel().pridajBod();
break;
}
}
if (kolizia) {
this.dy = - this.dy;
}
}
public void pohyb() {
if (this.x <= 0 || this.x >= (460 + PRIEMER)) {
this.dx = -this.dx;
} else if (this.y <= 0 || this.y >= (540 + PRIEMER)) {
this.dy = -this.dy;
}
this.skontrolujKoliziu();
this.x += this.dx;
this.y += this.dy;
}
}
šikulka. Sice ti to
trošku uhýbá, kdy se kulička neodráží vpravo od zdi, ale projde zdí
(protože tam neodečítáš při pravém odrazu její šířku), ale vypadá to
zajímavě.
Musel jsem kód sice hodně upravit, abych to spustil, ale jinak dobrý start. Projdu si to a když tak ti napíšu, kudy se dál ubírat.
Třída Breaker:
- První, co mě hodně bouchlo do očí, tak je ten český název metody. Proč? Vždyť máš většinu v angličtině. Tak metody piš také anglicky.
- Trošku zkus přemýšlet nad implementací. U takového jednoduchého projektu to není tak zásadní, ale vidím, že jsi holka šikovná, tak tě chci navnadit, aby ses už učila přemýšlet nad samotnou implementací. Myslím, že se ti za chvíli otevřou dveře pro webové technologie, tak proto tento bodík.
V main metodě deklaruješ proměnnou Breaker b. Toto je velice špatný
návyk a pokud možno nezvykej si na to. Nauč se třeba ze začátku proměnné
pojmenovávat stejně jako třídu, akorát s malým písmenem. Proměnná b je
velmi špatný název a to zejména, jedná-li se o objekt!
Dále je to samotná deklarace. Využíváš ji tady pouze pro provolání
jedné metody. Zkus uvažovat tak, že když vytváříš proměnnou, tak to
není jen uložiště hodnot, ale využití místa v paměti.
Těch pár bajtíků teď skutečně nehraje roli a mám za to, že jedna
proměnná ti nezpozdí runtime ani o milisekundu Nicméně zkus uvažovat tak,
že budeš jednou pracovat s miliony dat. A tenhle zápis by už byl
problém.
Proto pokud není doopravdy potřeba, tak nevytvářej proměnné.
Dalo by se to zapsat klidně i takhle:
public static void main(String[] args) {
new Breaker().zobraz();
}
A nejlepší by bylo, kdybys rovnou zavolala konstruktor. Přeci jen
konstruktor je i od slova zkonstruovat, tak proč to nevyužít
Potom by celý příkaz vypadal jednoduše:
public static void main(String[] args) {
new Breaker();
}
- Velice oceňuji využití přístupové metody pro atribut panel. To svědčí o tom, že jsi na dobré cestě stát se skvělou programátorkou;)
- poslední poznámečku, kterou bych měl, tak je klíčové slovo this u
panelu. V Javě to není potřeba, pokud nesetuješ parametr přes stejný
název. Není to chyba a pokud bys přešla na JavaScript, tak tam to naopak
povinné je
zvlášť u angularu platí víc thisů víc adidas
Ale tady se to dalo napsat jak v getteru tak v metodě zobraz() bez toho this.
- U metody zobraz() nevidím kromě českého názvu problém. Pro swingovskou
aplikaci ti poradím dvě fintičky, které jsou příjemné
Jde mi o zarovnání na střed obrazovky.
Poradím ti dva způsoby, z čehož je jeden speciálně pro swing a druhý,
který můžeš využít i tu a tam v budoucnu kdekoliv jinde.
Java dokáže získat aktuální rozlišení obrazovky (ještě aby to neuměla,
hlavně na desktopu musí umět všechno ).
To získáš pomocí třídy Dimension. Ale abys ji mohla použít, potřebuješ
nástroj ze třídy Toolkit. Přiznám se, že já osobně jsem tuto třídu
nepoužil nikdy na nic jiného. Takže já jsem se to prostě mechanicky naučil
(není to úplně správný přístup, ale nebudu ti přece lhát).
Kdybys měla zájem, tak tyto třídy nabízí samozřejmě více možností.
Kupříkladu dokáží i vytáhnout aktuální obrazovku (v podstatě
printscreen). To jsem třeba používal, když jsem experimentoval a z prdele si
zkoušel napsat virus
private final Toolkit tool = Toolkit.getDefaultToolkit();
private final Dimension src = tool.getScreenSize();
V konstantě src máš nyní uložené parametry aktuální obrazovky
(aktuálního rozlišení).
No a nyní můžeš použít tento údaj pro výpočet.
Abys zarovnala něco na střed, tak musíš znát rozměr plochy, která
slouží jako podklad a plochu, která se má zarovnat. Pro šířku i výšku
to musíš nastavit samostatně.
Předvedu ti to na šířce.
Chceš, aby úsečka o rozměrech 20cm měla střed ve stejném bodě, jako
úsečka 100cm
Toho docílíš tak, že potřebuješ 2 počáteční souřadnice. U první
úsečky (100cm) je to samozřejmě 0. (Začínáme od nuly )
U druhé úsečky musíme tuto počáteční souřadnici vypočítat pomocí
vzorečku:
šířka první úsečky / 2 - šířka druhé úsečky
/ 2
V tomto případě tedy druhá úsečka (20cm) bude začínat v bodě:
(100 / 2) - (20 / 10) Což je 50 - 10, takže druhá úsečka musí začínat v
bodě 40.
Zkus si to třeba i nakreslit a uvidíš, že ti to dá lepší smysl
No a tak díky konstantně src, ve které máš parametry obrazovky a díky rozlišení framu, který taky znáš, tak to můžeš implementovat. Takže výsledný kód by vypadal následovně:
//src.width / 2 - frame.getWidth() / 2 <- to je pro x souřadnici
//src.height / 2 - frame.getHeight() / 2 <- to je pro y souřadnici
frame.setLocation(src.width / 2 - frame.getWidth() / 2, src.height / 2 - frame.getHeight() / 2);
Swing výše uvedený výpočet umí provést jednoduchou metodou. Takže stejného výsledku docílíš klidně i takhle:
frame.setLocationRelativeTo(null);
Parametr null znamená, že se bere defaultně obrazovka. Jinak bys tam mohla dát componentu swingu.
- Poslední, co mě napadá, co bys mohla rozšířit, tak že bys hodnoty 490, 600 a "Block Breaker" nepsala v kódu, ale vytvořila si na ně třeba Properties. To si třeba nastuduj a zkus implementovat. Může to být hezký úvod pro práci se soubory.
Třída BlockBreakerPanel:
- tady se pár věcí najde:) předně ty magické hodnoty by šly odstranit.
Magická hodnota je číslo, které máš na pevno v kódu. To znamená, že ti
to bude teď opravdu fungovat. Ale když změní rozlišení framu hry, tak se
ti to rozhodí. Takže určitě získávej hodnoty z jednoho místa. Jak jsem ti
doporučoval tu třídu Properties, tak to můžeš získávat ze souboru. Ale
nervy pak zas všechno přímo sem. Neboj se mít víc tříd. A jednu třídu
specializuj pouze na čtení ze souboru. A pak veškeré hodnoty ber pouze z
jednoho místa. To je nejžádanější. Mít konfiguraci hezky pohromadě. U
složitějších projektů se to potom sice dělí, ale to hlavně z důvodu
bezpečnosti. Ale podívej se - ty už tady v lehkém projektíku nastavuješ
velikost hry v jedné třídě a velikost kostiček ve druhé. A teď si
představ, že budeš mít složitou aplikaci a každý výpočet bude někde
jinde... To by tě jeblo. Zkus mít logiku výpočtu hezky na jednom místě.
Třeba v jednom balíčku (nazvi ho třeba businesslogic
) a tam měj třeba 1 nebo 3 třídy, kde budeš mít různé výpočty.
- s předchozím bodem souvisí i celá tato třída. Když mi řekneš JPanel, tak očekávám grafický objekt případně jeho vlastnosti a funkce. Tys do této třídy narvala veškerou logiku hry. Výpočty pohybu, posluchače, další objekty, atd.
Toto je velká chyba proti OOP a zejmena proti dědičnosti.
Ano, ono to jde a funguje to. Ale o tom vlastně celé programování je. Nemůžeš ťukat všechno tak, že to prostě jde. Ale musíš to rozdělovat do logických celků. Potom i sama poznáš, že programuješ správně - tak, že si to dokážeš logicky zdůvodnit, proč je tohle tam a tohle tam.
Hlavně se neboj více specifikovat skupiny. Rozděl určitě grafiku a logiku hry. Logiku rozděl tak, že jedna část se bude starat jen o výpočty komponent, další jen o skore a třeba o vyhodnocování hry (jestli jsi prohrála či ještě ne) a další logika třeba zas na něco jiného.
V podstatě... Kdybych ti teď řekl - zkus naprogramovat ukládání hry, tak ty to budeš hledat v panelu... To nedává smysl.
Dám ti pár rad, čím se řídit:
- když naprogramuješ obejkt, nejdřív zkus, jestli jej můžeš použít i jinde. Například. Naprogramuješ balonek. Tak zkus třídu balonek vyjmout z projektu, vytvoř úplně nový projekt a zjisti, co všechno musíš mít, abys tento balonek použila v tom novém projektu. Tím si ověříš, že programuješ objektově. Jestli je tvůj balonek závislý na nějakém jiném objektu, je to chyba. Pokud máš třeba nějakou swing komponentu, tak by ti mělo stačit, že ji přidáš na libovolný frame nebo panel. Nic víc nepotřebuješ pokud ano, už je to nějak specializované a je to chybka.
Příklad s tím balonkem. Měla by to být taková komponenta, kterou
implementuješ do jiného panelu a on se bude stejně pohybovat, bude stejně
reagovat a bude mít stejné možnosti.
Ať to dáš na JPanel, JFrame nebo třeba JTabbedPane.
- další věc dědičnost. Dědičnost by měla rozšiřovat předka, ale neměla by drasticky změnit jeho podstatu. Povím ti příklad z praxe.
Úloha zněla. Mám žábu a cyklistu. Oba mají definované metody pro
pohyb. Žába skáče, cyklista jede na kole po silnici.
Problém:
Máme úsek bez silnice. Místo silnice je voda a kameny. Jaké je řešení
problému pro cyklistu, který nemůže projet?
Jedním z návrhů bylo, že cyklista bude dědit od žáby, takže mohl
přeskákat s kolem po kamenech.
Fungovalo to! Bylo to super.
Sranda byla, že cyklista zdědil všechny metody žáby. Takže najednou uměl
skvěle kvákat a klást vajíčka...
Nejde jen o to, že nějaké metody použiješ a nějaké prostě ne. Projekt by měl mít logiku.
Ve tvém podání, kdybych si vzal třídu BlockBreakerPanel
(Kdyby se mi třeba líbilo, že by tento panel měl krásné duhové pozadí),
tak díky tomu získám i většinu logiky celé hry, ale ta mi nebude někdy
fungovat, protože potřebuje další třídy, se kterými nepočítám...
To máš stejné, jako kdyby sis koupila auto a k němu by sis musela koupit i globus, protože špatný výrobce do auta naprogramoval, i tlačítko, kterým rozsvěcuješ globus. Asi by se ti to nelíbilo, protože od auta bys v prvé řadě očekávala, že umí jezdit a ne nějaký globus.
Promiň, včera jsem měl ještě povinnosti, tak jsem to musel utnout.
Další věc, co bych tam ještě viděl, tak si nastuduj něco o rozhraní a
datových typech (takhle dohromady, kdy rozhraní figuruje jako datový
typ).
Narážím na deklaraci a implementaci proměnné
private ArrayList<Blocks> blocks = new ArrayList<>();
Je lepší v takovýchto případech deklarovat datový typ obecný. Tím myslím, že bys mohla tento kód nahradit tímto
private List<Blocks> blocks = new ArrayList<>();
Je to dobré proto, protože kdyby ses rozhodla někdy, že ti nevyhovuje ArrayList, ale třeba LinkedHashList, tak ti stačí změnit už pouze konstruktor v implementaci. No a bude ti to vždy takhle sedět.
Určitě bych pro popisek nepoužíval grafickou podobu nástroje. Jednak to
vypadá, jako text v DOS a hlavně proč by popisek nemohl být samostatnou
komponentou? Především, když to swing tak krásně nabízí - třída
Label.
Takže určitě tohle bys mohla přehodnotit.
Minimálně i proto, kdybys chtěla implementovat pauzu nebo různě editovat
text (třeba i s ním pracovat), tak tím, že jsi odkázána pro
překreslování všeho, tak je to chyba.
Dále jsem trošku nepochopil ten for-each, kterým provoláváš metody paint pro jednotlivé blocky. Je tam potřeba? Když třídě Blocks (mimochodem nepojmenovávej třídu množným číslem. Když vidím proměnnou blocks, tak mě první napadne, že je to nějaká kolekce nebo pole Blocků) nastavíš dědičnost z JComponent (vytvoříš z ní componentu), tak při její vytvoření se vždy provolá třída paint. (respektive repaint() ).
Takže ten for-each nepotřebuješ kór když bys chtěla provolávat tuhle
metodu.
Aby to ovšem fungovalo, musí tedy Blocks dědit z JComponent a potom je
musíš i přidat na ten panel.
Pak koukám ještě na dvě věci.
Když jsem si to procházel, tak myslím, že by sis mohla zjistit také,
jako swing funguje. Ono je to jednoduché - je to skládání komponent na panel
a panely na sebe.
Ty máš veškerou kreslící logiku v jedné metodě. To nesouvisí s tím, co
jsem ti říkal o tom, že by takováto logika měla být na jednom místě.
Prioritně každý objekt by měl umět stát sám o sobě. Balonek by se měl
umět vykreslit naprosto nezávisle na ostatních komponentách. To samé Kostka
to samé plošina to samé hlavní okno aplikace.
Společná logika na jednom místě tím myslím výpočty případně různé
parametry či jazykové mutace atd.
Lupnu ti sem i takový jednoduchý modelový příklad, ze kterého se můžeš inspirovat.
No a poslední věc, co bych asi viděl v této třídě, tak jsou
posluchače kláves.
Stejně jako u mouseListenerů, tak i keyListener správně implementuješ
pomocí rozhraní KeyListener.
Jak KeyListener, tak MouseListener mají v sobě několik metod. Ale sama jsi
teď ukázala, že ne vždy všechny využiješ.
U těchto dvou rozhraní se vývojářům zželelo nás programátorů, abychom
nemuseli implementovat prázdné metody a tak pro tato dvě rozhraní
implementovali do standardní knihovny i jejich abstraktní podoby.
To souvisí s tématem Rozhraní vs Abstraktní třída - to si klidně
nastuduj;)
V praxi to pro tebe bude znamenat tohle:
Máš rozhraní MouseListener. Toto rozhraní implementuje metody:
- mouseClicked
- mousePressed
- mouseReleased
- mouseEntered
- mouseExited
Ty bys potřebovala jen mousePressed metodu
Tak abys neměla potom zbytečně další 4 metody, které by byly prázdné,
tak můžeš místo rozhraní použít abstraktní třídu MouseAdapter
a díky tomu si můžeš vybrat přímo metodu/metody, které chceš použít.
Jinak není potřeba implementovat rozhraní. Ukážu ti v dalším příkladu, jak používat ve swingu key a mouse listnery/adaptery a ukážu ti i na tom konkrétní rozdíl.
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
public class Frame extends JFrame {
private int widthOfFrame = 500;
private int heightOfFrame = 500;
private Color ballColor = Color.RED;
private int ballSize = 25;
private int movingSpeed = 5;
public Frame() {
// 1. nastavíš si hlavní okno (můžeš použít dědičnost z JFrame a nebo JFrame skládat pomocí atributů, to je na tobě)
// NBD (Nice to Be Done) následujcí 4 řádky bys klidně mohla hodit samostatně třeba do metody init().
setSize(widthOfFrame + 6, heightOfFrame + 40);
setLocationRelativeTo(null);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
// 2. nastavíš si nějaký panel (klidně to může být tedy i tvoje vlastní třída, ale pozor, pokud dědíš z panelu, tak by podstata třídy měla zůstat panelem a nic jiného!!)
JPanel panel = new JPanel();
add(panel); // a panel přidáš hlavnímu oknu. Tím to končí
panel.setLayout(null); // Pokud budeš chtít programovat vykreslovací program, je dobré nenastavovat žádný layout. Díky tomu můžeš krásně kreslit bez toho, aniž by ti to automaticky někde zarovnávalo komponenty
// pak mu tady můžeš klidně nastavovat barvičky podle libosti
// 3. přidávej si kompoenty na panel (případně to můžeš opět víc rozčlenit na více panelů - jeden panel na skore, jeden na hru, jeden na menu, atd. atd. Swing je skutečně o skládání panelů. Proto existuje i mnoho layoutů)
Ball ball = new Ball(ballColor, ballSize);
panel.add(ball);
ball.moveBall(movingSpeed, heightOfFrame);
// následující dva bloky (body 4 a 5) budou dělat úplně to samé!!!
// 4. mouseListener (pomocí listner)
panel.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
// Ball ball = new Ball(ballColor, ballSize);
// ball.setLocation(e.getX() - ball.getWidth() / 2, e.getY() - ball.getHeight() / 2);
// panel.add(ball);
// ball.moveBall(movingSpeed, heightOfFrame);
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
});
// 5. mouseAdapter (abys viděla rozdíl)
panel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
Ball ball = new Ball(ballColor, ballSize);
ball.setLocation(e.getX() - ball.getWidth() / 2, e.getY() - ball.getHeight() / 2);
panel.add(ball);
ball.moveBall(movingSpeed, heightOfFrame);
}
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("Kliklo se"); // tato metoda je totálně na hovno:) jen je to ukázka toho, že si můžeš skutečně vybrat tolik metod, kolik potřebuješ
}
});
// To samé platí i pro keyListenera. Také můžeš vytvořit nový keyAdapater a vybrat si některou z těch metod
}
public static void main(String[] args) {
new Frame();
}
}
Kdybys měla jakékoliv dotazy, klidně mi i napiš soukromě. Vidíš sama,
jaký je to už jen ode mě spam ještě pár věcí by se našlo, ale myslím, že to už teď stačí
PS: tady máš případné vylepšení té blbinky, co jsem ti poslal, jen
pro zábavu
panel.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
Ball ball = new Ball(ballColor, ballSize);
ball.setLocation(e.getX() - ball.getWidth() / 2, e.getY() - ball.getHeight() / 2);
panel.add(ball);
ball.moveBall(movingSpeed, heightOfFrame);
}
});
Radek Veverka:25.8.2020 17:06
Proto pokud není doopravdy potřeba, tak nevytvářej proměnné.
To bych neřekl. Klidně lokální proměnné vytvářej, pokud myslíš, že je pak kód přehlednější. Mnohdy je lepší si rozepsat kód na více řádků a pracovat s dobře pojmenovanými dočasnými proměnnými, než vše nacpat na jeden 200 znakovej řádek. A co se týče výkonu, optimalizátor se ti o to většinou automaticky postará a vnitřně si kód předělá. S lokálními proměnnými bych si opravdu nedělal starosti. Třeba v C je to trochu o něčem jiném, ale v Javě je IMHO irelevantní nad tím takto úzkostlivě uvažovat.
Lubor Pešek:25.8.2020 18:25
Když vezmeš v potaz webové služby, tak tam záleží při velkém objemu dat na každé milisekundě. Ano, určitě není přehledné narvat logické výrazy všechny do jednoho řádku. Ale vytvářet proměnnou pouze pro jeden účel, do kterého nedáš ani výpočet, tak to fakt nemá smysl.
Radek Veverka:25.8.2020 20:05
Souhlasím, reagoval jsem ale na tu konkrétní citovanou větou. Pointa je neprasit si kód tím, že budu pořád myslet na to, abych měl co nejméně lokálních proměnných. Mám optimalizátor. Navíc aplikace zpravidla spálí 90% výkonu na 10% kódu, takže když už, tak to stačí řešit pouze v těchto kritických místech.
Neaktivní uživatel:26.8.2020 20:08
Ahoj,
v prvom rade ti chcem veľmi poďakovať za reakciu a pomoc. Skúšam to prerobiť podľa tvojich postrehov, no vôbec to nie je jednoduché. Napríklad by ma zaujímalo čo s ActionListenerom, potrebujem ho v podstate na prekreslovanie tých komponentov pomocou metódy repaint()? Môže byť napísané obdobne ako mouseListener?
Lubor Pešek:26.8.2020 23:06
Actionlistener nepotřebuje takovou implementaci, protože obsahuje pouze
jedinou metodu - actionPerform. Takže pokud toto použiješ, tak vždy pro tuto
metodu.
Tento posluchač se využívá u tlačítek.
Zobrazeno 14 zpráv z 14.