Skip to content

Commit

Permalink
Dungeon: Enhance Projectile and Skill Logic (#1576)
Browse files Browse the repository at this point in the history
Dieser PR führt neue Funktionalitäten für Projektile und Skills ein, um
mehr Flexibilität und Kontrolle zu ermöglichen.

- **DamageProjectile.java**:
  - Hinzufügen eines Namens für Projektile
- Implementierung einer Ignore-Liste für Entities, die nicht vom
Projektil getroffen werden sollen
  - Einführung von Tint-Farben für Projektile
- Hinzufügen eines Callbacks für Treffer auf Entities, der vor dem
Schaden ausgeführt wird
  - Neue Methoden zum Verwalten der Ignore-Liste und Tint-Farbe

- **FireballSkill.java**:
- Anpassung des Konstruktors zur Unterstützung der neuen
`DamageProjectile`-Funktionalitäten
- Konstante Werte wie Projektilgeschwindigkeit, Schaden und Reichweite
wurde umbenannt.
  - Neuer Konstruktor für benutzerdefinierte Werte

- **Skill.java**:
  - Hinzufügen von Methoden zum Setzen und Abrufen der Abklingzeit
- Neue Methode zum setzen von der Abklingzeit auf den aktuell Zeitpunkt.

Diese Änderungen ermöglichen eine feinere Kontrolle über das Verhalten
von Projektilen und Skills. Projektile können nun benannt, bestimmte
Entities von der Kollision ausgeschlossen und das visuelle
Erscheinungsbild durch Tint-Farben anpassen werden. Die neue
Callback-Funktion für Entity-Treffer erlaubt zusätzliche Effekte oder
Logik vor der Schadensberechnung. Zusätzlich kann jetzt dynamisch die
Abklingzeit von Skills geändert werden.

Diese Änderung, verändert den Konstruktor für `DamageProjectile`, da
jetzt jede Implementierung einen Namen angeben muss.
  • Loading branch information
Flamtky authored Jul 5, 2024
1 parent 8658b68 commit adebc9f
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 17 deletions.
120 changes: 110 additions & 10 deletions dungeon/src/contrib/utils/components/skill/DamageProjectile.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
import core.utils.components.MissingComponentException;
import core.utils.components.path.IPath;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Logger;
Expand All @@ -29,6 +32,7 @@
public abstract class DamageProjectile implements Consumer<Entity> {

private static final Consumer<Entity> DEFAULT_ON_WALL_HIT = Game::remove;
private static final BiConsumer<Entity, Entity> DEFAULT_ON_ENTITY_HIT = (a, b) -> {};
private static final Logger LOGGER = Logger.getLogger(DamageProjectile.class.getSimpleName());
private final IPath pathToTexturesOfProjectile;
private final float projectileSpeed;
Expand All @@ -38,15 +42,27 @@ public abstract class DamageProjectile implements Consumer<Entity> {
private final Point projectileHitBoxSize;
private final Supplier<Point> selectionFunction;
private final Consumer<Entity> onWallHit;
private final String name;
private static int nextId = 0;
private final List<Entity> ignoreEntities = new ArrayList<>();

/**
* The DamageProjectile constructor sets the path to the textures of the projectile, the speed of
* the projectile, the damage amount and type to be dealt, the size of the projectile's hit box,
* the target selection function, the range of the projectile, and the behavior when a wall is
* hit.
* The behavior when an entity is hit. (The first parameter is the projectile, the second the
* entity that was hit)
*/
private final BiConsumer<Entity, Entity> onEntityHit;

private int tintColor = -1; // -1 means no tint

/**
* The DamageProjectile constructor sets the name, the path to the textures of the projectile, the
* speed of the projectile, the damage amount and type to be dealt, the size of the projectile's
* hit box, the target selection function, the range of the projectile, and the behavior when a
* wall is hit.
*
* <p>For a specific implementation, see {@link FireballSkill}.
*
* @param name Name of the projectile.
* @param pathToTexturesOfProjectile Path to the textures of the projectile.
* @param projectileSpeed Speed of the projectile.
* @param damageAmount Amount of damage to be dealt.
Expand All @@ -55,16 +71,20 @@ public abstract class DamageProjectile implements Consumer<Entity> {
* @param selectionFunction Specific functionality of the projectile.
* @param projectileRange Range in which the projectile is effective.
* @param onWallHit Behavior when a wall is hit.
* @param onEntityHit Behavior when an entity is hit before the damage is applied.
*/
public DamageProjectile(
final String name,
final IPath pathToTexturesOfProjectile,
float projectileSpeed,
int damageAmount,
final DamageType damageType,
final Point projectileHitBoxSize,
final Supplier<Point> selectionFunction,
float projectileRange,
final Consumer<Entity> onWallHit) {
final Consumer<Entity> onWallHit,
final BiConsumer<Entity, Entity> onEntityHit) {
this.name = name + "_" + nextId++;
this.pathToTexturesOfProjectile = pathToTexturesOfProjectile;
this.damageAmount = damageAmount;
this.damageType = damageType;
Expand All @@ -73,6 +93,45 @@ public DamageProjectile(
this.projectileHitBoxSize = projectileHitBoxSize;
this.selectionFunction = selectionFunction;
this.onWallHit = onWallHit;
this.onEntityHit = onEntityHit;
}

/**
* The DamageProjectile constructor sets the name, the path to the textures of the projectile, the
* speed of the projectile, the damage amount and type to be dealt, the size of the projectile's
* hit box, the target selection function, and the range of the projectile.
*
* <p>For a specific implementation, see {@link FireballSkill}
*
* @param name Name of the projectile.
* @param pathToTexturesOfProjectile Path to the textures of the projectile.
* @param projectileSpeed Speed of the projectile.
* @param damageAmount Amount of damage to be dealt.
* @param damageType Type of damage to be dealt.
* @param projectileHitBoxSize Size of the hit box.
* @param selectionFunction Specific functionality of the projectile.
* @param projectileRange Range in which the projectile is effective.
*/
public DamageProjectile(
String name,
final IPath pathToTexturesOfProjectile,
float projectileSpeed,
int damageAmount,
final DamageType damageType,
final Point projectileHitBoxSize,
final Supplier<Point> selectionFunction,
float projectileRange) {
this(
name,
pathToTexturesOfProjectile,
projectileSpeed,
damageAmount,
damageType,
projectileHitBoxSize,
selectionFunction,
projectileRange,
DEFAULT_ON_WALL_HIT,
DEFAULT_ON_ENTITY_HIT);
}

/**
Expand All @@ -99,14 +158,14 @@ public DamageProjectile(
final Supplier<Point> selectionFunction,
float projectileRange) {
this(
"DamageProjectile",
pathToTexturesOfProjectile,
projectileSpeed,
damageAmount,
damageType,
projectileHitBoxSize,
selectionFunction,
projectileRange,
DEFAULT_ON_WALL_HIT);
projectileRange);
}

/**
Expand All @@ -124,7 +183,7 @@ public DamageProjectile(
*/
@Override
public void accept(final Entity entity) {
Entity projectile = new Entity("Projectile");
Entity projectile = new Entity(name);
// Get the PositionComponent of the entity
PositionComponent epc =
entity
Expand All @@ -133,7 +192,9 @@ public void accept(final Entity entity) {
projectile.add(new PositionComponent(epc.position()));

try {
projectile.add(new DrawComponent(pathToTexturesOfProjectile));
DrawComponent dc = new DrawComponent(pathToTexturesOfProjectile);
dc.tintColor(tintColor());
projectile.add(dc);
} catch (IOException e) {
LOGGER.warning(
String.format("The DrawComponent for the projectile %s cant be created. ", entity)
Expand Down Expand Up @@ -169,10 +230,11 @@ public void accept(final Entity entity) {
// Create a collision handler for the projectile
TriConsumer<Entity, Entity, Tile.Direction> collide =
(a, b, from) -> {
if (b != entity) {
if (b != entity && !ignoreEntities.contains(b)) {
b.fetch(HealthComponent.class)
.ifPresent(
hc -> {
onEntityHit.accept(projectile, b);
// Apply the projectile damage to the collided entity
hc.receiveHit(new Damage(damageAmount, damageType, entity));

Expand All @@ -190,6 +252,44 @@ public void accept(final Entity entity) {
playSound();
}

/**
* Adds an entity to the list of entities to be ignored by the projectile. Entities in this list
* will not be affected by the projectile's collision handler.
*
* @param entity The entity to be ignored by the projectile.
*/
public void ignoreEntity(Entity entity) {
ignoreEntities.add(entity);
}

/**
* Removes an entity from the list of entities to be ignored by the projectile. Entities not in
* this list will be affected by the projectile's collision handler.
*
* @param entity The entity to be removed from the ignore list.
*/
public void removeIgnoredEntity(Entity entity) {
ignoreEntities.remove(entity);
}

/** Override this method to play a Sound-effect on spawning the projectile if you want. */
protected void playSound() {}

/**
* Sets the tint color of the projectile. Set to -1 to remove the tint.
*
* @param tintColor The tint color of the projectile.
*/
public void tintColor(int tintColor) {
this.tintColor = tintColor;
}

/**
* Returns the tint color of the projectile.
*
* @return The tint color of the projectile. -1 means no tint.
*/
public int tintColor() {
return tintColor;
}
}
32 changes: 26 additions & 6 deletions dungeon/src/contrib/utils/components/skill/FireballSkill.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@
*/
public final class FireballSkill extends DamageProjectile {

private static final String SKILL_NAME = "fireball";
private static final IPath PROJECTILE_TEXTURES = new SimpleIPath("skills/fireball");
private static final IPath PROJECTILE_SOUND = new SimpleIPath("sounds/fireball.wav");
private static final float PROJECTILE_SPEED = 15.0f;
private static final int DAMAGE_AMOUNT = 5;
private static final float DEFAULT_PROJECTILE_SPEED = 15.0f;
private static final int DEFAULT_DAMAGE_AMOUNT = 5;
private static final float DEFAULT_PROJECTILE_RANGE = 7f;
private static final DamageType DAMAGE_TYPE = DamageType.FIRE;
private static final Point HIT_BOX_SIZE = new Point(1, 1);
private static final float PROJECTILE_RANGE = 7f;

/**
* Create a {@link DamageProjectile} that looks like a fireball and will cause fire damage.
Expand All @@ -36,14 +37,33 @@ public final class FireballSkill extends DamageProjectile {
* @see DamageProjectile
*/
public FireballSkill(final Supplier<Point> targetSelection) {
this(
targetSelection, DEFAULT_PROJECTILE_RANGE, DEFAULT_PROJECTILE_SPEED, DEFAULT_DAMAGE_AMOUNT);
}

/**
* Creates a new FireballSkill with the specified target selection, range, speed, and damage
* amount. The target selection is a function used to select the point where the projectile should
* fly to. The range is the maximum distance the projectile can travel. The speed is the speed at
* which the projectile travels. The damage amount is the amount of damage the projectile will
* deal upon impact.
*
* @param targetSelection A function used to select the point where the projectile should fly to.
* @param range The maximum distance the projectile can travel.
* @param speed The speed at which the projectile travels.
* @param damageAmount The amount of damage the projectile will deal upon impact.
*/
public FireballSkill(
final Supplier<Point> targetSelection, float range, float speed, int damageAmount) {
super(
SKILL_NAME,
PROJECTILE_TEXTURES,
PROJECTILE_SPEED,
DAMAGE_AMOUNT,
speed,
damageAmount,
DAMAGE_TYPE,
HIT_BOX_SIZE,
targetSelection,
PROJECTILE_RANGE);
range);
}

@Override
Expand Down
30 changes: 29 additions & 1 deletion dungeon/src/contrib/utils/components/skill/Skill.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
public class Skill {

private final Consumer<Entity> skillFunction;
private final long coolDownInMilliSeconds;
private long coolDownInMilliSeconds;
private Instant lastUsed;
private Instant nextUsableAt = Instant.now();

Expand Down Expand Up @@ -64,11 +64,39 @@ public boolean canBeUsedAgain() {
return !(Duration.between(Instant.now(), nextUsableAt).toMillis() > 0);
}

/**
* Sets the cooldown of this skill.
*
* @param newCoolDown The new cooldown in milliseconds.
*/
public void cooldown(long newCoolDown) {
this.coolDownInMilliSeconds = newCoolDown;
}

/**
* Returns the cooldown of this skill.
*
* @return int The cooldown in milliseconds.
*/
public long cooldown() {
return coolDownInMilliSeconds;
}

/**
* Adds coolDownInMilliSeconds to the time the skill was last used and updates when this skill can
* be used again.
*/
private void activateCoolDown() {
nextUsableAt = lastUsed.plusMillis(coolDownInMilliSeconds);
}

/**
* Sets the last used time to now.
*
* <p>This method is used to reset the cool down of the skill.
*/
public void setLastUsedToNow() {
this.lastUsed = Instant.now();
activateCoolDown();
}
}

0 comments on commit adebc9f

Please sign in to comment.