How to create an in-game clock?

Started by , Thu 22/09/2005 17:32:27

Previous topic - Next topic

m0ds

Hi all, I have a small technical issue for a little game I'm working on. Somehow, I need to display an "in-game" clock that changes frequently, but not in real time. What I mean by this is that one minute passing in real time would equate to about 10 minutes passing in the game.

The clock would only display hours and minutes, HH:MM - no seconds or anything. Now, I've had a little toy around to see what I can do but I'm not getting very far! Failing at the first hurdle which is attempting to produce clock numbers in a label. I presume this would run by a timer, and some how printing a numercial value as a string. But how exactly I do that I'm not sure. The clock will also be a key element to trigger random events.

The clock should cycle 24 hours, though if anyone has any suggestions on how I could make it always start from 7am and end at 11pm, that would be great. If anyone has any ideas about how to code this (or if you KNOW the code!) then I'd be really greatful :)

Also, this game needs a background artist who can draw to detail, the backgrounds consisting of 10 or so cinema related locations (auditorium, foyer, office). If you could help or know someone who might please PM me :) If not it's fine, this won't hault the production of the game at all - because I can always revert to using photos.

Thanks again!!

:)
m0ds

GarageGothic

#1
Edit 3: I updated the code with the fixes suggested by Ashen and SteveMcCrea. Thanks guys

This should be a simple Repeatedly_Execute function.

Since you want 1 minute real time = 10 minutes game time, it should be 10 times faster. Thus 6 real seconds equals 60 seconds (1 minute) of game time. As the default speed of AGS is 40 cycles per second, a game minute equals 40x6=240 cycles. To match possible other game speed settings, we'll do GetGameSpeed()x6 instead.


at top of global script:

Code: ags
int cyclecounter;
int minute;
int hour;
int ampm; //are we in the A.M. or P.M.


in repeatedly_execute (you might want to put this within other conditionals such as (if IsGamePaused() == 0)):

Code: ags

cyclecounter++;
if (cyclecounter >= (GetGameSpeed()*6)) {
Ã,  cyclecounter = 0;
Ã,  minute++;
Ã,  if (minute >= 60) {
Ã,  Ã,  minute = 0;
Ã,  Ã,  hour++;
Ã,  Ã,  if ((hour > 12) && (ampm == 0)) { //if past 12am
Ã,  Ã,  Ã,  hour = 1;
Ã,  Ã,  Ã,  ampm = 1;
Ã,  Ã,  Ã,  }
Ã,  Ã,  else if ((hour > 12) && (ampm == 1)) { //if past 12pm
Ã,  Ã,  Ã,  hour = 1;
Ã,  Ã,  Ã,  ampm = 0;
Ã,  Ã,  Ã,  }
Ã,  Ã, string timelabeltext;
   StrCopy(timelabeltext, "The time is: %02d:%02d", hour, minute);
Ã,  Ã, if (ampm == 0) StrCat(timelabeltext, " AM");
Ã,  Ã, else StrCat(timelabeltext, " PM");
Ã,  Ã, lblTimeDisplay.SetText(timelabeltext);
Ã,  Ã, }


Edit: I added the time display code now. Not sure if it will work since I haven't been using the new String functions myself yet.

Edit2: You should be able to check/set the variables hour, minute and ampm from other parts of the script to trigger events and decide what time to start it at.

Kweepa

He said 1 minute (real) == 10 minutes (game), i.e. 6 seconds == 1 minute, so I'd change the ">= 400" to ">= 6*GetGameSpeed()".
Still waiting for Purity of the Surf II

GarageGothic

#3
Quote from: SteveMcCrea on Thu 22/09/2005 23:12:12
He said 1 minute (real) == 10 minutes (game), i.e. 6 seconds == 1 minute, so I'd change the ">= 400" to ">= 6*GetGameSpeed()".

Sorry, I read it as 10 minutes = 1 hour (not sure that my calculation was even correct for that). And yeah yeah, I know that you should use GetGameSpeed() but why add to the confusion :)

Well spotted!

m0ds

GarageGothic, thanks for your help! I'm getting an error at line 26 saying an ; is expected, but I've put one in and it didn't seem to help it. Any suggestions?

Ashen

Which is line 26?

Is it:
Code: ags

hour = hour++:


And if so, did you just add the ; or did you also get rid of the : ? (Obvious, I know.)
I know what you're thinking ... Don't think that.

GarageGothic

Quote from: m0ds on Fri 23/09/2005 00:10:05
GarageGothic, thanks for your help! I'm getting an error at line 26 saying an ; is expected, but I've put one in and it didn't seem to help it. Any suggestions?

Which one is line 26?

Edit: Ah yes, thanks for spotting the typo Ashen!

m0ds

I deleted the : so its hour++;

BTW, im using version 70 not 71, if that makes any difference?

Ashen

#8
Try just hour++; (instead of hour = hour++;)

Not sure, but because you're using '++' instead of '+1', I don't think you need the hour =. Didn't spot that before.

EDIT: OK, just tried it (also 2.70, so no new String format) and shortening it to hour ++; should work. I think the engine looks at it as two seperate statements ('hour = x' and 'hour ++'), so expects a ; in the middle. Or something.

I'm assuming that is line 26, yes, as I got the same error when I tried it.
I know what you're thinking ... Don't think that.

GarageGothic

True Ashen. So have we established that hour++ is line 26?

m0ds

Thanks! That cleared that problem, but now it says line 35;

Cannot assign value to string, use StrCopy.

Quotestring timelabeltext = string.Format("The time is: %02d:%02d", hour, minute);

??

GarageGothic

Ok, that is a 2.70 thing I think. When were new Strings fully implemented? It shouldn't be hard to change it to old style strings.

Ashen

OK, I wrote this as GG was posting, and I'm gonna post it anyway:

My guess (just confirmed) is that the code was written to use the new String property, which you don't got (I think it's only in 2.71 betas 3+). Try changing it (and any other string.Format / string.Append commands) back to the 'old' style, e.g.:
Code: ags

string timelabeltext;
StrFormat (timelabeltext, "The time is: %02d:%02d", hour, minute);
I know what you're thinking ... Don't think that.

GarageGothic

Ok, redid the string code with old style strings. I didn't have the old manual here so I couldn't check, but I believe that StrCat is the right command to append text.

Ashen

#14
You need to use:
Code: ags

StrFormat(timelabeltext, "The time is: %02d:%02d", hour, minute);

since StrCopy can't handle the extra parameters.

Also, there's a closing brace missing between the closing one for else if ((hour > 12) && (ampm == 1)) { //if past 12pm and string timelabeltext; (around line 35, I think).

Also also - you've got the AM/PM change happening as it moves from 12 - 1, instead of 11 - 12.
The code should probably look more like:
Code: ags

  cyclecounter++;
  if (cyclecounter >= (GetGameSpeed()*6)) {
    cyclecounter = 0;
    minute++;
    if (minute >= 60) {
      minute = 0;
      hour++;
      if (hour == 12) {
        if (ampm == 1) ampm=0;
        else ampm=1;
      }
      else if (hour > 12) {
        hour = 1;
      }
    }
    string timelabeltext;
    StrFormat(timelabeltext, "%02d:%02d", hour, minute);
    if (ampm == 0) StrCat(timelabeltext, " AM");
    else if (ampm == 1) StrCat(timelabeltext, " PM");
    lblStat.SetText(timelabeltext);
  }


Finally, on a purely aesthetic note, you might want to put the AM/PM tag on a seperate label - it bounces back and forth a few pixels as the numbers change, which looks a bit odd. (Although admittedly it was more obvious to me, as I had it running a lot faster than is needed.)
I know what you're thinking ... Don't think that.

GarageGothic

I'll let Ashen take it from here - I think this thread should serve as an example to people that you shouldn't try to help out with code unless you're actually able to test it yourself before posting it :)

m0ds

Thanks Ashen! That works a treat :) I may need a way of also displaying the day, month and year, but that's not essential right now. The code you've written works well so thanks for figuring that out :)

now i go make!

Ashen

QuoteI'll let Ashen take it from here

Then, if I may ...
Quote
if anyone has any suggestions on how I could make it always start from 7am and end at 11pm, that would be great

(I'm assuming you want to put some sort of cutscene/titlecard up at 11pm, e.g. to mark the end of a day.)

Create another int, isclockrunning. This'll be used to check, well, whether the clock should run. Declare it as = 2 (int isclockrunning = 2;), so it doesn't start  too soon. Set it to 1 at the end of whatever intro scene you have, or when going from the menu screen into the game. While you're at it, declare hour as 7 (int hour = 7;), so the clock starts set to the right time.

Put all of the rep_ex code inside an if (isclockrunning == 1) { condition, and modify it slightly:
Code: ags

if (isclockrunning == 1) {
  cyclecounter++;
  if (cyclecounter >= (GetGameSpeed()*6)) {
    cyclecounter = 0;
    minute++;
    if (minute >= 60) {
      minute = 0;
      hour++;
      if (hour == 12) {
        if (ampm == 1) ampm=0;
        else ampm=1;
        // Although, the 'ampm==0' bit is a tad redundant, as the clock will never be shown passing midnight.
      }
      else if (hour > 12) {
        hour = 1;
      }
      else if (hour == 11 && ampm == 1) { // If it's 11PM
        isclockrunning = 0; // Stop the clock
      }
    }
    string timelabeltext;
    StrFormat(timelabeltext, "%02d:%02d", hour, minute);
    if (ampm == 0) StrCat(timelabeltext, " AM");
    else if (ampm == 1) StrCat(timelabeltext, " PM");
    lblStat.SetText(timelabeltext);
  }
} // End of 'if (isclockrunning == 1)'


Next, add an if (isclockrunning == 0) condition:
Code: ags

if (isclockrunning == 0) {
  // Whatever you want to happen at 11pm.
  // You might want to add another int, to count which day it is and vary events accordingly.
  // This next bit is the key:
  hour = 7;
  minute = 0;
  ampm = 0; // Set clock to 07:00 AM
  isclockrunning = 1; // And restart it.
} // End of 'if (isclockrunning == 0)'


This should work in the abstract - as in it does what I expected it to, but I'm only guessing at what you want it for. If it doesn't work for you, or if I haven't explained something very well, just let me know.

As for day, month & year, they're just a case of adding more ints, and and setting/displaying them in the same way.
I know what you're thinking ... Don't think that.

m0ds

Sorry, old thread, thought it'd be as simple as just re-inserting the code you once gave me.

For some reason the label in gui 0 (named 'timez') is not displaying the time, I can't figure the hell out why. If I call a SetText and make it "whatever I want" elsewhere in rep ex it sets the text, but not via the code below. Any ideas why? using 2.72.

Code: ags

int cyclecounter;
int minute;
int hour;
int ampm; //are we in the A.M. or P.M.

cyclecounter++;
  if (cyclecounter >= (GetGameSpeed()*6)) {
    cyclecounter = 0;
    minute++;
    if (minute >= 60) {
      minute = 0;
      hour++;
      if (hour == 12) {
        if (ampm == 1) ampm=0;
        else ampm=1;
      }
      else if (hour > 12) {
        hour = 1;
      }
    }
    string grrr;
StrFormat (grrr, "The time is: %02d:%02d", hour, minute);

    if (ampm == 0)  StrCat(grrr, " AM");
       
    
    else if (ampm == 1)  StrCat(grrr, " PM");
    timez.SetText(grrr);    
    
}


Cheers!

tzachs

Did you by chance make this part:
Code: ags

int cyclecounter;
int minute;
int hour;
int ampm; //are we in the A.M. or P.M.

a part of the function?

They (the variable declerations) have to be outside of the function, otherwise they will be set to zero on each new run of the function and the first if will never return true...

SMF spam blocked by CleanTalk