Writing better code: The self taught coder

Derpspace is not abandoned but we are thinking of porting it over from the super-high-tech ASCII™ engine to the super-duper-high-tech Gamemaker™ engine. Then, after six months, we may port it over to CryEngine. It really depends on Gary Oldman’s schedule.

Just to test jsnell’s point I plugged in 1/16 (.0625) as the increment, and it worked again with the current logic. I’ll probably change it as advised to get rid of the mod operator, but it’s interesting to see the binary/decimal issue in action.

Yeah, float math is weird. It’s one of the times that understanding the numerical representation of computers actually matters I feel like everybody encounters the float == 0 error once, and then is inoculated against it.

Yeah it is fun! And all in game clocks end up being different depending on the need. I rather liked your notion of variable time increments based on footsteps. Means you can model slow terrain very easily. I like that!

But yeah floats and ==0’s usually end up with something weird. Not sure how gamemaker handles it but also watch for divide by zero. In C++ at least that is a really tough kind of bug to find.

It’s all derived from Ultima V, where player movement drives the world clock. The clockspeed varied depending on whether you were in a town or in the ‘overworld,’ but I don’t think it was ever used for terrain (except that there would be a die-roll for a ‘slow progress’ event on difficult terrain where you would simply not move at all). Interesting idea…

Oh thats neat it handles cities vs dungeons vs world as you just change the time inc per map. Yeah thats cool!

I see what you did there

You don’t say

Ah, but my avatar is from Ultima IV!

“Some people, when confronted with a problem, think, ‘I know, I’ll use floating point arithmetic’. Now they have 2.000000000000000000001 problems.”

Stolen from somewhere.

If you are thinking of working with Microsoft technologies, are looking into Dev ops, Angular or quite a few other topics and feel you could use some training, there is a tip that might be useful to you.

You likely work with Visual Studio (the community edition is free) or VS Code (free, open source, multi platform, awesome) and likely have a Microsoft account (the same kind you use for Windows, Xbox Live, …).

If so, visit this page:

https://my.visualstudio.com/

You’ll find a free 3 months trial for a site called Pluralsight.

My trial is coming to an end and I’ve gotten a lot of info from it on .net core, REST, MVC APIs, …

I don’t have much time or energy after work. But a bit of studying here and there and the fact the authors tend to answer questions have been really helpful for me.

I’m going to try and cram in some Angular training before the trial expires next week.

Check it out if you think it might be useful. Can’t argue with the price. :)

If you’ve got a few hours on your hand and want to know more than you should about floating point arithmetic, read the classic whitepaper What Every Computer Scientist Should Know About Floating-Point Arithmetic.

In general, a defensive coding technique is to always have your limits be >= rather than ==. This is especially true with floating point mathematics where compounding errors can throw things off from what you’re “expecting” if you’re not being scrupulously careful.

(Also, to be “proper” you should keep the amount you overflowed the day by and add that back into your clock, otherwise you’ll find you’re “losing” time)

ps: Is the code open source? I’d like to look at the logic involving daySwitch, because it’s screaming alarm bells at me as being a bit of wonky logic that could be much simpler. ;)

Sure. The daySwitch thing is about getting around issues that often come up with the ‘step’ event, which is that, once the condition is met, the thing happens over and over again instead of just once.

The object ‘worldClock’ contains most of the logic about nudging time/turns/hours/days around. Some of it is keyed off player movement (up/down/right/left keypresses) and some is keyed off the ‘step’ event which runs X times per second (I currently have it as 6).

When created, worldClock declares daySwitch as true:

daySwitch=true;

in its ‘step’ event, it checks to see if the conditions are met to flip over the Days counter and set hours back to 0. (I still have the modulo logic here, but will probably change it…) daySwitch becomes False so the ‘days’ counter doesn’t start ticking up on its own indefinitely.

if((global.hours mod 24 == 0) && (global.hours>0) && (daySwitch==true))
{
global.days += 1;
global.hours=0;
daySwitch=false;
}

Then, on player movement keypress (NSEW), daySwitch goes back to True so that the next time the conditions are met, Days will go up by exactly 1.

daySwitch=true;

Always happy to learn a less wonky way to do things, yet also always eager to get something to ‘just f’in work’ because I need that endorphin drip of seeing something cool happen in my game!

Yeah, this code also fails if hours is incremented enough to get over 24 before this code block runs. That could cause time to get stuck and never advance the day here. The “mod 24 == 0” is dependent on guaranteeing this day-update runs often enough relative to the hour increments to not skip past the magic hour.

But that would require the user to do 24 or more keypresses in 1/6 of a second, right? That doesn’t seem like a practical likelihood. Or do you mean something else?

I don’t know the use cases or how .hours gets updated. But it’s the kind of built in assumption which may fail in the future if you do something seemingly innocent like adjusting time of day for other reasons.

So, obviously I know nothing about your code or game design, but from your original description I would naivley expect an implementation similar to this pseudo code:

class WorldClock 
{

    /*
        Here we're using floats, so `1 hour = 1.0f` and `15 min = 0.25f`.
        The only problem with this method is that, depending on the size of
        HOURS_PER_STEP, you might accrue 'fragments' of a number, and will have
        to quantize that as some point, e.g. by rounding.
        
        You could also consider using a "scaled integer" scheme where
        all values here are 'scaled' by 100 or 1000 or whatever. 
        So `1 hours == 100` then `15 min == 25`, etc etc.
        (This is also know as n.2 fixed point, where n depends on how large your
        ints are)
        
        This would be my preferred method for keeping a long running counter,
        however hours is small and rolls over every 24, so it doesn't
        really matter. Days and turns are kept integer, as you can't
        have fractional turns (I guess??) and the subdivision of days
        is represented by the hours.
    */

    
    // HOURS_PER_STEP could actually be a variable, based on your terrain etc.
    constant float HOURS_PER_STEP = 1.0f;
    
    float hours = 0.0f;
    
    int days = 0;
    
    // turns might actually be stored in your "game" class
    int turns = 0;    
    
    // this is called from the code that processes user input events,
    // can also be named: playerStepped(), takeTurn(), increaseTurns(), nextTurn()
    // etc etc etc. Depends how else you use it.
    public tickTurn()
    {
        this.turns += 1;
        increaseHours(HOURS_PER_STEP)
    }

    private increaseHours(float numHours)
    {
        hours += numHours;
        if (hours >= 24.0f) 
        {
            hours = (hours - 24.0f);
            if (hours >= 24.0f)
            {
                log.warning(
                    "You're adding too many hours at a time! " +
                    "It's causing the days to skip. Hours = {}".format(hours)
                );
            }
            days += 1;
        }
    }
}


class GameOrPossiblyInYourPlayerClassOrWhatever
{
    handleInput(keyPressed) {
        enum DIRECTION direction = null;
        switch (keyPressed) {
            case 'W': direction = DIRECTION.UP; break;
            case 'A': direction = DIRECTION.LEFT; break;
            case 'S': direction = DIRECTION.DOWN; break;
            case 'D': direction = DIRECTION.RIGHT; break;
            default: 
                // do nothing. or issue a warning. or handle other keys etc.
                break;
        }
        movePlayer(direction);
    }
    
    movePlayer(DIRECTION direction) {
        //
        // manipulate your world position here
        //
        // etc
        
        WorldClock.tickTurn()
    }
}

There shouldn’t be any problem here with it happening multiple times etc – it should only go off each time the user moves the character.

But then you’ve also added this:

The object ‘worldClock’ contains most of the logic about nudging time/turns/hours/days around. Some of it is keyed off player movement (up/down/right/left keypresses) and some is keyed off the ‘step’ event which runs X times per second (I currently have it as 6).

What’s this step event and why is it running X times per second? Your original description made it sound like this was a turn-based game with time only counting up when the player moves.

If you’re connecting components of your game via an event system (which is a good idea) then you would expect movePlayer to “emit” a “player moved event” to the rest of the game, and the clock picks that up in it’s event handler and calls tickTurn(). But this shouldn’t keep going off, as there’s only ever a single “player moved event” for each movement of the player.

Could you explain more about the step event which runs X times per second? e.g. what it is, what it’s used for, what problem you were solving with it etc?

+1 to @Pod’s solution. It’s broadly similar to the approach I’ve taken in the past, and it means you have less chance of unexpected bugs if you should sometime in future find a need to have a game event add multiple hours, or other weird stuff.

If you are doing a turn-based game (i.e., performance is not that important) and keeping accurate track of time is, I would consider simply leveraging a Calendar/Date/Time library of your chosen programming language.

I just found that pseudo code in an notepad++ tab. So now I’m curious to how it went, @Gordon_Cameron . Did you manage to fix your dodgy day counter?

I’ve just left it where the hour increments by something that can be expressed both rationally and in binary … .0625, I think. I doubt that’s the permanent solution; more elegant ones were proposed upthread.

My current solution has another issue, that if you press keys too quickly (hours tick off turns which tick off player movement), the day doesn’t turn over at 24 hours and then you are trapped in a time warp forever. I’m not super concerned about that one, but it will have to be dealt with.

I’m currently obsessed with Ultima 3-style line of sight. I thought about trying to implement flood-fill line of sight but I like this style better; it’s just more evocative to me. My current code casts a cone of darkness beyond the first obstruction in each cardinal direction, and also casts darkness beyond adjacent obstructions, but the diagonals aren’t fully covered. I’m even making a Gamemaker replica of Ultima III’s Sosaria (called ‘fauxsaria’) so that I can compare the line of sight at any position.

Here’s an example of my version not quite getting it done.