# Hilfe mit mini-spiel für die Schule.



## Dschuls (18. Nov 2006)

Hey Leute,

Ich bin auf einem ITG und hab bis nach Weihnachten auf, ein (für euch wahrscheinlich seeehhhhrr) einfaches Spiel zu proggen...
Soweit sogut, ich hab auch schon eine Idee, aber die Umsetzung is doch ziemlich schwer, weil ich nicht wirklich gut proggen kann...! Deshalb hoff ich auf ein paar gute Tips, Denkanstöße und vllt. sogar ein paar Beispiele, die mir den Einstig etwas erleichtern.

*** Spieleprinzip:

Das Spiel (2D) soll aus einem Punkt (der durch die Maus kontrolliert wird) und "fallenden" Objekten bestehen, denen man mit der Maus ausweichen soll... (kennt ihr bestimmt) =)
Falls nicht, hab ich hier ein Link zum Beispiel: Klick mich

aber ich weiß echt nicht, wie ich das gestalten soll... 
z.B. gibts ja den "mouseEntered" Befehl, aber wie benutz ich den? 

Ich hab vom Lehrer eine: "GrLib" ausgeteilt bekommen... 


```
/*************************************************************************
 *
 *  Kompilieren:  javac GrLib.java
 *
 *  Ausfuehren:   java GrLib
 *
 *************************************************************************/

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.imageio.ImageIO;


public final class GrLib
        implements ActionListener, MouseListener, MouseMotionListener {

    // vordefinierte Farben
    public static final Color BLACK      = Color.BLACK;
    public static final Color BLUE       = Color.BLUE;
    public static final Color CYAN       = Color.CYAN;
    public static final Color DARK_GRAY  = Color.DARK_GRAY;
    public static final Color GRAY       = Color.GRAY;
    public static final Color GREEN      = Color.GREEN;
    public static final Color LIGHT_GRAY = Color.LIGHT_GRAY;
    public static final Color MAGENTA    = Color.MAGENTA;
    public static final Color ORANGE     = Color.ORANGE;
    public static final Color PINK       = Color.PINK;
    public static final Color RED        = Color.RED;
    public static final Color WHITE      = Color.WHITE;
    public static final Color YELLOW     = Color.YELLOW;

    // Standardfarben
    public static final Color DEFAULT_PEN_COLOR   = BLACK;
    public static final Color DEFAULT_CLEAR_COLOR = WHITE;

    // momentane Stiftfarbe
    private static Color penColor;

    // Standardgroesse fuer die Leinwand (canvas): SIZE mal SIZE
    private static final int SIZE = 512;
    private static int width  = SIZE;
    private static int height = SIZE;

    // Standardradius fuer den Stift
    private static final double DEFAULT_PEN_RADIUS = 0.002;

    // momentaner Stiftradius
    private static double penRadius;

    // gleich alles zeichnen oder bis zum naechsten draw warten?
    private static boolean defer = false;

    // Grenze der Leinwand: 5% 
    private static final double BORDER = 0.05;
    private static final double DEFAULT_XMIN = 0.0;
    private static final double DEFAULT_XMAX = 1.0;
    private static final double DEFAULT_YMIN = 0.0;
    private static final double DEFAULT_YMAX = 1.0;
    private static double xmin, ymin, xmax, ymax;

    // Standardschriftart
    private static final Font DEFAULT_FONT = new Font("Serif", Font.PLAIN, 16);

    // Momentane Schriftart
    private static Font font;

    // Zwischenspeicher fuer die Grafik
    private static BufferedImage offscreenImage, onscreenImage;
    private static Graphics2D offscreen, onscreen;

    // Bibliothek wird nur einmal erzeugt: ein Singleton
    private static GrLib std = new GrLib();

    // der Rahmen fuer das Fenster
    private static JFrame frame;

    // Maus-status Mausklicks und -position
    private static boolean mousePressed = false;
    private static double mouseX = 0;
    private static double mouseY = 0;


    // nicht instantiierbar
    private GrLib() { }


    // die static Initialisierung
    static { init(); }

    // Fenstergroesse wird auf w mal h pixel gesetzt
    public static void setCanvasSize(int w, int h) {
        width = w;
        height = h;
        init();
    }

    // init Methode fuer die static Initialisierung
    private static void init() {
        if (frame != null) frame.setVisible(false);
        frame = new JFrame();
        offscreenImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        onscreenImage  = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        offscreen = offscreenImage.createGraphics();
        onscreen  = onscreenImage.createGraphics();
        setXscale();
        setYscale();
        offscreen.setColor(DEFAULT_CLEAR_COLOR);
        offscreen.fillRect(0, 0, width, height);
        setPenColor();
        setPenRadius();
        setFont();
        clear();

        // antialiasing verbessert die Schriftdarstellung etwas
        RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
                                                  RenderingHints.VALUE_ANTIALIAS_ON);
        hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        offscreen.addRenderingHints(hints);

        // fuer den Rahmen
        ImageIcon icon = new ImageIcon(onscreenImage);
        JLabel draw = new JLabel(icon);

        // wir geben auf die Maus acht
        draw.addMouseListener(std);
        draw.addMouseMotionListener(std);

        // schon mal die Grundlagen
        frame.setContentPane(draw);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);            // alle Fenster schliesse
        // frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);      // nur aktuelles Fenster schliessen
        frame.setTitle("Grafik Bibliothek");
        frame.setJMenuBar(createMenuBar());
        frame.pack();
        frame.setVisible(true);
    }

    // Menueleiste anlegen
    public static JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("Datei");
        menuBar.add(menu);
        JMenuItem menuItem1 = new JMenuItem(" Speichern...   ");
        menuItem1.addActionListener(std);
        menuItem1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
                                Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        menu.add(menuItem1);
        return menuBar;
    }



    // die Skalierung des Koordinatensystems
    public static void setXscale() { setXscale(DEFAULT_XMIN, DEFAULT_XMAX); }
    public static void setYscale() { setYscale(DEFAULT_YMIN, DEFAULT_YMAX); }
    public static void setXscale(double min, double max) {
        double size = max - min;
        xmin = min - BORDER * size;
        xmax = max + BORDER * size;
    }
    public static void setYscale(double min, double max) {
        double size = max - min;
        ymin = min - BORDER * size;
        ymax = max + BORDER * size;
    }

    // Hilfsfunktionen, die zwischen Benutzerkoordinaten und Schirmkoordinaten umwandeln
    private static double scaleX (double x) { return width  * (x - xmin) / (xmax - xmin); }
    private static double scaleY (double y) { return height * (ymax - y) / (ymax - ymin); }
    private static double factorX(double w) { return w * width  / Math.abs(xmax - xmin);  }
    private static double factorY(double h) { return h * height / Math.abs(ymax - ymin);  }
    private static double userX  (double x) { return xmin + x * (xmax - xmin) / width;    }
    private static double userY  (double y) { return ymax - y * (ymax - ymin) / height;   }


    // den Schirm mit der uebergebenen Farbe loeschen
    public static void clear() { clear(DEFAULT_CLEAR_COLOR); }
    public static void clear(Color color) {
        offscreen.setColor(color);
        offscreen.fillRect(0, 0, width, height);
        offscreen.setColor(penColor);
        show();
    }

    // die Stiftgroesse einstellen
    public static void setPenRadius() { setPenRadius(DEFAULT_PEN_RADIUS); }
    public static void setPenRadius(double r) {
        penRadius = r * SIZE;
        BasicStroke stroke = new BasicStroke((float) penRadius);
        offscreen.setStroke(stroke);
    }

    // die Stiftfarbe einstellen
    public static void setPenColor() { setPenColor(DEFAULT_PEN_COLOR); }
    public static void setPenColor(Color color) {
        penColor = color;
        offscreen.setColor(penColor);
    }

    // eine Zeichenkette in der eingestellten Schriftart ausgeben
    public static void setFont() { setFont(DEFAULT_FONT); }
    public static void setFont(Font f) { font = f; }

    // eine Linie zeichnen: von (x0, y0) zu (x1, y1)
    public static void line(double x0, double y0, double x1, double y1) {
        offscreen.draw(new Line2D.Double(scaleX(x0), scaleY(y0), scaleX(x1), scaleY(y1)));
        show();
    }

    // einzelnen Pixel bei (x, y) zeichnen
    private static void pixel(double x, double y) {
        offscreen.fillRect((int) Math.round(scaleX(x)), (int) Math.round(scaleY(y)), 1, 1);
    }

    // einen Punkt bei (x, y) zeichnen
    public static void point(double x, double y) {
        double xs = scaleX(x);
        double ys = scaleY(y);
        double r = penRadius;
        // double ws = factorX(2*r);
        // double hs = factorY(2*r);
        // if (ws <= 1 && hs <= 1) pixel(x, y);
        if (r <= 1) pixel(x, y);
        else offscreen.fill(new Ellipse2D.Double(xs - r/2, ys - r/2, r, r));
        show();
    }

        
    // einen Kreis zeichnen, Radius r und Mittelpunkt (x,y)
    public static void circle(double x, double y, double r) {
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y); // Radius zu klein? dann Pixel
        else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        show();
    }


    // einen gefuellten Kreis zeichnen. Radius r, Mittelpunkt (x, y)
    public static void filledCircle(double x, double y, double r) {
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y); // Radius zu klein? dann Pixel
        else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        show();
    }

    // Quadrat zeichnen. Seitenlaenge 2r, Mittelpunkt (x, y)
    public static void square(double x, double y, double r) {
        // screen coordinates
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y); // zu klein? dann Pixel
        else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        show();
    }

    // Quadrat zeichnen. Seitenlaenge 2r, Mittelpunkt (x, y)
    public static void filledSquare(double x, double y, double r) {
        // screen coordinates
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y); // zu klein? dann Pixel
        else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        show();
    }

    // Polygon zeichnen. Koordinaten werden als (x[i], y[i]) uebergeben
    public static void polygon(double[] x, double[] y) {
        int N = x.length;
        GeneralPath path = new GeneralPath();
        path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0]));
        for (int i = 0; i < N; i++)
            path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i]));
        path.closePath();
        offscreen.draw(path);
        show();
    }

    // Polygon zeichnen. Koordinaten werden als (x[i], y[i]) uebergeben
    public static void filledPolygon(double[] x, double[] y) {
        int N = x.length;
        GeneralPath path = new GeneralPath();
        path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0]));
        for (int i = 0; i < N; i++)
            path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i]));
        path.closePath();
        offscreen.fill(path);
        show();
    }


    // Bild aus Datei/URL einlesen
    private static Image getImage(String filename) {

        // aus Datei einlesen
        ImageIcon icon = new ImageIcon(filename);

        // aus URL einlesen
        if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) {
            try {
                URL url = new URL(filename);
                icon = new ImageIcon(url);
            } catch (Exception e) { /* das ist keine url! */ }
        }

        // falls die Datei in einem .jar Archiv ist
        if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) {
            URL url = GrLib.class.getResource(filename);
            if (url == null) throw new RuntimeException("Bild " + filename + " nicht gefunden");
            icon = new ImageIcon(url);
        }

        return icon.getImage();
    }

    // Bild zeichnen (gif, jpg, oder png). Mittelpunkt (x, y)
    public static void picture(double x, double y, String s) {
        Image image = getImage(s);
        double xs = scaleX(x);
        double ys = scaleY(y);
        int ws = image.getWidth(null);
        int hs = image.getHeight(null);
        if (ws < 0 || hs < 0) throw new RuntimeException("Bild " + s + " ist kaputt");

        offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null);
        show();
    }

    // Bild zeichnen (gif, jpg, oder png). Mittelpunkt (x, y), skaliert fuer w mal h
    public static void picture(double x, double y, String s, double w, double h) {
        Image image = getImage(s);
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(w);
        double hs = factorY(h);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else {
            offscreen.drawImage(image, (int) Math.round(xs - ws/2.0),
                                       (int) Math.round(ys - hs/2.0),
                                       (int) Math.round(ws),
                                       (int) Math.round(hs), null);
        }
        show();
    }

    // schreibe s mit der aktuellen Schrift, Mittelpunkt (x, y)
    public static void text(double x, double y, String s) {
        offscreen.setFont(font);
        FontMetrics metrics = offscreen.getFontMetrics();
        double xs = scaleX(x);
        double ys = scaleY(y);
        int ws = metrics.stringWidth(s);
        int hs = metrics.getDescent();
        offscreen.drawString(s, (float) (xs - ws/2.0), (float) (ys + hs));
        show();
    }

    // zeige auf dem Bildschirm, Pausiere t Millisekunden
    public static void show(int t) {
        defer = true;
        onscreen.drawImage(offscreenImage, 0, 0, null);
        frame.repaint();
        try { Thread.currentThread().sleep(t); }
        catch (InterruptedException e) { System.out.println("Fehler: bin eingeschlafen"); }
    }


    // zeige auf dem Bildschirm, falls noetig, lege einen neuen Rahmen an
    public static void show() {
        if (!defer) onscreen.drawImage(offscreenImage, 0, 0, null);
        if (!defer) frame.repaint();
    }


    // als Datei speichern - Endung muss png, jpg, oder gif sein
    public static void save(String filename) {
        File file = new File(filename);
        String suffix = filename.substring(filename.lastIndexOf('.') + 1);

        // png Datei
        if (suffix.toLowerCase().equals("png")) {
            try { ImageIO.write(offscreenImage, suffix, file); }
            catch (IOException e) { e.printStackTrace(); }
        }

        // etwas komplizierter bei JPG
        // s. [url]http://archives.java.sun.com/cgi-bin/wa?A2=ind0404&L=java2d-interest&D=0&P=2727[/url]
        else if (suffix.toLowerCase().equals("jpg")) {
            WritableRaster raster = offscreenImage.getRaster();
            WritableRaster newRaster;
            newRaster = raster.createWritableChild(0, 0, width, height, 0, 0, new int[] {0, 1, 2});
            DirectColorModel cm = (DirectColorModel) offscreenImage.getColorModel();
            DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
                                                          cm.getRedMask(),
                                                          cm.getGreenMask(),
                                                          cm.getBlueMask());
            BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false,  null);
            try { ImageIO.write(rgbBuffer, suffix, file); }
            catch (IOException e) { e.printStackTrace(); }
        }

        else {
            System.out.println("Dateityp stimmt nicht: " + suffix);
        }
    }


    // Speichern-Dialog fuer das Menue
    public void actionPerformed(ActionEvent e) {
        FileDialog chooser = new FileDialog(GrLib.frame, ".png oder .jpg Dateinamen verwenden", FileDialog.SAVE);
        chooser.setVisible(true);
        String filename = chooser.getFile();
        if (filename != null) {
            GrLib.save(chooser.getDirectory() + File.separator + chooser.getFile());
        }
    }

    public static boolean mousePressed() { return mousePressed; }
    public static double mouseX()        { return mouseX;       }
    public static double mouseY()        { return mouseY;       }
    

    public void mouseClicked (MouseEvent e) { }
    public void mouseEntered (MouseEvent e) { }
    public void mouseExited  (MouseEvent e) { }
    public void mousePressed (MouseEvent e) {
        mouseX = GrLib.userX(e.getX());
        mouseY = GrLib.userY(e.getY());
        mousePressed = true;
    }
    public void mouseReleased(MouseEvent e) { mousePressed = false; }
    public void mouseDragged(MouseEvent e)  {
        mouseX = GrLib.userX(e.getX());
        mouseY = GrLib.userY(e.getY());
    }

    public void mouseMoved(MouseEvent e) {
        mouseX = GrLib.userX(e.getX());
        mouseY = GrLib.userY(e.getY());
    }    


    // kleine Testmethode
    public static void main(String[] args) {
        GrLib.square(.2, .8, .2);
        GrLib.filledSquare(.8, .8, .2);
        GrLib.circle(.2, .2, .2);

        // fuer Zeichnung
        GrLib.setPenColor(GrLib.GREEN);
        double[] x = { .1, .2, .3, .2 };
        double[] y = { .2, .3, .2, .1 };
        GrLib.filledPolygon(x, y);

        // fuer text
        GrLib.text(0.8, 0.2, "Supi-Foo! Dupi-Bar!");
    }

}
```

anhand dieser können wir arbeiten...

Bis jetzt hab ich nur etwas herum experimentiert, also Kästchen erstellt und z.B. per "mousePressed" die Farbe geändert usw...

Vllt. noch interessant zu wissen, wir arbeiten mit "BlueJ".

Würd mich über etwas Hilfe sehr freuen!!!

Danke schonmal!

Gruß
Dschuls


----------



## The_S (20. Nov 2006)

Lies dir am besten mal die Grafikkapitel im Inselbuch durch

http://www.galileocomputing.de/openbook/javainsel5/


----------

