-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathai.cpp
More file actions
257 lines (243 loc) · 9.01 KB
/
ai.cpp
File metadata and controls
257 lines (243 loc) · 9.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#include "ai.h"
#include "lighting.h"
#include "main.h"
#include "server.h"
#include <cmath>
#include <sstream>
Node::Node(sf::FloatRect nodeBox){
this->nodeBox = nodeBox;
int x = this->nodeBox.left+(this->nodeBox.width/2);
int y = this->nodeBox.top+(this->nodeBox.height/2);
this->middle = sf::Vector2f(x,y);
int debug = 0;
}
void Node::findNeighbors(threadArgs args){
Node *thisNode = args.thisNode;
vector<sf::FloatRect> targetColBoxes = args.collisionBoxes;
for(int i=0;i<aim.nodeList.size();i++){
float angle = atan2(aim.nodeList[i].middle.y-thisNode->middle.y,aim.nodeList[i].middle.x-thisNode->middle.x)*180/PI;
//cout << "angle: " << angle << endl;
bool hit = false;
bool hitNode = false;
for(int j=16;;j+=8){
//cout << "radius: " << j << endl;
for(int k=0;k<targetColBoxes.size();k++){ //Loop through all the collision objects
//and check if they're in the path of the ray
if(targetColBoxes[k].contains(LightManager::getCirclePoint(j,angle,thisNode->middle))){
hit = true;
break;
}
}
if(hit){ //If there was an object blocking the "ray"
//cout << "hitbreak" << endl;
break;
}
//Confirm that the node was actually reached
for(int k=0;k<aim.nodeList.size();k++){
if(&aim.nodeList[k] == thisNode)
continue;
if(aim.nodeList[k].nodeBox.contains(LightManager::getCirclePoint(j,angle,thisNode->middle))){
/*sf::Vector2f middle2(aim.nodeList[i].nodeBox.left+(aim.nodeList[i].nodeBox.width/2),
aim.nodeList[i].nodeBox.top+(aim.nodeList[i].nodeBox.height/2));
cout << "pushing back node " << middle2.x << "," << middle2.y << "-" << thisNode->middle.x << "," << thisNode->middle.y << endl;*/
thisNode->neighbors.push_back(&aim.nodeList[k]);
hitNode = true;
break;
}
}
if(hitNode)
break;
}
}
}
AIManager::AIManager(){ //This constructor does nothing. It's just here so that the object can be declared in a wide scope
//as it can't be initialized until other stuff is initialized first.
}
void AIManager::init(ShipEntity *ship){ //This actually initializes the AI Manager
//Thread objects
sf::Thread *thread1;
sf::Thread *thread2;
sf::Thread *thread3;
sf::Thread *thread4;
nodeList.clear();
int **level = ship->map->data;
//Get all the nodes, put them in a vector
for(int y=0;y<dunYSize;y++){
for(int x=0;x<dunXSize;x++){
if(level[x][y] == NODE){
cout << "pushing back to nodeList " << x << "," << y << endl;
this->nodeList.push_back(Node(sf::FloatRect(x*32,y*32,32,32)));
}
}
}
bool first = true;
for(int i=0;i<this->nodeList.size();i){
//We need a struct to contain arguments, as SFML threading only allows you to give one argument to the function
Node::threadArgs thread1Args;
thread1Args.collisionBoxes = ship->collisionBoxes;
//Initialize other thread argument objects with the same data
Node::threadArgs thread2Args = thread1Args;
Node::threadArgs thread3Args = thread1Args;
Node::threadArgs thread4Args = thread1Args;
if(first){ //Start the threads for the first time, only do this once as afterwards,
//threads will be restarted when they're finished.
thread1Args.thisNode = &this->nodeList[i];
thread1 = new sf::Thread(&Node::findNeighbors,thread1Args);
cout << "finding neighbors1 " << i+1 << "/" << nodeList.size() << endl;
thread1->launch();
//i++ increments the node ID, so every thread works on a different node.
//The thread's argument obejct is modified with the new node each time.
i++;
if(i<this->nodeList.size()){
thread2Args.thisNode = &this->nodeList[i];
thread2Args.collisionBoxes = ship->collisionBoxes;
thread2 = new sf::Thread(&Node::findNeighbors,thread2Args);
cout << "finding neighbors2 " << i+1 << "/" << nodeList.size() << endl;
thread2->launch();
}
i++;
if(i<this->nodeList.size()){
thread3Args.thisNode = &this->nodeList[i];
thread3Args.collisionBoxes = ship->collisionBoxes;
thread3 = new sf::Thread(&Node::findNeighbors,thread3Args);
cout << "finding neighbors3 " << i+1 << "/" << nodeList.size() << endl;
thread3->launch();
}
i++;
if(i<this->nodeList.size()){
thread4Args.thisNode = &this->nodeList[i];
thread4Args.collisionBoxes = ship->collisionBoxes;
thread4 = new sf::Thread(&Node::findNeighbors,thread4Args);
cout << "finding neighbors4 " << i+1 << "/" << nodeList.size() << endl;
thread4->launch();
}
}
first = false;
thread1->wait(); //Wait for thread to end
i++; //Increment node number, and then start it again with that node number
//Same goes for all other threads, which is why the code below is repetitive
if(i<this->nodeList.size()){
thread1Args.thisNode = &this->nodeList[i];
thread1Args.collisionBoxes = ship->collisionBoxes;
//cout << "Thread 1 finished; starting again." << endl;
cout << "finding neighbors1 " << i+1 << "/" << nodeList.size() << endl;
delete thread1; //Delete it, because it's using an old argument object
thread1 = new sf::Thread(&Node::findNeighbors,thread1Args); //Recreate it with new arguments
thread1->launch();
}
thread2->wait();
i++;
if(i<this->nodeList.size()){
thread2Args.thisNode = &this->nodeList[i];
thread2Args.collisionBoxes = ship->collisionBoxes;
//cout << "Thread 2 finished; starting again." << endl;
cout << "finding neighbors2 " << i+1 << "/" << nodeList.size() << endl;
delete thread2;
thread2 = new sf::Thread(&Node::findNeighbors,thread2Args);
thread2->launch();
}
thread3->wait();
i++;
if(i<this->nodeList.size()){
thread3Args.thisNode = &this->nodeList[i];
thread3Args.collisionBoxes = ship->collisionBoxes;
//cout << "Thread 3 finished; starting again." << endl;
cout << "finding neighbors3 " << i+1 << "/" << nodeList.size() << endl;
delete thread3;
thread3 = new sf::Thread(&Node::findNeighbors,thread3Args);
thread3->launch();
}
thread4->wait();
i++;
if(i<this->nodeList.size()){
thread4Args.thisNode = &this->nodeList[i];
thread4Args.collisionBoxes = ship->collisionBoxes;
//cout << "Thread 4 finished; starting again." << endl;
cout << "finding neighbors4 " << i+1 << "/" << nodeList.size() << endl;
delete thread4;
thread4 = new sf::Thread(&Node::findNeighbors,thread4Args);
thread4->launch();
}
}
}
/**
Draws the node net; useful for debugging.
*/
void AIManager::drawNet(sf::RenderWindow *screen, int screenx, int screeny){
sf::Vector2f p1;
sf::Vector2f p2;
for(int i=0;i<this->nodeList.size();i++){
p1 = this->nodeList[i].middle;
p1.x -= screenx;
p1.y -= screeny;
for(int j=0;j<this->nodeList[i].neighbors.size();j++){
p2 = this->nodeList[i].neighbors[j]->middle;
p2.x -= screenx;
p2.y -= screeny;
sf::Vertex line[] = {p1,p2};
line[0].color = sf::Color::Green;
line[1].color = sf::Color::Green;
screen->draw(line,2,sf::Lines);
}
}
}
Node *AIManager::findVisibleNode(sf::Vector2f relPoint, vector<sf::FloatRect> targetColBoxes){
Node *closestVisible;
bool foundOne = false;
for(int i=0,j=0,min=9999;i<aim.nodeList.size();i++){
if(isVisible(relPoint,aim.nodeList[i].nodeBox,targetColBoxes)){
j++;
float xdiff = abs(relPoint.x-aim.nodeList[i].middle.x);
float ydiff = abs(relPoint.y-aim.nodeList[i].middle.y);
float distance = sqrt(pow(xdiff,2.0f)+pow(ydiff,2.0f));
if(distance < min){
min = distance;
closestVisible = &aim.nodeList[i];
foundOne = true;
}
if(j>5)
break;
}
}
if(foundOne)
return closestVisible;
return &aim.nodeList[0];
}
void AIManager::spawnMonsters(vector<Entity*> *entityList, int numMonsters){
stringstream ss;
for(int i=0;i<numMonsters;i++){
sf::Vector2f floorTile = serverShip->getRandomFloorTile();
Monster *newMonster = new Monster();
newMonster->type = "monster";
newMonster->x = floorTile.x*32.0f;
newMonster->y = floorTile.y*32.0f;
/*ss.str("");
ss.clear();
ss << newMonster->ID << " " << newMonster->type << " " << newMonster->x << " " << newMonster->y << " " << newMonster->rot;
ENetPacket *spawnPacket = createPacket(scSpawn,ss.str(),ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(p1->peer,0,spawnPacket);
if(p2->connected)
enet_peer_send(p2->peer,0,spawnPacket);*/
newMonster->buildPath();
newMonster->pathTimer.restart();
entityList->push_back(newMonster);
}
}
bool AIManager::isVisible(sf::Vector2f startPoint, sf::FloatRect targetBox, vector<sf::FloatRect> targetColBoxes){
sf::Vector2f targetMiddle = sf::Vector2f(targetBox.left+targetBox.width/2,targetBox.top+targetBox.height/2);
float angle = atan2(targetMiddle.y-startPoint.y,targetMiddle.x-startPoint.x)*180/PI;
//cout << "angle: " << angle << endl;
for(int i=0;;i+=8){
//cout << "radius: " << j << endl;
if(targetBox.contains(LightManager::getCirclePoint(i,angle,startPoint))){
return true;
}
for(int j=0;j<targetColBoxes.size();j++){ //Loop through all the collision objects
//and check if they're in the path of the ray
if(targetColBoxes[j].contains(LightManager::getCirclePoint(i,angle,startPoint))){
return false;
}
}
}
cout << "returning something fucking stupid that I should jump off a cliff into lava for" << endl;
}