Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Health/damage system with unit tests #515

Merged
merged 11 commits into from
Jun 10, 2020
33 changes: 33 additions & 0 deletions engine/src/main/java/org/destinationsol/components/Health.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2020 The Terasology Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.destinationsol.components;

import org.terasology.gestalt.entitysystem.component.Component;

/**
* Contains information about the health of an entity.
*/
public final class Health implements Component<Health> {

public int maxHealth = 30;
public int currentHealth = 30;

@Override
public void copy(Health other) {
this.maxHealth = other.maxHealth;
this.currentHealth = other.currentHealth;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
public class EntitySystemManager {

private static EntityManager entityManager;
private static EventSystem eventSystem = new EventSystemImpl();
private EventSystem eventSystem = new EventSystemImpl();
private static EventReceiverMethodSupport eventReceiverMethodSupport = new EventReceiverMethodSupport();

public EntitySystemManager(ModuleEnvironment environment, ComponentManager componentManager){
public EntitySystemManager(ModuleEnvironment environment, ComponentManager componentManager) {

List<ComponentStore<?>> stores = Lists.newArrayList();
for (Class<? extends Component> componentType : environment.getSubtypesOf(Component.class)) {
Expand All @@ -51,9 +51,9 @@ public EntitySystemManager(ModuleEnvironment environment, ComponentManager compo

entityManager = new CoreEntityManager(stores);

for (Class<?> eventReceivers : environment.getTypesAnnotatedWith(RegisterEventReceivers.class)) {
for (Class<? extends EventReceiver> eventReceiver : environment.getSubtypesOf(EventReceiver.class)) {
try {
eventReceiverMethodSupport.register(eventReceivers.newInstance(), eventSystem);
eventReceiverMethodSupport.register(eventReceiver.newInstance(), eventSystem);
} catch (Exception e) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
*/
package org.destinationsol.entitysystem;

public @interface RegisterEventReceivers {
public interface EventReceiver {
}
34 changes: 34 additions & 0 deletions engine/src/main/java/org/destinationsol/events/DamageEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2020 The Terasology Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.destinationsol.events;

import org.terasology.gestalt.entitysystem.event.Event;

/**
* Event that contains information about the damage an entity receives.
*/
public class DamageEvent implements Event {

private int damage;

public DamageEvent(int damage) {
this.damage = damage;
}

public int getDamage() {
return damage;
}
}
56 changes: 56 additions & 0 deletions engine/src/main/java/org/destinationsol/systems/DamageSystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2020 The Terasology Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.destinationsol.systems;

import org.destinationsol.components.Health;
import org.destinationsol.entitysystem.ComponentSystem;
import org.destinationsol.entitysystem.EventReceiver;
import org.destinationsol.events.DamageEvent;
import org.terasology.gestalt.entitysystem.entity.EntityRef;
import org.terasology.gestalt.entitysystem.event.EventResult;
import org.terasology.gestalt.entitysystem.event.ReceiveEvent;

/**
* When a damage event happens to an entity with a health component, this system reads the damage from that event and
* lowers its health by that amount. If it would lower the health to less than zero, it's reduced to zero instead. If
* the damage is a negative amount, nothing happens.
*/
public class DamageSystem implements EventReceiver {

/**
* Handles a damage event done to an entity with a Health component.
*
* @param event the damage event that is occurring
* @param entity the entity that the damage is happening to
* @return the event should be processed by other systems, if there are
*/
@ReceiveEvent(components = Health.class)
public EventResult onDamage(DamageEvent event, EntityRef entity) {
if (event.getDamage() <= 0) {
return EventResult.CONTINUE;
}
if (entity.getComponent(Health.class).isPresent()) {
Health health = entity.getComponent(Health.class).get();
int newHealthAmount = health.currentHealth - event.getDamage();
if (newHealthAmount < 0) {
newHealthAmount = 0;
}
health.currentHealth = newHealthAmount;
entity.setComponent(health);
}
return EventResult.CONTINUE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2020 The Terasology Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.destinationsol.systems.DamageSystemTests;

import org.destinationsol.components.Health;
import org.destinationsol.entitysystem.EntitySystemManager;
import org.destinationsol.events.DamageEvent;
import org.destinationsol.modules.ModuleManager;
import org.junit.Before;
import org.junit.Test;
import org.terasology.gestalt.entitysystem.component.management.ComponentManager;
import org.terasology.gestalt.entitysystem.entity.EntityRef;

import static org.junit.Assert.assertEquals;

/**
* Test to ensure that a damage event with a negative amount of damage doesn't add health.
*/
public class NonNegativeDamageTest {

private ModuleManager moduleManager;
private EntitySystemManager entitySystemManager;

@Before
public void setUp() throws Exception {
moduleManager = new ModuleManager();
moduleManager.init();
entitySystemManager = new EntitySystemManager(moduleManager.getEnvironment(), new ComponentManager());
}

@Test
public void testNegativeDamageHasNoEffect() {
EntityRef entity = entitySystemManager.getEntityManager().createEntity(new Health());
if (entity.getComponent(Health.class).isPresent()) {
Health health = entity.getComponent(Health.class).get();
health.maxHealth = 50;
health.currentHealth = 50;
entity.setComponent(health);
}
DamageEvent event = new DamageEvent(-30);

entitySystemManager.sendEvent(event, new Health());

assertEquals(50, entity.getComponent(Health.class).get().currentHealth);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2020 The Terasology Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.destinationsol.systems.DamageSystemTests;

import org.destinationsol.components.Health;
import org.destinationsol.entitysystem.EntitySystemManager;
import org.destinationsol.events.DamageEvent;
import org.destinationsol.modules.ModuleManager;
import org.junit.Before;
import org.junit.Test;
import org.terasology.gestalt.entitysystem.component.management.ComponentManager;
import org.terasology.gestalt.entitysystem.entity.EntityRef;

import static org.junit.Assert.assertEquals;

/**
* Test to ensure that a damage event that would make the health become negative reduces it to zero instead.
*/
public class NonNegativeHealthTest {
private ModuleManager moduleManager;
private EntitySystemManager entitySystemManager;

@Before
public void setUp() throws Exception {
moduleManager = new ModuleManager();
moduleManager.init();
entitySystemManager = new EntitySystemManager(moduleManager.getEnvironment(), new ComponentManager());
}

@Test
public void testDamageDoesntMakeHealthBecomeNegative() {
EntityRef entity = entitySystemManager.getEntityManager().createEntity(new Health());
if (entity.getComponent(Health.class).isPresent()) {
Health health = entity.getComponent(Health.class).get();
health.maxHealth = 50;
health.currentHealth = 50;
entity.setComponent(health);
}
DamageEvent event = new DamageEvent(60);

entitySystemManager.sendEvent(event, new Health());

assertEquals(0, entity.getComponent(Health.class).get().currentHealth);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2020 The Terasology Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.destinationsol.systems.DamageSystemTests;

import org.destinationsol.components.Health;
import org.destinationsol.entitysystem.EntitySystemManager;
import org.destinationsol.events.DamageEvent;
import org.destinationsol.modules.ModuleManager;
import org.junit.Before;
import org.junit.Test;
import org.terasology.gestalt.entitysystem.component.management.ComponentManager;
import org.terasology.gestalt.entitysystem.entity.EntityRef;

import static org.junit.Assert.assertEquals;

/**
* Test to ensure that a damage event to an entity lowers that entity's health by that amount.
*/
public class OnDamageTest {

private ModuleManager moduleManager;
private EntitySystemManager entitySystemManager;

@Before
public void setUp() throws Exception {
moduleManager = new ModuleManager();
moduleManager.init();
entitySystemManager = new EntitySystemManager(moduleManager.getEnvironment(), new ComponentManager());
}

@Test
public void testOnDamage() {
EntityRef entity = entitySystemManager.getEntityManager().createEntity(new Health());
if (entity.getComponent(Health.class).isPresent()) {
Health health = entity.getComponent(Health.class).get();
health.maxHealth = 50;
health.currentHealth = 50;
entity.setComponent(health);
}
DamageEvent event = new DamageEvent(30);

entitySystemManager.sendEvent(event, new Health());

assertEquals(20, entity.getComponent(Health.class).get().currentHealth);
}

}