enemy_system.cpp 7 KB
Newer Older
1
2
#include "enemy_system.hpp"

3
#include "beat_system.hpp"
4
5
#include "combat_system.hpp"

6
#include "movement_comp.hpp"
7
8
#include "rigid_body_comp.hpp"
#include "player_comp.hpp"
9

10
#include <mirrage/ecs/components/transform_comp.hpp>
11
12
13

namespace phase_shifter::gameplay {
	
14
15
	using namespace mirrage::ecs;

16
17
18
19
	Enemy_system::Enemy_system(mirrage::util::Message_bus& bus,
	                           Entity_manager&             entity_manager,
	                           const Beat_system&          beat_system)
	  : _bus(bus), _entity_manager(entity_manager), _beat_system(beat_system)
20
21
	{
		_entity_manager.register_component_type<Fixed_path_comp>();
22
		_entity_manager.register_component_type<Follow_target_comp>();
23
		_entity_manager.register_component_type<Continuous_path_comp>();
24
		_entity_manager.register_component_type<Shooting_comp>();
25
		_entity_manager.register_component_type<Target_comp>();
26
		_entity_manager.register_component_type<Bullet_comp>();
27
28
29
30
	}

	void Enemy_system::update(mirrage::util::Time dt)
	{
31
32
		auto beat = _beat_system.beat_state();

33
34
35
36
37
38
39
40
41
42
43
44
45
		do_movement(beat);
		do_shooting(beat);
		do_bullet_hit_detection();
	}

	void Enemy_system::do_movement(Beat_state& beat) { 
		do_fixed_path_movement(beat);
		do_cont_path_movement(beat);
		do_hunting_movement(beat);
	}

	void Enemy_system::do_fixed_path_movement(Beat_state& beat) {
		for(auto&& [movement, fixed_path] : _entity_manager.list<Movement_comp, Fixed_path_comp>()) {
46
47
48
49
50
			if(beat.beat) {
				if(fixed_path.wait_beats == 0 && !movement.move) {
					float direction = fixed_path.next_direction();
					if(direction < 360) {
						float rad_direction = direction * mirrage::util::PI / 180.f;
51
52
53
						movement.aim.x      = std::sin(rad_direction);
						movement.aim.y      = -std::cos(rad_direction);
						movement.move       = true;
54
55
56
57
					}
					fixed_path.wait_beats = fixed_path.pause_between_steps;
				} else {
					fixed_path.wait_beats--;
58
59
60
				}
			}
		}
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
	}

	void Enemy_system::do_cont_path_movement(Beat_state& beat) {
		for(auto&& [movement, cont_path] : _entity_manager.list<Movement_comp, Continuous_path_comp>()) {
			if(beat.beat) {
				if(cont_path.wait_beats == 0 && !movement.move) {
					float rad_direction  = cont_path.next_direction() * mirrage::util::PI / 180.f;
					movement.aim.x       = std::sin(rad_direction);
					movement.aim.y       = -std::cos(rad_direction);
					movement.move        = true;
					cont_path.wait_beats = cont_path.pause_between_steps;
				} else {
					cont_path.wait_beats--;
				}
			}
		}
	}

	void Enemy_system::do_hunting_movement(Beat_state& beat) {
		for(auto&& [movement, follow_target, transform] :
		    _entity_manager.list<Movement_comp, Follow_target_comp, components::Transform_comp>()) {
82
83
84
			if(beat.beat) {
				if(follow_target.wait_beats == 0 && !movement.move) {
					auto target_facet = _entity_manager.get(follow_target.target);
85

86
					if(target_facet.is_some()) {
87
						auto target_transform = target_facet.get_or_throw().get<components::Transform_comp>();
88

89
90
91
92
93
94
95
96
97
98
99
						if(target_transform.is_some()) {
							auto& target_position = target_transform.get_or_throw().position;
							auto& my_position     = transform.position;
							movement.aim          = glm::vec2(
                                    {target_position.x - my_position.x, target_position.z - my_position.z});
							movement.move = true;
						}
					}
					follow_target.wait_beats = follow_target.pause_between_steps;
				} else {
					follow_target.wait_beats--;
100
101
102
				}
			}
		}
103
	}
104

105
106
107
108
	void Enemy_system::do_shooting(Beat_state& beat) {
		for(auto&& [shooting, transform] :
		    _entity_manager.list<Shooting_comp, components::Transform_comp>()) {
			auto      my_position = transform.position;
109
110
111
112
113
114
			glm::vec3 closest_target_pos;
			float     closest_dist = 999999999.f;

			for(auto&& [target, target_comp, target_transform] :
			    _entity_manager.list<Entity_facet, Target_comp, components::Transform_comp>()) {

115
116
				auto target_position = target_transform.position;
				auto dist            = glm::length(glm::vec2(target_position.x, target_position.z)
117
118
                                        - glm::vec2(my_position.x, my_position.z));
				if(dist < closest_dist) {
119
					closest_dist       = dist;
120
					closest_target_pos = target_position;
Tim Scheiber's avatar
Tim Scheiber committed
121
122
123
				}
			}

124
			glm::vec2 t_direction(closest_target_pos.x - my_position.x, closest_target_pos.z - my_position.z);
125
126
127
			shooting.target_direction =
			        std::acos(-t_direction.y / glm::length(t_direction)) * 180.f / mirrage::util::PI;
			if(t_direction.x < 0) {
128
129
130
				shooting.target_direction *= -1;
			}

131
			if(closest_dist <= shooting.attack_radius) {
132
133
134
135
136
137
138
139
140
141
142
				shooting.idle = false;
			} else {
				shooting.idle = true;
			}

			auto orientation = shooting.target_direction;
			if(shooting.idle) {
				orientation = shooting.default_orientation + shooting.rotation;
			}
			auto rad_orientation = orientation * mirrage::util::PI / 180.f;

143
			if(beat.beat) {
144
145
146
				if(shooting.idle && shooting.rotate) {
					shooting.do_rotation();
					shooting.rotate = false;
Tim Scheiber's avatar
Tim Scheiber committed
147
				}
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
				if(shooting.wait_beats == 0) {
					auto bullet_pattern = shooting.next_pattern();
					auto spawn_position =
					        transform.position
					        + shooting.spawn_offset
					                  * glm::vec3(std::sin(rad_orientation), 0, -std::cos(rad_orientation));

					for(auto bullet : bullet_pattern.bullets) {
						auto bullet_direction     = orientation + bullet.direction;
						auto rad_bullet_direction = bullet_direction * mirrage::util::PI / 180.f;
						_entity_manager.entity_builder("bullet")
						        .position(spawn_position)
						        .rotation(glm::rotation({0, 0, 1},
						                                glm::vec3(std::sin(rad_bullet_direction),
						                                          0,
						                                          -std::cos(rad_bullet_direction))))
						        .post_create([=](auto entity) {
							        entity.process([=](Continuous_path_comp& cont_path) {
								        cont_path.direction = bullet_direction;
								        cont_path.curvature = bullet.curvature;
							        });
						        })
						        .create();
					}

					shooting.wait_beats = shooting.pause_between_shots;
174
					shooting.rotate     = true;
175
176
				} else {
					shooting.wait_beats--;
177
178
				}
			}
179
180
181

			transform.orientation = glm::rotation(
			        {0, 0, 1}, glm::vec3(std::sin(rad_orientation), 0, -std::cos(rad_orientation)));
182
		}
183
	}
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

	void Enemy_system::do_bullet_hit_detection()
	{
		for(auto&& [bullet_handle, bullet, bullet_transform, bullet_body] :
		    _entity_manager.list<Entity_handle, Bullet_comp, components::Transform_comp, Rigid_body_comp>()) {
			for(auto&& [player_handle, player, player_transform, player_body] :
			    _entity_manager.list<Entity_handle, Player_comp, components::Transform_comp, Rigid_body_comp>()) {
				glm::vec2 bullet_pos{bullet_transform.position.x, bullet_transform.position.z};
				glm::vec2 player_pos{player_transform.position.x, player_transform.position.z};
				if (glm::length(player_pos - bullet_pos) < bullet_body.radius + player_body.radius) {
					_entity_manager.erase(bullet_handle);
					_bus.send<Damaged_msg>(player_handle);
				}
			}
		}
	}
200
}