Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Del 2 - Oppsett av verden og simulering

...

PlantUML Macro
class Asteroids {
}
class SpaceObject {
}
Asteroids *--> "*" SpaceObject: spaceObjects

class Asteroids1 {
}
class Asteroids2 {
}
class Asteroids3 {
}

Asteroid <|-- Asteroids1
Asteroid <|-- Asteroids2
Asteroid2 <|-- Asteroids3

Denne delen tar utgangspunkt i en delvis ferdigskrevet Asteroids-klasse. Oppgaven til Asteroids-klassen er todel: 1) å rigge opp verdenen med rom-objekter og 2) kjøre selve simuleringen. I koden for Asteroids-klassen, som ligger nederst på denne siden, legges det opp til at dette gjøres i henholdsvis init()- og run()-metoden, men du står forsåvidt fritt til å (gjen)bruke denne koden som du vil. Men for at du skal lære mest mulig om arv, så prøv å legge mest mulig av din egen kode i subklasser av Asteroids, heller enn å skrive den om. Vi foreslår at du gjør oppgaven i følgende trinn, med én subklasse pr. trinn.

 

 

Trinn 1 - Asteroids1

I dette trinnet er målet å få lagt inn noen SpaceObject-instanser, se (til) at simuleringen beveger dem på skjermen og få kollisjonsdeteksjon til å fungere.

SpaceObject-instansene opprettes i init()-metoden og legges inn med den ferdigskrevne add-metoden i Asteroids-klassen. For å få simuleringen til å virke, så må du fylle inn kode i tick()-metoden:

  • for hvert SpaceObject må du utføre ett simuleringstrinn
  • for hvert SpaceObject-par må du sjekke for kollisjon, altså om de overlapper hverandre

Sjekk for overlapp kan gjøres på mange måter, f.eks. sjekke overlapp av såkalt "bounding box" eller om hjørnene i det ene polygonet er inni det andre.

Trinn 2 - Asteroids2

I dette trinnet er målet å få gravitasjonslogikken til å fungere og sjekke det ved å legge inn en sol (stor, gul og rund Asteroid-instans) og masse asteroider (Asteroid-instanser av med ulik tetthet og størrelse).

Utvid tick()-metoden slik at du for hvert SpaceObject-par beregner og håndterer den gjensidige gravitasjonskraften.

Trinn 3 - Asteroids3

I dette trinnet implementerer du støtte for å styre romskipet med piltastene (venstre, høyre og forover). Finn selv ut hvilke Asteroids-metoder som må redefineres, for å få dette til. Sørg for å legge til et romskip og prøv å unngå å kollidere eller å bli slukt av sola!

Code Block
languagejava
titleBaseSpaceObject
collapsetrue
package inheritance;

import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.shape.Polygon;

public class BaseSpaceObject extends Polygon {
Code Block
languagejava
titleBaseSpaceObject
collapsetrue
package inheritance;

import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.shape.Polygon;

public class BaseSpaceObject extends Polygon {
    /**
     * Adds the point given by x,y to this Polygon
     * @param x the x-coordinate
     * @param y the y-coordinate
     */
    protected void addPoint(double x, double y) {
        getPoints().add(x);
        getPoints().add(y);
    }
    /**
     * Adds the pointspoint given by thex,y sequenceto of x- and y-coordinatesthis Polygon
     * @param xysx the x- and y-coordinatescoordinate
     */
    protected void addPoints(double... xys) {
     @param y the y-coordinate
    for (int*/
 i = 0; iprotected < xys.length; i += 2void addPoint(double x, double y) {
        getPoints().add(x);
     addPoint(xys[i], xys[i + 1] getPoints().add(y);
    }
    }/**
      }
    
    /*** Adds the points given by the sequence of x- and y-coordinates
     * @param Addsxys the point given by angle, length in polar coordinates
     * @param angle the angle
     * @param length the length
     */x- and y-coordinates
     */
    protected void addPoints(double... xys) {
        for (int i = 0; i < xys.length; i += 2) {
    protected void addPolarPoint(double angle, double length) {
  addPoint(xys[i], xys[i + 1]);
   addPoint(Math.cos(angle) * length, Math.sin(angle) * length);}
    }
    
    /**
     * ReturnsAdds the positionpoint ofgiven thisby Polygonangle, aslength ain Point2Dpolar objectcoordinates
     * @param @returnangle the position as a Point2D object angle
     * @param length the length
     */
    protected void addPolarPoint(double publicangle, Point2Ddouble getPosition(length) {
        return new Point2D(getTranslateX(), getTranslateY()addPoint(Math.cos(angle) * length, Math.sin(angle) * length);
    }
    
    /**
     * Moves (displaces) this Polygon by Returns the givenposition dx,of dy
     * @param dx the x displacementthis Polygon as a Point2D object
     * @param dy the y displacement@return the position as a Point2D object
     */
    public voidPoint2D translate(double dx, double dygetPosition() {
        setTranslateXreturn new Point2D(getTranslateX() + dx);
        setTranslateY(, getTranslateY() + dy);
    }
    
    /**
     * Returns the position of the center of Moves (displaces) this Polygon.
     * The asParentCoordinates determines if by the positiongiven is transformed into the parent coordinate system.dx, dy
     * @param asParentCoordinates determines if the position is transformed intodx the parent coordinatex systemdisplacement
     * @return@param dy the centery positiondisplacement
     */
    public Point2Dvoid getCenter(boolean asParentCoordinatestranslate(double dx, double dy) {
        Bounds bounds = getBoundsInLocal(setTranslateX(getTranslateX() + dx);
        Point2D center = new Point2D((bounds.getMaxX() + bounds.getMinX()) / 2, (bounds.getMaxY    setTranslateY(getTranslateY() + bounds.getMinY()) / 2);dy);
    }
    
    /**
     * Returns the ifposition (asParentCoordinates) {
    of the center of this Polygon.
     * The asParentCoordinates centerdetermines = localToParent(center);
        }
if the position is transformed into the parent coordinate system.
     * @param asParentCoordinates determines returnif center;
the position is transformed }
into the parent coordinate /**system
     * Returns@return the number of points in this Polygoncenter position
     */
 @return the number ofpublic pointsPoint2D in this PolygongetCenter(boolean asParentCoordinates) {
     */
   Bounds publicbounds int= getPointCountgetBoundsInLocal();
   {
     Point2D center = return getPointsnew Point2D((bounds.getMaxX() + bounds.sizegetMinX()) / 2;
    }
    /**
     * Determines of a specific point of another Polygon is inside this Polygon, (bounds.getMaxY() + bounds.getMinY()) / 2);
        if (asParentCoordinates) {
     * @param other the other Polygon
  center = localToParent(center);
 * @param pointNum the number of the point to check}
     * @return
     */
  return center;
  public boolean contains(BaseSpaceObject other, int pointNum) {
}
    /**
     * Returns the number ObservableList<Double>of points = other.getPoints();in this Polygon
     * @return the doublenumber of xpoints = points.get(pointNum * 2), y = points.get(pointNum * 2 + 1);in this Polygon
     */
    public int getPointCount() {
        return this.contains(parentToLocal(other.localToParent(x, y)));
    }
}
Code Block
languagejava
titleAsteroids-klassen
collapsetrue
package inheritance;

import java.util.ArrayList;
import java.util.List;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.util.Duration;

public class Asteroids extends Pane implements EventHandler<KeyEvent>  {

	private List<SpaceObject> spaceObjects;
    
    protected void add(SpaceObject so, double x, double y) {
        so.translate(x, y);getPoints().size() / 2;
    }
    /**
     * Determines of a specific point of another Polygon is inside this Polygon
     * @param other the other Polygon
     * @param pointNum the number of the point to check
     * @return
     */
    public boolean contains(BaseSpaceObject other, int pointNum) {
        getChildren().add(soObservableList<Double> points = other.getPoints();
        double spaceObjects.add(so);
    }
    public void init() {
x = points.get(pointNum * 2), y = points.get(pointNum * 2 + 1);
         spaceObjects = new ArrayList<SpaceObject>(return this.contains(parentToLocal(other.localToParent(x, y)));
    }
}
Code Block
languagejava
titleAsteroids-klassen
collapsetrue
package inheritance;

import java.util.ArrayList;
import java.util.List;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.util.Duration;

public class Asteroids extends Pane implements EventHandler<KeyEvent>  {

	private List<SpaceObject> spaceObjects;
    
    protected void add(SpaceObject so, double x, double y
	public void run() {
		// setter opp simuleringstakt
        Timeline tickTimer = new Timeline(new KeyFrame(Duration.millis(50), new EventHandler<ActionEvent>() {
    		private int tickCount = 0;
            @Override
            public void handle(ActionEvent event) {
        so.translate(x, y);
       tick(tickCount++ getChildren().add(so);
        spaceObjects.add(so);
    }
    public void init() {
   }));
     spaceObjects = new tickTimer.setCycleCount(Timeline.INDEFINITEArrayList<SpaceObject>();
    }

	public void   tickTimer.playrun();
    {
		// setter opp simuleringstakt
     requestFocus();
   Timeline tickTimer = new  setOnKeyPressed(this);Timeline(new KeyFrame(Duration.millis(50), new EventHandler<ActionEvent>() {
    		private int tickCount = setOnKeyTyped(this)0;
      }

	// kalles når spesialtaster som pilene trykkes
	protected void handleKey(KeyCode keyCode) {
@Override
           }

	// kalles når vanlige bokstavtaster trykkes
  public void handle(ActionEvent event) {
   protected void handleKey(String character) {
        if tick("+".equals(character)) {tickCount++);
            zoom(2);}
        } else if ("-".equals(character)) {;
            zoom(0.5tickTimer.setCycleCount(Timeline.INDEFINITE);
        }
tickTimer.play();
        }requestFocus();
    
    private void zoom(double factor) {setOnKeyPressed(this);
        setScaleXsetOnKeyTyped(getScaleX() * factor)this);
    }

	// kalles når spesialtaster setScaleY(getScaleY() * factor);
    }som pilene trykkes
	protected void handleKey(KeyCode keyCode) {
    }

	// kalles når vanlige bokstavtaster @Overridetrykkes
    publicprotected void handlehandleKey(KeyEventString keyEventcharacter) {
        if (keyEvent"+".getCodeequals(character) == KeyCode.UNDEFINED) {
            handleKey(keyEvent.getCharacter()zoom(2);
        } else if ("-".equals(character)) {
            handleKeyzoom(keyEvent0.getCode()5);
        }
    }

	    
    private void tickzoom(intdouble tickCountfactor) {
        // accelerate due to gravity
setScaleX(getScaleX() * factor);
        setScaleY(getScaleY() for (int i = 0; i < spaceObjects.size(); i++) {* factor);
    }
    
    @Override
    public void handle(KeyEvent keyEvent) for{
 (int j = i + 1; j <if spaceObjects(keyEvent.sizegetCode(); j++ == KeyCode.UNDEFINED) {
				// fyll inn kode her, for å håndtere gravitasjonskraften
    handleKey(keyEvent.getCharacter());
        }
 else {
      }
        // move all objects
handleKey(keyEvent.getCode());
        }
   for (SpaceObject spaceObject : spaceObjects }

	private void tick(int tickCount) {
        // accelerate due  spaceObject.tick();
        }to gravity

		// lag en (dobbel) løkke her, som
		// håndterer gravitasjonskraften for alle par i spaceObjects-lista 

        // checkmove forall collisionobjects
        for (intSpaceObject ispaceObject = 0; i < spaceObjects.size(); i++) : spaceObjects) {
            for (int j = i + 1; j < spaceObjects.sizespaceObject.tick(); j++) {
				// fyll inn kode her, for å håndtere kollisjoner, f.eks.
				// endre fargen, implementere støtfysikk e.l.
 }

        // check for collision
		// lag en (dobbel) løkke her, }
        }som
		// sjekker for og håndterer kollisjoner for alle par i spaceObjects-lista
    }

	public void handleGravity(SpaceObject spaceObject1, SpaceObject spaceObject2) {
		// regn ut avstanden mellom spaceObject1 og spaceObject2 (bruk getCenter-metoden),
		// beregn den gjensidige gravitasjonskraften basert på formelen
		// masse1 * masse2 / avstand ^ 2, og
		// påfør kraften med SpaceObject.applyForce-metoden
    }
}
Code Block
languagejava
titleAsteroidsProgram
collapsetrue
package inheritance;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class AsteroidsProgram extends Application {
    private int width = 800, height = 600;
    @Override
    public void start(Stage stage) throws Exception {
        String paneClassName = getParameters().getRaw().get(0);
        final Asteroids asteroidsPane = (Asteroids) Class.forName(paneClassName).newInstance();
        asteroidsPane.setPrefSize(width, height);
        Scene scene = new Scene(asteroidsPane, width, height, Color.BLACK);
        stage.setScene(scene);
        stage.show();
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                asteroidsPane.init();
                asteroidsPane.run();
            }
        });
    }
    
    public static void main(String[] args) {
        launch(AsteroidsProgram.class, args);
    }
}