Jump to content

Random Image in a Zone?


Mickey and Goofy

Recommended Posts

Does anyone have a script that I can use to make a Zone image Random?

I do know how to make a Random Number but don't know how to convert it to a set of images and use them as a Zone image. (or a Message Random image would work better.)

 

Any Help would be appreciated.

Edited by Mickey and Goofy
Link to comment

First of all, give all the images an Identifier (in urwigo you'll need to give them one, in earwigo one is generated automatically using the name), then do this Onenter():

 

(in this example we give them identifier image1-4, using 4 images)

 

require "math"
r=0
images={image1, image2, image3, image4}

r=math.random(4)
MessageBox{"Your text message"; images[r]}

 

r=0 defines a variable r and sets it to 0 (this isn't necessary but I like to do it to reset variables before executing my function)

images={image1, image2, image3, image4} defines a table with 4 values which are the identifiers of the images

r=math.random(4) makes the variable r a random number from 1 to 4 (note that we required the MATH functions to be present)

MessageBox{"Your text message"; images[r]} displays a message with a text and the r-th(random number) image from the table "images"

 

Hope this works for you :)

I'm not fully sure how you can set a zone's image but it should be similar

Link to comment

If you don't mind, I'd suggest modifying the example to this:

require "math"
local images={image1, image2, image3, image4}

local r=math.random(table.getn(images))
Wherigo.MessageBox{Text="Your text message", Media=images[r]}

The change I made allows you to just add images to the images table (the lua version of an array) and not have to worry about adjusting the rest of the code to take into account a different table size.

 

By the way, for more examples of code and randomness, you can download the source from two of my cartridges:

 

Whack-A-Lackey - Most people know of this one already. It's like a full-scale, five minute long whack-a-mole arcade game played with Lackeys and moderators on a football field. It has random zones, random times, random images, random places. The cartridge is also used to test some of the Wherigo Players, I've been proud to discover. I have several comments in the source, but didn't really make it with source code sharing in mind.

 

Battleship - This is one of my more recent play-anywhere cartridges. It emulates a game of Battleship on a football field (I use this field a lot in play-anywhere cartridges because football/soccer is the most popular sport in the world, so there's a good chance a football field is nearby). You have a limited supply of certain types of ammo. I like to think of it as the antithesis of Whack-A-Lackey because this one employs strategy, careful thought and planning, and can take as long as you want. The source code is organized and extremely well-documented. I hand-coded this from the ground up to be a better learning tool than Whack-A-Lackey. With this cartridge, I've begun creating some library (generic) code that I will carry over to future cartridges I create.

 

If you or anyone else has an idea for a fun play-anywhere cartridge along these lines, please mention it to me. If I like the idea, I'll create the cartridge. I've considered Clue, Sorry, Monopoly, etc. However, until the Wherigo API is set up and the third-party Players support cross-cartridge communication, my choices are limited to one player games (or having to keep track of where each player is in the game, forcing a hand-off of the device, and navigating the current player back to his/her current position on the game board) or adapting multi-player games to single player games as I did (quite well, I would think) with Battleship.

Link to comment

If you don't mind, I'd suggest modifying the example to this:

require "math"
local images={image1, image2, image3, image4}

local r=math.random(table.getn(images))
Wherigo.MessageBox{Text="Your text message", Media=images[r]}

The change I made allows you to just add images to the images table (the lua version of an array) and not have to worry about adjusting the rest of the code to take into account a different table size.

 

By the way, for more examples of code and randomness, you can download the source from two of my cartridges:

 

Whack-A-Lackey - Most people know of this one already. It's like a full-scale, five minute long whack-a-mole arcade game played with Lackeys and moderators on a football field. It has random zones, random times, random images, random places. The cartridge is also used to test some of the Wherigo Players, I've been proud to discover. I have several comments in the source, but didn't really make it with source code sharing in mind.

 

Battleship - This is one of my more recent play-anywhere cartridges. It emulates a game of Battleship on a football field (I use this field a lot in play-anywhere cartridges because football/soccer is the most popular sport in the world, so there's a good chance a football field is nearby). You have a limited supply of certain types of ammo. I like to think of it as the antithesis of Whack-A-Lackey because this one employs strategy, careful thought and planning, and can take as long as you want. The source code is organized and extremely well-documented. I hand-coded this from the ground up to be a better learning tool than Whack-A-Lackey. With this cartridge, I've begun creating some library (generic) code that I will carry over to future cartridges I create.

 

If you or anyone else has an idea for a fun play-anywhere cartridge along these lines, please mention it to me. If I like the idea, I'll create the cartridge. I've considered Clue, Sorry, Monopoly, etc. However, until the Wherigo API is set up and the third-party Players support cross-cartridge communication, my choices are limited to one player games (or having to keep track of where each player is in the game, forcing a hand-off of the device, and navigating the current player back to his/her current position on the game board) or adapting multi-player games to single player games as I did (quite well, I would think) with Battleship.

 

Thanks a Bunch for all the HELP! I love making cartridges with a little twist and rhe "Random" realy helps along with the good people in the fourms help.

 

A BIG THANKS!

Link to comment

Your code worked good! Is there a way that I can add a count to it?

Like with one of the images a variable will go up by one and show in the message?

 

(I have 5 images and one is bad that creats a point against the player and I would like to show the points also in the message.)

 

I do know how to do it normally Text= "the message ]].. number..[["

 

My script now is:

-- #Random Monkey image --

require "math"

local images={zmediapuzzle_msg, zmediapuzzle_msg, zmediagot_monkey, zmediapuzzle_msg, zmediapuzzle_msg}

local talk={"Go and Shake again.", "Great no Monkey!", "You just got a Monkey.", "Shake again.", "try again."}

monk = monk +1

local r=math.random(table.getn(images))

Wherigo.MessageBox{Text=talk[r]," ]] .. monk ..[[", Media=images[r]}

-- #END Random Monkey image --

This does not show "monk"? This script is just trying to show the "monk" value. When I get that working then I plan on adding an "If and" statement like "if r = You just got a Monkey then" "monk = monk +1" "end". Does this sound correct?

 

Simply I'm trying to make a program as the player goes through random zones if they collect to many random monkeys they have to start over.

P.S. The "images" and the "talk" is working great.

 

Am I asking too much now? If you want my full LUA I'll pm you it.

Lon

Edited by Mickey and Goofy
Link to comment

I can provide code later this evening (I'm replying using my cell phone), but I can provide a few comments:

 

The arrays and your count variable (especially, at the very least, your variable) should be outside any function (thus, global in scope). Lines three through five of your five line code sample should be in a function. You should also check to see if a monkey is found before incrementing your counter variable.

 

Feel free to ask for as much help as you need in this forum.

Link to comment
The arrays and your count variable (especially, at the very least, your variable) should be outside any function (thus, global in scope).

Or, you can just leave the word "local" off the declarations. :) Having things be global by default is essentially evil, but occasionally useful.

Link to comment
-- #Random Monkey image --

require "math"

local images={zmediapuzzle_msg, zmediapuzzle_msg, zmediagot_monkey, zmediapuzzle_msg, zmediapuzzle_msg}

local talk={"Go and Shake again.", "Great no Monkey!", "You just got a Monkey.", "Shake again.", "try again."}

local r=math.random(table.getn(images))

Wherigo.MessageBox{Text=talk[r]," ]] .. monk ..[[", Media=images[r]}

-- #END Random Monkey image --

 

-- #Random Monkey image --

require "math"

r=0

images={zmediapuzzle_msg, zmediapuzzle_msg, zmediagot_monkey, zmediapuzzle_msg, zmediapuzzle_msg}

talk={"Go and Shake again.", "Great no Monkey!", "You just got a Monkey.", "Shake again.", "try again."}

r=math.random(4)

Wherigo.MessageBox{Text=talk[r], Media=images[r]}

-- #END Random Monkey image --

 

I get an Error in Builder with Both scripts whether there is Local or not in it? Is this a Builder problem?

I do most of my editing with notepad++.

Link to comment
I get an Error in Builder with Both scripts whether there is Local or not in it? Is this a Builder problem?

I do most of my editing with notepad++.

Ah. It seems like the problem with reading your cartridge might not be "spontaneous corruption", but simply the limitations of the Builder.

 

Y'see, the Builder does not have a general-purpose, fully-functional Lua code parser. You can't expect to add arbitrary code and then still be able to open the cartridge, even if what you added is perfectly syntactically correct Lua code. The only place where you can add code is in the "Author Script" section (and even then, you have the issue of how to call that code).

 

I presume that Urwigo has toold to handle this. Earwigo certainly does, because it doesn't read a Lua file (except when importing from Builder); it builds the Lua file on the fly, including your Author Script code, plus it allows you to introduce arbitrary Lua statements at any point in the event handlers.

Link to comment

Here's the script I'd suggest. You'll need to break it up into different places in your code:

--Put this line at the top of your cartridge
require "math"


--Put these into your author script section:

images = {}
talk = {}
monk = 0

function cartMonkey:OnStart()    --You need to rename this based on the name of your cartridge
   images={zmediapuzzle_msg, zmediapuzzle_msg, zmediagot_monkey, zmediapuzzle_msg, zmediapuzzle_msg}
   talk={"Go and Shake again.", "Great no Monkey!", "You just got a Monkey.", "Shake again.", "try again."}
end

function RandomMonkey()
   monk = monk +1
   local r=math.random(table.getn(images))
   Wherigo.MessageBox{Text=talk[r] .. "   " .. monk, Media=images[r]}
end

As long as your code is in the author script section, Groundspeak's Builder application will not touch it. As for the above code, the cartridge's OnStart function will populate your images and talk arrays. I wasn't so sure your message's syntax was correct, so I revised that. Whenever you need to roll the proverbial dice and check for a monkey, you can call the RandomMonkey() function.

 

I'm wondering if you got an error with your scripts because you didn't have any of that inside a function block.

 

Also, here's a valuable tip (and an extreme word of caution): When I create code-heavy cartridges and need to debug them, I use the print() statement. This tells me what the variable values are and what my code is doing up to when it errors. Thus, you could use print() the following way:

function RandomMonkey()
   print("RandomMonkey called")
   monk = monk +1
   print("Number of monkeys: " .. monk)
   local r=math.random(table.getn(images))
   print("Random number chosen: " .. r)
   Wherigo.MessageBox{Text=talk[r] .. "   " .. monk, Media=images[r]}
   print("Message shown; exiting RandomMonkey")
end

Everything that goes through a print() call will show up on the second tab in the emulator. Thus, if your cartridge crashes, you'll know what all the values were up to that point--and where it crashed, if you use the print() statements correctly. Very, very helpful for the cartridges I like building.

 

Remember I said there was a word of extreme caution? Well, as far as I can tell, the print() statement is only supported in the emulator, (probably) the PDA player (does anyone use that these days?), and the Garmin Colorado. What you print() should and will, of course, be ignored in the Players. However, some Players do not handle the print() statement. I know for a fact the Garmin Oregon will power off if it encounters one and the last version of PiGo will throw a message to the player, saying the function is not supported. (Later, PiGo should ignore this.) Thus, when you finish your testing, I strongly recommend you comment out (remember: lua doesn't take well to using apostrophes in comments) or remove all print() statements.

Link to comment

Ah. The way you asked the questions led me to believe you knew about this, so I skipped over it.

 

Just so I can make sure we're on the same page: I placed the code in a function. A function is a block of code. All code within a function will not do anything (i.e. it won't be executed) until the function is called. To call a function, you type the function's name on one line, plus the parenthesis (you can pass things to functions by putting those things within the parenthesis, but we won't get into that at the moment). Thus, to call the monkey code, you type "RandomMonkey()" (minus the quotes) on one line. It is an extremely good idea to place all repetitive code within its own function so that, if the code ever needs changing, you only have to update the code in one place.

 

If you're building a cartridge with Groundspeak's Builder application, I think there's an option in the Tools menu for you to see Author Functions (if I remember correctly). If not, save what you have and open the lua file in notepad. Scroll all the way to the bottom of the file and you'll see a section titled "-- #Author Functions Go Here# --" and another titled "-- #End Author Functions# --". Insert the code I gave you between these two lines. Groundspeak's Builder does not mess with anything in this section, so whatever you write here will be safe. As for the "require "math"" section, you can either put it before anything else in Author Functions or place it at the top of the file, either below or above "require "Wherigo"".

 

As for calling the function, you can do that any time. I can't walk you through this part at the moment because I'm at work and don't have the Builder installed there.

 

Could someone please include Urwigo instructions for reference? I don't use it enough to go off memory.

 

One last thing: on occasion, I'll mistakenly refer to the "Author Functions" section as "Author Scripts". I mean the same thing.

Link to comment

Thanks Yes "Author Functions" is in the "Tools" section I do use notepad++ though.

 

Thanks for all your help. I'm new at Wherigo making but catching on at a good clip.

I have 4 published 1 I think that you would like Coin Collecting Frenzy My coding might be crude but it works. The one that I'm working on with the above code is a virtual Monkey Puzzle, I have been struggling with it for a year now but I think that I'm on the right track now.

 

Yes I used your advice and have it working now but I did have to put the require "math" in the Author Functions area under require "Wherigo" kept getting erased by Builder?

 

now I will be putting some of my modifyed coding in Author Functions.

Edited by Mickey and Goofy
Link to comment

Can you call a function within an If/And? I can't seem to make that work..

AFAIK, Groundspeak's builder provides no way to call functions. The only support way to get into Author Script code is to give an Author Script function the exact name which a Builder-generated event handler would have - for example, cartMyCart:OnStart. At that point, you renounce any possibility of constructing the cartridge "on Start" handler interactively (point and click) with the Builder. It's all or nothing.

 

Earwigo lets you:

- Write named functions interactively (ie, without using Lua)

- Write named functions in an Author Script section (using Lua)

- Call either type of function from an interactively-constructed line

- Include an arbitrary Lua statement at any point in any interactively-constructed event handler or function

 

I presume that Urwigo can do some or all of that as well.

 

The bottom line is that the Groundspeak Builder is OK either for simple cartridges, or else for very ambitious ones where in any case you'll probably be using a development environment and just pasting the Lua code into the cartridge source just before compiling. For a mixture of the two, I know that Earwigo can do it :), and the Urwigo people can presumably tell you as well.

Link to comment

I'm currently working on a cartridge which has quite a few images in it

 

512 of them are for use in a 3X3 grid (one image for each possible combination of squares filled)

 

I currently use a massive If.. else if.. else if... statement to select the correct image.

 

This would obviously be neater picking an element from an array as detailed earlier in this thread

My question is:

A: Would it be best to load array early on and pick from it as required or

B: Load the array as a local variable in a function as required.

 

I suspect that option A would be faster but more resource hungry

 

Any opinions?

 

Thanks

Mark

Link to comment

You're right in believing option B would be a bad idea. You'd be creating the entire array and tearing it down every time you called that function (that's what a local variable is, after all). As for option A, I've seen a maze cartridge around the Massachusetts/Rhode Island area (published two and a half years ago, I think) that displayed an image representing each juncture. I didn't notice too much delay when I played it with a Colorado.

 

The ideal would be to either create one image dynamically or adjust the file name of one static image, declared when the cartridge loads. I spent half an hour experimenting with this on the emulator. However, I could not get the emulator to load a random image either way. Oddly (or promisingly) enough, it did not error. It leads me to wonder if images/resources can only be read from the file system when the cartridge is first loaded (it can't be when it is instantiated because that statement precedes the media declarations and each media item needs a reference to the cartridge). Or, perhaps, there isn't support in the player application itself for creating such an object during the cartridge.

Link to comment

Maybe this will help (I haven't read through the requirement in detail).

 

Also, you might contact user "kikinoot", who has done some amazing stuff (but all in Lua) with dynamic images in a cartridge near me - you are racing against time, and it counts down with the display being updated every second with a "number" which is, in fact, a canned image corresponding to that number.

Link to comment

Also, you might contact user "kikinoot", who has done some amazing stuff (but all in Lua) with dynamic images in a cartridge near me - you are racing against time, and it counts down with the display being updated every second with a "number" which is, in fact, a canned image corresponding to that number.

 

I've done a similar thing myself to impose a time limit on reaching a zone. It works fine with my If ...else if .. else if.. structure.

 

Loading an array might be an unnecessary overhead

Is there an select case (as in VB) or switch (as in java) style structure in lua?

 

I presume that a multiple 'else if' checks every 'if' on the way through (at least until it finds a match)

Edited by Delta68
Link to comment
I presume that a multiple 'else if' checks every 'if' on the way through (at least until it finds a match)
You're absolutely right. Terribly inefficient. Have a look at this lua-users wiki page. It talks about switch statements. No, there isn't one with that syntax in lua. However, lua tables are efficient because they're hashed. You could make use of tables to create a pseudo-switch statement.
Link to comment

Hi after working on this I have things running OK but I have a simple question to finish my project.

 

I have this:

p = math.random(#allzones1); randomzone = allzones1

randomzone = allzones1

table.remove(allzones1, p

 

I need to be able to restore all that was removed in the "table.remove(allzones, p)" and be able to start over. Does anyone know how to do this?

Edited by Mickey and Goofy
Link to comment

This depends. You'll have to be more specific on your cartridge. There are three ways to do this:

  1. If the zones were created and added dynamically only to that array (lua table), you'll have to ask the cartridge for a complete list of zones, filter out the ones you don't want, and add the others back into your array. To recover from a cartridge resume, you'll have to have code that looks for your dynamically-created zones and recreates the array.
  2. If the zones were created and added dynamically, you could have two arrays: one from which you'll remove the zones as needed and another as sort of a "master" array. When you need to restore the other array, declare it as a new array again and add the zones from the master array. You'll have to do the same as the first option to recover from a cartridge resume.
  3. If you have created your zones in a builder application and not dynamically, you know which zones they are. All you'll need to do is create a function that drops all entries in your array and adds the zones back. You'll also have to call this function when the cartridge resumes (and starts for the first time to do the initial population). This option is much easier because you'll know which zones those are (out of the other zones you'll have in the cartridge) and will be able to reference those zones while you're creating the cartridge.

Link to comment

Here is what I'm working with:

 

function cartMonkeyPuzzle:OnStart() --You need to rename this based on the name of your cartridge

allzones = {zoneM1, zoneM2, zoneM3, zoneM4, zoneM5, zoneM6, zoneM7, zoneM8}

end

 

p = math.random(#allzones); randomzone = allzones[p]

randomzone = allzones[p]

table.remove(allzones, p)

 

randomzone.Visible = true

randomzone.Active = true

 

In another part of the script I'm randomly adding monkies. If a player gets to many monkies they are sent back to "Start" to try again. My problem is that the "allzones" that were "removed" create a problem where I would like the player to start over clean with "allzones" all there again like when they first started the game. (clean or empty the table?)I have tryed searching on the internet for LUA empty table info but haven't found anything that works?

 

Also Is there a good LUA book that I could get to help me with LUA?

Link to comment

It makes it easier when you know the names of your monkey zones when the cartridge starts. I'd suggest a few things. First, create a function that's safe for you to call both when the game starts, it is reset, and it is resumed. Your zones' states will persist when the cartridge is resumed, so that's a point in your favor (meaning you don't need code to set that up on start and resume). Next, you'll need a function to call to restart your game. This restart function should call the same function when the cartridge is started and restored, plus set your zones' states back to their original values (I'm assuming they're invisible and active). Thus, something like this:

function cartMonkeyPuzzle:OnStart() --You need to rename this based on the name of your cartridge
    InitializeGame()
end

function cartMonkeyPuzzle:OnRestore()
    InitializeGame()
end

function RestartGame()
    InitializeGame()
    for x=1,#allzones
         allzones[x].Active = false
         allzones[x].Visible = false
         allzones[x].Active = true
    end
end

function InitializeGame()
    allzones = {zoneM1, zoneM2, zoneM3, zoneM4, zoneM5, zoneM6, zoneM7, zoneM8}
    --Anything else you need here to set up variables that are not persisted across restores and game starts.
end

function RemoveRandomZone()
    local p = math.random(#allzones)
    local randomzone = allzones[p]
    table.remove(allzones, p)

    randomzone.Visible = true
    randomzone.Active = true
end

 

In short, you can just re-declare your array and put everything back in it.

Link to comment

Unless I take this part out Builder would not load the LUA file?

 

function RestartGame()

InitializeGame()

for x=1,#allzones

allzones[x].Active = false

allzones[x].Visible = false

allzones[x].Active = true

end

end

 

With everything else it loads...

 

Tryed calling "OnRestore()" and get an error in the emulator.

Edited by Mickey and Goofy
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...