Help me decide about gameplay...

Help me decide about gameplay…

Read before voting please:

For a long time now I’ve been making an RPG game with pretty complex gameplay elements.
These require quite a lot of processing, and at times it can be a bit of a speedbump.
Lately I’ve found a way to put some of these processes in to the background (with threading) so they can be performed while the game is still running, without causing any locking or lag. The problem is that when python uses an extra thread it takes at least double the amount of time to complete the process (in this case actually nearly 4 times longer!).

I want to know, from a gaming point of view, which is better, a 1 second wait with everything locked up so it seems as if the game might have crashed, or a 4 second wait with everything still running, but having an animation showing “calculating…” or whatever?

Some things to consider:

  • Because of the nature of python, using extra threads doesn’t actually improve speed. But it does stop the game from locking up or slowing down too much.
  • If the levels get really big, or there are a huge number of enemies, this calculation time could go up to as much as 10 seconds…
  • The game doesn’t always freeze during heavy calculations, but could drop to <10 frames per second.
  • It may be possible to reduce calculation time “a little” but I’ve already done a lot of work in this area and further methods to cut calculation time would result in a much less capable AI.
  • With threading you would still be able to carry out some actions during the AI turn, such as reading diary entries, checking your inventory, or getting mouseover information about enemies or allies.
  • Some longer processes could be threaded, while shorter ones happen almost instantly.

Threading will run “more slowly” than running the code in the same thread, if the application is already CPU bound. Threads are mainly useful for waiting on IO, which can just block independently of the main application. Waiting on IO is doing nothing, whilst waiting for an expensive subroutine to finish is still using CPU. In this case, multiprocessing is a better idea. This, unlike threading (which is GIL bound), spawns new processes, and can therefore make use of additional cores.

Your question really depends on what you’re doing, both in the type of task you’re using (again, expensive or idle blocking), and what it means to the game. However, generally I would advise avoiding blocking in the game because later additions become tricky (imaging later deciding to animate the loading screen, which isn’t possible if the render thread is blocked).

Gamers tend to prefer framerate over time-costs (although using multiprocessing can significantly eliminate the need to choose). They could be planning their turns, etc. Futhermore, AI routines taking time gives them more realism than instant reactions.

A bit longer wait time without locking would be nice.

If you don’t use multiprocess you could simplify your code using yield generator.
Threads aren’t as nice to handle.

But sockets seem to be the solution.
Either popen a python or java (or c++) external process.

I have had great success with both.

Thanks, I actually looked in to multiprocessing but it seems not to work at all well with windows/blender.

Multiprocessing usually uses an if name = main check, to make sure the new process isn’t the same as the old one, but in blender name isnt main, it’s watever the module or script is. When I tried it what happened was an infinite number of instances of blender were opened and my computer crashed. After some googling this seems to be a windows + blender problem that no one was able to overcome.

p.s one of the things I’m threading is building a graph for navigation by getting info from some meshes. It has to happen first thing when the level starts and is generated. With multi threading I can have an introductory animation or in game tips or something for a few seconds while the graph builds. Another thing that needs doing is creating a tactical map at the start of the AI turn. It only takes a couple of seconds but that seems better than having the framerate nose dive every time the AI turn starts.

I looked at your socket solution as well though it seemed a bit more complex. I’ll take another look and see how it compares.

Well, sockets are just one communication layer with another process. Queues and Shared Memory can be used in multiprocessing

Yield generators are useful as a platform for non-blocking coroutines, but you have to implement all of the logic in an appropriate manner (all IO operations must not block, or can only be called when we know that they won’t block). However, most game logic benefits from the more well defined game loop (rather than general coroutines) and is processor intensive, rather than IO bound.

I vote that keeping the game running and having a “calculating…” or “loading…” indicator is better than the game stuttering or freezing.

But I’m not sure if that is really a viable solution since most games go to lengths to minimize or greatly limit “loading screens”. Many gamers don’t tolerate loading screens now-a-days.

Technical suggestions

  • I’m not sure what these calculations are, but leveraging the GPU to do highly parallel computations might be an option for you and it might be possible to shoe-horn it into a shader and stay fully in Python if you can use a render-to-texture to reasonably get the data out.

  • Another option is to write your logic as a C or C++ module. A tight, CPU-intensive loop can easily be 100x faster in C/C++ than in Python. On top of that C/C++ code can spawn threads that are not blocked by the GIL and do run on other cores in the system.

Both of those really depend on the data you are operating on. If you rely on a lot of Blender objects then getting the data off to a GPU or into C/C++ can be a deal breaker.

Hi! I vote for a long time without freeze but maybe if you use another pathfinding algo (another than simple A*), you would not have those freezes. Here you can test multiple algos:https://qiao.github.io/PathFinding.js/visual/ and here: https://github.com/qiao/PathFinding.js/ are the algos (in java…). If you tried implementing jump point search (as I did, but you’re a better coder), I’m sure you’ll fall in love with this super algo :slight_smile: (And you could put it in a thread if you want…)

It is possible to get the multiprocessing module working with Blender as I’ve used it in a few projects. If you want, I can see if I can put together a simple example.

A few other suggestions:

Optimize your code if possible. 1 second sounds like a fairly long time to be calculating. A few simple improvements in code efficiency can go a long way, especially if they’re inside long loops. You could also consider using something like Cython which compiles Python code into C code to give you a large performance speedup.

As others have said, you can use generators to split up your computation over multiple frames. See if you can start your calculations earlier so they will have completed by the time you need them. Alternatively, you could see if it’s possible to split them up into multiple steps and perform each step as soon as it’s ready while you continue calculating the next step.

I didn’t mean to suggest to use multiprocess, as it is even more tedious to get working.
Just that because of GIL threads are not much different than generators, just that generators are safer/cleaner.

A simple socket chat programm is similar to multiprocessing.
But it probably can’t help you loop over mesh data, as you have to have the graph built and sent.
From a crash in multiprocessing I think saw that it actually uses sockets to (fake) share memory.
Not sure, but there is that…

@kastoria
From a simple comparison I did last week I can say that given a 10^6 loop for pathfinding:
Python took 50 sec , java 1.5-3.5 sec and c++ 1-2 sec .
I would suggest sticking with java as it easier to code. (even though I personally don’t like java)

Also, @Mobious, about “Cython which compiles Python code into C”, how to do it?

Not really. It is frustrating trying to figure out how to get it to work, but once you know what you need to do, it’s fairly quick and easy to setup.

You can find out pretty much everything you’ll need do know from the Cython documentation. It may take a day or two to learn to use it, but it’s a very useful tool to have when it comes to performance sensitive code.

why not ‘Roll’ complex instuctions ? (so every frame only X units proccess?)

have a command script, and a ‘Do’ script,

command is much more instensive then do, do just follows the plan command thinks up?

so every frame, you only command 5 units, and the rest of the time they are ‘doing’?

You end up having to write carefully not block the game, and work over frames. Instead, it’s often far simpler to assume you can block, write the code naively, and dump the results into the main game process when complete.

It also isn’t as useful if you’re doing something like pathfinding, which is just slow full stop.

Not sure if anyone suggested it, but if you’re looking at seconds-long waits to do pathfinding, it sounds like you might want to rethink how and when pathfinding is calculated. A couple of suggestions would be:

  1. If you have large areas, then rather than pathfinding across the entire game scene, you can pathfind on a “macro” level. For example, split up your game world into 20x20x20 BU “areas”. If you want to pathfind in a single, small area, go ahead and calculate it. If you want to pathfind over a larger area that spans more than one “area”, though, you could pathfind from the current area to the target area, and from the current position in the current area to the nearest “exit” to the next area. Once you reach the end of the current area, it can go from there to pathfind to the next exit. This way, you don’t really have to pathfind all that much to actually get from place to place.

  2. Share pathfindings. Once you find a single path, it probably will be valid for other nearby entities for a period of time as well. For example, if you have 4 bats adjacent to each other and you need them all to navigate toward the player, you could pathfind for one bat and copy and share that pathfinding result to the others. The only difference would be that they would need to navigate to the starting position, but otherwise, the path would basically be identical.

  3. Do gradual pathfinding. Just making it so that pathfinding is done over a maximum of a few iterations per game frame per NPC could help. Basically, you’d rather have a 60 FPS game with enemies that take 1 second to “think” than a 60 FPS game that drops to 10 FPS when enemies “think”.

You could also set up a priority value that indicates that certain objects get more pathfinding time (i.e. the player and nearby enemies).

  1. Fake it. Assume that objects that are far away, off-screen, and “unknown” to the player advance at a solid clip per unit of time, and individual hazards and the floor plan doesn’t actually influence the movement of the enemy. Alternatively, this actually could be done with #1’s macro pathfinding. You wouldn’t use pathfinding to navigate around the floor plan, but rather macro pathfinding to find the path from the starting area to the destination area . Once you’ve got that, the NPC can just travel through those areas slowly until they’re close enough to warrant actual pathfinding.

These are just a few ideas.

I voted for the long wait with loading animation because that’s the standard in UI design (I think it has to do with the fact that the user perceives motion as something that is working), assuming it happens only at the start of the level.
If the same procedure has to be repeated during the level then you should really find a way to avoid the delay entirely, dropping the feature if necessary.

Isn’t that all a bit off-topic?
I mean you are looking for advice what direction to go, rather to detail how to go into this direction.

As a gamer … I want a totally fluent and entertaining game without any lags, download time, repetitions and distracting things (like menus, popups, ads etc.) … and I want to earn real money while playing … (even when I’m not playing), so I can play all day.

You see you will not be able to satisfy the gamer in me. Luckily all the other games I played reduced my expectations quite a lot. (So I do not expect to earn money, but hope to spend as less as possible.)

I’m also used to the fact that starting the application takes some time without any feed back (sometimes an annoying “over all windows splash screen” appears, so I can’t do anything else in the meantime). Finally I end up in a boring menu (some games present them very nice) without playing.

So no problem to do that exactly the same.

Then I (hopefully) find the option “start game now”. Yeah … still waiting?

So no problem to do that exactly the same.

Now I’m in the game. It plays fluently, without nasty lags … until I reach the end of he level.

Here the games differ. Some games blend to cut scenes, others blend to other levels and some others let you run through without noticing there was a border. Typically any transition is pretty short and does not break the event flow.

Obviously the last one is the nicest. But is it really? I mean running around freely is nice, but your game wants to tell a story. Why not have an entertaining cut-scene from time to time. This does not only support the story it supports level switching to … combine them. But the same relies … the transitions should be pretty fast.

So I think it depends on what you want to do. I’m pretty sure you will end up with a combination of both, loading and streaming.

Finally the technical restrictions will dictate what you will do.

I say
… focus on your game idea
… use restrictions as features
… make it entertaining (rather than accurate)

Haha,that is funny.P

Actually, the pathfinding is not the problem, it’s setting up the level ready for efficient pathfinding which is a problem. If I was using hand designed levels I would pre-calculate the graph but with randomly generated levels that’s not really an option.

All the games I played when I was younger had long waiting times during the enemy turn. Games like Civilization could rack up 5 minutes on a large map. I got used to it. Likewise when playing RPGs like NeverWinter Nights you had to expect at least half a minute for loading the level from the HDD. It wasn’t a problem for me.

But… I haven’t played a modern game since STALKER: Shadow of Chernobyl, so I don’t know what people today expect from a game.
I know a lot of games are player vs player, multiplayer games so they don’t have any AI.

Even back in the day, AI wasn’t that great. If you go back to the first Resident Evil, the AI was basically a track to actuator. The original Civilization game had such a bad AI that it had to cheat. System shock 2, despite being an awesome game had some shockingly bad AI in places. By jumping up on to a table you could leave the navmesh and in effect become invisible to any monsters.

Do you think people will be prepared to wait a couple of seconds for the AI to do some thinking, if it results in a more interesting game?

It does not matter. You are a one man show. Caring to much will care your game to death.

If I am too nosey, ignore this,
but as this is quite interesting topic,
could you post some metrics about the graph building?
Like the average worst case graph size and type of check each node does(collision/raycast/dictionary).

Maybe a example map? Picture?
Having hard time imagining the situation.
Random maps most of the time aren’t “random”, they just place known elements in unknown ways.
Maps created from tiles( rooms ) or blocks are easy to graph.