# Jump n' Run 2D Geometrie und Kollisionsabfrage?



## ulrich1992 (10. Jun 2010)

Hallo ich überlege ob ich mich an am Programmieren eines Jump N' Run Spiels im Mario Stil versuche.

Ich bin mir nicht sicher wie ich die aktuelle Position von Elementen speichern/ändern soll.
Ich habe gehört, das man dazu Vektorrechnung braucht, aber ich bin absoluter Feind von höherer Mathematik.
Muss ich in einem Array Position x und y jedes Elements sowie Höhe und Breite speichern oder gibt es spezielle Klassen für 2D Geometrie und Kollisionsabfrage?
Die Kollisionsabfrage kann eine Bounding Rects sein, muss also nicht so präzise sein daher ich eh dann GIF Grafiken Grafiken verwende.


----------



## Marco13 (10. Jun 2010)

java.awt.geom (Java Platform SE 6) Sowas wie Rectangle mit Überscheidungstests und so. Programmieren ist übrigens Mathematik. Eine bestimmte Ausprägung davon. IMHO.


----------



## Runtime (10. Jun 2010)

Da dieser Mario ja nicht umfällt, kannst du einfach ein Rectangle nehmen und damit die Kollision testen und die Position speichern. Dann brauchst du nur noch die Fallbeschleuigung und das wärs ja schon .


----------



## Empire Phoenix (10. Jun 2010)

Vectorrechnung ist keine höhere Mathematik.
Ansonsten wie der Vorredner schon sagte, ansonsten gibt es noch die 2d engine für java, weiß aber gerade den namen nicht


----------



## Runtime (10. Jun 2010)

Phys2d und Box2d, aber da fällt Mario um, wenn er auf ne Kante springt. Ausserdem wird da viel zu viel berechnet. Die Richtung und Geschwindigkeit kann man mit Pixel/Sekunden berechnen. Wenn x positiv ist, dann geht er nach rechts, sonst nach links. Ähnlich geht das mit y.


----------



## Quaxli (11. Jun 2010)

Runtime hat gesagt.:


> Da dieser Mario ja nicht umfällt, kannst du einfach ein Rectangle nehmen ...



Den Zusammenhang verstehe ich nicht. Was hat das Umfallen von Marion damit zu tun, ob dessen Klasse von Rectangle (bzw. Rectangle2D.Double) erbt oder nicht. :bahnhof:


----------



## Runtime (11. Jun 2010)

Würde er umfallen, sähe es so aus:


----------



## Quaxli (11. Jun 2010)

Und? Ist AffineTransform kaputt? 
Außerdem muß es nicht zwingend sein, daß das Bild gedreht wird, nur weil die Figur umfällt.


----------



## Runtime (11. Jun 2010)

Aber dann ists irgendwie unsauber.


----------



## Quaxli (11. Jun 2010)

Unfug!
Wenn ich mir für die verschiedenen Bewegungsrichtungen sowieso ein TileSet bauen muß, warum sollte ich mir dann das Leben schwer machen und nicht alle notwendigen Bewegungsabläufe erfassen?
Und was das mit Rectangle zu tun hat, weiß ich immer noch nicht.


----------



## Marco13 (11. Jun 2010)

Naja, spätestens wenn man (nur als Beispiel) ein Autofahr-Spiel machen will, dann würde man das Auto in der Draufsicht von oben als Rectangle beschreiben, aber wenn es gedreht ist, sollte auch das Rectangle gedreht sein (und nicht ein größeres, Achsenparalleles Rectangle). Ich denke, das hängt auch stark davon ab, wie Rund das Objekt ist (bzw. wie gut es durch ein Rechteck angenähert werden kann oder durch ein gedrehtes Rechteck angenähert werden könnte)


----------



## Runtime (11. Jun 2010)

Ich hab ein Beispiel gemacht. Der source ist zwar ein bisschen unleserchlich.

```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package boxadventures;

/**
 *
 * @author Cyrill
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new MainFrame();
    }

}
```


```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package boxadventures;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.geom.Path2D;

/**
 *
 * @author Cyrill
 */
public class Level {

    public Path2D getFloor() {
        return floor;
    }

    public void setFloor(Path2D floor) {
        this.floor = floor;
    }

    public Point getStart() {
        return start;
    }

    public void setStart(Point start) {
        this.start = start;
    }

    public Dimension getRectSize() {
        return rectSize;
    }

    public void setRectSize(Dimension rectSize) {
        this.rectSize = rectSize;
    }

    private Path2D floor;
    private Point start;
    private Dimension rectSize;

}
```


```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package boxadventures;

import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.TimerTask;

/**
 *
 * @author Cyrill
 */
public class GravitationTask extends TimerTask {

    public GravitationTask(Rectangle2D rect, Path2D floor) {
        this.rect = rect;
        this.floor = floor;
    }

    public void jump() {
         if(floor.intersects(rect)) {
            y = -2f;
            rect.setRect(rect.getX(), rect.getY() + y, rect.getWidth(), rect.getHeight());
        }
    }

    private void interpolate() {
        if (y < 0) {
            y *= 0.97f;
            if (y < 0f && y > -0.2f) {
                y = 0f;
            }
        } else {
            if (y == 0f) {
                y = 0.3f;
            }
            y *= 1.04f;
        }
    }

    @Override
    public void run() {
        if (!floor.intersects(rect)) {
            interpolate();
            rect.setRect(rect.getX(), rect.getY() + y, rect.getWidth(), rect.getHeight());
        } else {
            y = 0;
        }
    }

    private Rectangle2D rect;
    private Path2D floor;
    private float y;

}
```


```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package boxadventures;

import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.TimerTask;

/**
 *
 * @author Cyrill
 */
public class RectangleMover extends TimerTask {

    public RectangleMover(Rectangle2D rect, float x, Path2D floor) {
        this.rect = rect;
        this.floor = floor;
        this.x = x;
    }

    @Override
    public void run() {
        Rectangle2D rect2 = rect.getBounds2D();
        rect2.setRect(rect2.getX() + x, rect2.getY() - 4,
                rect2.getWidth(), rect2.getHeight());
        if(!floor.intersects(rect2))
            rect.setRect(rect.getX() + x, rect.getY(), rect.getWidth(), rect.getHeight());
    }

    public void setX(float x) {
        this.x = x;
    }

    private float x;
    private Rectangle2D rect;
    private Path2D floor;

}
```


```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package boxadventures;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferStrategy;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;

/**
 *
 * @author Cyrill
 */
class MainFrame extends JFrame implements KeyListener {

    public MainFrame() {
        setSize(600, 400);
        setLocationRelativeTo(null);
        setVisible(true);
        setIgnoreRepaint(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        timer = new Timer();
        level = getLevel();
        rect = new Rectangle2D.Float(level.getStart().x,
                level.getStart().y,
                level.getRectSize().width,
                level.getRectSize().height);
        gravitationTask = new GravitationTask(rect, level.getFloor());
        createBufferStrategy(2);
        addKeyListener(this);
        mover = new RectangleMover(rect, 0, level.getFloor());
        timer.schedule(mover, 0, 1);
        timer.schedule(gravitationTask, 0, 10);
        timer.schedule(new RepaintTask(), 0, 1);
    }

    private void paint(BufferStrategy strategy) {
        Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
        g.setColor(Color.white);
        g.fillRect(0, 0, getWidth(), getHeight());
        int x = getWidth() / 2 - (int) rect.getX();
        int y = getHeight() / 2 - (int) rect.getY();
        g.translate(x, y);
        g.setColor(Color.black);
        g.draw(level.getFloor());
        g.setColor(new Color(0, 0, 200));
        g.fill(rect);
        strategy.show();
    }

    private Level getLevel() {
        Level lvl = new Level();
        GeneralPath path = new GeneralPath();
        path.moveTo(0, 100);
        path.lineTo(500, 100);
        path.lineTo(500, 50);
        path.lineTo(600, 50);
        path.lineTo(600, 100);
        path.lineTo(700, 100);
        path.lineTo(800, 200);
        path.closePath();
        lvl.setFloor(path);
        lvl.setStart(new Point(10, 10));
        lvl.setRectSize(new Dimension(20, 20));
        return lvl;
    }

    public void keyTyped(KeyEvent e) {
        if(e.getKeyChar() == ' ') {
            gravitationTask.jump();
        }
    }

    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_D)
            mover.setX(-3);
        if(e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_A)
            mover.setX(3);
    }

    public void keyReleased(KeyEvent e) {
        mover.setX(0);
    }

    private class RepaintTask extends TimerTask {

        @Override
        public void run() {
            paint(getBufferStrategy());
        }

    }

    private Level level;
    private Rectangle2D rect;
    private Timer timer;
    private GravitationTask gravitationTask;
    private RectangleMover mover;

}
```


----------

