Nearest entity...

Blitz3D Forums/Blitz3D Programming/Nearest entity...

gburgess(Posted 2004) [#1]
Here's the thing.

I have lots of turrets around a map, and they each try and choose a target nearest to them. This involves running through all the targetable objects and doing an "EntityDistance" with each one.

This was slow. So, optimised it. Turrets only check for new targets every four seconds (the turrets begin with a random time offset to spread the workload). But it's still a bit on the slow side with a lot of turrets (about 10-15). And I'd like to have quite a few.

So, can anyone think of a way of optimising this further? Some alternative to EntityDistance? It doesn't need to be precise.


big10p(Posted 2004) [#2]
Couple of questions:

- How many turrets are we talking about here?
- Are turrets always placed at the same locations or are they randomly positioned?
- Are turrets stationary or can they move around?
- Do turrets have a maximum firing range?

OK, that's more than a couple. :P


gburgess(Posted 2004) [#3]
Okay...

Before I answer your questions, an addendum/errata.

Despite being called far less often, the deltayaw and deltapitch commands used for lining up the turrets seem to be eating a fair chunk of runtime too. Any suggestions here would be appreciated. :D

Here we go:

-The game starts to take a speed hit with around 10 turrets. I've stress-tested the game with 80. It was pretty slow. That's quite a lot, probably a realistic aim would be between those two figures. Turrets are made from usually three objects: a base, a rotating turret and a gun barrell that pitches up and down.

-Turrets are placed according to the mission.

-Some can move (those attached to spaceships) some are stationary (attached to the ground or space stations).

-Yes, turrets have a maximum firing range. Unfotunately, an entitydistance needs to be performed on everything to make sure it's outside that maximum range.

Thanks for the response!


SabataRH(Posted 2004) [#4]
I fail to see how 10-15 EntityDistance() calls every 4 seconds would consume any CPU time whatsoever.

But I'll throw some psuedu towards ya anyways... Break your map up into grids.. these grids can be waypoints, nodes or single pivots with a distance entity around them..

Your turrents would then only check the grids in it's location therefore not having to check every targetable mesh on the map.

ie: if targetable=turrentgridrange then ;preform check

A simple equation can be used to automatically break your worldspace into grid chunks based on max x,z... Y should'nt filter into grid locales unless you have very high stacking maps.


gburgess(Posted 2004) [#5]
It's not 10-15, though.

Each turret can target other buildings...

Oh, wait, there's one solution right there. Immobile turrets shouldn't bother checking immobile buildings. If they can't hit each other at the start, they'll never be able to. Thought I'd got rid of stupid oversights like that.

Anyway...

Each turret performs and EntityDistance on every other shootable item in the scene. So if I have 80 buildings and 10 ships in my scene, a turret attached to a ship has to do 90 checks to find the closest. Multiply by three, for three turrets on a single ship, and we have 270. Multiply by four ships and we have over 1080 Entitydistance checks.


SabataRH(Posted 2004) [#6]
Ahh i see... well if you want a quick fix you can do something like this:

Break your turrent checking code into timeslices..Ie: only check say 5 turrents per render then move on to the next 5.. This will guarentee that the game logic only uses 5 entitydistance calls per render... on the flip side you'll have less responsive turrent reactions but in reality it would probably benefit you the most as it'll break up the routine pattern and provide you with some variety.

pesudeo (cheap and nasty example):

if turrentcurrent>totalturrents then turrentcurrent=1
for t=turrentcurrent to turrentcurrent+5
..
..
..
next
turrentcurrent=turrentcurrent+5


gburgess(Posted 2004) [#7]
That's similar to what I'm already doing. Each turret has a 4 second timer which, when it expires, triggers the turret to scan for a new target. As the level is loaded, each turret's timer is set to a random offset between zero and four seconds.

But your way's actually better, since it sets a maximum number of turrets to process, and doesn't allow it to be exceeded, whereas my way is prone to "clumping" of timers expiring.


DrakeX(Posted 2004) [#8]
EntityPick()?

i'm not sure how fast it is, but supposedly it returns the nearest pickable entity.


Rob Farley(Posted 2004) [#9]
Why not grid the whole thing...

Take the entityx and z of your items, divide it by a scale (quite a big number depending on what your world scale is), and floor that number.

This will give you a low res grid of where things are.

If any of these positions are in the grid position of a turret or any of the surronding 8 squares then do the code to spin the turret or whatever.


gburgess(Posted 2004) [#10]
That's an idea, Rob. Thanks, folks, I've fused a few ideas together and things are ticking over a lot better.


big10p(Posted 2004) [#11]
I was thinking of a solution along the lines of what's already been suggested here so didn't bother replying again... until I had a thought about another way it can be achieved: use a collision sphere. :)

It might be a bit of a hacky way of doing it but it seems to work fairly well - and fast. Why do all the hard work when you can get blitz to do it?! ;)

Here's a demo:




eBusiness(Posted 2004) [#12]
big10p, I think a couple of 100 collision spheres all colliding with each other will shurely kill his framerate (havn't read your code, but I presume it's something like that you want do). For a quick cutdown on CPU useage you can replace EntityDistance(). It uses a squareroot that you can avoid, and maybe you will not bother about the y-distance:
If (x1-x2)*(x1-x2)+(z1-z2)*(z1-z2)>=maxdistance*maxdistance Then ...
Mix this with the grid that Rob Farley suggested, I'm shure that'll speed things up.


big10p(Posted 2004) [#13]

big10p, I think a couple of 100 collision spheres all colliding with each other will shurely kill his framerate (havn't read your code, but I presume it's something like that you want do).



No, that's not what I'm doing - there's only one collision sphere. As it stands, the demo searches for a new target for 1 turret per frame. I originally had it checking for every turret on every frame - it was still pretty fast but seemed like overkill. :)


eBusiness(Posted 2004) [#14]
I'm sorry to disappoint you, but normal for/next method seems to be faster:Set method to 1 for your method, and to 0 for normal distance checks.


podperson(Posted 2004) [#15]
A simple method would be to have each turret set its next scan (for closest enemy) time to a random interval in the future, which will help eliminate clumping. (Take the same approach for all costly behavior.) Or to offset the scan times of each turret when they are instanced.


big10p(Posted 2004) [#16]
lol, I'm not disappointed at all - or surprised that method is faster.

I already said that I was already thinking of doing it along the line of how Rob H. etc. had suggested. I just thought I'd present a different approach. I did say it was a bit of a hacky way of doing it, too. :)


DrakeX(Posted 2004) [#17]
did anyone see my post? or is there a reason why EntityPick is not useable here?


eBusiness(Posted 2004) [#18]
All those nifty Blitz functions are in general really slow, I don't think EntityPick is an exeption.


big10p(Posted 2004) [#19]
Plus, EntityPick only detects other entities 'ahead' of the entity you use it with. You would have to point that entity in every feasible direction to ensure it detected any entities surrounding it. :/


Andy(Posted 2004) [#20]
>Each turret performs and EntityDistance on every other
>shootable item in the scene. So if I have 80 buildings and
>10 ships in my scene, a turret attached to a ship has to
>do 90 checks to find the closest. Multiply by three, for
>three turrets on a single ship, and we have 270. Multiply
>by four ships and we have over 1080 Entitydistance checks.

How many of those checks do you expect will yield a different result than the same check did the last time? My guess is that 99% will be yielding the same result, so you should look for a way to not waste checks on those 99% every frame... Divide and conquer.

In stead of checking every turret against all targets, why not set a radius a little larger than you need for the whole ship and then check 1 ship to 1 turret every frame. If they are inside the radius, you put them on a close_to_carrier list. With 4 ships in the water, you would check 4 ship to turret checks every frame and be able to process the list for each carrier also 1 each frame without ever dropping a single frame.

Andy