// Compute an entity's new position. // Returns an EntityDiff if the entity has changed, nil otherwise. func (m *Mover) UpdateEntity(ent *entity.Entity, now message.AbsoluteTick) (req *entity.UpdateRequest, collidesWith interface{}) { // TODO: remove Mover.lastUpdates? var last message.AbsoluteTick var ok bool if last, ok = m.lastUpdates[ent.Id]; !ok { last = now } m.lastUpdates[ent.Id] = now dt := time.Duration(now-last) * clock.TickDuration // Convert to seconds if dt == 0 { return } if dt < 0 { return // TODO: figure out if it's the right thing to do here } speed := ent.Speed pos := ent.Position nextPos := speed.GetNextPosition(pos, dt) if nextPos == nil { return } // Check terrain // TODO: use brensenham algorithm // See http://tech-algorithm.com/articles/drawing-line-using-bresenham-algorithm/ route := terrain.GetRouteBetween(pos, nextPos) stoppedAt, collidesWith := checkRoute(route, ent, m.engine.ctx.Terrain, m.engine.ctx.Entity.List()) if stoppedAt != nil { // The entity has been stopped while moving nextPos = stoppedAt } newEnt := entity.New() newEnt.Id = ent.Id newEnt.Position = nextPos diff := &message.EntityDiff{Position: true} req = entity.NewUpdateRequest(now, newEnt, diff) return }
func (e *Engine) moveEntities(t message.AbsoluteTick) { for _, ent := range e.entity.List() { req, collidesWith := e.mover.UpdateEntity(ent, t) // [GAME-SPECIFIC] Destroy balls when they collide if collidesWith != nil && ent.Type == game.BallEntity { req := entity.NewDeleteRequest(t, ent.Id) if err := e.entity.AcceptRequest(req); err != nil { panic(err) // This shouldn't happen } // If the ball collides with a player, decrease his health if collidesWith, ok := collidesWith.(*message.Entity); ok && collidesWith.Type == game.PlayerEntity { sender := ent.Attributes[game.SenderAttr].(message.EntityId) if sender != collidesWith.Id { health := collidesWith.Attributes[game.HealthAttr].(game.Health) updated := entity.New() updated.Attributes[game.HealthAttr] = health - 1 diff := message.NewEntityDiff() diff.Attributes = true req := entity.NewUpdateRequest(t, updated, diff) if err := e.entity.AcceptRequest(req); err != nil { panic(err) // This shouldn't happen } } } continue } if req != nil { // Let's assume mover already did all security checks if err := e.entity.AcceptRequest(req); err != nil { // This should not fail panic(err) } } } }