1+ class Brain {
2+ constructor ( vision ) {
3+ this . state = "Wander" ;
4+ this . target = null ; //pos to chase
5+ this . targetEntity = null ;
6+ this . stateTimer = 0 ;
7+ this . obj = null ; //obj to move and stuff
8+ this . id = random ( 10000 ) ;
9+ this . vision = vision ;
10+ this . deleteTag = false ;
11+ }
12+
13+ update ( ) {
14+ if ( this . obj != null ) {
15+ this . stateTimer ++ ;
16+ if ( this . state == "Wander" ) {
17+ this . wander ( ) ;
18+ if ( this . findTarget ( ) ) {
19+ this . stateTimer = 0 ;
20+ this . state = "Chasing" ;
21+
22+ let chunkPos = testMap . globalToChunk ( this . obj . pos . x , this . obj . pos . y ) ;
23+ socket . emit ( "update_obj" , {
24+ cx : chunkPos . x , cy : chunkPos . y ,
25+ objName : this . obj . objName ,
26+ pos : { x : this . obj . pos . x , y : this . obj . pos . y } ,
27+ z : this . obj . z ,
28+ id : this . obj . id ,
29+ brainID : this . id ,
30+ update_name : "hp" ,
31+ update_value : this . obj . hp
32+ } ) ;
33+ }
34+ }
35+ if ( this . state == "Chasing" ) {
36+ this . chase ( ) ;
37+ if ( ! this . canSee ( this . targetEntity . pos . x , this . targetEntity . pos . y ) ) {
38+ this . stateTimer = 0 ;
39+ this . state = "Wander" ;
40+ this . target = null ;
41+ this . targetEntity = null ;
42+
43+ let chunkPos = testMap . globalToChunk ( this . obj . pos . x , this . obj . pos . y ) ;
44+ socket . emit ( "update_obj" , {
45+ cx : chunkPos . x , cy : chunkPos . y ,
46+ objName : this . obj . objName ,
47+ pos : { x : this . obj . pos . x , y : this . obj . pos . y } ,
48+ z : this . obj . z ,
49+ id : this . obj . id ,
50+ brainID : this . id ,
51+ update_name : "hp" ,
52+ update_value : this . obj . hp
53+ } ) ;
54+ }
55+ }
56+ if ( this . state == "Space" ) {
57+ this . space ( ) ;
58+ }
59+ }
60+ }
61+
62+ wander ( ) {
63+ //Move randomly
64+ if ( this . target == null || this . obj . pos . dist ( this . target ) < 6 ) {
65+ socket . emit ( "wander_request" , { id : this . id , pos : { x : this . obj . pos . x , y : this . obj . pos . y } } ) ;
66+ return ;
67+ }
68+ this . moveObjTowards ( this . target . x , this . target . y , 2 ) ;
69+ }
70+
71+ chase ( ) {
72+ //Move towards target
73+ if ( this . obj . pos . dist ( this . target ) > projDic [ this . obj . projName ] . sr ) {
74+ this . moveObjTowards ( this . target . x , this . target . y , 6 ) ;
75+ }
76+ else { //if close enough spawn melee projectile and switch to space
77+ let chunkPos = testMap . globalToChunk ( this . obj . pos . x , this . obj . pos . y ) ;
78+ let toTarget = createVector ( this . target . x , this . target . y ) . sub ( this . obj . pos ) . setMag ( 50 ) ;
79+ let proj = createProjectile ( this . obj . projName , this . obj . objName , this . obj . color , this . obj . pos . x , this . obj . pos . y , toTarget . heading ( ) ) ;
80+ if ( testMap . chunks [ chunkPos . x + ',' + chunkPos . y ] != undefined ) {
81+ testMap . chunks [ chunkPos . x + ',' + chunkPos . y ] . projectiles . push (
82+ proj
83+ ) ;
84+ //tell the server you made a projectile
85+ socket . emit ( "new_proj" , proj ) ;
86+
87+ let temp = new SoundObj ( "swing.wav" , this . obj . pos . x , this . obj . pos . y ) ;
88+ testMap . chunks [ chunkPos . x + ',' + chunkPos . y ] . soundObjs . push ( temp ) ;
89+ socket . emit ( "new_sound" , { sound : "swing.wav" , cPos : chunkPos , pos : { x : this . obj . pos . x , y : this . obj . pos . y } , id : temp . id } ) ;
90+ }
91+
92+ this . stateTimer = 0 ;
93+ this . state = "Space" ;
94+
95+ socket . emit ( "update_obj" , {
96+ cx : chunkPos . x , cy : chunkPos . y ,
97+ objName : this . obj . objName ,
98+ pos : { x : this . obj . pos . x , y : this . obj . pos . y } ,
99+ z : this . obj . z ,
100+ id : this . obj . id ,
101+ brainID : this . id ,
102+ update_name : "hp" ,
103+ update_value : this . obj . hp
104+ } ) ;
105+ }
106+ }
107+
108+ space ( ) {
109+ // back up away from target until stateTimer == 120
110+ if ( this . stateTimer < 120 ) {
111+ this . target = this . obj . pos . copy ( ) . sub ( this . targetEntity . pos ) . setMag ( 100 ) . add ( this . targetEntity . pos ) ;
112+ if ( this . obj . pos . dist ( this . target ) > 4 ) {
113+ this . moveObjTowards ( this . target . x , this . target . y , 4 ) ;
114+ }
115+ //If player gets too close, prolong retreat
116+ if ( this . obj . pos . dist ( this . targetEntity . pos ) < 60 ) {
117+ this . stateTimer = 0 ;
118+ }
119+ //If player gets too far, reduce retreat
120+ if ( this . obj . pos . dist ( this . targetEntity . pos ) > 100 ) {
121+ this . stateTimer += 5 ;
122+ }
123+ }
124+ else {
125+ this . target = this . targetEntity . pos ;
126+ this . stateTimer = 0 ;
127+ this . state = "Chasing" ;
128+
129+ let chunkPos = testMap . globalToChunk ( this . obj . pos . x , this . obj . pos . y ) ;
130+ socket . emit ( "update_obj" , {
131+ cx : chunkPos . x , cy : chunkPos . y ,
132+ objName : this . obj . objName ,
133+ pos : { x : this . obj . pos . x , y : this . obj . pos . y } ,
134+ z : this . obj . z ,
135+ id : this . obj . id ,
136+ brainID : this . id ,
137+ update_name : "hp" ,
138+ update_value : this . obj . hp
139+ } ) ;
140+ }
141+ }
142+
143+ findTarget ( ) {
144+ this . targetEntity = null ;
145+
146+ //sort players from closest to furthest
147+ let playerArray = Object . values ( players ) ;
148+ playerArray . push ( curPlayer ) ;
149+
150+ playerArray . sort ( ( a , b ) => {
151+ let distA = this . obj . pos . dist ( a . pos ) ;
152+ let distB = this . obj . pos . dist ( b . pos ) ;
153+ return distA - distB ;
154+ } ) ;
155+
156+ playerArray . filter ( player => {
157+ return this . obj . pos . dist ( player . pos ) < this . vision ;
158+ } ) ;
159+
160+ for ( let i = 0 ; i < playerArray . length ; i ++ ) {
161+ if ( this . canSee ( playerArray [ i ] . pos . x , playerArray [ i ] . pos . y ) ) {
162+ if ( this . targetEntity == null ) {
163+ this . targetEntity = playerArray [ i ] ;
164+ this . target = playerArray [ i ] . pos ;
165+ i = playerArray . length ;
166+ }
167+ }
168+ }
169+
170+ return this . targetEntity != null ;
171+ }
172+
173+ canSee ( x , y ) {
174+ //check if there are any objects imbetween this.obj and x,y
175+ return createVector ( x , y ) . dist ( this . obj . pos ) < this . vision ;
176+ }
177+
178+ moveObjTowards ( x , y , speed ) {
179+ //TODO: collishion
180+ let oldChunkPos = testMap . globalToChunk ( this . obj . pos . x , this . obj . pos . y ) ;
181+ this . obj . pos . add ( createVector ( x , y ) . sub ( this . obj . pos ) . setMag ( speed ) ) ;
182+
183+ socket . emit ( "update_obj" , {
184+ cx : oldChunkPos . x , cy : oldChunkPos . y ,
185+ objName : this . obj . objName ,
186+ pos : { x : this . obj . pos . x , y : this . obj . pos . y } ,
187+ z : this . obj . z ,
188+ id : this . obj . id ,
189+ brainID : this . id ,
190+ update_name : "hp" ,
191+ update_value : this . obj . hp
192+ } ) ;
193+
194+ let newChunkPos = testMap . globalToChunk ( this . obj . pos . x , this . obj . pos . y ) ;
195+ if ( oldChunkPos . x != newChunkPos . x || oldChunkPos . y != newChunkPos . y ) {
196+ this . obj . deleteTag = true ;
197+ socket . emit ( "delete_obj" , {
198+ cx : oldChunkPos . x ,
199+ cy : oldChunkPos . y ,
200+ objName : this . obj . objName ,
201+ pos : { x : this . obj . pos . x , y : this . obj . pos . y } ,
202+ z : this . obj . z ,
203+ cost : objDic [ this . obj . objName ] . cost
204+ } ) ;
205+
206+ let temp = createObject ( "Ant" , this . obj . pos . x , this . obj . pos . y , 0 , this . obj . color , this . obj . id , this . obj . ownerName ) ;
207+ temp . brainID = this . id ;
208+ testMap . chunks [ newChunkPos . x + "," + newChunkPos . y ] . objects . push ( temp ) ;
209+ socket . emit ( "new_object" , {
210+ cx : newChunkPos . x ,
211+ cy : newChunkPos . y ,
212+ obj : temp
213+ } )
214+ this . obj = temp ;
215+ }
216+ }
217+
218+ giveBody ( obj ) {
219+ this . obj = obj ;
220+ this . obj . brainID = this . id ;
221+ }
222+
223+ debugRender ( ) {
224+ if ( this . target == null ) return ;
225+ push ( ) ;
226+ fill ( 255 , 0 , 0 , 100 ) ;
227+ noStroke ( ) ;
228+ circle ( this . target . x - camera . pos . x + width / 2 , this . target . y - camera . pos . y + height / 2 , 6 ) ;
229+ pop ( ) ;
230+ }
231+ }
232+
233+ function scareBrain ( brainID , proj ) {
234+ if ( brainID == undefined ) return ;
235+ let scarer ;
236+
237+ for ( let i = 0 ; i < testMap . brains . length ; i ++ ) {
238+ if ( brainID == testMap . brains [ i ] . id ) {
239+ if ( proj . flightPath != undefined ) {
240+ //check if turret is at proj.flightPath.origin
241+ let chunkPos = testMap . globalToChunk ( proj . flightPath . origin . x , proj . flightPath . origin . y ) ;
242+ let chunk = testMap . chunks [ chunkPos . x + "," + chunkPos . y ] ;
243+ if ( chunk != undefined ) {
244+ for ( let j = 0 ; j < chunk . objects . length ; j ++ ) {
245+ if ( chunk . objects [ j ] . objName == "Turret" ) {
246+
247+ if ( chunk . objects [ j ] . pos . dist ( proj . flightPath . origin ) < 70 ) {
248+ scarer = chunk . objects [ j ] ;
249+ j = chunk . objects . length ;
250+ }
251+ }
252+ }
253+ }
254+
255+ //check if proj.ownerName is curPlayer.name
256+ if ( proj . ownerName == curPlayer . name ) {
257+ scarer = curPlayer ;
258+ }
259+ //check if proj.ownerName belongs to another player
260+ let keys = Object . keys ( players ) ;
261+ for ( let j = 0 ; j < keys . length ; j ++ ) {
262+ if ( proj . ownerName == players [ keys [ j ] ] . name ) {
263+ scarer = players [ keys [ j ] ] ;
264+ j = keys . length ;
265+ }
266+ }
267+
268+ }
269+
270+ if ( scarer != undefined ) {
271+ testMap . brains [ i ] . targetEntity = scarer ;
272+ testMap . brains [ i ] . state = "Space" ;
273+ testMap . brains [ i ] . stateTimer = 0 ;
274+ i = testMap . brains . length ;
275+ }
276+ }
277+ }
278+ }
0 commit comments