Skip to content

Instantly share code, notes, and snippets.

@GymbylCoding
Last active December 16, 2021 09:59
Show Gist options
  • Star 32 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save GymbylCoding/8675733 to your computer and use it in GitHub Desktop.
Save GymbylCoding/8675733 to your computer and use it in GitHub Desktop.
Perspective Virtual Camera System
Perspective Virtual Camera System
Licensed under the MIT license, which basically means you can do anything you want with it.
-------------------------------------------------------------------------------
-- Perspective Demo
--------------------------------------------------------------------------------
display.setStatusBar(display.HiddenStatusBar)
--------------------------------------------------------------------------------
-- Localize
--------------------------------------------------------------------------------
local require = require
local perspective = require("perspective")
local function forcesByAngle(totalForce, angle) local forces = {} local radians = -math.rad(angle) forces.x = math.cos(radians) * totalForce forces.y = math.sin(radians) * totalForce return forces end
--------------------------------------------------------------------------------
-- Build Camera
--------------------------------------------------------------------------------
local camera = perspective.createView()
--------------------------------------------------------------------------------
-- Build Player
--------------------------------------------------------------------------------
local player = display.newPolygon(0, 0, {-50,-30, -50,30, 50,0})
player.strokeWidth = 6
player:setFillColor(0, 0, 0, 0)
player.anchorX = 0.2 -- Slightly more "realistic" than center-point rotating
-- Some various movement parameters
player.angularVelocity = 0 -- Speed at which player rotates
player.angularAcceleration = 1.05 -- Angular acceleration rate
player.angularDamping = 0.9 -- Angular damping rate
player.angularMax = 10 -- Max angular velocity
player.moveSpeed = 0 -- Current movement speed
player.linearDamping = 0 -- Linear damping rate
player.linearAcceleration = 1.05 -- Linear acceleration rate
player.linearMax = 10 -- Max linear velocity
camera:add(player, 1) -- Add player to layer 1 of the camera
camera:prependLayer()
--------------------------------------------------------------------------------
-- "Scenery"
--------------------------------------------------------------------------------
local scene = {}
for i = 1, 100 do
scene[i] = display.newCircle(0, 0, 10)
scene[i].x = math.random(display.screenOriginX, display.contentWidth * 3)
scene[i].y = math.random(display.screenOriginY, display.contentHeight)
scene[i]:setFillColor(math.random(100) * 0.01, math.random(100) * 0.01, math.random(100) * 0.01)
camera:add(scene[i], math.random(0, camera:layerCount()))
end
camera:setParallax(1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3) -- Here we set parallax for each layer in descending order
--------------------------------------------------------------------------------
-- Movement Buttons
--------------------------------------------------------------------------------
local m = {}
m.result = "none"
m.rotate = {}
m.rotate.left = display.newRect(0, 0, 60, 60)
m.rotate.left.x = display.screenOriginX + m.rotate.left.contentWidth + 10
m.rotate.left.y = display.contentHeight - m.rotate.left.contentHeight - 10
m.rotate.left.result = "rotate:left"
m.rotate.right = display.newRect(0, 0, 60, 60)
m.rotate.right.x = display.contentWidth - display.screenOriginX - m.rotate.right.contentWidth - 10
m.rotate.right.y = display.contentHeight - m.rotate.right.contentHeight - 10
m.rotate.right.result = "rotate:right"
m.forward = display.newRect(0, 0, display.contentWidth * 0.75, 60)
m.forward.x = display.contentCenterX
m.forward.y = display.contentHeight - m.forward.contentHeight - 10
m.forward.result = "move"
--------------------------------------------------------------------------------
-- Touch Movement Buttons
--------------------------------------------------------------------------------
function m.touch(event)
local t = event.target
if "began" == event.phase then
display.getCurrentStage():setFocus(t)
t.isFocus = true
m.result = t.result
if t.result == "rotate:left" then
player.angularVelocity = -2
elseif t.result == "rotate:right" then
player.angularVelocity = 2
elseif t.result == "move" then
player.moveSpeed = 2
end
elseif t.isFocus then
if "moved" == event.phase then
elseif "ended" == event.phase then
display.getCurrentStage():setFocus(nil)
t.isFocus = false
m.result = "none"
end
end
end
m.rotate.left:addEventListener("touch", m.touch)
m.rotate.right:addEventListener("touch", m.touch)
m.forward:addEventListener("touch", m.touch)
--------------------------------------------------------------------------------
-- Runtime Loop
--------------------------------------------------------------------------------
local function enterFrame(event)
if m.result == "rotate:left" then
player.angularVelocity = player.angularVelocity * player.angularAcceleration
player.angularVelocity = math.max(player.angularVelocity, -player.angularMax)
player.moveSpeed = player.moveSpeed * player.linearDamping
elseif m.result == "rotate:right" then
player.angularVelocity = player.angularVelocity * player.angularAcceleration
player.angularVelocity = math.min(player.angularVelocity, player.angularMax)
player.moveSpeed = player.moveSpeed * player.linearDamping
elseif m.result == "move" then
player.moveSpeed = player.moveSpeed * player.linearAcceleration
player.moveSpeed = math.min(player.moveSpeed, player.linearMax)
player.angularVelocity = player.angularVelocity * player.angularDamping
elseif m.result == "none" then
player.angularVelocity = player.angularVelocity * player.angularDamping
player.moveSpeed = player.moveSpeed * player.linearDamping
end
local forces = forcesByAngle(player.moveSpeed, 360 - player.rotation)
player:translate(forces.x, forces.y)
player:rotate(player.angularVelocity)
end
--------------------------------------------------------------------------------
-- Add Listeners
--------------------------------------------------------------------------------
Runtime:addEventListener("enterFrame", enterFrame)
camera.damping = 10 -- A bit more fluid tracking
camera:setFocus(player) -- Set the focus to the player
camera:track() -- Begin auto-tracking
--[[
Perspective v2.1.0
A library for easily and smoothly integrating a virtual camera into your game.
Based on modified version of the Dusk camera system.
v2.1.0 allows you to prepend layers in front, starting with index 0, and fixes
offset behavior.
Perspective is licensed under the MIT license. Enjoy.
--]]
local lib_perspective = {}
--------------------------------------------------------------------------------
-- Localize
--------------------------------------------------------------------------------
local display_newGroup = display.newGroup
local display_remove = display.remove
local type = type
local table_insert = table.insert
local math_huge = math.huge
local math_nhuge = -math.huge
local clamp = function(v, l, h) return (v < l and l) or (v > h and h) or v end
--------------------------------------------------------------------------------
-- Create View
--------------------------------------------------------------------------------
lib_perspective.createView = function(layerCount)
------------------------------------------------------------------------------
-- Create view, internal object, and layers
------------------------------------------------------------------------------
local view = display_newGroup()
view.damping = 1
view.snapWhenFocused = true -- Do we instantly snap to the object when :setFocus() is called?
local isTracking
local prependedLayers = 0
local internal -- So we can access it from inside the declaration
internal = {
trackingLevel = 1,
damping = 1,
scaleBoundsToScreen = true,
xScale = 1,
yScale = 1,
xOffset = 0,
yOffset = 0,
addX = display.contentCenterX,
addY = display.contentCenterY,
bounds = {
xMin = math_nhuge,
xMax = math_huge,
yMin = math_nhuge,
yMax = math_huge
},
scaledBounds = {
xMin = math_nhuge,
xMax = math_huge,
yMin = math_nhuge,
yMax = math_huge
},
trackFocus = true,
focus = nil,
viewX = 0,
viewY = 0,
getViewXY = function() if internal.focus then return internal.focus.x, internal.focus.y else return internal.viewX, internal.viewY end end,
layer = {},
updateAddXY = function() internal.addX = display.contentCenterX / view.xScale internal.addY = display.contentCenterY / view.yScale end
}
local layers = {}
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Internal Methods
------------------------------------------------------------------------------
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Scale Bounds
------------------------------------------------------------------------------
internal.scaleBounds = function(doX, doY)
if internal.scaleBoundsToScreen then
local xMin = internal.bounds.xMin
local xMax = internal.bounds.xMax
local yMin = internal.bounds.yMin
local yMax = internal.bounds.yMax
local doX = doX and not ((xMin == math_nhuge) or (xMax == math_huge))
local doY = doY and not ((yMin == math_nhuge) or (yMax == math_huge))
if doX then
local scaled_xMin = xMin / view.xScale
local scaled_xMax = xMax - (scaled_xMin - xMin)
if scaled_xMax < scaled_xMin then
local hopDist = scaled_xMin - scaled_xMax
local halfDist = hopDist * 0.5
scaled_xMax = scaled_xMax + halfDist
scaled_xMin = scaled_xMin - halfDist
end
internal.scaledBounds.xMin = scaled_xMin
internal.scaledBounds.xMax = scaled_xMax
end
if doY then
local scaled_yMin = yMin / view.yScale
local scaled_yMax = yMax - (scaled_yMin - yMin)
if scaled_yMax < scaled_yMin then
local hopDist = scaled_yMin - scaled_yMax
local halfDist = hopDist * 0.5
scaled_yMax = scaled_yMax + halfDist
scaled_yMin = scaled_yMin - halfDist
end
internal.scaledBounds.yMin = scaled_yMin
internal.scaledBounds.yMax = scaled_yMax
end
else
camera.scaledBounds.xMin, camera.scaledBounds.xMax, camera.scaledBounds.yMin, camera.scaledBounds.yMax = camera.bounds.xMin, camera.bounds.xMax, camera.bounds.yMin, camera.bounds.yMax
end
end
------------------------------------------------------------------------------
-- Process Viewpoint
------------------------------------------------------------------------------
internal.processViewpoint = function()
if internal.damping ~= view.damping then internal.trackingLevel = 1 / view.damping internal.damping = view.damping end
if internal.trackFocus then
local x, y = internal.getViewXY()
if view.xScale ~= internal.xScale or view.yScale ~= internal.yScale then internal.updateAddXY() end
if view.xScale ~= internal.xScale then internal.xScale = view.xScale internal.scaleBounds(true, false) end
if view.yScale ~= internal.yScale then internal.yScale = view.yScale internal.scaleBounds(false, true) end
x = clamp(x, internal.scaledBounds.xMin, internal.scaledBounds.xMax)
y = clamp(y, internal.scaledBounds.yMin, internal.scaledBounds.yMax)
internal.viewX, internal.viewY = x, y
end
end
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Public Methods
------------------------------------------------------------------------------
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Append Layer
------------------------------------------------------------------------------
view.appendLayer = function()
local layer = display_newGroup()
layer.xParallax, layer.yParallax = 1, 1
view:insert(layer)
layer:toBack()
table_insert(layers, layer)
layer._perspectiveIndex = #layers
internal.layer[#layers] = {
x = 0,
y = 0,
xOffset = 0,
yOffset = 0
}
function layer:setCameraOffset(x, y) internal.layer[layer._perspectiveIndex].xOffset, internal.layer[layer._perspectiveIndex].yOffset = x, y end
end
view.prependLayer = function()
view.appendLayer()
layers[#layers]:toFront()
layers[-prependedLayers] = layers[#layers]
internal.layer[-prependedLayers] = internal.layer[#internal.layer]
table.remove(layers, #layers)
table.remove(internal.layer, #internal.layer)
layers[-prependedLayers]._perspectiveIndex = -prependedLayers
prependedLayers = prependedLayers + 1
end
------------------------------------------------------------------------------
-- Add an Object to the Camera
------------------------------------------------------------------------------
function view:add(obj, l, isFocus)
local l = l or 4
layers[l]:insert(obj)
obj._perspectiveLayer = l
if isFocus then view:setFocus(obj) end
-- Move an object to a layer
function obj:toLayer(newLayer) if layer[newLayer] then layer[newLayer]:insert(obj) obj._perspectiveLayer = newLayer end end
--Move an object back a layer
function obj:back() if layer[obj._perspectiveLayer + 1] then layer[obj._perspectiveLayer + 1]:insert(obj) obj._perspectiveLayer = obj.layer + 1 end end
--Moves an object forwards a layer
function obj:forward() if layer[obj._perspectiveLayer - 1] then layer[obj._perspectiveLayer - 1]:insert(obj) obj._perspectiveLayer = obj.layer - 1 end end
--Moves an object to the very front of the camera
function obj:toCameraFront() layer[1]:insert(obj) obj._perspectiveLayer = 1 obj:toFront() end
--Moves an object to the very back of the camera
function obj:toCameraBack() layer[#layers]:insert(obj) obj._perspectiveLayer = #layers obj:toBack() end
end
------------------------------------------------------------------------------
-- Main Tracking Function
------------------------------------------------------------------------------
function view:trackFocus()
internal.processViewpoint()
local viewX, viewY = internal.viewX, internal.viewY
layers[1].xParallax, layers[1].yParallax = 1, 1
for i = -prependedLayers + 1, #layers do
local addX, addY = internal.addX, internal.addY
local layerX, layerY = internal.layer[i].x, internal.layer[i].y
local diffX = (-viewX - layerX)
local diffY = (-viewY - layerY)
local incrX = diffX
local incrY = diffY
internal.layer[i].x = layerX + incrX + internal.layer[i].xOffset + internal.xOffset
internal.layer[i].y = layerY + incrY + internal.layer[i].yOffset + internal.yOffset
layers[i].x = (layers[i].x - (layers[i].x - (internal.layer[i].x + addX) * layers[i].xParallax) * internal.trackingLevel)
layers[i].y = (layers[i].y - (layers[i].y - (internal.layer[i].y + addY) * layers[i].yParallax) * internal.trackingLevel)
end
view.scrollX, view.scrollY = layers[1].x, layers[1].y
end
------------------------------------------------------------------------------
-- Set the Camera Bounds
------------------------------------------------------------------------------
function view:setBounds(x1, x2, y1, y2)
local xMin, xMax, yMin, yMax
if x1 ~= nil then if not x1 then xMin = math_nhuge else xMin = x1 end end
if x2 ~= nil then if not x2 then xMax = math_huge else xMax = x2 end end
if y1 ~= nil then if not y1 then yMin = math_nhuge else yMin = y1 end end
if y2 ~= nil then if not y2 then yMax = math_huge else yMax = y2 end end
internal.bounds.xMin = xMin
internal.bounds.xMax = xMax
internal.bounds.yMin = yMin
internal.bounds.yMax = yMax
internal.scaleBounds(true, true)
end
------------------------------------------------------------------------------
-- Miscellaneous Functions
------------------------------------------------------------------------------
-- Begin auto-tracking
function view:track() if not isTracking then Runtime:addEventListener("enterFrame", view.trackFocus) isTracking = true end end
-- Stop auto-tracking
function view:cancel() if isTracking then Runtime:removeEventListener("enterFrame", view.trackFocus) isTracking = false end end
-- Remove an object from the view
function view:remove(obj) if obj and obj._perspectiveLayer then layers[obj._perspectiveLayer]:remove(obj) end end
-- Set the view's focus
function view:setFocus(obj) if obj then internal.focus = obj end if view.snapWhenFocused then view.snap() end end
-- Snap the view to the focus point
function view:snap() local t = internal.trackingLevel local d = internal.damping internal.trackingLevel = 1 internal.damping = view.damping view:trackFocus() internal.trackingLevel = t internal.damping = d end
-- Move the view to a point
function view:toPoint(x, y) view:cancel() local newFocus = {x = x, y = y} view:setFocus(newFocus) view:track() return newFocus end
-- Get a layer of the view
function view:layer(n) return layers[n] end
-- Get the layer container of the view
function view:layers() return layers end
-- Destroy the view
function view:destroy() view:cancel() for i = 1, #layers do display_remove(layers[i]) end display_remove(view) view = nil return true end
-- Set layer parallax
function view:setParallax(...) for i = 1, #arg do if type(arg[i]) == "table" then layers[i].xParallax, layers[i].yParallax = arg[i][1], arg[i][2] else layers[i].xParallax, layers[i].yParallax = arg[i], arg[i] end end end
-- Get number of layers
function view:layerCount() return #layers end
-- Set the view's master offset
function view:setMasterOffset(x, y) internal.xOffset, internal.yOffset = x, y end
------------------------------------------------------------------------------
-- Build Layers
------------------------------------------------------------------------------
for i = layerCount or 8, 1, -1 do view.appendLayer() end
return view
end
return lib_perspective
local perspective = require("perspective") -- Include the library
local camera = perspective.createView([numLayers]) -- Optional parameter is the number of layers
camera:appendLayer() -- Add a new layer to the back of the camera
camera:prependLayer() -- Add a new layer to the front of the camera indexed with 0, -1, -2, etc.
camera:add(obj, layer, [isFocus]) -- obj is any display object; layer is the layer to add the object to (lower numbers = front of camera); isFocus is a convenience value for whether to initially set the focus to this object
camera:trackFocus() -- "Tick" the camera once
camera:setBounds(x1, x2, y1, y2) -- Set the bounding box that tracking is confined to. Any values that evaluate to Boolean negative are interpreted as infinite; infinite values apply to an entire axis (if x2 is infinite and x1 is not, X-axis constraint will be disabled)
camera:track() -- Begin auto-tracking. This eliminates the need to update the camera every frame
camera:cancel() -- Stop auto-tracking
camera:remove(obj) -- Remove an object from the camera
camera:setFocus(obj) -- Set the camera focus to an object
camera:snap() -- Snap the camera to the focus point (ignores damping)
camera:toPoint(x, y) -- Change the camera's focus to an X,Y point
camera:layer(n) -- Get a layer object of the camera
camera:layers() -- Get the array holding each layer
camera:destroy() -- Destroy the camera and clear memory
camera:setParallax(...) -- Set parallax quickly for multiple layers. Each value provided will apply to the correspondingly indexed layer. Provide a table with {x, y} values for an argument to set X and Y parallax independently
camera:layerCount() -- Get the number of layers in the camera
camera:setMasterOffset(x, y) -- Set a camera-wide offset (for layer offset, use layer:setCameraOffset())
----------------------
camera.damping = n -- "Fluidity" the camera implements with tracking. Higher values will make the camera move more slowly; values approaching 1 will make the camera move more rigidly
layer.xParallax = n -- X-parallax ratio of a layer; expressed as fraction of "normal" movement
layer.yParallax = n -- Y-parallax ratio of a layer; expressed as fraction of "normal" movement
layer:setCameraOffset(x, y) -- Set an offset for the layer's tracking
--------------------------------------------------------------------------------
-- Perspective Demo
--------------------------------------------------------------------------------
display.setStatusBar(display.HiddenStatusBar)
--------------------------------------------------------------------------------
-- Localize
--------------------------------------------------------------------------------
local require = require
local perspective = require("perspective")
local function forcesByAngle(totalForce, angle) local forces = {} local radians = -math.rad(angle) forces.x = math.cos(radians) * totalForce forces.y = math.sin(radians) * totalForce return forces end
--------------------------------------------------------------------------------
-- Build Camera
--------------------------------------------------------------------------------
local camera = perspective.createView()
--------------------------------------------------------------------------------
-- Build Player
--------------------------------------------------------------------------------
local player = display.newPolygon(0, 0, {-50,-30, -50,30, 50,0})
player.strokeWidth = 6
player:setFillColor(0, 0, 0, 0)
player.anchorX = 0.2 -- Slightly more "realistic" than center-point rotating
-- Some various movement parameters
player.angularVelocity = 0 -- Speed at which player rotates
player.angularAcceleration = 1.05 -- Angular acceleration rate
player.angularDamping = 0.9 -- Angular damping rate
player.angularMax = 10 -- Max angular velocity
player.moveSpeed = 0 -- Current movement speed
player.linearDamping = 0 -- Linear damping rate
player.linearAcceleration = 1.05 -- Linear acceleration rate
player.linearMax = 10 -- Max linear velocity
camera:add(player, 1) -- Add player to layer 1 of the camera
--------------------------------------------------------------------------------
-- "Scenery"
--------------------------------------------------------------------------------
local scene = {}
for i = 1, 100 do
scene[i] = display.newCircle(0, 0, 10)
scene[i].x = math.random(display.screenOriginX, display.contentWidth * 3)
scene[i].y = math.random(display.screenOriginY, display.contentHeight)
scene[i]:setFillColor(math.random(100) * 0.01, math.random(100) * 0.01, math.random(100) * 0.01)
camera:add(scene[i], math.random(2, camera:layerCount()))
end
camera:setParallax(1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3) -- Here we set parallax for each layer in descending order
--------------------------------------------------------------------------------
-- Movement Buttons
--------------------------------------------------------------------------------
local m = {}
m.result = "none"
m.rotate = {}
m.rotate.left = display.newRect(0, 0, 60, 60)
m.rotate.left.x = display.screenOriginX + m.rotate.left.contentWidth + 10
m.rotate.left.y = display.contentHeight - m.rotate.left.contentHeight - 10
m.rotate.left.result = "rotate:left"
m.rotate.right = display.newRect(0, 0, 60, 60)
m.rotate.right.x = display.contentWidth - display.screenOriginX - m.rotate.right.contentWidth - 10
m.rotate.right.y = display.contentHeight - m.rotate.right.contentHeight - 10
m.rotate.right.result = "rotate:right"
m.forward = display.newRect(0, 0, display.contentWidth * 0.75, 60)
m.forward.x = display.contentCenterX
m.forward.y = display.contentHeight - m.forward.contentHeight - 10
m.forward.result = "move"
--------------------------------------------------------------------------------
-- Touch Movement Buttons
--------------------------------------------------------------------------------
function m.touch(event)
local t = event.target
if "began" == event.phase then
display.getCurrentStage():setFocus(t)
t.isFocus = true
m.result = t.result
if t.result == "rotate:left" then
player.angularVelocity = -2
elseif t.result == "rotate:right" then
player.angularVelocity = 2
elseif t.result == "move" then
player.moveSpeed = 2
end
elseif t.isFocus then
if "moved" == event.phase then
elseif "ended" == event.phase then
display.getCurrentStage():setFocus(nil)
t.isFocus = false
m.result = "none"
end
end
end
m.rotate.left:addEventListener("touch", m.touch)
m.rotate.right:addEventListener("touch", m.touch)
m.forward:addEventListener("touch", m.touch)
--------------------------------------------------------------------------------
-- Runtime Loop
--------------------------------------------------------------------------------
local function enterFrame(event)
if m.result == "rotate:left" then
player.angularVelocity = player.angularVelocity * player.angularAcceleration
player.angularVelocity = math.max(player.angularVelocity, -player.angularMax)
player.moveSpeed = player.moveSpeed * player.linearDamping
elseif m.result == "rotate:right" then
player.angularVelocity = player.angularVelocity * player.angularAcceleration
player.angularVelocity = math.min(player.angularVelocity, player.angularMax)
player.moveSpeed = player.moveSpeed * player.linearDamping
elseif m.result == "move" then
player.moveSpeed = player.moveSpeed * player.linearAcceleration
player.moveSpeed = math.min(player.moveSpeed, player.linearMax)
player.angularVelocity = player.angularVelocity * player.angularDamping
elseif m.result == "none" then
player.angularVelocity = player.angularVelocity * player.angularDamping
player.moveSpeed = player.moveSpeed * player.linearDamping
end
local forces = forcesByAngle(player.moveSpeed, 360 - player.rotation)
player:translate(forces.x, forces.y)
player:rotate(player.angularVelocity)
end
--------------------------------------------------------------------------------
-- Add Listeners
--------------------------------------------------------------------------------
Runtime:addEventListener("enterFrame", enterFrame)
camera.damping = 10 -- A bit more fluid tracking
camera:setFocus(player) -- Set the focus to the player
camera:track() -- Begin auto-tracking
@espace3d
Copy link

hi Caleb,

i'm a beginner and i have a question ;
Is the position of objects change?
or is it really the camera that moves around the object?

Because at the moment I'm working on a grid and it seems that the camera causes a shift of the coordinates of my grid.
Can you tell me more?

thank you

@GymbylCoding
Copy link
Author

Hi! Sorry for not posting sooner, I don't get notifications for this :)

@kadlugan: Please open a new forum topic for your scaling issue.

@espace3d: The position of the objects does not change. When you add an object to the camera, it really just inserts it into a group. Then, Perspective just moves the camera group. You're likely getting grid coordinate shift because the group position is changing. You can get an object's "real" position (relative to the screen, not its parent group) with object:localToContent(0, 0), or you can go the other way and convert a screen coordinate to an object coordinate with object:contentToLocal(0, 0).

@takaaptech
Copy link

Hi @GymbylCoding,
I want to use parallax background with repeated scrollX or scrollY (like JungleScene in corona sdk example folder, where grass.png is looping). Can you add this feature into Perspective? By the way, your lib is awesome!

@Partysun
Copy link

How to organize layers from array of display objects, for best future?)
Like foreground, background and etc...

@reverseslayer
Copy link

How would i get the position of an object inside the parallax camera layer. I need to raycast from an object but when i do it from the objects x,y positions it returns the nonparalaxed position.

@reverseslayer
Copy link

Never mind I figured it out. If you would like the code that I added here it is.

function view:add(obj, l, isFocus)
local l = l or 4
layers[l]:insert(obj)
obj._perspectiveLayer = l

    if isFocus then view:setFocus(obj) end
    -- Move an object to a layer
    function obj:toLayer(newLayer) if layer[newLayer] then layer[newLayer]:insert(obj) obj._perspectiveLayer = newLayer end end
    --Move an object back a layer
    function obj:back() if layer[obj._perspectiveLayer + 1] then layer[obj._perspectiveLayer + 1]:insert(obj) obj._perspectiveLayer = obj.layer + 1 end end
    --Moves an object forwards a layer
    function obj:forward() if layer[obj._perspectiveLayer - 1] then layer[obj._perspectiveLayer - 1]:insert(obj) obj._perspectiveLayer = obj.layer - 1 end end
    --Moves an object to the very front of the camera
    function obj:toCameraFront() layer[1]:insert(obj) obj._perspectiveLayer = 1 obj:toFront() end
    --Moves an object to the very back of the camera
    function obj:toCameraBack() layer[#layers]:insert(obj) obj._perspectiveLayer = #layers obj:toBack() end
    --Returns objects paralaxed position
    function obj:getPosition() local X, Y = view.scrollX+obj.x, view.scrollY+obj.y local t = {x=X,y=Y} return t end -- Added by ReverseStudio
end

@bonez001
Copy link

bonez001 commented Sep 5, 2016

Can I embed "perspective.lua" in my commercial project?

@GymbylCoding
Copy link
Author

GymbylCoding commented Sep 10, 2016

Hey all, sorry for the delay in answering, but as I mentioned, I do not get notifications for stuff posted on this Gist. Please post in the Corona SDK forum under the "Gymbyl Coding" subforum if you want me to see what you're asking.

@jhow77
Copy link

jhow77 commented Sep 16, 2016

Is this system compatible with Corona physics bodies? I'm having a hard time having my physics bodies (collision boxes) anchor to their associated objects. In other words, when I move my focused character, the collision boxes don't stay with their associated display objects. I'm guessing that this is due to the fact that the library manually moves your objects, correct? Thank you!

@Hanprogramer
Copy link

Great thanks to this!!!
im going to use it in my game project

@TylerRivera
Copy link

TylerRivera commented Jul 17, 2019

Hi, what do if background overlaps player?

P.S Sorry, i very bad speak English

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment