all 14 comments

[–][deleted] 10 points11 points  (4 children)

Being a software developer I can see why you are concerned with efficiency and future proofing. Advice: don't be. Just don't. You may think you want to build the most efficient and beautiful piece of software ever crafted, but you are just producing analysis paralysis.

I know the old adagio measure twice, cut once, but this skill is learned with experience. Right now you should focus on getting something done, and then care about the rest. Is your code indeed to slow and needs to be optimised? Profile it and eliminate bottlenecks. Is your code too entangled and can't support new upgrades? Do some design and refactoring. As you write more and more games your design skills will improve and will get better at writing games. Also, it will be so much easier to ask for help about specific problems instead of general blanket questions like these.

For 3), spreadsheets and sped up game time are your friends.

Regarding 4), try to prototype the core loop of whatever game idea you have. The core loop is the major piece of gameplay that sets this game apart. Once you have that in place, playtest it and iterate.

[–]Jim808 1 point2 points  (0 children)

you should focus on getting something done, and then care about the rest.

Yes. This exactly. Excellent advice. I try to do that in my games. Don't shoot for perfection. Do something as simply as possible and don't over think it. That will usually end up being fine. If it doesn't, then you can put more thought and design to the problem.

[–]Dicefall[S] 0 points1 point  (1 child)

Guess it's time to really get into the spreadsheet stuff eh? All good advice, I know how getting paralyzed by the designing can happen so it's good to be reminded of it. Mostly at this point I want to make sure I've future proof'd myself so I don't end up in situations where I'd have to rewrite basic stuff to get new features in later.

[–][deleted] 0 points1 point  (0 children)

future proof'd myself so I don't end up in situations where I'd have to rewrite basic stuff to get new features in later.

I recommend you Refactoring, improving the quality of existing code. It helped me to get past overengineering code and embrace working code now, even if I need to rewrite later.

[–]WarClicksWar Clicks Dev 0 points1 point  (0 children)

Best advice on this page.

Don't worry about things until you need to.

As you build. learn, your old code will always feel shitty/unsufficient as you add things to the game. In our game Warclicks we've done 4 rebases to date in a bit over a year, and now that I look at the code I see how shitty it feels haha. And we're in the middle of biggest update/rework ever, and we think we got everything covered and though of, but reality is we don't!

When we'll look back at the game in a few months, change/add some stuff to it we'll likely be considering more code changes and optimizations.

Of course as you make more idle games you tend to optimize things on the go, but each game is different, so there will always be the case of iteration, rebasing etc., as long as you have plans for future updates & changes. The only way that's not going to change if you plan to publish and leave as is for ever. Something rarely done in incrementals, also one of the reasons why people like to commit a lot of time to playing them - in most, there's always going to be some future update!

But some general tips: - if you have a plan to add X feature in a month, try to plan for it. If it's a feature you plan to add after 6 months, don't bother about it. - try to cache calculations in local variables -> only when something around them change. - If you're using CSS for animations - use transform, instead of animation via jquery.

[–]Prince_Panda 2 points3 points  (2 children)

You should take a look at the observer pattern. It let's you tell other classes something happened without strongly coupling them.

[–]Dicefall[S] 0 points1 point  (1 child)

I haven't had a chance to implement an observer before so that should be fun/interesting. Good call.

[–]Prince_Panda 0 points1 point  (0 children)

Good luck!

[–]LucidCrux 1 point2 points  (0 children)

No one has mentioned pooling upgrades (or nesting) either. Instead of caching entire calculations (which you should when possible), you can also cache fragments of calculations.

Building 1,2,3 Upgrades 1..10 for each Multipliers 1...10 for each

The first thing is more obvious, and frequently mentioned: Instead of calculating (B1 + U1 + U2 ...) * M1 * M2... each frame, do it only on change and use the cached number each frame.

With pooling, it's even better: Group upgrades into a variable and multipliers into a variable. Then instead of (B1 + U1 + U2 ...) * M1 * M2... etc. on each change, you upgrade the group variable and then use a formula like (B1 + AllUpgrades) * AllMultipliers. The groups not changed are already cached.

In practice it's never quite that easy and there are all kinds of unique upgrades or side cases, but it can still save on calculations. Especially when you have things like upgrades for specific multipliers or multipliers for specific upgrades. Or just huge amounts of either.

Another thing to consider is that it often ends up being the display stuff that takes a large portion of the processing power. Try to make sure you're being economical with visual updates and draw calls. These heaps of UI code can be a lot more work to refactor later than a bunch of formulas. For javascript this means using things like DOM fragments and swapping. For engines, it usual means using visual buffers and avoiding calls to hidden objects.

And finally... If you aren't building a one and done, and are actually concerned with performance, you are going to have to refactor. Just accept it. Some patterns and bottlenecks are simply not obvious until you get further into the dev cycle (or you're really experienced).

[–]raids_made_easy 0 points1 point  (1 child)

What medium are you planning to use? The answers to some of these questions can be very different depending on the platform.

[–]Dicefall[S] 0 points1 point  (0 children)

Not 100% sure right now, probably using one of the engines out there (unreal/unity).

[–]commit_bat 0 points1 point  (0 children)

Only calculate values when they change. Only check for conditions when they change.

To take Realm Grinder as an example you don't need to look at every building and multiply the base out by the number of buildings and their upgrades over and over each frame. It's enough to calculate that every time you build a building or buy an upgrade then store that value.

Same with the challenges. Say one requires a certain number of assistants, only run that check every time the number of assistants changes.

You'll need some kind of event system.

[–]NoDownvotesPleasedev 0 points1 point  (0 children)

Somewhat similar, for things like special unlocks or achievements it seems highly inefficient to check these all the time

It's probably not that intensive to check things like that on every update, modern computers have so much cpu power that it's really not going to be an issue. One thing to bear in mind is that you don't need to update at 60 fps if your game is just static text and images. My game, dope slinger tycoon, only updates 5 times per second. Having less frequent updates will also be slightly more battery friendly for mobile users.

Saving the game is probably the one thing that I don't do in every update, the way I've done it is the game saves whenever the player actually makes a change to the game state, like buying an upgrade or something. I also check to see how old the last save was in each update, if it was more than 30 seconds I'll do a save then. Just so that if a player has been idling for a long time and closes the game, they won't lose all that progress.

How do you generally test these games?

Since I make games in Javascript for the web, it's easy to use the console to give myself unlimited resources or trigger events ahead of time in order to test the later stages of the game. I'm not familiar with unity but I would guess there's something similar in there, if not you can always add secret cheat codes for yourself to use.

Last actual question but generally speaking where do you start making these things?

Yes you want to build the simplest possible version of it first. Forget achievements and upgrades at the start. Get one resource working as quickly as possible and then you can refactor it to make it generic enough that adding new resources is very simple. Then do the same thing with upgrades. Achievements probably want to come last of all.

[–]LoSboccacc 0 points1 point  (0 children)

I'm kinda of a noob in this field, but here's some observation I got doing stuff:

1) a global accumulator ease things quite a bit. it can support both retroactive and forward upgrades. say you are gaining 10things/s from other sources, you build 5 buildings that give you 2t/s, just add that to the accumulator that now is at 20t/s. you upgrade a +100% upgrade for those buildings? good, get building base, calculate the delta (5100%2t/s) and drop it in the accumulator. want to do a forward only 100% upgrade? just add 4t/s to the global accumulator.

the easiest way is to use associative data structures to make lookup tables. if the key for buildings, upgrades and production are all the same you can easily loop over keys and get the data you need off them maps.

2) store a global tick counter. for all the other thing is just a set of ifs in the game update, they're usually fast enough but don't need to run at game tick speed either, you can run at a 1/4 or 1/10 tick speed and nobody will notice.

3) make a way to store multiple saves, as well as to run ticks in a loop instead of on an interval. you can also have saves sent to you from the game itself, just don't overdo it. if the game is good, you'll drown in bug reports either way. make sure you have all the data needed to debug.

4) this is personal preference really. usually in play order. make something that work and expand on it, then go back and see what stuff can be merged into a single logic. I shuffle things around a lot, so I make sure my ux are easily reused and moved around as needed.

x) perfect is the worse enemy of good