GameLoop Render Methode

Rinderfilet75

Neues Mitglied
Hey,

Ich arbeite seit ein paar Tagen an einem Java 16 Spiel.
Bei der GameLoop, die ich von einem YouTuber habe, komme ich bei der Render Methode nicht weiter, da ich nicht so richtig verstehe wie ich diese füllen muss. Die Update Methode und die GameLoop an sich verstehe ich aber.

Ich habe mal die Gui Klasse, das Label mit dem ich zeichne und die GameLoop angehangen.


[CODE lang="java" title="Gui Klasse"]package Graphic;

import javax.swing.JFrame;

public class Gui {

public Gui() {

Main.Variables.jf1 = new JFrame();
Main.Variables.jf1.setSize(Main.Variables.screenwidth, Main.Variables.screenhight);
Main.Variables.jf1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Main.Variables.jf1.setLocationRelativeTo(null);
Main.Variables.jf1.setLayout(null);
Main.Variables.jf1.setTitle("Asteroids");
Main.Variables.jf1.setResizable(false);
Main.Variables.jf1.requestFocus();
Main.Variables.jf1.addKeyListener(new InputHandler.KeyHandler());
Main.Variables.jf1.addMouseListener(new InputHandler.MouseHandler());
Main.Variables.jf1.addMouseMotionListener(new InputHandler.MouseHandler());
Main.Variables.jf1.addMouseWheelListener(new InputHandler.MouseHandler());
Main.Variables.jf1.setVisible(true);

Main.Variables.lb1 = new Label();
Main.Variables.lb1.setBounds(0, 0, Main.Variables.screenwidth, Main.Variables.screenhight);
Main.Variables.lb1.setVisible(true);
Main.Variables.jf1.add(Main.Variables.lb1);



}

}[/CODE]
[CODE lang="java" title="Label Klasse:"]

package Graphic;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;

import javax.swing.JLabel;

public class Label extends JLabel {

private static final long serialVersionUID = 1L;

protected void paintComponent(Graphics g) {

super.paintComponent(g);

Graphics2D g2d = (Graphics2D) g;

g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

// Cursor
setCursor(Toolkit.getDefaultToolkit().createCustomCursor(Main.Variables.c, new Point(0, 0), "Cursor"));

// Background
g.drawImage(Main.Variables.b1, Main.Variables.backgroundX1, Main.Variables.backgroundY, 1200, 800, null);
g.drawImage(Main.Variables.b2, Main.Variables.backgroundX2, Main.Variables.backgroundY, 1200, 800, null);

// AsteroidBackground
for (int i = 0; i < 5; i++) {

g.drawImage(Main.Variables.ab, Main.Variables.AsteroidBackgroundX, Main.Variables.AsteroidBackgroundY,
100, 100, null);

}
// Player
g.drawImage(Actors.Player.rotate(), Main.Variables.pX, Main.Variables.pY, null);

// Asteroids
for (int i = 0; i < 5; i++) {
g.drawImage(Main.Variables.a, Main.Variables.AsteroidX, Main.Variables.AsteroidY, 100, 100, null);
}

//Collision
if(Main.Variables.CollisionAsteroid == true) {

g.setColor(new Color(230, 0, 0, 30));
g.fillRect(0, 0, Main.Variables.screenwidth, Main.Variables.screenhight);

Main.Variables.CollisionAsteroid = false;

}

// Display

g.setFont(new Font("Arial", Font.BOLD, 20));

Color rainbow = new Color(Effects.Rainbow.r, Effects.Rainbow.g, Effects.Rainbow.b);

g.setColor(rainbow);

g.drawString("Pos X : " + Main.Variables.pX, 10, 720);
g.drawString("Pos Y : " + Main.Variables.pY, 10, 750);

g.setFont(new Font("Arial", Font.BOLD, 35));

g.drawString("Health : " + Main.Variables.PlayerHealth, 10, 40);


repaint();


}

}[/CODE]
[CODE lang="java" title="GameLoop"]package Main;

public class GameLoop implements Runnable {

private boolean running = true;

@Override
public void run() {

long lastTime = System.nanoTime();
final double FPS = 60.0;
double ns = 1000000000 / FPS;
double deltaTime = 0;

long timer = System.currentTimeMillis();

while (running) {

long currentTime = System.nanoTime();
deltaTime += (currentTime - lastTime) / ns;
lastTime = currentTime;

if (deltaTime >= 1) {

update();
deltaTime--;
render();

}

if(System.currentTimeMillis() - timer > 1000) {

timer += 1000;

}

}

}

private void render() {


}

private void update() {

Actors.Player.MovePlayer();
Actors.Asteroids.MoveAsteroids();
Actors.Collision.AsteroidCollision();
Effects.AsteroidsBackground.MoveAsteroidsBackground();
Effects.Background.MoveBackground();

}

}
[/CODE]
 
Also als erstes eine Bemerkung bezüglich der Quelle, aus der Du gelernt hast: Vergiss diese Quelle und such Dir bessere.

Der Ansatz mit einer Klasse, in der alles mögliche gespeichert wird, ist in einer objektorientierten Sprache einfach absoluter Quatsch.

In der Objektorientierten Entwicklung hast Du Objekte mit einem Status und gewissen Verhaltensweisen. Das bringt viele Vorteile mit sich, auf die ich nicht näher eingehe - aber es vereinfacht Dinge wenn man das einmal verstanden hat. Denn Du musst nicht an allen möglichen Stellen auf alles mögliche achten. Code ist da, wo er hin gehört.

Bezüglich deines konkreten Problems, da ist mir jetzt so auf Anhieb nichts aufgefallen, was ich direkt als Fehler einstufen würde.
Daher wäre wichtig, dass Du uns mehr Details gibt, was für Fehler auftreten bzw. was nicht oder falsch passiert.

Was mir auffällt: Dein Label wird ständig neu gemalt. Sobald er fertig ist, wird mit repaint angefordert, dass es erneut gemalt wird. Das macht nicht wirklich Sinn. Das führt zu einer Voll-Last auf einem Core. Du musst nur dann neu malen, wenn Du alles berechnet hast. Durch diesen Ablauf ist es so, dass Werte gezeichnet werden, so wie sie derzeit gespeichert sind. Sind halt zwei Threads, die nicht synchronisiert sind....

Das wäre einfach mal eine Rückmeldung von meiner Seite ...
 
Ok, die Ruckler sind normal, da Du halt ständig alles neu malst - und das passiert ja sozusagen Schritt für Schritt.

Eine mögliche Lösung wäre hier z.B.:
- Nach jeder Änderung in der Schleife wird alles in ein Bild gemalt.
- Wenn das Bild fertig gemalt ist, wird es für das Label (So heisst Die Klasse, die ja bei Dir die Anzeige macht) bereit gestellt und das neu Malen angestoßen.
- Label malt nur das bereit gestellte Bild.

Das mit dem Malen kann man sich wie Warteschlangen vorstellen:
- Eine Warteschlange für Bilder, die zu malen sind / die dargestellt werden können (*)
- Eine Warteschlange für Bilder, die neu gemalt werden können.

Vor der Darstellung passiert dann ein check: Ist in der Warteschlange für Bilder, die zu malen sind, ein Bild? Wenn ja, dann wird das aktuelle Bild in die Warteschlange für Bilder, die neu gemalt werden können, getan und das Bild aus der Warteschlange mit zu malenden Bildern als aktuelles Bild genommen.

Vor dem Malen wird ein Bild aus der Warteschlange für Bilder, die gemalt werden können, heraus genommen. (Ist die Warteschlange leer, dann wird ein neues Bild erstellt).
Dann wird das Bild erstellt.
Und am Ende kommt es in die Warteschlange für Bilder, die zu malen sind. Und hier merkt man: Wir wollen ja immer nur das aktuellste Bild malen. Wenn da bereits ein Bild drin ist, dann schieben wir es direkt in die Warteschlange für Bilder, die neu gemalt werden können. Und schon kommen wir zu (*), denn wir haben da maximal ein Bild . Also reicht eine einfache Referenz und wir brauchen keine Warteschlange.

Also generell nicht sehr viel Änderung. Das ist übrigens einfach zu bauen - Was wir nur beachten müssen: Wir greifen von 2 Threads aus zu, d.h. wir müssen die oben genannte Logik synchronized machen. Dann kann immer nur ein Thread eine Aufruf machen und der andere Thread muss zur Not kurz warten.
 

Zurück
Oben