move each individual object - lua - lua

Im quite new to Lua so please pardon my ignorance but i cannot find the solution to my problem.
Whats going on
Im currently trying to move objects from A to B and once object is at B to restart at A and again move to B in a continuous cycle.
local function moveLeft(obj)
print("moving left")
local function resetObj(obj)
transition.to (obj,{ time = 10, x = obj.x + screenWidth + obj.width, onComplete=moveLeft })
end
transition.moveBy (obj,{ time = 3000, x = -screenWidth -obj.width, onComplete=resetObj })
end
and then called using
for idx1 = 1, 8 do
enemyRed = display.newImage("Images/enemyRed.png")
-- 7. Apply physics engine to the enemys, set density, friction, bounce and radius
physics.addBody(enemyRed, "dynamic", {density=0.1, friction=0.0, bounce=0, radius=9.5});
local xPositionEnemy = math.random() + math.random(1, screenWidth)
enemyRed.x = xPositionEnemy;
enemyRed.y = yPosition;
enemyRed.name = "enemyRed"..idx
moveLeft(enemyRed);
end
This is great and all objects are moving from A to B
Problem / issue
The issue here is that the onComplete is not called until ALL objects named "enemyRed" are at point B.
Question
What i want is for each individual object named "enemyRed" to reset to original position A once its reached its destination.

I can't answer the problem/issue because it is not clear (I added a comment). Re the question, you should probably add a A position field to each object, this way you can easily return to it (stylistic note: this is Lua, not c, you don't need semicolons). So In your loop do this:
enemyRed.x = xPositionEnemy
enemyRed.startPos = xPositionEnemy
then in your resetObj do this:
local function moveLeft(obj)
local function resetObj()
print("moving back")
transition.to (obj,
{ time = 10, x = obj.startPos, onComplete=function() moveLeft(obj) end })
end
print("moving left")
transition.moveBy (obj,
{ time = 3000, x = -screenWidth - obj.width, onComplete=resetObj })
end
The above also shows that when calling your moveLeft from the resetObj function, you have to give the obj to the moveLeft otherwise obj will be nil. The resetObjdoes not needobj` parameter since it is an upvalue already.

Related

Lua - World of Warcraft API Debuff frame

I have the strange problem, that with this AddOn it shows a frame with the current debuff. I think it displays only the first one and if another one is applied it just overlaps the first one. How can i make it so it displays the new ones next to the old ones?
This is the code:
function WCCPlayer_OnLoad()
this:SetHeight(40)
this:SetWidth(40)
this:SetPoint("CENTER", 0, 0)
this:RegisterEvent("UNIT_AURA")
this:RegisterEvent("PLAYER_AURAS_CHANGED")
this.texture = this:CreateTexture(this, "BACKGROUND")
this.texture:SetAllPoints(this)
this.cooldown = CreateFrame("Model", "Cooldown", this, "CooldownFrameTemplate")
this.cooldown:SetAllPoints(this)
this.maxExpirationTime = 0
this:Hide()
end
function WCCPlayer_OnEvent()
local spellFound = false
for i=1, 16 do -- 16 is enough due to HARMFUL filter
local texture = UnitDebuff("player", i)
WCCTooltip:ClearLines()
WCCTooltip:SetUnitDebuff("player", i)
local buffName = WCCTooltipTextLeft1:GetText()
if spellIds[buffName] then
spellFound = true
for j=0, 31 do
local buffTexture = GetPlayerBuffTexture(j)
if texture == buffTexture then
local expirationTime = GetPlayerBuffTimeLeft(j)
this:Show()
this.texture:SetTexture(buffTexture)
this.cooldown:SetModelScale(1)
if this.maxExpirationTime <= expirationTime then
CooldownFrame_SetTimer(this.cooldown, GetTime(), expirationTime, 1)
this.maxExpirationTime = expirationTime
end
return
end
end
end
end
if spellFound == false then
this.maxExpirationTime = 0
this:Hide()
end
end
function WCCTarget_OnLoad()
end
function WCCTarget_OnEvent()
end
I think it is all about the frame position, and as you said, the new frame is displaying on top of the previous frame.
You need to have the new frame position next to the previous so each time you run your WCCPlayer_OnLoad() function it increase the X coordinate by the width of the frame.
First declare a local setPointX variable out side of the function, then increment the setPointX variable by the frame width, (in your case it is 40), each time the function is run;
local setPointX, setPointY = 0,0 -- x and y variables
function WCCPlayer_OnLoad()
this:SetHeight(40)
this:SetWidth(40)
this:SetPoint('CENTER', setPointX, setPointY) -- use variables to set the frame point
this:RegisterEvent('UNIT_AURA')
this:RegisterEvent('PLAYER_AURAS_CHANGED')
this.texture = this:CreateTexture(this, 'BACKGROUND')
this.texture:SetAllPoints(this)
this.cooldown = CreateFrame('Model', 'Cooldown', this, 'CooldownFrameTemplate')
this.cooldown:SetAllPoints(this)
this.maxExpirationTime = 0
this:Hide()
setPointX = setPointX + 40 -- increase the x variable by the width of the frame
end
I have no background in programming, (just trying to teach myself Java and Lua), so there undoubtedly will be better and more efficient/effective ways to solve your issue.

Lua function only works on first click

I'm new to Lua, and I'm trying to do a simple program to change the location of an object randomly when it's clicked. The problem is, this program only works once, that is to say, upon loading the program and tapping the circle, it moves, but will not move again on subsequent taps. Any ideas?
local _W = display.contentWidth
local _H = display.contentHeight
math.randomseed(os.time())
math.random()
myCircle = display.newCircle(_W * 0.25, _H * 0.25, 50)
local function moveCircle(event)
h_random = math.random()
w_random = math.random()
display.remove(myCircle)
myCircle = display.newCircle(_W * w_random, _H * h_random, 50)
return true
end
myCircle:addEventListener("tap",moveCircle)
Many thanks in advance
I don't have any idea of what library you are using :) But try adding
myCircle:addEventListener("tap",moveCircle)
before return true in the moveCircle function.
From what I can understand from a quick inspection of the code snippet, the proposed change will bind the tap event to the newly created circle.

A lua script on roblox that moves a model upwards?

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

In corona sdk how can I reference / specify all indexes of a spawned object on the screen?

Hi I've been wondering this for a while and it's causing me lots of problems not knowing more about how to reference / specify all indexes of a spawned enemy on the screen at one time.
Say when my character dies I want all the enemies on the screen at that time to move away from my dead character as the screen fades out. Simply calling 'enemy1' only makes one (the last spawned I think) do as it's told.
Here is my enemy spawn script:
local spawnTable2 = {}
local function spawnEnemy()
enemy1 = display.newSprite( group, sheetE, sequenceData2 )
enemy1.x=math.random(100,1300)
enemy1.y=math.random(360,760)
enemy1.gravityScale = 0
enemy1:play()
enemy1.type="coin"
enemy1.objTable = spawnTable2
enemy1.index = #enemy1.objTable + 1
enemy1.myName = "enemy" .. enemy1.index
physics.addBody( enemy1, "kinematic",{ density = 0, friction = 0, bounce = 1 })
enemy1.isFixedRotation = true
enemy1.type = "enemy1"
enemy1.timer = nil
enemy1.enterFrame = moveEnemy
Runtime:addEventListener("enterFrame",enemy1)
enemy1.objTable[enemy1.index] = enemy1
hudGroup:toFront()
return enemy1
end
To reference all objects, you would need to have two things.
A Counter
Loop
First make a counter:
counter = 0
Every time the funciton is called have a counter:
counter = counter + 1
For tables, you would do something like this:
spawnTable2[counter].x=math.random(100,1300)
Then when you want to remove the object, you would just do this:
display.remove(spawnTable2[counter])
Just keep in mind, everything you do to manipulate that object will have to be inside that function. Good luck and hope this helps.

Corona SDK adding physics bodies/ not accepting collisions

I am attempting to add/remove objects from the physics engine (addBody() and removeBody()) in an app I am working on. The app I am working on is modular so the issue is in one of two files.
The objects file (TransmitterObject) or the main file (main):
This is the relevant code for both:
main.lua
local physics = require("physics")
physics.start()
physics.setGravity(0,0)
physics.setDrawMode( "debug" )
local TransmitterObject = require("TransmitterObject")
function updateGame(event)
if(ITERATIONS % 100 == 0) then
tran1:activate() --create new physics object here
end
ITERATIONS = ITERATIONS + 1
--print(ITERATIONS)
end
Runtime:addEventListener("enterFrame", updateGame)
TransmitterObject.lua
function transmitter.new(props) --constructor
Transmitter =
{
x = props.x,
y = props.y,
receivers = props.receivers
}
return setmetatable( Transmitter, transmitter_mt )
end
function transmitter:activate()
local group = math.random(1, #self.receivers)
local receiver = math.random(1,#self.receivers[group])
local x , y = self.receivers[group][receiver][1], self.receivers[group][receiver][2]
local d = math.sqrt(math.pow((self.x-x),2) + math.pow((self.y-y),2))
local dx = math.abs(self.x - x)
local angle = math.deg(math.acos(dx/d))
local beam = display.newRect(self.x,self.y, d, 10)
beam:setReferencePoint(display.TopLeftReferencePoint)
beam.rotation = 180 + angle
beam:setFillColor(0,255,0)
beam.alpha = 0
local function add(event)
physics.addBody(beam, "static")
end
local function delete(event)
physics.removeBody(beam)
end
transition.to( beam, { time=1000, alpha=1.0, onComplete=add } )
transition.to( beam, { time=1000, delay=2500, alpha=0, onComplete=delete})
end
Now let me try to describe the issue a little better. basically every 100th time that 'enterFrame' fires I tell the transmitter object (tran1) to call its function 'activate'
which then preforms some basic math to get coordinates. Then it creates a rectangle (beam) using the calculated information and sets some properties. That is all basic stuff. Next I tell it to transition from not visible (alpha = 0) to visible over the span of 1 second. When does it is to call the function 'add' which adds the object to the physics engine. Likewise with the next line where it removes the objects.
That being said, when i set physics.setDrawMode( "debug" ) the beam object appears as a static body, but does not accept collisions. Does anyone know why the above code would not accept collisions for the beam object?
Keep in mind I have other objects that do work properly within the physics engine.
Wow, I'm answering super late!
On collisions, modifying bodies aren't supported.
What I propose you is to create a new function,
local function addBody ( event )
physics.addBody(ball, "static")
end
and in your collision event you have to add this,
timer.performWithDelay(500, addBody)
The only thing that may cause some problems it's the delay, but as the collision doesn't take too much time it should be ok.
Sorry for this necroposting,
It's just to help other people that may have that problem,
Fannick

Resources