Lua / Corona SDK : 循环显示对象的位置差异
Lua / Corona SDK : Positional difference of display objects in loop
因此,在使用 Corona SDK 构建手机游戏时,我时不时会遇到一些问题。其中一个我似乎没有解决:
在循环中生成显示对象时,一行中的两个对象之间似乎随机出现位置差异。
起初,我认为这是由于在实际生成和过渡开始之间执行了大量代码,但后来我设法在几行中重现了同样的问题:
local rectangleLoopTimer;
local counter = 0;
local rectangleArray = {}
local function rectangleLoop()
counter = counter + 1
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
table.insert(rectangleArray, thisRectangle)
transition.to(
thisRectangle,
{
time = 5000,
x = thisRectangle.x + 1080,
onComplete = function()
display.remove(thisRectangle)
table.remove(rectangleArray, counter)
end
}
)
end
rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)
如果执行此操作,那么就会明白我的意思,那么您认为为什么会这样?我感谢每一个答案!
你好,尼尔斯
编辑:
这也会产生同样的问题:
local rectangleLoopTimer;
local counter = 0
local rectangleArray = {}
local thisRectangle
local function rectangleLoop()
counter = counter + 1
thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle.lastTime = 0
thisRectangle.rate = 216
table.insert(rectangleArray, thisRectangle)
thisRectangle.lastTime = system.getTimer()
thisRectangle.enterFrame = function(self, event)
local curTime = system.getTimer()
local dt = curTime - self.lastTime
self.lastTime = curTime
local dx = self.rate * dt / 1000
self.x = self.x + dx
end
Runtime:addEventListener("enterFrame", thisRectangle)
end
rectangleLoopTimer = timer.performWithDelay(1000, rectangleLoop, 0)
重新编辑:
此代码也会产生相同的问题,尽管使用的是独立于帧率的动画。如以下代码所示,在提高循环速度时,问题变得越来越突出:
local loopSpeed = 306
local loopTimerSpeed = 1000
local gapTable = {}
local gapLoopTimer
local frameTime
local gap
--enterFrame for time only
local function frameTime(event)
frameTime = system.getTimer()
end
--enterFrame
local function enterFrame(self, event)
local deltaTime = frameTime - self.time
print(deltaTime/1000)
self.time = frameTime
local speed = self.rate * deltaTime / 1000
self:translate(speed, 0)
end
--loop speed function
local function setLoopSpeed(factor)
loopSpeed = loopSpeed * factor
loopTimerSpeed = loopTimerSpeed / factor
end
--set the loop speed
setLoopSpeed(3)
--loop to create gaps
local function createGap()
gap = display.newRect(1, 1, 308, 442)
gap.time = system.getTimer()
gap.anchorX = 1
gap.anchorY = 0
--animation
gap.rate = loopSpeed
gap.enterFrame = enterFrame
Runtime:addEventListener("enterFrame", gap)
--fill table for cleaning up
table.insert(gapTable, gap)
--cleaning up
for i = #gapTable, 1, -1 do
local thisGap = gapTable[i]
if thisGap.x > display.contentWidth + 500 then
display.remove(thisGap)
table.remove(gapTable, i)
Runtime:removeEventListener("enterFrame", thisGap)
end
thisGap = nil
end
end
Runtime:addEventListener("enterFrame", frameTime)
gapLoopTimer = timer.performWithDelay(
loopTimerSpeed,
createGap,
0
)
如果您不需要进一步参考 rect,请使用下面的代码
local rand = math.random
local function rectangleLoop()
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle:setFillColor(rand(), rand(), rand())
transition.to(thisRectangle, {time=5000,x=thisRectangle.x + 1080, onComplete=display.remove})
end
rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)
您需要使用table来存储矩形吗?
这是一个非常常见的转换问题,[对我来说] 是 Corona SDK 中的一个错误。
需要注意的重要一点是过渡是如何工作的。
过渡只不过是一个 table ,其中包含对对象的引用以及关于每帧应该对它们执行的操作的信息。
检索此类对象的每一帧,并使用当前时间计算应应用于对象值的差异,如转换本身所指定。
这基本上意味着,如果您要求 Corona 在 time = 100
中将对象从 x = 0
移动到 x = 100
。每一帧,Corona 都会获取该信息,获取当前时间,并计算对象的 x
值。
这里的问题是,当前拍摄的时间是计算时的当前时间,而不是帧的时间。这意味着,如果你有很多过渡,那么一帧内的第一个和最后一个过渡之间可能会有几毫秒的时间。这将导致同一帧内的不同位置。
如果 Corona 需要帧时间 [所以帧开始的时间],它会使用相同的值来计算所有内容,并且无论您要从 A 过渡到 B 多少对象,所有对象都会出现在所有帧中的相同位置。
解决此问题的最简单方法是在 enterFrame
中手动处理转换或使用为您处理的库,例如:AKTween.
希望对您有所帮助。
编辑:
根据您的附加代码和评论,我认为这应该可以按您的意愿工作。请原谅我的代码质量,我是凭记忆写的,没有在 Corona 中测试。
local rectangleLoopTimer;
local allRectangles = display.newGroup()
local lastTime = system.getTimer()
local function enterFrame()
local curTime = system.getTimer()
local dt = curTime - lastTime
lastTime = curTime
for i = allRectangles.numChildren, 1 do
local rect = allRectangles[i]
local dx = rect.rate * dt / 1000
rect.x = rect.x + dx
end
end
Runtime:addEventListener("enterFrame", enterFrame)
local function createRectangle()
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle.lastTime = 0
thisRectangle.rate = 216
allRectangles:insert(thisRectangle)
end
timer.performWithDelay(1000, createRectangle, 0)
重新编辑 post 后编辑:
您在 enterFrame
侦听器中设置了时间,但您实际上并不知道何时调用它。我不会指望在 enterFrame
阶段调用函数的顺序。
因此,在使用 Corona SDK 构建手机游戏时,我时不时会遇到一些问题。其中一个我似乎没有解决:
在循环中生成显示对象时,一行中的两个对象之间似乎随机出现位置差异。
起初,我认为这是由于在实际生成和过渡开始之间执行了大量代码,但后来我设法在几行中重现了同样的问题:
local rectangleLoopTimer;
local counter = 0;
local rectangleArray = {}
local function rectangleLoop()
counter = counter + 1
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
table.insert(rectangleArray, thisRectangle)
transition.to(
thisRectangle,
{
time = 5000,
x = thisRectangle.x + 1080,
onComplete = function()
display.remove(thisRectangle)
table.remove(rectangleArray, counter)
end
}
)
end
rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)
如果执行此操作,那么就会明白我的意思,那么您认为为什么会这样?我感谢每一个答案!
你好,尼尔斯
编辑:
这也会产生同样的问题:
local rectangleLoopTimer;
local counter = 0
local rectangleArray = {}
local thisRectangle
local function rectangleLoop()
counter = counter + 1
thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle.lastTime = 0
thisRectangle.rate = 216
table.insert(rectangleArray, thisRectangle)
thisRectangle.lastTime = system.getTimer()
thisRectangle.enterFrame = function(self, event)
local curTime = system.getTimer()
local dt = curTime - self.lastTime
self.lastTime = curTime
local dx = self.rate * dt / 1000
self.x = self.x + dx
end
Runtime:addEventListener("enterFrame", thisRectangle)
end
rectangleLoopTimer = timer.performWithDelay(1000, rectangleLoop, 0)
重新编辑:
此代码也会产生相同的问题,尽管使用的是独立于帧率的动画。如以下代码所示,在提高循环速度时,问题变得越来越突出:
local loopSpeed = 306
local loopTimerSpeed = 1000
local gapTable = {}
local gapLoopTimer
local frameTime
local gap
--enterFrame for time only
local function frameTime(event)
frameTime = system.getTimer()
end
--enterFrame
local function enterFrame(self, event)
local deltaTime = frameTime - self.time
print(deltaTime/1000)
self.time = frameTime
local speed = self.rate * deltaTime / 1000
self:translate(speed, 0)
end
--loop speed function
local function setLoopSpeed(factor)
loopSpeed = loopSpeed * factor
loopTimerSpeed = loopTimerSpeed / factor
end
--set the loop speed
setLoopSpeed(3)
--loop to create gaps
local function createGap()
gap = display.newRect(1, 1, 308, 442)
gap.time = system.getTimer()
gap.anchorX = 1
gap.anchorY = 0
--animation
gap.rate = loopSpeed
gap.enterFrame = enterFrame
Runtime:addEventListener("enterFrame", gap)
--fill table for cleaning up
table.insert(gapTable, gap)
--cleaning up
for i = #gapTable, 1, -1 do
local thisGap = gapTable[i]
if thisGap.x > display.contentWidth + 500 then
display.remove(thisGap)
table.remove(gapTable, i)
Runtime:removeEventListener("enterFrame", thisGap)
end
thisGap = nil
end
end
Runtime:addEventListener("enterFrame", frameTime)
gapLoopTimer = timer.performWithDelay(
loopTimerSpeed,
createGap,
0
)
如果您不需要进一步参考 rect,请使用下面的代码
local rand = math.random
local function rectangleLoop()
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle:setFillColor(rand(), rand(), rand())
transition.to(thisRectangle, {time=5000,x=thisRectangle.x + 1080, onComplete=display.remove})
end
rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)
您需要使用table来存储矩形吗?
这是一个非常常见的转换问题,[对我来说] 是 Corona SDK 中的一个错误。
需要注意的重要一点是过渡是如何工作的。
过渡只不过是一个 table ,其中包含对对象的引用以及关于每帧应该对它们执行的操作的信息。
检索此类对象的每一帧,并使用当前时间计算应应用于对象值的差异,如转换本身所指定。
这基本上意味着,如果您要求 Corona 在 time = 100
中将对象从 x = 0
移动到 x = 100
。每一帧,Corona 都会获取该信息,获取当前时间,并计算对象的 x
值。
这里的问题是,当前拍摄的时间是计算时的当前时间,而不是帧的时间。这意味着,如果你有很多过渡,那么一帧内的第一个和最后一个过渡之间可能会有几毫秒的时间。这将导致同一帧内的不同位置。
如果 Corona 需要帧时间 [所以帧开始的时间],它会使用相同的值来计算所有内容,并且无论您要从 A 过渡到 B 多少对象,所有对象都会出现在所有帧中的相同位置。
解决此问题的最简单方法是在 enterFrame
中手动处理转换或使用为您处理的库,例如:AKTween.
希望对您有所帮助。
编辑: 根据您的附加代码和评论,我认为这应该可以按您的意愿工作。请原谅我的代码质量,我是凭记忆写的,没有在 Corona 中测试。
local rectangleLoopTimer;
local allRectangles = display.newGroup()
local lastTime = system.getTimer()
local function enterFrame()
local curTime = system.getTimer()
local dt = curTime - lastTime
lastTime = curTime
for i = allRectangles.numChildren, 1 do
local rect = allRectangles[i]
local dx = rect.rate * dt / 1000
rect.x = rect.x + dx
end
end
Runtime:addEventListener("enterFrame", enterFrame)
local function createRectangle()
local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0
thisRectangle.lastTime = 0
thisRectangle.rate = 216
allRectangles:insert(thisRectangle)
end
timer.performWithDelay(1000, createRectangle, 0)
重新编辑 post 后编辑:
您在 enterFrame
侦听器中设置了时间,但您实际上并不知道何时调用它。我不会指望在 enterFrame
阶段调用函数的顺序。