It ain't easy making a high-performance game. I want to cry

Well, I dreamed of a game so immersive you could fight like movie characters fight, with lots of units, with complex character building, and so on. One aspect I need is a high-performance simulation of the game world.

Making a high-performance game engine IS really difficult. I want to cry.

Now, imagine I want to have some units fighting.

struct Unit
    health::Float64
    attack::Float64
    #Bla bla bla...
end

function attack!(x::Unit,y::Unit)
    y.health -= x.attack
    #Bla bla bla... maybe calculate death and so on.
end

Now, if I have a mod that adds armor.

function attack!(x::Unit,y::Unit)
    attack = x.attack
    #Calculate armor.
    attack -= attack*max(y.armor-x.armor_penetration,0)
    y.health -= attack
    #Bla bla bla... maybe calculate death and so on.
end

But now, a new field has been added! How do I infer what field do units use?
And if I have TWO mods. Let’s say the second mod adds a morale system.

function attack!(x::Unit,y::Unit)
    y.health -= x.attack
    #Bla bla bla... maybe calculate death and so on.
end

Now, if I have a mod that adds armor.

function attack!(x::Unit,y::Unit)
    attack = x.attack
    #Calculate armor.
    attack -= attack*max(y.armor-x.armor_penetration,0)
    y.health -= attack
    #Bla bla bla... maybe calculate death and so on.
end

Wrong.

function attack!(x::Unit,y::Unit)
    attack = x.attack
    attack *= morale(x)/max_morale(x)
    y.health -= attack
    #Bla bla bla... maybe calculate death and so on.
end

Right.

function attack!(x::Unit,y::Unit)
    attack = x.attack
    attack *= morale(x)/max_morale(x)
    attack -= attack*max(y.armor-x.armor_penetration,0)
    y.health -= attack
    #Bla bla bla... maybe calculate death and so on.
end

So, when I add mods, I can’t just replace the code! I need to put them together!
And now, these suddenly add armor, armor penetration, morale system, etc… which means the attributes would have to change! But what attributes? Using a dictionary to store attributes wouldn’t be efficient. Ideally, you would have the compiler infer what attributes the “units” use. This could be implemented in multiple ways, for example, to have each mod explicitly specify what attributes there are, or to trace from usage seen in functions, which I find a bit better since you might have one mod that adds multiple systems for other mods and you might not use all of them.
But the pipeline is not over! Now, imagine I want to add an efficient element system, or maybe a union of unit types or something. Let’s implement these as binary traits.

struct Unit
    elements::UInt64
    #bla bla bla.
end

For example, if your attack does double damage to enemies with certain elements, half damage to enemies with certain elements, and so on…
you could do…

if has_fire_element(unit)
damage *= 2
end

But… get a lot of these and it gets slow.
You could actually do this.
damage *= damage_multiplier[begin+((unit.element&mask)*magic)>>shift]
How do you actually find the magic number and magic table? Well, perfect hashing brute force search precomputed.
But now, imagine this optimization where the elements and effects came from different mods.
And to push the limit of computation, you need this!
So, I need a compiler system that can compose mods by loading them together, infer the attributes needed, and then figure out the memory layout of those attributes and how to efficiently compute effects based on those attributes!

And that was just the attribute system!

And this was just the attribute system! I have yet to touch the pathfinding, rendering, other GPU programming, AI, light system, sound system, physics system, etc!

I want to cry.

Video games are some of the most complicated software stacks in the world. Making even a very simple video game from scratch is probably better thought of as a life-long project, not a quick couple of afternoons unless you’re just wanting to make tic-tac-toe.

If this is something you really want to do, I’d encourage you to keep it up, but if you’re already this upset, I think that’s a serious sign of misaligned expectations.

It’s probably best to think of this project as a way to teach yourself about programming and various ideas in game design. Focus on the journey, not the destination, because if we’re being honest, it’s very unlikely you’ll make it to the destination you appear to have in mind.

But that’s okay! Unfinished projects can still be very rewarding, so long as you enjoyed the process.

To quote your own words:

It ain’t easy being greedy!

12 Likes

Perhaps the fastest way to learn is by copying the work of the best. In the HTML source of this page, you’ll see that Steven De Keninck uses math (e.g., miniPGA: mini Projective Geometric Algebra) to go down the rabbit hole of high-performance simulation.

Oh, I made Tetris. (Well, using pygame anyway)
And I know I could’ve “cheated” with dictionaries but that wouldn’t cut it in my future games where there are millions of units, lots of effects/etc. Many games have less-performant modding API or they actually make their entire game not very performant, and these are actually good game developers, mind you. However, when I want to do the right thing with mods delivering a modding API that can somehow be composed together in a single game with performance as much as if they were hard-coded and optimized, hell broke loose.

… and maybe use a blog to document it. Yes, the Offtopic category is fairly permissive and there are no strict rules because historically people have not to abused it, but many of your recent posts @Tarny_GG_Channie would be more appropriate for a personal blog.

6 Likes

What blog? You mean my own personal journal offline or something?

I don’t think I’m abusing the category. I’m not posting about my experience gambling at a casino or something. I’m posting about my struggle with my journey into the Julia… which is related to the language itself, but does not exactly belong anywhere else so it piles up here.

There are thousands of people visiting this forum every day. If all of them posted random, loosely related off-topic posts every day about their current hopes, dreams, and daily frustrations, the signal-to-noise ratio in this forum would fall off a cliff.

Personally, I don’t think there’s much wrong with off-topic posts like this one, but the frequency of such posts should probably be kept in check. I agree with Tamas that a personal blog wherever you feel like hosting it might be a better place for things like this if you feel the need to post them often.

8 Likes

No, a personal blog, online. See https://www.juliabloggers.com/

2 Likes

You have a point. To be fair. I don’t quite have an idea what this forum is about really. What it tells me is that you should follow basic etiquette like no slurs and so on and the forum is for Julia users/enthusiasts posting “something” related to it. I have no idea what constitutes a good post here actually, is it like an announcement of some cursed package I published? ([ANN] Arceus.jl Efficient runtime trait library) Is it a post that generates engagement with lots of people joining? Lately I’m starting to feel the answer is getting closer to no. What’s the optimal number of reply. Is it a good idea to discuss the theoretical possibility of doing something with Julia? Or should the topic be grounded in something more concrete? Is there even a right answer to this question?

Definitely not. We’re not monetizing views or clicks here, so optimizing for things like “engagement” doesn’t really benefit anyone, unless people feel that “engagement” was actually time well spent.

There are many examples of very high engagement threads on this forum that were engaging only because the thread made people angry and argumentative. Relevant XKCD: xkcd: Duty Calls

5 Likes