-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSprite.hs
344 lines (218 loc) · 8.18 KB
/
Sprite.hs
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
{-
File : PlayerMoves.hs
Copyright : (c) Matt Teichman, 3/15/17
Functions for moving the player in Galaga.hs.
-}
module Sprite where
import Graphics.Gloss
import GameConstants
-- five directions for sprites to point in: left, right, up, down, and nowhere
data Direction = L | R | U | D | NoMove
deriving (Show, Eq)
-- state of a ship's health
data HealthState = Alive | Dead | Exploding | Attacking
deriving (Show, Eq)
-- kinds of sprite:
--
-- player
-- red enemy
-- blue enemy
-- red enemy
-- bullet
-- no one
-- a hidden red enemy
-- a hidden blue enemy
data Character = Player
| RedEnemy
| BlueEnemy
| HiddnREnmy
| HiddnBEnmy
| Bullet
| NoOne
deriving (Show, Eq)
-- Sprite datatype, which includes information about what kind
-- of sprite it is, where it is, how big it is, whether it's alive,
-- what its owner is (only relevant for bullets), what direction
-- it's pointing in, an internal clock, and the position it started in.
-- kind - what kind of sprite
-- loc - location of sprite
-- size - size of sprite
-- health - health status of sprite
-- owner - owner of sprite (only relevant for bullets)
-- dir - direction sprite is pointed in
-- sClock - internal clock on the sprite
-- initPos - location where sprite started
data Sprite = Sprite {kind :: Character,
loc :: (Float, Float),
size :: (Float, Float),
health :: HealthState,
owner :: Character,
dir :: (Direction, Direction),
sClock :: Float,
initPos :: (Float, Float)}
deriving (Show, Eq)
-- function for pulling x coordinate out of a sprite
xCoord :: Sprite -> Float
xCoord sprite = fst $ loc sprite
-- function for pulling y coordinate out of a sprite
yCoord :: Sprite -> Float
yCoord sprite = snd $ loc sprite
-- function for pulling the x size out of a sprite
xSize :: Sprite -> Float
xSize sprite = fst $ size sprite
-- function for pulling the y size out of a sprite
ySize :: Sprite -> Float
ySize sprite = snd $ size sprite
-- function for pulling the starting x coordinate out of sprite
xIPos :: Sprite -> Float
xIPos sprite = fst $ initPos sprite
-- function for pulling the starting y coordinate out of a sprite
yIPos :: Sprite -> Float
yIPos sprite = snd $ initPos sprite
-- function for rendering a sprite (i.e. making it into a Picture)
render :: Sprite -> IO Picture
render sprite@(Sprite Player _ _ _ _ _ _ _) = do
pic <- shipPic
return $ (transNScale sprite) pic
-- hidden enemies are invisible
render sprite@(Sprite HiddnREnmy _ _ _ _ _ _ _) = return Blank
render sprite@(Sprite HiddnBEnmy _ _ _ _ _ _ _) = return Blank
render sprite@(Sprite BlueEnemy _ _ _ _ _ _ _) = do
pic <- bEnemyPic
return $ (transNScale sprite) pic
render sprite@(Sprite RedEnemy _ _ _ _ _ _ _) = do
pic <- rEnemyPic
return $ (transNScale sprite) pic
render sprite@(Sprite Bullet _ _ _ Player _ _ _) = do
pic <- pBullPic
return $ (transNScale sprite) pic
render sprite@(Sprite Bullet _ _ _ RedEnemy _ _ _) = do
pic <- eBullPic
return $ (transNScale sprite) pic
render sprite@(Sprite Bullet _ _ _ BlueEnemy _ _ _) = do
pic <- eBullPic
return $ (transNScale sprite) pic
render _ = error "sprite not renderable"
-- helper functions for rendering sprites
-- translates a sprite to its x coordinate and y coordinate
sprTrans sprite = translate (xCoord sprite) (yCoord sprite)
-- scales a sprite to its x size and y size
sprScale sprite = scale (xSize sprite) (ySize sprite)
-- translates and scales a sprite
transNScale sprite = sprTrans sprite . sprScale sprite
-- converts Directions to a multiplier that will determine
-- how to translate directions into transformations on x and y
-- coordinates
dirToFloat :: Direction -> Float
dirToFloat L = (-1.0)
dirToFloat R = (1.0)
dirToFloat U = (1.0)
dirToFloat D = (-1.0)
dirToFloat NoMove = (0.0)
-- moves a sprite by a tiny amount in whatever direction it's pointing
-- first parameter is degree of horizontal movement
-- second parameter is degree of vertical movement
nudge :: Float -> Float -> Sprite -> Sprite
nudge inc1 inc2 sprite
= Sprite (kind sprite)
(xCoord sprite + (inc1 * dirToFloat (fst $ dir sprite)),
yCoord sprite + (inc2 * dirToFloat (snd $ dir sprite)))
(size sprite)
(health sprite)
(owner sprite)
(dir sprite)
(sClock sprite)
(initPos sprite)
-- changes direction of a sprite
aboutFace :: Sprite -> Sprite
aboutFace sprite
= Sprite (kind sprite)
(loc sprite)
(size sprite)
(health sprite)
(owner sprite)
(oppDir $ fst $ dir sprite, oppDir $ snd $ dir sprite)
(sClock sprite)
(initPos sprite)
-- maps a direction to its reverse
oppDir :: Direction -> Direction
oppDir L = R
oppDir R = L
oppDir U = D
oppDir D = U
oppDir NoMove = NoMove
-- bitmap picture for blue enemy
bEnemyPic :: IO Picture
bEnemyPic = loadBMP "images/models/blue_fighter.bmp"
-- bitmap picture for red enemy
rEnemyPic :: IO Picture
rEnemyPic = loadBMP "images/models/red_fighter.bmp"
-- bitmap picture for player ship
shipPic :: IO Picture
shipPic = loadBMP "images/models/ship.bmp"
-- bitmap picture for player bullet
pBullPic :: IO Picture
pBullPic = loadBMP "images/models/ship_bullet.bmp"
-- bitmap picture for enemy bullet
eBullPic :: IO Picture
eBullPic = loadBMP "images/models/enemy_bullet.bmp"
-- helper functions for ioPictures
-- lifts a two-place relation to a two-place relation on applicatives
ioApplication :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
ioApplication = \f x y -> ((f) <$> x <*> y)
-- groups two pictures into a single pictures
groupPic :: Picture -> Picture -> Picture
groupPic pic1 pic2 = pictures [pic1, pic2]
-- folds a two-place relation over an applicative, within the applicative,
-- then puts the applicative constructor back around the result
unwrapIO :: (Foldable t, Applicative f) => (a -> a -> a) -> t (f a) -> f a
unwrapIO f list = foldr1 (ioApplication f) list
-- analogue of Gloss' pictures function, but which groups together IO Pictures
-- into a single IO Picture
ioPictures :: [IO Picture] -> IO Picture
ioPictures [] = return Blank
ioPictures [pic] = pic
ioPictures picList = unwrapIO groupPic picList
-- true of a sprite just in case it is hidden
hidden :: Sprite -> Bool
hidden (Sprite HiddnBEnmy _ _ _ _ _ _ _ ) = True
hidden (Sprite HiddnREnmy _ _ _ _ _ _ _ ) = True
hidden _ = False
-- true of a sprite just in case it is neither hidden
-- nor attacking
hideable :: Sprite -> Bool
hideable sprite = not (hidden sprite || attacking sprite)
-- predicate true of alive sprites
alive :: Sprite -> Bool
alive (Sprite _ _ _ Alive _ _ _ _) = True
alive _ = False
-- predicate true of dead sprites
dead :: Sprite -> Bool
dead (Sprite _ _ _ Dead _ _ _ _) = True
dead _ = False
-- predicate true of an attacking enemy
attacking :: Sprite -> Bool
attacking (Sprite _ _ _ Attacking _ _ _ _) = True
attacking _ = False
-- predicate indicating that a sprite has gone offscreen
outOfBounds :: Sprite -> Bool
outOfBounds sprite
= xCoord sprite > (fromIntegral $ scrWidth)/2 + pad
|| xCoord sprite < ((fromIntegral $ scrWidth)/2 * (-1)) - pad
|| yCoord sprite > (fromIntegral $ scrHeight)/2 + pad
|| yCoord sprite < ((fromIntegral $ scrHeight)/2 * (-1)) - pad
-- initial state of the player's ship.
playerShip :: Sprite
playerShip = Sprite Player
(0.0, -235.0)
(0.25, 0.25)
Alive
NoOne
(NoMove, NoMove)
0.0
(0.0, -235.0)
-- creates a list of coordinates for creating a row of enemies
rowInitialize :: (Num a, Enum a) => a -> a -> [(a,a)]
rowInitialize width offset = zip ((map (* (-1)) (reverse [50,100..width])
++ [0,50..width]))
(replicate 12 offset)