Skip to content

Commit a87a61a

Browse files
authored
Merge pull request #515 from IsaacLic/ecsImplementation
Health/damage system with unit tests
2 parents 5dd6d8a + 35de062 commit a87a61a

File tree

8 files changed

+306
-5
lines changed

8 files changed

+306
-5
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2020 The Terasology Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.destinationsol.components;
17+
18+
import org.terasology.gestalt.entitysystem.component.Component;
19+
20+
/**
21+
* Contains information about the health of an entity.
22+
*/
23+
public final class Health implements Component<Health> {
24+
25+
public int maxHealth = 30;
26+
public int currentHealth = 30;
27+
28+
@Override
29+
public void copy(Health other) {
30+
this.maxHealth = other.maxHealth;
31+
this.currentHealth = other.currentHealth;
32+
}
33+
}

engine/src/main/java/org/destinationsol/entitysystem/EntitySystemManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
public class EntitySystemManager {
3737

3838
private static EntityManager entityManager;
39-
private static EventSystem eventSystem = new EventSystemImpl();
39+
private EventSystem eventSystem = new EventSystemImpl();
4040
private static EventReceiverMethodSupport eventReceiverMethodSupport = new EventReceiverMethodSupport();
4141

42-
public EntitySystemManager(ModuleEnvironment environment, ComponentManager componentManager){
42+
public EntitySystemManager(ModuleEnvironment environment, ComponentManager componentManager) {
4343

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

5252
entityManager = new CoreEntityManager(stores);
5353

54-
for (Class<?> eventReceivers : environment.getTypesAnnotatedWith(RegisterEventReceivers.class)) {
54+
for (Class<? extends EventReceiver> eventReceiver : environment.getSubtypesOf(EventReceiver.class)) {
5555
try {
56-
eventReceiverMethodSupport.register(eventReceivers.newInstance(), eventSystem);
56+
eventReceiverMethodSupport.register(eventReceiver.newInstance(), eventSystem);
5757
} catch (Exception e) {
5858
e.printStackTrace();
5959
}

engine/src/main/java/org/destinationsol/entitysystem/RegisterEventReceivers.java renamed to engine/src/main/java/org/destinationsol/entitysystem/EventReceiver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
*/
1616
package org.destinationsol.entitysystem;
1717

18-
public @interface RegisterEventReceivers {
18+
public interface EventReceiver {
1919
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2020 The Terasology Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.destinationsol.events;
17+
18+
import org.terasology.gestalt.entitysystem.event.Event;
19+
20+
/**
21+
* Event that contains information about the damage an entity receives.
22+
*/
23+
public class DamageEvent implements Event {
24+
25+
private int damage;
26+
27+
public DamageEvent(int damage) {
28+
this.damage = damage;
29+
}
30+
31+
public int getDamage() {
32+
return damage;
33+
}
34+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2020 The Terasology Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.destinationsol.systems;
17+
18+
import org.destinationsol.components.Health;
19+
import org.destinationsol.entitysystem.ComponentSystem;
20+
import org.destinationsol.entitysystem.EventReceiver;
21+
import org.destinationsol.events.DamageEvent;
22+
import org.terasology.gestalt.entitysystem.entity.EntityRef;
23+
import org.terasology.gestalt.entitysystem.event.EventResult;
24+
import org.terasology.gestalt.entitysystem.event.ReceiveEvent;
25+
26+
/**
27+
* When a damage event happens to an entity with a health component, this system reads the damage from that event and
28+
* lowers its health by that amount. If it would lower the health to less than zero, it's reduced to zero instead. If
29+
* the damage is a negative amount, nothing happens.
30+
*/
31+
public class DamageSystem implements EventReceiver {
32+
33+
/**
34+
* Handles a damage event done to an entity with a Health component.
35+
*
36+
* @param event the damage event that is occurring
37+
* @param entity the entity that the damage is happening to
38+
* @return the event should be processed by other systems, if there are
39+
*/
40+
@ReceiveEvent(components = Health.class)
41+
public EventResult onDamage(DamageEvent event, EntityRef entity) {
42+
if (event.getDamage() <= 0) {
43+
return EventResult.CONTINUE;
44+
}
45+
if (entity.getComponent(Health.class).isPresent()) {
46+
Health health = entity.getComponent(Health.class).get();
47+
int newHealthAmount = health.currentHealth - event.getDamage();
48+
if (newHealthAmount < 0) {
49+
newHealthAmount = 0;
50+
}
51+
health.currentHealth = newHealthAmount;
52+
entity.setComponent(health);
53+
}
54+
return EventResult.CONTINUE;
55+
}
56+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2020 The Terasology Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.destinationsol.systems.DamageSystemTests;
17+
18+
import org.destinationsol.components.Health;
19+
import org.destinationsol.entitysystem.EntitySystemManager;
20+
import org.destinationsol.events.DamageEvent;
21+
import org.destinationsol.modules.ModuleManager;
22+
import org.junit.Before;
23+
import org.junit.Test;
24+
import org.terasology.gestalt.entitysystem.component.management.ComponentManager;
25+
import org.terasology.gestalt.entitysystem.entity.EntityRef;
26+
27+
import static org.junit.Assert.assertEquals;
28+
29+
/**
30+
* Test to ensure that a damage event with a negative amount of damage doesn't add health.
31+
*/
32+
public class NonNegativeDamageTest {
33+
34+
private ModuleManager moduleManager;
35+
private EntitySystemManager entitySystemManager;
36+
37+
@Before
38+
public void setUp() throws Exception {
39+
moduleManager = new ModuleManager();
40+
moduleManager.init();
41+
entitySystemManager = new EntitySystemManager(moduleManager.getEnvironment(), new ComponentManager());
42+
}
43+
44+
@Test
45+
public void testNegativeDamageHasNoEffect() {
46+
EntityRef entity = entitySystemManager.getEntityManager().createEntity(new Health());
47+
if (entity.getComponent(Health.class).isPresent()) {
48+
Health health = entity.getComponent(Health.class).get();
49+
health.maxHealth = 50;
50+
health.currentHealth = 50;
51+
entity.setComponent(health);
52+
}
53+
DamageEvent event = new DamageEvent(-30);
54+
55+
entitySystemManager.sendEvent(event, new Health());
56+
57+
assertEquals(50, entity.getComponent(Health.class).get().currentHealth);
58+
}
59+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2020 The Terasology Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.destinationsol.systems.DamageSystemTests;
17+
18+
import org.destinationsol.components.Health;
19+
import org.destinationsol.entitysystem.EntitySystemManager;
20+
import org.destinationsol.events.DamageEvent;
21+
import org.destinationsol.modules.ModuleManager;
22+
import org.junit.Before;
23+
import org.junit.Test;
24+
import org.terasology.gestalt.entitysystem.component.management.ComponentManager;
25+
import org.terasology.gestalt.entitysystem.entity.EntityRef;
26+
27+
import static org.junit.Assert.assertEquals;
28+
29+
/**
30+
* Test to ensure that a damage event that would make the health become negative reduces it to zero instead.
31+
*/
32+
public class NonNegativeHealthTest {
33+
private ModuleManager moduleManager;
34+
private EntitySystemManager entitySystemManager;
35+
36+
@Before
37+
public void setUp() throws Exception {
38+
moduleManager = new ModuleManager();
39+
moduleManager.init();
40+
entitySystemManager = new EntitySystemManager(moduleManager.getEnvironment(), new ComponentManager());
41+
}
42+
43+
@Test
44+
public void testDamageDoesntMakeHealthBecomeNegative() {
45+
EntityRef entity = entitySystemManager.getEntityManager().createEntity(new Health());
46+
if (entity.getComponent(Health.class).isPresent()) {
47+
Health health = entity.getComponent(Health.class).get();
48+
health.maxHealth = 50;
49+
health.currentHealth = 50;
50+
entity.setComponent(health);
51+
}
52+
DamageEvent event = new DamageEvent(60);
53+
54+
entitySystemManager.sendEvent(event, new Health());
55+
56+
assertEquals(0, entity.getComponent(Health.class).get().currentHealth);
57+
}
58+
59+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2020 The Terasology Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.destinationsol.systems.DamageSystemTests;
17+
18+
import org.destinationsol.components.Health;
19+
import org.destinationsol.entitysystem.EntitySystemManager;
20+
import org.destinationsol.events.DamageEvent;
21+
import org.destinationsol.modules.ModuleManager;
22+
import org.junit.Before;
23+
import org.junit.Test;
24+
import org.terasology.gestalt.entitysystem.component.management.ComponentManager;
25+
import org.terasology.gestalt.entitysystem.entity.EntityRef;
26+
27+
import static org.junit.Assert.assertEquals;
28+
29+
/**
30+
* Test to ensure that a damage event to an entity lowers that entity's health by that amount.
31+
*/
32+
public class OnDamageTest {
33+
34+
private ModuleManager moduleManager;
35+
private EntitySystemManager entitySystemManager;
36+
37+
@Before
38+
public void setUp() throws Exception {
39+
moduleManager = new ModuleManager();
40+
moduleManager.init();
41+
entitySystemManager = new EntitySystemManager(moduleManager.getEnvironment(), new ComponentManager());
42+
}
43+
44+
@Test
45+
public void testOnDamage() {
46+
EntityRef entity = entitySystemManager.getEntityManager().createEntity(new Health());
47+
if (entity.getComponent(Health.class).isPresent()) {
48+
Health health = entity.getComponent(Health.class).get();
49+
health.maxHealth = 50;
50+
health.currentHealth = 50;
51+
entity.setComponent(health);
52+
}
53+
DamageEvent event = new DamageEvent(30);
54+
55+
entitySystemManager.sendEvent(event, new Health());
56+
57+
assertEquals(20, entity.getComponent(Health.class).get().currentHealth);
58+
}
59+
60+
}

0 commit comments

Comments
 (0)