Jump to content

From Scratch Timers


Ranger Fox

Recommended Posts

I have been trying to create a timer object from scratch. After the object is created, I store it in a global table. The OnStart event fires, but the OnTick event does not. The following is a code snippet. The table "timers" is instantiated (globally) outside the function I populate the table. The function in which this resides is called by an action from the player and is not executed when the cartridge loads.

 

		for x=1,numTimers do
	local t = Wherigo.ZTimer{
		Name = "Timer " .. x,
		Description = "Timer " .. x,
		Visible = true,
		Duration = math.random(minTimerSeconds,maxTimerSeconds),
		Type = "Countdown",
	}

	t.OnTick = function()
		--TimerTickEvent(t, x)
		Wherigo.MessageBox{Text="Timer ticked",}
	end

	t.OnStart = function()
		Wherigo.MessageBox{Text="Timer started",}
	end

	table.insert(timers, t)
end

for x=1,numTimers do
	timers[x]:Start()
end

 

I have two workarounds, but would not like to use them. One workaround is to have a set number of timers instantiated as the cartridge loads and just use a switch statement to choose amongst them. The other is to have a timer firing in one second intervals, executing code I have lined up in a filmstrip fashion. Neither option would be good for extensibility and they're not good programming practice, either.

Link to comment

I have been trying to create a timer object from scratch. After the object is created, I store it in a global table. The OnStart event fires, but the OnTick event does not. The following is a code snippet. The table "timers" is instantiated (globally) outside the function I populate the table. The function in which this resides is called by an action from the player and is not executed when the cartridge loads.

 

		for x=1,numTimers do
	local t = Wherigo.ZTimer{
		Name = "Timer " .. x,
		Description = "Timer " .. x,
		Visible = true,
		Duration = math.random(minTimerSeconds,maxTimerSeconds),
		Type = "Countdown",
	}

	t.OnTick = function()
		--TimerTickEvent(t, x)
		Wherigo.MessageBox{Text="Timer ticked",}
	end

	t.OnStart = function()
		Wherigo.MessageBox{Text="Timer started",}
	end

	table.insert(timers, t)
end

for x=1,numTimers do
	timers[x]:Start()
end

 

I have two workarounds, but would not like to use them. One workaround is to have a set number of timers instantiated as the cartridge loads and just use a switch statement to choose amongst them. The other is to have a timer firing in one second intervals, executing code I have lined up in a filmstrip fashion. Neither option would be good for extensibility and they're not good programming practice, either.

I think a countdown timer gets a stop event, try that. Actually, so do duration timers, they actually start-stop-start

 

David

Link to comment

Nope. The builder has problems parsing the additional code (yes, the code is in the author section), so I can't even open the file.

 

I added the following code and a message box to see if the event was called:

	t.OnStop = function()
		Wherigo.MessageBox{Text="stop",}
	end

 

The timer tick events still did not fire. I even tried reordering how the events were added. Negative on that one.

 

The lua log wasn't much help, either. I saw the start events, but not the stop ones:

Wed May 07 19:12:19 2008 CARTRIDGE [Lua]: 36.07465|-79.79510|0.000|1.000|ZTimer:Stop - Timer 1

Wed May 07 19:12:19 2008 CARTRIDGE [Lua]: 36.07465|-79.79510|0.000|1.000|MessageBox:Show - stop

Wed May 07 19:11:20 2008 CARTRIDGE [Lua]: 36.07465|-79.79510|0.000|1.000|ZTimer:Start - Timer 2

Wed May 07 19:11:20 2008 CARTRIDGE [Lua]: 36.07465|-79.79510|0.000|1.000|ZTimer:Start - Timer 1

 

From the department of creativity, I created a timer the normal way and to its OnTick event I added the timer table iteration code to trigger those timers' Start function calls. The theory was that I needed to wait a second for the code to process and reference everything. No love there. As you could see from the above message log, the timers did in fact start (the logs were from this experiment).

 

I even reassigned the Visible, Duration, and Type properties outside the instantiation code in addition to the inside.

 

I was curious, so I even replaced the "t.OnTick" assignment code with "t.OnTick = ztimerGameTimer.OnTick", which is a reference to a timer I created through the builder. I hoped I could hold a reference to ztimerGameTimer in the "t" timer's OnTick event. Nothing there.

 

There are only so many ways I can come up with to do the same thing. I think I'm running out of ideas.

 

Should I send you the source? I'd rather not post it to the forums yet because I don't want an incomplete version floating around. I am at the point, though, where I need this to work before I can go on to something else.

 

Also on my list of problems is that the code won't work with the current non-beta Colorado software. I'll try updating to the beta version before asking what features my code depends on that have not been added to the Colorado's player.

 

Sheesh. I get the feeling I'm pushing the player too far with all the hand-coding I'm doing. But we're programmers and we like to do that sort of thing with our toys, right?

Link to comment

I notice that when the builder creates a timer, (what I assume is) the constructor has a single argument which refers to the cartridge itself. I would not be surprised to find that the constructor adds the timer instance to a list of timers maintained at the cartridge level. It is possible that only timers in the list are incremented and otherwise processed on the hardware timer tick. All I see in your code fragment is initialization of various properties of the instance -- no call to the constructor. If the code fragement is all the initialization there is, you may want to try calling the constructor, then initializing the other properties.

 

I also notice that the timer, like other objects, has a GUID ID assigned by the builder. I have no idea what this is used for, or whether or not it is important. But I notice your code fails to set it as well.

 

Let us all know how it turns out.

Edited by twolpert
Link to comment

That did it, twolpert. I needed a reference to the cartridge.

 

The following is the completed code. Since I mentioned Whack-A-Mole in another post, I'll show you the actual code I'm using, copy and paste. The alreadySetUp variable prevents new objects from being created when ones still exist. Technically, I don't need OnStop, but I keep it in anyway.

	for x=1,numMoles do
	--for x=1,table.getn(moleZones) do	  --nah; keep it consistent between zone and timer creation

	local t 
	if alreadySetUp == true then
		t = moleTimers[x]
	else
		t = Wherigo.ZTimer{
			Cartridge = cartWhackAMole,
			Name = "Mole " .. x,
			Description = "Mole " .. x .. " Timer",
			Visible = true,
			Duration = math.random(minTimerSeconds,maxTimerSeconds),
			Type = "Countdown",
		}
	end

	t.OnStop = function()
	end

	--Time up; move the mole
	t.OnTick = function()
		MoleTimerTick(x)
	end

	--When starting the timer, determine if the mole is hidden for this round
	t.OnStart = function()
		local y = math.random(0,100)
		moleZones[x].Active = y > 40
		moleZones[x].Visible = y > 40
	end

	if alreadySetUp == false then
		table.insert(moleTimers, t)
	end

end


--Time to begin the timers.  This is in its own loop so all timers start as close together as possible.
for x=1,numMoles do
	moleTimers[x]:Start()
end

Link to comment

I forgot to mention. You don't have to use the "new" keyword to instantiate new instances of Wherigo library objects. I guess that's how constructors go for the Wherigo library. Well, at least for timer and zone objects, that is.

 

You also don't need the ID keyword to make it work. I wonder if adding an ID will allow the object state to saved when the user saves the cartridge?

Link to comment

I forgot to mention. You don't have to use the "new" keyword to instantiate new instances of Wherigo library objects. I guess that's how constructors go for the Wherigo library. Well, at least for timer and zone objects, that is.

 

You also don't need the ID keyword to make it work. I wonder if adding an ID will allow the object state to saved when the user saves the cartridge?

The ID is used for the builder. But, if everything is in the author scripting section then it doesn't matter. Does the cartridge open in the builder at all?

 

David

Link to comment
The ID is used for the builder. But, if everything is in the author scripting section then it doesn't matter. Does the cartridge open in the builder at all?

The builder opens the cartridge and plays nicely with everything. In fact, I can add things through the builder, save the lua file, and open it in notepad to move what the builder wrote to the author section if I need to modify it further. I've been having a lot of success with that method. I like the hand-coding method as it's easier to do wild stuff.

 

I have not needed to add anything for the ID attribute. Even without adding an ID, the player application will pick up on my new zones and store their state with the saved game. However, the array (I think they call it a "table" in lua) that keeps the object references is not stored with the saved game. If I wanted to store it, I guess I could add it to the list of builder variables. However...

 

I'm concerned, though, because the builder might not understand array objects and, therefore, the code that saves the cartridge's state might not save the array properly. To get around this, I suppose I could always recreate the array based on object names (they're all zones beginning with the same name) when the cartridge is run again. If I don't do that and the user saves and opens the cartridge repeatedly, I'll end up with 20 or more inactive zones.

 

Though I have the cartridge more or less in a complete state, there's a lot of cleaning up and niceties to build. By the way, is there a way to nullify or unload an object, such as a zone?

 

Edit:

By the way, did you know that I can't use the apostrophe in my comments? The builder doesn't like that and will refuse to open the cartridge code until I remove the offending apostrophe.

Edited by Ranger Fox
Link to comment
The ID is used for the builder. But, if everything is in the author scripting section then it doesn't matter. Does the cartridge open in the builder at all?

The builder opens the cartridge and plays nicely with everything. In fact, I can add things through the builder, save the lua file, and open it in notepad to move what the builder wrote to the author section if I need to modify it further. I've been having a lot of success with that method. I like the hand-coding method as it's easier to do wild stuff.

 

I have not needed to add anything for the ID attribute. Even without adding an ID, the player application will pick up on my new zones and store their state with the saved game. However, the array (I think they call it a "table" in lua) that keeps the object references is not stored with the saved game. If I wanted to store it, I guess I could add it to the list of builder variables. However...

 

I'm concerned, though, because the builder might not understand array objects and, therefore, the code that saves the cartridge's state might not save the array properly. To get around this, I suppose I could always recreate the array based on object names (they're all zones beginning with the same name) when the cartridge is run again. If I don't do that and the user saves and opens the cartridge repeatedly, I'll end up with 20 or more inactive zones.

 

Though I have the cartridge more or less in a complete state, there's a lot of cleaning up and niceties to build. By the way, is there a way to nullify or unload an object, such as a zone?

 

Edit:

By the way, did you know that I can't use the apostrophe in my comments? The builder doesn't like that and will refuse to open the cartridge code until I remove the offending apostrophe.

You can set an object to nil in lua and that essentially deletes it:

 

Nil is a type with a single value, nil, whose main property is to be different from any other value. As we have seen, a global variable has a nil value by default, before a first assignment, and you can assign nil to a global variable to delete it. Lua uses nil as a kind of non-value, to represent the absence of a useful value.

 

The comment issue is a lua thing. The first thing that happens when the builder opens a cart is a lua "dofile". This validates the lua file as a valid lua object (parses it with the lua dofile command). If that works, then the builder manually parses the function statements. So, an apostrophe in a comment hoses the dofile.

 

David.

Edited by davidloew
Link to comment

So, an apostrophe in a comment hoses the dofile.

 

That would seem to be a pretty big bug in dofile. :blink: Is it on some Lua known bug list? I understand that the code has to know if it's in a string or not before it can decide to reject the stuff between -- and end-of-line, but this isn't parser rocket surgery. I wonder if the same problem affects multiline ( --[[ .. --]] ) comments?

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...