Animating a line in each frame

Does anyone know how to animate a polygon so a little is added during each frame of animation?

I’m trying to animate a line like this:

FRAME 1: -
FRAME 2: –
FRAME 3: —
FRAME 4: ----
FRAME 5: -----

And so on. it’s supposed to look like a [slow] laser beam.

Appending new (x,y)'s in each frame doesn’t work.
Deleting and creating lines in each frame doesn’t work.

I tried creating a new line in each frame until the line got as long as I needed it, then going back and deleting all lines but the last. This “works”, but it looks terrible: some flashing, and just not smooth. I’d use sprites, but I need to make sure the width of the beam is an exact number of pixels, and never changes.

Any ideas??? I’m stumped.
Thanks in advance.
[import]uid: 9659 topic_id: 4905 reply_id: 304905[/import]

Hi Lococo,
For ideas, here’s two

  1. You would know how long this beam has to be and the number of frames in which it has to reach this distance. So you can keep creating a new line and remove the previous line, all you would need is just two lines.

  2. If you would use a sprite then you would want to have your screen split up into tiles, where you know that the entire screen is made up of x tiles of this laser beam. So you would create a series of sprites using the x co-ordinate as ( tileWidth * beamSegmentNumber ) + StartXPos

If you share your code maybe you can get some solutions on how to better handle that.

cheers,

Jayant C Varma [import]uid: 3826 topic_id: 4905 reply_id: 15818[/import]

Hi J:

Thanks for pitching in with some ideas. I did try #1 already, and as I mentioned, it doesn’t work. I’m pretty sure there’s some kind of internal Corona issue with this, as it seems sound in theory.

When I try an append() in each frame, the line never shows up until a new line is drawn. I tried setting isVisible=true in each frame, and a bunch of other attributes, to no avail.

When I try deleting the previous line in each frame, Corona gets confused, and I get an error that the line object doesn’t have a removeSelf() function.

I also tried not deleting the old lines and just drawing new lines on top of them. This “works” but looks terrible.

I’ve considered the tile approach, your #2 idea, and the nature of my game might make that possible, but there are different colored beams that can criss-cross, and some beams can be bent, so I’m left wondering just how many tiles I’d have to create, and how I’d manage them all.

I come from an OpenGL background where you have total control over each frame. I’ve gotten used to the Corona way, and I like Corona quite a lot, but I have to say, this kind of thing drives me crazy. A simple animated line, and I can’t seem to do it.

Thanks again for throwing some ideas out there. I appreciate the effort!
[import]uid: 9659 topic_id: 4905 reply_id: 15832[/import]

I’m not a game expert but…

Instead of mucking about with creating/deleting lines, what about just using the same line and just scaling it across x axis until it reaches it’s maximum length. Origin of the line will be at the source.

Once it’s reached maximum length the line moves across the screen.

On impact the line begins to scale down with termination on the target until it disappears.

You could load a PNG image thats one pixel wide but has red white red gradients vertically and stretch that to get a snazzier looking laser beam. Since it’s 1 pixel wide your xscale will accurately reflect the number of pixels the laser currently is.
[import]uid: 11393 topic_id: 4905 reply_id: 15835[/import]

That sounds like a good idea. The only thing that prevented me from trying it earlier was that I forgot you can scale x & y independently. Doh!

I’ll try it ASAP. Thanks!
[import]uid: 9659 topic_id: 4905 reply_id: 15836[/import]

Hope it helped.

And I forgot to mention…

The line flickering that you were seeing maybe you can slow your screen draw updates down. You said it was a slow moving line. If you redraw one pixel per frame on 30fps thats 30 pixels of scale/movement per second.

Maybe you can set up a counter on your frame event so it only calculates and redraws on every n number of frame updates until you get the speed you want.

Good luck! [import]uid: 11393 topic_id: 4905 reply_id: 15837[/import]

lococo,
I had also missed the scale thingie as when dealing with images, you cannot *just* change the image so it involved creating a new object.

I cannot see what wall are you hitting and why the flicker, try this code

[code]
–[[
Sample by Jayant C Varma
OZ APPS
www.oz-apps.com

Shooting laser beams made of vector objects.

–]]

local displayGroup = display.newGroup()

local currLine = display.newLine(0,100,60,100)
currLine:setColor(0,0,0,0)
local oldLine

local xPos = 0 – Start of the Laser Beam
local xLen = 5 – Length of the laser beam
local speedOfLaser = 2 –

local startAgain = true

–Add a yPos if you want this moving in y direction too
–The function that actually animates the laser beam
local onFrame = function (event)
–print (“tick”)
–Heartbeat, I love listening to them once every so often

if startAgain == true then
–print(“Starting again”)
–print ("Display has " … displayGroup.numChildren )
–If you want to check if all is ok

–Reset the line parameters
–Start a new line from 0
xLen = 5

startAgain = false
end

xLen = xLen + speedOfLaser

–remove the last line
displayGroup:remove( currLine )

– add a new line
currLine = display.newLine(displayGroup,xPos,100,xLen,100)
currLine:setColor(xLen/2,0,0)
–I am using this xLen/2 to give it a variation of colour

if xLen >= 300 then startAgain = true end
–Since the app is running in portrait, using 300 to stop the beam

end

Runtime:addEventListener(“enterFrame”, onFrame)
[/code] [import]uid: 3826 topic_id: 4905 reply_id: 15839[/import]

You’re right, Jayant, your code works perfectly. It does exactly what I was trying to do.

Now I’m stumped. I have no idea why my code isn’t working. When I try deleting the line, I get an error.

Obviously my code is much more complicated (translation: buggy). I guess I’ll have to strip it down and build it back up piece by piece.

Thanks a million – this gives me hope that at least it’s possible! :slight_smile:
[import]uid: 9659 topic_id: 4905 reply_id: 15840[/import]

Here is a sample using xscale on an image which is 1 pixel wide and four pixels high.

From 1 to 4 vertically the pixels are red, white, white, red.

[lua]function animate()
img.xScale = img.xScale + 1
if img.xScale >= display.contentWidth * 0.5 then img.xScale = 1 end
img.rotation = img.rotation + 1
end

img = display.newImage( “laser.png” )

img:setReferencePoint( display.TopLeftReferencePoint )
img.x = display.contentWidth * 0.5
img.y = display.contentHeight * 0.5

Runtime:addEventListener( “enterFrame”, animate )[/lua]

This is the same except using rectangles and a display group:
[lua]function animate()
laser.xScale = laser.xScale + 1
if laser.xScale >= display.contentWidth * 0.5 then laser.xScale = 1 end
laser.rotation = laser.rotation + 1
end

laser = display.newGroup()

beam = display.newRect( 1,1,1,1 )
beam:setFillColor( 255,0,0 )
laser:insert( beam )
beam = display.newRect( 1,2,1,2 )
laser:insert( beam )
beam = display.newRect( 1,4,1,1 )
beam:setFillColor( 255,0,0 )
laser:insert( beam )

laser:setReferencePoint( display.TopLeftReferencePoint )
laser.x = display.contentWidth * 0.5
laser.y = display.contentHeight * 0.5

Runtime:addEventListener( “enterFrame”, animate )[/lua]

Disadvantage to this approach over jayantv’s is that if you want an angled trajectory you need to rotate the object not just adjust y coordinate. And as you can see above you need to use the object’s scale to determine the width as Corona still reports it as the original image size of 1. [import]uid: 11393 topic_id: 4905 reply_id: 15843[/import]

Ha, Bedhouin, very clever indeed. Your method definitely has the advantage of allowing for a fancier-looking laser beam. :slight_smile:
[import]uid: 9659 topic_id: 4905 reply_id: 15848[/import]

In case anyone stumbles upon this thread in search for a solution I also wanted to mention my workaround, as I had the same flickering problems/ issues with appending: Now I use a new line for every step, as that stops the flickering for the old lines, and I add a filled circle on top of where the join would be when appending (because otherwise the join will be odd-looking). Once the line is fully drawn by the user (in my case, it’s a little canvas drawing thing) I can replace the whole bundle with a proper single line using newLine/ append. [import]uid: 10284 topic_id: 4905 reply_id: 26718[/import]

Hi Philipp,
some code would always be nice to see what you are suggesting.

cheers,
[import]uid: 3826 topic_id: 4905 reply_id: 26720[/import]

Well to clarify, actually my task was a bit different than drawing polygon animations. What I wanted to do was to let the user draw something on the screen, so I start with a bit of a line which then grows to a longer set of lines. I did have the same flickering base issue though, for which the workaround described above helped.

As it’s integrated in my little sprites framework the code below isn’t copy and paste ready but maybe it gets across the idea. The following is inside the canvas sprite’s “handle” function, and the canvas sprite is set to listenToTouch = true and sets self.data.lines = {}:

[code]local framesToWaitBeforeRecordingPoint = 2
local maxPointsPerDrawing = 250

if self.action.touched then
if self.phase.name == ‘default’ then
if self.action.touchJustBegan then
self.data.lines[#self.data.lines + 1] = {}
end

if not self.phase:isInited() then
self.phase:set(‘drawPause’, framesToWaitBeforeRecordingPoint, ‘default’)
end

if self.data.pointsCount <= maxPointsPerDrawing then
local line = self.data.lines[#self.data.lines]

local isSufficientlyNewPosition = true
if #line >= 2 then
local distance = misc.getDistance( {x = self.touchedX, y = self.touchedY}, {x = line[#line - 1], y = line[#line]} )
isSufficientlyNewPosition = distance >= 10
end

if isSufficientlyNewPosition then
self.data.pointsCount = self.data.pointsCount + 2
line[#line + 1] = self.touchedX
line[#line + 1] = self.touchedY

if #line >= 4 then
local lastPoints = {line[#line - 3], line[#line - 2], line[#line - 1], line[#line - 0]}
app.spritesHandler:createLine(‘temporaryDrawingIndicator’, lastPoints, nil, self.id)
end
if #line >= 2 then
app.spritesHandler:createCircle(‘temporaryDrawingIndicator’, line[#line - 1], line[#line - 0], app.canvasStrokeWidth / 2, nil, self.id)
end

if self.data.pointsCount > maxPointsPerDrawing then self.phase:set(‘suppressFurtherPoints’) end

end
end
end
end[/code]

When the user is finished drawing using above it results in the self.data.lines array, which is a set of lines that can be drawn using display.newLine and append. [import]uid: 10284 topic_id: 4905 reply_id: 26745[/import]