# [2D] Karte neuzeichnen



## andi91 (24. Jan 2010)

Hallo!

Ich habe mich mit dem Tutorial von Quaxli auseinandergesetzt,möchte aber nicht so weit greifen und die "tile-basierte Karte" aus Teil2 weglassen,da bei meinem Rennspiel auch keine Schattenkarte etc. verwendet wird.

Ich möchte einfach mein GIF-Bild (die Straße) in der Mitte meines Panels zeichnen lassen und bei Bewegung des Autos immer wieder passend anhängen(so,dass die Straße unendlich ist).

Ich habe leider noch keine Möglichkeit gefunden,dass zu realisieren.

Ich würde mich über eine Idee/Anregung freuen!


----------



## Steev (24. Jan 2010)

Na ja, das ist doch eigendlich ganz einfach:

1. Du baust dir ein Straßen-Tileset

2. Du generierst eine Tilemap die gerade so groß ist, dass sie den gesamten Bildbereich abdeckt.
3. Wenn der Spieler am "oberen" Ende der Tilemap angelangt ist, dann springe ein Tile nach unten und Belege die oberen Tiles mit einem anderen Tile.
Der Spieler sollte halt immer nur nach vorne fahren können.

Tuts gibt es dazu sicher dutzende.


----------



## Quaxli (25. Jan 2010)

Steev hat gesagt.:


> 3. Wenn der Spieler am "oberen" Ende der Tilemap angelangt ist, dann springe ein Tile nach unten und Belege die oberen Tiles mit einem anderen Tile.
> Der Spieler sollte halt immer nur nach vorne fahren können.



Den 3. Punkt verstehe ich nicht. Davon ausgehende, daß die vertikale Bewegung des Fahrzeugs durch Verschieben des Hintergrunds simuliert wird, muß er ja oben ein neues Bild hinzeichnen, sobald daß erste Bild um einen Pixel nach unten verschoben wurde.
Das heißt wenn es eine gleichförmige Straße ist, benötigt er 2 Hintergrundbilder,die er verschiebt und sobald eines unten rausgewandert ist, muß es sofort oben angehängt werden.

Etwas ähnliches habe ich in horizontaler Richtung bei meinem FalconPatrol-Klon gemacht. Einfach mal auf den Link in der Signatur klicken. Da sind es zwar ein paar mehr als 2 Tiles aber das Ergebnis ist das Gleiche.


----------



## andi91 (25. Jan 2010)

Danke erstmal.Die Idee verstehe ich und sie gefällt mir auch.Nur muss ich dazu sagen,dass es sich bei meinem Projekt um meine Facharbeit in Informatik für die Schule handelt.Es ist also "Neuland",welches ich hier betrete und meine Kenntnisse sind in den 2/3 Wochen Arbeitsphase noch nicht so umfangreich,dass ich Ideen sofort umsetzen kann.

@Quaxli: Ich habe mich an deinem Tutorial sehr stark orientiert,d.h. ich habe das Rennspiel aus dem 2. Teil übernommen,da es vom Grundaufbau her stimmt.Das Prinzip muss ich jetzt ändern.

Mein Ziel ist ein Rennspiel mit einer "unendlich" geradeaus verlaufenden Straße.Für den Spieler ist das Ziel,solange wie möglich "unfallfrei" zu fahren.Damit meine ich,dass mit der Zeit das Spiel etwas schneller wird,in erster Linie aber der Spieler entgegenkommenden Elementen ausweichen soll.Am Ende sollen sich Spieler in einer Highscore-Tabelle messen(für die Facharbeit aber ein erstmal unwichtiger Zusatz,das Prinzip muss erstmal laufen).

Ich habe nun also ein Tileset für die Straße und suche eine Möglichkeit,auf die Level-Dateien aus dem Tutorial zu verzichten,und im Programm eine gerade Straße zu erzeugen(im Tut. sind ja auch Kurven und die Elemente sind auf den Tiles fest verbaut,das brauche ich nicht).

Ich würde das in der Klasse "MapDisplay" machen,wo die Tiles ohnehin zusammengesetzt werden,aber ich habe nur einen blassen Schimmer,wie das ganze ohne Level-Textdateien gemacht werden kann.


```
public MapDisplay(String level, String picpath, String shadowpath, int col, int row, GamePanel p){
    tiles = new Vector<Tile>();
    parent = (Rennspiel) p;
    
    loadLevelData(level);
    
    control = ImageControl.getInstance();
    control.setSourceImage(picpath, col, row);
    control.setShadowImage(shadowpath, col, row);
    
    display = new Rectangle2D.Double(0,0,parent.getWidth(),((Component) parent).getHeight());
  }
  
  private void loadLevelData(String level) {

    try {

      InputStreamReader isr = new InputStreamReader(getClass().getClassLoader()
          .getResourceAsStream(level));
      BufferedReader bufread = new BufferedReader(isr);

      String line = null;

      do {

        line = bufread.readLine();

        if (line == null) {
          continue;
        }
        
        String[] split = line.split("/");
        int posx = Integer.parseInt(split[0]);
        int posy = Integer.parseInt(split[1]);
        int width = Integer.parseInt(split[2]);
        int height = Integer.parseInt(split[3]);
        int num = Integer.parseInt(split[4]);

        if ((posx + width) > this.width) {
          this.width = posx + width;
        }

        if ((posy + height) > this.height) {
          this.height = posy + height;
        }

        Tile t = new Tile(posx, posy, width, height, num);
        tiles.add(t);

      } while (line != null);

      bufread.close();
      isr.close();

    } catch (IOException e) {
      e.printStackTrace();
    }

  }
```


----------



## Quaxli (26. Jan 2010)

Für dieses Problem mit der unendlichen, geraden Straße benötigst Du die Tile-Set-Geschichte aus dem Tutorial nicht. Das wäre sehr überfrachtet.
Wie Steev schon geschrieben hat, brauchst Du nur ein Hintergrundbild, das den gesamten Bildschirm abdeckt. Dieses Hintergrundbild wird verschoben, um die Bewegung zu simulieren. Du mußt dann nur jedesmal sicher stellen, daß oben ein 2. Bild angesetzt wird, damit die Straße fortlaufend ist.
Damit ist die grundsätzliche Logik ja schon mal klar, Du mußt das jetzt nur noch zusammenfrickeln. 
Das ist eigentlich gar nicht so schwer. Wenn's eine Facharbeit ist, mußt Du da schon selbst einiges an Gehirnschmalz reinstecken.
Mein Vorschlag, bastele ein kleines, kompilierbares, eigenständiges Beispiel, das nur dieses eine Problem abdeckt und wenn Du Fragen hast, kannst Du hier den Code posten.

<edit>
Was mir gerade noch so einfällt: Bei einer gleichförmigen, unendlichen Straße brauchst Du noch nicht mal ein bewegliches Hintergrundbild: In einfachster Ausprägung würden ja schon ein paar bewegliche Mittelstreifen ausreichen.... 
</edit>


----------



## andi91 (27. Jan 2010)

Danke für den Vorschlag,ich werde das so machen.

Jetzt gibt es aber viele Möglichkeiten,ein Hintergrundbild in ein JFrame oder Panel zu laden.In meiner aktuellen Variante ist das Bild zumindest erstmal angezeigt,jetzt müsste ich das Auto über der Straße zeichnen und sobald das Spiel gestartet wird und die Position des Autos um 1 Wert erhöht wurde,ein weiteres Bild anhängen...


```
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;


public class GamePanel extends JPanel implements Runnable {

  private static final long serialVersionUID = 1L;

 boolean game_running = true;

 long delta = 0;
 long last = 0;
 long fps = 0;

 private BufferedImage road;

  public GamePanel(int w, int h) {
  this.setPreferredSize(new Dimension(w,h));
  JFrame frame = new JFrame("Rennspiel");
  frame.setLocation(100, 100);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.add(this);
  frame.pack();
  frame.setVisible(true);
  doInitializations();


    try{

     road = ImageIO.read(new File("pics/road.gif"));

    }

      catch(IOException e){

       e.printStackTrace();

      }
 }

  public static void main(String[] args) {
   new GamePanel(300,600);
  }

  private void doInitializations() {
   last = System.nanoTime();

   Thread t = new Thread(this);
   t.start();
  }

   public void run() {
     while(game_running) {
      computeDelta();

      repaint();

       try {
        Thread.sleep(10);
       }
        catch (InterruptedException e){}

     }
   }

   private void computeDelta() {
     delta = System.nanoTime() - last;
     last = System.nanoTime();

     fps = ((long) 1e9)/delta;
   }

   @Override
   public void paintComponent(Graphics g) {
     super.paintComponent(g);

     g.setColor(Color.red);
     g.drawString("FPS: " + Long.toString(fps), 20, 10);
     g.drawImage(road, 0, 0, getWidth(), getHeight(), this);
   }

}
```


----------



## Quaxli (27. Jan 2010)

andi91 hat gesagt.:


> ...
> Jetzt gibt es aber viele Möglichkeiten,ein Hintergrundbild in ein JFrame oder Panel zu laden.



Es bietet sich JPanel an, da von Haus aus doppelt gepuffert.




andi91 hat gesagt.:


> ...
> ...jetzt müsste ich das Auto über der Straße zeichnen und sobald das Spiel gestartet wird und die Position des Autos um 1 Wert erhöht wurde,ein weiteres Bild anhängen...



Eigentlich bewegt sich das Auto nicht in Y-Richtung. Die Bewegung wird ja eigentlich durch Veränderung des Hintergrundes simuliert. Das heißt der Y-Wert des Bildes wird um n erhöht und oben ein neues Bild angehängt.
Ich würde aber nicht das Bild um 1 erhöhen,  sondern die Bewegung abhängig von der Zeit die der GameLoop benötigt hat abhängig machen.
Für einen ersten Test ist eine Erhöhung um 1 aber sicherlich erst einmal o.k.


----------

