Generate a random number, but every random seconds in LUA/Love2d - random
I am trying to generate a random number, every random seconds (the final purpose would be to change the color of a block from time to time, randomly).
For that, I am using the Hump library (http://vrld.github.io/hump/#hump.timer).
Here is my code at the moment, I am true beginner in LUA/Love2d coding.
It generates a number, and displays it every seconds, instead of every random seconds... (but the random seconds is also generated).
I don't really understand why it is not working.
local Timer = require "timer"
function love.load()
text="t"
number2=1
end
local f = function()
math.randomseed(os.time())
number = math.random( 2,10 )
text="in " .. number2 .. " seconds (random)... random number =" .. number
return true
end
function love.update(dt)
number2 = math.random( 2,4 )
Timer.update(number2)
Timer.addPeriodic(number2, f)
end
function love.draw()
love.graphics.print( text, 330, 300 )
end
Thanks for any help !
While I am not familiar with Hump, it seems that you can easily use the timer's add function for your purpose, as it will call the function exactly once after x seconds, allowing you to schedule the next execution with a different delay:
local timer = require("timer")
local text = ""
local function tick()
-- Generate random number
local newNumber = math.random(2, 10)
local newDelay = math.random(2, 4)
text = ("Current number: %d, next in %d seconds!"):format(newNumber, newDelay)
-- Actually schedule the next call
timer.add(newDelay, tick)
end
function love.load()
tick()
end
function love.update(dt)
timer.update(dt)
end
function love.draw()
love.graphics.print(text, 330, 300)
end
Related
How to print 3600.125 seconds in "H:M:S.s" format in Julia
I got some time intervals using the tic() and toc() functions which are in seconds. Let's suppose I have a time interval dt=3600.125 seconds. How can I print it in "H:M:S.s" format using Julia?
If you convert it to Dates formats then you can use this method. julia> t1 = now() 2017-11-10T10:00:51.974 # Wait julia> t2 = now() 2017-11-10T10:10:07.895 julia> x = Dates.canonicalize(Dates.CompoundPeriod(t2-t1)) 9 minutes, 15 seconds, 921 milliseconds julia> x.periods 3-element Array{Base.Dates.Period,1}: 9 minutes 15 seconds 921 milliseconds julia> x.periods[2] 15 seconds julia> x.periods[2].value 18
You can make your own function. The main function to know is divrem which gives you the divisor as well as the remainder in one convenient function call. dt=3600.125 function hmss(dt) (h,r) = divrem(dt,60*60) (m,r) = divrem(r, 60) #(s,r) = divrem(r, 60) string(Int(h),":",Int(m),":",r) end hmss(dt) hmss(3452.98)
Have a look at the dates section in the manual. Not sure if this is the most efficient way, but this works for instance: julia> Dates.format(DateTime("2017-10-01T01:02:03"), "H:M:S.s") "1:2:3.0"
""" working properly only if 0<= sec <=86400 otherwise truncating """ function fmtsec(sec, fmt::Dates.DateFormat) # nanos = Dates.Nanosecond(sec * 1e9) # we could get InexactError here! nanos = Dates.Nanosecond(trunc(Int, sec * 1e9)) mytime = Dates.Time(nanos) Dates.format(mytime, fmt) end fmt = dateformat"H:M:S.s" # Creating a DateFormat object is expensive. (see doc) fmtsec(3600.125, fmt) # "1:0:0.125" EDIT: Without truncating nanoseconds we could get error -> julia> tic();sleep(1);old_fmtsec(toc(), dateformat"S.s") elapsed time: 1.002896514 seconds ERROR: InexactError() Stacktrace: [1] convert(::Type{Int64}, ::Float64) at ./float.jl:679 [2] fmtsec(::Float64, ::DateFormat{Symbol("S.s"),Tuple{Base.Dates.DatePart{'S'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'s'}}}) at ./REPL[47]:2 julia> tic();sleep(1);old_fmtsec(toc(), dateformat"S.s") elapsed time: 1.002857122 seconds "1.002" tic & toc are deprecated. toc could bring rounding error because it internally use time_ns but nanoseconds convert to seconds dividing by 1e9.
This date from toc() and time() in Julia uses UNIX timestamp, i.e., seconds elapsed since January 1, 1970 The same occurs with the function ctime(f) that returns timestamp from a file path f. The conversion is very straightforward. tic() .... dif = toc() # My local is Brazil, one should replace for its local format Dt = DateTime(LibC.strftime(dif),"d/m/y H:M:S") LibC does not have to be imported explicitly
I had a go now, but doing the carry over is a bit messy sorry: using Dates using Printf function formatDuration(duration::Period, types::Vector{DataType}=[Hour, Minute, Second]; addUnit::Bool=false) periods = canonicalize(Dates.CompoundPeriod(duration)).periods missingTypes = Vector{DataType}(types) newPeriods = vcat(periods, map(t->t(0), missingTypes)) sort!(newPeriods; rev=true) newPeriods1 = Vector{Period}() carryover = nothing for (i, p) in enumerate(newPeriods) typeofp = typeof(p) if !isnothing(carryover) newPeriod = convert(typeofp, floor(Millisecond(p) + Millisecond(carryover), typeofp(1))) carryover = nothing else newPeriod = p end if (typeof(newPeriod) in types) push!(newPeriods1, newPeriod) filter!(e->e≠typeofp,missingTypes) else carryover = newPeriod end end m = map(types) do t f = findfirst(x -> typeof(x) == t, newPeriods1); r = isnothing(f) ? 0 : newPeriods1[f].value; #sprintf("%02d",r) * (addUnit ? lowercase("$t"[1]) : "") end join(m, ":") end Usage examples: #show formatDuration(Millisecond(3600.125*1000)) # returns "01:00:00" #show formatDuration(Day(2), [Hour, Minute, Second]) # returns "48:00:00" #show formatDuration(Second(100000000), [Hour, Minute, Second]) # returns "27777:46:40" #show formatDuration(Second(100000001), [Day, Hour, Minute, Second, Millisecond]) # returns "1157:09:46:41:00" #show formatDuration(Millisecond(10000000001), [Week, Day, Hour, Minute, Second, Millisecond]; addUnit=true) #returns "16w:03d:17h:46m:40s:01m"
Effect not showing up on guis
I'm making an effect in my game where it scrolls through some choices and slows down to a stop on one choice. There's 4 screens and I want each one to play the effect simultaneously, all the guis show up at the same time but the effect never plays. I've marked the part of the code that does the effect in the block of code below: message.chooseduel = function(spins) local lobby=workspace.Lobby local screens=lobby.Screens local n1,n2 for _, screen in pairs(screens:GetChildren()) do local gui=screen.SurfaceGui local ds=gui.DuelScreen gui.Enabled=true for i, v in pairs(ds.Container:GetChildren()) do local ll local lastpicked local t = ds.Container:GetChildren() local menuItems = #t -- number of menu items local repeats = 1 -- Repeated for R = 65 + spins, 1, -1 do ll = t[repeats] if ll:IsA("GuiObject") then --**effect**-- local newgui = coroutine.wrap(function() print("HI!") ll.BackgroundColor3=Color3.fromRGB(130, 125, 56) wait( R^-.7*.7 ) -- ll.BackgroundColor3=ll.BorderColor3 repeats = repeats % menuItems + 1 end) newgui() --**effect**-- end end ll = t[repeats] ll.BackgroundColor3=Color3.fromRGB(230, 225, 156) n1=string.sub(ll.n1.Image,64) n2=string.sub(ll.n2.Image,64) print("Returning:",n1,n2) end end wait(2) return {n1,n2} end
Hope this helps: message.chooseduel = function(spins) spins = math.ceil(spins) -- just making sure. local lobby=workspace.Lobby local screens=lobby.Screens local n1,n2 for _, screen in pairs(screens:GetChildren()) do local gui=screen.SurfaceGui local ds=gui.DuelScreen gui.Enabled=true spawn(function() -- I think this is where the coroutine / async function should start local ll local lastpicked -- Variable not used local t = ds.Container:GetChildren() local numMenuItems = #t -- number of menu items local current = 1 -- Repeated print("HI!") for R = 65 + spins, 1, -1 do ll = t[current] if ll:IsA("GuiObject") then ll.BackgroundColor3=Color3.fromRGB(130, 125, 56) wait( R^-.7*.7 ) -- ll.BackgroundColor3=ll.BorderColor3 current = current % numMenuItems + 1 end end print("BYE!") ll = t[current] ll.BackgroundColor3=Color3.fromRGB(230, 225, 156) n1=string.sub(ll.n1.Image,64) -- um... Interesting. wait what? n2=string.sub(ll.n2.Image,64) print("Returning:",n1,n2) end) end wait(2) return {n1,n2} end I'm not sure I totally get what you are doing here or how you have things set up, but in general you should try to move coroutines / spawned functions to the outsides of loops.
Join tiles in Corona SDK into one word for a Breakout game grid?
I have a game project to re-implement Breakout. I want to display two words, each word on a line. They are joined by the bricks block. Inside, the top line is the first name, aligned left. The bottom line is the last name, aligned right. They are input from textboxes, and rendered as shown: Each second that passes, the screen will add a configurable number of bricks to the grid (for example, five bricks per second) until the two words appear complete. I displayed a letter of the alphabet which is created from the matrix(0,1). ...But I don’t know how to join them into one word. How can I join these letters? This is what I've gotten so far: Bricks.lua local Bricks = display.newGroup() -- static object local Events = require("Events") local Levels = require("Levels") local sound = require("Sound") local physics = require("physics") local Sprites = require("Sprites") local Func = require("Func") local brickSpriteData = { { name = "brick", frames = {Sprites.brick} }, { name = "brick2", frames = {Sprites.brick2} }, { name = "brick3", frames = {Sprites.brick3} }, } -- animation table local brickAnimations = {} Sprites:CreateAnimationTable { spriteData = brickSpriteData, animationTable = brickAnimations } -- get size from temp object for later use local tempBrick = display.newImage('red_apple_20.png',300,500) --local tempBrick = display.newImage('cheryGreen2.png',300,500) local brickSize = { width = tempBrick.width, height = tempBrick.height } --tempBrick:removeSelf( ) ---------------- -- Rubble -- needs to be moved to its own file ---------------- local rubbleSpriteData = { { name = "rubble1", frames = {Sprites.rubble1} }, { name = "rubble2", frames = {Sprites.rubble2} }, { name = "rubble3", frames = {Sprites.rubble3} }, { name = "rubble4", frames = {Sprites.rubble4} }, { name = "rubble5", frames = {Sprites.rubble5} }, } local rubbleAnimations = {} Sprites:CreateAnimationTable { spriteData = rubbleSpriteData, animationTable = rubbleAnimations } local totalBricksBroken = 0 -- used to track when level is complete local totalBricksAtStart = 0 -- contains all brick objects local bricks = {} local function CreateBrick(data) -- random brick sprite local obj = display.newImage('red_apple_20.png') local objGreen = display.newImage('cheryGreen2.png') obj.name = "brick" obj.x = data.x --or display.contentCenterX obj.y = data.y --or 1000 obj.brickType = data.brickType or 1 obj.index = data.index function obj:Break() totalBricksBroken = totalBricksBroken + 1 bricks[self.index] = nil obj:removeSelf( ) sound.play(sound.breakBrick) end function obj:Update() if(self == nil) then return end if(self.y > display.contentHeight - 20) then obj:Break() end end if(obj.brickType ==1) then physics.addBody( obj, "static", {friction=0.5, bounce=0.5 } ) elseif(obj.brickType == 2) then physics.addBody( objGreen,"static",{friction=0.2, bounce=0.5, density = 1 } ) end return obj end local currentLevel = testLevel -- create level from bricks defined in an object -- this allows for levels to be designed local function CreateBricksFromTable(level) totalBricksAtStart = 0 local activeBricksCount = 0 for yi=1, #level.bricks do for xi=1, #level.bricks[yi] do -- create brick? if(level.bricks[yi][xi] > 0) then local xPos local yPos if(level.align == "center") then --1100-((99*16)*0.5) xPos = display.contentCenterX- ((level.columns * brickSize.width) * 0.5/3) + ((xi-1) * level.xSpace)--display.contentCenterX --xPos = 300 +(xi * level.xSpace) yPos = 100 + (yi * level.ySpace)--100 else xPos = level.xStart + (xi * level.xSpace) yPos = level.yStart + (yi * level.ySpace) end local brickData = { x = xPos, y = yPos, brickType = level.bricks[yi][xi], index = activeBricksCount+1 } bricks[activeBricksCount+1] = CreateBrick(brickData) activeBricksCount = activeBricksCount + 1 end end end totalBricks = activeBricksCount totalBricksAtStart = activeBricksCount end -- create bricks for level --> set from above functions, change function to change brick build type local CreateAllBricks = CreateBricksFromTable -- called by a timer so I can pass arguments to CreateAllBricks local function CreateAllBricksTimerCall() CreateAllBricks(Levels.currentLevel) end -- remove all brick objects from memory local function ClearBricks() for i=1, #bricks do bricks[i] = nil end end -- stuff run on enterFrame event function Bricks:Update() -- update individual bricks if(totalBricksAtStart > 0) then for i=1, totalBricksAtStart do -- brick exists? if(bricks[i]) then bricks[i]:Update() end end end -- is level over? if(totalBricksBroken == totalBricks) then Events.allBricksBroken:Dispatch() end end ---------------- -- Events ---------------- function Bricks:allBricksBroken(event) -- cleanup bricks ClearBricks() local t = timer.performWithDelay( 1000, CreateAllBricksTimerCall) --CreateAllBricks() totalBricksBroken = 0 -- play happy sound for player to enjoy sound.play(sound.win) print("You Win!") end Events.allBricksBroken:AddObject(Bricks) CreateAllBricks(Levels.currentLevel) return Bricks Levels.lua local Events = require("Events") local Levels = {} local function MakeLevel(data) local level = {} level.xStart = data.xStart or 100 level.yStart = data.yStart or 100 level.xSpace = data.xSpace or 23 level.ySpace = data.ySpace or 23 level.align = data.align or "center" level.columns = data.columns or #data.bricks[1] level.bricks = data.bricks --> required return level end Levels.test4 = MakeLevel { bricks = { {0,2,0,0,2,0,0,2,0}, {0,0,2,0,2,0,2,0,0}, {0,0,0,0,2,0,0,0,0}, {1,1,2,1,1,1,2,1,1}, {0,0,0,0,1,0,0,0,0}, {0,0,0,0,1,0,0,0,0}, {0,0,0,0,1,0,0,0,0}, } } Levels.test5 = MakeLevel { bricks = { {0,0,0,1,0,0,0,0}, {0,0,1,0,1,0,0,0}, {0,0,1,0,1,0,0,0}, {0,1,0,0,0,1,0,0}, {0,1,1,1,1,1,0,0}, {1,0,0,0,0,0,1,0}, {1,0,0,0,0,0,1,0}, {1,0,0,0,0,0,1,0}, {1,0,0,0,0,0,1,0} } } -- Levels.test6 = MakeLevel2 -- { -- bricks = -- { ----A "a" = {{0,0,0,1,0,0,0,0}, -- {0,0,1,0,1,0,0,0}, -- {0,0,1,0,1,0,0,0}, -- {0,1,0,0,0,1,0,0}, -- {0,1,1,1,1,1,0,0}, -- {1,0,0,0,0,0,1,0}, -- {1,0,0,0,0,0,1,0}, -- {1,0,0,0,0,0,1,0}, -- {1,0,0,0,0,0,1,0}}, ----B -- "b" = {{1,1,1,1,0,0,0}, -- {1,0,0,0,1,0,0}, -- {1,0,0,0,1,0,0}, -- {1,0,0,0,1,0,0}, -- {1,1,1,1,0,0,0}, -- {1,0,0,0,1,0,0}, -- {1,0,0,0,0,1,0}, -- {1,0,0,0,0,1,0}, -- {1,1,1,1,1,0,0}}, --........... --....... --... -- --Z -- "z"= {{1,1,1,1,1,1,1,0}, -- {0,0,0,0,0,1,0,0}, -- {0,0,0,0,1,0,0,0}, -- {0,0,0,0,1,0,0,0}, -- {0,0,0,1,0,0,0,0}, -- {0,0,1,0,0,0,0,0}, -- {0,0,1,0,0,0,0,0}, -- {0,1,0,0,0,0,0,0}, -- {1,1,1,1,1,1,1,0}} -- } -- } -- stores all levels in ordered table so that one can be selected randomly by index Levels.levels = { --Levels.test4, Levels.test5 -- Levels.test6, } function Levels:GetRandomLevel() return self.levels[math.random(#Levels.levels)] end Levels.notPlayedYet = {} Levels.currentLevel = Levels:GetRandomLevel() -- Events function Levels:allBricksBroken(event) self.currentLevel = Levels:GetRandomLevel() end Events.allBricksBroken:AddObject(Levels) return Levels The work I've done thus far (same as above) as an external download: http://www.mediafire.com/download/1t89ftkbznkn184/Breakout2.rar
In the interest of actually answering the question: I'm not 100% sure what you mean by "How can I join these letters", but from poking through the code I have a guess, so please clarify on whether it is accurate, or if I am wrong about what you wanted. Scenario 1 You haven't successfully achieved the image illustrated in the screenshot - you've been able to draw one letter, but not multiple ones. In this case, you'll need to have a better understanding of what your code is doing. The CreateBricksFromTable function takes in a Level object, which is created by the MakeLevel function from a table with a bricks property, which is a table of tables that represent rows with columns in them, showing what type of brick should be at each position. In your commented-out level, you have created an table where the bricks field contains a field for each letter, but the MakeLevel function still expects a bricks field that directly contains the grid of blocks. You will have to - as it seems you attempted - create a MakeWordLevel function (or the like) that takes this letter list, and a word for each line, and constructs a larger grid by copying the appropriate letters into it. StackOverflow is not your programming tutor, and an SO question is not the right forum for having people write code for you or getting into step-by-step details of how to do this, but I'll leave you a basic outline. Your function would look something like this: local function MakeWordLevel(data, line1, line2) local level = {} ... return level end And then would have to: Populate all of the same properties that MakeLevel does Calculate how wide (level.columns) the level should be with all the letters Create a table in the same format as the bricks properties, but big enough to hold all of the letters Go through the input strings (line1 and line2), find the correct letter data from what is now the test6 array, and copy that data into the large table Assign that table as level.bricks This question already is a bit outside of what StackOverflow is intended for in that it asks about how to implement a feature rather than achieve a small, specific programming task, so any further followup should take place in a chatroom - perhaps the Hello World room would be helpful. Scenario 2: This was my original guess, but after considering and reading past edits, I doubt this is answering the right question You may want a solid "background" of, say, red blocks, surrounding your letters and making the field into a solid "wall", with the name in a different color. And you may want these bricks to slowly show up a few at a time. In that case, the main thing you need to do is keep track of what spaces are "taken" by the name bricks. There are many ways to do this, but I would start with a matrix to keep track of that - as big as the final playing field - full of 0's. Then, as you add the bricks for the name, set a 1 at the x,y location in that matrix according to that block's coordinate. When you want to fill in the background, each time you go to add a block at a coordinate, check that "taken" matrix before trying to add a block - if it's taken (1), then just skip it and move onto the next coordinate. This works if you're filling in the background blocks sequentially (say, left to right, top to bottom), or if you want to add them randomly. With random, you'd also want to keep updating the "taken" matrix so you don't try to add a block twice. The random fill-in, however, presents its own problem - it will keep taking longer to fill in as it goes, because it'll find more and more "taken" blocks and have to pick a new one. There are solutions to this, of course, but I won't go too far down that road when I don't know if that's even what you want.
I don't really understand (or read, for that matter) your code but from what I see joining them into complete words is easy. You have two possibilities. You can "render" them directly into your level/display data, simply copy them to the appropriate places, like this: -- The level data. local level = {} -- Create the level data. for row = 1, 25, 1 do local rowData = {} for column = 1, 80, 1 do rowData[column] = "." end level[row] = rowData end -- Now let us setup the letters. local letters = { A = { {".",".",".","#",".",".",".","."}, {".",".","#",".","#",".",".","."}, {".",".","#",".","#",".",".","."}, {".","#",".",".",".","#",".","."}, {".","#","#","#","#","#",".","."}, {"#",".",".",".",".",".","#","."}, {"#",".",".",".",".",".","#","."}, {"#",".",".",".",".",".","#","."}, {"#",".",".",".",".",".","#","."} }, B = { {"#","#","#","#",".",".","."}, {"#",".",".",".","#",".","."}, {"#",".",".",".","#",".","."}, {"#",".",".",".","#",".","."}, {"#","#","#","#",".",".","."}, {"#",".",".",".","#",".","."}, {"#",".",".",".",".","#","."}, {"#",".",".",".",".","#","."}, {"#","#","#","#","#",".","."} } } -- The string to print. local text = "ABBA" -- Let us insert the data into the level data. for index = 1, #text, 1 do local char = string.sub(text, index, index) local charData = letters[char] local offset = index * 7 for row = 1, 9, 1 do local rowData = charData[row] for column = 1, 7, 1 do level[row][offset + column] = rowData[column] end end end -- Print everything for row = 1, 25, 1 do local rowData = level[row] for column = 1, 80, 1 do io.write(rowData[column]) end print() end You save you letters in a lookup table and then copy them, piece by piece, to the level data. Here I replaced the numbers with dots and number signs to make it prettier on the command line. Alternately to that you can also "render" the words into a prepared buffer and then insert that into the level data by using the same logic.
Random in .lua programming
I have to make a random numer (1 and 2) in .lua, and change this value every 3 seconds. I have a variable = randomMode, this randomMode have to change every 3 seconds (1 or 2)
You could try making a kind of timer that changes the value. For example the main program loop could to change the variable every 3 seconds by using time stamps. If you cant use a good way to implement a timer, maybe just checking time stamps since last call is good enough. For example this function randomizes the number on each call to GetRandomMode if more than 3 seconds has passed: local lastChange = os.time() local mode = math.random(1, 2) function GetRandomMode() local now = os.time() if os.difftime(now, lastChange) > 3 then lastChange = now mode = math.random(1, 2) end return mode end
Lua for loop does not iterate properly
I am in dire need of help with a for loop. I'm trying to go through a for loop in Lua with the Corona SDK, but I am doing something wrong but I don't know what. See below for my code: function moveLift(event) for j=1,4,1 do if event.phase == "began" then markY = event.target.y elseif event.phase == "moved" then local y = (event.y - event.yStart) + markY event.target.y = y elseif event.phase == "ended" then if (hasCollided( event.target, hotSpots[j] )) then print("hasCollided with floor: ", hotSpots[j].floor) if (event.target.destination == hotSpots[j].floor) then print("correct floor") succesfullPassengers = succesfullPassengers + 1 if succesfullPassengers == PASSENGER_AMOUNT then print("game over") end else print("Wrong! elevator has collided with floor: ", hotSpots[j].floor) end end end return true end end What I'm trying to do here is checking when I drag and drop an elevator on screen on what floor it has landed. I've created hotspots (basically hitboxes and currently serving as art placeholder) and placed them in the hotSpot table like this: -- Create elevator hotspots for k=1,4,1 do hotSpots[k] = display.newRect( gameAreaGroup, 0, 0, 50, 75 ) hotSpots[k].alpha = 0.25 --Show hotspots with alpha hotSpots[k].floor = k -- The floor id print("Created hotspot on floor: ",hotSpots[k].floor) hotSpots[k].x = display.contentWidth *0.5 hotSpots[k].y = firstFloor - (FLOOR_HEIGHT * k) hotSpots[k]:setFillColor( 255,0,0 ) hotSpots[k]:addEventListener( "tap", returnFloor ) -- Check floor value gameAreaGroup:insert(hotSpots[k]) end I check if every hotspot has a unique floor value with a test function called returnFloor, which they have (1,2,3,4). When I drag and drop my elevator on the first floor, I receive the message "Wrong! elevator has collided with floor: 1", but on any other floor I receive the message: "hasCollided with floor: 1". So there must be something wrong with the for loop in my moveLift function because it only returns floor 1 and not any other floor. PS: the correct floor is 4, the top floor.
You have "return true" inside your for loop, so it will never get past j=1. I think you may need to move that statement up inside the last if statement, or below the "end" that follows it (without knowing the full logic, I'm not sure what the returned value is used for).
Last lines of code should not be end end return true end end but end end end return true end so the return is after the loop has completed.