The code sample below is from a single storyboard scene. A magnifying glass (mg), a green circle (asset1), a return button and an animated ship (ship) are all added to the scene's display group as it unfolds. During this, the ship is also removed again with display.remove(ship).
This all works fine the first time the scene is created, however, when I click the return button, make a scene change, and then return to this scene, the code fails when it attempts to add the ship to the display group: "attempt to call method 'insert' (a nil value)"
What gives?
local storyboard = require ("storyboard")
local widget = require ("widget")
local scene = storyboard.newScene()
storyboard.purgeOnSceneChange = true
function scene:createScene(event)
local group=self.view
local asset1x = 600
local asset1y = 400
-- MAGNIFYING GLASS
local mg=display.newImage( "images/mg.jpg" )
mg.x=600
mg.y=150
mg.myName = "mg"
physics.addBody(mg,"dynamic", { density = 1.0, friction = 0.3, bounce = 0.2, radius = mgRadius})
group:insert(mg)
-- ASSET PLANT
local asset1 = display.newCircle(asset1x,asset1y,30)
asset1:setFillColor(100,200,300)
physics.addBody(asset1,"static")
asset1.myName = "asset1"
asset1.isSensor = true
asset1.isVisible = false
group:insert(mg)
asset1.collision = function(self,event)
if (event.phase == "began" and event.other.myName == "mg") then
print("began")
ship=display.newSprite( shipSheet, shipSeqData )
ship:play()
ship:scale(2,2)
ship.x=asset1x
ship.y=asset1y
ship.myName = "ship"
group:insert(ship)
elseif (event.phase == "ended" and event.other.myName == "mg") then
print("ended")
display.remove(ship)
end
end
asset1:addEventListener("collision")
-- RETURN BUTTON
local function returnWelcome(event)
storyboard.gotoScene("000","fade", 600)
end
local returnButton = widget.newButton
{
left=900,
top=385,
width=300,
height=225,
defaultFile="images/bg000.jpg",
onRelease=returnWelcome,
}
group:insert(returnButton)
end
scene:addEventListener( "createScene", scene )
return scene
It turns out I accidentally added the mg display object to the display group twice and never added asset1 - this somehow caused the bug.
Related
I cannot change the scene with composer or storyboard. I am trying to change the scene when you touch a row in tableview. I am able to change the scene from the main file to the file with the tableview. The tableview touch is not working though.
Some of my code is below:
local widget = require( "widget" )
local storyboard = require( "storyboard" )
local composer = require( "composer" )
local scene = composer.newScene()
function RowTouch( event )
composer.gotoScene( "thehike" )
end
myTable = widget.newTableView
{
width = display.contentWidth,
height = display.contentHeight,
backgroundColor = { .47, .66, .53 },
topPadding = 0,
hideBackground = false,
onRowRender = onRowRender,
onRowTouch = RowTouch,
noLines = true,
}
for i=1, #hike do
myTable:insertRow{
rowHeight = 220,
isCategory = false,
lineColor = { .47, .66, .53 }
}
end
end
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if phase == "will" then
-- Called when the scene is still off screen and is about to move on screen
elseif phase == "did" then
-- Called when the scene is now on screen
--
-- INSERT code here to make the scene come alive
-- e.g. start timers, begin animation, play audio, etc.
end
end
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if event.phase == "will" then
-- Called when the scene is on screen and is about to move off screen
--
-- INSERT code here to pause the scene
-- e.g. stop timers, stop animation, unload sounds, etc.)
elseif phase == "did" then
-- Called when the scene is now off screen
end
end
function scene:destroy( event )
local sceneGroup = self.view
-- Called prior to the removal of scene's "view" (sceneGroup)
--
-- INSERT code here to cleanup the scene
-- e.g. remove display objects, remove touch listeners, save state, etc.
end
---------------------------------------------------------------------------------
-- Listener setup
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-----------------------------------------------------------------------------------------
return scene
Your code does not work for a couple of reasons. You have a dangling end in line 34 and you did not define hike. You probably need a smaller rowHeight in order to show the rows in your view:
local myTable = widget.newTableView
{
left = 0,
top = 0,
height = 330,
width = 300
}
myTable:insertRow(
{
isCategory = false,
rowHeight = 40,
rowColor = rowColor,
lineColor = {.47, .66, .53}
}
)
Also, the documentation is pretty good on this[1].
[1] http://docs.coronalabs.com/api/library/widget/newTableView.html
I am trying to make a card game.. I am creating a scene, making the background,and adding an image where when the player touches he/she will be transfered to the next scene.
singlePlayer scene:
local storyboard = require("storyboard")
local singlePlayer = storyboard.newScene()
local card1,card2,card3
function singlePlayer:createScene(event )
local group = self.view
-- body
local bg = display.newImage("bg.png")
bg.x = 100 ; bg.y = 50
group:insert(bg)
end
function singlePlayer:enterScene( event )
local group = self.view
local count = math.random(3)
local storyboard = require("storyboard")
local singlePlayer = storyboard.newScene()
local card1,card2,card3
function singlePlayer:createScene(event )
local group = self.view
-- body
local bg = display.newImage("bg.png")
bg.x = 100 ; bg.y = 50
group:insert(bg)
end
function singlePlayer:enterScene( event )
local group = self.view
local count = math.random(3)
if(count == 1) then
card1 = display.newImage("attack.png")
card1.x = 50 ; card1.y = 150
group:insert(card1)
else
card1 = display.newImage("ability.png")
card1.x = 50 ; card1.y = 150
group:insert(card1)
end
function card1:touch(event )
print("ok")
if(event.phase == "ended") then
storyboard.gotoScene("opponent_scene")
else
end
-- body
end
card1:addEventListener("touch",card1)
-- body
end
function singlePlayer:exitScene(event)
local group = self.view
card1:removeEventListener("touch",card1)
end
singlePlayer:addEventListener("createScene",singlePlayer)
singlePlayer:addEventListener("enterScene",singlePlayer)
singlePlayer:addEventListener("exitScene",singlePlayer)
return singlePlayer
Opponent scene:
local storyboard = require("storyboard")
local opponent_scene = storyboard.newScene()
function opponent_scene:createScene(event )
print("opponent_scene created")
-- body
end
function opponent_scene:enterScene(event )
print("opponent_scene enter")
local group = self.view
storyboard.removeScene("judge")
local text = display.newText("Opponent's turn",150,200)
storyboard.gotoScene("judge")
-- body
end
function opponent_scene:exitScene(event )
-- body
local group = self.view
end
opponent_scene:addEventListener("createScene",opponent_scene)
opponent_scene:addEventListener("enterScene",opponent_scene)
opponent_scene:addEventListener("exitScene",opponent_scene)
return opponent_scene
Judge scene:
local storyboard = require("storyboard")
local judge = storyboard.newScene()
function judge:createScene(event )
local group = self.view
local bg = display.newImage("destiny.png")
storyboard.removeScene("opponent_scene")
storyboard.gotoScene("singlePlayer")
-- body
end
judge:addEventListener("createScene",judge)
return judge
Will anyone explain to me what is going on with these scenes?
All i want is to make the game wait for the player's input (touching of the card)
After two clicks on the icon, storyboard is taken to opponent scene and it just shows on the screen the text "opponent's turn". What I want to do is for the text to appear briefly and then the scene to be taken to the player scene
Move your scene changing code inside a delayed function with timer.delay.. Here is what I did for my game to change screen after a brief time..
local function onSceneTouch( self, event )
if event.phase == "began" then
-- write all your other code here
-- function to change screen
function myClosure()
storyboard.gotoScene("opponent_scene")
end
-- Delay the call of closure function by 2 second (2000 milliseconds)
timer.performWithDelay( 2000, myClosure, 1 )
end
end
then call onSceneTouch function on touch of the screen
The single player enterscene code is wrong ,because you cant have two global function with the same name, the approach is not the right one . why do you call create scene inside the enter frame. suppose what you have done is correct then you should add event listeners to the function which you create in the enterscene as did earlier
singlePlayer:addEventListener("createScene",singlePlayer)
singlePlayer:addEventListener("enterScene",singlePlayer)
singlePlayer:addEventListener("exitScene",singlePlayer)
First of all please read the documentation of the storyboard and look the sample.
http://docs.coronalabs.com/api/library/storyboard/
But i request you to use composer instead of storyboard : http://docs.coronalabs.com/api/library/composer/index.html
I've been trying to create a simple game where the player controls a physics body that increases in size when it collides with other objects. From what I understand it's not possible to scale the actual physics body directly, instead I'm trying to create a new one using the parameters of the original one. However, when created a new physics body of the appropriate size has been created, I lose the ability to move it around. Any form of input would be highly appriciated, as I can't figure out what to do (I'm still very new to this).
Here's what I've got so far:
function movePlayer(event)
if "began" == event.phase then
player.isFocus = true
player.x0 = event.x - player.x
player.y0 = event.y - player.y
elseif player.isFocus == true then
if "moved" == event.phase then
player.x = event.x - player.x0
player.y = event.y - player.y0
stayOnScreen( player )
elseif "ended" == phase or "cancelled" == phase then
player.isFocus = false
end
end
return true
end
function checks()
if player.resize == true then
local player2 = createPlayer(player.x, player.y, player.xScale, player.yScale, player.rotation)
if player.isFocus == true then
player2.isFocus = player.isFocus
player2.x0 = player.x0
player2.y0 = player.y0
end
player2.resize = false
player:removeSelf()
player = player2
end
end
player:addEventListener("touch", movePlayer)
Runtime:addEventListener( "enterFrame", checks)
Thanks in advance!
Edit:
Here's the code that generates a new player and adds a physics body:
function createPlayer( x, y, xScale, yScale, rotation)
local player = display.newImageRect("images/p1.png", 71, 71)
player.x = x
player.y = y
player.xScale = xScale
player.yScale = yScale
local playerCollisionFilter = { categoryBits = 2, maskBits = 5 }
local playerBodyElement = { filter=playerCollisionFilter, radius = (player.xScale * (player.width *0.5)) }
player.objectType = "player"
physics.addBody ( player, "dynamic", playerBodyElement )
player.isBullet = true
player.isSleepingAllowed = false
player.rotation = rotation
player.resize = false
return player
end
It looks like a problem with your "touch" event handler to me. Specifically, this line:
player:addEventListener("touch", movePlayer)
is only executed once, when the main Lua file is load. That handler needs to be removed from player and added to player2 when you're making the change to player2 in the checks() function.
After you do player:removeSelf(), the physics engine will no longer have a reference to player (because the removeSelf also unregisters from physics). So you have to make player (player2) a physics body:
physics.addBody(player2, ...)
where ... represents same parameters as used when you added player the first time.
Update:
OK so you've already taken care of addBody. I can't see any obvious problem with your code, but you are using the same var name "player" in a few places so its hard to be sure. Try using event.target instead of player in handler, see if that helps. For maintainability consider naming the locals like newPlayer, a give unique name for the global like rocket or person whatever your player actually is.
I am making a game in corona and I am facing a problem. I have a circle on screen and I want it to follow the touch coordinates continuously. I am using transition.to function to do so but the thing is, whenever this function get a coordinate, it completes the transition even if the coordinates are updated during the transition.
if event.phase == "began" or event.phase == "moved" then
follow = true
touchX = event.x; touchY = event.y
elseif event.phase == "ended" then
follow = false
end
And in another function, I am doing this
if follow == true then
transition.to(circle, {time = 500, x = touchX, y = touchY, transition = easing.inOutQuad})
end
The code works fine for simple touch but I want the circle to follow the touch even when it's moving.
There are some examples which may solve your problem.
Refer:
1) Flight Path posted by carlos in corona Community.
2) Move Object through a path by renvis
Sample:
local circle = display.newCircle(10,10,20)
circle.x = 160
circle.y = 160
local olderTransition
local function moveCircle(e)
if olderTransition ~= nil then
transition.cancel( olderTransition )
end
olderTransition = transition.to(circle,{time=100,x=e.x,y=e.y})
end
Runtime:addEventListener("touch",moveCircle)
Keep Coding.......... :)
You cant add a new transition to an object, which already in a transition. Thats why you should cancel the older transition first. You can try :
local olderTransition -- This should be visible outside of your function
local function blabla()
if follow == true then
if olderTransition ~= nil then
transition.cancel( olderTransition )
end
olderTransition = transition.to(circle, {time = 500, x = touchX, y = touchY, transition = easing.inOutQuad, onComplete = function() olderTransition = nil end })
end
end
Btw If you want to drag and drop objects, transitions are bad in performance way
I'm attempting to switch scenes with the storyboard, but when I press the button, it keeps the current scene... I haven't been able to find a solution to this issue anywhere on the internet. The terminal indicates that it is getting to the method that prints out "leaving main menu", and my next scene is successfully opened, but the background and button remain from the original scene.
local storyboard = require( "storyboard" )
local widget = require "widget"
local scene = storyboard.newScene()
local function onButton(event)
--local btn = event.target
--storyboard.gotoScene("sceneTemplate")
if event.phase == "release" then
print("play pressed")
storyboard.gotoScene("sceneTemplate")
end
end
function scene:createScene( event )
local group = self.view
print("menu scene created")
end
function scene:enterScene( event )
local group = self.view
print("menu scene viewing!")
local bgImage = display.newImage("images/mainBG.png",0,0);
local playButton = widget.newButton{
default = "images/playUp.png",
over = "images/playDown.png",
onEvent = onButton
}
playButton.x = 80
playButton.y = 20
end
function scene:exitScene( event )
local group = self.view
print("leaving main menu")
storyboard.removeScene("menu")
storyboard.removeAll()
display.remove(group)
group:removeSelf()
end
I found a solution! If I add both the background image and the button to a new display group, and then remove them upon the scene exiting, it works out:
function scene:enterScene( event )
local group = self.view
print("menu scene viewing!")
local bgImage = display.newImage("images/mainBG.png",0,0);
local playButton = widget.newButton{
default = "images/playUp.png",
over = "images/playDown.png",
onEvent = onButton
}
displayGroup:insert(bgImage)
displayGroup:insert(playButton)
end
function scene:exitScene( event )
local group = self.view
print("leaving main menu")
display.remove(displayGroup)
storyboard.removeScene("menu")
end
Please refer the below link-
http://docs.coronalabs.com/api/library/storyboard/removeScene.html
This can help you.