From dc17461910194815ff9b329f386f17d6218a5853 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Mon, 18 Sep 2023 21:55:14 +0200 Subject: feat: Move avoid colision between moving entities --- main.go | 13 ++++++++++--- move.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/main.go b/main.go index 8d49043..900429c 100644 --- a/main.go +++ b/main.go @@ -80,7 +80,7 @@ func (g *Game) Update() error { g.updateSelecting(cursor) } for _, e := range g.Entities { - e.UpdateMove() + e.UpdateMove(g.getMoveMap()) } return nil } @@ -118,13 +118,20 @@ func main() { game.Entities = append(game.Entities, &ironMine) personImage := NewColorImage(Point{100, 100}, color.RGBA{0xff, 0xff, 0xff, 0xff}) personSelectedImage := NewHaloImage(personImage, color.RGBA{0xff, 0x00, 0x00, 0xff}, 10) - alterPerson := Entity{ + person1 := Entity{ Position: C(Point{2000, 2000}), Image: C(personImage), Selection: C(Selection{IsSelected: false, SelectedImage: personSelectedImage}), Move: C(Move{IsActive: false}), } - game.Entities = append(game.Entities, &alterPerson) + game.Entities = append(game.Entities, &person1) + person2 := Entity{ + Position: C(Point{2200, 2200}), + Image: C(personImage), + Selection: C(Selection{IsSelected: false, SelectedImage: personSelectedImage}), + Move: C(Move{IsActive: false}), + } + game.Entities = append(game.Entities, &person2) game.CurrentAction = Selecting if err := ebiten.RunGame(game); err != nil { panic(err) diff --git a/move.go b/move.go index 2135aaf..c45378d 100644 --- a/move.go +++ b/move.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "image/color" "math" @@ -10,11 +11,19 @@ import ( "golang.org/x/exp/slog" ) +const MOVE_SPEED = 10.0 + +type Path []Point + +func (p Path) String() string { + return fmt.Sprintf("%s -> %s", p[0].String(), p[len(p)-1].String()) +} + type Move struct { IsActive bool Origin Point Destination Point - Path []Point + Path Path } type Node struct { @@ -41,7 +50,7 @@ type PathSearch struct { moveMap MoveMap } -func SearchPath(origin Point, destination Point, moveMap MoveMap) ([]Point, bool) { +func SearchPath(origin Point, destination Point, moveMap MoveMap) (Path, bool) { search := PathSearch{ origin: origin, destination: destination, @@ -99,9 +108,9 @@ func (s *PathSearch) bestOpenNode() (Point, Node) { return bestPoint, bestNode } -func (s *PathSearch) buildPath() []Point { +func (s *PathSearch) buildPath() Path { point := s.destination - path := []Point{s.destination} + path := Path{s.destination} node := s.closedList[s.destination] for point != s.origin { point = node.Parent @@ -112,7 +121,7 @@ func (s *PathSearch) buildPath() []Point { return path } -func (s *PathSearch) search() ([]Point, bool) { +func (s *PathSearch) search() (Path, bool) { s.openList[s.origin] = Node{CostFromOrigin: 0, CostToDestination: int(Distance(s.origin, s.destination)), Parent: s.origin} point := s.origin var node Node @@ -125,7 +134,7 @@ func (s *PathSearch) search() ([]Point, bool) { if point == s.destination { return s.buildPath(), true } - return []Point{}, false + return Path{}, false } func NewMove(origin Point, destination Point, moveMap MoveMap) Move { @@ -133,15 +142,15 @@ func NewMove(origin Point, destination Point, moveMap MoveMap) Move { origin.X / 100 * 100, origin.Y / 100 * 100, } - search, ok := SearchPath(current, destination, moveMap) + path, ok := SearchPath(current, destination, moveMap) if !ok { slog.Info("no path found", slog.String("destination", destination.String())) return Move{IsActive: false} } - return Move{IsActive: true, Origin: origin, Destination: destination, Path: search} + return Move{IsActive: true, Origin: origin, Destination: destination, Path: path} } -func (m *Move) Update(position Point, speed int) Point { +func (m *Move) Update(position Point, speed int, moveMap MoveMap) Point { if !m.IsActive { return position } @@ -151,7 +160,14 @@ func (m *Move) Update(position Point, speed int) Point { m.IsActive = false slog.Info("move finished", slog.String("destintation", m.Destination.String())) } else { - m.Path = m.Path[1:] + slog.Info("next joined, searching new path", slog.String("next", next.String())) + path, ok := SearchPath(next, m.Destination, moveMap) + if !ok { + slog.Info("no path found", slog.String("destination", m.Destination.String())) + m.IsActive = false + } else { + m.Path = path + } } return next } @@ -169,9 +185,36 @@ func (e *Entity) StartMove(destination Point, moveMap MoveMap) { } } -func (e *Entity) UpdateMove() { +func (e *Entity) moveToward(destination Point) { + remainingMove := destination.Sub(e.Position.Value) + delta := remainingMove.Mul(MOVE_SPEED).Div(int(Length(remainingMove))) + e.Position.Value = e.Position.Value.Add(delta) +} + +func (e *Entity) UpdateMove(moveMap MoveMap) { if e.Move.IsEnabled && e.Position.IsEnabled { - e.Position.Value = e.Move.Value.Update(e.Position.Value, 10) + position := e.Position.Value + if !e.Move.Value.IsActive { + return + } + next := e.Move.Value.Path[1] + if Distance(position, next) < MOVE_SPEED { + e.Position.Value = next + if next == e.Move.Value.Destination { + e.Move.Value.IsActive = false + slog.Info("move finished", slog.String("destintation", e.Move.Value.Destination.String())) + } else { + path, ok := SearchPath(next, e.Move.Value.Destination, moveMap) + if !ok { + slog.Info("no path found", slog.String("destination", e.Move.Value.Destination.String())) + e.Move.Value.IsActive = false + } else { + e.Move.Value.Path = path + } + } + } else { + e.moveToward(next) + } } } @@ -181,7 +224,7 @@ func DrawMove(screen *ebiten.Image, e *Entity) { last := e.Position.Value dx := +e.Image.Value.Bounds().Dx() / 2 dy := +e.Image.Value.Bounds().Dy() / 2 - for _, point := range e.Move.Value.Path { + for _, point := range e.Move.Value.Path[1:] { vector.StrokeLine(screen, float32(last.X+dx), float32(last.Y+dy), float32(point.X+dx), float32(point.Y+dy), 10.0, color.RGBA{256 * 3 / 16, 256 * 3 / 16, 256 * 3 / 16, 256 / 4}, true) last = point } -- cgit v1.3