-- title: cylshooter -- author: pixelbath -- desc: short description -- site: website link -- license: MIT License (change this to your license of choice) -- version: 0.1 -- script: lua -- The idea: -- like Resogun, a cylindrical shooter -- 1. render map -- 2. fix column-by-column, raycast style -- 3. how to draw background? -- 1. render bg map offscreen -- 2. memcpy to onscreen -- 3. render fg map offscreen -- 4. memcpy/pix the fg to the screen? local t=0 local player = { x=140, y=70, vx=0, vy=0, speed=1.5, } function player:update() self.vx = 0 self.vy = 0 if btn(0) then self.vy=-self.speed end if btn(1) then self.vy=self.speed end if btn(2) then self.vx=-self.speed end if btn(3) then self.vx=self.speed end -- slow down diagonal movements if self.vx * self.vy ~= 0 then self.vx = self.vx * 0.707 self.vy = self.vy * 0.707 end self.x = self.x + self.vx self.y = self.y + self.vy end local Random = { angle = { between = function(min, max) return min + math.random() * (max - min) end } } local Shot = { x = 20, y = 20, speed = {}, direction = {}, position = {}, velocity = {}, bullets = {}, } function Shot:new() local shot = setmetatable({}, { __index = Shot }) shot.bullets = {} return shot end function Shot.speed:set(value) return function() Shot.speed = value end end function Shot.position:set(distance, bearing) return function() Shot.x = math.cos(math.rad(bearing)) * distance Shot.y = math.sin(math.rad(bearing)) * distance end end function Shot.velocity:set(speed, direction) return function() Shot.speed = speed Shot.direction = direction end end function Shot.direction:add(degrees) return function() Shot.direction = Shot.direction + degrees end end -- Pattern manager local PatternManager = { activePatterns = {}, windowWidth = 800, -- Default window size windowHeight = 600 -- Default window size } function PatternManager:new(windowWidth, windowHeight) local manager = setmetatable({}, { __index = PatternManager }) manager.activePatterns = {} manager.windowWidth = windowWidth or 800 manager.windowHeight = windowHeight or 600 return manager end -- Initialize the pattern manager with window dimensions patternManager = PatternManager:new(240,136) function TIC() cls() if t==0 then -- Start both patterns patternManager:startPattern("firstShot") patternManager:startPattern("secondShot") end -- player:update() patternManager:update() patternManager:draw() t = t + 1 end -- Pattern system functions local function aim() return function() local dx = player.x - Shot.x local dy = player.y - Shot.y Shot.direction = math.deg(math.atan2(dy, dx)) end end local function line(count, options) return function() local speedChange = options.shotSpeedChange or 0 local currentSpeed = Shot.speed for i = 1, count do currentSpeed = currentSpeed + (speedChange * (count - 1)) table.insert(Shot.bullets, { x = Shot.x, y = Shot.y, speed = currentSpeed, direction = Shot.direction, vanishTime = nil }) end end end local function wait(frames) return function() for i = 1, frames do coroutine.yield() end end end local function fire(actions) return function() local bullet = { x = Shot.x, y = Shot.y, speed = Shot.speed, direction = Shot.direction, vanishTime = nil } -- for _, action in ipairs(actions) do -- if type(action) == "function" then -- action(bullet) -- end -- end table.insert(Shot.bullets, bullet) end end local function vanish() return function(bullet) bullet.vanishTime = 0 end end local function loop(actions) return function() while true do for _, action in ipairs(actions) do if type(action) == "function" then action() end end end end end -- Pattern definitions local patterns = { firstShot = { Shot.speed:set(2), loop({ -- Shot.position:set(150, Random.angle.between(0, 360)), aim(), line(8, { shotSpeedChange = 0.5 }), wait(100) }) }, secondShot = { Shot.velocity:set(1, 90), loop({ fire({ wait(60), vanish() }), Shot.direction:add(12), wait(1) }) }, } function PatternManager:startPattern(patternName) local pattern = patterns[patternName] if not pattern then error("Pattern " .. patternName .. " not found") end local co = coroutine.create(function() for _, action in ipairs(pattern) do if type(action) == "function" then action() end end end) table.insert(self.activePatterns, { coroutine = co, name = patternName }) end function PatternManager:update() -- Update all active patterns for i = #self.activePatterns, 1, -1 do local pattern = self.activePatterns[i] if coroutine.status(pattern.coroutine) ~= "dead" then local success, err = coroutine.resume(pattern.coroutine) if not success then error("Error in pattern " .. pattern.name .. ": " .. err) end else table.remove(self.activePatterns, i) end end -- Update bullet positions for i = #Shot.bullets, 1, -1 do local bullet = Shot.bullets[i] if bullet.vanishTime then bullet.vanishTime = bullet.vanishTime + 1 if bullet.vanishTime >= 30 then table.remove(Shot.bullets, i) end else bullet.x = bullet.x + math.cos(math.rad(bullet.direction)) * bullet.speed bullet.y = bullet.y + math.sin(math.rad(bullet.direction)) * bullet.speed -- Remove bullets that are off screen if bullet.x < -50 or bullet.x > self.windowWidth + 50 or bullet.y < -50 or bullet.y > self.windowHeight + 50 then table.remove(Shot.bullets, i) end end end end function PatternManager:draw() -- Draw all bullets for _, bullet in ipairs(Shot.bullets) do circ(bullet.x, bullet.y, 2, 6) end end -- -- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57 --