Angehensweise für ein Brettspiel mit Java 2D

Pitchblack

Mitglied
Hallo Community,

da mir mal wieder ein wenig langweilig ist wollte ich mich etwas mit den 2D Möglichkeiten in Java beschäftigen. Aus diesem Grund möchte ich mir ein Brettspiel kreieren.

Die Oberfläche, die Spielfigur und die Felder habe ich schon als JPG Dateien erstellt. Mein Problem ist Momentan die Angehensweise bezüglich der Spielfelder.
Ich möchte nämlich, dass sich ein besuchtes Feld verändert. Somit kann das Feld schonmal nicht statisch im Hintergrund integriert sein, sondern muss durch ein Objekt repräsentiert werden. Da ich 52 Felder habe müsste ich mir also 52 Objekte erzeugen. Ist das nicht ziemlich Speicherintensiv? Mal angenommen ich hätte 100 Felder, müsste ich dann auch 100 Objekte erzeugen?


Falls also jemand die nötige Erfahrung mit kleinen Minigames hat, würde ich doch sehr bitten sein implizietes Wissen expliziet zur Verfügung zu stellen.

MfG
Pitchblack
 

flashray

Erfahrenes Mitglied
Hallo Pitchblack,

das ist ein Memoryspiel mit bis zu 20 Bilderparen also insgesamt 40 Spielfeldern:
https://sourceforge.net/projects/penguincards/

Wenn du nach dem downloaden das jar PenguinCards extrahierst wirst du auch die Quelldateien wiederfinden. Soweit ich das auf die Kürze festellen könnte verwendet der Autor für die Felder ein GridLayout mit der Anzahl der Feldern.


Vg Erdal
 

Pitchblack

Mitglied
Danke für den interessanten Link. Das hat mich schon viel weiter gebracht. Allerdings würde ich gerne meine Flächen frei positionieren können und da ist das GridLayout nicht optimal.

Hast du da vielleicht einen Vorschlag? Ich könnte z.B. Rectangel Objekte erstellen, die dann frei positionierbar wären.
 

Pitchblack

Mitglied
Ok, das sieht doch hilfreich aus. Denkst du denn, dass 52 Schichten (Layer) die richtige angehensweise für ein Spielbrett sind? Kennst du vielleicht Alternativen?
 

flashray

Erfahrenes Mitglied
Ähnliches könnte man auch mit JInternalFrame machen. Wenn du die Titelleisten entfernen möchtest, brauchst du zusätzlich Listener zum Verschieben der Internalframes - was ich hier auch gemacht habe.

Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.*;

public class JInternalFrameDemo extends JFrame {

	private JDesktopPane desktop = new JDesktopPane();

	public JInternalFrameDemo() {
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setAlwaysOnTop(true);
		this.setLocationByPlatform(true);
		this.setSize(700, 740);

		for (int i = 0; i < 7; i++)
			for (int j = 0; j < 7; j++) {
				this.addInternalToDesktop(desktop, i * 100, j * 100);
			}
		this.add(desktop);

		this.setVisible(true);

	}

	public void addInternalToDesktop(JDesktopPane desktop, int i, int j) {
		JXInternalFrame iframe;
		iframe = new JXInternalFrame(null, // title
				false, // resizable
				false, // closeable
				false, // maximizable
				false); // iconifiable
		iframe.setBounds(i, j, 100, 100);
		iframe.setVisible(true);
		desktop.add(iframe);
	}

	public static void main(String[] args) {
		new JInternalFrameDemo();
	}

	class JXInternalFrame extends JInternalFrame {

		private Point p1 = new Point(), p2 = new Point();

		public JXInternalFrame(String title, boolean b, boolean c, boolean d,
				boolean e) {
			super(title, b, c, d, e);

			// Listener - Verschieben
			this.addMouseListener(new MouseAdapter() {
				public void mousePressed(MouseEvent e) {
					p1.setLocation(e.getPoint());
				}
			});
			this.addMouseMotionListener(new MouseMotionAdapter() {
				public void mouseDragged(MouseEvent e) {
					p2 = e.getComponent().getParent().getMousePosition();
					JXInternalFrame.this.setLocation(p2.x - p1.x, p2.y - p1.y);
				}
			});

			// Titlebar entfernen
			((javax.swing.plaf.basic.BasicInternalFrameUI) this.getUI())
					.getNorthPane().setPreferredSize(new Dimension(0, 0));

			// Border verändern
			this.setBorder(BorderFactory.createEtchedBorder());

			// Hintergrundfarbe
			int color = (int) (Math.random() * 3);
			switch (color) {
			case 0:
				this.setBackground(Color.RED);
				break;
			case 1:
				this.setBackground(Color.BLUE);
				break;
			default:
				this.setBackground(Color.GREEN);
			}
		}
	}
}


Vg Erdal
 

Pitchblack

Mitglied
Ich denke, ich versuche es mit den InternalFrames. Jetzt muss ich nur noch herausfinden, wie ich eine Spielfläche auf ein JFrame zeichnen kann und wie ich die einzelnen Felder am besten anspreche.

MfG
Pitch
 

flashray

Erfahrenes Mitglied
Hallo Pitch,

da hättest du mindestens zwei Möglichkeiten. Wenn es wenige, einfache, geometrische Linien, Formen sind könntest du es per paint(Graphics g) zeichen. Hingegen falls es ein komplizierter Hintergrund ist, einfach als Bild als Hintergrund im JFrame laden.


Vg Erdal
 

Thomas Darimont

Erfahrenes Mitglied
Hallo!

Als Basis für ein kleines Spiel mit Java 2D könntest du folgendes nehmen:
Java:
/**
 * 
 */
package de.tutorials;
 
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
 
import javax.swing.JFrame;
 
/**
 * @author Tom
 * 
 */
public class Java2DGamingExample extends JFrame {
 
    boolean shouldExitGame;
 
    final Dimension currentWindowSize;
 
    BufferStrategy bufferStrategy;
 
    final ExecutorService executorService = Executors.newFixedThreadPool(1);
 
    final static Random RANDOM = new Random();
 
    boolean keyUpPressed;
 
    boolean keyDownPressed;
 
    boolean keyLeftPressed;
 
    boolean keyRigthPressed;
 
    Ball[] balls;
 
    Player player;
 
    AlphaComposite[] alphaComposites;
 
    abstract class Figure {
        Color color;
 
        int x;
 
        int y;
 
        public Figure(int x, int y, Color color) {
            this.color = color;
            this.x = x;
            this.y = y;
        }
 
        public void drawOn(Graphics2D g) {
            Color oldColor = g.getColor();
            g.setColor(color);
            drawInternal(g);
            g.setColor(oldColor);
        }
 
        abstract void drawInternal(Graphics2D g);
    }
 
    class Player extends Figure {
 
        int width;
 
        int widthHalf;
 
        int height;
 
        int heightHalf;
 
        public int velocity;
 
        public Player(int x, int y, int width, int height, int velocity,
                Color color) {
            super(x, y, color);
            this.width = width;
            this.widthHalf = width / 2;
            this.height = height;
            this.heightHalf = height / 2;
            this.velocity = velocity;
        }
 
        @Override
        void drawInternal(Graphics2D g) {
            g.fillRect(x - widthHalf, y - heightHalf, width, height);
        }
    }
 
    class Ball extends Figure {
 
        LinkedList<Point> historyPoints;
 
        int historySize;
 
        int radius;
 
        int radiusHalf;
 
        int velocityY;
 
        int velocityX;
 
        int radiusShrinkStep;
 
        public Ball(int x, int y, int radius, int velocityX, int velocityY,
                Color color, int historySize) {
            super(x, y, color);
            this.radius = radius;
            this.radiusHalf = radius / 2;
            this.velocityX = velocityX;
            this.velocityY = velocityY;
            this.historyPoints = new LinkedList<Point>();
            this.historySize = historySize;
            this.radiusShrinkStep = (radius - (int) (.1 * radius))
                    / historySize;
        }
 
        public void move() {
            if ((x <= 0) || (x >= currentWindowSize.width - radiusHalf)) {
                velocityX *= -1;
            }
 
            if ((y <= 0) || (y >= currentWindowSize.height - radiusHalf)) {
                velocityY *= -1;
            }
 
            addToHistory(new Point(x, y));
 
            x += velocityX;
            y += velocityY;
 
        }
 
        private void addToHistory(Point point) {
            if (historyPoints.size() >= historySize) {
                historyPoints.removeLast();
            }
 
            historyPoints.addFirst(point);
        }
 
        @Override
        void drawInternal(Graphics2D g) {
            int currentRadius = radius;
 
            Composite oldComposite = g.getComposite();
            int currentHistoryPointIndex = 0;
            for (Point historyPoint : historyPoints) {
                g.setComposite(alphaComposites[currentHistoryPointIndex++]);
                currentRadius -= radiusShrinkStep;
                g.fillOval(historyPoint.x - radiusHalf, historyPoint.y
                        - radiusHalf, currentRadius, currentRadius);
            }
            g.setComposite(oldComposite);
            g.fillOval(x - radiusHalf, y - radiusHalf, radius, radius);
        }
    }
 
    Runnable gameLoop = new Runnable() {
        public void run() {
 
            while (!shouldExitGame) {
                processKeys();
                updateGameState();
                drawScene();
            }
            shutdown();
        }
    };
 
    public Java2DGamingExample() {
        setUndecorated(true);
        setIgnoreRepaint(true);
        GraphicsDevice graphicsDevice = getGraphicsConfiguration().getDevice();
        graphicsDevice.setFullScreenWindow(this);
        graphicsDevice.setDisplayMode(new DisplayMode(640, 480, 16, 60));
 
        setVisible(true);
        currentWindowSize = getSize();
        createBufferStrategy(2);
        bufferStrategy = getBufferStrategy();
 
        init();
        addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) {
                case KeyEvent.VK_UP:
                    keyUpPressed = true;
                    break;
                case KeyEvent.VK_DOWN:
                    keyDownPressed = true;
                    break;
                case KeyEvent.VK_LEFT:
                    keyLeftPressed = true;
                    break;
                case KeyEvent.VK_RIGHT:
                    keyRigthPressed = true;
                    break;
                case KeyEvent.VK_ESCAPE:
                    shouldExitGame = true;
                    break;
                }
            }
 
            public void keyReleased(KeyEvent e) {
                switch (e.getKeyCode()) {
                case KeyEvent.VK_UP:
                    keyUpPressed = false;
                    break;
                case KeyEvent.VK_DOWN:
                    keyDownPressed = false;
                    break;
                case KeyEvent.VK_LEFT:
                    keyLeftPressed = false;
                    break;
                case KeyEvent.VK_RIGHT:
                    keyRigthPressed = false;
                    break;
                }
            }
        });
    }
 
    private void init() {
        balls = createBalls(50, 30, 5);
        player = new Player(100, 100, 20, 20, 5, Color.RED);
    }
 
    protected void processKeys() {
        if (keyUpPressed) {
            player.y -= player.velocity;
        }
 
        if (keyDownPressed) {
            player.y += player.velocity;
        }
 
        if (keyRigthPressed) {
            player.x += player.velocity;
        }
 
        if (keyLeftPressed) {
            player.x -= player.velocity;
        }
    }
 
    private Ball[] createBalls(int ballCount, int ballRadius, int historySize) {
        Ball[] balls = new Ball[ballCount];
        alphaComposites = new AlphaComposite[historySize];
 
        int currentRadius = ballRadius;
        int minRadius = (int) (currentRadius * .1);
        int radiusShringStep = (ballRadius - minRadius) / historySize;
 
        for (int i = 0; i < alphaComposites.length; i++) {
            alphaComposites[i] = AlphaComposite.getInstance(
                    AlphaComposite.SRC_OVER, 0.8F * currentRadius / ballRadius);
            currentRadius -= radiusShringStep;
        }
 
        int DEFAULT_SPEED_X = 16;
        int DEFAULT_SPEED_Y = 16;
        for (int j = 0; j < balls.length; j++) {
            Color ballColor = null;
            switch (RANDOM.nextInt(5)) {
            case 0:
                ballColor = Color.RED;
                break;
            case 1:
                ballColor = Color.BLUE;
                break;
            case 2:
                ballColor = Color.GREEN;
                break;
            case 3:
                ballColor = Color.YELLOW;
                break;
            case 4:
                ballColor = Color.MAGENTA;
                break;
            }
            balls[j] = new Ball(20 + RANDOM.nextInt(400), 20 + RANDOM
                    .nextInt(300), ballRadius,
                    RANDOM.nextBoolean() ? -RANDOM.nextInt(DEFAULT_SPEED_X)
                            : RANDOM.nextInt(DEFAULT_SPEED_X), RANDOM
                            .nextBoolean() ? -RANDOM.nextInt(DEFAULT_SPEED_Y)
                            : RANDOM.nextInt(DEFAULT_SPEED_Y), ballColor,
                    historySize);
        }
        return balls;
    }
 
    private void drawScene() {
        Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
        drawBackground(g);
        drawBalls(g);
        drawPlayer(g);
        g.dispose();
        bufferStrategy.show();
    }
 
    private void drawPlayer(Graphics2D g) {
        player.drawOn(g);
    }
 
    private void drawBalls(Graphics2D g) {
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        // g.setRenderingHint(RenderingHints.KEY_RENDERING,
        // RenderingHints.VALUE_COLOR_RENDER_SPEED);
        // g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
        // RenderingHints.VALUE_COLOR_RENDER_SPEED);
        for (int i = 0; i < balls.length; i++) {
            Ball ball = balls[i];
            ball.drawOn(g);
        }
    }
 
    private void drawBackground(Graphics2D g) {
        g.fillRect(0, 0, currentWindowSize.width, currentWindowSize.height);
    }
 
    private void updateGameState() {
        for (int i = 0; i < balls.length; i++) {
            Ball ball = balls[i];
            checkForCollision(ball);
            ball.move();
 
        }
    }
 
    private void checkForCollision(Ball ballToCheck) {
        for (int i = 0; i < balls.length; i++) {
            Ball ball = balls[i];
            if (ball == ballToCheck) {
                continue;
            } else {
                if ((abs(ball.x - ballToCheck.x) <= ballToCheck.radiusHalf)
                        && (abs(ball.y - ballToCheck.y) <= ballToCheck.radiusHalf)) {
                    ball.velocityX *= -1;
                    ballToCheck.velocityX *= -1;
 
                    ball.velocityY *= -1;
                    ballToCheck.velocityY *= -1;
 
                }
            }
        }
    }
 
    public static int abs(int a) {
        return (a ^ (a >> 31)) - (a >> 31);
    }
 
    private void shutdown() {
        executorService.shutdown();
        System.exit(0);
    }
 
    public static void main(String[] args) {
        new Java2DGamingExample().start();
    }
 
    private void start() {
        executorService.execute(gameLoop);
    }
}
Läuft bei mir unter Java 6 mit folgenden Optionen am schnellsten:
-server -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true

Gruß Tom
 

Anhänge

  • 25932attachment.jpg
    25932attachment.jpg
    24,8 KB · Aufrufe: 1.154