Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[ GameUtils
- A simple API for creating optimized, graphically intensive games by Nitrogen Fingers
- Version: 0.3a
- ]]--
- --The back buffer. Initialized as nil
- local backbuffer = nil
- --The bounds of the terminal the back buffer displays to
- local tw,th = nil, nil
- --[[Constructs a new buffer. This must be done before the buffer can written to.
- Params: terminal:?table = The function table to draw to a screen. By default (nil) this refers
- to the native terminal, but monitor displays can be passed through as well:
- local leftMonitor = peripherals.wrap("left")
- initializeBuffer(leftMonitor)
- Returns:boolean = True if the buffer was successfully initialized; false otherwise
- ]]--
- function initializeBuffer(terminal)
- if not terminal then terminal = term end
- if not terminal.getSize then
- error("Parameter cannot be used to initialize the backbuffer.")
- end
- if not terminal.isColour() then
- error("Parameter does not represent an advanced computer.")
- end
- tw,th = terminal.getSize()
- backbuffer = { }
- for y=1,th do
- backbuffer[y] = { }
- end
- return true
- end
- --[[Will clear the buffer and reset to nil, or to a colour if provided
- Params: colour:?number = The colour to set the back buffer to
- Returns:nil
- ]]--
- function clearBuffer(colour)
- if not backbuffer then
- error("Back buffer not yet initialized!")
- end
- for y=1,#backbuffer do
- backbuffer[y] = { }
- if colour then
- for x=1,tw do
- backbuffer[y][x] = colour
- end
- end
- end
- end
- --[[Draws the given entity to the back buffer
- Params: entity:table = the entity to draw to the buffer
- Returns:nil
- ]]--
- function writeToBuffer(entity)
- if not backbuffer then
- error("Back buffer not yet initialized!")
- end
- local image = nil
- if entity.type == "animation" then
- image = entity.frames[entity.currentFrame]
- else
- image = entity.image
- end
- for y=1,image.dimensions.height do
- for x=1,image.dimensions.width do
- if image[y][x] then
- local xpos,ypos = x,y
- if entity.mirror.x then xpos = image.dimensions.width - x + 1 end
- if entity.mirror.y then ypos = image.dimensions.height - y + 1 end
- backbuffer[entity.y + ypos - 1][entity.x + xpos - 1]
- = image[y][x]
- end
- end
- end
- end
- --[[Draws the contents of the buffer to the screen. This will not clear the screen or the buffer.
- Params: terminal:table = the terminal to draw to
- Returns:nil
- ]]--
- function drawBuffer(terminal)
- if not backbuffer then
- error("Back buffer not yet initialized!")
- end
- if not terminal then terminal = term end
- if not terminal.setCursorPos or not terminal.setBackgroundColour or not terminal.write then
- error("Parameter cannot be used to initialize the backbuffer.")
- end
- if not terminal.isColour() then
- error("Parameter does not represent an advanced computer.")
- end
- for y=1,math.min(#backbuffer, th) do
- for x=1,tw do
- if backbuffer[y][x] then
- terminal.setCursorPos(x,y)
- terminal.setBackgroundColour(backbuffer[y][x])
- terminal.write(" ")
- end
- end
- end
- end
- --[[Converts a hex digit into a colour value
- Params: hex:?string = the hex digit to be converted
- Returns:string A colour value corresponding to the hex, or nil if the character is invalid
- ]]--
- local function getColourOf(hex)
- local value = tonumber(hex, 16)
- if not value then return nil end
- value = math.pow(2,value)
- return value
- end
- --[[Converts every pixel of one colour in a given sprite to another colour
- Use for "reskinning". Uses OO function.
- Params: self:sprite = the sprite to reskin
- oldcol:number = the colour to replace
- newcol:number = the new colour
- Returns:nil
- ]]--
- local function repaintS(self, oldcol, newcol)
- for y=1,self.image.bounds.height do
- for x=1, self.image.bounds.width do
- if self.image[y][x] == oldcol then
- self.image[y][x] = newcol
- end
- end
- end
- end
- --[[Converts every pixel of one colour in a given animation to another colour
- Use for "reskinning". Uses OO function.
- Params: self:animation = the animation to reskin
- oldcol:number = the colour to replace
- newcol:number = the new colour
- Returns:nil
- ]]--
- local function repaintA(self, oldcol, newcol)
- for f=1,#self.frames do
- print(self.frames[f].bounds)
- for y=1,self.frames[f].bounds.height do
- for x=1, self.frames[f].bounds.width do
- if self.frames[f][y][x] == oldcol then
- self.frames[f][y][x] = newcol
- end
- end
- end
- end
- end
- --[[Prints the sprite on the screen
- Params: self:sprite = the sprite to draw
- Returns:nil
- ]]--
- local function drawS(self)
- local image = self.image
- for y=1,image.dimensions.height do
- for x=1,image.dimensions.width do
- if image[y][x] then
- local xpos,ypos = x,y
- if self.mirror.x then xpos = image.dimensions.width - x + 1 end
- if self.mirror.y then ypos = image.dimensions.height - y + 1 end
- term.setBackgroundColour(image[y][x])
- term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1)
- term.write(" ")
- end
- end
- end
- end
- --[[Prints the current frame of the animation on screen
- Params: self:anim = the animation to draw
- frame:?number = the specific frame to draw (default self.currentFrame)
- Returns:nil
- ]]--
- local function drawA(self, frame)
- if not frame then frame = self.currentFrame end
- local image = self.frames[frame]
- for y=1,image.dimensions.height do
- for x=1,image.dimensions.width do
- if image[y][x] then
- local xpos,ypos = x,y
- if self.mirror.x then xpos = image.dimensions.width - x + 1 end
- if self.mirror.y then ypos = image.dimensions.height - y + 1 end
- term.setBackgroundColour(image[y][x])
- term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1)
- term.write(" ")
- end
- end
- end
- end
- --[[Checks the animation timer provided to see whether or not the animation needs to be updated.
- If so, it makes the necessary change.
- Params: self:animation = the animation to be updated
- timerID:number = the ID of the most recent timer event
- Returns:bool = true if the animation was update; false otherwise
- ]]--
- local function updateA(self, timerID)
- if self.timerID and timerID and self.timerID == timerID then
- self.currentFrame = self.currentFrame + 1
- if self.currentFrame > self.upperBound then
- self.currentFrame = self.lowerBound
- end
- return true
- else
- return false
- end
- end
- --[[Moves immediately to the next frame in the sequence, as though an update had been called.
- Params: self:animation = the animation to update
- Returns:nil
- ]]--
- local function nextA(self)
- self.currentFrame = self.currentFrame + 1
- if self.currentFrame > self.upperBound then
- self.currentFrame = self.lowerBound
- end
- end
- --[[Moves immediately to the previous frame in the sequence
- Params: self:animation = the animation to update
- Returns:nil
- ]]--
- local function previousA(self)
- self.currentFrame = self.currentFrame - 1
- if self.currentFrame < self.lowerBound then
- self.currentFrame = self.upperBound
- end
- end
- --[[Performs a rectangle collision with another given entity. Entity can be of sprite or animation
- type (also true of the self). Bases collision using a least squared approach (rectangle precision).
- Params: self:sprite,animation = the object in question of the testing
- other:sprite,animation = the other object tested for collision
- Returns:bool = true if bounding rectangle intersect is true; false otherwse
- ]]--
- local function rCollidesWith(self, other)
- error("not implemented yet...")
- end
- --[[Performs a pixel collision test on another given entity. Either entity can be of sprite or animation
- type. Bases collision on a pixel occupancy approach.
- Params: self:sprite,animation = the object in question of the testing
- other:sprite,animation = the other object being tested for collision
- Returns:?number,?number: The X and Y position in which the collision occurred.
- ]]--
- local function pCollidesWith(self, other)
- error("not implemented yet..")
- end
- --[[
- Sprites Fields:
- x:number = the x position of the sprite in the world
- y:number = the y position of the sprite in the world
- image:table = a table of the image. Indexed by height, a series of sub-tables, each entry being a pixel
- at [y][x]. It also contains:
- bounds:table =
- x:number = the relative x position of the bounding rectangle
- y:number = the relative y position of the bounding rectangle
- width:number = the width of the bounding rectangle
- height:number = the height of the bounding rectangle
- dimensions:table =
- width = the width of the entire image in pixels
- height = the height of the entire image in pixels
- mirror:table =
- x:bool = whether or not the image is mirrored on the X axis
- y:bool = whether or not the image is mirrored on the Y axis
- repaint:function = see repaintS (above)
- rCollidesWith:function = see rCollidesWith (above)
- pCollidesWith:function = see pCollidesWith (above)
- draw:function = see drawS (above)
- ]]--
- --[[Loads a new sprite into a table, and returns it to the user.
- Params: path:string = the absolute path to the desired sprite
- x:number = the initial X position of the sprite
- y:number = the initial Y position of the sprite
- ]]--
- function loadSprite(path, x, y)
- local sprite = {
- type = "sprite",
- x = x,
- y = y,
- image = { },
- mirror = { x = false, y = false }
- }
- if fs.exists(path) then
- local file = io.open(path, "r" )
- local leftX, rightX = math.huge, 0
- local topY, botY = nil,nil
- local lcount = 0
- for line in file:lines() do
- lcount = lcount+1
- table.insert(sprite.image, {})
- for i=1,#line do
- if string.sub(line, i, i) ~= " " then
- leftX = math.min(leftX, i)
- rightX = math.max(rightX, i)
- if not topY then topY = lcount end
- botY = lcount
- end
- sprite.image[#sprite.image][i] = getColourOf(string.sub(line,i,i))
- end
- end
- file:close()
- sprite.image.bounds = {
- x = leftX,
- width = rightX - leftX + 1,
- y = topY,
- height = botY - topY + 1
- }
- sprite.image.dimensions = {
- width = rightX,
- height = botY
- }
- sprite.repaint = repaintS
- sprite.rCollidesWith = rCollidesWith
- sprite.pCollidesWith = pCollidesWith
- sprite.draw = drawS
- return sprite
- else
- error(path.." not found!")
- end
- end
- --Animations contain
- --Everything a sprite contains, but the image is a series of frames, not just one image
- --An timerID that tracks the last animation
- --An upper and lower bound on the active animation
- --An update method that takes a timer event and updates the animation if necessary
- --[[
- ]]--
- function loadAnimation(path, x, y, currentFrame)
- local anim = {
- type = "animation",
- x = x,
- y = y,
- frames = { },
- mirror = { x = false, y = false },
- currentFrame = currentFrame
- }
- table.insert(anim.frames, { })
- if fs.exists(path) then
- local file = io.open(path, "r")
- local leftX, rightX = math.huge, 0
- local topY, botY = nil,nil
- local lcount = 0
- for line in file:lines() do
- lcount = lcount+1
- local cFrame = #anim.frames
- if line == "~" then
- anim.frames[cFrame].bounds = {
- x = leftX,
- y = topY,
- width = rightX - leftX + 1,
- height = botY - topY + 1
- }
- anim.frames[cFrame].dimensions = {
- width = rightX,
- height = botY
- }
- table.insert(anim.frames, { })
- leftX, rightX = math.huge, 0
- topY, botY = nil,nil
- lcount = 0
- else
- table.insert(anim.frames[cFrame], {})
- for i=1,#line do
- if string.sub(line, i, i) ~= " " then
- leftX = math.min(leftX, i)
- rightX = math.max(rightX, i)
- if not topY then topY = lcount end
- botY = lcount
- end
- anim.frames[cFrame][#anim.frames[cFrame]] [i] = getColourOf(string.sub(line,i,i))
- end
- end
- end
- file:close()
- local cFrame = #anim.frames
- anim.frames[cFrame].bounds = {
- x = leftX,
- y = topY,
- width = rightX - leftX + 1,
- height = botY - topY + 1
- }
- if not currentFrame or type(currentFrame) ~= "number" or currentFrame < 1 or
- currentFrame > #anim.frames then
- anim.currentFrame = 1
- end
- anim.timerID = nil
- anim.lowerBound = 1
- anim.upperBound = #anim.frames
- anim.updating = false
- anim.repaint = repaintA
- anim.rCollidesWith = rCollidesWith
- anim.pCollidesWith = pCollidesWith
- anim.draw = drawA
- anim.update = updateA
- anim.next = nextA
- anim.previous = previousA
- return anim
- else
- error(path.." not found!")
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement