diff --git a/pom.xml b/pom.xml
index 53a059ee66a70ef50dbbb866e904112f2ae64eb3..31f71f2f89db024293be17c164419ce3b1564efe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>vsb-cs-java1</groupId>
-	<artifactId>lab02</artifactId>
+	<artifactId>lab03</artifactId>
 	<version>0.0.1-SNAPHOST</version>
 	<packaging>jar</packaging>
 	<properties>
diff --git a/src/main/java/lab/App.java b/src/main/java/lab/App.java
index 2fa95e3778cd4d5ae9c8b32a9f4fd7044224ea30..c94ee8b5e8b68ccaab4d4c0718cb9da3cc59af5f 100644
--- a/src/main/java/lab/App.java
+++ b/src/main/java/lab/App.java
@@ -5,7 +5,6 @@ import javafx.application.Application;
 import javafx.scene.Group;
 import javafx.scene.Scene;
 import javafx.scene.canvas.Canvas;
-import javafx.scene.canvas.GraphicsContext;
 import javafx.stage.Stage;
 import javafx.stage.WindowEvent;
 
@@ -21,7 +20,7 @@ public class App extends Application {
 	
 	private Canvas canvas;
 	private AnimationTimer animationTimer;
-	
+	private Laboratory lab;
 	@Override
 	public void start(Stage primaryStage) {
 		try {
@@ -33,10 +32,10 @@ public class App extends Application {
 			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
 			primaryStage.setScene(scene);
 			primaryStage.resizableProperty().set(false);
-			primaryStage.setTitle("Java 1 - 2nd laboratory");
+			primaryStage.setTitle("Java 1 - 3rd laboratory");
 			primaryStage.show();
 			
-			
+			lab = new Laboratory(canvas);
 			
 			//Draw scene on a separate thread to avoid blocking UI.
 			animationTimer = new AnimationTimer() {
@@ -66,9 +65,7 @@ public class App extends Application {
 	 *@return      nothing
 	 */
 	private void drawScene(double deltaT) {
-		//graphic context is used for a painting
-		GraphicsContext gc = canvas.getGraphicsContext2D();
-		
+		lab.draw(deltaT);
 	}
 	
 	private void exitProgram(WindowEvent evt) {
diff --git a/src/main/java/lab/BulletAnimated.java b/src/main/java/lab/BulletAnimated.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d953f5ccf205688aa2703f71bf97f8b2c11676b
--- /dev/null
+++ b/src/main/java/lab/BulletAnimated.java
@@ -0,0 +1,86 @@
+package lab;
+
+import javafx.geometry.Point2D;
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.image.Image;
+
+public class BulletAnimated {
+
+	private Point2D position;
+	private Point2D start;
+	private Point2D speed;
+	private Point2D initialSpeed;
+	private double size;
+	private double mass = 2;
+	private double strenghtOfCannon = 2;
+	private double cannonLength = 100;
+	private boolean accelerate = true;
+	private boolean hitToGround = false;
+
+	private double crossSectionalArea;
+	private double dragCoefficient = 0.47;
+	
+	private Image image;
+	private World world;
+	private Cannon cannon;
+
+	public BulletAnimated(World world, Cannon cannon) {
+		this(world, cannon, new Point2D(0, 0), new Point2D(0, 0), 10);
+	}
+
+	public BulletAnimated(World world, Cannon cannon, Point2D start, Point2D speed, double size) {
+		this.start = start;
+		this.position = this.start;
+		this.initialSpeed = speed;
+		this.speed = speed;
+		this.size = size;
+		this.world = world;
+		this.cannon = cannon;
+		image = new Image(getClass().getResourceAsStream("fireball-transparent.gif"), size, size,
+				true, true);
+	}
+
+	public void draw(GraphicsContext gc) {
+		gc.save();
+		Point2D canvasPosition = world.getCanvasPoint(position);
+		gc.drawImage(image, canvasPosition.getX(), canvasPosition.getY());
+		gc.restore();
+	}
+
+	public void simulate(double deltaT) {
+		double timeStep = deltaT * 1000;
+		if (accelerate && start.distance(position) < cannonLength) {
+			double cannonAngle = cannon.getAngle(); 
+			speed = speed
+					.add(new Point2D(Math.cos(cannonAngle) * strenghtOfCannon, Math.sin(cannonAngle) * strenghtOfCannon)
+							.multiply(1 / mass));
+		} else if (!hitToGround) {
+			accelerate = false;
+			Point2D airResistanceforce = new Point2D(
+					-1. / 2 * crossSectionalArea * Constants.AIR_DENSITY * dragCoefficient * Math.pow(speed.getX(), 2),
+					-1. / 2 * crossSectionalArea * Constants.AIR_DENSITY * 0.47 * Math.pow(speed.getY(), 2));
+			Point2D acceleration = new Point2D(-airResistanceforce.getX() * mass,
+					(-Constants.GRAVITATIONAL_ACCELERATION + airResistanceforce.getY()) * mass);
+			speed = speed.add(acceleration.multiply(timeStep / 1000));
+		}
+		if (!hitToGround) {
+			position = position.add(speed);
+			if (!accelerate && position.getY() <= size / 2) {
+				hitToGround = true;
+				position = new Point2D(position.getX(), size / 2);
+			}
+		} else {
+			reload();
+		}
+		
+		
+	}
+
+	public void reload() {
+		position = start;
+		speed = initialSpeed;
+		hitToGround = false;
+		accelerate = true;
+	}
+	
+}
diff --git a/src/main/java/lab/Cannon.java b/src/main/java/lab/Cannon.java
new file mode 100644
index 0000000000000000000000000000000000000000..92c54310524127224b89db59c3b840b7709df328
--- /dev/null
+++ b/src/main/java/lab/Cannon.java
@@ -0,0 +1,49 @@
+package lab;
+
+import javafx.geometry.Point2D;
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.paint.Color;
+import javafx.scene.transform.Affine;
+
+public class Cannon {
+
+	private int direction=-1;
+	private double angle = 0;
+	private Point2D position;
+	private Point2D size;
+	private World world;
+	
+	
+	 
+
+	public Cannon(World world, Point2D position, Point2D size) {
+		super();
+		this.world = world;
+		this.position = position;
+		this.size = size;
+	}
+
+	public void simulate(double timeStep) {
+		angle = angle + direction*0.8;
+		if(angle <=-90 || angle >= 0) {
+			direction*=-1;
+		}
+	}
+	
+	public void draw(GraphicsContext gc) {
+		gc.save();
+		Point2D worldPosition = world.getCanvasPoint(position);
+		gc.setFill(Color.BROWN);
+		gc.fillRect(worldPosition.getX()-10, worldPosition.getY()+size.getY(), size.getX()+20, size.getY()/2);
+		gc.fillOval(worldPosition.getX()-20, worldPosition.getY()+size.getY()/2, 40, 40);
+		gc.fillOval(worldPosition.getX()+size.getX(), worldPosition.getY()+size.getY()/2, 40, 40);
+		gc.setTransform(new Affine(Affine.rotate(angle, worldPosition.getX(), worldPosition.getY()+size.getY()/2)));
+		gc.setFill(Color.BLACK);
+		gc.fillRect(worldPosition.getX(), worldPosition.getY(), size.getX(), size.getY());
+		gc.restore();
+	}
+
+	public double getAngle() {
+		return (angle * -1) / 180 * Math.PI;
+	}
+}
diff --git a/src/main/java/lab/Constants.java b/src/main/java/lab/Constants.java
new file mode 100644
index 0000000000000000000000000000000000000000..98b67c362b4cff775e4a587b6324df481e6b947a
--- /dev/null
+++ b/src/main/java/lab/Constants.java
@@ -0,0 +1,17 @@
+package lab;
+
+import javafx.scene.image.Image;
+
+public final class Constants {
+	private Constants() {}
+	
+	public static final double GRAVITATIONAL_ACCELERATION = 9.81;
+	
+	public static final double AIR_DENSITY = 1.2;
+	
+	public static final Image DRAGON_IMAGE;
+	
+	static{ 
+		DRAGON_IMAGE = new Image(Constants.class.getResourceAsStream("dragon.gif"));
+	}
+}
diff --git a/src/main/java/lab/Laboratory.java b/src/main/java/lab/Laboratory.java
new file mode 100644
index 0000000000000000000000000000000000000000..c45aa390eb2764617432b913606fc69bed8d265b
--- /dev/null
+++ b/src/main/java/lab/Laboratory.java
@@ -0,0 +1,20 @@
+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);
+		
+	}
+}
diff --git a/src/main/java/lab/Routines.java b/src/main/java/lab/Routines.java
index 89fcce7f1e20229e95fbdc50c69e2b0bb695f060..cfc1fc8b98187dce87ac262c34d087bbbc3d81a9 100644
--- a/src/main/java/lab/Routines.java
+++ b/src/main/java/lab/Routines.java
@@ -1,8 +1,8 @@
 package lab;
 
-public class Routines {
+public final class Routines {
 
-	
+	private Routines() {	}
 	
 	public static void sleep(int timeInMilisenonds) {
 		try {
diff --git a/src/main/java/lab/World.java b/src/main/java/lab/World.java
new file mode 100644
index 0000000000000000000000000000000000000000..e8c621995c224c22aabe1f6bf6e8f4b86f3d2b85
--- /dev/null
+++ b/src/main/java/lab/World.java
@@ -0,0 +1,53 @@
+package lab;
+
+import javafx.geometry.Point2D;
+import javafx.scene.canvas.Canvas;
+import javafx.scene.canvas.GraphicsContext;
+
+public class World {
+	private double width;
+	private double height;
+	private BulletAnimated bulletAnimatted;
+	private Cannon cannon;
+
+	public World(double width, double height) {
+		super();
+		this.width = width;
+		this.height = height;
+		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);
+	}
+
+	public Point2D getCanvasPoint(Point2D worldPoint) {
+		return new Point2D(worldPoint.getX(), height - worldPoint.getY());
+	}
+
+	public void draw(Canvas canvas) {
+		GraphicsContext gc = canvas.getGraphicsContext2D();
+		gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
+		cannon.draw(gc);
+		bulletAnimatted.draw(gc);
+	}
+
+	public void simulate(double timeDelta) {
+		bulletAnimatted.simulate(timeDelta);
+		cannon.simulate(timeDelta);
+	}
+
+	public double getWidth() {
+		return width;
+	}
+
+	public void setWidth(double width) {
+		this.width = width;
+	}
+
+	public double getHeight() {
+		return height;
+	}
+
+	public void setHeight(double height) {
+		this.height = height;
+	}
+
+}
diff --git a/src/main/resources/lab/dragon.gif b/src/main/resources/lab/dragon.gif
new file mode 100644
index 0000000000000000000000000000000000000000..aa36183f67ee4fbc6fa99b80076bdc7a7489a445
Binary files /dev/null and b/src/main/resources/lab/dragon.gif differ