Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package dk.sdu.mmmi.cbse.asteroid;

import dk.sdu.mmmi.cbse.common.asteroids.Asteroid;
import dk.sdu.mmmi.cbse.common.data.Entity;
import dk.sdu.mmmi.cbse.common.data.GameData;
import dk.sdu.mmmi.cbse.common.data.World;
import dk.sdu.mmmi.cbse.common.services.IEntityProcessingService;

import java.util.Random;

public class AsteroidControlSystem implements IEntityProcessingService {

private final Random random = new Random();
private final int maxAsteroids = 10; // max asteroids
private final float spawnInterval = 1.5f; // Seconds between spawn of asteroid.
private float spawnTimer = 0;

@Override
public void process(GameData gameData, World world) {
spawnTimer += gameData.getDelta();

int currentCount = world.getEntities(Asteroid.class).size();

while (spawnTimer >= spawnInterval && currentCount < maxAsteroids) {
Entity asteroid = createAsteroid(gameData);
world.addEntity(asteroid);
spawnTimer -= spawnInterval;
currentCount++;
}
}

private Entity createAsteroid(GameData gameData) {
Entity asteroid = new Asteroid();

int size = random.nextInt(20) + 10; // size range
asteroid.setPolygonCoordinates(
size, -size,
-size, -size,
-size, size,
size, size
);

// spawn point to avoid asteroids spawning anywhere
int side = random.nextInt(4);
float x, y, rotation;
switch (side) {
case 0: // Left
x = 0;
y = random.nextInt(gameData.getDisplayHeight());
rotation = random.nextInt(120) - 60;
break;
case 1: // Right
x = gameData.getDisplayWidth();
y = random.nextInt(gameData.getDisplayHeight());
rotation = 180 + random.nextInt(120) - 60;
break;
case 2: // Top
x = random.nextInt(gameData.getDisplayWidth());
y = 0;
rotation = 90 + random.nextInt(120) - 60;
break;
case 3: // Bottom
x = random.nextInt(gameData.getDisplayWidth());
y = gameData.getDisplayHeight();
rotation = 270 + random.nextInt(120) - 60;
break;
default:
x = gameData.getDisplayWidth() / 2f;
y = gameData.getDisplayHeight() / 2f;
rotation = random.nextInt(360);
}

asteroid.setX(x);
asteroid.setY(y);
asteroid.setRotation(rotation);
asteroid.setRadius(size / 2f);
asteroid.setColor(javafx.scene.paint.Color.BLACK);

return asteroid;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import dk.sdu.mmmi.cbse.common.data.GameData;
import dk.sdu.mmmi.cbse.common.data.World;
import dk.sdu.mmmi.cbse.common.services.IGamePluginService;
import javafx.scene.paint.Color;

import java.util.Random;

/**
Expand All @@ -29,6 +31,7 @@ public void stop(GameData gameData, World world) {

private Entity createAsteroid(GameData gameData) {
Entity asteroid = new Asteroid();
asteroid.setColor(Color.BLACK);
Random rnd = new Random();
int size = rnd.nextInt(10) + 5;
asteroid.setPolygonCoordinates(size, -size, -size, -size, -size, size, size, size);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,30 @@ public class AsteroidProcessor implements IEntityProcessingService {

@Override
public void process(GameData gameData, World world) {

for (Entity asteroid : world.getEntities(Asteroid.class)) {
double changeX = Math.cos(Math.toRadians(asteroid.getRotation()));
double changeY = Math.sin(Math.toRadians(asteroid.getRotation()));

asteroid.setX(asteroid.getX() + changeX * 0.5);
asteroid.setY(asteroid.getY() + changeY * 0.5);

// ✅ FIXED: Use + instead of -
if (asteroid.getX() < 0) {
asteroid.setX(asteroid.getX() - gameData.getDisplayWidth());
asteroid.setX(asteroid.getX() + gameData.getDisplayWidth());
}

if (asteroid.getX() > gameData.getDisplayWidth()) {
asteroid.setX(asteroid.getX() % gameData.getDisplayWidth());
}

if (asteroid.getY() < 0) {
asteroid.setY(asteroid.getY() - gameData.getDisplayHeight());
asteroid.setY(asteroid.getY() + gameData.getDisplayHeight());
}

if (asteroid.getY() > gameData.getDisplayHeight()) {
asteroid.setY(asteroid.getY() % gameData.getDisplayHeight());
}

}

}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
package dk.sdu.mmmi.cbse.asteroid;

import dk.sdu.mmmi.cbse.common.asteroids.Asteroid;
import dk.sdu.mmmi.cbse.common.asteroids.IAsteroidSplitter;
import dk.sdu.mmmi.cbse.common.data.Entity;
import dk.sdu.mmmi.cbse.common.data.World;

/**
*
* @author corfixen
*/
public class AsteroidSplitterImpl implements IAsteroidSplitter {

@Override
public void createSplitAsteroid(Entity e, World world) {
}
public void createSplitAsteroid(Entity asteroid, World world) {
float currentRadius = asteroid.getRadius();

// Prevent splitting if already small
if (currentRadius <= 5) {
return;
}


float splitRadius = 4f;

for (int i = 0; i < 2; i++) {
Entity smallerAsteroid = new Asteroid();

smallerAsteroid.setX(asteroid.getX());
smallerAsteroid.setY(asteroid.getY());
smallerAsteroid.setRotation((float) (asteroid.getRotation() + (i == 0 ? 20 : -20)));

smallerAsteroid.setRadius(splitRadius);
smallerAsteroid.setPolygonCoordinates(
splitRadius, -splitRadius,
-splitRadius, -splitRadius,
-splitRadius, splitRadius,
splitRadius, splitRadius
);

smallerAsteroid.setColor(asteroid.getColor());

world.addEntity(smallerAsteroid);
}
}
}
18 changes: 12 additions & 6 deletions Asteroids/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import dk.sdu.mmmi.cbse.common.services.IEntityProcessingService;
import dk.sdu.mmmi.cbse.common.services.IGamePluginService;

module Asteroid {
requires Common;
requires CommonAsteroids;
provides IGamePluginService with dk.sdu.mmmi.cbse.asteroid.AsteroidPlugin;
provides IEntityProcessingService with dk.sdu.mmmi.cbse.asteroid.AsteroidProcessor;
}
requires javafx.graphics;

provides dk.sdu.mmmi.cbse.common.services.IGamePluginService
with dk.sdu.mmmi.cbse.asteroid.AsteroidPlugin;

provides dk.sdu.mmmi.cbse.common.services.IEntityProcessingService
with dk.sdu.mmmi.cbse.asteroid.AsteroidProcessor,
dk.sdu.mmmi.cbse.asteroid.AsteroidControlSystem;

provides dk.sdu.mmmi.cbse.common.asteroids.IAsteroidSplitter
with dk.sdu.mmmi.cbse.asteroid.AsteroidSplitterImpl;
}
23 changes: 23 additions & 0 deletions Bullet/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
<artifactId>Bullet</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>Common</artifactId>
Expand All @@ -19,5 +26,21 @@
<artifactId>CommonBullet</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,65 @@
import dk.sdu.mmmi.cbse.common.data.GameData;
import dk.sdu.mmmi.cbse.common.data.World;
import dk.sdu.mmmi.cbse.common.services.IEntityProcessingService;
import javafx.scene.paint.Color;

import java.util.*;

public class BulletControlSystem implements IEntityProcessingService, BulletSPI {

private static final float MAX_LIFETIME = 1.5f; // Bullets disappear after 1.5 seconds
private static final float BULLET_SPEED = 10f; // How fast bullets move per frame

// Keeps track of how long each bullet has existed
private final Map<Entity, Float> bulletTimers = new HashMap<>();

@Override
public void process(GameData gameData, World world) {
List<Entity> expiredBullets = new ArrayList<>();

for (Entity bullet : world.getEntities(Bullet.class)) {
double changeX = Math.cos(Math.toRadians(bullet.getRotation()));
double changeY = Math.sin(Math.toRadians(bullet.getRotation()));
bullet.setX(bullet.getX() + changeX * 3);
bullet.setY(bullet.getY() + changeY * 3);
// Move the bullet forward based on its direction and speed
double radians = Math.toRadians(bullet.getRotation());
bullet.setX(bullet.getX() + Math.cos(radians) * BULLET_SPEED);
bullet.setY(bullet.getY() + Math.sin(radians) * BULLET_SPEED);

// Update how long this bullet has been alive
float newLifetime = bulletTimers.getOrDefault(bullet, 0f) + gameData.getDelta();
bulletTimers.put(bullet, newLifetime);

// Mark bullets that lived too long for removal
if (newLifetime >= MAX_LIFETIME) {
expiredBullets.add(bullet);
}
}

// remove expired bullets
for (Entity expired : expiredBullets) {
bulletTimers.remove(expired);
world.removeEntity(expired);
}
}

@Override
public Entity createBullet(Entity shooter, GameData gameData) {
Entity bullet = new Bullet();
bullet.setPolygonCoordinates(1, -1, 1, 1, -1, 1, -1, -1);
double changeX = Math.cos(Math.toRadians(shooter.getRotation()));
double changeY = Math.sin(Math.toRadians(shooter.getRotation()));
bullet.setX(shooter.getX() + changeX * 10);
bullet.setY(shooter.getY() + changeY * 10);
bullet.setRotation(shooter.getRotation());
bullet.setRadius(1);
return bullet;
Entity newBullet = new Bullet();

// bullet shape
newBullet.setPolygonCoordinates(0, -2, 1, -1, 1, 1, 0, 2, -1, 1, -1, -1);


double angle = Math.toRadians(shooter.getRotation());
newBullet.setX(shooter.getX() + Math.cos(angle) * 3);
newBullet.setY(shooter.getY() + Math.sin(angle) * 3);

newBullet.setRotation(shooter.getRotation());
newBullet.setRadius(1); // For collision detection

newBullet.setColor(Color.YELLOW); // Bullet color

// Start the bullet's lifetime timer at 0
bulletTimers.put(newBullet, 0f);

return newBullet;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public void stop(GameData gameData, World world) {
for (Entity e : world.getEntities()) {
if (e.getClass() == Bullet.class) {
world.removeEntity(e);

}
}
}
Expand Down
21 changes: 13 additions & 8 deletions Bullet/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import dk.sdu.mmmi.cbse.common.bullet.BulletSPI;
import dk.sdu.mmmi.cbse.common.services.IEntityProcessingService;
import dk.sdu.mmmi.cbse.common.services.IGamePluginService;

module Bullet {
requires Common;
requires CommonBullet;
provides IGamePluginService with dk.sdu.mmmi.cbse.bulletsystem.BulletPlugin;
provides BulletSPI with dk.sdu.mmmi.cbse.bulletsystem.BulletControlSystem;
provides IEntityProcessingService with dk.sdu.mmmi.cbse.bulletsystem.BulletControlSystem;
}
requires javafx.graphics;

exports dk.sdu.mmmi.cbse.bulletsystem;

provides dk.sdu.mmmi.cbse.common.services.IGamePluginService
with dk.sdu.mmmi.cbse.bulletsystem.BulletPlugin;

provides dk.sdu.mmmi.cbse.common.bullet.BulletSPI
with dk.sdu.mmmi.cbse.bulletsystem.BulletControlSystem;

provides dk.sdu.mmmi.cbse.common.services.IEntityProcessingService
with dk.sdu.mmmi.cbse.bulletsystem.BulletControlSystem;
}
26 changes: 26 additions & 0 deletions Bullet/src/test/java/BulletControlSystemTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dk.sdu.mmmi.cbse.bulletsystem;

import dk.sdu.mmmi.cbse.common.data.Entity;
import dk.sdu.mmmi.cbse.common.data.GameData;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class BulletControlSystemTest {

private final BulletControlSystem system = new BulletControlSystem();

@Test
void createsBulletCorrectly() {
Entity shooter = new Entity();
shooter.setX(100);
shooter.setY(200);
shooter.setRotation(90);

Entity bullet = system.createBullet(shooter, new GameData());

assertNotNull(bullet);
assertEquals(90, bullet.getRotation(), 0.1);
assertEquals(1, bullet.getRadius(), 0.1);
assertTrue(bullet.getY() > 200); // moving down if rotation is 90 degrees
}
}
Loading