Guest User

Untitled

a guest
Jan 4th, 2018
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.30 KB | None | 0 0
  1. diff --git a/src/comm/comm.go b/src/comm/comm.go
  2. index fe0f492..6d374f9 100644
  3. --- a/src/comm/comm.go
  4. +++ b/src/comm/comm.go
  5. @@ -55,7 +55,7 @@ func (cs *CommService) Run(input chan core.Msg) {
  6. shutdown := make(chan bool)
  7. go listen(cs.svc, input, "tcp", cs.address, shutdown)
  8.  
  9. - cs.svc.Game <- core.MsgTick{input} // Service is ready
  10. + cs.svc.Game <- core.MsgTick{Origin: input} // Service is ready
  11.  
  12. for {
  13. msg := <-input
  14. diff --git a/src/core/component.go b/src/core/component.go
  15. index b38aaa9..47d03fc 100644
  16. --- a/src/core/component.go
  17. +++ b/src/core/component.go
  18. @@ -34,7 +34,7 @@ type Action interface {
  19. // Returns a unique and semi-descriptive name for each Action (defined by
  20. // the Action)
  21. Name() string
  22. - Act(ent Entity, svc ServiceContext)
  23. + Act(ent Entity, svc ServiceContext, dt float64)
  24. }
  25.  
  26. // An Entity is a struct composed from various States and Actions, which each
  27. @@ -130,11 +130,11 @@ func (cd *CmpData) Run(svc ServiceContext) {
  28. // Check at the start of the tick because Game actually removes at
  29. // the end of the previous tick
  30. if _, ok := cd.states[cmpId.Remove]; ok {
  31. - m.Origin <- MsgTick{cd.input}
  32. + m.Origin <- MsgTick{Origin: cd.input}
  33. return // Entity was removed, bail
  34. }
  35. - cd.update(svc)
  36. - m.Origin <- MsgTick{cd.input} // Reply that we are updated
  37. + cd.update(svc, m.Duration)
  38. + m.Origin <- MsgTick{Origin: cd.input} // Reply that we are updated
  39. case MsgGetState:
  40. cd.sendState(m)
  41. case MsgGetAllStates:
  42. @@ -144,7 +144,7 @@ func (cd *CmpData) Run(svc ServiceContext) {
  43. case MsgAddAction:
  44. cd.AddAction(m.Action)
  45. case MsgRunAction:
  46. - m.Action.Act(cd, svc)
  47. + m.Action.Act(cd, svc, 0.)
  48. if m.Add {
  49. cd.AddAction(m.Action)
  50. }
  51. @@ -153,9 +153,9 @@ func (cd *CmpData) Run(svc ServiceContext) {
  52. }
  53.  
  54. // Loop through each Action and let it run
  55. -func (cd *CmpData) update(svc ServiceContext) {
  56. +func (cd *CmpData) update(svc ServiceContext, dt float64) {
  57. for _, v := range cd.actions {
  58. - v.Act(cd, svc)
  59. + v.Act(cd, svc, dt)
  60. }
  61. }
  62.  
  63. diff --git a/src/core/messages.go b/src/core/messages.go
  64. index b41ba8a..fde662f 100644
  65. --- a/src/core/messages.go
  66. +++ b/src/core/messages.go
  67. @@ -13,7 +13,8 @@ type Msg interface{}
  68. // Message to signal an update and/or updated status.
  69. // A completion of update reply should be sent to the Origin channel.
  70. type MsgTick struct {
  71. - Origin chan Msg // Identifies the sources of the tick
  72. + Origin chan Msg // Identifies the sources of the tick
  73. + Duration float64 // Time in milliseconds since the last tick
  74. }
  75.  
  76. // Tells the receiver to quit, shutdown, stop, halt, cease operations, close for
  77. @@ -75,3 +76,10 @@ type MsgAssignControl struct {
  78. Uid UniqueId // Entity to be given to a client
  79. Revoked bool // True, if control is to be removed
  80. }
  81. +
  82. +// Message for proof-of-concept demo's spider AI.
  83. +// Requests that the spider entity be moved toward the nearest player.
  84. +type MsgPersueNearestPlayer struct {
  85. + Entity *EntityDesc
  86. + Speed float64 // units per second
  87. +}
  88. diff --git a/src/game/game.go b/src/game/game.go
  89. index fec2fa5..6b0c15c 100644
  90. --- a/src/game/game.go
  91. +++ b/src/game/game.go
  92. @@ -47,10 +47,11 @@ func (g *Game) Run(input chan core.Msg) {
  93. // List of up to date entities
  94. updated := make(map[chan core.Msg]bool, len(g.ents))
  95. remove_list := []chan core.Msg{}
  96. - tick_msg := core.MsgTick{input}
  97. + tick_dur := float64(skip_ns) / 1.0e6
  98.  
  99. for {
  100. tick_start := time.Nanoseconds()
  101. + tick_msg := core.MsgTick{input, tick_dur}
  102.  
  103. // Tell all the entities that a new tick has started
  104. ent_num := len(g.ents) // Store ent count for *this* tick
  105. @@ -79,7 +80,7 @@ func (g *Game) Run(input chan core.Msg) {
  106. }
  107. }
  108. update_end:
  109. - g.svc.Comm <- tick_msg
  110. + g.svc.Comm <- core.MsgTick{input, tick_dur}
  111.  
  112. // Remove all entities that reported themselves to be removed
  113. for _, ent := range remove_list {
  114. @@ -92,8 +93,10 @@ func (g *Game) Run(input chan core.Msg) {
  115. sleep_ns := (tick_start + skip_ns) - time.Nanoseconds()
  116. if sleep_ns > 0 {
  117. time.Sleep(sleep_ns)
  118. + tick_dur = float64(skip_ns) / 1.0e6
  119. } else {
  120. log.Println("game: behind by", sleep_ns/1e6*-1, "ms")
  121. + tick_dur = float64(skip_ns - sleep_ns) / 1.0e6
  122. }
  123. }
  124. }
  125. diff --git a/src/main/main.go b/src/main/main.go
  126. index 3689de1..3abde92 100644
  127. --- a/src/main/main.go
  128. +++ b/src/main/main.go
  129. @@ -6,6 +6,7 @@
  130. package main
  131.  
  132. import (
  133. + "github.com/tm1rbrt/s3dm"
  134. "core"
  135. "game"
  136. "comm"
  137. @@ -34,5 +35,7 @@ func main() {
  138. func initGameSvc(g *game.Game, svc core.ServiceContext) {
  139. spider := sf.InitSpider(g.GetUid())
  140. g.AddEntity(spider)
  141. + spider.AddAction(sf.Persue{5.})
  142. + spider.SetState(sf.Position{s3dm.NewV3(3., 3., 0.)})
  143. go spider.Run(svc)
  144. }
  145. diff --git a/src/pubsub/pubsub.go b/src/pubsub/pubsub.go
  146. index f486d5d..04749ac 100644
  147. --- a/src/pubsub/pubsub.go
  148. +++ b/src/pubsub/pubsub.go
  149. @@ -47,7 +47,7 @@ func NewPubSub(svc core.ServiceContext) *PubSub {
  150.  
  151. // Starts a loop to receive and handle messages from the passed channel
  152. func (ps *PubSub) Run(input chan core.Msg) {
  153. - ps.svc.Game <- core.MsgTick{input} // Service is ready
  154. + ps.svc.Game <- core.MsgTick{Origin: input} // Service is ready
  155.  
  156. for {
  157. msg := <-input
  158. diff --git a/src/sf/actions.go b/src/sf/actions.go
  159. index ab99004..cfd1cbd 100644
  160. --- a/src/sf/actions.go
  161. +++ b/src/sf/actions.go
  162. @@ -19,7 +19,7 @@ func (a Move) Id() core.ActionId { return cmpId.Move }
  163. func (a Move) Name() string { return "Move" }
  164.  
  165. // Modifies the Position of an Entity with the passed Move vector.
  166. -func (a Move) Act(ent core.Entity, svc core.ServiceContext) {
  167. +func (a Move) Act(ent core.Entity, svc core.ServiceContext, dt float64) {
  168. svc.World <- MoveMsg{core.NewEntityDesc(ent), a.Direction}
  169. }
  170.  
  171. @@ -30,7 +30,7 @@ type Attack struct{}
  172. func (a Attack) Id() core.ActionId { return cmpId.Attack }
  173. func (a Attack) Name() string { return "Attack" }
  174.  
  175. -func (a Attack) Act(ent core.Entity, svc core.ServiceContext) {
  176. +func (a Attack) Act(ent core.Entity, svc core.ServiceContext, dt float64) {
  177. var health Health
  178. var ok bool
  179. if health, ok = (ent.GetState(cmpId.Health)).(Health); !ok {
  180. @@ -43,3 +43,16 @@ func (a Attack) Act(ent core.Entity, svc core.ServiceContext) {
  181. }
  182. ent.SetState(health)
  183. }
  184. +
  185. +type Persue struct {
  186. + Speed float64
  187. +}
  188. +
  189. +func (a Persue) Id() core.ActionId { return cmpId.Persue }
  190. +func (a Persue) Name() string { return "Persue" }
  191. +
  192. +func (a Persue) Act(ent core.Entity, svc core.ServiceContext, dt float64) {
  193. + ed := core.NewEntityDesc(ent)
  194. + speed := a.Speed * .001 * dt
  195. + svc.World <- core.MsgPersueNearestPlayer{ed, speed}
  196. +}
  197. diff --git a/src/sf/cmpId/cmpId.go b/src/sf/cmpId/cmpId.go
  198. index fa9c36f..58ad336 100644
  199. --- a/src/sf/cmpId/cmpId.go
  200. +++ b/src/sf/cmpId/cmpId.go
  201. @@ -22,6 +22,7 @@ const (
  202. const (
  203. Move = iota + core.ACTION_END
  204. Attack
  205. + Persue
  206. )
  207.  
  208. // Entities
  209. diff --git a/src/sf/world.go b/src/sf/world.go
  210. index 85793de..510cdc8 100644
  211. --- a/src/sf/world.go
  212. +++ b/src/sf/world.go
  213. @@ -36,18 +36,21 @@ type World struct {
  214. ents map[string]chan core.Msg
  215. // Entity position (or cells) as 3D vectors may be looked up with this
  216. pos map[core.UniqueId]*s3dm.V3
  217. + // List of the player entities' unique ID's
  218. + players []core.UniqueId
  219. }
  220.  
  221. func NewWorld(svc core.ServiceContext) *World {
  222. ents := make(map[string]chan core.Msg)
  223. pos := make(map[core.UniqueId]*s3dm.V3)
  224. - return &World{svc, ents, pos}
  225. + players := make([]core.UniqueId, 0)
  226. + return &World{svc, ents, pos, players}
  227. }
  228.  
  229. func (w *World) Run(input chan core.Msg) {
  230. // Subscribe to listen for new entities in order to track their position
  231. w.svc.PubSub <- pubsub.SubscribeMsg{"entity", input}
  232. - w.svc.Game <- core.MsgTick{input} // Service is ready
  233. + w.svc.Game <- core.MsgTick{Origin: input} // Service is ready
  234.  
  235. for {
  236. msg := <-input
  237. @@ -60,10 +63,35 @@ func (w *World) Run(input chan core.Msg) {
  238. if pos, ok := (<-reply).(Position); ok {
  239. w.putInEmptyPos(m.Entity, pos.Position)
  240. }
  241. + if m.Entity.Id == cmpId.Player {
  242. + w.players = append(w.players, m.Entity.Uid)
  243. + }
  244. case core.MsgEntityRemoved:
  245. pos := w.pos[m.Entity.Uid]
  246. w.pos[m.Entity.Uid] = nil, false
  247. w.ents[hashV3(pos)] = nil, false
  248. + if m.Entity.Id == cmpId.Player {
  249. + for i, pl := range w.players {
  250. + if pl == m.Entity.Uid {
  251. + w.players = append(w.players[:i], w.players[i+1:]...)
  252. + break
  253. + }
  254. + }
  255. + }
  256. + case core.MsgPersueNearestPlayer:
  257. + const REMOVE_DIST = 100. // distance at which to remove entity
  258. + nearest, dist := w.findNearestPlayer(m.Entity)
  259. + if nearest <= 0 {
  260. + break
  261. + }
  262. + if dist >= REMOVE_DIST {
  263. + m.Entity.Chan <- core.MsgSetState{core.Remove{true}}
  264. + w.svc.Game <- core.MsgEntityRemoved{m.Entity}
  265. + break
  266. + }
  267. + spos, ppos := w.pos[m.Entity.Uid], w.pos[nearest]
  268. + dir := ppos.Sub(spos).Unit() // normalized direction vector
  269. + w.moveEnt(m.Entity, dir.Muls(m.Speed))
  270. }
  271. }
  272. }
  273. @@ -107,15 +135,10 @@ func (w *World) moveEnt(ent *core.EntityDesc, vel *s3dm.V3) {
  274. new_pos := old_pos.Add(vel)
  275. hash := hashV3(new_pos)
  276.  
  277. - // See if destination cell is occupied
  278. - if ent_ch, ok := w.ents[hash]; ok {
  279. - // TODO: HACK remove following if block when spider AI uses time based move
  280. - // Update position if movement is less than 1, this lets spider move slowly
  281. - if math.Fabs(vel.X) < 1 && math.Fabs(vel.Y) < 1 {
  282. - w.pos[ent.Uid] = new_pos
  283. - ent.Chan <- core.MsgSetState{Position{new_pos}}
  284. - }
  285. - ent_ch <- core.MsgRunAction{Attack{}, false} // Can't move there, attack instead
  286. + // See if destination cell is occupied by another entity
  287. + if ch, ok := w.ents[hash]; ok && ch != ent.Chan {
  288. + // Can't move there, attack instead
  289. + ch <- core.MsgRunAction{Attack{}, false}
  290. return
  291. }
  292. // If not, move the entity to the new pos
  293. @@ -155,17 +178,37 @@ func (w *World) spawnSpiders(pos *s3dm.V3) {
  294.  
  295. // Spawn spiders at a random point in a ring around the player
  296. // between MIN_DIST and MAX_DIST.
  297. - reply := make(chan *core.EntityDesc)
  298. for i := 0; i < count; i++ {
  299. radius := rand.Float64()*(MAX_DIST-MIN_DIST) + MIN_DIST
  300. angle := rand.Float64() * 2. * math.Pi
  301. x := pos.X + radius*math.Cos(angle)
  302. y := pos.Y + radius*math.Sin(angle)
  303. +
  304. // Create the spider entity and position it
  305. - go func(X, Y float64) {
  306. - w.svc.Game <- game.MsgSpawnEntity{InitSpider, reply}
  307. - spider := <-reply
  308. - spider.Chan <- core.MsgSetState{Position{s3dm.NewV3(X, Y, 0.)}}
  309. - }(x, y)
  310. + f := func(uid core.UniqueId) core.Entity {
  311. + ent := InitSpider(uid)
  312. + ent.SetState(Position{s3dm.NewV3(x, y, 0.)})
  313. + ent.AddAction(Persue{5.})
  314. + return ent
  315. + }
  316. + go func() {
  317. + w.svc.Game <- game.MsgSpawnEntity{f, nil}
  318. + }()
  319. + }
  320. +}
  321. +
  322. +// Returns UID and distance of player entity nearest to given entity
  323. +func (w *World) findNearestPlayer(ent *core.EntityDesc) (core.UniqueId, float64) {
  324. + spos := w.pos[ent.Uid]
  325. + var best core.UniqueId = 0
  326. + var best_dist float64
  327. + for _, pl := range w.players {
  328. + ppos := w.pos[pl]
  329. + dist := spos.Distance(ppos)
  330. + if best == 0 || dist < best_dist {
  331. + best = pl
  332. + best_dist = dist
  333. + }
  334. }
  335. + return best, best_dist
  336. }
Add Comment
Please, Sign In to add comment