Love2D, LUA Tween resetting - lua

I have a problem with my tweening. I am using tween.lua to move my character left or right when that button is held. On release the player returns back to the middle. Tweening works perfectly for when the character goes either left or right but, for some reason when it has to go back to the middle the character just warps there and does not tween. I suspect that either the base X is overriding it or I am not resseting at the right moment.
Here is my code:
--Local variables
local lg = love.graphics
local lk = love.keyboard
function player:load(arg) --Player load function. Called when loaded.
self.img = lg.newImage(currentPimg)
playerWidth = player.img:getWidth() --Gets player image width and sets as a variable
self.mid = width/2 - playerWidth/2
self.left = 100 - playerWidth/2
self.right = width - 100 - playerWidth/2
self.x = player.mid
self.y = height-150
self.speed = 0.04
GoMid = tween.new(player.speed , player, {x=player.mid}, 'linear')
GoLeft = tween.new(player.speed , player, {x=player.left}, 'linear')
GoRight = tween.new(player.speed , player, {x=player.right}, 'linear')
end
function player:update(dt) --Player update function. Called each frame, passes DT (delta time)
playerWidth = player.img:getWidth() --Gets player image width and sets as a variable
if LeftStarted and not isLeft then
GoLeft:reset()
LeftStarted = false
end
if RightStarted and not isRight then
GoRight:reset()
RightStarted = false
end
if MidStarted and not isMid then
GoMid:reset()
MidStarted = false
end
if isMid then --If is true then do action
GoMid:update(dt)
MidStarted = true
end
if isRight then --If is true then do action
GoRight:update(dt)
RightStarted = true
end
if isLeft then --If is true then do action
GoLeft:update(dt)
LeftStarted = true
end
if lk.isDown("left", "a") and not isRight then --this check needs to be done since the code is executed the first time. If I do not check weird stuff happens
isLeft = true
isRight, isMid = false
elseif lk.isDown("right", "d") then --checks if the button is down and returns true if it is
isRight = true
isLeft, isMid = false
else -- if nothing is down resets player to mid and all variables to false
isLeft, isRight = false
isMid = true
end
end
function player:draw(dt) --Draw function. Called each frame, passes DT (delta time)
lg.draw(player.img, player.x, player.y) --Draws player image at X and Y
end

Working version of your code
So, after messing a lot with the code, I can present the following to you:
player = { } --Required table thing
--Local variables
local lg = love.graphics
local lk = love.keyboard
function player:load(arg) --Player load function. Called when loaded.
self.img = lg.newImage(currentPimg)
playerWidth = player.img:getWidth() --Gets player image width and sets as a variable
self.mid = width/2 - playerWidth/2
self.left = 100 - playerWidth/2
self.right = width - 100 - playerWidth/2
self.x = player.mid
self.y = height-150
self.speed = 0.5
GoMid = tween.new(player.speed , player, {x=player.mid}, 'linear')
GoLeft = tween.new(player.speed , player, {x=player.left}, 'linear')
GoRight = tween.new(player.speed , player, {x=player.right}, 'linear')
end
function player:update(dt) --Player update function. Called each frame, passes DT (delta time)
playerWidth = player.img:getWidth() --Gets player image width and sets as a variable
if LeftStarted and not isLeft then
GoMid = tween.new(player.speed , player, {x=player.mid}, 'linear')
LeftNeedsReset = true
LeftStarted = false
end
if RightStarted and not isRight then
GoMid = tween.new(player.speed , player, {x=player.mid}, 'linear')
RightNeedsReset = true
RightStarted = false
end
if isMid then --If is true then do action
GoMid:update(dt)
end
if isRight then --If is true then do action
if RightNeedsReset then
GoRight:reset()
RightNeedsReset = false
end
GoRight:update(dt)
RightStarted = true
end
if isLeft then --If is true then do action
if LeftNeedsReset then
GoLeft:reset()
LeftNeedsReset = false
end
GoLeft:update(dt)
LeftStarted = true
end
if lk.isDown("left", "a") and not isRight then --this check needs to be done since the code is executed the first time. If I do not check weird stuff happens
isLeft = true
isRight, isMid = false, false
elseif lk.isDown("right", "d") then --checks if the button is down and returns true if it is
isRight = true
isLeft, isMid = false, false
else -- if nothing is down resets player to mid and all variables to false
isLeft, isRight = false, false
isMid = true
end
end
function player:draw(dt) --Draw function. Called each frame, passes DT (delta time)
lg.draw(player.img, player.x, player.y) --Draws player image at X and Y
end
This sort of achieves what I think you wanted (the player smoothly moving back to the center), but I still don't think this is a good solution.
What I did was that I made a new motion with the appropriate starting point whenever the player needs to start moving back towards the center, and I delayed the resetting of the directional motions until it was necessary, because it makes the player jump back to the starting point.
Observations
I have noticed a few things while I was working with your code.
The first one was that you tried to give a value to multiple variables. As far as I know, it doesn't work this way in Lua. In order to do that you would have to write this:
isLeft, isRight = false, false
instead of this:
isLeft, isRight = false
Also a thing that took a while for me to notice while debugging was that you have wrote the resetting parts of the directions in a different order than the updating parts. I wouldn't consider this a good habit unless you have got very strong reasons to do it this way.
Suggestions
In my opinion this library isn't really suited for this task (although I don't know it very well, this was my first time using it while debugging your code). This could be done easily with built in functionality of the language and the framework itself. You could have a variable that keeps track of the current position, and then change it continuously towards the direction of the pressed button until a limit, and then dragging it back to the center when all the keys are released.
I haven't tested this code, just written it blindly, but it might look something like this:
if love.keyboard.isDown("left") then
if currentPosition > middlePosition - movementLimit then
currentPosition = currentPosition - 20 * dt
end
elseif love.keyboard.isDown("right") then
if currentPosition < middlePosition + movementLimit then
currentPosition = currentPosition + 20 * dt
end
else
if currentPosition < middlePosition then
currentPosition = currentPosition + 20 * dt
elseif currentPosition > middlePosition then
currentPosition = currentPosition - 20 * dt
end
end
ps.:Another thing I wouldn't mind would be if you could keep the wording of your comments in the source code between the bounds of good taste.
[khm.. debugging.lua : line 7. khm..]
I hope you succeed with your project! Good luck!

Related

Having issues with Region3 in roblox lua

I have been trying to work on a Region3 script were when you are in it, it plays a song. But I've come across 2 issues, 1 being it thinks the player is always in it when you the player isn't. And the second being the script runs so fast that it keeps repeating before anything can happen
local RegionPart = game.Workspace.RegionArea
local pos1 = RegionPart.Position - (RegionPart.Size / 2)
local pos2 = RegionPart.Position + (RegionPart.Size / 2)
local Region = Region3.new(pos1, pos2)
while true do
wait()
local burhj = workspace:FindPartsInRegion3(Region, nil, 1000)
local song = game.Workspace.bb
song:Play()
print("THE SCRIPT WORKS!")
end
You query the objects which are in Region, but never used the result and just continued. Loop over burhj and check for valid parts.
In this forum the use of FindFirstChild is suggested:
for i,v in ipairs(burhj) do
local player = v.Parent:FindFirstChild("Humanoid")
if player then
print("player is in region: " + player.Parent.Name)
end
end
Alternatively, you can directly use the player position, if the player object or position is known:
local pos = yourPlayer.HumanoidRootPart.Position
local center = region.CFrame
local size = region.Size
if pos.X > center.X - size.X / 2 and pos.X < center.X + size.X / 2 and ... then
print("player is in region")
end
A helper function, if not already present, might be helpful.
For the second problem, set a flag if the player is in the region. Play the sound when the flag was not already set. Unset the flag if you leave the region.
--here are your vars
local enteredFlag = false
while true do
wait()
if playerIsWithinRegion then --here come whatever approach you chose earlier
if not enteredFlag then
enteredFlag = true
local song = game.Workspace.bb
song:Play()
print("THE SCRIPT WORKS!")
end
else
--no player is in the region, lets reset the flag
enteredFlag = false
end
end

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.

My script in Roblox works fine, but once I added a debounce, it still worked perfectly, but only sometimes?

For example: The script works fine in one game session, but then in another, it doesn't work at all; almost as if there's some sort of random chance for the script to be deleted or completely ignored. If I remove the debounce, there's a 100% chance for the script to work once again. What could possibly be going wrong here?
local radius = script.Parent
local light = radius.Parent.Light
local sound = radius.Parent.lighton
local debounce = false
radius.Touched:connect(function(hit)
if debounce == false then debounce = true
if game.Players:GetPlayerFromCharacter(hit.Parent) then
light.PointLight.Brightness = 10
light.Material = "Neon"
sound:Play()
wait(5.5)
light.PointLight.Brightness = 0
light.Material = "Plastic"
sound:Play()
wait(0.5)
debounce = false
end
end
end)
Your problem is one of scoping. The debounce will always be set to true, but will only sometimes be set back to false. If it doesn't get changed, the function will obviously never be run again. You'll want to avoid lines like if debounce == false then debounce = true, as they make it more difficult for you to notice that the debounce is not changed in the same scope.
Fixed code:
local radius = script.Parent
local light = radius.Parent.Light
local sound = radius.Parent.lighton
local debounce = false
radius.Touched:connect(function(hit)
if debounce == false then
debounce = true
if game.Players:GetPlayerFromCharacter(hit.Parent) then
light.PointLight.Brightness = 10
light.Material = "Neon"
sound:Play()
wait(5.5)
light.PointLight.Brightness = 0
light.Material = "Plastic"
sound:Play()
wait(0.5)
end
debounce = false
end
end)
Note that both statements changing the value of debounce align.

Corona SDK - Resize a moving physics body

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.

Update the target coordinates while transitioning

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

Resources