-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathChaseEvade.elm
111 lines (89 loc) · 2.84 KB
/
ChaseEvade.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
module ChaseEvade exposing (..)
import Color exposing (..)
import Collage exposing (..)
import Element exposing (Element)
import Random exposing (Generator, generate, initialSeed, Seed)
import Time exposing (..)
import Vec2 exposing (..)
import ClassicalEngine exposing (..)
--- Structures ---
type Action = Init Simulation | Tick Time
type alias Simulation = {
quarry : Actor {},
target : Vec2,
chaser : Actor {},
evader : Actor {},
reset : Float
}
sim0 : Simulation
sim0 =
{ quarry = actor0
, target = (0, 0)
, chaser = actor0
, evader = actor0
, reset = 0
}
--- Constants ---
maxA : Float
maxA = 50
maxV : Float
maxV = 100
--- Behavior ---
chase : Float -> Float -> Vec2 -> Actor etc -> Actor etc
chase maxV maxA target chaser = { chaser |
a = normalize (target .-. chaser.pos) .* maxV .-. chaser.v
|> clamp2 0 maxA }
evade : Float -> Float -> Vec2 -> Actor etc -> Actor etc
evade maxV maxA target evader = { evader |
a = normalize (target .-. evader.pos) .* -maxV .-. evader.v
|> clamp2 0 maxA }
arrive : Float -> Float -> Vec2 -> Actor etc -> Actor etc
arrive maxV maxA target arriver = let
stopt = maxV / maxA
stopd = stopt * maxV / 2
diff = target .-. arriver.pos
d = norm diff
desired_v = if d < stopd then diff .* (2 / stopt) else diff .* (maxV / d)
in
{ arriver | a = desired_v .-. arriver.v |> clamp2 0 maxA }
--- Simulation ---
initSim : Generator Simulation
initSim = let
vec200 = Random.pair (Random.float -200 200) (Random.float -200 200)
vec40 = Random.pair (Random.float -40 40) (Random.float -40 40)
in Random.map4 (\r0 r1 r2 r3 ->
{ quarry = {pos = r0, v = r1, a = (0, 0)}
, target = r0 .+. r1
, chaser = {pos = r2, v = (0, 0), a = (0, 0)}
, evader = {pos = r3, v = (0, 0), a = (0, 0)}
, reset = Time.second * 10
}
) vec200 vec40 vec200 vec200
simulate : Time -> Simulation -> (Simulation, Cmd Action)
simulate t sim = let
dt = (inSeconds t)
sim = { sim
| quarry = sim.quarry |> stepActor maxV dt
, target = sim.quarry.pos .+. sim.quarry.v .*
(dist sim.target sim.chaser.pos / maxV)
, chaser = sim.chaser |> chase maxV maxA sim.target |> stepActor maxV dt
, evader = sim.evader |> evade maxV maxA sim.target |> stepActor maxV dt
, reset = sim.reset - t
}
in
(sim, if sim.reset > 0 then Cmd.none else generate Init initSim)
--- Drawing ---
drawTarget : LineStyle -> Vec2 -> List Form
drawTarget style target =
[ outlined style (circle 5) |> move target
, outlined style (circle 8) |> move target
, traced style <| segment (target .+. (0, 15)) (target .-. (0, 15))
, traced style <| segment (target .+. (15, 0)) (target .-. (15, 0))
]
drawSim : Simulation -> Element
drawSim sim = collage 500 500 (
drawTarget (solid black) sim.target ++
drawVehicle grey sim.quarry ++
drawVehicle red sim.chaser ++
drawVehicle yellow sim.evader
)