How can I save a DisplayObjects to be reused between scenes?
Example:
scene1 contains the DisplayObject drawing.
In scene:exitScene I save it to storyboard.state.scene1.drawing
Then when I get back to my scene in scene:enterScene I do:
drawing = storyboard.state.scene1.drawing
self.view:insert(drawing)
But I get an error as if drawing was invalid.
Given that you store the reference to the displayobject in a variable, I would do it like this
No tested but the idea should work.
FromScene:
local displayObj=yourDisplayObject
-- when it is time to change scene, do it like this:
local options={
local params ={
dispObj = displayObj,
},
}
storyboard.gotoscene(targetScene, options)
---
targetScene:
scene:createScene(event)
local params=event.params
local displayObj=params.dispObj
--and then do whatever you want with displayObj
...
...
end
Doing it in this ways requires you to not nullify, or remove, the display object in destroyscene of the first scene.
if you want to reuse the object in different Scene you can do this by creating an object lua file for example i will create a rect and save it as RectObject.lua
local H = display.contentHeight
local W = display.contentWidth
local myRect
myObject = {}
--the ScreenGroup parameter is the group from the scene where this object calls
function myObject:drawRect(ScreenGroup)
myRect = display.newRect(W/2 + 50, H/2, 50,50)
myRect:setFillColor(255,255,128)
ScreenGroup:insert(myRect)
end
so when i go to my scene i will just call it whenever i need it like this
require("RectObject.lua")
function scene:enterScene( event )
local group = self.view
--calling Object from RectObject.lua
myObject:drawRect(group)
end
Note: that you need to pass the group to the object in order for it to remove to the scene when you exit.
Related
I'm currently trying to get an app in Corona to move to a new scene. After much trial and error, and looking at the examples from others, I have got my second scene loading onto the screen.
However, when the second scene is loaded, there is no transition, and the previous scene stays visible too, leaving both scene1 and scene2 visible.
My main.lua file:
local composer = require("composer")
display.setStatusBar(display.HiddenStatusBar)
composer.gotoScene("scene1")
My scene1.lua file:
local composer = require("composer")
local scene = composer.newScene()
function scene:create(event)
local sceneGroup = self.view
local transitionOptions =
{
effect = "fade",
time = 2000
}
local function gotoScene2(event)
composer.gotoScene("scene2", transitionOptions)
end
local rect = display.newRect(display.contentCenterX,
display.contentCenterY, 50, 50)
rect:addEventListener("tap", gotoScene2)
end
scene:addEventListener("create", scene)
return scene
My scene2.lua file:
local composer = require("composer")
local scene = composer.newScene()
function scene:create(event)
local circ = display.newCircle(display.contentCenterX, 100, 25)
end
scene:addEventListener("create", scene)
return scene
I can't figure out what I'm doing wrong, so any help would be great, thanks.
Add
sceneGroup:insert( rect )
at end of scene:create function in scene1.lua file. It also apply to circ in scene2 scene.
From Corona documentation
Remember that you must insert scene display objects into the scene's
self.view group. If you create display objects but do not insert them
into this group, they will reside in front of the Composer stage and
they will not be regarded as part of the scene. For display objects
which should be part of the scene and "managed" by Composer — for
example, cleaned up when the scene is removed — you must insert them
into the scene's self.view group
Currently creating a game with Corona SDK is it possible to have an image and when it is clicked it displays 3 images and once one them 3 images are clicked the score increases by 1. Also Im only a beginner at coding , this is a new language to me. Thanks.
local CButton = display.newImage("+5.jpg" , 100 , 600)
CButton.alpha = 0.5
CButton.name = "CButton"
local CButtonLabel = display.newText( { text = "", x = 0, y = 0, fontSize = 28 } )
CButtonLabel:setTextColor( 0 ) ; CButtonLabel.x = 100 ; CButtonLabel.y = 45
local function touchCListener( event )
local object = event.target
print( event.target.name.." TOUCH on the '"..event.phase.."' Phase!" )
local ChordCOne = display.newImage("+5.jpg", 900,300)
local ChordCTwo = display.newImage("+5.jpg", 1000,300)
local ChordCThree = display.newImage("+5.jpg", 1100,300)
end
--add "touch" listener -- LABEL IS FOR TESTING!
CButton:addEventListener( "touch", touchCListener)
ChordCOne:addEventListener( "touch", updateScore)
CButtonLabel.text = "touch"
Yes, new DisplayObjects can be created in a listener function and listeners can be added to those objects as well.
In your code, you have not added the DisplayObjects created in your listener to any GroupObject (such as scene.view), which will give unexpected results.
Since the variables pointing to the newly created DisplayObjects (ChordCOne, etc.) are local to the function where they are instantiated, you cannot call addEventListener() on them outside the function. You should add the listener when they are created.
Also, the updateScore() listener function isn't defined anywhere. Make sure updateScore is not nil when and wherever you give it as an argument to addEventListener().
I have the following code:
function scene:create( event )
local sceneGroup = self.view
-- Initialize the scene here.
-- Example: add display objects to "sceneGroup", add touch listeners, etc.
local options1 = {
x = display.contentWidth / 2,
y = 200,
onRelease = button,
lableAlign = "center",
emboss = true,
id = "1",
label = "Button1"
}
local options2 = {
y = 300,
x = display.contentWidth / 2,
onRelease = button,
lableAlign = "center",
emboss = true,
id = "2",
label = "Button2"
}
local button1 = widget.newButton(options1)
local button2 = widget.newButton(options2)
sceneGroup:insert(button1)
sceneGroup:insert(button2)
end
When I place this code in a standalone file (not a scene) the buttons show up as supposed. However now I am turning this standalone file into a scene and for some reason the above code results in nothing in the simulator. Any ideas?
You have two choices:
move your scene the a yourScene.lua file (named as you wish) in which you call storyboard.newScene() (no argument) and in your main.lua you use storyboard.goto('yourScene')
you can create the scene in main.lua via storyboard.newScene('yourScene') and goto it from within main.lua via storyboard.goto('yourScene')
Basically your scene can be in a separate module, corona automatically names it based on module name, and main.lua goes to it, or your scene can be in same module, but then you have to give it a name yourself, and main.lua can "goto" it (within same module). You can even have multiple scenes in same module.
I recommend you have your scenes in separate modules, it just makes for better modularization. Conjecture: maybe the method 2 was the original, and method 1 was added latter when developers found their scenes were getting large and so needed to move them to separate modules.
The code posted above is within the main.lua file. Therefore, the scene is never called. The solution is to rename the file above to something like menu.lua and then call this scene from main.lua.
I have a model called door
Inside I have a BoolValue named Open
I have a model called Top that has all of the door blocks named Work Mabey Comeon and Proboblynot
And I have Block that when touched is supposed to make Top move up
Directly inside door I have this script
door = script.Parent
open = door.Open
Top = door.Top
opener = 18
speed = 100
steps = speed
startl = Top.CFrame
function MoveDoorToCFrame(cfrm,dr)
dr.Work.CFrame = cfrm
dr.Mabey.CFrame = dr.Work.CFrame * CFrame.new(0,-7.2,0)
dr.Comeon.CFrame = dr.Work.CFrame * CFrame.new(0,10.8,0)
dr.Problynot.CFrame = dr.Work.CFrame * CFrame.new(0,10.8,0)
end
function Update()
if speed/steps < 0.5 then
calc = 1-math.cos(math.rad((-90/speed)*steps*2))
else
calc = 1+math.sin(math.rad((90/speed)*((speed/2)-steps)*2))
end
MoveDoorToCFrame(startl * CFrame.new(0,(calc/2)*opener,0),Top)
end
Update()
while true do
wait()
if not open.Value and steps < speed then
steps = steps + 1
Update()
elseif open.Value and steps > 0 then
steps = steps - 1
Update()
end
end
Inside the button that is supposed to activate on touch I have
script.Parent.Touched:connect(function()
script.Parent.Parent.Open.Value = not script.Parent.Parent.Open.Value
end)
script.Parent.Parent.Open.Changed:connect(Update)
Update()
If you know how to fix this it would be gladly appreciated.
Update November 2015:
Using PrimaryPart
Since writing this post, ROBLOX has changed a lot in regards to the API. To move a model like requested, you should set the PrimaryPart property of the model to a central part inside the model. This will act as the origin for the model's movements.
You can then use model:SetPrimaryPartCFrame(cframe) to set the CFrame of the model. You can also retrieve this property by using model:GetPrimaryPartCFrame(), although I believe that is just a shortcut method for model.PrimaryPart.CFrame.
In code, it would look like this:
-- Set PrimaryPart:
MODEL.PrimaryPart = MODEL.SomeCentralPart
...
-- CFrame movement:
local movement = CFrame.new(0, 10, 0)
-- Move the model:
MODEL:SetPrimaryPartCFrame(MODEL:GetPrimaryPartCFrame() * movement)
Option A: Use Model's methods
I think you are making this much more difficult than it needs to be. Whenever you run into an issue like this, be sure to check the current APIs provided. The ROBLOX Model object contains a nifty method called 'TranslateBy' which takes a Vector3 argument to translate the model.
Using MODEL:TranslateBy(Vector3) is similar to moving a model via CFrame, since it ignores collisions.
Another alternative is MODEL:MoveTo(Vector3) which moves a whole model to the given Vector3 world position. The downside to this is that it does collide.
One way to get the same MoveTo effect but without collisions can be done with the TranslateBy method:
MODEL:TranslateBy(Vector3Position - MODEL:GetModelCFrame().p)
Option B: Write a custom function to manipulate the model's CFrame
Another alternative would be to manipulate the whole model's CFrame entirely. To do this, you can write a clever function that will move a whole model relative to an 'origin' point. This is similar to moving shapes on a grid given their points and an origin, except in three dimensions. Using ROBLOX's built-in functions, this is much easier though.
A good way to do this would be to write a function that lets you actually assign a CFrame value to a whole model. Another way would be to allow a translation via CFrame too.
Here's an example:
function ModelCFrameAPI(model)
local parts = {} -- Hold all BasePart objects
local cf = {} -- API for CFrame manipulation
do
-- Recurse to get all parts:
local function Scan(parent)
for k,v in pairs(parent:GetChildren()) do
if (v:IsA("BasePart")) then
table.insert(parts, v)
end
Scan(v)
end
end
Scan(model)
end
-- Set the model's CFrame
-- NOTE: 'GetModelCFrame()' will return the model's CFrame
-- based on the given PrimaryPart. If no PrimaryPart is provided
-- (which by default is true), ROBLOX will try to determine
-- the center CFrame of the model and return that.
function cf:SetCFrame(cf)
local originInverse = model:GetModelCFrame():inverse()
for _,v in pairs(parts) do
v.CFrame = (cf * (originInverse * v.CFrame))
end
end
-- Translate the model's CFrame
function cf:TranslateCFrame(deltaCf)
local cf = (model:GetModelCFrame() * deltaCf)
self:SetCFrame(cf)
end
return cf
end
-- Usage:
local myModel = game.Workspace.SOME_MODEL
local myModelCF = ModelCFrameAPI(myModel)
-- Move to 10,10,10 and rotate Y-axis by 180 degrees:
myModelCF:SetCFrame(CFrame.new(10, 10, 10) * CFrame.Angles(0, math.pi, 0))
-- Translate by 30,0,-10 and rotate Y-axis by 90 degrees
myModelCF:TranslateCFrame(CFrame.new(30, 0, -10) * CFrame.Angles(0, math.pi/2, 0))
This might be hard.
You might want to look to free models for this one unless the people above get it to work.
I, however, do have a script to move a model:
game.Workspace.Model:MoveTo(Vector3.new(0,0,0))
Your code indeed needs fixing.
You should NOT use a never-ending loop to make your stuff work (unless that is the only way).
You should rather base actions on events.
Consider to use this:
Structure:
Door [Model]
DoorScript [Script]
Button [Part]
DoorOpen [BoolValue]
Top [Model]
Mabey [Part]
Comeon [Part]
Problynot [Part]
DoorScript:
local Model = script.Parent
local Door = Model.Top
local Button = Model.Button
local DoorOpen = Model.DoorOpen
local Offset = 0
local ToOffset = 100
local Direction = 1
local StepLength = 0.1
local Moving = false
function StartMoving()
if Moving then return end
Moving = true
while (DoorOpen.Value and Offset ~= ToOffset) or (not DoorOpen.Value and Offset ~= 0) do
local Change = Offset
Offset = math.max(0,math.min(ToOffset,Offset + StepLength * (DoorOpen.Value and 1 or -1)))
Change = Offset - Change
Top:TranslateBy(Vector3.new(0,Change,0))
wait()
end
Moving = false
end
StartMoving()
DoorOpen.Changed:connect(StartMoving)
local Debounce = false
Button.Touched:connect(function()
if Debounce then return end
Debounce = true
DoorOpen.Value = not DoorOpen.Value
wait(4)
Debounce = false
end)
You might want to adjust the speed tho.
This can be used to move models, try adding something like this into your code. It's more dynamic.
a = Workspace.Model
for i=0.1,40 do
for i,v in pairs(a:getChildren()) do
if v:IsA("Part") then
v.CFrame = CFrame.new(v.CFrame + Vector3.new(0,0.1,0))
else print("Not a part")
end
end
end
I'm currently making a tower defense game with Corona SDK. However, while I'm making the gaming scene, The background scene always cover the monster spawn, I've tried background:toBack() ,however it's doesn't work.Here is my code:
module(..., package.seeall)
function new()
local localGroup = display.newGroup();
local level=require(data.levelSelected);
local currentDes = 1;
monsters_list = display.newGroup()
--The background
local bg = display.newImage ("image/levels/1/bg.png");
bg.x = _W/2;bg.y = _H/2;
bg:toBack();
--generate the monsters
function spawn_monster(kind)
local monster=require("monsters."..kind);
newMonster=monster.new()
--read the spawn(starting point) in level, and spawn the monster there
newMonster.x=level.route[1][1];newMonster.y=level.route[1][2];
monsters_list:insert(newMonster);
localGroup:insert(monsters_list);
return monsters_list;
end
function move(monster,x,y)
-- Using pythagoras to calauate the moving distace, Hence calauate the time consumed according to speed
transition.to(monster,{time=math.sqrt(math.abs(monster.x-x)^2+math.abs(monster.y-y)^2)/(monster.speed/30),x=x, y=y, onComplete=newDes})
end
function newDes()
currentDes=currentDes+1;
end
--moake monster move according to the route
function move_monster()
for i=1,monsters_list.numChildren do
move(monsters_list[i],200,200);
print (currentDes);
end
end
function agent()
spawn_monster("basic");
end
--Excute function above.
timer2 = timer.performWithDelay(1000,agent,10);
timer.performWithDelay(100,move_monster,-1);
timer.performWithDelay(10,update,-1);
move_monster();
return localGroup;
end
and the monster just stuck at the spawn point and stay there.
but, When i comment these 3 lines of code:
--local bg = display.newImage ("image/levels/1/bg.png");
--bg.x = _W/2;bg.y = _H/2;
--bg:toBack();
The problem disappear
Any ideas??Thanks for helping
Since you are using director, you should insert all your display objects into the localGroup.
You haven't inserted bg into localGroup.
SO director class inserts bg finally after inserting localGroup.
Modify your code as
--The background
local bg = display.newImage (localGroup,"image/levels/1/bg.png");
bg.x = _W/2;bg.y = _H/2;
bg:toBack();
or add the code
localGroup:insert(bg)
In more recent versions of Corona SDK:
Composer is the official scene (screen) creation and management library in Corona SDK.... The primary object in the Composer library is the scene object...and it contains a unique self.view.... This self.view is where you should insert visual elements pertaining to the scene.
So now in your scene:create() method, you should insert all DisplayObjects into self.view. It looks like this:
local composer = require( "composer" )
local scene = composer.newScene()
function scene:create()
local sceneGroup = self.view
local bg = display.newImage( ...
bg.x, bg.y = ...
local dude = display.newImage( ...
dude.x, dude.y = ....
sceneGroup:insert(bg)
sceneGroup:insert(dude)
end
The layering of DisplayObjects in this sceneGroup depends on the order in which they are added to the group, with the object added last on top. You can control this ordering with the toBack() and toFront() methods.