Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (15)
Showing
with 457 additions and 90 deletions
File mode changed from 100644 to 100755
#!/usr/bin/env bash
remote_add () {
git remote add $1 https://git.cs.vsb.cz/vyuka-koz01/java-1/2021/$1.git
}
remote_add lab01
remote_add lab02
remote_add lab03
remote_add lab04
\ No newline at end of file
...@@ -3,24 +3,24 @@ ...@@ -3,24 +3,24 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>vsb-cs-java1</groupId> <groupId>vsb-cs-java1</groupId>
<artifactId>lab03</artifactId> <artifactId>lab06</artifactId>
<version>0.0.1-SNAPHOST</version> <version>0.0.1-SNAPHOST</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source> <maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId> <artifactId>javafx-controls</artifactId>
<version>11</version> <version>17.0.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId> <artifactId>javafx-fxml</artifactId>
<version>11</version> <version>17.0.2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency> <dependency>
......
#!/usr/bin/env bash
push_remote () {
git push -f $1 origin/$1:master
}
push_remote lab01
push_remote lab02
push_remote lab03
push_remote lab04
\ No newline at end of file
package lab; package lab;
import javafx.animation.AnimationTimer;
import javafx.application.Application; import javafx.application.Application;
import javafx.scene.Group; import javafx.fxml.FXMLLoader;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.canvas.Canvas; import javafx.scene.layout.BorderPane;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.WindowEvent; import javafx.stage.WindowEvent;
...@@ -18,40 +17,25 @@ public class App extends Application { ...@@ -18,40 +17,25 @@ public class App extends Application {
launch(args); launch(args);
} }
private Canvas canvas; private GameController controller;
private AnimationTimer animationTimer;
private Laboratory lab;
@Override @Override
public void start(Stage primaryStage) { public void start(Stage primaryStage) {
try { try {
//Construct a main window with a canvas. //Construct a main window with a canvas.
Group root = new Group();
canvas = new Canvas(800, 400); FXMLLoader loader = new FXMLLoader(this.getClass().getResource("GameView.fxml"));
root.getChildren().add(canvas);
Scene scene = new Scene(root, 800, 400); BorderPane root = loader.load();
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
Scene scene = new Scene(root);
primaryStage.setScene(scene); primaryStage.setScene(scene);
primaryStage.resizableProperty().set(false); primaryStage.resizableProperty().set(false);
primaryStage.setTitle("Java 1 - 3rd laboratory"); primaryStage.setTitle("Java 1 - 6th laboratory");
primaryStage.show(); primaryStage.show();
controller = loader.getController();
lab = new Laboratory(canvas); controller.startGame();
//Draw scene on a separate thread to avoid blocking UI.
animationTimer = new AnimationTimer() {
private Long previous;
@Override
public void handle(long now) {
if (previous == null) {
previous = now;
} else {
drawScene((now - previous)/1e9);
previous = now;
}
}
};
animationTimer.start();
//Exit program when main window is closed //Exit program when main window is closed
primaryStage.setOnCloseRequest(this::exitProgram); primaryStage.setOnCloseRequest(this::exitProgram);
} catch (Exception e) { } catch (Exception e) {
...@@ -59,17 +43,10 @@ public class App extends Application { ...@@ -59,17 +43,10 @@ public class App extends Application {
} }
} }
/**
* Draws objects into the canvas. Put you code here.
*
*@return nothing
*/
private void drawScene(double deltaT) {
lab.draw(deltaT);
}
private void exitProgram(WindowEvent evt) { private void exitProgram(WindowEvent evt) {
animationTimer.stop(); controller.stopGame();
System.exit(0); System.exit(0);
} }
} }
\ No newline at end of file
package lab; package lab;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.canvas.GraphicsContext; import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image; import javafx.scene.image.Image;
public class BulletAnimated { public class BulletAnimated implements DrawableSimulable, Collisionable{
private static final double STRENGTH_CANNON_COEFICIENT = 1.;
private Point2D position; private Point2D position;
private Point2D start; private Point2D start;
private Point2D speed; private Point2D speed;
private Point2D initialSpeed; private Point2D initialSpeed;
private double size; private double size;
private double mass = 2; private double mass = 2;
private double strenghtOfCannon = 2;
private double cannonLength = 100; private double cannonLength = 100;
private boolean accelerate = true; private boolean accelerate = false;
private boolean hitToGround = false; private boolean hitToGround = false;
private double crossSectionalArea; private double crossSectionalArea;
...@@ -23,7 +25,10 @@ public class BulletAnimated { ...@@ -23,7 +25,10 @@ public class BulletAnimated {
private Image image; private Image image;
private World world; private World world;
private Cannon cannon; private Cannon cannon;
private boolean fired;
private HitListener hitListener = new EmptyHitListener();
public BulletAnimated(World world, Cannon cannon) { public BulletAnimated(World world, Cannon cannon) {
this(world, cannon, new Point2D(0, 0), new Point2D(0, 0), 10); this(world, cannon, new Point2D(0, 0), new Point2D(0, 0), 10);
} }
...@@ -31,7 +36,7 @@ public class BulletAnimated { ...@@ -31,7 +36,7 @@ public class BulletAnimated {
public BulletAnimated(World world, Cannon cannon, Point2D start, Point2D speed, double size) { public BulletAnimated(World world, Cannon cannon, Point2D start, Point2D speed, double size) {
this.start = start; this.start = start;
this.position = this.start; this.position = this.start;
this.initialSpeed = speed; this.initialSpeed = Point2D.ZERO;
this.speed = speed; this.speed = speed;
this.size = size; this.size = size;
this.world = world; this.world = world;
...@@ -48,12 +53,15 @@ public class BulletAnimated { ...@@ -48,12 +53,15 @@ public class BulletAnimated {
} }
public void simulate(double deltaT) { public void simulate(double deltaT) {
double timeStep = deltaT * 1000; if (!fired) {
return;
}
if (accelerate && start.distance(position) < cannonLength) { if (accelerate && start.distance(position) < cannonLength) {
double cannonAngle = cannon.getAngle(); double cannonAngle = cannon.getAngle();
double strenghtOfCannon = cannon.getStrength() * STRENGTH_CANNON_COEFICIENT;
speed = speed speed = speed
.add(new Point2D(Math.cos(cannonAngle) * strenghtOfCannon, Math.sin(cannonAngle) * strenghtOfCannon) .add(new Point2D(Math.cos(cannonAngle) * strenghtOfCannon, Math.sin(cannonAngle) * strenghtOfCannon)
.multiply(1 / mass)); .multiply(deltaT / mass));
} else if (!hitToGround) { } else if (!hitToGround) {
accelerate = false; accelerate = false;
Point2D airResistanceforce = new Point2D( Point2D airResistanceforce = new Point2D(
...@@ -61,10 +69,10 @@ public class BulletAnimated { ...@@ -61,10 +69,10 @@ public class BulletAnimated {
-1. / 2 * crossSectionalArea * Constants.AIR_DENSITY * 0.47 * Math.pow(speed.getY(), 2)); -1. / 2 * crossSectionalArea * Constants.AIR_DENSITY * 0.47 * Math.pow(speed.getY(), 2));
Point2D acceleration = new Point2D(-airResistanceforce.getX() * mass, Point2D acceleration = new Point2D(-airResistanceforce.getX() * mass,
(-Constants.GRAVITATIONAL_ACCELERATION + airResistanceforce.getY()) * mass); (-Constants.GRAVITATIONAL_ACCELERATION + airResistanceforce.getY()) * mass);
speed = speed.add(acceleration.multiply(timeStep / 1000)); speed = speed.add(acceleration.multiply(deltaT));
} }
if (!hitToGround) { if (!hitToGround) {
position = position.add(speed); position = position.add(speed.multiply(deltaT*100));
if (!accelerate && position.getY() <= size / 2) { if (!accelerate && position.getY() <= size / 2) {
hitToGround = true; hitToGround = true;
position = new Point2D(position.getX(), size / 2); position = new Point2D(position.getX(), size / 2);
...@@ -73,14 +81,40 @@ public class BulletAnimated { ...@@ -73,14 +81,40 @@ public class BulletAnimated {
reload(); reload();
} }
} }
public Rectangle2D getBoundingBox() {
return new Rectangle2D(position.getX() - size, position.getY(), size, size);
}
public boolean overlaps(Dragon dragon) {
return getBoundingBox().intersects(dragon.getBoundingBox());
}
public void hitBy(Collisionable other) {
hitListener.hit();
reload();
}
public void reload() { public void reload() {
position = start; position = start;
speed = initialSpeed; speed = Point2D.ZERO;
hitToGround = false; hitToGround = false;
accelerate = false;
fired = false;
}
public void fire() {
if (fired) {
return;
}
fired = true;
accelerate = true; accelerate = true;
speed = initialSpeed;
}
public void setHitListener(HitListener hitListener) {
this.hitListener = hitListener;
} }
} }
...@@ -5,15 +5,16 @@ import javafx.scene.canvas.GraphicsContext; ...@@ -5,15 +5,16 @@ import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.transform.Affine; import javafx.scene.transform.Affine;
public class Cannon { public class Cannon implements DrawableSimulable {
private int direction=-1;
private double angle = 0; private double angle = 0;
private double strength = 50.;
private Point2D position; private Point2D position;
private Point2D size; private Point2D size;
private World world; private World world;
public Cannon(World world, Point2D position, Point2D size) { public Cannon(World world, Point2D position, Point2D size) {
...@@ -24,10 +25,11 @@ public class Cannon { ...@@ -24,10 +25,11 @@ public class Cannon {
} }
public void simulate(double timeStep) { public void simulate(double timeStep) {
angle = angle + direction*0.8; /*angle = angle + direction*0.8;
if(angle <=-90 || angle >= 0) { if(angle <=-90 || angle >= 0) {
direction*=-1; direction*=-1;
} }
{*/
} }
public void draw(GraphicsContext gc) { public void draw(GraphicsContext gc) {
...@@ -46,4 +48,17 @@ public class Cannon { ...@@ -46,4 +48,17 @@ public class Cannon {
public double getAngle() { public double getAngle() {
return (angle * -1) / 180 * Math.PI; return (angle * -1) / 180 * Math.PI;
} }
public void setAngle(double doubleValue) {
angle = doubleValue;
}
public double getStrength() {
return strength;
}
public void setStrength(double doubleValue) {
this.strength = doubleValue;
}
} }
package lab;
import javafx.geometry.Rectangle2D;
public interface Collisionable {
Rectangle2D getBoundingBox();
default boolean intersects(Collisionable other) {
return getBoundingBox().intersects(other.getBoundingBox());
}
void hitBy(Collisionable other);
}
package lab;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.canvas.GraphicsContext;
public class Dragon implements DrawableSimulable, Collisionable{
private Point2D position;
private Point2D speed;
private final World world;
private final double size = 45;
public Dragon(World world, Point2D position, Point2D speed) {
super();
this.world = world;
this.position = position;
this.speed = speed;
}
@Override
public void draw(GraphicsContext gc) {
Point2D canvasPosition = world.getCanvasPoint(position);
gc.drawImage(Constants.DRAGON_IMAGE, canvasPosition.getX(), canvasPosition.getY(), size, size);
}
@Override
public void simulate(double timeDelta) {
double timeDeltaS = timeDelta;
double newX = (position.getX() + speed.getX() * timeDeltaS + world.getWidth()) % world.getWidth();
double newY = (position.getY() + speed.getY() * timeDeltaS + world.getHeight()) % world.getHeight();
position = new Point2D(newX, newY);
}
public Rectangle2D getBoundingBox() {
return new Rectangle2D(position.getX() - size, position.getY(), size, size);
}
public void hit() {
speed = speed.multiply(-1.);
}
@Override
public void hitBy(Collisionable other) {
if (!(other instanceof Dragon)) {
hit();
}
}
}
package lab;
import javafx.scene.canvas.GraphicsContext;
public interface DrawableSimulable {
void draw(GraphicsContext gc);
void simulate(double deltaT);
}
package lab;
import javafx.animation.AnimationTimer;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
public class DrawingThread extends AnimationTimer {
private final Canvas canvas;
private final GraphicsContext gc;
private final World world;
private long lasttime = -1;
public DrawingThread(Canvas canvas, World world) {
this.canvas = canvas;
this.gc = canvas.getGraphicsContext2D();
this.world = world;
}
/**
* Draws objects into the canvas. Put you code here.
*/
@Override
public void handle(long now) {
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
world.draw(gc);
if (lasttime > 0) {
//time are in nanoseconds and method simulate expects seconds
world.simulate((now - lasttime) / 1e9);
}
lasttime = now;
}
}
package lab;
public class EmptyGameListener implements GameListener {
@Override
public void stateChanged(int shoots, int hits) {
}
@Override
public void gameOver() {
}
}
package lab;
public class EmptyHitListener implements HitListener {
@Override
public void hit() {
}
}
package lab;
import javafx.animation.AnimationTimer;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
public class GameController {
private World world;
@FXML
private Slider angleSlider;
@FXML
private Slider strengthSlider;
@FXML
private Canvas canvas;
@FXML
private Label shoots;
@FXML
private Label hits;
private AnimationTimer animationTimer;
public GameController() {
}
public void startGame() {
this.world = new World(canvas.getWidth(), canvas.getHeight());
//Draw scene on a separate thread to avoid blocking UI.
animationTimer = new DrawingThread(canvas, world);
angleSlider.valueProperty().addListener(this::angleChanged);
world.setCannonAngle(angleSlider.getValue());
strengthSlider.valueProperty().addListener(this::strenghtChanged);
world.setCannonStrength(strengthSlider.getValue());
animationTimer.start();
}
public void stopGame() {
animationTimer.stop();
}
@FXML
private void firePressed() {
world.fire();
}
private void angleChanged(ObservableValue<? extends Number> observable
, Number oldValue, Number newValue) {
world.setCannonAngle(newValue.doubleValue());
}
private void strenghtChanged(ObservableValue<? extends Number> observable
, Number oldValue, Number newValue) {
world.setCannonStrength(newValue.doubleValue());
}
}
package lab;
public interface GameListener {
void stateChanged(int shoots, int hits);
void gameOver();
}
package lab;
public interface HitListener {
void hit();
}
package lab;
import javafx.scene.canvas.Canvas;
public class Laboratory {
private World world;
private Canvas canvas;
public Laboratory(Canvas canvas) {
this.canvas = canvas;
this.world = new World(canvas.getWidth(), canvas.getHeight());
}
public void draw(double deltaT) {
world.draw(canvas);
world.simulate(deltaT);
}
}
package lab; package lab;
import java.util.Random;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext; import javafx.scene.canvas.GraphicsContext;
public class World { public class World {
private final static int NUMBER_OF_DRAGONS = 2;
private double width; private double width;
private double height; private double height;
private BulletAnimated bulletAnimatted;
private Cannon cannon; private GameListener gameListener = new EmptyGameListener();
private int hits = 0;
private int shoots = 0;
private DrawableSimulable []entities;
public World(double width, double height) { public World(double width, double height) {
super(); super();
this.width = width; this.width = width;
this.height = height; this.height = height;
cannon = new Cannon(this, new Point2D(50, 50), new Point2D(100, 20)); Cannon cannon = new Cannon(this, new Point2D(50, 50), new Point2D(100, 20));
bulletAnimatted = new BulletAnimated(this, cannon, new Point2D(30, 60), new Point2D(0, 0), 40); entities = new DrawableSimulable[2 + NUMBER_OF_DRAGONS];
entities[0] = cannon;
entities[1] = new BulletAnimated(this, cannon, new Point2D(30, 60), new Point2D(0, 0), 40);
Random rnd = new Random();
for (int i = 2; i < entities.length; i++) {
int x = rnd.nextInt((int) width);
int y = rnd.nextInt((int) height);
int vel_x = (rnd.nextInt(10) - 5) * 10;
int vel_y = (rnd.nextInt(10) - 5) * 10;
entities[i] = new Dragon(this, new Point2D(x, y), new Point2D(vel_x, vel_y));
}
} }
public Point2D getCanvasPoint(Point2D worldPoint) { public Point2D getCanvasPoint(Point2D worldPoint) {
return new Point2D(worldPoint.getX(), height - worldPoint.getY()); return new Point2D(worldPoint.getX(), height - worldPoint.getY());
} }
public void draw(Canvas canvas) { public void draw(GraphicsContext gc) {
GraphicsContext gc = canvas.getGraphicsContext2D(); gc.clearRect(0, 0, getWidth(), getHeight());
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); for(DrawableSimulable entity: entities) {
cannon.draw(gc); entity.draw(gc);
bulletAnimatted.draw(gc); }
} }
public void simulate(double timeDelta) { public void simulate(double timeDelta) {
bulletAnimatted.simulate(timeDelta); for(DrawableSimulable entity: entities) {
cannon.simulate(timeDelta); entity.simulate(timeDelta);
if (entity instanceof Collisionable) {
Collisionable thisCollinsable = (Collisionable) entity;
for(DrawableSimulable entity2 : entities) {
if (entity != entity2 && entity2 instanceof Collisionable) {
Collisionable thatCollinsable = (Collisionable) entity2;
if (thisCollinsable.intersects(thatCollinsable)) {
thisCollinsable.hitBy(thatCollinsable);
thatCollinsable.hitBy(thisCollinsable);
}
}
}
}
}
} }
public double getWidth() { public double getWidth() {
...@@ -50,4 +84,39 @@ public class World { ...@@ -50,4 +84,39 @@ public class World {
this.height = height; this.height = height;
} }
public void setCannonAngle(double doubleValue) {
for (DrawableSimulable d: entities) {
if (d instanceof Cannon) {
Cannon cannon = (Cannon) d;
cannon.setAngle(doubleValue);
}
}
}
public void setCannonStrength(double doubleValue) {
for (DrawableSimulable d: entities) {
if (d instanceof Cannon) {
Cannon cannon = (Cannon) d;
cannon.setStrength(doubleValue);
}
}
}
public void fire() {
for (DrawableSimulable e: entities) {
if (e instanceof BulletAnimated) {
BulletAnimated ba = (BulletAnimated) e;
ba.fire();
shoots++;
gameListener.stateChanged(shoots, hits);
}
}
}
public void setGameListener(GameListener listener) {
this.gameListener = listener;
}
} }
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Group?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.GameController">
<bottom>
<HBox alignment="CENTER" BorderPane.alignment="CENTER_LEFT">
<children>
<Slider fx:id="angleSlider" max="0.0" min="-90.0" showTickLabels="true" showTickMarks="true" value="-45.0" HBox.hgrow="ALWAYS" />
<Button mnemonicParsing="false" onAction="#firePressed" text="Fire" HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets bottom="11.0" left="14.0" right="11.0" top="12.0" />
</HBox.margin></Button>
<Slider fx:id="strengthSlider" showTickLabels="true" showTickMarks="true" value="50.0" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</bottom>
<center>
<Group BorderPane.alignment="CENTER">
<children>
<GridPane layoutX="20.0" layoutY="20.0" prefHeight="61.0" prefWidth="167.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="79.0" minWidth="10.0" prefWidth="51.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="124.0" minWidth="10.0" prefWidth="116.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Shoots:" />
<Label fx:id="shoots" text="0" GridPane.columnIndex="1" />
<Label text="Hits:" GridPane.rowIndex="1" />
<Label fx:id="hits" text="0" GridPane.rowIndex="1" GridPane.columnIndex="1" />
</children>
</GridPane>
<Canvas fx:id="canvas" height="400.0" width="600.0" />
</children>
</Group>
</center>
</BorderPane>