Corona SDK piano app - swapping sounds, etc - function

So basically I am making piano app in Corona SDK (my first project) and Im new to it. I've asked some questions about my problem on Corona forums but I don't have achieved exact answers that would help me, so I'm asking for your help. As I said im new, so it may be hard for me to crack out the needed code, but I know that you, more experienced Corona users, can easily do this.
I use this code for each key: (I know that media.playEventSound is pretty weak option to do that, I've seen some libraries about playing audio on Coronalabs like audio.loadSound etc. but if it is possible, of course, I'd like to stay with "media..."-based functions)
local widget = require("widget")
local C = media.newEventSound("C.mp3")
local button_C_Press = function(event)
media.playEventSound(C, button_C_Press)
end
local button_C = widget.newButton
{
defaultFile = "NewKey.png",
overFile = "NewKey2.png",
onPress = button_C_Press,
}
button_C.x = 20; button_C.y = 295
I want the piano to have 2 pedals that just switch its sound when they're pressed (I have in my project folder in total 3 different sound arragments - default and 2 pedal sustained audio files) and button that requires note letters on keys.
And here's my problem - how to get this all into one code?
I mean can you write me down there a code for one key like this sample I've posted below but including those features which I just mentioned please? I'd really love to have that solved..
Btw. I know soundTable/fileTable method, however it is called, but I think I have enough time to do each key individually - or use table method maybe - I only wish it was easy, beacuse it is my first project therefore should it be.
Sorry for my English and thanks!

You have asked for more code; I've got this recommended on Corona forums
Boolean variable:
local isPedalActive = false
And when they have touched the pedal button, then set it to true:
isPedalActive = true
And then add this to button_C_press function:
if event.phase == "began" then
if isPedalActive = true then
media.playEventSound(cPedal) --assuming you already loaded your audio above
end
end
Of course, if you have a large number of piano keys, it's better to don't do this individually for each function, rather:
Set a specific id for each key, in the widget.newButton table.
In the if statement, load the sound there but instead you would retrieve the button's id and play that mp3 file.
(that supports only one pedal)
--create table of key button ids and mp3 files for their pedal noises
local keys = {
{buttonId = "C", pedalNoise = "Cpedal.mp3"},
{buttonId = "D", pedalNoise = "Dpedal.mp3"}
}
function pianoKeys(event)
for i = 1, #keys do -- for each table in the keys table, load the sound for each key
local keySound = media.newEventSound(keys[i].buttonId .. ".mp3") -- normal sound loaded
local keypedalSound = media.newEventSound(keys[i].pedalNoise) --pedal sound loaded
function buttonPress(event) --When they press the key, detect if the pedal is active
if event.phase == "began" then
if isPedalActive == true then
media.playEventSound(keyPedalSound) --is active, play pedal sound
else
media.playEventSound(keySound) -- is not active, play regular sound
end
end
end
local pianoKey = widget.newButton({
id = keys[i].buttonId, -- place appropriate id
defaultFile = "new" .. keys[i].buttonId .. "key.png", -- place appropriate defaultFile
overFile = "new" .. keys[i].buttonId .. "key2.png", -- place appropriate overFile
onPress = buttonPress -- apply above function to each key
})
end
end
My problem - I dont't want to make sound table. I'd rather to do each key individually. Like that sample of one key's code I've posted below. But how? I dont know how to get everything into one valid thing :/ ( 2 pedals + note button)

Related

attempt to index global 'INV' (a nil value) (line:23)

print("cl_inv wurde geladen!")
concommand.Add("inv_model", function(ply)
local wep = ply:GetActiveWeapon()
if not IsValid(wep) then return end
print(wep:GetWeaponWorldModel())
end)
net.Receive("inv_init", function()
LocalPlayer().inv = {}
end)
net.Receive("inv_give", function()
local classname = net.ReadString()
table.insert(LocalPlayer().inv, classname)
end)
function INV.Open()
local ply = LocalPlayer()
local plyinv = ply.inv
if not ply.inv then return end
local scrw, scrh = ScrW(),ScrH()
INV.Menu = vgui.Create("DFrame")
local inv = INV.Menu
inv:SetSize(scrw * .4, scrh * .6)
inv:Center()
inv:SetTitle("")
inv:MakePopup()
inv.Paint = function(me,w,h)
surface.SetDrawColor(0,0,0,200)
surface.DrawRect(0,0,w,h)
end
local scroll = inv:Add("DScrollPanel")
scroll:Dock(FILL)
scroll.panels = {}
for k,v in pairs(plyinv) do
local itemPanel = scroll:Add("DPanel")
itemPanel:Dock(TOP)
scroll.panels[itemPanel] = true
end
end
hook.Add( "OnPlayerChat", "InvOpen", function( ply, strText, bTeam, bDead )
if ( ply != LocalPlayer() ) then return end
if string.lower(strText) != "!inv" then return end
INV.Open()
end )
I already searched the whole internet for a solution, i did found something but it didnt really helped me so what im expecting is that someone may be so nice and can help me solve my problem. In line 23 is the error :attempt to index global 'INV' (a nil value) (line:23)
As I can see, you're using the Garry's Mod Lua API. Although this API adds some features to the basic Lua language (e.g. ! operator for negation, C-style comments //), you still need to use the Lua language properly.
What the error says, is that you're trying to access to a table that isn't defined in the current scope of your program.
I can bet your addon defined some global table to interoperate between files and other addons installed on your machine.
As I don't have that much information on the way you're loading your file, here are multiple guesses on possible solutions:
For a file located inside an autorun folder
If the snippet you gave is under an autorun folder, the issue may be that the INV table does not yet exist when you load your file. To correct that, you can use the GLua Timer's Library.
Here is a simple snippet:
Timer.Simple(0.2, function()
-- put your code here
end
Timer.Simple takes two parameters: first one is a delay, in seconds and the other one is a callback function, executed once the delay has ended !
If you're doing something that requires the server to have loaded some other addons before actually running your script, this might be helpfull.
Accessing Global variables of your environment
As you did not gave that many informations about your problem I have to continue to guess what you're trying to do. An other source of problem is maybe that the INV table simply doesn't exist.
How to get all defined global tables in Lua ?
In Lua, there is the _G table that contains all the data of your current environnement. For more in-depth information, please see the official Lua documentation.
To know if your table does in fact exist in your environment, you can run this snippet on your Lua server:
local function doesINVExist()
for name in pairs(_G) do
if (name == "INV") then return true end
end
return false
end
And then you can simply run it using:
print(doesINVExist())
What to do if the table doesn't exist
If INV isn't present in your environment, then it may be because your Garry's Mod server did not loaded any file that defines such a table. Then what you can do is checking the addon that should dclare that table to see if there are any errors that might make it a nil value.
I hope this can help. Of course my answer could've been much more detailed if I had more information. But as I can't write comments (my rating isn't high enough), here is all I can do for you !
Have a great day,
Pedro.

Faliure of Unequipping Trigger in Roblox

function Part1()
wait(0)
script.Parent.Parent.Humanoid.WalkSpeed = 32
end
function Part2()
wait(0)
script.Parent.Parent.Humanoid.Walkspeed = 16
end
script.Parent.Equipped:Connect(Part1)
script.Parent.Unequipped:Connect(Part2)
I want to properly trigger the function Part2, which is linked to unequipping function, but it fails. The code is inside the tool I want to use. How do I do this?
Does this Tool have or need a handle?
If your Tool does not need a handle, you can make the Equipped and Unequipped events
fire without any extra setup by adding this to your LocalScript :
script.Parent.RequiresHandle = false
If your Tool does need a handle, double check that there is a Part that is a child of the Tool named "Handle".
You should get the player's Humanoid by doing:
local player = game.Players.LocalPlayer --Gets the player whos client the localscript is running on
local character = player.CharacterAdded:Wait() --The script will likely load into the game and run before the player and its character loads into the game, so we wait for the character to eventually get the humanoid from it
local humanoid = character:WaitForChild("Humanoid")
This is because when the game runs, the tools that are in StarterPlayer will clone to the player's Backpack, so you cannot do script.Parent.Parent.Humanoid.
Now, we can continue with the original script:
local player = game.Players.LocalPlayer
local character = player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
function Part1()
humanoid.WalkSpeed = 32
end
function Part2()
humanoid.WalkSpeed = 16
end
script.Parent.Equipped:Connect(Part1)
script.Parent.Unequipped:Connect(Part2)

How to remember a room has been cleared? AS3,FP

I have am new to AS3 and coding in general so this is why I am asking this question. I am trying to make a like semi-proceduraly generated dungeon crawler sort of thing like binding of isaac using flashbuilder and flashpunk.
but this has left me with a problem; I have figured out two ways to do the rooms. Either I can spawn all the rooms at once and have the players move between them using a door entity to block progress or I can load a new world that contains the room inside it and nothing else using FP.world = new world. But this gives me two problems so basically this is the main thing I want to know.
I want the world to remember what was in it and what was killed even if I enter a new world. E.g. right now if I enter a new world it will load that world up fresh and then if I kill all the enemies and leave and then re enter it will just spawn all the enemies again. I need to know how to get that room to remember it has been cleared of enemies.
Is there anyway to do this?
I'm not familiar with FP, so I cannot tell if FP allows to save room states. You better check the documentation, but if it doesn't help, you can do the following:
Find a way to get the room unique ID somehow. It could be anything - a coordinate, a number, a name, an object, etc. Just be sure it is unique. Once you have it, proceed.
The next mandatory thing you need is a way to get and set the room state. I.e. after getting state you can know that there are three goblins in a room. And setting state would be like "remove all and put these three goblins in this room". These requirements are natural as you are going to read and write the room's content anyway. Once you have it, the rest is easy.
Choose how you will keep the state. Let's say, an Object like {goblins:3, chest:1}. If you kill one goblin, it will become { goblins:2, chest:1 }. If you want to remember just the rooms that are FULLY cleared, then you simply need a boolean variable (true/false) as a state object.
You can store the state Object in a Dictionary as a key-value pair where key is the room's unique ID.
var visited_rooms:Dictionary = new Dictionary();
var roomID = ... // unique room id
var savedState:Object = { goblins:3, chest:1 } // read room state somehow
visited_rooms[roomID] = savedState;
Now, upon leaving the room, you get the state info and put it in the Dictionary.
Once you enter this room again, just check if its unique ID is present in the Dictionary and restore the state if so:
var roomID = ... // unique room id
if (roomID in visited_rooms) {
var savedState:Object = visited_rooms[roomID];
room.setState(savedState);
}
That's basically all.

Saving and Loading progress in action script 3

I've looked everywhere for this answer..but I am not quite sure on how to do it exactly...
I am making a Flash Game using Flash AS3...
I need options where user can save and load their progress..
can somebody give a step by step on how to do this please? I am very new to actionscript...
usually other tuts shows u how to save certain variables
Cookies!
Lucky us it's very simple. Unlucky us it's not obvious how it's done:
// have that referenced all the time:
var cookies: SharedObject = SharedObject.getLocal("myGameData");
// start saving
cookies.data.progress = 50;
cookies.data.lives = 5;
cookies.data.anyRandomVariable = "my name or something";
cookies.flush();
// now it's saved
// start loading
var progress: Number = cookies.data.progress;
var lives: int = cookies.data.lives = 5;
var anyRandomBlah: String = cookies.data.anyRandomVariable;
// now it's loaded
(following the comments above...)
Yes, pretty much along those lines. I was asking questions to try to get you to see that you do actually have variables/data which you'd save. =b
If you want to save in the middle of the level, it is up to you... I don't know how you've designed your game, but basically you can write the saving code to trigger whenever you want based on any conditions you want.
For saving in the middle of levels, since you are handling the saving and loading you could try having a value like level "7.5" or whatever notation you want to indicate a level that is partway done. Or just use whole numbers like 750 and treat it as a percentage (level 7 at 50% done). And so forth. It's up to you.
A very similar question has been asked how to save a current frame value using a SharedObject. In your case, replace 'current frame' with whatever values you want to save:
Actionscript 3 saving currentframe location to local hard drive?

Actionscript 3 saving currentframe location to local hard drive?

I asked similar question sometime ago, but I am making new one to be much more specific with my question with some example!
I´ve found this code snippet/tutorial from googling, but I cant seem to figure out how to modify it for my needs:
// open a local shared object called "myStuff", if there is no such object - create a new one
var savedstuff:SharedObject = SharedObject.getLocal("myStuff");
// manage buttons
btnSave.addEventListener(MouseEvent.CLICK, SaveData);
btnLoad.addEventListener(MouseEvent.CLICK, LoadData);
function SaveData(MouseEvent){
savedstuff.data.username = nameField.text // changes var username in sharedobject
savedstuff.flush(); // saves data on hard drive
}
function LoadData(MouseEvent){
if(savedstuff.size>0){ // checks if there is something saved
nameField.text = savedstuff.data.username} // change field text to username variable
}
// if something was saved before, show it on start
if(savedstuff.size>0){
nameField.text = savedstuff.data.username}
So what I am trying to figure out how to do, is to save users current frame to local hard drive, as my flash progress is based on frame location. yeah, so how do I modify it so that it stores data of current frame? and how about current frame inside movieclip, if that is makes things different?
help MUUUCH appreciated! thanks!
In your example it looks like it is already saving something to the shared object:
savedstuff.data.username = nameField.text;
Just replace it with the movie clip frame value instead (and probably under a different property name other then "username").
Then on load, there is another line where it loads the data:
nameField.text = savedstuff.data.username;
It would be the same way, except replace "username" with whatever property name you choose. Then you may have to parse into an int again and use it to restore progress however way you have it set up.