-
Notifications
You must be signed in to change notification settings - Fork 1
/
Bullet.elm
157 lines (120 loc) · 3.42 KB
/
Bullet.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
module Bullet
exposing
( Bullet
, toEntity
, fireTowards
, fireFrom
, move
, impact
, keepExploding
, isDead
)
import Coordinate
import Entity exposing (Entity)
import Time exposing (Time)
type Status
= Flying
| Exploding Time
| Impacted
type alias Bullet =
{ position : Coordinate.Global
, target : Coordinate.Global
, status : Status
}
fireFrom : Coordinate.Global -> Bullet
fireFrom position =
{ position = position
, target = position
, status = Flying
}
fireTowards : Coordinate.Global -> Bullet -> Bullet
fireTowards targetPosition bullet =
{ bullet | target = targetPosition }
move : Time -> Bullet -> Bullet
move diff bullet =
case bullet.status of
Flying ->
moveTheBullet diff bullet
_ ->
bullet
moveTheBullet : Time -> Bullet -> Bullet
moveTheBullet diff bullet =
let
distanceToNextPoint =
Coordinate.distance bullet.position bullet.target
distanceInThisInterval =
(Time.inSeconds diff) * speedPerSecond
in
if distanceToNextPoint > distanceInThisInterval then
let
thisTickG =
bullet.target
|> Coordinate.toLocal bullet.position
|> Coordinate.setMagnitude distanceInThisInterval
|> Coordinate.toGlobal bullet.position
in
{ bullet | position = thisTickG }
else
{ bullet | position = bullet.target }
impact : Bullet -> Bullet
impact bullet =
{ bullet | status = Exploding 0 }
keepExploding : Time -> Bullet -> Bullet
keepExploding diff bullet =
case bullet.status of
Exploding timeSoFar ->
if ceiling (timeSoFar / explosionSpeed) > 3 then
{ bullet | status = Impacted }
else
{ bullet | status = Exploding (timeSoFar + diff) }
_ ->
bullet
isDead : Bullet -> Bool
isDead { position, target, status } =
status == Impacted || position == target
speedPerSecond : number
speedPerSecond =
300
toEntity : Bullet -> Entity
toEntity { position, status } =
case status of
Exploding diff ->
if ceiling (diff / explosionSpeed) == 1 then
explosionPhase1 position diff
else if ceiling (diff / explosionSpeed) == 2 then
explosionPhase2 position diff
else
explosionPhase3 position diff
_ ->
regularBulletEntity position
regularBulletEntity : Coordinate.Global -> Entity
regularBulletEntity position =
{ position = position
, width = 10
, height = 10
, imagePath = "images/cannon-ball.png"
}
explosionPhase1 : Coordinate.Global -> Time -> Entity
explosionPhase1 position timeSoFar =
{ position = position
, width = 50
, height = 50
, imagePath = "images/explosion1.png"
}
explosionPhase2 : Coordinate.Global -> Time -> Entity
explosionPhase2 position timeSoFar =
{ position = position
, width = 75
, height = 75
, imagePath = "images/explosion2.png"
}
explosionPhase3 : Coordinate.Global -> Time -> Entity
explosionPhase3 position timeSoFar =
{ position = position
, width = 50
, height = 50
, imagePath = "images/explosion3.png"
}
explosionSpeed : Time
explosionSpeed =
Time.second / 20