Javaspel programmering handledning - Flappy fågeln Redux (9 / 12 steg)
Steg 9: Fade operationen
Vid denna tidpunkt, vi har mycket av vad behövs för att få spelet insvept: rören går på skärmen, klasserna spelare och hinder är färdiga, klassen PlayGameScreen är nästan klar och vi är nästan klar med TopClass.
Detta steg handlar om att göra spel flödet bättre. Om vi inte använde detta, skulle vi ha en abrupt hoppa från en välkomstskärm till en spelskärmen och det skulle vara mycket obehagligt att spela. Metoden fadeOperation i TopClass kommer att utföra en "enkel" vissna till svart och fade-från-svart att starta spelet.
Fade operationen kommer utlösas med metoden actionPerformed. När källan till ActionEvent är knappen startGame, ändrar vi loopVar till false berätta spelet öglan för att sluta köra. Nästa kallar vi fadeOperation().
Den första delen av handstil fadeOperation() startar en ny tråd för att hantera förändringarna framöver. Inom den nya tråd run()-metoden, vi först ta bort knappen från primära innehållspanelen (topPanel) och panelen bilder och sedan uppdatera topPanel. Sedan skapar vi en tillfällig JPanel (kallas temp) som vi kommer att lägga ovanpå topPanel; Detta är panelen vi tona (kom ihåg Toppanel's bakgrunden är svart).
Vi skapar en ny variabel för att hålla alpha, sedan inställd temp's bakgrund på en transparent svart JPanel. Vi lägga till temp i topPanel och lägga till PaintGameScreen-förekomsten (pgs) tillbaka på toppen av det, följt av en uppdatera.
Vid denna punkt, vi behöver ett tag loop att utföra den faktiska vissna till svart. Som i spelet slingan, vi skapar en variabel för att hålla iteration tiden, men denna gång, while loop slutet tillstånd är när panelen temp alfavärde är 255 (helt transparent). Ställa in en IF-sats att berätta för oss hur ofta för att utföra ändringar. Jag använde sedan en enkel If-Else uttalande för att diktera hur toningen sker (mestadels linjärt här). Du kan göra vad du vill här. Efter detta kan du ställa in temp's bakgrund och uppdatera topPanel.
När vissna till svart är klar, vi ta bort allt från topPanel, lägger till panelen temp, skapa en ny instans av PlayGameScreen (Tvingande pgs), ta bort rubriktexten och lägga till pgs tillbaka till topPanel. För att tona från svart, utför vi i huvudsak åtgärden vissna till svart motsatt logik.
När du är klar måste vi informera spelet som det är tillåtet för att börja. Det gör skapat vi ett globalt objekt som kallas buildComplete. I slutet av fadeOperation avtryckare vi manuellt en ActionEvent på buildComplete.
Den sista förändringen vi gör på detta steg är att metoden actionPerformed. Vi skapar en ny villkorlig (annars-om) för buildComplete. Här, vi skapar en ny tråd, och i dess run()-metoden, vi ändra loopVar tillbaka till sant (tillåta spelklocka köra igen) och anropa metoden gameScreen, denna gång passerar i falsk - vi ser därför på nästa steg.
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Image;
import java.awt.Color;
import java.awt.LayoutManager;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
allmän klass TopClass implementerar ActionListener {
globala konstant variabler
privata statisk sista int skärmbredd = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
privata statisk sista int SCREEN_HEIGHT = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
privata statisk sista int PIPE_GAP = SCREEN_HEIGHT/5; avståndet i bildpunkter mellan rören
privata statisk sista int PIPE_WIDTH = skärmbredd/8, PIPE_HEIGHT = 4 * PIPE_WIDTH;
privata statisk sista int UPDATE_DIFFERENCE = 25; tid i ms mellan uppdateringar
privata statisk sista int X_MOVEMENT_DIFFERENCE = 5; distansera det rör flytten varje uppdatering
privata statisk sista int SCREEN_DELAY = 300; behövs på grund av långa laddningstider tvingar rör dyka upp halva skärmen
globala variabler
privata boolean loopVar = sant; falskt -> Kör inte slinga; -True > springa slinga för rör
privata objekt buildComplete = ny objekt();
globala swing objekt
privat JFrame f = nya JFrame ("Flappy fågeln Redux");
privat JButton startGame;
privat JPanel topPanel; förklarat globalt att rymma måla verksamheten och möjliggöra removeAll(), etc.
andra globala objekt
privata statisk TopClass tc = nya TopClass();
privata statisk PlayGameScreen pgs; panel som har rörliga bakgrunden i början av spelet
/**
* Standardkonstruktör
*/
offentliga TopClass() {
}
/**
* Huvudsakliga körbara metoden anropas när du kör hittar.jar-filen
* args
*/
offentliga statisk void main (String [] args) {
bygga GUI på en ny tråd
javax.swing.SwingUtilities.invokeLater (nya Runnable() {
public void run() {
tc.buildFrame();
skapa en ny tråd för att hålla det grafiska Gränssnittet lyhörd medan spelet körs
Gänga t = nya Thread() {
public void run() {
tc.gameScreen(true);
}
};
t.start();
}
});
}
/**
-Metoden att bygga JFrame och lägga till programmet innehåll
*/
privata void buildFrame() {
Bildikon = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("resources/blue_bird.png"));
f.setContentPane(createContentPane());
f.setResizable(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setAlwaysOnTop(false);
f.setVisible(true);
f.setMinimumSize (ny Dimension (skärmbredd * 1/4, SCREEN_HEIGHT * 1/4));
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setIconImage(icon);
f.addKeyListener(this);
}
privat JPanel createContentPane() {
topPanel = nya JPanel(); översta JPanel i layout hierarki
topPanel.setBackground(Color.BLACK);
Tillåt oss till lagret panelerna
LayoutManager overlay = nya OverlayLayout(topPanel);
topPanel.setLayout(overlay);
Starta spelet JButton
startGame = ny JButton ("börja spela!");
startGame.setBackground(Color.BLUE);
startGame.setForeground(Color.WHITE);
startGame.setFocusable(false); snarare än bara setFocusabled(false)
startGame.setFont (nya typsnitt ("kaliber", Font.BOLD, 42));
startGame.setAlignmentX(0.5f); Centrera vågrätt på skärmen
startGame.setAlignmentY(0.5f); Centrera lodrätt på skärmen
startGame.addActionListener(this);
topPanel.add(startGame);
måste lägga till sist för att säkerställa knappens synlighet
PGS = nya PlayGameScreen (skärmbredd, SCREEN_HEIGHT, true); sant -> vi vill pgs vara startbilden
topPanel.add(pgs);
returnera topPanel;
}
/**
* Genomförandet för åtgärder händelser
*/
public void actionPerformed (ActionEvent e) {
IF(e.GetSource() == startGame) {
stoppa startbilden
loopVar = false;
fadeOperation();
}
annat if(e.getSource() == buildComplete) {
Gänga t = nya Thread() {
public void run() {
loopVar = sant;
tc.gameScreen(false);
}
};
t.start();
}
}
/**
* Utföra fade operation som sker innan rundor
*/
privata void fadeOperation() {
Gänga t = nya Thread() {
public void run() {
topPanel.remove(startGame);
topPanel.remove(pgs);
topPanel.revalidate();
topPanel.repaint();
panelen att blekna
JPanel temp = nya JPanel();
int alpha = 0; alfakanal variabel
temp.setBackground (ny färg (0, 0, 0, alfa)); transparent, svart JPanel
topPanel.add(temp);
topPanel.add(pgs);
topPanel.revalidate();
topPanel.repaint();
långa currentTime = System.currentTimeMillis();
långa startTime = currentTime;
While((system.currentTimeMillis() - startTime) > FADE_TIME_MILLIS || temp.getBackground().getAlpha()! = 255) {
IF((system.currentTimeMillis() - startTime) > UPDATE_DIFFERENCE/2) {
om (alpha < 255-10) {
alpha + = 10.
}
annat {
alpha = 255;
}
temp.setBackground (ny färg (0, 0, 0, alfa));
topPanel.revalidate();
topPanel.repaint();
startTime = System.currentTimeMillis();
}
}
topPanel.removeAll();
topPanel.add(temp);
PGS = nya PlayGameScreen (skärmbredd, SCREEN_HEIGHT, false);
pgs.sendText(""); ta bort rubriktext
topPanel.add(pgs);
While((system.currentTimeMillis() - startTime) > FADE_TIME_MILLIS || temp.getBackground().getAlpha()! = 0) {
IF((system.currentTimeMillis() - startTime) > UPDATE_DIFFERENCE/2) {
om (alfa > 10) {
alpha-= 10.
}
annat {
alpha = 0;
}
temp.setBackground (ny färg (0, 0, 0, alfa));
topPanel.revalidate();
topPanel.repaint();
startTime = System.currentTimeMillis();
}
}
actionPerformed (nya ActionEvent (buildComplete, -1, "Bygga avslutad"));
}
};
t.start();
}
/**
* Metod som utför plaska skärm grafik rörelser
*/
privata void gameScreen (boolean isSplash) {
BottomPipe bp1 = ny BottomPipe (PIPE_WIDTH, PIPE_HEIGHT);
BottomPipe bp2 = ny BottomPipe (PIPE_WIDTH, PIPE_HEIGHT);
TopPipe tp1 = ny TopPipe (PIPE_WIDTH, PIPE_HEIGHT);
TopPipe tp2 = ny TopPipe (PIPE_WIDTH, PIPE_HEIGHT);
variabler att spåra x och y bild platser för nedre röret
int xLoc1 = skärmbredd + SCREEN_DELAY, xLoc2 = (int) ((dubbel) 3.0/2.0*SCREEN_WIDTH+PIPE_WIDTH/2.0)+SCREEN_DELAY;
int yLoc1 = bottomPipeLoc(), yLoc2 = bottomPipeLoc();
variabel att hålla slingan starttid
långa startTime = System.currentTimeMillis();
While(loopVar) {
IF((system.currentTimeMillis() - startTime) > UPDATE_DIFFERENCE) {
Kontrollera om en uppsättning rör har skärmen
om så är fallet, Återställ rörets X läge och tilldela en ny Y plats
om (xLoc1 < (0-PIPE_WIDTH)) {
xLoc1 = skärmbredd;
yLoc1 = bottomPipeLoc();
}
annars om (xLoc2 < (0-PIPE_WIDTH)) {
xLoc2 = skärmbredd;
yLoc2 = bottomPipeLoc();
}
minska på röret platser med förutbestämda belopp
xLoc1-= X_MOVEMENT_DIFFERENCE;
xLoc2-= X_MOVEMENT_DIFFERENCE;
uppdatera BottomPipe och TopPipe platserna
BP1.setX(xLoc1);
BP1.setY(yLoc1);
bp2.setX(xLoc2);
bp2.setY(yLoc2);
TP1.setX(xLoc1);
TP1.setY(yLoc1-PIPE_GAP-PIPE_HEIGHT); säkerställa tp1 på rätt plats
TP2.setX(xLoc2);
TP2.setY(yLoc2-PIPE_GAP-PIPE_HEIGHT); säkerställa tp2 på rätt plats
som de BottomPipe och TopPipe lokala variablerna i PlayGameScreen genom att analysera de lokala variablerna
pgs.setBottomPipe (bp1, bp2);
pgs.setTopPipe (tp1, tp2);
uppdatera pgs's JPanel
topPanel.revalidate();
topPanel.repaint();
uppdatera variabeln tid-spårning efter alla som har slutförts
startTime = System.currentTimeMillis();
}
}
}
/**
* Beräknar ett slumpmässigt heltal för botten rörets placering
* int
*/
privata int bottomPipeLoc() {
int temp = 0;
iterera tills temp är ett värde som gör att båda rören vara på skärmen
medan (temp < = PIPE_GAP + 50 || temp > = SCREEN_HEIGHT-PIPE_GAP) {
Temp = (int) ((dubbel) Math.random()*((double)SCREEN_HEIGHT));
}
returnera härda;
}
}