Created
June 30, 2013 01:28
-
-
Save XanDDemoX/5893398 to your computer and use it in GitHub Desktop.
Codea Project Gist Created with AutoGist
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AutoGist Tab Order Version: 2.1.5 | |
------------------------------ | |
This file should not be included in the Codea project. | |
#Floor | |
#Main | |
#Scene3D | |
#SceneCamera | |
#Tower |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
-- SceneCamera -- | |
-- A library which moves the camera and alters perspective -- | |
-- by animating them with tween, tween.path and tween.sequence -- | |
-- for cinematic effects or any other movement you can think of -- | |
-- Version:1.0.3 -- | |
-- Written by: XanDDemoX -- | |
------------------------------------------------------------------------------------------- | |
Floor = class() | |
function Floor:init() | |
-- you can accept and set parameters here | |
end | |
function Floor:draw() | |
-- Codea does not automatically call this method | |
-- Make a floor (borrowed from one of the example projects) | |
rotate(90,1,0,0) | |
sprite("SpaceCute:Background", 0, 0, 300, 300) | |
end | |
function Floor:touched(touch) | |
-- Codea does not automatically call this method | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
-- SceneCamera -- | |
-- A library which moves the camera and alters perspective -- | |
-- by animating them with tween, tween.path and tween.sequence -- | |
-- for cinematic effects or any other movement you can think of -- | |
-- Version:1.0.3 -- | |
-- Written by: XanDDemoX -- | |
------------------------------------------------------------------------------------------- | |
-- Use this function to perform your initial setup | |
function setup() | |
saveProjectInfo("Description","SceneCamera - An Animated 3D camera which uses the built in tween library") | |
saveProjectInfo("Author","XanDDemoX") | |
--setup a 3d scene - the camera is created in Scene3D | |
scene = Scene3D() | |
-- callback to print the finished messages | |
local rs =function() tween.resetAll() scene:reset() end | |
local completedCallback = function(...) print(...) end | |
-- SceneCamera is a use of the built in perspective and camera functions | |
-- in combination with the built in tween library allowing simple but powerful | |
-- custom camera movements which appear smooth because it is animated to new positions | |
-- easing is mostly compatible, however it appears tween.easing.bounce and tween.easing.elastic | |
-- and thier derrivatives do not work currently | |
-- camera movement functions create functions which are used to move the camera | |
-- so calling just move the camera wont move until the function it creates is called | |
-- | |
-- SceneCamera:move(time,target,options. returns function(callback,...) end | |
-- | |
-- Creates a function which when called creates a tween from the cameras current position to | |
-- the target. Options for the tween can also be optionally specified. | |
-- to use the callback pass callback and parameters when calling the created function | |
-- | |
-- SceneCamera:path(time,path,options). returns function(callback,...) end | |
-- | |
-- Creates a function which when called creates a tween.path from the cameras current position to | |
-- the end of the specified path. Options for the tween can also be optionally specified. | |
-- to use the callback pass callback and parameters when calling the created function | |
-- SceneCamera:sequence(...). returns function(callback,...) end | |
-- | |
-- Creates a function which when called creates a tween.sequence of the specified movements | |
-- to use the callback pass callback and parameters when calling the created function | |
-- | |
-- SceneCamera:seq(...) returns function(callback,...) end | |
-- shortcut for calling sequence | |
-- | |
-- | |
-- SceneCamera:reset(time) returns function(callback,...) end | |
-- creates a function which resets the camera to the position it was initialised with using either | |
-- a tween or immediately if no time is specfied | |
-- supported movement parameters for all movement functions | |
-- eye - vec3 - camera eye | |
-- centre - vec3 - camera centre | |
-- up - vec3 - camera up | |
-- fov - int / float - perspective fov | |
-- aspect - int / float - aspect ratio | |
-- size - int / float - size / zoom | |
-- angle - int / float - rotation around origin | |
-- sequence function specific additional parameters | |
-- time - int /float - duration of the movement | |
-- before- int / float - tween.delay before | |
-- after - int/ float- tween.delay after | |
-- callback - function - callback function | |
-- args - table - args to pass to callback | |
-- options - table of options (easing and loop) | |
-- e.g options={easing=tween.easing.cubicIn, loop=tween.loop.pingpong} | |
-- single movement example | |
local move = scene.camera:move(4,{angle=360,eye={y=600}},{easing=tween.easing.backIn}) | |
parameter.action("Move",function() | |
rs() | |
local mid,m = move(completedCallback,"Single Movement finished") | |
print("Move Started: returned id == wrapped id",mid==m.id," ",m) | |
-- the wrapped id (s) returned can stop and reset the movement | |
--m:stop() | |
--m:reset() | |
end) | |
local path = scene.camera:path(3,{{angle=180}, {eye = {x=360}} }) | |
parameter.action("Path",function() | |
rs() | |
local pid,p=path(completedCallback,"Path Movement Completed") | |
print("Path Started: returned id == wrapped id",pid==p.id," ",p) | |
-- the wrapped id returned (p) can stop and reset the path | |
--p:stop() | |
--p:reset() | |
end) | |
-- simple example sequence | |
seq = scene.camera:sequence({before=1,time=2,after=1,eye={x=180,y=300},centre={x=20,y=20}}, | |
{time=2,eye={x=0,y=300},centre={x=180,y=50},options={easing=tween.easing.expoIn}}, | |
{time=2,eye={x=0,y=0}, centre={x=0,y=0}}) | |
-- simple example sequence move button | |
parameter.action("Sequence",function() | |
rs() | |
local sid,s=seq(completedCallback,"Sequence Movement Completed") | |
print("Sequence started: returned id == wrapped id",sid==s.id," ",s) | |
-- the wrapped id returned (s) can stop and reset the sequence | |
--s:stop() | |
--s:reset() | |
end) | |
parameter.action("Reset",function()rs() end) | |
end | |
-- This function gets called once every frame | |
function draw() | |
-- This sets a dark background color | |
background(40, 40, 50) | |
-- This sets the line thickness | |
strokeWidth(5) | |
scene:draw() | |
end | |
-- see Scene3D for touch example | |
function touched(touch) | |
scene:touched(touch) | |
end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
-- SceneCamera -- | |
-- A library which moves the camera and alters perspective -- | |
-- by animating them with tween, tween.path and tween.sequence -- | |
-- for cinematic effects or any other movement you can think of -- | |
-- Version:1.0.3 -- | |
-- Written by: XanDDemoX -- | |
------------------------------------------------------------------------------------------- | |
Scene3D = class() | |
function Scene3D:init() | |
-- setup a scene for seeing the camera move | |
self.floor = Floor() | |
-- setup camera with defaults | |
-- optionall specfiy different initial values in the constructor in a table | |
-- e.g SceneCamera({fov=55, angle=60 }) | |
self.camera = SceneCamera({angle=0,fov=50}) | |
self.angle = self.camera.view.angle | |
self.fov = self.camera.view.fov | |
self.limits = { | |
minFov = 20, | |
maxFov = 100 | |
} | |
end | |
-- resets the camera and current fov and angle | |
function Scene3D:reset() | |
scene.camera:reset()() | |
self.angle = self.camera.view.angle | |
self.fov = self.camera.view.fov | |
end | |
function Scene3D:draw() | |
-- Codea does not automatically call this method | |
-- call the cameras draw method to set the position | |
self.camera:draw() | |
-- draw the scene | |
self.floor:draw() | |
-- set back to normal 2d drawing | |
ortho() | |
viewMatrix(matrix()) | |
end | |
-- touch example | |
function Scene3D:touched(touch) | |
-- Codea does not automatically call this method | |
if touch.state == MOVING then | |
-- determine which way left/right or up/down | |
if (touch.deltaX > 0 and touch.deltaX > touch.deltaY) or | |
(touch.deltaX < 0 and touch.deltaX < touch.deltaY) then | |
-- increment or decrement the angle roughly by delta | |
self.angle = self.angle + (touch.deltaX / 10) * 3 | |
else | |
-- increment or decrement the fov roughly by delta | |
self.fov = self.fov + (touch.deltaY / 10) * 3 | |
-- limit fov | |
if self.fov > self.limits.maxFov then | |
self.fov = self.limits.maxFov | |
elseif self.fov < self.limits.minFov then | |
self.fov = self.limits.minFov | |
end | |
end | |
-- stop the current movement | |
if self.curMove ~= nil then | |
self.curMove:stop() | |
self.curMove = nil | |
end | |
-- prepare and start camera movement | |
local id | |
id,self.curMove=self.camera:move(0.3,{angle=self.angle,fov=self.fov})() | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
-- SceneCamera -- | |
-- A library which moves the camera and alters perspective -- | |
-- by animating them with tween, tween.path and tween.sequence -- | |
-- for cinematic effects or any other movement you can think of -- | |
-- Version:1.0.3 -- | |
-- Written by: XanDDemoX -- | |
------------------------------------------------------------------------------------------- | |
SceneCamera = class() | |
-- default setup of camera and perspective | |
SceneCamera.default = { | |
eye=vec3(0,300,-300), | |
centre=vec3(0,0,0), | |
up =vec3(0,1,0), | |
fov=45, | |
size=150, | |
angle=0, | |
options={easing = tween.easing.linear, | |
loop = tween.loop.once} | |
} | |
-- creates a new scene camera with optional initial values contained witin a table passed on construction | |
-- eye={x=5,y=200,z=50},centre={x=10,y=20,z=30},up={x=20,y=50,z=70},fov=35,aspect=600/500, | |
-- options={easing = tween.easing.linear,loop = tween.loop.once}} | |
function SceneCamera:init(tbl) | |
tbl = tbl or {} | |
-- setup parameters from table or defaults | |
self.view = {} | |
self.view.eye = SceneCamera.syncvec3(tbl.eye,SceneCamera.default.eye) or | |
SceneCamera.copyvec3(SceneCamera.default.eye) | |
self.view.centre =SceneCamera.syncvec3(tbl.centre,SceneCamera.default.centre) or | |
SceneCamera.copyvec3(SceneCamera.default.centre) | |
self.view.up = SceneCamera.syncvec3(tbl.up,SceneCamera.default.up) or | |
SceneCamera.copyvec3(SceneCamera.default.up) | |
self.view.fov= tbl.fov or SceneCamera.default.fov | |
self.view.aspect= tbl.aspect or WIDTH/HEIGHT | |
self.view.size = tbl.size or SceneCamera.default.size | |
self.view.angle = tbl.angle or SceneCamera.default.angle | |
self.options = tbl.options or {} | |
self.options.easing = self.options.easing or SceneCamera.default.options.easing | |
self.options.loop = self.options.loop or SceneCamera.default.options.loop | |
self.initial = SceneCamera.copyview(self.view) | |
end | |
-- sets the camera and perspective | |
function SceneCamera:draw() | |
-- set perspective | |
perspective(self.view.fov, self.view.aspect) | |
-- set camera pos | |
camera(self.view.eye.x, | |
self.view.eye.y, | |
self.view.eye.z, | |
self.view.centre.x, | |
self.view.centre.y, | |
self.view.centre.z, | |
self.view.up.x, | |
self.view.up.y, | |
self.view.up.z) | |
-- set size and rotation | |
translate(0,-self.view.size/2,0) | |
rotate(self.view.angle,0,1,0) | |
end | |
-- creates a function to perform a tween.sequence when the returned function is called | |
-- when the returned function is called it returns the tween id and a table which wraps the id | |
-- with a stop and reset function. | |
--------------------------------------- | |
-- call sequence with all required movements. with time, delays before and after, callbacks and args. | |
--{time=2, callback = function() end, args={} before=1,after=1, | |
--eye={x=5,y=200,z=50},centre={x=10,y=20,z=30},up={x=20,y=50,z=70},fov=35,aspect=600/500}, | |
-- {eye={x=10,y=300,z=50},centre={x=10,y=20,z=30},up={x=20,y=50,z=70},fov=35,aspect=600/500}} | |
-- options - any custom options other than the instances default | |
-- returns a function(callback,...) end which calls a tween.sequence and returns the id and a table | |
-- which wraps the id with a stop and reset function. | |
--if a callback and args is passed its called on completion of the sequence | |
function SceneCamera:sequence(...) | |
path = Tower(arg) | |
local tbl = Tower() | |
for k,v in path:items() do | |
v.time = v.time or 1 | |
v.args = v.args or {} | |
v.options = v.options or {} | |
v.options.easing = self.options.easing | |
v.options.loop = self.options.loop | |
-- set delay before if specified | |
if v.before ~= nil and v.before > 0 then | |
tbl:push(function() return tween.delay(v.before) end) | |
end | |
-- set movement | |
tbl:push(function() | |
return self:move(v.time,{eye = v.eye,centre= v.centre,up= v.up, | |
fov=v.fov,aspect = v.aspect,size =v.size,angle = v.angle},v.options)(v.callback,unpack(v.args)) | |
end) | |
-- set delay after if specfied | |
if v.after ~= nil and v.after > 0 then | |
tbl:push(function() return tween.delay(v.after) end) | |
end | |
end | |
return function(cb,...) | |
if cb ~= nil and path:count() > 0 then | |
local args = arg | |
local i = path:item(path:count()) | |
local new =-1 | |
-- setup correct function for callback | |
if i.after ~= nil and i.after > 0 then | |
new = function() return tween.delay(i.after,cb,unpack(args)) end | |
else | |
new = function() return self:move(i.time,{ | |
eye=i.eye,centre = i.centre,up =i.up,fov = i.fov, | |
aspect = i.aspect,angle = i.angle,size = i.size},i.options)(cb,unpack(args)) end | |
end | |
-- bin the original function without a callbck and add the new one | |
tbl:pop() | |
tbl:push(new) | |
end | |
local id = tween.sequence(unpack(tbl:map(function(tw) | |
local id = tw() | |
return id end))) | |
return id,SceneCamera.wrap(id) | |
end | |
end | |
-- shortcut method for sequence | |
function SceneCamera:seq(...) | |
return self:sequence(...) | |
end | |
-- creates a function to perform a movement of the camera with tween.path | |
-- when the returned function is called it returns the tween id and a table which wraps the id | |
-- with a stop and reset function. | |
--------------------------------------- | |
-- time - the time span of the movement | |
-- path - the path to animate from the current position using one or more of the options below | |
-- e.g {{eye={x=5,y=200,z=50},centre={x=10,y=20,z=30},up={x=20,y=50,z=70},fov=35,aspect=600/500}, | |
-- {eye={x=10,y=300,z=50},centre={x=10,y=20,z=30},up={x=20,y=50,z=70},fov=35,aspect=600/500}} | |
-- options - any custom options other than the instances default | |
-- returns a function(callback,...) end which calls a tween.path and returns the id and a table | |
-- which wraps the id with a stop and reset function. | |
--if a callback and args is passed its called on completion of the path | |
function SceneCamera:path(time,path,options) | |
if time == nil then return end | |
path = path or {} | |
-- set defaults or values | |
for k,v in pairs(path) do | |
v.eye = SceneCamera.syncvec3(v.eye,self.view.eye) or self.view.eye | |
v.centre = SceneCamera.syncvec3(v.centre,self.view.centre) or self.view.centre | |
v.up = SceneCamera.syncvec3(v.up,self.view.up) or self.view.up | |
v.fov = v.fov or self.view.fov | |
v.aspect = v.aspect or self.view.aspect | |
v.size = v.size or self.view.size | |
v.angle = v.angle or self.view.angle | |
end | |
options = options or {} | |
options.easing = self.options.easing | |
options.loop = self.options.loop | |
-- create function to call path | |
return function(callback,...) | |
local id = tween.path(time,self.view,path,options,callback,unpack(arg)) | |
return id,SceneCamera.wrap(id) | |
end | |
end | |
-- creates a function to perform a movement of the camera with a single tween | |
-- when the returned function is called | |
-- time - the time span of the movement | |
-- target - the target values to animate from the current position using one or more of the options below | |
-- e.g {eye={x=5,y=200,z=50},centre={x=10,y=20,z=30},up={x=20,y=50,z=70},fov=35,aspect=600/500} | |
-- options - any custom options other than the instances default | |
-- returns a function(callback,...) end which calls a tween.path and returns the id and a table | |
-- which wraps the id with a stop and reset function. | |
--if a callback and args is passed its called on completion of the tween | |
function SceneCamera:move(time,target,options) | |
if time == nil then return end | |
-- set defaults or values | |
local tbl = target or {} | |
options = options or {} | |
options.easing = self.options.easing | |
options.loop = self.options.loop | |
-- create function which calls tween and returns id | |
return function(callback,...) | |
local id = tween(time,self.view | |
,tbl,options,callback,...) | |
return id,SceneCamera.wrap(id) | |
end | |
end | |
-- create a function that resets the camera position to the initial values it was created with | |
function SceneCamera:reset(time) | |
if time ~= nil and time > 0 then | |
return function(callback,...) | |
return self:move(time,self.copyview(self.initial),self.initial.options)(callback,...) | |
end | |
else | |
return function(callback,...) | |
self.view = SceneCamera.copyview(self.initial) | |
if callback ~= nil and type(callback) == "function" then callback(...) end | |
end | |
end | |
end | |
-- wraps tween id within a table which contains a stop and reset function | |
function SceneCamera.wrap(twid) | |
return { | |
id=twid, | |
stop=function(self) return tween.stop(self.id) end, | |
reset=function(self) return tween.reset(self.id) end | |
} | |
end | |
-- copy a vec3 | |
function SceneCamera.copyvec3(v) | |
if v == nil then return end | |
return vec3(v.x,v.y,v.z) | |
end | |
-- sychronise a vec3 with another replacing nils in vx with values from vy | |
function SceneCamera.syncvec3(vx,vy) | |
if vx == nil or vy == nil then return end | |
local x = vx.x or vy.x | |
local y = vx.y or vy.y | |
local z = vx.z or vy.z | |
return vec3(x,y,z) | |
end | |
function SceneCamera.copyview(view) | |
local newView = {} | |
for i,v in pairs(view) do | |
if v ~= nil and type(v) == "table" then | |
newView[i] = SceneCamera.copyview(v) | |
elseif v ~= nil and type(v) == "userdata" then | |
newView[i] = SceneCamera.copyvec3(v) | |
else | |
newView[i] = v | |
end | |
end | |
return newView | |
end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
-- SceneCamera -- | |
-- A library which moves the camera and alters perspective -- | |
-- by animating them with tween, tween.path and tween.sequence -- | |
-- for cinematic effects or any other movement you can think of -- | |
-- Version:1.0.3 -- | |
-- Written by: XanDDemoX -- | |
------------------------------------------------------------------------------------------- | |
Tower = class() | |
-- An all in one index based table manipulation (array manipulation) class which takes some inspiration from | |
-- .net and linq functions. | |
-- this can also operate, based on usage, as a stack (Last in first out LiFo), queue (First in First out FiFo) or -- Dequeue / (pronounced "deck") which is also called a double ended queue. e.g stack operates normally with push - | |
-- and pop, queue operates with push and pull. and poke inserts items at the top by default poke is equivalent to | |
-- table.insert(self._items,1) | |
-- note: The implementation of dequeue and queue is not as efficient as it could be because it | |
-- invites the internal table to shift its items to close gaps >_< | |
-- the user can select when to optimise the different associated functions (push,pop/poke,pull) | |
-- which inverts the internal table and switches push and pop from inserting and removing from the bottom | |
-- of the table to the top | |
-- this also provides powerful manipulation for using the contents of the collection with dynamic functions :D | |
-- (which is used for calling event callbacks) | |
function Tower:init(items,indexed) | |
self._itemCount = 0 | |
self._items = {} | |
self._optimisePushPop = true | |
self:addrange(items,indexed) | |
end | |
-- internal function to increment / decrement the item count | |
function Tower:_incCount(amount) | |
self._itemCount = self._itemCount + amount | |
end | |
-- internal property returns the current index to pop items from | |
function Tower:_popIndex() | |
if self._optimisePushPop == true then | |
return self._itemCount | |
else | |
return 1 | |
end | |
end | |
-- internal property returns the current index to pull items from | |
function Tower:_pullIndex() | |
if self._optimisePushPop == false then | |
return self._itemCount | |
else | |
return 1 | |
end | |
end | |
-- returns the item at a given index or nil | |
function Tower:item(index) | |
if index < 1 or index > self._itemCount then | |
return nil | |
else | |
return self._items[index] | |
end | |
end | |
function Tower:items() | |
return ipairs(self._items) | |
end | |
-- returns a shallow copy of the internal items collection | |
function Tower:getItems() | |
local cloneItems = {} | |
for i,v in ipairs(self._items) do | |
table.insert(cloneItems,v) | |
end | |
return cloneItems | |
end | |
-- returns a clone with a shallow copy of the internal items collection | |
function Tower:clone() | |
return Tower(self._items) | |
end | |
-- inserts an item at the top of the stack (bottom of the table) | |
function Tower:push(...) | |
if #arg > 0 then | |
for i,v in ipairs(arg) do | |
if self._optimisePushPop == true then | |
self:insertAt(v) | |
else | |
self:insertAt(v,1) | |
end | |
end | |
end | |
end | |
function Tower:pushArray(items) | |
if #items > 0 then | |
self:push(unpack(items)) | |
end | |
end | |
-- removes and returns the first item at the top of the stack / bottom of the queue (bottom of the table) | |
-- or returns nil | |
function Tower:pop() | |
local index = self:_popIndex() | |
local item = self:item(index) | |
if item then | |
self:removeAt(index) | |
end | |
return item | |
end | |
-- inserts the given item at the the bottom of the stack / top of the queue (top of the table) | |
function Tower:poke(...) | |
if #arg > 0 then | |
for i,v in ipairs(arg) do | |
if self._optimisePushPop == false then | |
self:insertAt(v) | |
else | |
self:insertAt(v,1) | |
end | |
end | |
end | |
end | |
function Tower:pokeArray(items) | |
if #items > 0 then | |
self:poke(unpack(items)) | |
end | |
end | |
-- removes and returns the first item at the bottom of the stack / top of the queue (top of the table) | |
function Tower:pull() | |
local index = self:_pullIndex() | |
local item = self:item(index) | |
if item then | |
self:removeAt(index) | |
end | |
return item | |
end | |
-- returns the first item at the top of the stack / bottom of the queue (top of the table) | |
-- or returns nil | |
function Tower:peek() | |
return self:item(self:_popIndex()) | |
end | |
-- returns the first item at the bottom of the stack / top of the queue (bottom of the table) | |
function Tower:peer() | |
return self:item(self:_pullIndex()) | |
end | |
-- swaps push and pop from using the top of the table too the bottom | |
-- giving cheaper calls when pushing/poping items. | |
-- but more expensive calls to pull and poke. | |
function Tower:optimisePushPop() | |
if self._optimisePushPop == false then | |
self:invert() | |
self._optimisePushPop = true | |
end | |
end | |
-- swaps pull and poke from using the top of the table to the bottom | |
-- giving cheaper calls when pulling / poking items. | |
-- but more expensive calls to push and pop. | |
function Tower:optimisePullPoke() | |
if self._optimisePushPop == true then | |
self:invert() | |
self._optimisePushPop = false | |
end | |
end | |
-- example optimise use case: using tower as a large queue | |
-- tower populated with push initially then call optimisePullPoke | |
-- this has an initial cost of inverting the table but yeilds cheeper calls to | |
-- pull because the items are removed from the bottom of the table | |
-- circomventing the table shifting items up on removal or down on insert | |
-- (via poke). after using optimisePullPoke calls to push and pop become more | |
-- expensive as they are switched to use the top of the table instead | |
-- returns the count of items currently in the internal collection | |
function Tower:count() | |
return self._itemCount | |
end | |
function Tower:invert() | |
if self._itemCount > 0 then | |
local items = self:getItems() | |
local count = self._itemCount | |
self:clear() | |
-- counter for decrementing index | |
local c = count | |
for i=1, count do | |
self:insertAt(items[c]) | |
c = c - 1 | |
end | |
end | |
end | |
-- clears all items from the tower | |
function Tower:clear() | |
self._items = {} | |
self._itemCount = 0 | |
end | |
-- returns the first index from the top within the internal collection of the given item | |
-- otherwise returns -1 | |
function Tower:indexOf(item) | |
local items = self._items | |
for i,v in ipairs(items) do | |
if v == item then return i end | |
end | |
return -1 | |
end | |
-- inserts the given item at the given index or the bottom of the collection (if index is > count) | |
-- returns the true if the item was inserted or false if the index is < 0 | |
-- if index is nil item is inserted at the bottom of the collection | |
function Tower:insertAt(item, index) | |
if item == nil then return end | |
if index then | |
if index > self._itemCount then | |
table.insert(self._items,item) | |
elseif index < 0 then | |
table.insert(self._items,1,item) | |
else | |
table.insert(self._items,index,item) | |
end | |
else | |
table.insert(self._items,item) | |
end | |
self:_incCount(1) | |
return true | |
end | |
-- updates the item at the given index with the given new value | |
-- returns true if the item was updated or false if the index is out of range | |
function Tower:updateAt(index,newValue) | |
if index < 0 or index > self._itemCount then | |
return false | |
else | |
self._items[index] = newValue | |
return true | |
end | |
end | |
-- returns true if the item at the given index was removed from the internal collection | |
-- otherwise returns false | |
function Tower:removeAt(index) | |
if index < 0 or index > self._itemCount then | |
return false | |
else | |
table.remove(self._items,index) | |
self:_incCount(-1) | |
return true | |
end | |
end | |
-- returns true if the given item is contained within the internal collection | |
-- otherwise returns false | |
function Tower:contains(item) | |
for i,v in ipairs(self._items) do | |
if v == item then return true end | |
end | |
return false | |
end | |
function Tower:addrange(items,indexed) | |
if items == nil then return end | |
if #items > 0 then | |
if indexed == nil then indexed = true end | |
if indexed then | |
for i,v in ipairs(items) do | |
self:insertAt(v) | |
end | |
else | |
for i,v in pairs(items) do | |
self:insertAt(v) | |
end | |
end | |
end | |
end | |
function Tower:add(item) | |
self:insertAt(item) | |
end | |
-- returns true if the given item was removed from the internal collection | |
-- otherwise returns false | |
function Tower:remove(item) | |
local index = self:indexOf(item) | |
if index > 0 then | |
return self:removeAt(index) | |
end | |
return false | |
end | |
-- returns the first item matched by the given function(item) from the top of the internal collection | |
-- otherwise returns nil | |
function Tower:find(findDelegate) | |
local items = self._items | |
for i,v in ipairs(items) do | |
if findDelegate(v) then return v end | |
end | |
return nil | |
end | |
-- returns the first index from the top of the item matched by the given function(item) | |
-- otherwise returns -1 | |
function Tower:findIndex(findDelegate) | |
local items = self._items | |
for i,v in ipairs(items) do | |
if findDelegate(v) == true then return i end | |
end | |
return -1 | |
end | |
-- returns all indexs matched by the given function(item) | |
-- otherwise returns nil | |
function Tower:findIndexes(findDelegate) | |
local items = self._items | |
local foundItems = {} | |
for i,v in ipairs(items) do | |
if findDelegate(v) then | |
table.insert(foundItems,i) | |
end | |
end | |
return foundItems | |
end | |
-- returns all items matched by the given function(item) | |
-- otherwise returns nil | |
function Tower:findAll(findDelegate) | |
local items = self._items | |
local foundItems = {} | |
for i,v in ipairs(items) do | |
if findDelegate(v) then | |
table.insert(foundItems,v) | |
end | |
end | |
return foundItems | |
end | |
-- updates the first item from the top of the colection | |
-- which is matched by the given function(item) with the given new value | |
-- returns true if an item was updated otherwise false | |
function Tower:update(findDelegate,newValue) | |
local index = self:findIndex(findDelegate) | |
if index > 0 then | |
return self:updateAt(index,newValue) | |
end | |
return false | |
end | |
-- updates all items that match the given function(item) with the given new value | |
-- returns the count of items updated | |
function Tower:updateAll(findDelegate,newValue) | |
local indexes = self:findIndexes(findDelegate) | |
local count = 0 | |
for i,v in ipairs(indexes) do | |
if self:updateAt(index,newValue) then count = count + 1 end | |
end | |
return count | |
end | |
-- removes the first item from the top of the collection which is matched by the given function(item) | |
function Tower:delete(findDelegate) | |
local item = self:find(findDelegate) | |
if item then | |
return self:remove(item) | |
end | |
return false | |
end | |
-- removes the all items from the collection which are matched by the given function(item) | |
-- returns the count of items removed | |
function Tower:deleteAll(findDelegate) | |
local indexes = self:findIndexes(findDelegate) | |
local count = 0 | |
for i,v in ipairs(indexes) do | |
if self:removeAt((v-count)) then count = count + 1 end | |
end | |
return count | |
end | |
-- maps the items contained in the internal collection to the given function | |
function Tower:paramMap(func) | |
if func == nil then return function() end end | |
if self._itemCount < 1 then return function() end end | |
local funcType = type(func) | |
if funcType == "function" then | |
local items = self:getItems() | |
return function () return func(unpack(items)) end | |
elseif funcType == "table" then | |
local items = self:clone() | |
local functable = Tower(func) | |
return function() | |
local result = Tower() | |
functable:foreach(function(f) if f then result:add(items:paramMap(f)()) end end) | |
return result | |
end | |
else | |
return function() end | |
end | |
end | |
-- maps an item to the parameter of a given function for each item contained in the within the internal collection | |
function Tower:map(func) | |
if self._itemCount < 1 then return nil end | |
local funcs = {} | |
local items = self:getItems() | |
for i,v in ipairs(items) do | |
funcs[i] = func(v) | |
end | |
return funcs | |
end | |
-- maps an item as the parameters to a given function for each item within the internal collection | |
function Tower:mapn(func) | |
if self._itemCount < 1 then return nil end | |
local result = {} | |
local items = self:getItems() | |
local count = self._itemCount | |
local n = #self:peer()[1] | |
for i=1,n do | |
local args = {} | |
for k,v in ipairs(items) do | |
table.insert(args,v[i]) | |
end | |
local f = func(unpack(args)) | |
table.insert(result,f) | |
end | |
return result | |
end | |
-- iterates the internal collection calling a user defined function | |
function Tower:foreach(func) | |
if func then | |
for k,v in self:items() do | |
func(v) | |
end | |
end | |
end | |
-- sorts a (shallow) cloned insance of self and returns | |
function Tower:clonesort(func) | |
if func then | |
local cloneobj = self:clone() | |
cloneobj:sort(func) | |
return cloneobj | |
else | |
return nil | |
end | |
end | |
-- sorts the internal collection with a user defined function using table.sort | |
function Tower:sort(func) | |
if func then | |
table.sort(self._items,func) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment