Is it possible to drag and drop polygon blocks with the mouse? - lua

I am practicing simple lua programming with love2d.
What about the code that enables mouse drag and drop of polygon blocks here?
function love.load()
b1 = {}
mouse = {}
love.physics.setMeter(70)
world = love.physics.newWorld(0, 9.81*64, true)
objects = {}
objects.ground = {}
objects.ground.body = love.physics.newBody(world, 700/2, 660)
objects.ground.shape = love.physics.newRectangleShape(650, 50)
objects.ground.fixture = love.physics.newFixture(objects.ground.body,objects.ground.shape)
objects.lwall = {}
objects.lwall.body = love.physics.newBody(world, 0, 350)
objects.lwall.shape = love.physics.newRectangleShape(50, 6500)
objects.lwall.fixture = love.physics.newFixture(objects.lwall.body,objects.lwall.shape)
objects.rwall = {}
objects.rwall.body = love.physics.newBody(world, 700, 350)
objects.rwall.shape = love.physics.newRectangleShape(50, 6500)
objects.rwall.fixture = love.physics.newFixture(objects.rwall.body,objects.rwall.shape)
objects.block1 = {}
objects.block1.body = love.physics.newBody(world, 200, 300, "dynamic")
objects.block1.shape = love.physics.newRectangleShape(0, 0, 162.5,32.5)
objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 5)
objects.block2 = {}
objects.block2.body = love.physics.newBody(world, 200, 350, "dynamic")
objects.block2.shape = love.physics.newRectangleShape(0, 0, 162.5,32.5)
objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.shape, 2)
objects.block3 = {}
objects.block3.body = love.physics.newBody(world, 200, 400, "dynamic")
objects.block3.shape = love.physics.newRectangleShape(0, 0, 162.5,32.5)
objects.block3.fixture = love.physics.newFixture(objects.block3.body, objects.block3.shape, 5)
objects.block4 = {}
objects.block4.body = love.physics.newBody(world, 200, 450, "dynamic")
objects.block4.shape = love.physics.newRectangleShape(0, 0, 162.5,32.5)
objects.block4.fixture = love.physics.newFixture(objects.block4.body, objects.block4.shape, 5)
objects.block5 = {}
objects.block5.body = love.physics.newBody(world, 200, 500, "dynamic")
objects.block5.shape = love.physics.newRectangleShape(0, 0, 162.5,32.5)
objects.block5.fixture = love.physics.newFixture(objects.block5.body, objects.block5.shape, 5)
objects.block6 = {}
objects.block6.body = love.physics.newBody(world, 200, 550, "dynamic")
objects.block6.shape = love.physics.newRectangleShape(0, 0, 162.5,32.5)
objects.block6.fixture = love.physics.newFixture(objects.block6.body, objects.block6.shape, 5)
objects.block7 = {}
objects.block7.body = love.physics.newBody(world, 200, 600, "dynamic")
objects.block7.shape = love.physics.newRectangleShape(0, 0, 162.5,32.5)
objects.block7.fixture = love.physics.newFixture(objects.block7.body, objects.block7.shape, 5)
love.graphics.setBackgroundColor(0, 0, 0)
love.window.setMode(700, 650)
end
function getMouse()
local isDown = love.mouse.isDown(1,2)
return x, y, isDown
end
function love.update(dt)
world:update(dt)
mouse.x, mouse.y = love.mouse.getPosition()
objects.block1.x, objects.block1.y = objects.block1.body:getPosition()
if love.keyboard.isDown("d") then
objects.block1.body:applyForce(4000, 0)
objects.block1.body:applyTorque(100000)
if love.keyboard.isDown("w") then
objects.block1.body:applyForce(0, -150000)
objects.block1.body:setLinearVelocity(0, 0)
end
elseif love.keyboard.isDown("a") then
objects.block1.body:applyForce(-4000, 0)
objects.block1.body:applyTorque(-100000)
if love.keyboard.isDown("w") then
objects.block1.body:applyForce(0, -150000)
objects.block1.body:setLinearVelocity(0, 0)
end
elseif love.keyboard.isDown("w") then
objects.block1.body:applyForce(0, -350000)
objects.block1.body:setLinearVelocity(0, 0)
elseif love.keyboard.isDown("s") then
objects.block1.body:applyForce(0, 350000)
objects.block1.body:setLinearVelocity(0, 0)
end
if love.keyboard.isDown("l") then
objects.block2.body:applyForce(4000, 0)
elseif love.keyboard.isDown("j") then
objects.block2.body:applyForce(-4000, 0)
elseif love.keyboard.isDown("i") then
objects.block2.body:applyForce(0, -150000)
objects.block2.body:setLinearVelocity(0, 0)
end
if objects.block1.body:getPosition() == love.mouse.getPosition() then
if love.mouse.isDown(1) then
objects.block1.x = objects.block1.x - 700
objects.block1.y = objects.block1.y - 650
end
end
end
function love.draw()
love.graphics.setColor(0.7, 0.7, 0.7)
love.graphics.polygon("fill", objects.ground.body:getWorldPoints(objects.ground.shape:getPoints()))
love.graphics.polygon("fill", objects.lwall.body:getWorldPoints(objects.lwall.shape:getPoints()))
love.graphics.polygon("fill", objects.rwall.body:getWorldPoints(objects.rwall.shape:getPoints()))
love.graphics.setColor(0.95, 0.5, 0.1)
love.graphics.polygon("fill", objects.block1.body:getWorldPoints(objects.block1.shape:getPoints()))
love.graphics.polygon("fill", objects.block2.body:getWorldPoints(objects.block2.shape:getPoints()))
love.graphics.polygon("fill", objects.block3.body:getWorldPoints(objects.block1.shape:getPoints()))
love.graphics.polygon("fill", objects.block4.body:getWorldPoints(objects.block2.shape:getPoints()))
love.graphics.polygon("fill", objects.block5.body:getWorldPoints(objects.block1.shape:getPoints()))
love.graphics.polygon("fill", objects.block6.body:getWorldPoints(objects.block2.shape:getPoints()))
love.graphics.polygon("fill", objects.block7.body:getWorldPoints(objects.block1.shape:getPoints()))
love.graphics.setColor(1, 1, 1)
love.graphics.print("Mouse locate : " .. mouse.x..','..mouse.y)
love.graphics.print("block 1 locate : " .. objects.block1.x..','..objects.block1.y, 200)
end
How can I fix it so that I can drag and drop each polygon block in that code?
(in a similar way to Google Gravity)
I tried to configure the code so that the individual polygon blocks and the current mouse position are the same, and move when left-clicked, but it failed.

You are trying to compare a position (center of object) with the position of the mouse. Both are floats, the chance that you hit exactly the center of your shape is effectively zero.
Instead you might want to check for collision:
if love.mouse.isDown(1) then
local mx, my = love.mouse.getPosition()
mx, my = objects.block1.body:getLocalPoint(mx, my)
if objects.block1.shape:testPoint(mx, my, 0, 0, 0) then
objects.block1.body:setPosition(love.mouse.getPosition())
end
end
I transformed the current mouse position to the position relative to your body. I then checked, if this point collides with the bodies shape. The last three arguments are not properly documented, but it looks like they are offset and rotation.
I then set the position using the bodies setPosition. You tried to set your copy of the position, which won't reflect your change. Notice that setting the position will not reset or modify the velocity, thus if you hold the object, it will still build up velocity due to gravity.
There is still room for improvement, for example, you should hold on the object once pressed, as well as keep the initial offset.

Related

how do I fix my script made in Roblox Lua?

I'm making my script and the Script Analysis tool says
Error: (54,2) Expected , got 'end'
I thought maybe you guys might help.
Here is the code
-- to be placed in StarterPlayer > StarterPlayerScripts
local Players = game:GetService("Players")
-- wait for local player PlayerGui
local LocalPlayer = Players.LocalPlayer
local playerGui = LocalPlayer:WaitForChild("PlayerGui")
-- create a ScreenGui
local screenGui = Instance.new("ScreenGui", playerGui)
-- create a holder for our bar
local frame = Instance.new("Frame", screenGui)
frame.AnchorPoint = Vector2.new(0.0, 0.0)
frame.Position = UDim2.new(0.0, 0, 0.0, 0)
frame.Size = UDim2.new(0.0, 0, 0.0, 0)
-- create a bar
local bar = Instance.new("Frame", frame)
bar.Position = UDim2.new(0, 0, 0, 0)
bar.Size = UDim2.new(1, 0, 1, 0)
bar.BackgroundColor3 = Color3.new(0, 1, 0)
-- create a sound
local sound = Instance.new("Sound", screenGui)
local lastLoudness = 0
sound.SoundId = "rbxassetid://697821987"
sound.Looped = true
sound:Play()
-- define a max loudness
local maxLoudness = 30
-- animate the amplitude bar
while true do
local amplitude = math.clamp(sound.PlaybackLoudness / maxLoudness, 0, 1)
print(80-(game.Workspace.CurrentCamera.FieldOfView))
bar.Size = UDim2.new(sound.PlaybackLoudness / maxLoudness, 0, 0, 0)
wait(0.00001)
local lastLoudness = 0
local PBS = ((sound.PlaybackLoudness/50)^(sound.PlaybackLoudness/50))
if lastLoudness~=0 then
local formula = math.abs((lastLoudness*15)) + ((lastLoudness+PBS)/1.9)
if (math.abs(PBS) > formula) == true then
game.Workspace.CurrentCamera.FieldOfView = (lastLoudness)
if game.Workspace.CurrentCamera.FieldOfView <= 10 then
print(formula, PBS)
else
game.Workspace.CurrentCamera.FieldOfView = 0
print(formula, PBS)
end
end
end
end
end
end
I genuinely Don't know how to fix the code, So...
Could you guys Help me?
I spent a long time (a couple of hours) on this and I'm legitimately stuck in the deepest pits of coding hell. And I want this fixed SO BADLY.
Also, Just To Clarify, The script is supposed to change FOV when sound.PlaybackLoudness ÷ 50 × sound.PlaybackLoudness ÷ 50 is over 0.
Egor Skriptunoff is right. Let me reformat your while-loop to show you why.
-- animate the amplitude bar
while true do
local amplitude = math.clamp(sound.PlaybackLoudness / maxLoudness, 0, 1)
print(80-(game.Workspace.CurrentCamera.FieldOfView))
bar.Size = UDim2.new(sound.PlaybackLoudness / maxLoudness, 0, 0, 0)
wait(0.00001)
local lastLoudness = 0
local PBS = ((sound.PlaybackLoudness/50)^(sound.PlaybackLoudness/50))
if lastLoudness~=0 then
local formula = math.abs((lastLoudness*15)) + ((lastLoudness+PBS)/1.9)
if (math.abs(PBS) > formula) == true then
game.Workspace.CurrentCamera.FieldOfView = (lastLoudness)
if game.Workspace.CurrentCamera.FieldOfView <= 10 then
print(formula, PBS)
else
game.Workspace.CurrentCamera.FieldOfView = 0
print(formula, PBS)
end
end
end
end
end -- <-- these bad boys don't go with anything
end -- <-- just remove them to get rid of the error
EDIT : Here's a more complete answer to help with your other script issues. You were resizing your animation stuff to 0 pixels tall, so you couldn't see anything.
-- to be placed in StarterPlayer > StarterPlayerScripts
local Players = game:GetService("Players")
-- wait for local player PlayerGui
local LocalPlayer = Players.LocalPlayer
local playerGui = LocalPlayer:WaitForChild("PlayerGui")
-- create a ScreenGui
local screenGui = Instance.new("ScreenGui", playerGui)
-- create a holder for our bar
local frame = Instance.new("Frame", screenGui)
frame.AnchorPoint = Vector2.new(0.0, 0.0)
frame.Position = UDim2.new(0.0, 0, 0.0, 0)
frame.Size = UDim2.new(1.0, 0, 0.0, 50) -- <-- this is no longer invisible
-- create a bar
local bar = Instance.new("Frame", frame)
bar.Position = UDim2.new(0, 0, 0, 0)
bar.Size = UDim2.new(1, 0, 1, 0)
bar.BackgroundColor3 = Color3.new(0, 1, 0)
-- create a sound
local sound = Instance.new("Sound", screenGui)
local lastLoudness = 0
sound.SoundId = "rbxassetid://697821987"
sound.Looped = true
sound:Play()
-- define a max loudness
local maxLoudness = 30.0 -- <-- this needed to be a decimal value
local lastLoudness = 0
-- animate the amplitude bar
while true do
-- PlaybackLoudness values range from 0 to 500, so downscale it
local sampledLoundness = (sound.PlaybackLoudness / 50)
local amplitude = math.clamp(sampledLoundness / maxLoudness, 0, 1)
print("sound values : ", sound.PlaybackLoudness, maxLoudness, amplitude)
-- animate the bar
bar.Size = UDim2.new(amplitude, 0, 1, 0) -- <-- this was squashed to 0 pixels
wait(0.00001)
-- create a camera shake effect
-- NOTE - not sure what the expected behavior is here, it just zooms in
local PBS = sampledLoundness ^ sampledLoundness
if lastLoudness ~=0 then
local formula = math.abs(lastLoudness * 15) + ((lastLoudness + PBS) / 1.9)
if (math.abs(PBS) > formula) == true then
game.Workspace.CurrentCamera.FieldOfView = lastLoudness
if game.Workspace.CurrentCamera.FieldOfView <= 10 then
print("FOV is less than 10 : ", formula, PBS)
else
game.Workspace.CurrentCamera.FieldOfView = 0
print("FOV forced to 0 : ", formula, PBS)
end
end
end
-- update lastLoudness and loop
lastLoudness = sampledLoundness
end

Even with delay all objects appear in display at once... what do I do?

local path = pather:getPath(startx,starty, endx,endy)
if path then
compPath = display.newGroup();
for node, count in path:nodes() do
--timer.performWithDelay( 1000, function (event)
print(('Step: %d - x: %d - y: %d'):format(count, node:getX(), node:getY()))
local tile = display.newRect((node:getX() * 50) - 25, (node:getY() * 50) - 25, 48, 48)
colorCell(tile, 0, 0, 255)
tile.alpha = 0
usleep(500);
transition.fadeIn( tile, { time=1500 } )
compPath:insert(tile)
--end
--)
end
end
I have this path that I am trying to animate as it appears but it seems to all show at once even with a delay or if I put it in a timer to go in spurts. Do I have to be displaying it using framerate at every second instead?
What am I missing?
You're not incrementing the delay time in the loop, so you're scheduling all your path nodes to show up in 1 second.
Remember, the loop is going to execute almost instantly (computers are fast).
Try this:
if path then
compPath = display.newGroup();
local revealInterval = 500
local revealTimeout = 0
for node, count in path:nodes() do
timer.performWithDelay( revealTimeout, function (event)
local tile = display.newRect((node:getX() * 50) - 25, (node:getY() * 50) - 25, 48, 48)
colorCell(tile, 0, 0, 255)
tile.alpha = 0
transition.fadeIn( tile, { time=1500 } )
compPath:insert(tile)
end
)
revealTimeout = revealTimeout + revealInterval
end
end

What is wrong with the restart game function in corona

The restart game function doesn't seem to work and I don't know why. The balloons, scores resets but the game doesn't resets, i can't shoot the balloons again. (plus the askUser, yesBtn and noBtn doesn't go invisible either)
function createBalloons(a, b)
for i = 1, a do
for j = 1, b do
local balloon = display.newImage ('balloon_fat_red.png', 270+ (i * 30), 80 + (j * 50))
balloonText = display.newText(hiragana_array[x+1], 300, 125)
balloonTextt = display.newText(hiragana_array[x+2], 300, 175)
balloonTexttt = display.newText(hiragana_array[x+3], 300, 225)
balloonText:setFillColor( 1,1, 0 )
balloonTextt:setFillColor( 1,1, 0 )
balloonTexttt:setFillColor( 1,1, 0 )
balloon.name = 'balloon'
physics.addBody(balloon)
balloon.bodyType = 'static'
table.insert(balloons, balloon)
end
end
target.text = #balloons
end
function restartLvl()
for i = 1, #balloons do
display.remove(balloons[i])
print ("restart level")
end
score.text = '0'
ballRemain.text = '3'
balloons = {}
createBalloons(1, 3)
askUser.isVisible = false
yesBtn.isVisible = false
noBtn.isVisible = false
print("time from start: ", (system.getTimer()-gameTime))
print('send mail')
sendMail()
end
This is what it shows in the simulator.
I'm not seeing any problem with that code, my guess is the problem is elsewhere. You're going to have to dig a little more, maybe put some more print statements. For example maybe isVisible is being reset to true by another function, after the restartLvl, like in an enterFrame handler.

Re-set spawn after collision

Basically what happens is objects spawn off screen at random positions and then flow in and out of the screen view.
as they flow of screen they reset at a random position off screen again, however I cannot get that to happen if the player collides with it.
So to summarise, how would I make the object position respawn off screen again on collision with player?
Heres the object code.
UFO = display.newImage("ufo.png")
UFO.name = "UFO"
UFO.x = 640
UFO.y = 100
UFO.speed = math.random(2,6)
UFO.initY = UFO.y
UFO.amp = math.random(20,100)
UFO.angle = math.random(1,360)
physics.addBody(UFO, "static")
function moveUFO(self,event)
if self.x < -50 then
self.x = math.random(500,1500)
self.y = math.random(90,220)
self.speed = math.random(2,6)
self.amp = math.random(20,100)
self.angle = math.random(1,360)
else
self.x = self.x - self.speed
self.angle = self.angle + .1
self.y = self.amp*math.sin(self.angle)+self.initY
end
Here is the code for collision detection
function ship:collision(event)
if (event.other.name == 'UFO') then
event.other:removeSelf(self)
scoreAnim = display.newText('+10', ship.x, ship.y-10, native.systemFontBold, 16)
transition.to(scoreAnim, {time = 1000, y = scoreAnim.y - 30, alpha = 0, onComplete = function() display.remove(scoreAnim) scoreAnim = nil end})
scoreAnim:setTextColor(0,255,12)
--increases score
collectedN.text = tostring(tonumber(collectedN.text) + 1)
ship:addEventListener("collision", onCollision, ship, addTime)
If I didn't misunderstand you don't know about collision detection. You should study this page:http://developer.coronalabs.com/content/game-edition-collision-detection
edit part:
function ship:collision(event)
if (event.other.name == 'UFO') then
timer.performWithDelay( 50, function() event.other.x = math.random( 0, 320 ); event.other.y = math.random( 0.480 ); end, 1 )
scoreAnim = display.newText('+10', ship.x, ship.y-10, native.systemFontBold, 16)
transition.to(scoreAnim, {time = 1000, y = scoreAnim.y - 30, alpha = 0, onComplete = function() display.remove(scoreAnim) scoreAnim = nil end})
scoreAnim:setTextColor(0,255,12)
--increases score
collectedN.text = tostring(tonumber(collectedN.text) + 1)
This will do it.. You can modify random values over there. And you couldn't move your object right in collision time, because Corona physics, lock all physics objects in collision time. So you should move your objects right after collision.

How to Spawn multiple objects every 10 seconds

How to make this spawn 'math.random(1,3)' smile.png every 10 seconds , and delete the smile.png after the left screen
<code>
local physics = require ("physics");
physics.start();
local function listener(me)
transition.to (me, {time = math.random(1000,4000), x = math.random(10,310), y = -30, onComplete = function()listener(me)end});
end
--Spawning multiple objects in randoms locations
local function spawnsmile()
local smile = display.newImageRect("smile.png", 45, 45);
smile:setReferencePoint(display.CenterReferencePoint);
smile.x = math.random(-10, 400);
smile.y = -40;
transition.to( smile, {time = math.random(2000, 8000), x = math.random(-10, 400) , y = 600,});
physics.addBody(smile, "dynamic", {density = 0.1, bounce = 0.1, friction = .1, radius = 0});
--Adding touch event
smile:addEventListener("touch", smile);
end
tmr = timer.performWithDelay(0, spawnsmile, total_smiles);
<code>
Regards Kevin
Your code was missing total_smiles value assignment and delay argument.
Working code:
local physics = require ("physics");
physics.start();
local function listener(me)
transition.to (me, {time = math.random(1000,4000), x = math.random(10,310), y = -30, onComplete = function()listener(me)end});
end
--Spawning multiple objects in randoms locations
local function spawnsmile()
local smile = display.newImageRect("Button.png", 45, 45);
smile:setReferencePoint(display.CenterReferencePoint);
smile.x = math.random(-10, 400);
smile.y = -40;
transition.to( smile, {time = math.random(2000, 8000), x = math.random(-10, 400) , y = 600,});
physics.addBody(smile, "dynamic", {density = 0.1, bounce = 0.1, friction = .1, radius = 0});
--Adding touch event
smile:addEventListener("touch", smile);
end
local total_smiles = 15
tmr = timer.performWithDelay(10000, spawnsmile, total_smiles);
Moreover, you should store references to created smiles in order to properly destroy them and don't leak memory. more info on memory managment
local smiles = {}
table.insert(smiles, smile)
And disposal:
for i=#smiles,1,-1 do
smiles[i]:removeSelf()
smiles[i] = nil
end
change your timer to perform every 10.000 ms instead of 0. And your listener function doesnt really fill any purpose, remove that and change your transition.to inside of spawnsmile function to
transition.to( smile, {time = math.random(2000, 8000), x = math.random(-10, 400) , y = 600, onComplete = function(obj) obj:removeSelf() obj = nil end});
That should do what you want it to do =) Also there needs to be a value inside total_smiles, but i guess you have it elsewhere.

Resources