(SOLVED) A quick way to check for targets in a radius (C#)

Started by Kilroy232, June 22, 2017, 08:19:20 PM

Previous topic - Next topic

Kilroy232

I am working on some code and I have attempted a few different methods of detecting if there are enemies withing a 3.1f radius including mimicking part of the turret code but I cannot successfully get the building to check if there are enemies around.

Does anyone happen to have a method to do this? If you would you mind pointing me in the right direction or sharing a snippet of code?

Thirite

Query the turret's Map, then request MapPawns from that. Then you can use something like FindAll (iirc) to return a collection of pawns matching the specific criteria you define.

Kilroy232

Quote from: Thirite on June 22, 2017, 09:38:54 PM
Query the turret's Map, then request MapPawns from that. Then you can use something like FindAll (iirc) to return a collection of pawns matching the specific criteria you define.

The only part of that I don't understand how to do is the first part. Would use something like, base.Map then use get MapPawns? I think I understand the rest of that though


Haplo

I'm currently not near my computer, so it may not be 100% right, but:


foreach (Pawn p in this.Map.mapPawns)
{
    float dist = GetDistanceFunction( Position, p.Position )
    if (dist <= 3.1f)
    { ... }
}


If possible try to use a distance function that doesn't need to calc squareroots though :)
( Squareroots == BAD ) ;D

I may have something in my common functions that I can give you later on..
Or there is even a distance function in RimWorld as far as I can remember?

jamaicancastle

Is there a function that quickly generates a list of cells within a radius? (There must be, to power things like the orbital trade beacon, right?) For a small radius, it might be easier to query the tiles to find pawns on top of them rather than trying to look through the full list of pawns to find close ones.

skullywag

lookup genradius and its uses in ilspy (right click analyze the method to see it uses in core). Itll give you all you need.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

Jaxxa

Quote from: jamaicancastle on June 23, 2017, 06:32:03 AM
Is there a function that quickly generates a list of cells within a radius? (There must be, to power things like the orbital trade beacon, right?) For a small radius, it might be easier to query the tiles to find pawns on top of them rather than trying to look through the full list of pawns to find close ones.

If you do it this way you can cache the cells that are in range to save calculating them every tick.

Haplo

Ok, if it's still needed, here are two functions from me that may or may not of use:
( No guarantee that they are the best to use though 8) )

        /// <summary>
        /// Checks if a cell is inside a defined radius without using Squareroots
        /// </summary>
        /// <param name="checkCell">The cell to check if its in range</param>
        /// <param name="centerOfRadius">The center cell of the radius</param>
        /// <param name="radius">The radius</param>
        /// <returns></returns>
        public static bool IsCellInRadius(IntVec3 checkCell, IntVec3 centerOfRadius, float radius)
        {
            // True when '<' means it is inside the radius
            // True when '==' means it is on the radius border
            // True when '>' means it is outside the radius

            return Mathf.Pow(checkCell.x - centerOfRadius.x, 2) + Mathf.Pow(checkCell.z - centerOfRadius.z, 2) <= Mathf.Pow(radius, 2);
        }


and


        /// <summary>
        /// Get all cells inside a defined radius (without using Squareroots)
        /// </summary>
        /// <param name="center">The center cell</param>
        /// <param name="radius">The radius</param>
        /// <returns></returns>
        public static IEnumerable<IntVec3> GetAllCellsInRadius(IntVec3 center, Map map, int radius)
        {

            for (int z = -radius; z <= radius; z++)
                for (int x = -radius; x <= radius; x++)
                {
                    IntVec3 cell = new IntVec3(center.x + x, center.y, center.z + z);
                    if ((x * x) + (z * z) <= (radius * radius) && GenGrid.InBounds(cell, map))
                        yield return cell;
                }
        }

Kilroy232

You are all best, thank you very much. I am going to try again tonight and see what I can mange. I am hoping to make something awesome

Xnope

#9
Already mentioned above, but GenRadial (one of my faves) is a great utility class to utilise. It is very efficient, and I think you should cache a List<IntVec3> of the cells to check every tick in your building's class, for efficiency. No need to fuss with IntVec3.DistanceTo(other) or IntVec3.DistanceToSquared(other). Just check each cell that you cache with something like:


foreach (var cell in this.cachedCells)
{
    if (cell.GetThingList(this.map).Any(t => t is Pawn)) // add any other checks, like IsHostileTo(Faction.OfPlayer)
    {
        // do whatever it was you wanted to do if
    }
}


BTW using GenRadial.RadialCellsAround() is probably more efficient than Haplo's method, computationally speaking, because at startup GenRadial caches a bunch of IntVec3s that make calculating radial cells a breeze.
My W.I.P. mods:
Carnivale: GitHub | Forum Post
XnopeCore: GitHub

Kilroy232

Hey guys, I just wanted to thank you again. I got my code working thanks to you guys! I hope that I will have finished the addition to my turret mod soon and then I can show you guys