func (s *Sim) potential(unit *unit, x, y float64) float64 { // Distance to end //max := 300.0 //dist := (&geo.Vec{x,y}).Distance(&unit.end) //potEnd := dist/max potEnd := 1.0 pos := &geo.Vec{x, y} if unit.path != nil { for e := unit.path.Front(); e.Next() != nil; e = e.Next() { pt0 := e.Value.(*geo.Vec) pt1 := e.Next().Value.(*geo.Vec) av := geo.OrthogonalVector(pt0, pt1.Sub(pt0), &geo.Vec{x, y}) if av != nil { potEnd = math.Min(av.Len()/10.0, 1) } else { if l := pt0.Sub(pos).Len(); l <= 10 { potEnd = math.Min(l/10.0, potEnd) } else if l := pt1.Sub(pos).Len(); l <= 10 { potEnd = math.Min(l/10.0, potEnd) } } } } // other units MIN := 5.0 MAX := 10.0 potDist := 0.0 for _, oUnit := range s.units { if oUnit.id != unit.id { dist := oUnit.pos.Distance(&geo.Vec{x, y}) potDist += 1 - math2.MinMax(1, (dist-MIN)/(MAX-MIN), 0) } } potDist = math2.MinMax(1, potDist, 0) // trail potTrail := 0.0 elms := unit.trail.Elements() for _, elm := range elms { if elm != nil { trailPos := elm.(geo.Vec) dist := trailPos.Distance(&geo.Vec{x, y}) potTrail += 1.0 - math2.MinMax(1, dist/float64(1), 0) } } potTrail = math2.MinMax(1, potTrail, 0) if unit.id == 0 && potDist > 0 { //fmt.Println(potDist) } pot := 0.5*potEnd + 0*potDist + 0.25*potTrail xd := int(x) yd := int(y) if xd >= 0 && xd < 300 && yd >= 0 && yd < 300 { if s.static[xd][yd] == 1 { pot = 1 } } return pot }
func (s *Sim) Update() { speed := 20.0 / float64(time.Second) // -> 10 units per second lastUpdate := time.Now() time.Sleep(1 * time.Nanosecond) for { dTime := time.Since(lastUpdate) start := time.Now() // Update the units for _, unit := range s.units { if unit.pos == unit.end { // TODO when to finish? continue } min, radMin := 1.0, 0.0 for i := 0; i < 16; i++ { // TODO We can cache all these static directions rad := math.Pi * 2 * float64(i) / 16.0 dy := math.Sin(rad) dx := math.Cos(rad) pot := s.potential(unit, unit.pos.X+dx, unit.pos.Y+dy) if pot < min { min = pot radMin = rad } } d := speed * float64(dTime) unit.pos.X += math.Cos(radMin) * d unit.pos.Y += math.Sin(radMin) * d // Add position to trail if more than 0.25 units away if last := unit.trail.Front(); last != nil { lastPos := last.(geo.Vec) if lastPos.Distance(&unit.pos) >= 0.25 { unit.trail.AddToFront(unit.pos) } } else { unit.trail.AddToFront(unit.pos) } // if the unit already walks at the next path piece, forget the current front one if unit.path.Len() > 2 { pt1 := unit.path.Front().Next().Value.(*geo.Vec) pt2 := unit.path.Front().Next().Next().Value.(*geo.Vec) if geo.OrthogonalVector(pt1, pt2.Sub(pt1), &unit.pos) != nil { unit.path.Remove(unit.path.Front()) } } } // Important: update BEFORE the render lastUpdate = time.Now() fps := 1 / (float64(time.Since(start)) / float64(time.Second)) _ = fps //fmt.Printf("%.f \t\n", fps) //fmt.Println(fps, s.units[0].pos) //s.ui.fpsLabel.SetLabel(fmt.Sprintf("%f", fps)) time.Sleep(1 * time.Millisecond) } }