-
-
Save monkeyman32123/66dbce67133583804bda to your computer and use it in GitHub Desktop.
Object Oriented Draws
This file contains 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
--# Main | |
function setup() | |
n = nil | |
m = Persist(color(255,255,255),false) | |
p = Persist("spr",50,90) | |
p.angCorr = 90 | |
end | |
function touched(t) | |
p:oidCyc(t) | |
end | |
function perFrameCalculations() | |
p:checkoidandcall({"p:roToward(p.t)","p:moveByAngle(n,3,true,true)"}) | |
end | |
--draws all persistent objects, and calls "perFrameCalculations" prior to, to do calculations and keep the draw loop clean | |
function draw() | |
if perFrameCalculations then | |
perFrameCalculations() | |
end | |
if masterPersist then | |
masterPersist:drawall() | |
end | |
end | |
--# persist | |
--[[ | |
this class creates a persistently drawing object. The first instance is always the "master", which is used for drawing and such. | |
]]-- | |
Persist = class() | |
--draw types ive added so far | |
SPRITE = 1 | |
RECT = 2 | |
ELLIPSE = 3 | |
MESH = 4 | |
--init function for the persistent drawing | |
--variables in init (if the master): | |
--variables in init (if not the master): | |
--drawtype: RECT or "rec", SPRITE or "spr", ELLIPSE or "ell", MESH or "mesh" | |
--width: width of the draw; height: height of draw, takes the value of width if nil | |
--x: x location, set to WIDTH/2 if nil; y: y location, set to HEIGHT/2 if nil | |
--spritenamemeshverts: spritename(defaults to planet cute boy), or, if a mesh, the vertices for the mesh | |
--fillcol: fill color;strokecol: stroke color; strokewid: stroke width | |
--correctAng: corrects the default rotation so that things' fronts can be changed | |
--id: set an ID for the specific instance, allows it to be drawn by the "draw by Id" function | |
--invisible: if true, makes the object invisible to start | |
function Persist:init(drawtype,width,height,x,y,spritenamemeshverts,fillcol,strokecol,strokewid,correctAng,id,invisible) | |
if not q then | |
q={} | |
self.master = true | |
self.bgcol = drawtype | |
self.smoothing = width | |
zorq = 1 | |
masterPersist = self | |
else | |
self.ident = zorq | |
zorq = zorq + 1 | |
self.s = string.find(tostring(drawtype),"spr") or drawtype == SPRITE | |
self.e = string.match(tostring(drawtype),"ell") or drawtype == ELLIPSE | |
self.r = string.match(tostring(drawtype),"rec") or drawtype == RECT | |
self.m = string.match(tostring(drawtype),"mesh") or drawtype == MESH | |
if self.s then | |
self.spritename = (spritenamemeshverts) or ("Planet Cute:Character Boy") | |
end | |
if self.m then | |
self.mesh = mesh() | |
self.verts = spritenamemeshverts or nil | |
self.mesh.vertices = self.verts | |
else | |
self.wid = width or 30 | |
self.hei = height or width or 30 | |
self.diag = math.sqrt(((self.wid/2)^2)+((self.hei/2)^2)) | |
self.strokewid = strokewid or 0 | |
self.strokecol = strokecol or color(0,0,0) | |
self.x =x or WIDTH/2 | |
self.y =y or HEIGHT/2 | |
self.loc = vec2(self.x,self.y) | |
self.angCorr = correctAng or 0 | |
end | |
self.fillcol = fillcol or color(0,0,0) | |
if self.m then | |
self.mesh.setColors(fillcol) | |
end | |
table.insert(q,self) | |
self.invis = invisible or false | |
self.id = id or 0 | |
self.ang = math.rad(90) | |
self.oid = nil | |
self.t = nil | |
end | |
end | |
--draws the object, quite simply | |
function Persist:draw() | |
if not self.invis then | |
pushMatrix() | |
if not self.m then | |
translate(self.x,self.y) | |
rotate(math.deg(self.ang)-self.angCorr) | |
end | |
if self.s then | |
spriteMode(CENTER) | |
sprite(self.spritename,0,0,self.wid,self.hei) | |
elseif self.e then | |
ellipseMode(CENTER) | |
fill(self.fillcol) | |
strokeWidth(self.strokewid) | |
stroke(self.strokecol) | |
ellipse(0,0,self.wid,self.hei) | |
elseif self.r then | |
rectMode(CENTER) | |
fill(self.fillcol) | |
strokeWidth(self.strokewid) | |
stroke(self.strokecol) | |
rect(0,0,self.wid,self.hei) | |
elseif self.m then | |
self.mesh:draw() | |
end | |
popMatrix() | |
end | |
end | |
--moves the object by the amount (xoffs,yoffs), unless you set the third variable to | |
--true, then it sets the location to (xoffs,yoffs) | |
function Persist:move(xoffs,yoffs,setloc) | |
if not self.m then | |
if setloc then | |
xoffs = xoffs or WIDTH/2 | |
yoffs = yoffs or HEIGHT/2 | |
self:setLoc(xoffs,yoffs) | |
else | |
xoffs = xoffs or 0 | |
yoffs = yoffs or 0 | |
self.x = self.x + xoffs | |
self.y = self.y + yoffs | |
self.loc = vec2(self.x,self.y) | |
end | |
end | |
end | |
--set the location to (x,y) | |
function Persist:setLoc(x,y) | |
if not self.m then | |
self.x = x | |
self.y = y | |
self.loc = vec2(self.x,self.y) | |
end | |
end | |
--move by mag amount at an angle of angleRad radians | |
--if the third parameter is true then you can instead put in degrees for angleRad, | |
--and it will be converted to radians for you | |
--the fourth parameter moves the object using the angle it is currently pointing at | |
function Persist:moveByAngle(angleRad,mag,useDeg,useSelfAng) | |
if not self.m then | |
if useSelfAng then | |
angleRad = self.ang | |
end | |
if useDeg and not useSelfAng then | |
angleRad = math.rad(angleRad) | |
end | |
self.x = self.x + (mag*math.cos(angleRad)) | |
self.y = self.y + (mag*math.sin(angleRad)) | |
self.loc = vec2(self.x,self.y) | |
end | |
end | |
--resizes the current object to the size w for width and h for height | |
--if the third parameter is set to true, then it instead adds w and h to the | |
--width and height, respectively. w and h each default to 50 if nil | |
function Persist:resize(w,h,Additive) | |
w = w or 50 | |
h = h or 50 | |
if Additive then | |
self.wid = self.wid + w | |
self.hei = self.hei + h | |
self.diag = math.sqrt(((self.wid/2)^2)+((self.hei/2)^2)) | |
else | |
self.wid = w | |
self.hei = h | |
self.diag = math.sqrt(((self.wid/2)^2)+((self.hei/2)^2)) | |
end | |
end | |
--rotates the object to ang radians, if the second parameter is used it instead | |
--adds ang radians to the current angle. if the third parameter is set to true, | |
--you may instead use degrees for ang. | |
function Persist:rotate(ang, increment,degs) | |
if degs then ang = math.rad(ang) end | |
if increment then | |
self.ang = self.ang + ang | |
else | |
self.ang = ang | |
end | |
if self.ang > 2*math.pi then | |
self.ang = self.ang - 2*math.pi | |
end | |
if self.ang < 0 then | |
self.ang = self.ang + 2*math.pi | |
end | |
end | |
--can only be called from the master instance of Persist, toggles smoothing | |
function Persist:togglesmooth() | |
if self.master then | |
self.smoothing = not self.smoothing | |
end | |
end | |
--toggles the visibility of the object. Without the first parameter it simply switches visibility, with the first parameter (invis) it sets the visibility to invis | |
function Persist:togglevis(invis) | |
if not invis then | |
self.invis = not self.invis | |
else | |
self.invis = invis | |
end | |
end | |
--if sent a touch and self.oid is nil then the object will save the touch id as | |
--self.oid and return true, otherwise if sent a touch and self.oid isnt nil and the | |
-- touch id is the same as self.oid and the touch has ended, then self.oid will be | |
--set to nil and the function will return false. if the second parameter is true | |
--then it will only save the touch's id if the touch is on the object (isPointTouching()). | |
--the second and third parameters are only used to be the parameters for the isPointTouching() function (which, as stated earlier, is only called if the second parameter is true). see the isPointTouching() function for more information about these parameters | |
--if this is called with no parameters, then it will return true if self.oid is not nil and false if it is nil | |
function Persist:oidCyc(t,iftouchon,circ,radoverride) | |
if t and t.x and t.y and t.id and t.state then | |
if t.state == BEGAN and self.oid == nil then | |
if iftouchon then | |
if self:isPointTouching(vec2(t.x,t.y),circ,radoverride) then | |
self.oid = t.id | |
self.t = t | |
return true | |
end | |
else | |
self.oid = t.id | |
self.t = t | |
return true | |
end | |
elseif t.state == ENDED and self.oid and self.oid == t.id then | |
self.oid = nil | |
self.t = nil | |
return false | |
elseif t.state == MOVING and self.oid and self.oid == t.id then | |
self.t = t | |
end | |
else | |
if self.oid then return true end | |
if not self.oid then return false end | |
end | |
end | |
--if t is specified, returns true if t.id and self.oid are the same, returns false | |
--if they are different | |
--if t is not specified, it simply returns self.oid | |
function Persist:checkoid(t) | |
if t and t.id then | |
if t.id == self.oid then | |
return true | |
else | |
return false | |
end | |
else | |
return self.oid | |
end | |
end | |
function Persist:checkoidandcall(callbacks) | |
if self.oid then | |
if string.find(type(callbacks),"tab") then | |
for i=1,#callbacks do | |
if string.find(type(callbacks[i]), "string") then | |
loadstring(callbacks[i])() | |
end | |
end | |
elseif string.find(type(callbacks),"string") then | |
loadstring(callbacks)() | |
else | |
print("No string functions entered") | |
end | |
end | |
end | |
--if t is specified, runs both the oidCyc and checkoid functions with t as their parameter (also has the other parameters for oidCyc optionally) | |
--returns true if either function returns true, otherwise returns false | |
function Persist:oidCycleandCheck(t,iftouchon,circ,radoverride) | |
if t then | |
if p:oidCyc(t,iftouchon,circ,radoverride) or p:checkoid(t) then | |
return true | |
else | |
return false | |
end | |
end | |
end | |
--check if a point, t, is touching the object. returns fakse if t is not specified | |
--if the second parameter is set to true, it checks in a circular area for the point, | |
--otherwise a rectangular area is used. the third parameter overrides the default | |
--radius (width/2) for the circle check. (as sometimes, for things like buttons, | |
--you need a larger radius) | |
function Persist:isPointTouching(t,circ,radoverride) | |
if t then | |
if circ then | |
local r = radoverride or self.wid/2 | |
if vec2(t.x,t.y):dist(self.loc)<r then | |
return true | |
else | |
return false | |
end | |
else | |
if math.abs(t.x-self.x) < self.wid/2 then | |
if math.abs(t.y-self.y) < self.hei/2 then | |
return true | |
else | |
return false | |
end | |
else | |
return false | |
end | |
end | |
else | |
print("NO POINT SPECIFIED") | |
return false | |
end | |
end | |
--checks if the object can be seen. the method of checking this is very primitive, | |
--but is effective and never DOESNT work. if you use the second parameter, and | |
--set it to true, then it will set the object to invisible when off screen and | |
--visible when on screen, so as to save memory by avoiding unnecessary draws | |
function Persist:isonscreen(toggleVisibility) | |
if self.x+self.diag > 0 | |
and self.y+self.diag > 0 | |
and self.x-self.diag < WIDTH | |
and self.y-self.diag< HEIGHT then | |
if toggleVisibility then | |
self:togglevis(true) | |
end | |
return true | |
else | |
if toggleVisibility then | |
self.togglevis(false) | |
end | |
return false | |
end | |
end | |
--rotates toward x and y coordinates specified by (vec2orX,y). alternately, you can | |
--leave out the second parameter and send a vec2,vec3,vec4,or userdata type (if | |
--userdata, then it must have a variable named x and a variable named y), and the | |
--object will rotate toward the x and y coordinates of the first parameter | |
function Persist:roToward(vec2orX,y) | |
if y and string.find(type(y),"number") | |
and vec2orX and string.find(type(vec2orX),"number") then | |
self.ang = math.atan2(y-self.y,vec2orX-self.x) | |
elseif vec2orX and vec2orX.x and vec2orX.y then | |
self.ang = math.atan2(vec2orX.y-self.y,vec2orX.x-self.x) | |
else | |
print("ERR: Invalid Argument") | |
end | |
end | |
--moves the object to a random location within the rectangle defined by the points: | |
--(xmin,ymin),(xmin,ymax),(xmax,ymin),(xmax,ymax) | |
--if called with no parameters, moves the object to a random location anywhere on the | |
--screen | |
function randlocRec(xmin,xmax,ymin,ymax) | |
xmin = xmin or 0 | |
xmax = xmax or WIDTH | |
ymin = ymin or 0 | |
ymax = ymax or HEIGHT | |
if ymax < ymin or xmax < xmin then | |
print("ERR: minimums cannot be higher than maximums") | |
return | |
end | |
self.x = math.random(xmin,xmax) | |
self.y = math.random(ymin,ymax) | |
self.loc = vec2(self.x,self.y) | |
end | |
--moves the object to a random location within a square defined by the points | |
--x-wid,x+wid,y-wid,y+wid where wid is the third parameter divided by two | |
--(this makes the whole square the size of wid by wid) | |
--X and Y define the center of the square | |
--if called without parameters, the square is centered on the screen and is as big as | |
--it can get without going off screen | |
function Persist:randlocSq(X,Y,wid) | |
local x=X or WIDTH/2 | |
local y=Y or HEIGHT/2 | |
if WIDTH>HEIGHT then | |
wid = wid/2 or HEIGHT/2 | |
else | |
wid = wid/2 or WIDTH/2 | |
end | |
self:randlocRect(x-wid,x+wid,y-wid,y+wid) | |
end | |
--moves the object to a random location within a circle | |
function randlocCirc(centerorX,radorY,rad,angmin,angmax,radmin) | |
centerorX = centerorX or WIDTH/2 | |
radorY = radorY or HEIGHT/2 | |
angmin = math.rad(angmin) or 0 | |
angmax = math.rad(angmax) or 2*math.pi | |
radmin = radmin or 0 | |
if angmax < angmin then | |
print("ERR: max angle cannot be less than minimum") | |
end | |
if centerorX and centerorX.x and centerorX.y and radorY then | |
if radorY < radmin then | |
print("ERR: minimum radius cannot be higher than the maximum radius") | |
end | |
local ang = math.random(angmin,angmax) | |
local mag = math.random(radmin,radorY) | |
self.x = centerorX.x + math.cos(ang)*mag | |
self.y = centerorX.y + math.sin(ang)*mag | |
elseif centerorX and radorY and rad then | |
if rad < radmin then | |
print("ERR: minimum radius cannot be higher than the maximum radius") | |
end | |
local ang = math.random(angmin,angmax) | |
local mag = math.random(radmin,rad) | |
self.x = centerorX + math.cos(ang)*mag | |
self.y = radorY + math.sin(ang)*mag | |
else | |
print("ERR: Invalid Arguments!") | |
end | |
self.loc= vec2(self.x,self.y) | |
end | |
--draws all objects | |
function Persist:drawall() | |
background(self.bgcol or 0) | |
if q then | |
if self.smoothing then | |
smooth() | |
else | |
noSmooth() | |
end | |
if q[1] then | |
for i=1,#q do | |
q[i]:draw() | |
end | |
end | |
end | |
end | |
--draws only objects specified by id (which defaults to 0 if nil (also the default id | |
--for objects)) | |
function Persist:drawbyId(id) | |
background(self.bgcol or 0) | |
if q then | |
local idcheck = id or 0 | |
if self.smoothing then | |
smooth() | |
else | |
noSmooth() | |
end | |
if q[1] then | |
for i=1,#q do | |
if q[i].id == idcheck then | |
q[i]:draw() | |
end | |
end | |
end | |
end | |
end | |
--destroys the object which calls it. if it is the master, then it destroys ALL | |
--objects. the master will also destroy its own use unless the first and only | |
--parameter is set to true | |
function Persist:destroy(savemaster) | |
if not self.master then | |
table.remove(q,self.ident) | |
zorq = zorq - 1 | |
if q[1] then | |
for i=1,#q do | |
if q[i].ident > self.ident then | |
q[i].ident = q[i].ident - 1 | |
end | |
end | |
end | |
else | |
if q then | |
while q[1] do | |
q[1] = nil | |
table.remove(q,1) | |
end | |
q = nil | |
zorq = nil | |
masterPersist = nil | |
if savemaster then | |
q={} | |
zorq=1 | |
masterPersist = self | |
end | |
end | |
end | |
end | |
--if it is the master, changes the background colour | |
function Persist:bgCol(col) | |
if self.master then | |
self.bgcol = col or self.bgcol | |
end | |
end | |
function runcallbacks(callbacks) | |
if string.find(type(callbacks),"tab") then | |
for i=1,#callbacks do | |
if string.find(type(callbacks[i]), "string") then | |
loadstring(callbacks[i])() | |
end | |
end | |
elseif string.find(type(callbacks),"string") then | |
loadstring(callbacks)() | |
else | |
print("No string functions entered") | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment