-- Aquario.lua -- Copyright (c) Marcio M. Andrade -- Tank class definition Tank = {} function Tank:init(id) -- The background is composed of 4 bitmaps of same size in a 2x2 matrix. -- This is necessary because in high density mode a 320x320 bitmap -- does not fit in a single resource (PalmOS limitation). -- The id parameter is the bitmap resource id of the upper left quarter. local bmp, dx, dy -- Load the upper left quarter and get its dimensions bmp = resource.open("Tbmp", id) _, dx, dy = resource.size(bmp) -- Create the offscreen buffer and selects it for writing self.width = dx * 2 self.height = dy * 2 self.buffer = buffer.new(self.width, self.height) buffer.use(self.buffer) -- Draw the upper left quarter screen.moveto(0, 0) resource.draw(bmp) resource.close(bmp) -- Load the upper right quarter and draw it screen.moveto(dx, 0) bmp = resource.open("Tbmp", id+1) resource.draw(bmp) resource.close(bmp) -- Load the bottom left quarter and draw it screen.moveto(0, dy) bmp = resource.open("Tbmp", id+2) resource.draw(bmp) resource.close(bmp) -- Load the bottom right quarter and draw it screen.moveto(dx, dy) bmp = resource.open("Tbmp", id+3) resource.draw(bmp) resource.close(bmp) -- Select the screen for writing and clear it buffer.use() screen.clear() -- Create the sprite background centralized on the screen local width,height = screen.mode() sprite.init(self.buffer, (width - self.width)/ 2, (height - self.height) / 2) -- The fish tank is initialy empty self.inhabitants = {} end function Tank:add(fish) -- Add one fish to the tank table.insert(self.inhabitants, fish) fish.index = table.getn(self.inhabitants) fish.tank = self fish.x = -fish.width fish.y = math.random(self.height - fish.height) -- Create the sprite sprite.add(fish.index, fish) end function Tank.animate_item(i, fish) -- Helper function to iterate the inhabitants table (animate) fish:move() end function Tank:animate() -- Iterate the inhabitants table and move each fish table.foreachi(self.inhabitants, self.animate_item) -- Update the sprite engine sprite.update() end function Tank.destroy_item(i, fish) -- Helper function to iterate the inhabitants table (destroy) sprite.remove(fish.index) fish:destroy() end function Tank:finish() -- Finish the sprite engine and free the offscreen buffer sprite.finish() buffer.free(self.buffer) -- Iterate the inhabitants table and destroy each fish table.foreachi(self.inhabitants, self.destroy_item) end -- Fish class definition Fish = {} function Fish.reverse(fish) -- Reverse the direction of a fish by swapping its bitmap. fish.right = not fish.right if fish.right then fish.bitmap = fish.rightSide else fish.bitmap = fish.leftSide end end function Fish.collision(fish1,fish2) -- The sprite collision function. If two fishes collide and are moving -- in opposite directions, reverse both. if fish1.right ~= fish2.right then local now = os.time() -- This check avoids a fast reverse cycle between two fishes if (now - fish1.lasthit) > 1 then fish1:reverse() fish1.lasthit = now end if (now - fish2.lasthit) > 1 then fish2:reverse() fish2.lasthit = now end end end function Fish.move(fish) -- Move a fish by updating its horizontal position according to its speed if fish.right then fish.x = fish.x + fish.speed else fish.x = fish.x - fish.speed end -- If the fish moved out of the screen, reverse its direction -- and set a new vertical position. if fish.x < -fish.width or fish.x > fish.tank.width then fish:reverse() fish.lasthit = 0 fish.y = math.random(fish.tank.height - fish.height) end end function Fish.destroy(fish) -- Close the bitmap resources allocated to the fish resource.close(fish.rightSide) resource.close(fish.leftSide) end function Fish:new(id) -- Ceate a new Fish object. -- A fish is a Lua table with various fields and methods. -- Loads two bitmaps. The parameter id is the bitmap pointing right, -- and id+1000 is the bitmap pointing left. local b1 = resource.open("Tbmp", id) local b2 = resource.open("Tbmp", id + 1000) local size, dx, dy = resource.size(b1) local fish = { -- These fields are required by the sprite engine bitmap = b1, active = true, x = 0, y = 0, -- These fields are not part of the sprite engine, but are used -- by the Fish class right = true, rightSide = b1, leftSide = b2, width = dx, height = dy, speed = math.random(4), lasthit = 0 } -- Access the methods in the Fish class by defining a meta table setmetatable(fish, { __index = self }) return fish end -- Fish sub-classes definitions Angel = {} function Angel:new() return Fish:new(1001) end Flame = {} function Flame:new() return Fish:new(1002) end Pooler = {} function Pooler:new() return Fish:new(1003) end Copper = {} function Copper:new() return Fish:new(1004) end -- The main code local start = os.clock() local frames = 0 local last = start function Animate() local now = os.clock() if now - last >= 0.05 then Tank:animate() last = now frames = frames + 1 local fps = frames / (now - start) -- show frames per socond screen.moveto(0,0) print(string.format("%05.2f",fps)) end end function MainForm() math.randomseed(os.date("%S")) Tank:init(3001) Tank:add(Angel:new()) Tank:add(Flame:new()) Tank:add(Pooler:new()) Tank:add(Copper:new()) gui.sethandler(nilEvent, Animate) gui.sethandler(penDown, Animate) gui.sethandler(penMove, Animate) gui.sethandler(keyDown, Animate) gui.main(50) Tank:finish() end MainForm()