Hey mate have you managed to do it yet?
James
Hey mate have you managed to do it yet?
James
No reason why that wouldn’t work. Another option rather than doing it in photoshop is to load your character image as a spritesheet, then create frames from small sections of the sheet, then create different sprites from the pieces.
Give this a whirl:
[lua]
local breakSprite = function (params)
local temp = display.newImage(params.image)
local pieceSize = params.pieceSize
local force = params.force
local density = params.density
local px = params.x
local py = params.y
local options = { sheetContentWidth = temp.width, sheetContentHeight = temp.height, frames = {} }
display.remove(temp)
temp = nil
local piecesX = options.sheetContentWidth/pieceSize
local piecesY = options.sheetContentHeight/pieceSize
local images = {}
for a = 0, piecesX -1, 1 do
for b = 0, piecesY -1, 1 do
options.frames[b-1+(a\*piecesY)] = {xPos = a, yPos = b, x=a*pieceSize, y = b*pieceSize, width = pieceSize, height = pieceSize}
end
end
local sprites = graphics.newImageSheet(params.image, options)
local g = display.newGroup()
for a = 1, #options.frames, 1 do
local i = display.newSprite(sprites, { name = “piece”, start = a, count = 1, time = 1})
i.x = options.frames[a].xPos * pieceSize
i.y = options.frames[a].yPos *pieceSize
i:setSequence(“piece”)
i:play()
g:insert(i)
images[a] = i
physics.addBody(i, “static”, {density = density, bounce = bounce})
local delayIt = function ()
i.bodyType = “dynamic”
i:applyForce(math.random(-force, force),math.random(-force,force),i.x, i.y)
end
timer.performWithDelay(params.delay, delayIt)
end
g.anchorX = 0.5
g.anchorY = 0.5
g.x = px
g.y = py
return g
end
[/lua]
[lua]
local sonic = breakSprite(
{pieceSize = 2, image = “sonic.png”, delay = 1000, density = 2,
bounce = 0.2, force = 2, x = 240, y = 160})
[/lua]
Hey there by creating frames from small sections of the sheet how exactly would I do this? this is my character btw:
Your code looks fantastic and I plan on using it all! haha just need to break it down in my head so I understand it properly!!
Thank You,
you’re a god,
James
You should be able to replace “sonic.png” with the filename of the sprite above.
Say your character is held in memory as playerOne and the image is “player.png”, when your character dies call:
[lua]
local dead = breakSprite(
{pieceSize = 2, image = “player.png”, delay = 10, density = 2,
bounce = 0.2, force = 2, x = playerOne.x, y = playerOne.y})
[/lua]
You’ll need to play with the pieceSize, density, bounce and force values to get the effect you want. I don’t recommend setting pieceSize less than 2 as this creates a sprite for every pixel and slows right down.
Okay brilliant Im really sorry but is there anyway you could comment the code in a bit of detail i really dont understand whats going on!
Thank You for all the help!
James
[lua]
local breakSprite = function (params) – params table is passed to the function
local temp = display.newImage(params.image) – temporarily load our sprite using newImage
– as we don’t specify a size it will use its actual size, which we can then measure
local pieceSize = params.pieceSize – get the size of each piece from params table
local force = params.force – get the maximum force to apply to each piece
local density = params.density – get the density to give each piece
local px = params.x – get the x position to place the sprite before it explodes
local py = params.y – get the y position to place the sprite before it explodes
local options = { sheetContentWidth = temp.width, sheetContentHeight = temp.height, frames = {} }
– set up a table to pass to the .newImageSheet function.
– this contains the size of the imageSheet, which we get from the height/width of the temp image
– we loaded earlier. Set up a blank frames table to hold the frames data.
display.remove(temp) – remove the temp image as we no longer need it
temp = nil – nil the reference
local piecesX = options.sheetContentWidth/pieceSize – calculate the number of pieces on the X axis
local piecesY = options.sheetContentHeight/pieceSize – calculate the number of pieces on the Y axis
– we are splitting our image into a grid of 2x2 pieces
for a = 0, piecesX -1, 1 do – loop through the columns
for b = 0, piecesY -1, 1 do – loop through the rows
options.frames[b-1+(a\*piecesY)] = { – for this frame
xPos = a – remember its X position in the grid
yPos = b, – set its Y position in the grid
x=a*pieceSize, – set the top left position to start grabbing pixels
y = b*pieceSize, – set the top left position to start grabbing pixels
width = pieceSize, – set number of pixels across to grab for this frame
height = pieceSize} – set number of pixels down to grab for this frame
end
end
local sprites = graphics.newImageSheet(params.image, options)
– create a Corona image sheet using the image and the options we have set
local g = display.newGroup() – create a display group to hold all the pieces
for a = 1, #options.frames, 1 do – loop through all the frames
local i = display.newSprite(sprites, { name = “piece”, start = a, count = 1, time = 1})
– create a new 1 frame sprite sequence for each piece, named ‘piece’
i.x = options.frames[a].xPos * pieceSize – position the piece in its correct position
i.y = options.frames[a].yPos *pieceSize – position the piece in its correct position
i:setSequence(“piece”) – set the sprite sequence (probably redundant…)
i:play() – set the sprite sequence to play (probably redundant…)
g:insert(i) – insert this piece into the display group
physics.addBody(i, “static”, {density = density, bounce = bounce})
– give the piece a physics body. make it static so the pieces don’t fall until we want
local delayIt = function ()
i.bodyType = “dynamic” – change to dynamic so gravity will now apply
i:applyForce(math.random(-force, force),math.random(-force,force),i.x, i.y)
– give each piece a random force so the sprite appears to explode
end
timer.performWithDelay(params.delay, delayIt) – wait for the delay set in the params table
end
g.anchorX = 0.5 – give the group a central anchor point
g.anchorY = 0.5 – give the group a central anchor point
g.x = px – position the group where we specified in params table
g.y = py – position the group where we specified in params table
return g – returns the exploding sprite to a local variable
– we can then access it after so we can remove it, move it, hide it etc
end
[/lua]
[lua]
local sonic = breakSprite( – create an exploding sprite called sonic
{pieceSize = 2, – the size of each piece (i.e. 2x2 pixels)
image = “sonic.png”, – the filename of the image to explode
delay = 1000, – the delay before the image explodes, set to 1 for instantaneous
density = 2, – the density of each piece
bounce = 0.2, – the bounch of each piece
force = 2, – the maximum force applied to each piece (more density or bigger pieces = more force required)
x = 240, – the X position on the screen to place the sprite before it explodes
y = 160}) – the Y position on the screen to place the sprite before it explodes
[/lua]
Okay brilliant thank you so what should i put in the image sheet?
Not sure what you mean by that. Does your skateboarder have more than one frame?
Just replace “sonic.png” with the filename of the skateboarder image. If he has more than one frame just save one of the frames to its own .png file.
Okay yeah the skater is only the image of the skater! all this is brilliant thank you so much but weirdly when he collides with an object it gives an error:
attempt to call methiod “applyForce” (a nil value)
Is there something wrong
James
Can you post all your code as I don’t know how you’ve implemented my function.
Here it is!
-- requires physics = require "physics" physics.start() storyboard = require ("storyboard") scene = storyboard.newScene() -- CREATESCENE -- ================================================================================= function scene:createScene(event) screenGroup = self.view background = display.newImage("bg\_final.png") background.anchorX = 0 background.anchorY = 0 background.x = 0 background.y = 0 screenGroup:insert(background) background2 = display.newImage("bg\_final.png") background2.anchorX = 0 background2.anchorY = 0 background2.x = 2560 background2.y = 0 screenGroup:insert(background2) ground = display.newImage("newground.png") ground.x = 500 ground.y = 540 ground.name = "floor" physics.addBody( ground, "static", {density=1.0, friction=1.0, bounce=0.0, } ) screenGroup:insert(ground) skater = display.newImage("skater.png") skater.x = 230 skater.y = 540 skater.xScale = 0.3 skater.yScale = 0.3 physics.addBody( skater, { friction=1.0, density=1.0, bounce=0.15, radius=10} ) skater:applyForce( 0, -100, skater.x, skater.y ) skater.name = "james" skater.isFixedRotation = true screenGroup:insert(skater) i = 0 dustbin = {} function spawnDustbin() i = i + 1 dustbin[i] = display.newImage("dustbin.png") dustbin[i].xScale = 0.55 dustbin[i].yScale = 0.55 dustbin[i].y = 555 dustbin[i].x = (math.random(1000,1100) \* i) dustbin[i].speed = 4 physics.addBody( dustbin[i], "static", { friction=1.0, density=1.0, bounce=0, radius=60} ) dustbin[i].enterFrame = moveDustbin Runtime:addEventListener("enterFrame", dustbin[i]) screenGroup:insert(dustbin[i]) end end nMilliseconds = 500 incrementfortime = 750 val = 11 increment = 1 nMilliseconds = nMilliseconds + incrementfortime while val \< 15 do system.getTimer( ) timer.performWithDelay(nMilliseconds) val = val + increment end function scrollCity(self,event) if self.x \< -2400 then self.x = 2560 else self.x = self.x - val end end function moveDustbin(self,event) if self.x \< -2560 then self.x = 2560 else self.x = self.x - val end end local function onScreenTouch( event ) if event.phase == "began" then skater:applyForce( 0, 600, skater.x, skater.y ) end return true end function onCollision(event) if event.object1.name ~= "floor" and event.object2.name ~= "floor" then local breakSprite = function (params) -- params table is passed to the function local temp = display.newImage(params.image) -- temporarily load our sprite using newImage -- as we don't specify a size it will use its actual size, which we can then measure local pieceSize = params.pieceSize -- get the size of each piece from params table local force = params.force -- get the maximum force to apply to each piece local density = params.density -- get the density to give each piece local px = params.x -- get the x position to place the sprite before it explodes local py = params.y -- get the y position to place the sprite before it explodes local options = { sheetContentWidth = temp.width, sheetContentHeight = temp.height, frames = {} } -- set up a table to pass to the .newImageSheet function. -- this contains the size of the imageSheet, which we get from the height/width of the temp image -- we loaded earlier. Set up a blank frames table to hold the frames data. display.remove(temp) -- remove the temp image as we no longer need it temp = nil -- nil the reference local piecesX = options.sheetContentWidth/pieceSize -- calculate the number of pieces on the X axis local piecesY = options.sheetContentHeight/pieceSize -- calculate the number of pieces on the Y axis -- we are splitting our image into a grid of 2x2 pieces for a = 0, piecesX -1, 1 do -- loop through the columns for b = 0, piecesY -1, 1 do -- loop through the rows options.frames[b-1+(a\*piecesY)] = { -- for this frame xPos = a, -- remember its X position in the grid yPos = b, -- set its Y position in the grid x=a\*pieceSize, -- set the top left position to start grabbing pixels y = b\*pieceSize, -- set the top left position to start grabbing pixels width = pieceSize, -- set number of pixels across to grab for this frame height = pieceSize} -- set number of pixels down to grab for this frame end end local sprites = graphics.newImageSheet(params.image, options) -- create a Corona image sheet using the image and the options we have set local g = display.newGroup() -- create a display group to hold all the pieces for a = 1, #options.frames, 1 do -- loop through all the frames local i = display.newSprite(sprites, { name = "piece", start = a, count = 1, time = 1}) -- create a new 1 frame sprite sequence for each piece, named 'piece' i.x = options.frames[a].xPos \* pieceSize -- position the piece in its correct position i.y = options.frames[a].yPos \*pieceSize -- position the piece in its correct position i:setSequence("piece") -- set the sprite sequence (probably redundant...) i:play() -- set the sprite sequence to play (probably redundant...) g:insert(i) -- insert this piece into the display group physics.addBody(i, "static", {density = density, bounce = bounce}) -- give the piece a physics body. make it static so the pieces don't fall until we want local delayIt = function () i.bodyType = "dynamic" -- change to dynamic so gravity will now apply i:applyForce(math.random(-force, force),math.random(-force,force),i.x, i.y) -- give each piece a random force so the sprite appears to explode end timer.performWithDelay(params.delay, delayIt) -- wait for the delay set in the params table end g.anchorX = 0.5 -- give the group a central anchor point g.anchorY = 0.5 -- give the group a central anchor point g.x = px -- position the group where we specified in params table g.y = py -- position the group where we specified in params table return g -- returns the exploding sprite to a local variable -- we can then access it after so we can remove it, move it, hide it etc end local sonic = breakSprite( -- create an exploding sprite called sonic {pieceSize = 4, -- the size of each piece (i.e. 2x2 pixels) image = "skater.png", -- the filename of the image to explode delay = 1000, -- the delay before the image explodes, set to 1 for instantaneous density = 2, -- the density of each piece bounce = 0.2, -- the bounch of each piece force = 2, -- the maximum force applied to each piece (more density or bigger pieces = more force required) x = 240, -- the X position on the screen to place the sprite before it explodes y = 160}) -- the Y position on the screen to place the sprite before it explodes timer.performWithDelay(3000, gotointro) function gotointro() storyboard.gotoScene("intro", introOptions) end end end --ENTERSCENE: --==================================================== function scene:enterScene(event) background.enterFrame = scrollCity Runtime:addEventListener("enterFrame", background) print("added scrollcity runtime listener for bg1") background2.enterFrame = scrollCity Runtime:addEventListener("enterFrame", background2) print("added scrollcity runtime listener for bg2") Runtime:addEventListener( "touch", onScreenTouch) print("added touch listener for jumping") timer.performWithDelay(1000, spawnDustbin, 14) print("sarting performWithDelay spawnDustbin function") Runtime:addEventListener( "collision", onCollision) print("adding collision listener") end --EXITSCENE: --====================================================== function scene:exitScene(event) background.enterFrame = scrollCity Runtime:removeEventListener("enterFrame", background) background2.enterFrame = scrollCity Runtime:removeEventListener("enterFrame", background2) Runtime:removeEventListener( "touch", onScreenTouch) Runtime:removeEventListener( "collision", onCollision) end --DESTROYSCENE: --====================================================== function scene:destroyScene(event) end scene:addEventListener("createScene", scene) scene:addEventListener("enterScene", scene) scene:addEventListener("exitScene", scene) scene:addEventListener("destroyScene", scene) return scene
Ok, I’ll have a look, might not be til tomorrow though - I’ll see if I can tidy it up as you have loads of global variables and objects and all user functions should really be declared before the storyboard functions.
Oh brilliant that way it will show me true formatting,
I’d just like to take a minute to truly thank you for what you’ve done, you’ve helped me learn a lot faster than i ever would have by myself.
Kindest,
James
Hey there,
Any chance you can try today?
Thank You
James
Code was a bit scrambled here it is formatted:
-- requires physics = require "physics"physics.start() storyboard = require ("storyboard")scene = storyboard.newScene() -- CREATESCENE-- =================================================================================function scene:createScene(event) screenGroup = self.view background = display.newImage("bg\_final.png")background.anchorX = 0background.anchorY = 0background.x = 0background.y = 0screenGroup:insert(background) background2 = display.newImage("bg\_final.png")background2.anchorX = 0background2.anchorY = 0background2.x = 2560background2.y = 0screenGroup:insert(background2) ground = display.newImage("newground.png")ground.x = 500ground.y = 540ground.name = "floor"physics.addBody( ground, "static", {density=1.0, friction=1.0, bounce=0.0, } )screenGroup:insert(ground) skater = display.newImage("skater.png")skater.x = 230skater.y = 540skater.xScale = 0.3skater.yScale = 0.3physics.addBody( skater, { friction=1.0, density=1.0, bounce=0.15, radius=10} )skater:applyForce( 0, -100, skater.x, skater.y )skater.name = "james"skater.isFixedRotation = truescreenGroup:insert(skater) i = 0dustbin = {}function spawnDustbin() i = i + 1 dustbin[i] = display.newImage("dustbin.png") dustbin[i].xScale = 0.55 dustbin[i].yScale = 0.55 dustbin[i].y = 555 dustbin[i].x = (math.random(1000,1100) \* i) dustbin[i].speed = 4 physics.addBody( dustbin[i], "static", { friction=1.0, density=1.0, bounce=0, radius=60} ) dustbin[i].enterFrame = moveDustbin Runtime:addEventListener("enterFrame", dustbin[i]) screenGroup:insert(dustbin[i])end end nMilliseconds = 500incrementfortime = 750val = 11increment = 1nMilliseconds = nMilliseconds + incrementfortime while val \< 15 do system.getTimer( ) timer.performWithDelay(nMilliseconds) val = val + incrementend function scrollCity(self,event)if self.x \< -2400 thenself.x = 2560else self.x = self.x - val end end function moveDustbin(self,event)if self.x \< -2560 thenself.x = 2560else self.x = self.x - val end end local function onScreenTouch( event )if event.phase == "began" then skater:applyForce( 0, 600, skater.x, skater.y ) endreturn trueend function onCollision(event) if event.object1.name ~= "floor" and event.object2.name ~= "floor" then local breakSprite = function (params) -- params table is passed to the function local temp = display.newImage(params.image) -- temporarily load our sprite using newImage -- as we don't specify a size it will use its actual size, which we can then measure local pieceSize = params.pieceSize -- get the size of each piece from params table local force = params.force -- get the maximum force to apply to each piece local density = params.density -- get the density to give each piece local px = params.x -- get the x position to place the sprite before it explodes local py = params.y -- get the y position to place the sprite before it explodes local options = { sheetContentWidth = temp.width, sheetContentHeight = temp.height, frames = {} } -- set up a table to pass to the .newImageSheet function. -- this contains the size of the imageSheet, which we get from the height/width of the temp image -- we loaded earlier. Set up a blank frames table to hold the frames data. display.remove(temp) -- remove the temp image as we no longer need it temp = nil -- nil the reference local piecesX = options.sheetContentWidth/pieceSize -- calculate the number of pieces on the X axis local piecesY = options.sheetContentHeight/pieceSize -- calculate the number of pieces on the Y axis -- we are splitting our image into a grid of 2x2 pieces for a = 0, piecesX -1, 1 do -- loop through the columns for b = 0, piecesY -1, 1 do -- loop through the rows options.frames[b-1+(a\*piecesY)] = { -- for this frame xPos = a, -- remember its X position in the grid yPos = b, -- set its Y position in the grid x=a\*pieceSize, -- set the top left position to start grabbing pixels y = b\*pieceSize, -- set the top left position to start grabbing pixels width = pieceSize, -- set number of pixels across to grab for this frame height = pieceSize} -- set number of pixels down to grab for this frame end end local sprites = graphics.newImageSheet(params.image, options) -- create a Corona image sheet using the image and the options we have set local g = display.newGroup() -- create a display group to hold all the pieces for a = 1, #options.frames, 1 do -- loop through all the frames local i = display.newSprite(sprites, { name = "piece", start = a, count = 1, time = 1}) -- create a new 1 frame sprite sequence for each piece, named 'piece' i.x = options.frames[a].xPos \* pieceSize -- position the piece in its correct position i.y = options.frames[a].yPos \*pieceSize -- position the piece in its correct position i:setSequence("piece") -- set the sprite sequence (probably redundant...) i:play() -- set the sprite sequence to play (probably redundant...) g:insert(i) -- insert this piece into the display group physics.addBody(i, "static", {density = density, bounce = bounce}) -- give the piece a physics body. make it static so the pieces don't fall until we want local delayIt = function () i.bodyType = "dynamic" -- change to dynamic so gravity will now apply i:applyForce(math.random(-force, force),math.random(-force,force),i.x, i.y) -- give each piece a random force so the sprite appears to explode end timer.performWithDelay(params.delay, delayIt) -- wait for the delay set in the params table end g.anchorX = 0.5 -- give the group a central anchor point g.anchorY = 0.5 -- give the group a central anchor point g.x = px -- position the group where we specified in params table g.y = py -- position the group where we specified in params table return g -- returns the exploding sprite to a local variable -- we can then access it after so we can remove it, move it, hide it etcend local sonic = breakSprite( -- create an exploding sprite called sonic {pieceSize = 4, -- the size of each piece (i.e. 2x2 pixels) image = "skater.png", -- the filename of the image to explode delay = 1000, -- the delay before the image explodes, set to 1 for instantaneous density = 2, -- the density of each piece bounce = 0.2, -- the bounch of each piece force = 2, -- the maximum force applied to each piece (more density or bigger pieces = more force required) x = 240, -- the X position on the screen to place the sprite before it explodes y = 160}) -- the Y position on the screen to place the sprite before it explodes timer.performWithDelay(3000, gotointro) function gotointro() storyboard.gotoScene("intro", introOptions)end end end --ENTERSCENE:--====================================================function scene:enterScene(event) background.enterFrame = scrollCityRuntime:addEventListener("enterFrame", background)print("added scrollcity runtime listener for bg1") background2.enterFrame = scrollCityRuntime:addEventListener("enterFrame", background2)print("added scrollcity runtime listener for bg2") Runtime:addEventListener( "touch", onScreenTouch)print("added touch listener for jumping") timer.performWithDelay(1000, spawnDustbin, 14)print("sarting performWithDelay spawnDustbin function") Runtime:addEventListener( "collision", onCollision)print("adding collision listener") end --EXITSCENE:--======================================================function scene:exitScene(event) background.enterFrame = scrollCityRuntime:removeEventListener("enterFrame", background) background2.enterFrame = scrollCityRuntime:removeEventListener("enterFrame", background2) Runtime:removeEventListener( "touch", onScreenTouch) Runtime:removeEventListener( "collision", onCollision) end --DESTROYSCENE:--======================================================function scene:destroyScene(event)end scene:addEventListener("createScene", scene)scene:addEventListener("enterScene", scene)scene:addEventListener("exitScene", scene)scene:addEventListener("destroyScene", scene) return scene
Taking a look at this now. Could you e-mail me your images so I can test the code? Don’t worry I won’t steal them
I also need them to see what size they are, so I can convert to display.newImageRect which is preferable as then the images will scale correctly on different devices.
What resolution have you got set in config.lua?
Sent the email!
Resolution is 1280 x 720
THANKYOU SO MUCH!
my hero
James
I am away for the weekend as my gf is doing a skydive, hopefully will get some time to finish this at the hotel later.
Thank you mate,
you are genuinely one of the nicest people I’ve ever found on the internet