2 Batto! A clicking arcade game
3 Copyright 2018 Pajo <xpio at tut dot by>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
22 love
.window
.setMode(1080/2.5, 1920/2.5)
24 w
= love
.graphics
.getWidth(),
25 h
= love
.graphics
.getHeight()
33 love
.graphics
.setColor(.5, .5, .8)
34 love
.graphics
.circle("fill", self
.x
, self
.y
, self
.size
/ 2)
36 move
= function(self
, x
, y
)
37 if trails
[1] then return end -- no movement until all trails expire
38 trails
:make(x
, y
, self
.x
, self
.y
)
42 destroy
= function(self
)
43 game
.score
= game
.score
- 10
44 explosions
:make(self
.x
, self
.y
, self
.size
)
53 make
= function(self
, x
, y
, sx
, sy
)
55 local d
= ((x
- sx
) ^
2 + (y
- sy
) ^
2) ^
0.5
56 local howmany
= math
.max(math
.min(d
/ expiration
, self
.max), self
.min)
58 for a
= self
.min, howmany
do
59 step
= 1 - a
/ howmany
62 x
= sx
- (sx
- x
) * step
,
63 y
= sy
- (sy
- y
) * step
68 love
.graphics
.setColor(1, .5, 0)
70 love
.graphics
.circle("line", self
[a
].x
, self
[a
].y
, self
[a
].size
/ 2)
73 expire
= function(self
, dt
)
74 self
.timer
= self
.timer
+ dt
75 if self
.timer
> self
.duration
and #self
> 0 then
77 self
.timer
= self
.timer
- self
.duration
80 check
= function(self
)
81 for a
= 1, #self
do for b
= 1, #enemies
do
82 if not enemies
[b
].dying
and collides(trails
[a
], enemies
[b
]) then
83 if not enemies
[b
].isbullet
then enemies
[b
]:die() end
87 purge
= function(self
)
88 while #self
> 0 do self
[#self
] = nil end
95 self
.x
= self
.x
+ self
.speedx
96 self
.y
= self
.y
+ self
.speedy
97 self
.dying
= self
.dying
or
98 (self
.x
< 1 or self
.x
> screen
.w
or self
.y
< 1 or self
.y
> screen
.h
)
101 wander
= function(self
)
102 self
.x
= self
.x
+ self
.speedx
103 self
.y
= self
.y
+ self
.speedy
104 if self
.x
< 1 or self
.x
> screen
.w
then
105 self
.speedx
= - self
.speedx
107 if self
.y
< 1 or self
.y
> screen
.h
then
108 self
.speedy
= - self
.speedy
112 chase
= function(self
)
113 self
.speedx
= self
.speedx
* 199/200 + (player
.x
- self
.x
) / 2000
114 self
.speedy
= self
.speedy
* 199/200 + (player
.y
- self
.y
) / 2000
115 self
.speedx
= self
.speedx
/ math
.abs(self
.speedx
) * math
.min(3, math
.abs(self
.speedx
))
116 self
.speedy
= self
.speedy
/ math
.abs(self
.speedy
) * math
.min(3, math
.abs(self
.speedy
))
117 self
.x
= self
.x
+ self
.speedx
118 self
.y
= self
.y
+ self
.speedy
122 draw
= function(self
)
124 love
.graphics
.setColor(self
[a
].kind
.color
)
125 love
.graphics
.rectangle("fill", self
[a
].x
- self
[a
].size
/ 2, self
[a
].y
- self
[a
].size
/ 2, self
[a
].size
, self
[a
].size
)
128 make
= function(self
, kind
, x
, y
, speedx
, speedy
)
130 kind
= kind
, x
= x
, y
= y
, speedx
= speedx
, speedy
= speedy
,
134 explosions
:make(self
.x
, self
.y
, self
.size
)
135 game
.score
= game
.score
+ 1
137 -- will be disposed of in cleanup
141 move
= function(self
)
143 self
[a
] = self
[a
].kind
.movement(self
[a
])
146 check
= function(self
)
148 if not self
[a
].dying
and collides(player
, self
[a
]) then
153 if #self
== 0 and game
.happened
== #scenario
[game
.level
] then
157 cleanup
= function(self
)
158 for a
= #self
, 1, -1 do if self
[a
].dying
then
159 self
[a
] = self
[#self
]
168 movement
= enemies
.movements
.wander
,
173 movement
= enemies
.movements
.chase
,
178 movement
= enemies
.movements
.pass
,
183 movement
= enemies
.movements
.pass
,
190 make
= function(self
, x
, y
, size
)
198 grow
= function(self
)
199 -- must go backwards not to disrupt the loop
200 for a
= #self
, 1, -1 do
201 self
[a
].step
= self
[a
].step
+ 1
202 if self
[a
].step
> self
.maxsteps
then
207 destroy
= function(self
, a
)
208 self
[a
] = self
[#self
]
211 draw
= function(self
)
212 love
.graphics
.setColor(1,1,0)
214 love
.graphics
.rectangle("line", self
[a
].x
- self
[a
].size
/ 2 - self
[a
].step
* 2, self
[a
].y
- self
[a
].size
/ 2 - self
[a
].step
* 2, self
[a
].size
+ self
[a
].step
* 4, self
[a
].size
+ self
[a
].step
* 4)
217 purge
= function(self
)
218 while #self
> 0 do self
[#self
] = nil end
223 ul
= { x
= 0, y
= 0 },
224 u
= { x
= screen
.w
/ 2, y
= 0 },
225 ur
= { x
= screen
.w
, y
= 0 },
226 l
= { x
= 0, y
= screen
.h
/ 2 },
227 c
= { x
= screen
.w
/ 2, y
= screen
.h
/ 2 },
228 r
= { x
= screen
.w
, y
= screen
.h
/ 2 },
229 dl
= { x
= 0, y
= screen
.h
},
230 d
= { x
= screen
.w
/ 2, y
= screen
.h
},
231 dr
= { x
= screen
.w
, y
= screen
.h
},
238 player_origin
= origins
.c
,
240 { time
= 0, origin
= origins
.ul
, speed
= { 1, 1 }, kind
= enemies
.kinds
.passer
},
242 { time
= 2, origin
= origins
.l
, speed
= { 1, 0 }, kind
= enemies
.kinds
.passer
},
244 { time
= 4, origin
= origins
.dl
, speed
= { 1, -1 }, kind
= enemies
.kinds
.passer
},
246 { time
= 6, origin
= origins
.d
, speed
= { 0, -1 }, kind
= enemies
.kinds
.passer
},
251 player_origin
= origins
.d
,
253 { time
= 0, origin
= origins
.ul
, speed
= { 1, 1 }, kind
= enemies
.kinds
.wanderer
},
255 { time
= 1, origin
= origins
.r
, speed
= { -5, 0 }, kind
= enemies
.kinds
.bullet
},
257 { time
= 2, origin
= origins
.l
, speed
= { 1, 0 }, kind
= enemies
.kinds
.wanderer
},
262 player_origin
= origins
.c
,
264 { time
= 1, origin
= origins
.u
, speed
= { 1, 1 }, kind
= enemies
.kinds
.chaser
},
266 { time
= 2, origin
= origins
.dr
, speed
= { 1, 0 }, kind
= enemies
.kinds
.chaser
},
268 { time
= 3, origin
= origins
.dl
, speed
= { 1, 0 }, kind
= enemies
.kinds
.chaser
},
282 function collides(obj1
, obj2
)
283 local o1x
, o1y
, o2x
, o2y
, d
284 o1x
= obj1
.x
+ obj1
.size
/ 2
285 o1y
= obj1
.y
+ obj1
.size
/ 2
286 o2x
= obj2
.x
+ obj2
.size
/ 2
287 o2y
= obj2
.y
+ obj2
.size
/ 2
288 d
= obj1
.size
/ 2 + obj2
.size
/ 2
289 return (o1x
- o2x
) ^
2 + (o1y
- o2y
) ^
2 < d ^
2
293 function beginlevel()
297 player
.x
= scenario
[game
.level
].player_origin
.x
298 player
.y
= scenario
[game
.level
].player_origin
.y
302 function happen(number)
303 game
.happened
= number
304 local s
= scenario
[game
.level
][number]
305 enemies
:make(s
.kind
, s
.origin
.x
, s
.origin
.y
, s
.speed
[1], s
.speed
[2])
306 enemies
[#enemies
].isbullet
= s
.kind
== enemies
.kinds
.bullet
314 game
.level
= game
.level
+ 1
315 if game
.level
> #scenario
then
324 function love
.update(dt
)
326 love
.timer
.sleep(1/30 - dt
)
328 game
.timer
= game
.timer
+ dt
329 if game
.mode
== "play" then
335 for a
= game
.happened
+ 1, #scenario
[game
.level
] do
336 if game
.timer
> scenario
[game
.level
][a
].time
then
340 elseif game
.mode
== "title" then
341 if game
.timer
> 3 then
349 love
.graphics
.setColor(1,1,1)
350 love
.graphics
.print(math
.floor(game
.timer
) .. ':' .. game
.score
, 1, 2)
351 love
.graphics
.print('game.mode = ' .. game
.mode
, 1, 20)
352 love
.graphics
.print('#enemies = ' .. #enemies
, 1, 30)
357 if game
.mode
== "play" then
362 elseif game
.mode
== "title" then
363 love
.graphics
.setColor(1,1,1)
364 love
.graphics
.print(scenario
[game
.level
].title
, 100, 100)
365 elseif game
.mode
== "theend" then
366 love
.graphics
.setColor(1,1,1)
367 love
.graphics
.print('The End', 100, 100)
373 function love
.mousepressed(x
, y
, button
)
374 if game
.mode
== "title" or game
.mode
== "theend" then
376 elseif game
.mode
== "play" then
383 function love
.keypressed(k
)
384 if k
== "escape" or k
== "q" then
385 love
.event
.push("quit")