Browse Source

First commit

tags/earlywindows
Madiwka3 3 years ago
commit
87e4b0cc4b
49 changed files with 4495 additions and 0 deletions
  1. +16
    -0
      buttonClutter.lua
  2. +6
    -0
      debuggame.sh
  3. BIN
      entities/background.jpg
  4. +22
    -0
      entities/base/base.lua
  5. BIN
      entities/base/base.png
  6. +11
    -0
      entities/camera/VCAM.lua
  7. +45
    -0
      entities/planet/planet.lua
  8. BIN
      entities/planet/planet1.png
  9. BIN
      entities/planet/planet10.png
  10. BIN
      entities/planet/planet11.png
  11. BIN
      entities/planet/planet12.png
  12. BIN
      entities/planet/planet13.png
  13. BIN
      entities/planet/planet14.png
  14. BIN
      entities/planet/planet15.png
  15. BIN
      entities/planet/planet16.png
  16. BIN
      entities/planet/planet17.png
  17. BIN
      entities/planet/planet18.png
  18. BIN
      entities/planet/planet2.png
  19. BIN
      entities/planet/planet3.png
  20. BIN
      entities/planet/planet4.png
  21. BIN
      entities/planet/planet5.png
  22. BIN
      entities/planet/planet6.png
  23. BIN
      entities/planet/planet7.png
  24. BIN
      entities/planet/planet8.png
  25. BIN
      entities/planet/planet9.png
  26. BIN
      entities/ship/large_red_01.png
  27. +103
    -0
      entities/ship/ship.lua
  28. BIN
      entities/ship/smol_red_01.png
  29. BIN
      entities/trashbin.png
  30. +27
    -0
      explosion.lua
  31. +2505
    -0
      fakemain.lua
  32. BIN
      font.ttf
  33. +134
    -0
      levels/level1.lua
  34. +11
    -0
      levels/menu.lua
  35. +119
    -0
      levels/practice.lua
  36. +22
    -0
      levels/selectlv.lua
  37. +57
    -0
      main.lua
  38. +369
    -0
      src/Camera.lua
  39. +221
    -0
      src/GUI.lua
  40. +94
    -0
      src/class.lua
  41. +17
    -0
      src/dependencies.lua
  42. +39
    -0
      src/fullScreener.lua
  43. +53
    -0
      src/mainMenu.lua
  44. +27
    -0
      src/pongDisplayControl.lua
  45. +272
    -0
      src/push.lua
  46. +121
    -0
      src/ser.lua
  47. +123
    -0
      src/simpleScale.lua
  48. +70
    -0
      src/tick.lua
  49. +11
    -0
      stateMachine.lua

+ 16
- 0
buttonClutter.lua View File

@@ -0,0 +1,16 @@
function buttonClutter()
table.insert(buttons, menu:addButton("Practice",
function()
gameState = "practice"
end))
table.insert(buttons, menu:addButton("Levels",
function()
gameState = "selectlv"
end
))
end
local t=0
function explode(x, y)
t = t+10
love.graphics.circle("fill", x, y, t)
end

+ 6
- 0
debuggame.sh View File

@@ -0,0 +1,6 @@
rm game.love
rm game.zip
zip -r game *
mv game.zip game.love
love game.love
rm game.love

BIN
entities/background.jpg View File

Before After
Width: 1920  |  Height: 1600  |  Size: 367 KiB

+ 22
- 0
entities/base/base.lua View File

@@ -0,0 +1,22 @@
base = Class{}

G = 6.67e-5

function base:init(x, y)
self.x = x
self.y = y
self.image = love.graphics.newImage("entities/base/base.png")
self.w = self.image:getWidth()
self.h = self.image:getHeight()
end

function base:update(dt)
local distanceToShip = math.sqrt((firstShip.x - self.x)^2 + (firstShip.y - self.y)^2)
if distanceToShip < self.w/2 then
reachedGoal = true
end
end

function base:draw()
love.graphics.draw(self.image, self.x, self.y, 0, 1, 1, self.w/2, self.w/2)
end

BIN
entities/base/base.png View File

Before After
Width: 48  |  Height: 48  |  Size: 2.1 KiB

+ 11
- 0
entities/camera/VCAM.lua View File

@@ -0,0 +1,11 @@
VCAM = Class{}

function VCAM:init(x, y)
self.x = x
self.y = y
end

function VCAM:update(x,y)
self.x = x
self.y = y
end

+ 45
- 0
entities/planet/planet.lua View File

@@ -0,0 +1,45 @@
planet = Class{}

G = 6.67e-5

function planet:init(x, y, mass, radius, img)
self.x = x
self.y = y
self.mass = mass
self.r = radius
self.w = img:getWidth()
self.image = img
self.angle = 0
self.color = {1,1,1,1}
end

function planet:update(dt)
local distanceToShip = math.sqrt((firstShip.x - self.x)^2 + (firstShip.y - self.y)^2)
local gravitationalAttraction = G*self.mass/(distanceToShip^2)
print((firstShip.x - self.x) .. " " .. (firstShip.y - self.y))
self.angle = math.atan( (firstShip.y - self.y)/ (firstShip.x - self.x))
if self.x < firstShip.x then
self.angle = self.angle - 3.14159
end
--print("Angle is:" .. self.angle*57.29)
self.attractionY = math.sin(self.angle) * gravitationalAttraction
self.attractionX = math.cos(self.angle) * gravitationalAttraction
love.window.setTitle(self.attractionX)
firstShip.dx = firstShip.dx + self.attractionX
firstShip.dy = firstShip.dy + self.attractionY
if distanceToShip < self.w/4 then
shipIsHit = true
end
end

function planet:draw()
--love.graphics.rectangle("fill", firstShip.x, firstShip.y, 30, 30)
love.graphics.push()
love.graphics.translate(firstShip.x, firstShip.y) -- move relative (0,0) to (x,y)
love.graphics.rotate(self.angle) -- rotate coordinate system around relative (0,0) (absolute (x,y))
--love.graphics.rectangle("fill", -(firstShip.x - self.x)/2, -20/2, (firstShip.x - self.x), 20) VECTOR
love.graphics.pop()
love.graphics.setColor(unpack(self.color))
love.graphics.draw(self.image, self.x, self.y, 1.5708, self.r, self.r, self.w/2, self.w/2)
end

BIN
entities/planet/planet1.png View File

Before After
Width: 300  |  Height: 300  |  Size: 76 KiB

BIN
entities/planet/planet10.png View File

Before After
Width: 300  |  Height: 300  |  Size: 83 KiB

BIN
entities/planet/planet11.png View File

Before After
Width: 300  |  Height: 300  |  Size: 88 KiB

BIN
entities/planet/planet12.png View File

Before After
Width: 300  |  Height: 300  |  Size: 84 KiB

BIN
entities/planet/planet13.png View File

Before After
Width: 300  |  Height: 300  |  Size: 79 KiB

BIN
entities/planet/planet14.png View File

Before After
Width: 300  |  Height: 300  |  Size: 84 KiB

BIN
entities/planet/planet15.png View File

Before After
Width: 300  |  Height: 300  |  Size: 84 KiB

BIN
entities/planet/planet16.png View File

Before After
Width: 300  |  Height: 300  |  Size: 80 KiB

BIN
entities/planet/planet17.png View File

Before After
Width: 300  |  Height: 300  |  Size: 89 KiB

BIN
entities/planet/planet18.png View File

Before After
Width: 300  |  Height: 300  |  Size: 93 KiB

BIN
entities/planet/planet2.png View File

Before After
Width: 300  |  Height: 300  |  Size: 79 KiB

BIN
entities/planet/planet3.png View File

Before After
Width: 300  |  Height: 300  |  Size: 81 KiB

BIN
entities/planet/planet4.png View File

Before After
Width: 300  |  Height: 300  |  Size: 93 KiB

BIN
entities/planet/planet5.png View File

Before After
Width: 300  |  Height: 300  |  Size: 76 KiB

BIN
entities/planet/planet6.png View File

Before After
Width: 300  |  Height: 300  |  Size: 78 KiB

BIN
entities/planet/planet7.png View File

Before After
Width: 300  |  Height: 300  |  Size: 90 KiB

BIN
entities/planet/planet8.png View File

Before After
Width: 300  |  Height: 300  |  Size: 81 KiB

BIN
entities/planet/planet9.png View File

Before After
Width: 300  |  Height: 300  |  Size: 89 KiB

BIN
entities/ship/large_red_01.png View File

Before After
Width: 128  |  Height: 128  |  Size: 3.3 KiB

+ 103
- 0
entities/ship/ship.lua View File

@@ -0,0 +1,103 @@
ship = Class{}


function ship:init(x, y, image)
self.x = x
self.y = y
self.ox = x
self.oy = y
self.dy = 0
self.dx = 5
self.image = love.graphics.newImage(image)
self.width = self.image:getWidth()
self.height = self.image:getHeight()
self.rotation = 1.5708
self.vector = 1.5708
self.color = {1,1,1,1}
self.path = {}
end
function ship:newPathDot(dotx, doty)
return {
x = dotx,
y = doty
}
end
function ship:update(dt)
if not shipIsHit then
table.insert(self.path, self:newPathDot(self.x, self.y))
self.x = self.x + self.dx/2
self.y = self.y + self.dy/2
if self.dx ~= 0 then
self.vector = math.atan( self.dy/ self.dx)
end
if love.keyboard.isDown('s') then
self.speed = math.sqrt(self.dx^2 + self.dy^2)
self.speed = self.speed - 0.5
self.dx = math.cos(self.vector) * self.speed
self.dy = math.sin(self.vector) * self.speed
end
if love.keyboard.isDown('w') then
self.speed = math.sqrt(self.dx^2 + self.dy^2)
self.speed = self.speed + 0.5
self.dx = math.cos(self.vector) * self.speed
self.dy = math.sin(self.vector) * self.speed
end
if love.keyboard.isDown('left') then
self.dx = self.dx - 0.5
end
if love.keyboard.isDown('right') then
self.dx = self.dx + 0.5
end
if love.keyboard.isDown('up') then
self.dy = self.dy - 0.5
end
if love.keyboard.isDown('down') then
self.dy = self.dy + 0.5
end
print(self.speed)
--[[
if love.keyboard.isDown('right') then
self.rotation = self.rotation + 10
elseif love.keyboard.isDown('left') then
self.rotation = self.rotation - 10
end]]--

print("rotation:" .. self.rotation)
print("speed:" .. self.dx .. " " .. self.dy)
if self.dx < 0 then
self.vector = self.vector - 3.14159
end
self.vector = self.vector + 1.5708
end
end

function ship:draw()

-- Draw the `self.canvas` to screen
love.graphics.setColor(unpack(self.color))
print("DAW" .. camera.x)
love.graphics.draw(self.image, self.x, self.y, self.vector, 1, 1, self.width/2, self.height/2)
for i in ipairs(self.path) do
if i > 1 then
love.graphics.setColor(0,1,0,1)
print("DOING".. i)
love.graphics.line(self.path[i].x, self.path[i].y, self.path[i-1].x, self.path[i-1].y)
end
end
love.graphics.setColor(1,1,1,1)
end

function ship:reset()
self.x = self.ox
self.y = self.oy
self.dy = 0
self.dx = 20
self.rotation = 1.57
self.canvas = love.graphics.newCanvas(WINDOW_WIDTH, WINDOW_HEIGHT)
self.vector = 1.56
self.speed = 0
self.path = {}
end

BIN
entities/ship/smol_red_01.png View File

Before After
Width: 64  |  Height: 64  |  Size: 4.3 KiB

BIN
entities/trashbin.png View File

Before After
Width: 64  |  Height: 64  |  Size: 812 B

+ 27
- 0
explosion.lua View File

@@ -0,0 +1,27 @@
explosion = Class{}

function explosion:init(x, y, v, color)
self.color = color
self.x = x
self.y = y
self.v = v
self.range = 0
self.killed = false
print(self.i)
end

function explosion:update(dt)
self.range = self.range + dt * 24
if self.range * self.v > WINDOW_WIDTH * 2 then
print("killing myself with range" .. self.range)
self.killed = true
end
end



function explosion:render()
print("rendering myself" .. self.x .. " " .. self.y .. " " .. self.range .. " " .. self.v)
love.graphics.setColor(unpack(self.color))
love.graphics.circle("fill", self.x, self.y, self.range * self.v, 100)
end

+ 2505
- 0
fakemain.lua
File diff suppressed because it is too large
View File


BIN
font.ttf View File


+ 134
- 0
levels/level1.lua View File

@@ -0,0 +1,134 @@
level1 = Class{}
local levelLoaded = false
local M = {}
function level1.update(dt)
if not levelLoaded then
shipsleft = 1
local planetImage = love.graphics.newImage("entities/planet/planet" .. math.random(1, 18) .. ".png")
planetsleft = 3
gameStatus = "setup"
playbutts = {}
guibutts = {}
VCAM.x, VCAM.y = WINDOW_WIDTH/2, WINDOW_HEIGHT/2
explosions = {}
shipIsHit = false
guimenu = mainMenu()
reachedGoal = false
lvlbase = base(900, 200)
levelLoaded = true
table.insert(playbutts, menu:addButton("Return to setup", function()
gameStatus = "setup"
level1.reset()
end ))
table.insert(guibutts, menu:addButton("Release brake!", function ()
selectedItem = "none"
gameStatus = "play"
end
))
table.insert(guibutts, menu:addButton("To menu", function ()
level1.goBack()
end))
table.insert(planets, planet(700, 200, 50, 0.3, planetImage))
end
if reachedGoal then
if levelsBeaten < 1 then
levelsBeaten = 1
end
print("levelsBeaten is " .. levelsBeaten)
love.filesystem.write("save", levelsBeaten)
level1.goBack()
end
camera:update(dt)
lvlbase:update(dt)
--print(camera.x .. " " .. camera.y)
for i, explosion in ipairs(explosions) do
explosion:update(dt)
if explosion.killed then
table.remove(explosions, i)
gameStatus = "setup"
level1.reset()
end
end
if gameStatus == "play" then
camera.x, camera.y = firstShip.x - firstShip.height*4, firstShip.y- firstShip.width
--print(camera.x .. firstShip.x)
if shipIsHit then
if #explosions == 0 then
table.insert(explosions, explosion(firstShip.x, firstShip.y, 100, {1,1,1,1}))
end
end
firstShip:update(dt)
for i in ipairs(planets) do
planets[i]:update(dt)
end
else
camera:follow(VCAM.x, VCAM.y)
end
level1.GUIControl()
end

function level1.draw()
love.graphics.setColor(1,1,1,1)
camera:attach()
firstShip:draw()
lvlbase:draw()
for i in ipairs(planets) do
planets[i]:draw(dt)
end
--love.graphics.rectangle("fill",VCAM.x,VCAM.y,30,30)
if shipIsHit then
for i, explosion in ipairs(explosions) do
explosion:render()
--print("exploding")
end
end
camera:detach()
camera:draw()
if gameStatus == "setup" then
GUIDraw("left")
elseif gameStatus == "play" then
guimenu:butt(playbutts, WINDOW_WIDTH, WINDOW_HEIGHT, 1100, WINDOW_HEIGHT-50, 40, WINDOW_WIDTH/3)
end
end
function level1.goBack()
level1.reset()
gameStatus = "setup"
firstShip.path = {}
levelLoaded = false
for k in pairs(planets) do
planets[k] = nil
end
gameState = "selectlv"
end
function level1.reset()
firstShip:reset()
for k in pairs(planets) do
planets[k] = nil
end
local planetImage = love.graphics.newImage("entities/planet/planet" .. math.random(1, 18) .. ".png")
table.insert(planets, planet(700, 200, 50, 0.3, planetImage))
shipsleft = 1
shipIsHit = false
planetsleft = 3
end
function level1.GUIControl()
if (love.keyboard.isDown('a') and VCAM.x > WINDOW_WIDTH/2) then
VCAM.x = VCAM.x - 10
end
if (love.keyboard.isDown('d')) then
VCAM.x = VCAM.x + 10
end
end
return level1


+ 11
- 0
levels/menu.lua View File

@@ -0,0 +1,11 @@
menu = Class{}
local M = {}
function menu.update(dt)

end

function menu.draw(dt)
menu:butt(buttons, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH/2, WINDOW_HEIGHT/2, 40, WINDOW_WIDTH/3)
end

return menu

+ 119
- 0
levels/practice.lua View File

@@ -0,0 +1,119 @@
practice = Class{}
local levelLoaded = false
local M = {}
function practice.update(dt)
if not levelLoaded then
shipsleft = 1
planetsleft = 10
gameStatus = "setup"
playbutts = {}
guibutts = {}
XCAM = 0
YCAM = 0
explosions = {}
shipIsHit = false
guimenu = mainMenu()
table.insert(playbutts, menu:addButton("Return to setup", function()
gameStatus = "setup"
practice.reset()
end ))
table.insert(guibutts, menu:addButton("Release brake!", function ()
selectedItem = "none"
gameStatus = "play"
end
))
table.insert(guibutts, menu:addButton("To menu", function ()
practice.goBack()
end
))
levelLoaded = true
end
camera:update(dt)
print(camera.x .. " " .. camera.y)
for i, explosion in ipairs(explosions) do
explosion:update(dt)
if explosion.killed then
table.remove(explosions, i)
gameStatus = "setup"
practice.reset()
end
end
if gameStatus == "play" then
camera.x, camera.y = firstShip.x - firstShip.height*4, firstShip.y- firstShip.width
print(camera.x .. firstShip.x)
if shipIsHit then
if #explosions == 0 then
table.insert(explosions, explosion(firstShip.x, firstShip.y, 100, {1,1,1,1}))
end
end
firstShip:update(dt)
for i in ipairs(planets) do
planets[i]:update(dt)
end
else
camera:follow(VCAM.x, VCAM.y)
end
practice.GUIControl()
end

function practice.draw()
camera:attach()
firstShip:draw()
for i in ipairs(planets) do
planets[i]:draw(dt)
end
--love.graphics.rectangle("fill",VCAM.x,VCAM.y,30,30)
if shipIsHit then
for i, explosion in ipairs(explosions) do
explosion:render()
--print("exploding")
end
end
camera:detach()
camera:draw()
if gameStatus == "setup" then
GUIDraw("anywhere")
elseif gameStatus == "play" then
guimenu:butt(playbutts, WINDOW_WIDTH, WINDOW_HEIGHT, 1100, WINDOW_HEIGHT-50, 40, WINDOW_WIDTH/3)
end
end
function practice.goBack()
practice.reset()
gameStatus = "setup"
levelLoaded = false
gameState = "menu"
end
function practice.reset()
firstShip:reset()
for k in pairs(planets) do
planets[k] = nil
end
shipsleft = 1
shipIsHit = false
planetsleft = 10
end
function practice.GUIControl()
if (love.keyboard.isDown('w')) then
VCAM.y = VCAM.y - 10
end
if (love.keyboard.isDown('a')) then
VCAM.x = VCAM.x - 10
end
if (love.keyboard.isDown('s')) then
VCAM.y = VCAM.y + 10
end
if (love.keyboard.isDown('d')) then
VCAM.x = VCAM.x + 10
end
end
return practice

+ 22
- 0
levels/selectlv.lua View File

@@ -0,0 +1,22 @@
selectlv = Class{}
levels = {}
table.insert(levels, menu:addButton("Level 1", function ()
gameState = "level1"
end ))




table.insert(levels, menu:addButton("Go Back", function ()
gameState = "menu"
end ))
local M = {}
function selectlv.update(dt)

end

function selectlv.draw(dt)
menu:butt(levels, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH/2, WINDOW_HEIGHT/2, 40, WINDOW_WIDTH/3, "beatenGreen")
end

return selectlv

+ 57
- 0
main.lua View File

@@ -0,0 +1,57 @@
gameState = "menu"
require 'src/dependencies'
math.randomseed(os.time())
--VARIABLES
RESOLUTION_SET = 0
isFullscreen = 0
DIFFERENCE_X = 1
DIFFERENCE_Y = 1
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720
OFFSET_X = 0
OFFSET_Y = 0

levelsBeaten = 0
planets = {}
buttons = {}
menu = mainMenu()

function love.load()
testwalls = love.filesystem.load("save")
if testwalls ~= nil then
levelsBeaten = love.filesystem.load("save")
print("Save file found")
else
print("No save file found!")
end
tick.framerate = 60
camera = Camera()
BG = love.graphics.newImage("entities/background.jpg")
simpleScale.setWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT)
firstShip = ship(-500, -500, "entities/ship/smol_red_01.png")
VCAM = VCAM(WINDOW_WIDTH/2, WINDOW_HEIGHT/2)
smallfont = love.graphics.newFont("font.ttf", 25)
--table.insert(planets, planet(100, WINDOW_HEIGHT/2-100, 1010000000, 1))
buttonClutter()
--planet2 = planet(1000, 300, 1000000000, 20)
end

function love.update(dt)
stateUpdate(dt)

end

function love.draw()
simpleScale.set()
--love.graphics.draw(BG, 0, 0)
stateDraw()
simpleScale.unSet()
end



function love.mousereleased(x, y, button)
love.keyboard.mouseisReleased = true
end



+ 369
- 0
src/Camera.lua View File

@@ -0,0 +1,369 @@
--[[
MIT License

Copyright (c) 2017 SSYGEN

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]--

local function lerp(a, b, x) return a + (b - a)*x end
local function csnap(v, x) return math.ceil(v/x)*x - x/2 end

-- Shake according to https://jonny.morrill.me/en/blog/gamedev-how-to-implement-a-camera-shake-effect/
local function newShake(amplitude, duration, frequency)
local self = {
amplitude = amplitude or 0,
duration = duration or 0,
frequency = frequency or 60,
samples = {},
start_time = love.timer.getTime()*1000,
t = 0,
shaking = true,
}

local sample_count = (self.duration/1000)*self.frequency
for i = 1, sample_count do self.samples[i] = 2*love.math.random()-1 end

return self
end

local function updateShake(self, dt)
self.t = love.timer.getTime()*1000 - self.start_time
if self.t > self.duration then self.shaking = false end
end

local function shakeNoise(self, s)
if s >= #self.samples then return 0 end
return self.samples[s] or 0
end

local function shakeDecay(self, t)
if t > self.duration then return 0 end
return (self.duration - t)/self.duration
end

local function getShakeAmplitude(self, t)
if not t then
if not self.shaking then return 0 end
t = self.t
end

local s = (t/1000)*self.frequency
local s0 = math.floor(s)
local s1 = s0 + 1
local k = shakeDecay(self, t)
return self.amplitude*(shakeNoise(self, s0) + (s - s0)*(shakeNoise(self, s1) - shakeNoise(self, s0)))*k
end

-- Camera
local Camera = {}
Camera.__index = Camera

local function new(x, y, w, h, scale, rotation)
return setmetatable({
x = x or (w or love.graphics.getWidth())/2, y = y or (h or love.graphics.getHeight())/2,
mx = x or (w or love.graphics.getWidth())/2, my = y or (h or love.graphics.getHeight())/2,
screen_x = x or (w or love.graphics.getWidth())/2, screen_y = y or (h or love.graphics.getHeight())/2,
w = w or love.graphics.getWidth(), h = h or love.graphics.getHeight(),
scale = scale or 1,
rotation = rotation or 0,
horizontal_shakes = {}, vertical_shakes = {},
target_x = nil, target_y = nil,
scroll_x = 0, scroll_y = 0,
last_target_x = nil, last_target_y = nil,
follow_lerp_x = 1, follow_lerp_y = 1,
follow_lead_x = 0, follow_lead_y = 0,
deadzone = nil, bound = nil,
draw_deadzone = false,
flash_duration = 1, flash_timer = 0, flash_color = {0, 0, 0, 1},
last_horizontal_shake_amount = 0, last_vertical_shake_amount = 0,
fade_duration = 1, fade_timer = 0, fade_color = {0, 0, 0, 0},
}, Camera)
end

function Camera:attach()
love.graphics.push()
love.graphics.translate(self.w/2, self.h/2)
love.graphics.scale(self.scale)
love.graphics.rotate(self.rotation)
love.graphics.translate(-self.x, -self.y)
end

function Camera:detach()
love.graphics.pop()
end

function Camera:move(dx, dy)
self.x, self.y = self.x + dx, self.y + dy
end

function Camera:toWorldCoords(x, y)
local c, s = math.cos(self.rotation), math.sin(self.rotation)
x, y = (x - self.w/2)/self.scale, (y - self.h/2)/self.scale
x, y = c*x - s*y, s*x + c*y
return x + self.x, y + self.y
end

function Camera:toCameraCoords(x, y)
local c, s = math.cos(self.rotation), math.sin(self.rotation)
x, y = x - self.x, y - self.y
x, y = c*x - s*y, s*x + c*y
return x*self.scale + self.w/2, y*self.scale + self.h/2
end

function Camera:getMousePosition()
return self:toWorldCoords(love.mouse.getPosition())
end

function Camera:shake(intensity, duration, frequency, axes)
if not axes then axes = 'XY' end
axes = string.upper(axes)

if string.find(axes, 'X') then table.insert(self.horizontal_shakes, newShake(intensity, duration*1000, frequency)) end
if string.find(axes, 'Y') then table.insert(self.vertical_shakes, newShake(intensity, duration*1000, frequency)) end
end

function Camera:update(dt)
self.mx, self.my = self:toWorldCoords(love.mouse.getPosition())

-- Flash --
if self.flashing then
self.flash_timer = self.flash_timer + dt
if self.flash_timer > self.flash_duration then
self.flash_timer = 0
self.flashing = false
end
end

-- Fade --
if self.fading then
self.fade_timer = self.fade_timer + dt
self.fade_color = {
lerp(self.base_fade_color[1], self.target_fade_color[1], self.fade_timer/self.fade_duration),
lerp(self.base_fade_color[2], self.target_fade_color[2], self.fade_timer/self.fade_duration),
lerp(self.base_fade_color[3], self.target_fade_color[3], self.fade_timer/self.fade_duration),
lerp(self.base_fade_color[4], self.target_fade_color[4], self.fade_timer/self.fade_duration),
}
if self.fade_timer > self.fade_duration then
self.fade_timer = 0
self.fading = false
if self.fade_action then self.fade_action() end
end
end

-- Shake --
local horizontal_shake_amount, vertical_shake_amount = 0, 0
for i = #self.horizontal_shakes, 1, -1 do
updateShake(self.horizontal_shakes[i], dt)
horizontal_shake_amount = horizontal_shake_amount + getShakeAmplitude(self.horizontal_shakes[i])
if not self.horizontal_shakes[i].shaking then table.remove(self.horizontal_shakes, i) end
end
for i = #self.vertical_shakes, 1, -1 do
updateShake(self.vertical_shakes[i], dt)
vertical_shake_amount = vertical_shake_amount + getShakeAmplitude(self.vertical_shakes[i])
if not self.vertical_shakes[i].shaking then table.remove(self.vertical_shakes, i) end
end
self.x, self.y = self.x - self.last_horizontal_shake_amount, self.y - self.last_vertical_shake_amount
self:move(horizontal_shake_amount, vertical_shake_amount)
self.last_horizontal_shake_amount, self.last_vertical_shake_amount = horizontal_shake_amount, vertical_shake_amount

-- Follow --
if not self.target_x and not self.target_y then return end

-- Set follow style deadzones
if self.follow_style == 'LOCKON' then
local w, h = self.w/16, self.w/16
self:setDeadzone((self.w - w)/2, (self.h - h)/2, w, h)

elseif self.follow_style == 'PLATFORMER' then
local w, h = self.w/8, self.h/3
self:setDeadzone((self.w - w)/2, (self.h - h)/2 - h*0.25, w, h)

elseif self.follow_style == 'TOPDOWN' then
local s = math.max(self.w, self.h)/4
self:setDeadzone((self.w - s)/2, (self.h - s)/2, s, s)

elseif self.follow_style == 'TOPDOWN_TIGHT' then
local s = math.max(self.w, self.h)/8
self:setDeadzone((self.w - s)/2, (self.h - s)/2, s, s)

elseif self.follow_style == 'SCREEN_BY_SCREEN' then
self:setDeadzone(0, 0, 0, 0)

elseif self.follow_style == 'NO_DEADZONE' then
self.deadzone = nil
end

-- No deadzone means we just track the target with no lerp
if not self.deadzone then
self.x, self.y = self.target_x, self.target_y
if self.bound then
self.x = math.min(math.max(self.x, self.bounds_min_x + self.w/2), self.bounds_max_x - self.w/2)
self.y = math.min(math.max(self.y, self.bounds_min_y + self.h/2), self.bounds_max_y - self.h/2)
end
return
end

-- Convert appropriate variables to camera coordinates since the deadzone is applied in terms of the camera and not the world
local dx1, dy1, dx2, dy2 = self.deadzone_x, self.deadzone_y, self.deadzone_x + self.deadzone_w, self.deadzone_y + self.deadzone_h
local scroll_x, scroll_y = 0, 0
local target_x, target_y = self:toCameraCoords(self.target_x, self.target_y)
local x, y = self:toCameraCoords(self.x, self.y)

-- Screen by screen follow mode needs to be handled a bit differently
if self.follow_style == 'SCREEN_BY_SCREEN' then
-- Don't change self.screen_x/y if already at the boundaries
if self.bound then
if self.x > self.bounds_min_x + self.w/2 and target_x < 0 then self.screen_x = csnap(self.screen_x - self.w/self.scale, self.w/self.scale) end
if self.x < self.bounds_max_x - self.w/2 and target_x >= self.w then self.screen_x = csnap(self.screen_x + self.w/self.scale, self.w/self.scale) end
if self.y > self.bounds_min_y + self.h/2 and target_y < 0 then self.screen_y = csnap(self.screen_y - self.h/self.scale, self.h/self.scale) end
if self.y < self.bounds_max_y - self.h/2 and target_y >= self.h then self.screen_y = csnap(self.screen_y + self.h/self.scale, self.h/self.scale) end
-- Move to the next screen if the target is outside the screen boundaries
else
if target_x < 0 then self.screen_x = csnap(self.screen_x - self.w/self.scale, self.w/self.scale) end
if target_x >= self.w then self.screen_x = csnap(self.screen_x + self.w/self.scale, self.w/self.scale) end
if target_y < 0 then self.screen_y = csnap(self.screen_y - self.h/self.scale, self.h/self.scale) end
if target_y >= self.h then self.screen_y = csnap(self.screen_y + self.h/self.scale, self.h/self.scale) end
end
self.x = lerp(self.x, self.screen_x, self.follow_lerp_x)
self.y = lerp(self.y, self.screen_y, self.follow_lerp_y)

-- Apply bounds
if self.bound then
self.x = math.min(math.max(self.x, self.bounds_min_x + self.w/2), self.bounds_max_x - self.w/2)
self.y = math.min(math.max(self.y, self.bounds_min_y + self.h/2), self.bounds_max_y - self.h/2)
end

-- All other follow modes
else
-- Figure out how much the camera needs to scroll
if target_x < x + (dx1 + dx2 - x) then
local d = target_x - dx1
if d < 0 then scroll_x = d end
end
if target_x > x - (dx1 + dx2 - x) then
local d = target_x - dx2
if d > 0 then scroll_x = d end
end
if target_y < y + (dy1 + dy2 - y) then
local d = target_y - dy1
if d < 0 then scroll_y = d end
end
if target_y > y - (dy1 + dy2 - y) then
local d = target_y - dy2
if d > 0 then scroll_y = d end
end

-- Apply lead
if not self.last_target_x and not self.last_target_y then self.last_target_x, self.last_target_y = self.target_x, self.target_y end
scroll_x = scroll_x + (self.target_x - self.last_target_x)*self.follow_lead_x
scroll_y = scroll_y + (self.target_y - self.last_target_y)*self.follow_lead_y
self.last_target_x, self.last_target_y = self.target_x, self.target_y

-- Scroll towards target with lerp
self.x = lerp(self.x, self.x + scroll_x, self.follow_lerp_x)
self.y = lerp(self.y, self.y + scroll_y, self.follow_lerp_y)

-- Apply bounds
if self.bound then
self.x = math.min(math.max(self.x, self.bounds_min_x + self.w/2), self.bounds_max_x - self.w/2)
self.y = math.min(math.max(self.y, self.bounds_min_y + self.h/2), self.bounds_max_y - self.h/2)
end
end
end

function Camera:draw()
if self.draw_deadzone and self.deadzone then
local n = love.graphics.getLineWidth()
love.graphics.setLineWidth(2)
love.graphics.line(self.deadzone_x - 1, self.deadzone_y, self.deadzone_x + 6, self.deadzone_y)
love.graphics.line(self.deadzone_x, self.deadzone_y, self.deadzone_x, self.deadzone_y + 6)
love.graphics.line(self.deadzone_x - 1, self.deadzone_y + self.deadzone_h, self.deadzone_x + 6, self.deadzone_y + self.deadzone_h)
love.graphics.line(self.deadzone_x, self.deadzone_y + self.deadzone_h, self.deadzone_x, self.deadzone_y + self.deadzone_h - 6)
love.graphics.line(self.deadzone_x + self.deadzone_w + 1, self.deadzone_y + self.deadzone_h, self.deadzone_x + self.deadzone_w - 6, self.deadzone_y + self.deadzone_h)
love.graphics.line(self.deadzone_x + self.deadzone_w, self.deadzone_y + self.deadzone_h, self.deadzone_x + self.deadzone_w, self.deadzone_y + self.deadzone_h - 6)
love.graphics.line(self.deadzone_x + self.deadzone_w + 1, self.deadzone_y, self.deadzone_x + self.deadzone_w - 6, self.deadzone_y)
love.graphics.line(self.deadzone_x + self.deadzone_w, self.deadzone_y, self.deadzone_x + self.deadzone_w, self.deadzone_y + 6)
love.graphics.setLineWidth(n)
end

if self.flashing then
local r, g, b, a = love.graphics.getColor()
love.graphics.setColor(self.flash_color)
love.graphics.rectangle('fill', 0, 0, self.w, self.h)
love.graphics.setColor(r, g, b, a)
end

local r, g, b, a = love.graphics.getColor()
love.graphics.setColor(self.fade_color)
love.graphics.rectangle('fill', 0, 0, self.w, self.h)
love.graphics.setColor(r, g, b, a)
end

function Camera:follow(x, y)
self.target_x, self.target_y = x, y
end

function Camera:setDeadzone(x, y, w, h)
self.deadzone = true
self.deadzone_x = x
self.deadzone_y = y
self.deadzone_w = w
self.deadzone_h = h
end

function Camera:setBounds(x, y, w, h)
self.bound = true
self.bounds_min_x = x
self.bounds_min_y = y
self.bounds_max_x = x + w
self.bounds_max_y = y + h
end

function Camera:setFollowStyle(follow_style)
self.follow_style = follow_style
end

function Camera:setFollowLerp(x, y)
self.follow_lerp_x = x
self.follow_lerp_y = y or x
end

function Camera:setFollowLead(x, y)
self.follow_lead_x = x
self.follow_lead_y = y or x
end

function Camera:flash(duration, color)
self.flash_duration = duration
self.flash_color = color or self.flash_color
self.flash_timer = 0
self.flashing = true
end

function Camera:fade(duration, color, action)
self.fade_duration = duration
self.base_fade_color = self.fade_color
self.target_fade_color = color
self.fade_timer = 0
self.fade_action = action
self.fading = true
end

return setmetatable({new = new}, {__call = function(_, ...) return new(...) end})

+ 221
- 0
src/GUI.lua View File

@@ -0,0 +1,221 @@
selectedItem = "none"
local planetImage = love.graphics.newImage("entities/planet/planet" .. math.random(1, 18) .. ".png")


function GUIDraw(mode)
--MAIN
love.graphics.setColor(1,1,1,1)
love.graphics.rectangle("fill", WINDOW_WIDTH*0.7-3, 0, WINDOW_WIDTH*0.3-3, WINDOW_HEIGHT)
love.graphics.setColor(0,0,0,1)
local menuX = WINDOW_WIDTH*0.7
local menuW = WINDOW_WIDTH*0.3
local menuY = 3
love.graphics.rectangle("fill", WINDOW_WIDTH*0.7, 3, WINDOW_WIDTH*0.3, WINDOW_HEIGHT-6)
love.graphics.setFont(smallfont)
love.graphics.setColor(1,1,1,1)
local textW = smallfont:getWidth("Control Panel")
love.graphics.print("Control Panel",menuX + menuW/2-textW/2,menuY+10)
--MAIN

--SHIP
local shipImage = love.graphics.newImage("entities/ship/smol_red_01.png")
GUIButton(shipsleft, shipImage, menuX + 60, menuY+WINDOW_HEIGHT*0.2, function() selectedItem = "ship" end, 1, 1, {1,1,1,1}, 1.57)
--SHIP
--PLANET
GUIButton(planetsleft, planetImage, menuX + 60, menuY+WINDOW_HEIGHT*0.4, function() selectedItem = "planet" end, 0.5, 0.5, {1,1,1,1}, 1.57)
--PLANET


--PLACING
local mx, my = love.mouse.getPosition()
local vmx, vmy = camera:getMousePosition()
local mx = mx * DIFFERENCE_X
local my = my * DIFFERENCE_Y
if mode == "anywhere" then
love.graphics.setColor(1,1,1,0.5)
if selectedItem == "ship" and mx < menuX then
local shipW = shipImage:getWidth()
local shipH = shipImage:getHeight()
love.graphics.draw(shipImage,mx,my, 1.5708, 1, 1, shipW/2, shipH/2)
if love.keyboard.mouseisReleased then
love.keyboard.mouseisReleased = false
firstShip.x = vmx
firstShip.y = vmy
shipsleft = shipsleft - 1
end
if shipsleft == 0 then
selectedItem = "none"
end
end
elseif mode == "left" then
love.graphics.setColor(1,1,1,0.5)
if selectedItem == "ship" and mx < menuX then
local shipW = shipImage:getWidth()
local shipH = shipImage:getHeight()
love.graphics.draw(shipImage,10,my, 1.5708, 1, 1, shipW/2, shipH/2)
if love.keyboard.mouseisReleased then
love.keyboard.mouseisReleased = false
firstShip.x = 250
firstShip.y = vmy
shipsleft = shipsleft - 1
end
if shipsleft == 0 then
selectedItem = "none"
end
end
end
local dx, dy = camera:toCameraCoords(firstShip.x, firstShip.y)
if VCAM.x - WINDOW_WIDTH/2+250 > firstShip.x and shipsleft == 0 then
love.graphics.setColor(1,0,0,1)
love.graphics.rectangle("fill", 0, dy-firstShip.width/2, 10, firstShip.width)
end
if VCAM.y - WINDOW_HEIGHT/2+50 > firstShip.y and shipsleft == 0 then
love.graphics.setColor(1,0,0,1)
love.graphics.rectangle("fill", dx-firstShip.height/2, 0, firstShip.height, 10)
end
if VCAM.y + WINDOW_HEIGHT/2+50 < firstShip.y and shipsleft == 0 then
love.graphics.setColor(1,0,0,1)
love.graphics.rectangle("fill", dx-firstShip.height/2, WINDOW_HEIGHT-10, firstShip.height, 10)
end
if VCAM.x + WINDOW_WIDTH/2-150< firstShip.x and shipsleft == 0 then
love.graphics.setColor(1,0,0,1)
love.graphics.rectangle("fill", menuX-10, dy-firstShip.width/2, 10, firstShip.width)
end
for k in ipairs(planets) do
local dx, dy = camera:toCameraCoords(planets[k].x, planets[k].y)
if VCAM.x - WINDOW_WIDTH/2+250 > planets[k].x then
love.graphics.setColor(0,0,1,1)
love.graphics.rectangle("fill", 0, dy-planets[k].w*0.3/2, 10, planets[k].w*0.3)
end
if VCAM.y - WINDOW_HEIGHT/2+50 > planets[k].y then
love.graphics.setColor(0,0,1,1)
love.graphics.rectangle("fill", dx-planets[k].w*0.3/2, 0, planets[k].w*0.3, 10)
end
if VCAM.y + WINDOW_HEIGHT/2+50 < planets[k].y then
love.graphics.setColor(0,0,1,1)
love.graphics.rectangle("fill", dx-planets[k].w*0.3/2, WINDOW_HEIGHT-10, planets[k].w*0.3, 10)
end
if VCAM.x + WINDOW_WIDTH/2-150< planets[k].x then
love.graphics.setColor(0,0,1,1)
love.graphics.rectangle("fill", menuX-10, dy-planets[k].w*0.3/2, 10, planets[k].w*0.3)
end
end
if lvlbase ~= nil then
local dx, dy = camera:toCameraCoords(lvlbase.x, lvlbase.y)
print("YESYEYSYSYADSYADYASD")
if VCAM.x - WINDOW_WIDTH/2+250 > lvlbase.x then
love.graphics.setColor(0,1,0,1)
love.graphics.rectangle("fill", 0, dy-lvlbase.w/2, 10, lvlbase.w)
end
if VCAM.y - WINDOW_HEIGHT/2+50 > lvlbase.y then
love.graphics.setColor(0,1,0,1)
love.graphics.rectangle("fill", dx-lvlbase.w/2, 0, lvlbase.w, 10)
end
if VCAM.y + WINDOW_HEIGHT/2+50 < lvlbase.y then
love.graphics.setColor(0,1,0,1)
love.graphics.rectangle("fill", dx-lvlbase.w/2, WINDOW_HEIGHT-10, lvlbase.w, 10)
end
if VCAM.x + WINDOW_WIDTH/2-150< lvlbase.x then
love.graphics.setColor(0,1,0,1)
love.graphics.rectangle("fill", menuX-10, dy-lvlbase.w/2, 10, lvlbase.w)
end
end
if selectedItem == "planet" and mx < menuX then
local shipW = planetImage:getWidth()
local shipH = planetImage:getHeight()
love.graphics.draw(planetImage,mx,my,0, 0.3, 0.3, shipW/2, shipH/2)
if love.keyboard.mouseisReleased then
love.keyboard.mouseisReleased = false
table.insert(planets, planet(vmx, vmy, 1000000000, 0.3, planetImage))
planetImage = love.graphics.newImage("entities/planet/planet" .. math.random(1, 18) .. ".png")
planetsleft = planetsleft-1
end
if planetsleft == 0 then
selectedItem = "none"
end
end
if selectedItem == "eraser" then
local hot = (vmx > firstShip.x-firstShip.height/2 and vmx < firstShip.x+firstShip.height and vmy > firstShip.y-firstShip.width/2 and vmy < firstShip.y - firstShip.width/2 + firstShip.width)
if hot then
firstShip.color = {1,0,0,1}
print("hot")
else
firstShip.color = {1,1,1,1}
print(mx .. " " .. my .. " " .. firstShip.x .. " " .. firstShip.y .. " " .. firstShip.width .. firstShip.height)
end
local pressed = love.keyboard.mouseisReleased
if location == "android" then
pressed = love.mouse.isDown(1)
end
if pressed and hot then
love.keyboard.mouseisReleased = false
firstShip.x = -9000
shipsleft = shipsleft + 1
end


for j in ipairs(planets) do
local hot = (vmx > planets[j].x-planets[j].w*0.3/2 and vmx < planets[j].x+planets[j].w*0.3 and vmy > planets[j].y-planets[j].w*0.3/2 and vmy < planets[j].y + planets[j].w*0.3)
if hot then
planets[j].color = {1,0,0,1}
print("hot")
else
planets[j].color = {1,1,1,1}
--print(mx .. " " .. my .. " " .. firstShip.x .. " " .. firstShip.y .. " " .. firstShip.width .. firstShip.height)
end
local pressed = love.keyboard.mouseisReleased
if location == "android" then
pressed = love.mouse.isDown(1)
end
if pressed and hot then
love.keyboard.mouseisReleased = false
table.remove(planets, j)
planetsleft = planetsleft + 1
break
end
end
end
--PLACING


--REMOVE TOOL
trashbin = love.graphics.newImage("entities/trashbin.png")
GUIButton("inf", trashbin, menuX + 60, menuY+WINDOW_HEIGHT*0.6, function() selectedItem = "eraser" end, 1, 1, {1,1,1,1}, 0)
--REMOVE TOOL

--START BUTTON
if shipsleft == 0 then
guimenu:butt(guibutts, WINDOW_WIDTH, WINDOW_HEIGHT, menuX + 200, WINDOW_HEIGHT-100, 40, WINDOW_WIDTH/3.7)
end
--START BUTTON
love.window.setTitle(selectedItem)
end


function GUIButton(num, shipImage, x, y, fn, sx, sy, color, r)
love.graphics.setColor(unpack(color))
local shipW = shipImage:getWidth()
local shipH = shipImage:getHeight()

local mx, my = love.mouse.getPosition()
local vmx, vmy = camera:getMousePosition()
local mx = mx * DIFFERENCE_X
local my = my * DIFFERENCE_Y
local hot = (mx > x-shipW/2*sx and mx < x-shipW/2*sx + shipW*sx and my > y-shipH/2*sy and my < y -shipH/2*sy + shipH*sy)
if (hot) then
love.graphics.setColor(1,0,0,0.5)
--love.graphics.rectangle("fill", x, y, shipW, shipH)
end
local pressed = love.keyboard.mouseisReleased
if location == "android" then
pressed = love.mouse.isDown(1)
end
if pressed and hot then
love.keyboard.mouseisReleased = false
fn()
end
love.graphics.draw(shipImage,x,y, r, sx, sy, shipW/2, shipH/2)
love.graphics.print("x" .. num,x+10,y)
love.graphics.setColor(1,1,1,1)
end

+ 94
- 0
src/class.lua View File

@@ -0,0 +1,94 @@
--[[
Copyright (c) 2010-2013 Matthias Richter
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
Except as contained in this notice, the name(s) of the above copyright holders
shall not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
]]--
local function include_helper(to, from, seen)
if from == nil then
return to
elseif type(from) ~= 'table' then
return from
elseif seen[from] then
return seen[from]
end
seen[from] = to
for k,v in pairs(from) do
k = include_helper({}, k, seen) -- keys might also be tables
if to[k] == nil then
to[k] = include_helper({}, v, seen)
end
end
return to
end
-- deeply copies `other' into `class'. keys in `other' that are already
-- defined in `class' are omitted
local function include(class, other)
return include_helper(class, other, {})
end
-- returns a deep copy of `other'
local function clone(other)
return setmetatable(include({}, other), getmetatable(other))
end
local function new(class)
-- mixins
class = class or {} -- class can be nil
local inc = class.__includes or {}
if getmetatable(inc) then inc = {inc} end
for _, other in ipairs(inc) do
if type(other) == "string" then
other = _G[other]
end
include(class, other)
end
-- class implementation
class.__index = class
class.init = class.init or class[1] or function() end
class.include = class.include or include
class.clone = class.clone or clone
-- constructor call
return setmetatable(class, {__call = function(c, ...)
local o = setmetatable({}, c)
o:init(...)
return o
end})
end
-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons).
if class_commons ~= false and not common then
common = {}
function common.class(name, prototype, parent)
return new{__includes = {prototype, parent}}
end
function common.instance(class, ...)
return class(...)
end
end
-- the module
return setmetatable({new = new, include = include, clone = clone},
{__call = function(_,...) return new(...) end})

+ 17
- 0
src/dependencies.lua View File

@@ -0,0 +1,17 @@
Class = require 'src/class'
require 'src/simpleScale'
require 'src/fullScreener'
require 'src/mainMenu'
require 'src/pongDisplayControl'
require 'entities/ship/ship'
require 'entities/planet/planet'
require 'buttonClutter'
require 'explosion'
require 'src/GUI'
require 'stateMachine'
require 'entities/base/base'
require 'entities/camera/VCAM'
tick = require 'src/tick'
utf8 = require("utf8")
serialize = require 'src/ser'
Camera = require 'src/Camera'

+ 39
- 0
src/fullScreener.lua View File

@@ -0,0 +1,39 @@
fullScreener = Class{}
function fullScreener:init(a,b,c,d,e,f)
self.a = a
self.b = b
self.c = c
self.d = d
self.e = e
self.f = f
end
function fullScreener:toggle(vh, vw)
self.a = self.a + 1
if (self.a > 1) then
self.a = 0
end
if (self.a == 0 ) then
if (self.b == 1) then
self.c = 1
self.d = 1
self.e = 0
self.f = 0
simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT,{fullscreen = false})
self.b = 0
end
end
if (self.a == 1) then
if (self.b == 0) then
simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, {fullscreen = true})
local newWidth = love.graphics.getWidth()
local newHeight = love.graphics.getHeight()
self.c = VIRTUAL_WIDTH / newWidth
self.d = VIRTUAL_HEIGHT / newHeight
self.e = math.fmod(newWidth * self.d, VIRTUAL_WIDTH) / 2
self.f = math.fmod(newHeight * self.d, VIRTUAL_HEIGHT) / 2
self.b = 1
end
end
end

+ 53
- 0
src/mainMenu.lua View File

@@ -0,0 +1,53 @@
mainMenu = Class{}
function mainMenu:butt(buttons, VIRTUAL_WIDTH, VIRTUAL_HEIGHT, locationx, locationy, ev_BUTTON_HEIGHT, ev_button_width, arg)
local margin = 16
local hot = false
local cursor_y = 0
local total_height = (ev_BUTTON_HEIGHT + margin) * #buttons
local ev_bx, ev_by
for i, button in ipairs(buttons) do
button.last = button.now
ev_bx = locationx - (ev_button_width * 0.5)
ev_by = locationy - (total_height * 0.5) + cursor_y
local color = {255, 255, 255, 255}
local mx, my = love.mouse.getPosition()
local mx = mx * DIFFERENCE_X
local my = my * DIFFERENCE_Y
local hot = (mx > ev_bx and mx < ev_bx + ev_button_width and my > ev_by and my < ev_by + ev_BUTTON_HEIGHT) and i
if (hot == i) then
color = {10, 10, 0, 255}
end
button.now = love.keyboard.mouseisReleased
if location == "android" then
button.now = love.mouse.isDown(1)
end
if button.now and hot == i then
love.keyboard.mouseisReleased = false
button.fn()
break
end
if arg == "beatenGreen" then
if i <= levelsBeaten then
color = {0,1,0,1}
end
end
love.graphics.setColor(unpack(color))
love.graphics.rectangle("fill", ev_bx,ev_by, ev_button_width, ev_BUTTON_HEIGHT)
love.graphics.setColor(0, 0, 0, 255)
local textW = smallfont:getWidth(button.text)
local textH = smallfont:getHeight(button.text)
love.graphics.print(button.text, smallfont, ev_bx + ev_button_width*0.5 - textW*0.5, ev_by+textH*0.5)
love.graphics.setColor(255, 255, 255, 255)
cursor_y = cursor_y + (ev_BUTTON_HEIGHT + margin)
end
end
function mainMenu:addButton(text, fn)
return {
text = text,
fn = fn,
now = false,
last = false
}
end

+ 27
- 0
src/pongDisplayControl.lua View File

@@ -0,0 +1,27 @@
function resolutionChanger()
if (RESOLUTION_SET > 1) then
RESOLUTION_SET = 0
end
if (RESOLUTION_SET == 0) then
if (isFullscreen == 1) then
DIFFERENCE_X = 1
DIFFERENCE_Y = 1
OFFSET_X = 0
OFFSET_Y = 0
simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, {fullscreen = false})
isFullscreen = 0
end
end
if (RESOLUTION_SET == 1) then
if (isFullscreen == 0) then
simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, {fullscreen = true})
local newWidth = love.graphics.getWidth()
local newHeight = love.graphics.getHeight()
DIFFERENCE_X = VIRTUAL_WIDTH / newWidth
DIFFERENCE_Y = VIRTUAL_HEIGHT / newHeight
OFFSET_X = math.fmod(newWidth, VIRTUAL_WIDTH) / 2
OFFSET_Y = math.fmod(newHeight, VIRTUAL_HEIGHT) / 2
isFullscreen = 1
end
end
end

+ 272
- 0
src/push.lua View File

@@ -0,0 +1,272 @@
local love11 = love.getVersion() == 11
local getDPI = love11 and love.window.getDPIScale or love.window.getPixelScale
local windowUpdateMode = love11 and love.window.updateMode or function(width, height, settings)
local _, _, flags = love.window.getMode()
for k, v in pairs(settings) do flags[k] = v end
love.window.setMode(width, height, flags)
end
local push = {
defaults = {
fullscreen = false,
resizable = false,
pixelperfect = false,
highdpi = true,
canvas = true,
stencil = true
}
}
setmetatable(push, push)
function push:applySettings(settings)
for k, v in pairs(settings) do
self["_" .. k] = v
end
end
function push:resetSettings() return self:applySettings(self.defaults) end
function push:setupScreen(WWIDTH, WHEIGHT, RWIDTH, RHEIGHT, settings)
settings = settings or {}
self._WWIDTH, self._WHEIGHT = WWIDTH, WHEIGHT
self._RWIDTH, self._RHEIGHT = RWIDTH, RHEIGHT
self:applySettings(self.defaults) --set defaults first
self:applySettings(settings) --then fill with custom settings
windowUpdateMode(self._RWIDTH, self._RHEIGHT, {
fullscreen = self._fullscreen,
resizable = self._resizable,
highdpi = self._highdpi
})
self:initValues()
if self._canvas then
self:setupCanvas({ "default" }) --setup canvas
end
self._borderColor = {0, 0, 0}
self._drawFunctions = {
["start"] = self.start,
["end"] = self.finish
}
return self
end
function push:setupCanvas(canvases)
table.insert(canvases, { name = "_render", private = true }) --final render
self._canvas = true
self.canvases = {}
for i = 1, #canvases do
push:addCanvas(canvases[i])
end
return self
end
function push:addCanvas(params)
table.insert(self.canvases, {
name = params.name,
private = params.private,
shader = params.shader,
canvas = love.graphics.newCanvas(self._WWIDTH, self._WHEIGHT),
stencil = params.stencil or self._stencil
})
end
function push:setCanvas(name)
if not self._canvas then return true end
return love.graphics.setCanvas(self:getCanvasTable(name).canvas)
end
function push:getCanvasTable(name)
for i = 1, #self.canvases do
if self.canvases[i].name == name then
return self.canvases[i]
end
end
end
function push:setShader(name, shader)
if not shader then
self:getCanvasTable("_render").shader = name
else
self:getCanvasTable(name).shader = shader
end
end
function push:initValues()
self._PSCALE = (not love11 and self._highdpi) and getDPI() or 1
self._SCALE = {
x = self._RWIDTH/self._WWIDTH * self._PSCALE,
y = self._RHEIGHT/self._WHEIGHT * self._PSCALE
}
if self._stretched then --if stretched, no need to apply offset
self._OFFSET = {x = 0, y = 0}
else
local scale = math.min(self._SCALE.x, self._SCALE.y)
if self._pixelperfect then scale = math.floor(scale) end
self._OFFSET = {x = (self._SCALE.x - scale) * (self._WWIDTH/2), y = (self._SCALE.y - scale) * (self._WHEIGHT/2)}
self._SCALE.x, self._SCALE.y = scale, scale --apply same scale to X and Y
end
self._GWIDTH = self._RWIDTH * self._PSCALE - self._OFFSET.x * 2
self._GHEIGHT = self._RHEIGHT * self._PSCALE - self._OFFSET.y * 2
end
function push:apply(operation, shader)
self._drawFunctions[operation](self, shader)
end
function push:start()
if self._canvas then
love.graphics.push()
love.graphics.setCanvas({ self.canvases[1].canvas, stencil = self.canvases[1].stencil })
else
love.graphics.translate(self._OFFSET.x, self._OFFSET.y)
love.graphics.setScissor(self._OFFSET.x, self._OFFSET.y, self._WWIDTH*self._SCALE.x, self._WHEIGHT*self._SCALE.y)
love.graphics.push()
love.graphics.scale(self._SCALE.x, self._SCALE.y)
end
end
function push:applyShaders(canvas, shaders)
local _shader = love.graphics.getShader()
if #shaders <= 1 then
love.graphics.setShader(shaders[1])
love.graphics.draw(canvas)
else
local _canvas = love.graphics.getCanvas()
local _tmp = self:getCanvasTable("_tmp")
if not _tmp then --create temp canvas only if needed
self:addCanvas({ name = "_tmp", private = true, shader = nil })
_tmp = self:getCanvasTable("_tmp")
end
love.graphics.push()
love.graphics.origin()
local outputCanvas
for i = 1, #shaders do
local inputCanvas = i % 2 == 1 and canvas or _tmp.canvas
outputCanvas = i % 2 == 0 and canvas or _tmp.canvas
love.graphics.setCanvas(outputCanvas)
love.graphics.clear()
love.graphics.setShader(shaders[i])
love.graphics.draw(inputCanvas)
love.graphics.setCanvas(inputCanvas)
end
love.graphics.pop()
love.graphics.setCanvas(_canvas)
love.graphics.draw(outputCanvas)
end
love.graphics.setShader(_shader)
end
function push:finish(shader)
love.graphics.setBackgroundColor(unpack(self._borderColor))
if self._canvas then
local _render = self:getCanvasTable("_render")
love.graphics.pop()
local white = love11 and 1 or 255
love.graphics.setColor(white, white, white)
--draw canvas
love.graphics.setCanvas(_render.canvas)
for i = 1, #self.canvases do --do not draw _render yet
local _table = self.canvases[i]
if not _table.private then
local _canvas = _table.canvas
local _shader = _table.shader
self:applyShaders(_canvas, type(_shader) == "table" and _shader or { _shader })
end
end
love.graphics.setCanvas()
--draw render
love.graphics.translate(self._OFFSET.x, self._OFFSET.y)
local shader = shader or _render.shader
love.graphics.push()
love.graphics.scale(self._SCALE.x, self._SCALE.y)
self:applyShaders(_render.canvas, type(shader) == "table" and shader or { shader })
love.graphics.pop()
--clear canvas
for i = 1, #self.canvases do
love.graphics.setCanvas(self.canvases[i].canvas)
love.graphics.clear()
end
love.graphics.setCanvas()
love.graphics.setShader()
else
love.graphics.pop()
love.graphics.setScissor()
end
end
function push:setBorderColor(color, g, b)
self._borderColor = g and {color, g, b} or color
end
function push:toGame(x, y)
x, y = x - self._OFFSET.x, y - self._OFFSET.y
local normalX, normalY = x / self._GWIDTH, y / self._GHEIGHT
x = (x >= 0 and x <= self._WWIDTH * self._SCALE.x) and normalX * self._WWIDTH or nil
y = (y >= 0 and y <= self._WHEIGHT * self._SCALE.y) and normalY * self._WHEIGHT or nil
return x, y
end
--doesn't work - TODO
function push:toReal(x, y)
return x + self._OFFSET.x, y + self._OFFSET.y
end
function push:switchFullscreen(winw, winh)
self._fullscreen = not self._fullscreen
local windowWidth, windowHeight = love.window.getDesktopDimensions()
if self._fullscreen then --save windowed dimensions for later
self._WINWIDTH, self._WINHEIGHT = self._RWIDTH, self._RHEIGHT
elseif not self._WINWIDTH or not self._WINHEIGHT then
self._WINWIDTH, self._WINHEIGHT = windowWidth * .5, windowHeight * .5
end
self._RWIDTH = self._fullscreen and windowWidth or winw or self._WINWIDTH
self._RHEIGHT = self._fullscreen and windowHeight or winh or self._WINHEIGHT
self:initValues()
love.window.setFullscreen(self._fullscreen, "desktop")
if not self._fullscreen and (winw or winh) then
windowUpdateMode(self._RWIDTH, self._RHEIGHT) --set window dimensions
end
end
function push:resize(w, h)
if self._highdpi then w, h = w / self._PSCALE, h / self._PSCALE end
self._RWIDTH = w
self._RHEIGHT = h
self:initValues()
end
function push:getWidth() return self._WWIDTH end
function push:getHeight() return self._WHEIGHT end
function push:getDimensions() return self._WWIDTH, self._WHEIGHT end
return push

+ 121
- 0
src/ser.lua View File

@@ -0,0 +1,121 @@
local pairs, ipairs, tostring, type, concat, dump, floor, format = pairs, ipairs, tostring, type, table.concat, string.dump, math.floor, string.format

local function getchr(c)
return "\\" .. c:byte()
end

local function make_safe(text)
return ("%q"):format(text):gsub('\n', 'n'):gsub("[\128-\255]", getchr)
end

local oddvals = {[tostring(1/0)] = '1/0', [tostring(-1/0)] = '-1/0', [tostring(-(0/0))] = '-(0/0)', [tostring(0/0)] = '0/0'}
local function write(t, memo, rev_memo)
local ty = type(t)
if ty == 'number' then
t = format("%.17g", t)
return oddvals[t] or t
elseif ty == 'boolean' or ty == 'nil' then
return tostring(t)
elseif ty == 'string' then
return make_safe(t)
elseif ty == 'table' or ty == 'function' then
if not memo[t] then
local index = #rev_memo + 1
memo[t] = index
rev_memo[index] = t
end
return '_[' .. memo[t] .. ']'
else
error("Trying to serialize unsupported type " .. ty)
end
end

local kw = {['and'] = true, ['break'] = true, ['do'] = true, ['else'] = true,
['elseif'] = true, ['end'] = true, ['false'] = true, ['for'] = true,
['function'] = true, ['goto'] = true, ['if'] = true, ['in'] = true,
['local'] = true, ['nil'] = true, ['not'] = true, ['or'] = true,
['repeat'] = true, ['return'] = true, ['then'] = true, ['true'] = true,
['until'] = true, ['while'] = true}
local function write_key_value_pair(k, v, memo, rev_memo, name)
if type(k) == 'string' and k:match '^[_%a][_%w]*$' and not kw[k] then
return (name and name .. '.' or '') .. k ..'=' .. write(v, memo, rev_memo)
else
return (name or '') .. '[' .. write(k, memo, rev_memo) .. ']=' .. write(v, memo, rev_memo)
end
end

-- fun fact: this function is not perfect
-- it has a few false positives sometimes
-- but no false negatives, so that's good
local function is_cyclic(memo, sub, super)
local m = memo[sub]
local p = memo[super]
return m and p and m < p
end

local function write_table_ex(t, memo, rev_memo, srefs, name)
if type(t) == 'function' then
return '_[' .. name .. ']=loadstring' .. make_safe(dump(t))
end
local m = {}
local mi = 1
for i = 1, #t do -- don't use ipairs here, we need the gaps
local v = t[i]
if v == t or is_cyclic(memo, v, t) then
srefs[#srefs + 1] = {name, i, v}
m[mi] = 'nil'
mi = mi + 1
else
m[mi] = write(v, memo, rev_memo)
mi = mi + 1
end
end
for k,v in pairs(t) do
if type(k) ~= 'number' or floor(k) ~= k or k < 1 or k > #t then
if v == t or k == t or is_cyclic(memo, v, t) or is_cyclic(memo, k, t) then
srefs[#srefs + 1] = {name, k, v}
else
m[mi] = write_key_value_pair(k, v, memo, rev_memo)
mi = mi + 1
end
end
end
return '_[' .. name .. ']={' .. concat(m, ',') .. '}'
end

return function(t)
local memo = {[t] = 0}
local rev_memo = {[0] = t}
local srefs = {}
local result = {}

-- phase 1: recursively descend the table structure
local n = 0
while rev_memo[n] do
result[n + 1] = write_table_ex(rev_memo[n], memo, rev_memo, srefs, n)
n = n + 1
end

-- phase 2: reverse order
for i = 1, n*.5 do
local j = n - i + 1
result[i], result[j] = result[j], result[i]
end

-- phase 3: add all the tricky cyclic stuff
for i, v in ipairs(srefs) do
n = n + 1
result[n] = write_key_value_pair(v[2], v[3], memo, rev_memo, '_[' .. v[1] .. ']')
end

-- phase 4: add something about returning the main table
if result[n]:sub(1, 5) == '_[0]=' then
result[n] = 'return ' .. result[n]:sub(6)
else
result[n + 1] = 'return _[0]'
end

-- phase 5: just concatenate everything
result = concat(result, '\n')
return n > 1 and 'local _={}\n' .. result or result
end

+ 123
- 0
src/simpleScale.lua View File

@@ -0,0 +1,123 @@
simpleScale = {}
--Your Game's Aspect Ratio
local gAspectRatio
--The Window's Aspect Ratio
local wAspectRatio
--The scale between the game and the window's aspect ratio
simpleScale.scale = 1

local xt, yt = 0, 0, 1
local gameW, gameH, windowW, windowH = 800, 600, 800, 600

-- Declares your game's width and height, and sets the window size/settings
-- To be used instead of love.window.setMode
-- [gw] and [gh] are the width and height of the initial game
-- [sw] and [sh] (optional) are the width and height of the final window
-- [settings] (optional) are settings for love.window.setMode
function simpleScale.setWindow(gw, gh, sw, sh, settings)
sw = sw or gw
sh = sh or gh
gAspectRatio = gw/gh
gameW = gw
gameH = gh
simpleScale.updateWindow(sw, sh, settings)
end

-- Updates the Window size/settings
-- To be used instead of love.window.setMode
-- [sw] and [sh] are the width and height of the new Window
-- [settings] (optional) are settings for love.window.setMode
function simpleScale.updateWindow(sw, sh, settings)
love.window.setMode(sw, sh, settings)
windowW, windowH = love.graphics.getWidth(), love.graphics.getHeight()
wAspectRatio = windowW/windowH

--Window aspect ratio is TALLER than game
if gAspectRatio > wAspectRatio then
scale = windowW/gameW
xt = 0
yt = windowH/2 - (scale*gameH)/2

--Window aspect ratio is WIDER than game
elseif gAspectRatio < wAspectRatio then
scale = windowH/gameH
xt = windowW/2 - (scale*gameW)/2
yt = 0

--Window and game aspect ratios are EQUAL
else
scale = windowW/gameW

xt = 0
yt = 0
end
simpleScale.scale = scale
end

-- If you screen is resizable on drag, you'll need to call this to make sure
-- the appropriate screen values stay updated
-- You can call it on love.update() with no trouble
function simpleScale.resizeUpdate()
windowW, windowH = love.graphics.getWidth(), love.graphics.getHeight()
wAspectRatio = windowW/windowH

--Window aspect ratio is TALLER than game
if gAspectRatio > wAspectRatio then
scale = windowW/gameW
xt = 0
yt = windowH/2 - (scale*gameH)/2

--Window aspect ratio is WIDER than game
elseif gAspectRatio < wAspectRatio then
scale = windowH/gameH
xt = windowW/2 - (scale*gameW)/2
yt = 0

--Window and game aspect ratios are EQUAL
else
scale = windowW/gameW

xt = 0
yt = 0
end
simpleScale.scale = scale
end

-- Transforms the game's window relative to the entire window
-- Call this at the beginning of love.draw()
function simpleScale.set()
love.graphics.push()
love.graphics.translate(xt, yt)
love.graphics.scale(scale, scale)
end

-- Untransforms the game's window
-- Call this at the end of love.draw
-- You can optionally make the letterboxes a specific color by passing
-- [color] (optional) a table of color values
function simpleScale.unSet(color)
love.graphics.scale(1/scale, 1/scale)
love.graphics.translate(-xt, -yt)
love.graphics.pop()

--Draw the Letterboxes
local r,g,b,a = love.graphics.getColor()
local originalColor = love.graphics.getColor()
local boxColor
if color == nil then
boxColor = {0,0,0}
else
boxColor = color
end
love.graphics.setColor(boxColor)
--Horizontal bars
if gAspectRatio > wAspectRatio then
love.graphics.rectangle("fill", 0, 0, windowW, math.abs((gameH*scale - (windowH))/2))
love.graphics.rectangle("fill", 0, windowH, windowW, -math.abs((gameH*scale - (windowH))/2))
--Vertical bars
elseif gAspectRatio < wAspectRatio then
love.graphics.rectangle("fill", 0, 0, math.abs((gameW*scale - (windowW))/2),windowH)
love.graphics.rectangle("fill", windowW, 0, -math.abs((gameW*scale - (windowW))/2),windowH)
end
love.graphics.setColor(r,g,b,a)
end

+ 70
- 0
src/tick.lua View File

@@ -0,0 +1,70 @@
-- tick
-- https://github.com/bjornbytes/tick
-- MIT License

local tick = {
framerate = nil,
rate = .03,
timescale = 1,
sleep = .001,
dt = 0,
accum = 0,
tick = 1,
frame = 1
}
local timer = love.timer
local graphics = love.graphics
love.run = function()
if not timer then
error('love.timer is required for tick')
end
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
timer.step()
local lastframe = 0
love.update(0)
return function()
tick.dt = timer.step() * tick.timescale
tick.accum = tick.accum + tick.dt
while tick.accum >= tick.rate do
tick.accum = tick.accum - tick.rate
if love.event then
love.event.pump()
for name, a, b, c, d, e, f in love.event.poll() do
if name == 'quit' then
if not love.quit or not love.quit() then
return a or 0
end
end
love.handlers[name](a, b, c, d, e, f)
end
end
tick.tick = tick.tick + 1
if love.update then love.update(tick.rate) end
end
while tick.framerate and timer.getTime() - lastframe < 1 / tick.framerate do
timer.sleep(.0005)
end
lastframe = timer.getTime()
if graphics and graphics.isActive() then
graphics.origin()
graphics.clear(graphics.getBackgroundColor())
tick.frame = tick.frame + 1
if love.draw then love.draw() end
graphics.present()
end
timer.sleep(tick.sleep)
end
end
return tick

+ 11
- 0
stateMachine.lua View File

@@ -0,0 +1,11 @@
state = require("levels/"..gameState)
print("levels/"..gameState)
function stateUpdate(dt)
state = require("levels/"..gameState)
state.update(dt)
end


function stateDraw()
state.draw()
end

Loading…
Cancel
Save