diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6fd0a37..0000000 --- a/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# Compiled Lua sources -luac.out - -# luarocks build files -*.src.rock -*.zip -*.tar.gz - -# Object files -*.o -*.os -*.ko -*.obj -*.elf - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo -*.def -*.exp - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - diff --git a/README.md b/README.md index 4cc03e4..5eee433 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,3 @@ Collision from [Edvard Thörnros](https://github.com/FredTheDino/) [1.0 - As presented at the Game Jam](https://github.com/reggosaurus-reg/ShapeShifter/releases/tag/v1.0 "GameJam version") - - - - - diff --git a/entities.lua b/entities.lua new file mode 100644 index 0000000..fc3482d --- /dev/null +++ b/entities.lua @@ -0,0 +1,184 @@ +c = require("lib/collision") +require("lib/graphics") +require("lib/helpers") +require("movement") + +enemy_spawn_interval = 2 +enemies_spawned = 0 + +shot_interval = 1 +last_shot = 0 + +-- Spawn object +function spawn(object_type, args) + if object_type == "player" then + local player = {} + player.curr_damage = 1 + player.draw = get_value(args, "draw", draw_rectangle) + player.filling = "line" + player.height = get_value(args, "height", 60) + player.width = get_value(args, "width", 60) + player.max_damage = 4 + player.move = get_value(args, "move", move_player) + player.object_type = object_type + player.rotate = get_value(args, "rotate", rotate) + player.rotation = 0 + player.rotation_dir = 0 + player.rotation_speed = math.pi * 2 + player.round = 0 + player.update = get_value(args, "update", update) + player.x = get_value(args, "x", win_w / 2) + player.x_dir = 0 + player.x_speed = get_value(args, "x_speed", 300) + player.y = get_value(args, "y", win_h / 2) + player.y_dir = 0 + player.y_speed = get_value(args, "y_speed", 300) + + player.shape = c.makeRect(player.x, player.y, player.width, player.height) + return player + elseif object_type == "enemy" then + local enemy = {} + enemy.draw = get_value(args, "draw", draw_single_rectangle) + enemy.filling = "fill" + enemy.height = get_value(args, "height", 80) + enemy.width = get_value(args, "width", 80) + enemy.min_speed = 100 + enemy.max_speed = 200 + enemy.move = get_value(args, "move", move_enemy) + enemy.object_type = object_type + enemy.rotation = get_value(args, "rotation", 0) + enemy.rotation_dir = 0 + enemy.round = 0 + enemy.update = get_value(args, "update", update) + enemy.x = get_value(args, "x", 0) + enemy.x_dir = get_value(args, "x_dir", 1) + enemy.y = get_value(args, "y", 0) + enemy.y_dir = get_value(args, "y_dir", 1) + + enemy.shape = c.makeRect(enemy.x, enemy.y, enemy.width, enemy.height) + enemy.x_speed = get_value(args, "x_speed", + math.random(enemy.min_speed, enemy.max_speed)) + enemy.y_speed = get_value(args, "y_speed", + math.random(enemy.min_speed, enemy.max_speed)) + return enemy + elseif object_type == "shot" then + local shot = {} + shot.draw = get_value(args, "draw", draw_ellipse) + shot.filling = "fill" + shot.move = get_value(args, "move", move_shot) + shot.object_type = object_type + shot.radius = get_value(args, "radius", 8) + shot.rotation = get_value(args, "rotation", 0) + shot.round = 1 + shot.speed = get_value(args, "speed", 400) + shot.update = get_value(args, "update", update) + shot.x = get_value(args, "x", 200) + shot.x_dir = 1 + shot.y = get_value(args, "y", 200) + shot.y_dir = 1 + + shot.height = shot.radius * 2 + shot.width = shot.radius * 2 + shot.shape = c.makeCircle(shot.x, shot.y, shot.radius) + shot.x_speed = shot.speed * math.cos(shot.rotation) + shot.y_speed = shot.speed * math.sin(shot.rotation) + return shot + end +end + +-- Creation functions + +function init_objects() + player = spawn("player", {height = 70}) + enemies = {} + shots = {} + + start_time = love.timer.getTime() +end + +function spawn_shot() + local args = {} + args.x = player.x + args.y = player.y + args.rotation = player.rotation - math.pi/2 + shots[#shots + 1] = spawn("shot", args) +end + +function spawn_enemy() + local args = {} + + -- to only spawn on borders + math.randomseed(os.time()) + wall_or_roof = random_of_two(0, 1) + left_or_right = random_of_two(0, 1) + --- wall + if wall_or_roof == 0 then + args.x = random_of_two(0, win_w) + args.y = math.random(win_h) + --- roof + else + args.x = math.random(win_w) + args.y = random_of_two(0, win_h) + end + + -- to move towards the other end of the screen + if args.x < win_w/2 then + args.x_dir = 1 + else + args.x_dir = -1 + end + + if args.y < win_h/2 then + args.y_dir = 1 + else + args.y_dir = -1 + end + + return spawn("enemy", args) +end + +function spawn_invinc_enemy() + local enemy = spawn_enemy() + enemy.object_type = "invinc" + enemy.filling = "line" + enemy.x_speed = enemy.x_speed * 2 + enemy.y_speed = enemy.y_speed * 2 + return enemy +end + +function update(entity) end + +function update_other_objects(dt) + to_remove = {} + for i, shot in pairs(shots) do + if shot:move(dt) == false then + to_remove[#to_remove + 1] = i + end + shot:update() + end + for i, num in pairs(to_remove) do + table.remove(shots, i) + end + if enemies_spawned < math.floor(game_time / enemy_spawn_interval) then + -- e.g. game_time = 6.01 => game_time / enemy_interval = 3.005 + -- so if enemies_spawned == 2 then spawn + sound.enemy_spawn:play() + enemies_spawned = enemies_spawned + 1 + if game_time > 60 then + enemies[#enemies + 1] = random_of_two(spawn_enemy(), spawn_invinc_enemy()) + else + enemies[#enemies + 1] = spawn_enemy() + end + end + to_remove = {} + for i, enemy in pairs(enemies) do + if enemy:move(dt) == false then + to_remove[#to_remove + 1] = i + end + enemy:update() + end + for i, num in pairs(to_remove) do + table.remove(enemies, i) + end +end + diff --git a/functions.lua b/functions.lua deleted file mode 100644 index 626bea7..0000000 --- a/functions.lua +++ /dev/null @@ -1,116 +0,0 @@ -require("values") - -function write_centered(text, font, y, win) - local w = font:getWidth(text) - love.graphics.setFont(font) - love.graphics.print(text, (win - w) / 2, y) -end - -function write_right(text, font, win_w, margin) - local w = font:getWidth(text) - love.graphics.setFont(font) - love.graphics.print(text, win_w - w - 2*margin, margin) -end - -function write(text, font, x, y) - local w = font:getWidth(text) - love.graphics.setFont(font) - love.graphics.print(text, x, y) -end - -function time_to_string(time) - time = math.ceil((time * 100)) / 100 - local time = ""..time - if #time == 1 then - return time..".00" - elseif #time== 3 then - return time.."0" - else - return time - end -end - --- Used by modes to move player - -function reset_rotations() - player.rotation_dir = 0 - if pressed_keys.right == "rot" then - pressed_keys.right = "none" - move_on_key(key_right) - end - if pressed_keys.left == "rot" then - pressed_keys.left = "none" - move_on_key(key_left) - end -end - -function reset_movements() - player.x_dir = 0 - player.y_dir = 0 - if pressed_keys.right == "move" then - pressed_keys.right = "none" - rotate_on_key(key_right) - end - if pressed_keys.left == "move" then - pressed_keys.left = "none" - rotate_on_key(key_left) - end - if pressed_keys.down == "move" then - pressed_keys.down = "none" - end - if pressed_keys.up == "move" then - pressed_keys.up = "none" - end -end - -function rotate_on_key(key) - if key == key_right and pressed_keys.right ~= "move" then - player.rotation_dir = player.rotation_dir + 1 - pressed_keys.right = "rot" - elseif key == key_left and pressed_keys.left ~= "move" then - player.rotation_dir = player.rotation_dir - 1 - pressed_keys.left = "rot" - end -end - -function move_on_key(key) - if key == key_right and pressed_keys.right ~= "rot" then - player.x_dir = player.x_dir + 1 - pressed_keys.right = "move" - elseif key == key_left and pressed_keys.left ~= "rot" then - player.x_dir = player.x_dir - 1 - pressed_keys.left = "move" - elseif key == key_down and pressed_keys.down ~= "rot" then - player.y_dir = player.y_dir + 1 - pressed_keys.down = "move" - elseif key == key_up and pressed_keys.up ~= "rot" then - player.y_dir = player.y_dir - 1 - pressed_keys.up = "move" - end -end - -function stop_rotate_on_key(key) - if key == key_right and pressed_keys.right == "rot" then - player.rotation_dir = player.rotation_dir - 1 - pressed_keys.right = "none" - elseif key == key_left and pressed_keys.left == "rot" then - player.rotation_dir = player.rotation_dir + 1 - pressed_keys.left = "none" - end -end - -function stop_move_on_key(key) - if key == key_right and pressed_keys.right == "move" then - player.x_dir = player.x_dir - 1 - pressed_keys.right = "none" - elseif key == key_left and pressed_keys.left == "move" then - player.x_dir = player.x_dir + 1 - pressed_keys.left = "none" - elseif key == key_down and pressed_keys.down == "move" then - player.y_dir = player.y_dir - 1 - pressed_keys.down = "none" - elseif key == key_up and pressed_keys.up == "move" then - player.y_dir = player.y_dir + 1 - pressed_keys.up = "none" - end -end diff --git a/collision.lua b/lib/collision.lua similarity index 92% rename from collision.lua rename to lib/collision.lua index 1b33ed2..e85c4a4 100644 --- a/collision.lua +++ b/lib/collision.lua @@ -56,11 +56,11 @@ function collision.collisionTest(a, b) circle = a end local nearestX = math.clamp(circle.x, - rect.x, - rect.x + rect.width) + rect.x, + rect.x + rect.width) local nearestY = math.clamp(circle.y, - rect.y, - rect.y + rect.height) + rect.y, + rect.y + rect.height) love.graphics.setColor(1, 1, 1) love.graphics.circle("fill", nearestX, nearestY, 10) local diffX = circle.x - nearestX @@ -70,8 +70,4 @@ function collision.collisionTest(a, b) return dSq < rSq end -function math.clamp(lo, val, hi) - return math.min(math.max(lo, val), hi) -end - return collision diff --git a/lib/graphics.lua b/lib/graphics.lua new file mode 100644 index 0000000..13201ac --- /dev/null +++ b/lib/graphics.lua @@ -0,0 +1,72 @@ +function draw_shot(shots) + for i, shot in pairs(shots) do + shot:draw() + end +end + +function draw_enemies(enemies) + for i, enemy in pairs(enemies) do + enemy:draw() + end +end + +-- Draw shapes +function draw_rectangle(object) + love.graphics.push() + love.graphics.translate(object.x, object.y) + love.graphics.rotate(object.rotation) + function sub_rectangle(x, y, w, h) + love.graphics.rectangle(object.filling, x, y, w, h) + end + draw_subs(object, sub_rectangle) + love.graphics.pop() +end + +function draw_single_rectangle(object) + love.graphics.push() + love.graphics.translate(object.x, object.y) + love.graphics.rotate(object.rotation) + love.graphics.rectangle(object.filling, - (object.width / 2), - (object.height / 2), + object.width, object.height) + love.graphics.pop() +end + +function draw_ellipse(object) + love.graphics.push() + love.graphics.translate(object.x, object.y) + love.graphics.rotate(object.rotation) + function sub_ellipse(x, y, w, h) + love.graphics.rectangle(object.filling, x, y, w, h, + object.width / 2, object.height / 2) + end + draw_subs(object, sub_ellipse) + love.graphics.pop() +end + +function draw_triangle(object) + love.graphics.push() + love.graphics.translate(object.x, object.y) + love.graphics.rotate(object.rotation) + local w0 = object.width / 2 + local h0 = object.height / 2 + for hurt = player.curr_damage, player.max_damage do + local s = 1 - hurt / player.max_damage + local diff = 1.1 + vertices = {0, - h0 + diff*s*h0, + w0 - diff*s*w0, h0 - s*h0, + -w0 + diff*s*w0, h0 - s*h0} + love.graphics.polygon(object.filling, vertices) + end + love.graphics.pop() +end + +function draw_subs(object, func) + local x0 = - (object.width / 2) + local y0 = - (object.height / 2) + local w0 = object.width + local h0 = object.height + for hurt = player.curr_damage, player.max_damage do + local p = hurt / player.max_damage + func(x0 + w0/2 * (1-p), y0 + h0/2 * (1-p), w0 * p, h0 * p) + end +end diff --git a/lib/helpers.lua b/lib/helpers.lua new file mode 100644 index 0000000..ef14c34 --- /dev/null +++ b/lib/helpers.lua @@ -0,0 +1,19 @@ +function get_value(table, arg, default) + if table[arg] ~= nil then return table[arg] else return default end +end + +function rotate(object, dt) + object.rotation = object.rotation + object.rotation_dir * object.rotation_speed * dt +end + +function random_of_two(a, b) + if math.random(0, 1) == 0 then + return a + else + return b + end +end + +math.clamp = function(lo, val, hi) + return math.min(math.max(lo, val), hi) +end diff --git a/slam.lua b/lib/slam.lua similarity index 100% rename from slam.lua rename to lib/slam.lua diff --git a/lib/sound.lua b/lib/sound.lua new file mode 100644 index 0000000..51067f3 --- /dev/null +++ b/lib/sound.lua @@ -0,0 +1,29 @@ +require("lib/slam") + +sound = {} +music = {} + +local sound_path = "res/sound/" + +-- SOUND EFFECTS +sound.enemy_hit = love.audio.newSource(sound_path.."enemy_hit.wav", "static") +sound.enemy_spawn = love.audio.newSource({ + sound_path.."enemy_spawn_long.wav", + sound_path.."enemy_spawn_short.wav" +}, "static") +sound.player_hit = love.audio.newSource({ + sound_path.."hit_short.wav", + sound_path.."hit_long.wav" +}, "static") +sound.shoot = love.audio.newSource(sound_path.."shot.wav", "static") + +-- MUSIC +music.main_music_started = false +music.bergakung = love.audio.newSource(sound_path.."bergakung.wav", "stream") +music.penta = love.audio.newSource(sound_path.."penta.wav", "stream") +music.western = love.audio.newSource(sound_path.."western.wav", "stream") + +music.bergakung:setLooping(true) +music.penta:setLooping(true) +music.western:setLooping(false) + diff --git a/lib/text.lua b/lib/text.lua new file mode 100644 index 0000000..c9ff98e --- /dev/null +++ b/lib/text.lua @@ -0,0 +1,41 @@ +local alphabet = "abcdefghijklmnopqrstuvwxyz0123456789" +is_character = function(key) return string.find(alphabet, key) end + +local yf_font = "res/yf16font.ttf" +big_font = love.graphics.newFont(yf_font, 55) +medium_font = love.graphics.newFont(yf_font, 35) +small_font = love.graphics.newFont(yf_font, 15) +small_font:setFilter("nearest", "nearest") +medium_font:setFilter("nearest", "nearest") +big_font:setFilter("nearest", "nearest") + +function write_centered(text, font, y, win_w) + local w = font:getWidth(text) + love.graphics.setFont(font) + love.graphics.print(text, (win_w - w) / 2, y) +end + +function write_right(text, font, win_w, margin) + local w = font:getWidth(text) + love.graphics.setFont(font) + love.graphics.print(text, win_w - w - 2*margin, margin) +end + +function write(text, font, x, y) + local w = font:getWidth(text) + love.graphics.setFont(font) + love.graphics.print(text, x, y) +end + +function time_to_string(time) + time = math.ceil(time * 100) / 100 + local time = ""..time + if #time == 1 then + return time..".00" + elseif #time== 3 then + return time.."0" + else + return time + end +end + diff --git a/main.lua b/main.lua index aab70d7..a105343 100644 --- a/main.lua +++ b/main.lua @@ -1,19 +1,36 @@ -collision = require("collision") +collision = require("lib/collision") +require("entities") +require("lib/sound") +require("lib/text") require("modes") -require("objects") -require("functions") -require("values") +require("movement") function love.load() + win_w = 800 + win_h = 600 + love.window.setMode(win_w, win_h, {resizable=false, vsync=true, highdpi=true}) + hs_holder = "A. Nonymous" + highscore = 0 + + key_right = "right" + key_left = "left" + key_up = "up" + key_down = "down" + key_see = "1" + key_move = "2" + key_attack = "3" + + -- "none", "rot", "move" + pressed_keys = {left = "none", right = "none", up = "none", down = "none"} + modes = {mode1 = mode_see, mode2 = mode_move, mode3 = mode_attack} mode = "mode"..key_see state = "start" -- or "game_running" or "take_name" or "dead" or "info" - music_bergakung:play() - music_bergakung:setLooping(true) + music.bergakung:play() end function love.keypressed(key) @@ -21,9 +38,9 @@ function love.keypressed(key) if key == "escape" then state = "start" mode = "mode"..key_see - music_penta:stop() - music_western:stop() - music_bergakung:play() + music.bergakung:play() + music.penta:stop() + music.western:stop() end -- Modes if key == key_see or key == key_move or key == key_attack then @@ -48,18 +65,19 @@ function love.keypressed(key) if key == "escape" then state = "start" elseif key == "space" or key == "return" then - music_bergakung:stop() + music.bergakung:stop() start_game() end elseif state == "death" then - if key == "space" or key == "return"or key == "escape" then + if key == "space" or key == "return" or key == "escape" then state = "start" end elseif state == "take_name" then if key == "return" or key == "escape" then + music.bergakung:play() state = "start" end if key == "backspace" and #hs_holder > 0 then @@ -67,7 +85,7 @@ function love.keypressed(key) hs_holder = hs_holder:sub(1, #hs_holder - 1) end end - if string.find(alphabet, key) then + if is_character(key) then if #hs_holder < 20 then if love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift") then hs_holder = hs_holder..string.upper(key) @@ -90,19 +108,19 @@ end function love.update(dt) if state == "game_running" then game_time = game_time + dt - if game_time > 6 and not game_music_started then - game_music_started = true - music_penta:play() - music_penta:setLooping(true) - end + if game_time > 6 and not music.main_music_started then + music.main_music_started = true + music.penta:play() + music.penta:setLooping(true) + end modes[mode].func_update(dt) -- check if an enemy has hit the player for i, enemy in pairs(enemies) do if collision.collisionTest(player.shape, enemy.shape) then - sound_player_hit:play() - curr_damage = curr_damage + 1 + sound.player_hit:play() + player.curr_damage = player.curr_damage + 1 table.remove(enemies, i) end end @@ -112,10 +130,10 @@ function love.update(dt) for j, enemy in pairs(enemies) do if collision.collisionTest(shot.shape, enemy.shape) then if enemy.object_type ~= "invinc" then - if curr_damage > 1 then - curr_damage = curr_damage - 1 + if player.curr_damage > 1 then + player.curr_damage = player.curr_damage - 1 end - sound_enemy_hit:play() + sound.enemy_hit:play() table.remove(shots, i) table.remove(enemies, j) end @@ -123,7 +141,7 @@ function love.update(dt) end end - if curr_damage > max_damage then + if player.curr_damage > player.max_damage then lose_game() end end @@ -148,13 +166,15 @@ function start_game() init_objects() game_time = 0 - reset_state_values() - music_western:play() + enemies_spawned = 0 + last_shot = 0 + music.western:play() end function lose_game() mode = "mode"..key_see - music_penta:stop() + music.penta:stop() + music.main_music_started = false highscore = math.max(highscore, game_time) if highscore == game_time then state = "take_name" @@ -195,9 +215,10 @@ function show_startscreen() love.graphics.rectangle("line", x - dist, y, w, h, w/2, h/2) love.graphics.rectangle("line", x, y, w, h, 0) - love.graphics.polygon("line", {x + dist, y, - x + dist, y + h, - x + w + dist, y + h/2}) + love.graphics.polygon("line", { + x + dist, y, + x + dist, y + h, + x + w + dist, y + h/2}) end function show_infoscreen() @@ -210,25 +231,26 @@ function show_infoscreen() write_centered("Shift between modes:", medium_font, 0.3*win_h / 4, win_w) write_centered("Press", small_font, y - 2.1*w, win_w) - write("1", small_font, x - 1.1*w, y - 1.4*w) - write_centered("2", small_font, y - 1.4*w, win_w) - write("3", small_font, x + 1.8*w, y - 1.4*w) + write("1", small_font, x - 1.1*w, y - 1.4*w) + write_centered("2", small_font, y - 1.4*w, win_w) + write("3", small_font, x + 1.8*w, y - 1.4*w) write_centered("to", small_font, y - dist + 0.7*w, win_w) - write("see", small_font, x - 1.3*w, y + 0.9*w) - write_centered("move", small_font, y + 0.9*w, win_w) - write("shoot", small_font, x + 1.5*w, y + 0.9*w) + write("see", small_font, x - 1.3*w, y + 0.9*w) + write_centered("move", small_font, y + 0.9*w, win_w) + write("shoot", small_font, x + 1.5*w, y + 0.9*w) --write_centered("with", small_font, y + 1.6*w, win_w) - write_centered("< > to rotate in see and shoot mode", small_font, y + 2.2*w, win_w) - write_centered("< ^ ˇ > to move in move mode", small_font, y + 2.8*w, win_w) + write_centered("< > to rotate in see and shoot mode", small_font, y + 2.2*w, win_w) + write_centered("< ^ ˇ > to move in move mode", small_font, y + 2.8*w, win_w) love.graphics.rectangle("line", x - dist, y, w, h, w/2, h/2) love.graphics.rectangle("line", x, y, w, h, 0) - love.graphics.polygon("line", {x + dist, y, - x + dist, y + h, - x + w + dist, y + h/2}) + love.graphics.polygon("line", { + x + dist, y, + x + dist, y + h, + x + w + dist, y + h/2}) write_centered("Press to start game (and shoot)!", small_font, 3.2*win_h / 4, win_w) end diff --git a/modes.lua b/modes.lua index a2d28d7..7400316 100644 --- a/modes.lua +++ b/modes.lua @@ -1,18 +1,19 @@ -require("objects") -require("functions") +require("entities") +require("lib/graphics") +require("movement") mode_see = { func_draw = function() draw_ellipse(player) - draw_shot() - draw_enemies() + draw_shot(shots) + draw_enemies(enemies) end, func_key_pressed = rotate_on_key, func_key_released = stop_rotate_on_key, func_update = function(dt) reset_movements() player:rotate(dt) - update(player) + player:update() update_other_objects(dt) end, func_shoot = function() @@ -28,80 +29,31 @@ mode_move = { func_update = function(dt) reset_rotations() player:move(dt) - update(player) + player:update() update_other_objects(dt) end, func_shoot = function() end } -last_shot = 0 - mode_attack = { func_draw = function() draw_triangle(player) - draw_shot() + draw_shot(shots) end, func_key_pressed = rotate_on_key, func_key_released = stop_rotate_on_key, func_update = function(dt) reset_movements() - rotate(player, dt) - update(player) + player:rotate(dt) + player:update() update_other_objects(dt) end, func_shoot = function() if game_time - last_shot > shot_interval then last_shot = game_time spawn_shot() - sound_shoot:play() + sound.shoot:play() end end } - -function draw_shot() - for i, shot in pairs(shots) do - shot:draw() - end -end - -function draw_enemies() - for i, enemy in pairs(enemies) do - enemy:draw() - end -end - -function update_other_objects(dt) - to_remove = {} - for i, shot in pairs(shots) do - if shot:move(dt) == false then - to_remove[#to_remove + 1] = i - end - shot:update() - end - for i, num in pairs(to_remove) do - table.remove(shots, i) - end - if enemies_spawned < math.floor(game_time / enemy_spawn_interval) then - -- e.g. game_time = 6.01 => game_time / enemy_interval = 3.005 - -- so if enemies_spawned == 2 then spawn - sound_enemy_spawn:play() - enemies_spawned = enemies_spawned + 1 - if game_time > 60 then - enemies[#enemies + 1] = random_of_two(spawn_enemy(), spawn_invinc_enemy()) - else - enemies[#enemies + 1] = spawn_enemy() - end - end - to_remove = {} - for i, enemy in pairs(enemies) do - if enemy:move(dt) == false then - to_remove[#to_remove + 1] = i - end - enemy:update() - end - for i, num in pairs(to_remove) do - table.remove(enemies, i) - end -end - diff --git a/movement.lua b/movement.lua new file mode 100644 index 0000000..77e5e7b --- /dev/null +++ b/movement.lua @@ -0,0 +1,126 @@ +function move_player(player, dt) + if (player.x + player.x_dir * player.x_speed * dt) + player.width/2 > win_w then + player.x = win_w - player.width/2 + return false + elseif player.x + player.x_dir * player.x_speed * dt < player.width/2 then + player.x = player.width/2 + return false + end + + if (player.y + player.y_dir * player.y_speed * dt) + player.height/2 > win_h then + -- TODO player gets "stuck" here + return false + elseif player.y + player.y_dir * player.y_speed * dt < player.height/2 then + player.y = player.height/2 + return false + end + move(player, dt) + return true +end + +function move_shot(shot, dt) + if shot.x - shot.radius > win_w or shot.x + shot.radius < 0 or + shot.y - shot.radius > win_h or shot.y + shot.radius < 0 then return false end + move(shot, dt) + return true + end + + function move_enemy(enemy, dt) + if enemy.x - enemy.width*2 > win_w or + enemy.y - enemy.height*2 > win_h or + enemy.x + enemy.width*2 < 0 or + enemy.y + enemy.height*2 < 0 then return false end + move(enemy, dt) + return true + end + + function move(object, dt) + -- if object.canMove() + object.x = object.x + object.x_dir * object.x_speed * dt + object.y = object.y + object.y_dir * object.y_speed * dt + + c.moveTo(object.shape, object.x, object.y) + end + + function reset_rotations() + player.rotation_dir = 0 + if pressed_keys.right == "rot" then + pressed_keys.right = "none" + move_on_key(key_right) + end + if pressed_keys.left == "rot" then + pressed_keys.left = "none" + move_on_key(key_left) + end + end + + function reset_movements() + player.x_dir = 0 + player.y_dir = 0 + if pressed_keys.right == "move" then + pressed_keys.right = "none" + rotate_on_key(key_right) + end + if pressed_keys.left == "move" then + pressed_keys.left = "none" + rotate_on_key(key_left) + end + if pressed_keys.down == "move" then + pressed_keys.down = "none" + end + if pressed_keys.up == "move" then + pressed_keys.up = "none" + end + end + + function rotate_on_key(key) + if key == key_right and pressed_keys.right ~= "move" then + player.rotation_dir = player.rotation_dir + 1 + pressed_keys.right = "rot" + elseif key == key_left and pressed_keys.left ~= "move" then + player.rotation_dir = player.rotation_dir - 1 + pressed_keys.left = "rot" + end + end + + function move_on_key(key) + if key == key_right and pressed_keys.right ~= "rot" then + player.x_dir = player.x_dir + 1 + pressed_keys.right = "move" + elseif key == key_left and pressed_keys.left ~= "rot" then + player.x_dir = player.x_dir - 1 + pressed_keys.left = "move" + elseif key == key_down and pressed_keys.down ~= "rot" then + player.y_dir = player.y_dir + 1 + pressed_keys.down = "move" + elseif key == key_up and pressed_keys.up ~= "rot" then + player.y_dir = player.y_dir - 1 + pressed_keys.up = "move" + end + end + + function stop_rotate_on_key(key) + if key == key_right and pressed_keys.right == "rot" then + player.rotation_dir = player.rotation_dir - 1 + pressed_keys.right = "none" + elseif key == key_left and pressed_keys.left == "rot" then + player.rotation_dir = player.rotation_dir + 1 + pressed_keys.left = "none" + end + end + + function stop_move_on_key(key) + if key == key_right and pressed_keys.right == "move" then + player.x_dir = player.x_dir - 1 + pressed_keys.right = "none" + elseif key == key_left and pressed_keys.left == "move" then + player.x_dir = player.x_dir + 1 + pressed_keys.left = "none" + elseif key == key_down and pressed_keys.down == "move" then + player.y_dir = player.y_dir - 1 + pressed_keys.down = "none" + elseif key == key_up and pressed_keys.up == "move" then + player.y_dir = player.y_dir + 1 + pressed_keys.up = "none" + end + end diff --git a/objects.lua b/objects.lua deleted file mode 100644 index 0ce253b..0000000 --- a/objects.lua +++ /dev/null @@ -1,262 +0,0 @@ -c = require("collision") -require("values") - -function get_value(table, arg, default) - if table[arg] ~= nil then return table[arg] else return default end -end - --- Spawn object -function spawn(object_type, args) - if object_type == "player" then - local player = {} - player.object_type = object_type - player.x = get_value(args, "x", win_w / 2) - player.y = get_value(args, "y", win_h / 2) - player.x_speed = get_value(args, "x_speed", 300) - player.y_speed = get_value(args, "y_speed", 300) - player.x_dir = 0 - player.y_dir = 0 - player.height = get_value(args, "height", 60) - player.width = get_value(args, "width", 60) - player.rotation = 0 - player.rotation_dir = 0 - player.round = 0 - player.filling = "line" - player.shape = c.makeRect(player.x, player.y, player.width, player.height) - player.move = get_value(args, "move", move_player) - player.rotate = get_value(args, "rotate", rotate) - player.update = get_value(args, "update", update) - player.draw = get_value(args, "draw", draw_rectangle) - return player - elseif object_type == "enemy" then - local enemy = {} - enemy.object_type = object_type - enemy.x = get_value(args, "x", 0) - enemy.y = get_value(args, "y", 0) - enemy.x_speed = get_value(args, "x_speed", 100) - enemy.y_speed = get_value(args, "y_speed", 100) - enemy.x_dir = get_value(args, "x_dir", 1) - enemy.y_dir = get_value(args, "y_dir", 1) - enemy.height = get_value(args, "height", 80) - enemy.width = get_value(args, "width", 80) - enemy.rotation = get_value(args, "rotation", 0) - enemy.rotation_dir = 0 - enemy.round = 0 - enemy.filling = "fill" - enemy.shape = c.makeRect(enemy.x, enemy.y, enemy.width, enemy.height) - enemy.draw = get_value(args, "draw", draw_single_rectangle) - enemy.move = get_value(args, "move", move_enemy) - enemy.update = get_value(args, "update", update) - return enemy - elseif object_type == "shot" then - local shot = {} - shot.object_type = object_type - shot.x = get_value(args, "x", 200) - shot.y = get_value(args, "y", 200) - shot.x_dir = 1 - shot.y_dir = 1 - shot.rotation = get_value(args, "rotation", 0) - shot.speed = get_value(args, "speed", 400) - shot.x_speed = shot.speed * math.cos(shot.rotation) - shot.y_speed = shot.speed * math.sin(shot.rotation) - shot.radius = get_value(args, "radius", 8) - shot.width = shot.radius * 2 - shot.height = shot.radius * 2 - shot.round = 1 - shot.filling = "fill" - shot.shape = c.makeCircle(shot.x, shot.y, shot.radius) - shot.move = get_value(args, "move", move_shot) - shot.update = get_value(args, "update", update) - shot.draw = get_value(args, "draw", draw_ellipse) - return shot - end -end - --- Creation functions - -function init_objects() - player = spawn("player", {height = 70}) - curr_damage = 1 - - enemies = {} - start_time = love.timer.getTime() - min_speed = 100 - max_speed = 200 - - shots = {} -end - -function spawn_shot() - local args = {} - args.x = player.x - args.y = player.y - args.rotation = player.rotation - math.pi / 2 - shots[#shots + 1] = spawn("shot", args) -end - -function spawn_enemy() - local args = {} - - -- to only spawn on borders - math.randomseed(os.time()) - wall_or_roof = random_of_two(0, 1) - left_or_right = random_of_two(0, 1) - --- wall - if wall_or_roof == 0 then - args.x = random_of_two(0, win_w) - args.y = math.random(win_h) - --- roof - else - args.x = math.random(win_w) - args.y = random_of_two(0, win_h) - end - - -- to move towards the other end of the screen - if args.x < win_w / 2 then - args.x_dir = 1 - else - args.x_dir = -1 - end - - if args.y < win_h / 2 then - args.y_dir = 1 - else - args.y_dir = -1 - end - - args.x_speed = math.random(min_speed, max_speed) -- TODO: Change max/ min when "levelup" - args.y_speed = math.random(min_speed, max_speed) - - return spawn("enemy", args) -end - -function spawn_invinc_enemy() - local enemy = spawn_enemy() - enemy.object_type = "invinc" - enemy.filling = "line" - enemy.x_speed = enemy.x_speed * 2 - enemy.y_speed = enemy.y_speed * 2 - return enemy -end - --- Draw functions -function draw_rectangle(object) - love.graphics.push() - love.graphics.translate(object.x, object.y) - love.graphics.rotate(object.rotation) - function sub_rectangle(x, y, w, h) - love.graphics.rectangle(object.filling, x, y, w, h) - end - draw_subs(object, sub_rectangle) - love.graphics.pop() -end - -function draw_single_rectangle(object) - love.graphics.push() - love.graphics.translate(object.x, object.y) - love.graphics.rotate(object.rotation) - love.graphics.rectangle(object.filling, - (object.width / 2), - (object.height / 2), object.width, object.height) - love.graphics.pop() -end - -function draw_ellipse(object) - love.graphics.push() - love.graphics.translate(object.x, object.y) - love.graphics.rotate(object.rotation) - function sub_ellipse(x, y, w, h) - love.graphics.rectangle(object.filling, x, y, w, h, - object.width / 2, object.height / 2) - end - draw_subs(object, sub_ellipse) - love.graphics.pop() -end - -function draw_triangle(object) - love.graphics.push() - love.graphics.translate(object.x, object.y) - love.graphics.rotate(object.rotation) - local w0 = object.width / 2 - local h0 = object.height / 2 - for hurt = curr_damage, max_damage do - local s = 1 - hurt / max_damage - local diff = 1.1 - vertices = {0, - h0 + diff*s*h0, - w0 - diff*s*w0, h0 - s*h0, - - w0 + diff*s*w0, h0 - s*h0} - love.graphics.polygon(object.filling, vertices) - end - love.graphics.pop() -end - -function draw_subs(object, func) - local x0 = - (object.width / 2) - local y0 = - (object.height / 2) - local w0 = object.width - local h0 = object.height - for hurt = curr_damage, max_damage do - local p = hurt / max_damage - func(x0 + w0/2 * (1-p), y0 + h0/2 * (1-p), w0 * p, h0 * p) - end -end - --- Update functions - -function rotate(object, dt) - object.rotation = object.rotation + object.rotation_dir * rotation_speed * dt -end - -function move_player(player, dt) - if (player.x + player.x_dir * player.x_speed * dt) + player.width / 2 > win_w then - player.x = win_w - player.width / 2 - return false - elseif player.x + player.x_dir * player.x_speed * dt < player.width / 2 then - player.x = player.width / 2 - return false - end - - if (player.y + player.y_dir * player.y_speed * dt) + player.height / 2 > win_h then - -- TODO player gets "stuck" here - return false - elseif player.y + player.y_dir * player.y_speed * dt < player.height / 2 then - player.y = player.height / 2 - return false - end - move(player, dt) - return true -end - -function move_shot(shot, dt) - if shot.x - shot.radius > win_w or shot.x + shot.radius < 0 or - shot.y - shot.radius > win_h or shot.y + shot.radius < 0 then return false end - move(shot, dt) - return true -end - -function move_enemy(enemy, dt) - if enemy.x - enemy.width * 2 > win_w or - enemy.y - enemy.height * 2 > win_h or - enemy.x + enemy.width * 2 < 0 or - enemy.y + enemy.height * 2 < 0 then return false end - move(enemy, dt) - return true -end - -function move(object, dt) - -- if object.canMove() - object.x = object.x + object.x_dir * object.x_speed * dt - object.y = object.y + object.y_dir * object.y_speed * dt - - c.moveTo(object.shape, object.x, object.y) -end - -function update(object) - -end - -function random_of_two(a, b) - if math.random(0, 1) == 0 then - return a - else - return b - end -end diff --git a/screenshots/screenshot_infopage.png b/res/screenshots/screenshot_infopage.png similarity index 100% rename from screenshots/screenshot_infopage.png rename to res/screenshots/screenshot_infopage.png diff --git a/screenshots/screenshot_titlepage.png b/res/screenshots/screenshot_titlepage.png similarity index 100% rename from screenshots/screenshot_titlepage.png rename to res/screenshots/screenshot_titlepage.png diff --git a/sound/bad.wav b/res/sound/bad.wav similarity index 100% rename from sound/bad.wav rename to res/sound/bad.wav diff --git a/sound/bergakung.wav b/res/sound/bergakung.wav similarity index 100% rename from sound/bergakung.wav rename to res/sound/bergakung.wav diff --git a/sound/enemy_hit.wav b/res/sound/enemy_hit.wav similarity index 100% rename from sound/enemy_hit.wav rename to res/sound/enemy_hit.wav diff --git a/sound/enemy_spawn_long.wav b/res/sound/enemy_spawn_long.wav similarity index 100% rename from sound/enemy_spawn_long.wav rename to res/sound/enemy_spawn_long.wav diff --git a/sound/enemy_spawn_short.wav b/res/sound/enemy_spawn_short.wav similarity index 100% rename from sound/enemy_spawn_short.wav rename to res/sound/enemy_spawn_short.wav diff --git a/sound/hit_long.wav b/res/sound/hit_long.wav similarity index 100% rename from sound/hit_long.wav rename to res/sound/hit_long.wav diff --git a/sound/hit_short.wav b/res/sound/hit_short.wav similarity index 100% rename from sound/hit_short.wav rename to res/sound/hit_short.wav diff --git a/sound/melody.wav b/res/sound/melody.wav similarity index 100% rename from sound/melody.wav rename to res/sound/melody.wav diff --git a/sound/mode1.wav b/res/sound/mode1.wav similarity index 100% rename from sound/mode1.wav rename to res/sound/mode1.wav diff --git a/sound/mode3.wav b/res/sound/mode3.wav similarity index 100% rename from sound/mode3.wav rename to res/sound/mode3.wav diff --git a/sound/mode4.wav b/res/sound/mode4.wav similarity index 100% rename from sound/mode4.wav rename to res/sound/mode4.wav diff --git a/sound/move2.wav b/res/sound/move2.wav similarity index 100% rename from sound/move2.wav rename to res/sound/move2.wav diff --git a/sound/noise.wav b/res/sound/noise.wav similarity index 100% rename from sound/noise.wav rename to res/sound/noise.wav diff --git a/sound/penta.wav b/res/sound/penta.wav similarity index 100% rename from sound/penta.wav rename to res/sound/penta.wav diff --git a/sound/shot.wav b/res/sound/shot.wav similarity index 100% rename from sound/shot.wav rename to res/sound/shot.wav diff --git a/sound/western.wav b/res/sound/western.wav similarity index 100% rename from sound/western.wav rename to res/sound/western.wav diff --git a/yf16font.ttf b/res/yf16font.ttf similarity index 100% rename from yf16font.ttf rename to res/yf16font.ttf diff --git a/values.lua b/values.lua deleted file mode 100644 index 535df2a..0000000 --- a/values.lua +++ /dev/null @@ -1,63 +0,0 @@ -require("slam") - --- KEYMAP -alphabet = "abcdefghijklmnopqrstuvwxyz0123456789" - -big_font = love.graphics.newFont("yf16font.ttf", 55) -medium_font = love.graphics.newFont("yf16font.ttf", 35) -small_font = love.graphics.newFont("yf16font.ttf", 15) -small_font:setFilter( "nearest", "nearest" ) -medium_font:setFilter( "nearest", "nearest" ) -big_font:setFilter( "nearest", "nearest" ) - -key_right = "right" -key_left = "left" -key_up = "up" -key_down = "down" -key_see = "1" -key_move = "2" -key_attack = "3" --- "none", "rot", "move" -pressed_keys = {left = "none", right = "none", up = "none", down = "none"} - -rotation_speed = math.pi * 2 -- half a lap per second - -win_w = 800 -win_h = 600 - -hs_holder = "A. Nonymous" -highscore = 0 -max_damage = 4 - -enemy_spawn_interval = 2 -enemies_spawned = 0 - -shot_interval = 1 - -function reset_state_values() - -- reset all state-values (that change every game) - enemies_spawned = 0 - last_shot = 0 -end - -function reset_all_values() - -- reset ALL values (including save-data) -end - --- SOUND EFFECTS -sound_enemy_hit = love.audio.newSource("sound/enemy_hit.wav", "static") -sound_enemy_spawn = love.audio.newSource({ - "sound/enemy_spawn_long.wav", - "sound/enemy_spawn_short.wav" -}, "static") -sound_player_hit = love.audio.newSource({ - "sound/hit_short.wav", - "sound/hit_long.wav" -}, "static") -sound_shoot = love.audio.newSource("sound/shot.wav", "static") - --- MUSIC -main_music_started = false -music_western = love.audio.newSource("sound/western.wav", "stream") -music_bergakung = love.audio.newSource("sound/bergakung.wav", "stream") -music_penta = love.audio.newSource("sound/penta.wav", "stream")