Why isn't my clock keeping the right time?

I’m trying to make an in-game clock for my day/night cycle, for easy testing I’ve been trying to make it take 60 seconds for a full day to pass. I’m working in Game-Days-Per-Minute for ease of use, then converting it to game-seconds-per-second for ease of calculation:

void UCalendar::WorldTimeConversion(){
	if (DayInMinutes != 0){
	int32 dayInSeconds = DayInMinutes * 60;
	gameSecondsPerWorldSecond = 86400 / dayInSeconds;
	}
	else{
		gameSecondsPerWorldSecond = 1;
	}
}

Once gameSecondsPerWorldSecond has been set, I run a really rudimentary clock every tick based on deltatime:

void UCalendar::AdvanceClock(float DeltaTime){

	tallySecond += DeltaTime;
	if (tallySecond>=1){
		tallySecond -= 1;
		clockSecond += gameSecondsPerWorldSecond;
		if (clockSecond >= 60){
			float tallyMinute=0;
			while (clockSecond>60){
				clockSecond -= 60;
				tallyMinute++;
			}
			clockMinute += tallyMinute;
			if (clockMinute > 60){
				clockMinute -= 60;
				clockHour += 1;
				if (clockHour > 23){
					clockHour = 0;
				}
			}
		}
	}
}

This looks right to me, but the timing doesn’t work out: if I set DayInMinutes to 1, it takes approximately three real-world seconds for one in-game minute to pass, which only works out to 20 game minutes per minute, not 1440. Is there an obvious cludge-up with my logic, or is deltatime not what I want to be using to run my clock?

I don’t think your tallySecond is doing what you want, but you’re doing this in a way more complicated way than is probably necessary.

Just do something like this (not tested but something similar should work):

inGameTime += gameSecondsPerWorldSecond * DeltaTime;
clockSecond =(int)totalTime % 60;
clockMinute = (int)(totalTime - clockSecond) %60;
clockHour = (int)(totalTime - clockSecond - clockMinute * 60) % 24;

Ooh, that is significantly cleaner than my guy- what is the function of the % operand? It’s giving me an error, “left operand has type float”.

It’s the modulo operator. It pretty much gives you the remainder of a division operation. The error is my bad since 60 and 24 are ints not floats. Try switching to 60.0f and 24.0f.

I lied, I forgot modulus only works the way you want it to here on int types. So cast your floats to ints and then mod them.

Hmm okay, does this look right to you? It compiles cleanly, but everything starts at 0 and never advances:

void UCalendar::AdvanceClock(float DeltaTime){
	int tempSecond = clockSecond;
	int tempMinute = clockMinute;
	int tempHour = clockHour;
	int tempTime = totalTime;

	inGameTime += gameSecondsPerWorldSecond * DeltaTime;
	clockSecond = tempTime % 60;
	clockMinute = (tempTime - tempSecond) % 60;
	clockHour = (tempTime - tempSecond - tempMinute * 60) % 24;
}

I tried it with casting instead of using temporary variables, but for some reason it doesn’t like it when I do something like:

Cast<int32>(totalTime)

Cast() is an unreal cast for unreal objects like UObject or AActor or anything else that uses Unreal’s reflection system. You want to use a C style cast like this (int)totalTime.

You shouldn’t need your clockSecond/Minute/Hour to be anything other than ints, so you don’t need all your temps.

The inGameTime should probably be a float or a double too (float’s probably fine).

Try this:

void UCalendar::AdvanceClock(float DeltaTime){
     inGameTime += gameSecondsPerWorldSecond * DeltaTime;
     int gameTimeSeconds = (int)inGameTime;
     clockSecond = gameTimeSeconds % 60;
     clockMinute = (gameTimeSeconds - clockSecond) % 60;
     clockHour = (gameTimeSeconds - clockSecond - clockMinute * 60) % 24;
 }

and then define your inGameTime as a float and all the clockSecond/Minute/Hour as ints. I’m not sure why it’s 0 without seeing more code. have you tried putting a breakpoint in there to see what it’s doing?

Ooh, thank you for the heads-up about casting, I didn’t even know that C-style casts worked in ue. :slight_smile:

I think the all-zero thing was a weirdness in my original logic, as it’s gone away with implementing yours, but it’s still a bit weird. I yanked out everything except for the bare bones, shifted some of the stuff that didn’t need floating-point accuracy to ints, and ran it with this:

//Variable decs in the .h
int32 clockSecond=0;
int32 clockMinute=0;
int32 clockHour=0;
float inGameTime;
float totalTime;
//timekeeping function that runs every ComponentTick:

void UCalendar::AdvanceClock(float DeltaTime){
	inGameTime += gameSecondsPerWorldSecond * DeltaTime;
	int32 gameTimeSeconds = (int32)inGameTime;
	clockSecond = gameTimeSeconds % 60;
	clockMinute = (gameTimeSeconds - clockSecond) % 60;
	clockHour = (gameTimeSeconds - clockSecond - clockMinute * 60) % 24;
}

Clock second increments correctly, climbing from 0-60 at the prescribed rate and then resetting, but something weird happens with the minutes and hours: clockMinute always remains 0, and every time clockSecond goes from 60-0, clockHour will flip-flop between 0, and 12.

Oh Crap. Sorry I forgot a very important part.

void UCalendar::AdvanceClock(float DeltaTime){
     inGameTime += gameSecondsPerWorldSecond * DeltaTime;
     int32 gameTimeSeconds = (int32)inGameTime;
     clockSecond = gameTimeSeconds % 60;
     clockMinute = ((gameTimeSeconds - clockSecond) / 60) % 60;
     clockHour = ((gameTimeSeconds - clockSecond - clockMinute * 60) / 60) % 24;
 }

Forgot to divide by 60 for the seconds->minutes and the minutes->hours.