/// <summary> /// Handles the starship's targeting. /// </summary> protected override void OnUpdate() { // Note that we need to pass the quadrant system structure to WithReadOnly(). This is because other systems are // reading from it in parallel and we need to ensure the safety system that we will not modify the memory. var quadrantHashMap = QuadrantSystem.QuadrantHashMap; Entities.WithReadOnly(quadrantHashMap).WithAll <SpaceshipTag>().ForEach( (Entity entity, ref TargetingComponent target, in Translation pos, in TeamComponent team, in BoidComponent boid) => { var hashMapKey = QuadrantSystem.HashKeyFromPosition(pos.Value); // Search neighboring quadrants if the currently locked target is still in range, // or find a new closest enemy target var minDistance = float.MaxValue; var closestEntity = target.TargetEntity; var closestPos = target.TargetPosition; var newTargetFound = false; if (SearchQuadrantNeighbors(in quadrantHashMap, hashMapKey, entity, target.TargetingRadius, pos.Value, team.Team, target.TargetLocked, target.TargetEntity, ref minDistance, ref closestEntity, ref closestPos, ref newTargetFound)) { return; // Currently locked target still in range } if (newTargetFound) { target.TargetPosition = closestPos; target.TargetEntity = closestEntity; target.TargetLocked = true; } else { target.TargetLocked = false; } }).ScheduleParallel();
public void Execute(Entity e, int jobIndex, ref Translation translation, ref VelocityComponent velocity, [ReadOnly] ref ProjectileComponent projectile) { if (translation.Value.y < 0.15f) { // find all the entities in the nearby quad and destroy it if within the radius int key = QuadrantSystem.GetPositionHashMapKey(translation.Value); if (QuadMap.TryGetFirstValue(key, out var data, out var it)) { do { float distance = distancesq(data.position, translation.Value); if (data.quadEntityData.type == QuadEntityType.Cavalry) { continue; } if (distance < projectile.DamageRadius) { CommandBuffer.DestroyEntity(jobIndex, data.e); } } while (QuadMap.TryGetNextValue(out data, ref it)); } CommandBuffer.DestroyEntity(jobIndex, e); } // apply gravity velocity.Value.y += -0.0098f * projectile.Weight; velocity.Value.y = clamp(velocity.Value.y, -10f, 100f); // apply air resistance velocity.Value.z += projectile.AirResistance * -0.0001f; velocity.Value.z = clamp(velocity.Value.z, 0.5f, 100f); translation.Value += velocity.Value * deltaTime; }
private void OnDrawGizmos() { var camera = Camera.main; var cameraPosition = camera.transform.position; var camHeight = camera.orthographicSize; var camWidth = camHeight * camera.aspect; var maxX = cameraPosition.x + camWidth; var minX = cameraPosition.x - camWidth; var maxY = cameraPosition.y + camHeight; var minY = cameraPosition.y - camHeight; var xStep = QuadrantSystem.quadrantSize; var yStep = QuadrantSystem.quadrantSize; for (float x = minX; x < maxX; x += xStep) { for (float y = minY; y < maxY; y += yStep) { QuadrantSystem.DrawQuadrant(new Unity.Mathematics.float3(x, y, 0), Color.black); } } var mousePos = Utils.GetMouseWorldPosition(camera); QuadrantSystem.DrawQuadrant(mousePos.ToF3(), Color.red); }
protected override void OnUpdate() { Entities.ForEach((Entity entity, ref Translation translation, ref Rotation rotation, ref ProjectileData projectileData) => { // Update position: float3 forwardVector = math.mul(rotation.Value, new float3(0, -1, 0)); translation.Value += forwardVector * projectileData.SpeedMultiplier * Time.deltaTime; // Update life time: projectileData.LifeTime += Time.deltaTime; if (projectileData.LifeTime >= projectileData.MaxLifeTime) { PostUpdateCommands.DestroyEntity(entity); return; } // Destroy if collided with asteroid and update the score (use more quadrant cells for better collision precision): int hashMapKey = QuadrantSystem.GetQuadrantHashMapKey(translation.Value); QuadrantSystem.QuadrantEntityData[] quadrantData = new QuadrantSystem.QuadrantEntityData[9]; bool[] isCollision = new bool[9]; isCollision[0] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[0]); isCollision[1] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey + 1, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[1]); isCollision[2] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey - 1, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[2]); isCollision[3] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey + QuadrantSystem.QuadrantYMultiplier, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[3]); isCollision[4] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey - QuadrantSystem.QuadrantYMultiplier, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[4]); isCollision[5] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey + 1 + QuadrantSystem.QuadrantYMultiplier, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[5]); isCollision[6] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey - 1 + QuadrantSystem.QuadrantYMultiplier, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[6]); isCollision[7] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey + 1 - QuadrantSystem.QuadrantYMultiplier, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[7]); isCollision[8] = AsteroidsSystem.IsCollisionWithAsteroid(hashMapKey - 1 - QuadrantSystem.QuadrantYMultiplier, entity, entity.Index, translation, QuadrantSystem.QuadrantAsteroidsMultiHashMap, out quadrantData[8]); for (int i = 0; i < isCollision.Length; i++) { if (isCollision[i]) { if (entity != Entity.Null) { PostUpdateCommands.DestroyEntity(entity); } if (quadrantData[i].entity != Entity.Null) { PostUpdateCommands.DestroyEntity(quadrantData[i].entity); } ShipSystem.Score++; UI.UpdateScore(ShipSystem.Score); break; } } }); }
public void Execute(Entity e, int jobIndex, ref Translation translation, ref WidthComponent width) { int hashKey = QuadrantSystem.GetPositionHashMapKey(translation.Value); BlockMap.Add(hashKey, new BlockerData { entity = e, position = translation.Value, width = width.Value }); }
public void Execute([ReadOnly] ref Translation translation, ref TargetComponent target, [ReadOnly] ref QuadrantEntityComponent entityQuadInfo) { float3 entityPosition = translation.Value; // if the entity is so far off the map, it doesn't even need to search for anything if (entityPosition.z > 80 || entityPosition.z < -200) { return; } float closestDistance = 1000f; int hashKey = QuadrantSystem.GetPositionHashMapKey(entityPosition); if (EntityHashMap.TryGetFirstValue(hashKey, out var quadData, out var it)) { do { if (((ushort)(quadData.quadEntityData.type) & target.targetMask) == 0) { continue; } float3 otherUnitLoc = quadData.position; // only care to find a target that is in the approximate same lane if (abs(otherUnitLoc.x - entityPosition.x) > 25f) { continue; } // check distance after float currentDis = distancesq(entityPosition, otherUnitLoc); // if the distance is closer then the minimum, it found the necessary target, // use that cavalry unit as the target immediately if (closestDistance > currentDis) { if ((ushort)(entityQuadInfo.type & QuadEntityType.Cavalry) != 0) { // if this is a cavalry unit make the entity targeted so that other cavalry units can't take it } closestDistance = currentDis; target.entity = quadData.e; target.location = otherUnitLoc; } } while (EntityHashMap.TryGetNextValue(out quadData, ref it)); } if (closestDistance > 999f) { target.entity = Entity.Null; } }
public void Execute(Entity entity, int index, ref Translation translation, ref PhysicsCollider collider, ref CollisionData collisionData) { int hashMapKey = QuadrantSystem.GetPositionHashMapKey(translation.Value); CheckCollisions(hashMapKey, index, ref entity, ref translation, ref collider, ref collisionData); CheckCollisions(hashMapKey + 1, index, ref entity, ref translation, ref collider, ref collisionData); CheckCollisions(hashMapKey - 1, index, ref entity, ref translation, ref collider, ref collisionData); CheckCollisions(hashMapKey + QuadrantSystem.quadrantYMultiplier, index, ref entity, ref translation, ref collider, ref collisionData); CheckCollisions(hashMapKey - QuadrantSystem.quadrantYMultiplier, index, ref entity, ref translation, ref collider, ref collisionData); CheckCollisions(hashMapKey + 1 + QuadrantSystem.quadrantYMultiplier, index, ref entity, ref translation, ref collider, ref collisionData); CheckCollisions(hashMapKey - 1 + QuadrantSystem.quadrantYMultiplier, index, ref entity, ref translation, ref collider, ref collisionData); CheckCollisions(hashMapKey + 1 - QuadrantSystem.quadrantYMultiplier, index, ref entity, ref translation, ref collider, ref collisionData); CheckCollisions(hashMapKey - 1 - QuadrantSystem.quadrantYMultiplier, index, ref entity, ref translation, ref collider, ref collisionData); }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { NativeArray <Translation> translations = chunk.GetNativeArray(translationType); NativeArray <int> quadrantKeys = new NativeArray <int>(MAX_QUADRANT_NEIGHBORS, Allocator.Temp); //TODO make something that is dynamic float radius = 0.5f; float combinedRadius = radius * 2.0f; for (int entityIdx = 0; entityIdx < chunk.ChunkEntityCount; entityIdx++) { float2 currentPosition = translations[entityIdx].Value.xz; int countNeighborQuadrant = 0; QuadrantSystem.GetCurrentCellAndNeighborsKeys(currentPosition, ref quadrantKeys, ref countNeighborQuadrant); //Get nearest neighbors for (int i = 0; i < countNeighborQuadrant; i++) { if (!quadrantMap.TryGetFirstValue(quadrantKeys[i], out var neighbor, out var nativeMultiHashMapIterator)) { continue; } do { float distance = math.distance(neighbor.position, currentPosition); if (distance < combinedRadius && distance > 0.0001f) { var entity = ecb.CreateEntity(chunkIndex); Collision collision = new Collision() { // percentage = ((combinedRadius - distance) * 0.5f) / radius, percentage = distance, position = (neighbor.position + currentPosition) / 2.0f, frame = key }; ecb.AddComponent(chunkIndex, entity, collision); } } while (quadrantMap.TryGetNextValue(out neighbor, ref nativeMultiHashMapIterator)); } } }
public void Execute(Entity e, int jobIndex, [ReadOnly] ref Translation translation, [ReadOnly] ref MeleeStrengthComponent strength, ref MovementStateComponent state) { int hashKey = QuadrantSystem.GetPositionHashMapKey(translation.Value); state.Value = (ushort)MovementState.Moving; if (BlockerMap.TryGetFirstValue(hashKey, out var blockerData, out var it)) { float zombieX = translation.Value.x; do { float furthestRight = blockerData.position.x + blockerData.width / 2; float furthestLeft = blockerData.position.x - blockerData.width / 2; if (zombieX < furthestLeft || zombieX > furthestRight) { continue; } // within the bounds of the blocker // check how far away are you from the blocker if (abs(translation.Value.z - blockerData.position.z) > 2.5f) { continue; } if (!HealthData.Exists(blockerData.entity)) { // entity is dead return; } // the zombie is right in front of the blocker state.Value = (ushort)MovementState.Blocked; // detect if the blocker has a DamageTag. If not, add one if (!DamageData.Exists(blockerData.entity)) { CommandBuffer.AddComponent(jobIndex, blockerData.entity, new BlockerDamageTag()); return; } } while(BlockerMap.TryGetNextValue(out blockerData, ref it)); } }
public void Execute(Entity entity, int index, ref Translation translation, ref AsteroidVelocityData vel) { // Update position: translation.Value.x += vel.Velocity.x * deltaTime; translation.Value.y += vel.Velocity.y * deltaTime; // Destroy if collided with other asteroid: int hashMapKey = QuadrantSystem.GetQuadrantHashMapKey(translation.Value); QuadrantSystem.QuadrantEntityData quadrantData; if (IsCollisionWithAsteroid(hashMapKey, entity, index, translation, quadrantMultiHashMap, out quadrantData)) { if (entity != Entity.Null) { entityCommandBuffer.DestroyEntity(index, entity); } if (quadrantData.entity != Entity.Null) { entityCommandBuffer.DestroyEntity(quadrantData.entity.Index, quadrantData.entity); } } }
public void Execute(Entity entity, int index, [ReadOnly] ref Sight sight, [ReadOnly] ref LocalToWorld location, [ReadOnly] ref QuadrantEntity quadrantEntity, [ReadOnly] ref Diet diet, [ReadOnly] ref AnimalSize size, [ReadOnly] ref LifeStatus lifeStatus) { EntityWithPosition closestDangerTarget = new EntityWithPosition { entity = Entity.Null }; float closestDangerTargetDistance = float.MaxValue; EntityWithPosition closestFoodTarget = new EntityWithPosition { entity = Entity.Null }; float closestFoodTargetDistance = float.MaxValue; int hashMapKey = QuadrantSystem.GetPositionHashMapKey(location.Position); var entityDesc = new EntityDescription() { sight = sight, diet = diet, location = location, quadrantEntity = quadrantEntity, size = size, lifeStatus = lifeStatus }; FindTarget(index, hashMapKey, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); FindTarget(index, hashMapKey + 1, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); FindTarget(index, hashMapKey - 1, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); FindTarget(index, hashMapKey + QuadrantSystem.quadrantYMultiplier, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); FindTarget(index, hashMapKey - QuadrantSystem.quadrantYMultiplier, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); FindTarget(index, hashMapKey + 1 + QuadrantSystem.quadrantYMultiplier, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); FindTarget(index, hashMapKey - 1 + QuadrantSystem.quadrantYMultiplier, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); FindTarget(index, hashMapKey + 1 - QuadrantSystem.quadrantYMultiplier, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); FindTarget(index, hashMapKey - 1 - QuadrantSystem.quadrantYMultiplier, entityDesc, ref closestDangerTarget, ref closestDangerTargetDistance, ref closestFoodTarget, ref closestFoodTargetDistance); closestDangerTargetArray[index] = closestDangerTarget; closestFoodTargetArray[index] = closestFoodTarget; }
public void Execute(Entity entity, int index, [ReadOnly] ref Translation translation, [ReadOnly] ref QuadrantEntity quadrantEntity) { float3 unitPosition = translation.Value; Entity closestTargetEntity = Entity.Null; float3 closestTargetPosition = float3.zero; int key = QuadrantSystem.GetKeyFromPosition(unitPosition); NativeMultiHashMapIterator <int> iterator = new NativeMultiHashMapIterator <int>(); QuadrantData quadrantData; if (quadrantMap.TryGetFirstValue(key, out quadrantData, out iterator)) { do { if (quadrantEntity.type != quadrantData.quadrantEntity.type) { if (closestTargetEntity == Entity.Null) { // No target closestTargetEntity = quadrantData.entity; closestTargetPosition = math.distance(unitPosition, quadrantData.position); } else { if (math.distance(unitPosition, quadrantData.position) < math.distance(unitPosition, closestTargetPosition)) { // This target is closer closestTargetEntity = entity; closestTargetPosition = math.distancesq(unitPosition, quadrantData.position); } } } } while (quadrantMap.TryGetNextValue(out quadrantData, ref iterator)); } closestTargets[index] = closestTargetEntity; }
private static void FindTarget(ref Translation translation, ref MeleeFindTargetSettingsComponentData findingSettings, ref MeleeTargetComponentData meleeData, ref FactionComponentData faction, NativeMultiHashMap <int, QuadrantSystem.QuadrandEntityData> quadrantMap) { var pos = translation.Value; var quadrant = QuadrantSystem.GetQuadrant(pos); var closest = new MeleeTargetComponentData() { target = Entity.Null, targetPosition = translation.Value }; closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.CURRENT), closest); closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.DOWN), closest); closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.LEFT), closest); closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.LEFT_DOWN), closest); closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.LEFT_UP), closest); closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.RIGHT), closest); closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.RIGHT_DOWN), closest); closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.RIGHT_UP), closest); closest = FindClosest(findingSettings, faction, quadrantMap, pos, QuadrantSystem.GetNearestQuadrantKey(quadrant, QuadrantSystem.NearestQuadrant.UP), closest); meleeData.target = closest.target; meleeData.targetPosition = closest.targetPosition; }
public void Execute(Entity entity, int index, [ReadOnly] ref Translation unitTranslation, [ReadOnly] ref QuadrantEntity unitQuandrantEntity) { Entity closestTargetEntity = Entity.Null; float3 unitPosition = unitTranslation.Value; float3 closestTargetPosition = new float3(0); int hashMapKey = QuadrantSystem.GetPositionHasMapKey(unitTranslation.Value); FindTarget(hashMapKey, unitPosition, unitQuandrantEntity, ref closestTargetEntity, ref closestTargetPosition); for (int i = 1; i <= 2; i++) { FindTarget(hashMapKey + i, unitPosition, unitQuandrantEntity, ref closestTargetEntity, ref closestTargetPosition); FindTarget(hashMapKey - i, unitPosition, unitQuandrantEntity, ref closestTargetEntity, ref closestTargetPosition); FindTarget(hashMapKey + i * QuadrantSystem.quadrantYMultiplier, unitPosition, unitQuandrantEntity, ref closestTargetEntity, ref closestTargetPosition); FindTarget(hashMapKey - i * QuadrantSystem.quadrantYMultiplier, unitPosition, unitQuandrantEntity, ref closestTargetEntity, ref closestTargetPosition); } if (closestTargetEntity != Entity.Null) { entityCommandBuffer.AddComponent(index, entity, new HasTarget() { target = closestTargetEntity }); } }
protected override void OnCreate() { base.OnCreate(); Instance = this; quadrantMap = new NativeMultiHashMap <int, QuadrandEntityData>(0, Allocator.Persistent); }
public void Execute(Entity entity, int index, ref Translation translation, [ReadOnly] ref Rotation rotation, [ReadOnly] ref NonUniformScale nonUniformScale, [ReadOnly] ref MotionProperties motionProperties, ref Planetoid planetoidCrashInfo) { float3 position = translation.Value; float3 scale = nonUniformScale.Value; float qRotationZ = rotation.Value.value.z; float axisA = nonUniformScale.Value.x / 2f; float axisB = nonUniformScale.Value.y / 2f; //TODO read the angle from quaternion //float angleZ = GameHandler.ToEulerAngles(q).z; //angleZ = angleZ % (2 * math.PI); // read z angle of entity rotation by multiplying right vector by quaternion: float3 rotationRightVectorN = math.normalize(qRotationZ * new float3(0, 0, 1)); int hashMapKey = QuadrantSystem.GetPositionHashMapKey(position); if (quadrantMultiHashMap.TryGetFirstValue(hashMapKey, out EntityWithProps inspectedEntityWithProps, out NativeMultiHashMapIterator <int> it)) //TODO check the neighbouring quadrants { //TODO find the closest entity and only monitor that one do { float distance = math.distancesq(position, inspectedEntityWithProps.position); //TODO for ellipses: // calculate angle vector to the target //float3 vectorToTarget = inspectedEntityWithProps.position - position; //float distanceToTargetSq = vectorToTarget.x * vectorToTarget.x + vectorToTarget.y + vectorToTarget.y; float3 vectorToTargetN = math.normalize(inspectedEntityWithProps.position - position); // add angle to rotation angle of active ellipse collider float radiaeAngle = math.acos(math.dot(rotationRightVectorN, vectorToTargetN)); float sinRadiaeAngle = math.sin(radiaeAngle); float cosRadiaeAngle = math.cos(radiaeAngle); // calculate radius in line of target of active ellipse collider float radiusToTarget = axisA * axisB / math.sqrt(axisA * axisA * sinRadiaeAngle * sinRadiaeAngle + axisB * axisB * cosRadiaeAngle * cosRadiaeAngle); // do the same with passive ellipse collider float qRotationZofInspectedEntity = inspectedEntityWithProps.rotation.value.z; float3 rotationRightVectorNofInspectedEntity = math.normalize(qRotationZofInspectedEntity * new float3(0, 0, 1)); float axisAofInspectedEntity = inspectedEntityWithProps.nonUniformScale.x / 2f; float axisBofInspectedEntity = inspectedEntityWithProps.nonUniformScale.y / 2f; float radiaeAngleOfInspectedEntity = math.acos(math.dot(rotationRightVectorNofInspectedEntity, -vectorToTargetN)); float sinRadiaeAngleOfInspectedEntity = math.sin(radiaeAngleOfInspectedEntity); float cosRadiaeAngleOfInspectedEntity = math.cos(radiaeAngleOfInspectedEntity); float radiusFromTarget = axisAofInspectedEntity * axisBofInspectedEntity / math.sqrt(axisAofInspectedEntity * axisAofInspectedEntity * sinRadiaeAngleOfInspectedEntity * sinRadiaeAngleOfInspectedEntity + axisBofInspectedEntity * axisBofInspectedEntity * cosRadiaeAngleOfInspectedEntity * cosRadiaeAngleOfInspectedEntity); // sum the radiae to get the distance float radiaeSum = radiusToTarget + radiusFromTarget; float radiaeSumSq = radiaeSum * radiaeSum; // set the longer axis of ellipse to be the zero degrees rotation vector // or make it so that the x axis of ellipse is always longer // calculate the rotation of the asteroid % 360 // calculate the rotation of the asteroid upon which the check is being made // calculate the vector between two of the asteroids (maybe make it the normal vector) // calculate the angle between asteroid rotation and the connecting vector // and calculate for the radius at that point // same for the other asteroid // sum up the radii to obtain the collision distance // check for the collision distance (below) if (distance < radiaeSumSq && inspectedEntityWithProps.entity != entity && !(inspectedEntityWithProps.planetoidCrashData.crashTime > 0))// TODO and if entity that is being collided with has crashTime zero { planetoidCrashInfo.crashTime = realTimeSinceStartUp; inspectedEntityWithProps.planetoidCrashData.crashTime = realTimeSinceStartUp; destroyedPlanetoidsQueue.Enqueue(entity); destroyedPlanetoidsQueue.Enqueue(inspectedEntityWithProps.entity); //explosion location, TODO put exlosion locations into a persistent queue float3 explosionPoint = position - (position - inspectedEntityWithProps.position) / 2; explosionCoordsQueue.Enqueue(explosionPoint); break; } }while (quadrantMultiHashMap.TryGetNextValue(out inspectedEntityWithProps, ref it)); } }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { NativeArray <Translation> translations = chunk.GetNativeArray(translationType); NativeArray <Velocity> velocities = chunk.GetNativeArray(velocityType); NativeArray <Line> orcaLines = new NativeArray <Line>(maxNeighbors, Allocator.Temp); NativeArray <KeyValuePair <float, AgentNeighbor> > agentNeighbors = new NativeArray <KeyValuePair <float, AgentNeighbor> >(maxNeighbors, Allocator.Temp); NativeArray <int> quadrantKeys = new NativeArray <int>(MAX_QUADRANT_NEIGHBORS, Allocator.Temp); float invTimeStep = 1.0f / dt; float combinedRadius = radius * 2.0f; float combinedRadiusSqr = math.pow(combinedRadius, 2); float rangeSqr = neighborsDist * neighborsDist; for (int entityIdx = 0; entityIdx < chunk.ChunkEntityCount; entityIdx++) { float2 velocity = velocities[entityIdx].Value; //Early exit if the agent is not moving if (math.lengthsq(velocity) < 0.001f) { continue; } float2 position = translations[entityIdx].Value.xz; int countNeighborQuadrant = 0; QuadrantSystem.GetCurrentCellAndNeighborsKeys(position, ref quadrantKeys, ref countNeighborQuadrant); //ORCA setup int neighborsCount = 0; int nbObstacleLine = 0; //Get nearest neighbors for (int i = 0; i < countNeighborQuadrant; i++) { if (!quadrantMap.TryGetFirstValue(quadrantKeys[i], out var neighbor, out var nativeMultiHashMapIterator)) { continue; } do { float2 dir = position - neighbor.position; float distSqr = math.dot(dir, dir); //Condition to avoid self if (distSqr > 0.001f) { //If the other agent is under the minimum range => add it if (!(distSqr < rangeSqr)) { continue; } //If there is a free space, add it immediately if (neighborsCount < maxNeighbors) { agentNeighbors[neighborsCount] = new KeyValuePair <float, AgentNeighbor>(distSqr, new AgentNeighbor() { position = neighbor.position, velocity = neighbor.velocity }); neighborsCount++; } //Make sure the list is sorted int j = neighborsCount - 1; while (j != 0 && distSqr < agentNeighbors[j - 1].Key) { agentNeighbors[j] = agentNeighbors[j - 1]; j--; } //Once a spot with a further agent is found, place if agentNeighbors[j] = new KeyValuePair <float, AgentNeighbor>(distSqr, new AgentNeighbor() { position = neighbor.position, velocity = neighbor.velocity }); //If the list is full, only check agent nearer than the farrest neighbor. if (neighborsCount == maxNeighbors) { rangeSqr = agentNeighbors[maxNeighbors - 1].Key; } } } while (quadrantMap.TryGetNextValue(out neighbor, ref nativeMultiHashMapIterator)); } //Evaluate each neighbors for (int neighborIdx = 0; neighborIdx < neighborsCount; neighborIdx++) { AgentNeighbor otherAgent = agentNeighbors[neighborIdx].Value; float2 relativePosition = otherAgent.position - position; float2 relativeVelocity = velocity - otherAgent.velocity; float distSqr = math.lengthsq(relativePosition); Line line; float2 u; if (distSqr > combinedRadiusSqr) { // No Collision float2 w = relativeVelocity - invTimeHorizon * relativePosition; // Vector from center to relative velocity float wLengthSqr = math.lengthsq(w); float dotProduct1 = math.dot(w, relativePosition); if (dotProduct1 < 0.0f && math.pow(dotProduct1, 2) > combinedRadiusSqr * wLengthSqr) { // Project on circle float wLength = math.sqrt(wLengthSqr); float2 unitW = w / wLength; line.direction = new float2(unitW.y, -unitW.x); u = (combinedRadius * invTimeHorizon - wLength) * unitW; } else { // Projection on legs float leg = math.sqrt(distSqr - combinedRadiusSqr); if (Det(relativePosition, w) > 0.0f) { line.direction = new float2( relativePosition.x * leg - relativePosition.y * combinedRadius, relativePosition.x * combinedRadius + relativePosition.y * leg) / distSqr; } else { line.direction = -new float2( relativePosition.x * leg - relativePosition.y * combinedRadius, -relativePosition.x * combinedRadius + relativePosition.y * leg) / distSqr; } float dotProduct2 = math.dot(relativeVelocity, line.direction); u = dotProduct2 * line.direction - relativeVelocity; } } else { //Collision float2 w = relativeVelocity - invTimeStep * relativePosition; float wLength = math.length(w); float2 wUnit = w / wLength; line.direction = new float2(wUnit.y, -wUnit.x); u = (combinedRadius * invTimeStep - wLength) * wUnit; } line.point = velocity + 0.5f * u; orcaLines[neighborIdx] = line; } float2 optimalVel = velocity; float2 vel = float2.zero; float maxSpeed = velocities[entityIdx].maxSpeed; int lineFail = LinearProgram2(orcaLines, neighborsCount, maxSpeed, optimalVel, false, ref vel); if (lineFail < neighborsCount) { LinearProgram3(orcaLines, neighborsCount, nbObstacleLine, lineFail, maxSpeed, ref vel); } velocities[entityIdx] = new Velocity() { Value = vel, maxSpeed = maxSpeed }; } quadrantKeys.Dispose(); orcaLines.Dispose(); agentNeighbors.Dispose(); }
/// <summary> /// Handles flocking simulation. /// </summary> protected override void OnUpdate() { var deltaTime = Time.DeltaTime; // Note that we need to pass the quadrant system structure to WithReadOnly(). This is because other systems are // reading from it in parallel and we need to ensure the safety system that we will not modify the memory. var quadrantHashMap = QuadrantSystem.QuadrantHashMap; // Query for all entities with BoidObstacle tag component var allObstacles = GetEntityQuery(ComponentType.ReadOnly <BoidObstacle>()).ToEntityArray(Allocator.TempJob); Entities.WithReadOnly(quadrantHashMap).WithReadOnly(allObstacles).WithAll <SpaceshipTag>().ForEach( (Entity entity, ref MovementComponent movement, in BoidComponent boid, in Translation pos, in TargetingComponent target) => { var neighborCnt = 0; var cohesionPos = float3.zero; // For average position in neighborhood var alignmentVec = float3.zero; // For average alignment vector var separationVec = float3.zero; // For average separation vector // Get all translation components (will be needed for the obstacle positions) var allTranslations = GetComponentDataFromEntity <Translation>(true); // Search neighboring quadrants and update aggregate steering data var hashMapKey = QuadrantSystem.HashKeyFromPosition(pos.Value); SearchQuadrantNeighbors(in quadrantHashMap, hashMapKey, entity, boid.CellRadius, pos.Value, ref neighborCnt, ref cohesionPos, ref alignmentVec, ref separationVec); // Average steering data if (neighborCnt > 0) { separationVec /= neighborCnt; cohesionPos /= neighborCnt; alignmentVec /= neighborCnt; } else { // apply no steering cohesionPos = pos.Value; alignmentVec = movement.Heading; separationVec = movement.Heading; } // Compute obstacle avoidance var avoidanceHeading = float3.zero; var avoidObstacle = false; // if the boid should avoid obstacle instead of normal steering for (var i = 0; i < allObstacles.Length; i++) { var otherPos = allTranslations[allObstacles[i]]; // Obstacle position var distance = Vector3.Distance(pos.Value, otherPos.Value); if (distance >= boid.ObstacleAversionDistance) { continue; // This obstacle is not close } avoidObstacle = true; var obstacleSteering = pos.Value - otherPos.Value; if (obstacleSteering.Equals(float3.zero)) { obstacleSteering = movement.Heading; } obstacleSteering = math.normalizesafe(obstacleSteering); avoidanceHeading = otherPos.Value + obstacleSteering * boid.ObstacleAversionDistance - pos.Value; break; // We have found an obstacle to avoid } // Check if we are in pursuit and compute pursuit steering var pursuitSteering = float3.zero; if (target.TargetLocked) { pursuitSteering = math.normalizesafe(target.TargetPosition - pos.Value) * boid.PursuitWeight; } // Combine all steering factors and decide which one to use var targetSteering = math.normalizesafe(movement.Target - pos.Value) * boid.TargetWeight; var alignmentSteering = math.normalizesafe(alignmentVec) * boid.AlignmentWeight; var cohesionSteering = math.normalizesafe(cohesionPos - pos.Value) * boid.CohesionWeight; var separationSteering = math.normalizesafe(separationVec) * boid.SeparationWeight; var normalHeading = math.normalizesafe(targetSteering + alignmentSteering + cohesionSteering + separationSteering + pursuitSteering); var targetHeading = avoidObstacle ? avoidanceHeading : normalHeading; // Setting a new heading (shifted towards target heading) movement.Heading = math.normalizesafe(movement.Heading + deltaTime * boid.SteeringSpeed * (targetHeading - movement.Heading)); }).ScheduleParallel();
protected override void OnUpdate() { var quadrantMultiHashMap = quadrantMultiHashMap2; float deltaTime = Time.DeltaTime; var ecb = m_EndSimulationEcbSystem.CreateCommandBuffer().ToConcurrent(); NativeArray <long> localInfectedCounter = new NativeArray <long>(1, Allocator.TempJob); localInfectedCounter[0] = 0; NativeArray <long> localTotalInfectedCounter = new NativeArray <long>(1, Allocator.TempJob); localTotalInfectedCounter[0] = 0; NativeArray <long> localSymptomaticCounter = new NativeArray <long>(1, Allocator.TempJob); localSymptomaticCounter[0] = 0; NativeArray <long> localAsymptomaticCounter = new NativeArray <long>(1, Allocator.TempJob); localAsymptomaticCounter[0] = 0; NativeArray <long> localDeathCounter = new NativeArray <long>(1, Allocator.TempJob); localDeathCounter[0] = 0; NativeArray <long> localRecoveredCounter = new NativeArray <long>(1, Allocator.TempJob); localRecoveredCounter[0] = 0; NativeArray <long> localTotalRecoveredCounter = new NativeArray <long>(1, Allocator.TempJob); localTotalRecoveredCounter[0] = 0; //job -> each element, if not infected, check if there are infected in its same quadrant var jobHandle = Entities.ForEach((Entity entity, int nativeThreadIndex, Translation t, ref QuadrantEntity qe, ref HumanComponent humanComponent, ref InfectionComponent ic) => { //for non infected entities, a check in the direct neighbours is done for checking the presence of infected if (ic.status == Status.susceptible) { //not infected-> look for infected in same cell int hashMapKey = QuadrantSystem.GetPositionHashMapKey(t.Value); //Debug.Log("Infected false"); QuadrantData quadrantData; NativeMultiHashMapIterator <int> nativeMultiHashMapIterator; if (quadrantMultiHashMap.TryGetFirstValue(hashMapKey, out quadrantData, out nativeMultiHashMapIterator)) { //cycle through all entries oh hashmap with the same Key do { //Debug.Log(quadrantData.position); if (math.distance(t.Value, quadrantData.position) < 2f) { //TODO consider also social resp other human involved //increment infectionCounter if one/more infected are in close positions (infected at quadrantData.position) //infection counter is determined by time and human responsibility ic.contagionCounter += 1f * deltaTime * (1 - humanComponent.socialResposibility); } //TODO we could add a cap here to speed up the check } while (quadrantMultiHashMap.TryGetNextValue(out quadrantData, ref nativeMultiHashMapIterator)); } else { //no infected in same cell -> human is safe ic.contagionCounter = 0f; } } //infection happened if (ic.contagionCounter >= contagionThreshold && ic.status == Status.susceptible) { //human become infected unsafe { Interlocked.Increment(ref ((long *)localInfectedCounter.GetUnsafePtr())[0]); Interlocked.Increment(ref ((long *)localTotalInfectedCounter.GetUnsafePtr())[0]); } qe.typeEnum = QuadrantEntity.TypeEnum.exposed; ic.status = Status.exposed; ic.exposedCounter = 0; } //Infectious status -> symptoms vs non-symptoms if (ic.exposedCounter > ic.exposedThreshold && ic.status == Status.exposed) { qe.typeEnum = QuadrantEntity.TypeEnum.infectious; ic.status = Status.infectious; ic.infected = true; if (ic.humanSymptomsProbability > (100 - ic.globalSymptomsProbability)) { //symptomatic -> lasts between 0.5 and 1.5 day ic.symptomatic = true; unsafe { Interlocked.Increment(ref ((long *)localSymptomaticCounter.GetUnsafePtr())[0]); } ic.infectiousCounter = 0; } else { //asymptomatic ic.symptomatic = false; unsafe { Interlocked.Increment(ref ((long *)localAsymptomaticCounter.GetUnsafePtr())[0]); } ic.infectiousCounter = 0; } } if (ic.infectiousCounter > ic.infectiousThreshold && ic.status == Status.infectious) { if (ic.humanDeathProbability > (100 - ic.globalDeathProbability)) { //remove entity unsafe { Interlocked.Increment(ref ((long *)localDeathCounter.GetUnsafePtr())[0]); Interlocked.Decrement(ref ((long *)localInfectedCounter.GetUnsafePtr())[0]); } if (ic.symptomatic) { unsafe { Interlocked.Decrement(ref ((long *)localSymptomaticCounter.GetUnsafePtr())[0]); } } else { unsafe { Interlocked.Decrement(ref ((long *)localAsymptomaticCounter.GetUnsafePtr())[0]); } } ic.status = Status.removed; qe.typeEnum = QuadrantEntity.TypeEnum.removed; ecb.DestroyEntity(nativeThreadIndex, entity); } else { //recovery time set up unsafe { Interlocked.Decrement(ref ((long *)localInfectedCounter.GetUnsafePtr())[0]); Interlocked.Increment(ref ((long *)localRecoveredCounter.GetUnsafePtr())[0]); Interlocked.Increment(ref ((long *)localTotalRecoveredCounter.GetUnsafePtr())[0]); } if (ic.symptomatic) { unsafe { Interlocked.Decrement(ref ((long *)localSymptomaticCounter.GetUnsafePtr())[0]); } } else { unsafe { Interlocked.Decrement(ref ((long *)localAsymptomaticCounter.GetUnsafePtr())[0]); } } ic.status = Status.recovered; ic.infected = false; //qe.typeEnum = QuadrantEntity.TypeEnum.recovered; ic.recoveredCounter = 0; } } if (ic.recoveredCounter > ic.recoveredThreshold && ic.status == Status.recovered) { ic.status = Status.susceptible; qe.typeEnum = QuadrantEntity.TypeEnum.susceptible; unsafe { Interlocked.Decrement(ref ((long *)localRecoveredCounter.GetUnsafePtr())[0]); } } if (ic.status == Status.exposed) { ic.exposedCounter += 1f * deltaTime; } if (ic.status == Status.infectious) { ic.infectiousCounter += 1f * deltaTime; } if (ic.status == Status.recovered) { ic.recoveredCounter += 1f * deltaTime; } }).WithReadOnly(quadrantMultiHashMap).ScheduleParallel(Dependency); m_EndSimulationEcbSystem.AddJobHandleForProducer(jobHandle); this.Dependency = jobHandle; jobHandle.Complete(); unsafe { Interlocked.Add(ref infectedCounter, Interlocked.Read(ref ((long *)localInfectedCounter.GetUnsafePtr())[0])); Interlocked.Add(ref totalInfectedCounter, Interlocked.Read(ref ((long *)localTotalInfectedCounter.GetUnsafePtr())[0])); Interlocked.Add(ref symptomaticCounter, Interlocked.Read(ref ((long *)localSymptomaticCounter.GetUnsafePtr())[0])); Interlocked.Add(ref asymptomaticCounter, Interlocked.Read(ref ((long *)localAsymptomaticCounter.GetUnsafePtr())[0])); Interlocked.Add(ref recoveredCounter, Interlocked.Read(ref ((long *)localRecoveredCounter.GetUnsafePtr())[0])); Interlocked.Add(ref deathCounter, Interlocked.Read(ref ((long *)localDeathCounter.GetUnsafePtr())[0])); Interlocked.Add(ref populationCounter, -Interlocked.Read(ref ((long *)localDeathCounter.GetUnsafePtr())[0])); } //Write some text to the test.txt file writer.WriteLine(Interlocked.Read(ref populationCounter) + "\t" + Interlocked.Read(ref infectedCounter) + "\t" + Interlocked.Read(ref totalInfectedCounter) + "\t" + Interlocked.Read(ref symptomaticCounter) + "\t" + Interlocked.Read(ref asymptomaticCounter) + "\t" + Interlocked.Read(ref deathCounter) + "\t" + Interlocked.Read(ref recoveredCounter) + "\t" + Interlocked.Read(ref totalRecoveredCounter) + "\t" + (int)Datetime.total_minutes); localInfectedCounter.Dispose(); localTotalInfectedCounter.Dispose(); localAsymptomaticCounter.Dispose(); localSymptomaticCounter.Dispose(); localRecoveredCounter.Dispose(); localTotalRecoveredCounter.Dispose(); localDeathCounter.Dispose(); }
protected override void OnCreate() { endSimulationEntityCommandBuffer = World.GetOrCreateSystem <EndSimulationEntityCommandBufferSystem>(); quadrantSystem = World.GetOrCreateSystem <QuadrantSystem>(); base.OnCreate(); }
// todo: maybe intelligent ones should avoid not only the blockers but also each other? public void Execute([ReadOnly] ref Translation translation, [ReadOnly] ref TargetComponent target, ref MovementComponent movement) { int hashKey = QuadrantSystem.GetPositionHashMapKey(translation.Value); float3 dir = new float3(0, 0, -1); float closestDis = 1000f; float3 closestPos = float3(10000f, 1000f, 1000f); bool bFoundPotentialThreat = false; if (BlockerMap.TryGetFirstValue(hashKey, out var data, out var it)) { float zombieX = translation.Value.x; do { // todo: maybe you should first find the closest target first and then determine if it's worth avoiding // are you close enough to care? float furthestRight = data.position.x + data.width / 2 + 2f; float furthestLeft = data.position.x - data.width / 2 - 2f; if (zombieX < furthestLeft || zombieX > furthestRight) { continue; } float disSq = distancesq(translation.Value, data.position); if (disSq > closestDis) { continue; } closestDis = disSq; closestPos = data.position; bFoundPotentialThreat = true; } while (BlockerMap.TryGetNextValue(out data, ref it)); } if (!bFoundPotentialThreat) { movement.defaultDirection = dir; // todo: cause an irrational movement return; } if (closestDis > 150f) { movement.defaultDirection = dir; return; } // yes avoid float3 vFromAiToBlocker = normalize(closestPos - translation.Value); float dotProd = dot(dir, vFromAiToBlocker); // is it behind? if (dotProd < 0f) { movement.defaultDirection = dir; return; } // detect if to the left or to the right float3 right = new float3(1, 0, 0); float side = dot(right, vFromAiToBlocker); if (side > 0f) { // to the right, go left movement.defaultDirection.x -= ((movement.direction.x - 0.1) < -1) ? 0 : 0.1f; movement.defaultDirection.z += ((movement.direction.z + 0.1) > 0) ? 0 : 0.1f; return; } // to the left, go right movement.defaultDirection.x += ((movement.direction.x + 0.1) > 1) ? 0 : 0.1f; movement.defaultDirection.z += ((movement.direction.z + 0.1) > 0) ? 0 : 0.1f; }
protected override JobHandle OnUpdate(JobHandle inputDeps) { //NativeQueue<CrashInfo> destroyedPlanetoidsQueue = new NativeQueue<CrashInfo>(Allocator.TempJob); EntityQuery entityQuery = GetEntityQuery(typeof(Planetoid)); NativeArray <Planetoid> planetoids = entityQuery.ToComponentDataArray <Planetoid>(Allocator.TempJob); NativeArray <int> keys = QuadrantSystem.quadrantMultiHashMap.GetKeyArray(Allocator.TempJob); NativeArray <JobHandle> jobHandles = new NativeArray <JobHandle>(keys.Length, Allocator.TempJob); for (int i = 0; i < keys.Length; i++) { NativeArray <EntityWithProps> entityWithPropsArray = new NativeArray <EntityWithProps>(QuadrantSystem.GetEntityCountInQuadrant(QuadrantSystem.quadrantMultiHashMap, keys[i]), Allocator.TempJob); SortPositionsJob sortPositionsJob = new SortPositionsJob { quadrantMultiHashMap = QuadrantSystem.quadrantMultiHashMap, entityWithPropsArray = entityWithPropsArray, realtimeSinceStartUp = Time.realtimeSinceStartup, planetoids = planetoids, keys = keys, index = i }; jobHandles[i] = sortPositionsJob.Schedule(); } JobHandle job = JobHandle.CombineDependencies(jobHandles); JobHandle.CompleteAll(jobHandles); jobHandles.Dispose(); keys.Dispose(); //destroyedPlanetoidsQueue.Dispose(); DisableJob disableJob = new DisableJob { entityCommandBuffer = endSimulationEntityCommandBufferSystem.CreateCommandBuffer().ToConcurrent() }; JobHandle jobHandle = disableJob.Schedule(this, job);//TODO try job handles combine endSimulationEntityCommandBufferSystem.AddJobHandleForProducer(jobHandle); AddTranslationJob addTranslationJob = new AddTranslationJob { seed = UnityEngine.Random.Range(1, 1000000), realTimeSinceStartUp = Time.realtimeSinceStartup, entityCommandBuffer = endPresentationSimulationEntityCommandBufferSystem.CreateCommandBuffer().ToConcurrent(), cameraMaxLeftDown = Camera.main.ViewportToWorldPoint(new Vector3(0, 0)), cameraMaxRightUp = Camera.main.ViewportToWorldPoint(new Vector3(1, 1)) }; jobHandle = addTranslationJob.Schedule(this, jobHandle); endPresentationSimulationEntityCommandBufferSystem.AddJobHandleForProducer(jobHandle); return(jobHandle); }
public void Execute(ref Translation translation, ref Scale scale, ref ProjectileComponentData projectileData, ref ProjectileCollisionComponentData processData, ref VelocityComponentData velocity) { if (processData.colisionTimeOut > 0) { processData.colisionTimeOut -= deltaTime; return; } if (processData.maxHitCount <= 0) { return; } var projectileMoved = velocity.value.x != 0 || velocity.value.y != 0; var projectileStopsRightNow = !projectileMoved && projectileData.itStopsRightNow; if (processData.detectTime == ProjectileCollisionComponentData.DetectCillisionTime.WHEN_MOVE && !projectileMoved) { return; } else if (processData.detectTime == ProjectileCollisionComponentData.DetectCillisionTime.WHEN_STOPS && (projectileMoved || !projectileStopsRightNow)) { return; } processData.processData.direction = projectileData.previousProjectilePosition.ToF2().GetDirectionTo(translation.Value); processData.processData.direction.y = 0; var radius = processData.collisionRadius; if (radius <= 0) { radius = 0.5f; } radius *= scale.Value; var radSqr = radius * radius; QuadrantSystem.GuadrantIterator qiterator; if (QuadrantSystem.TryGetFirstQuadrantInRadius(translation.Value, radius, out qiterator)) { do { var key = QuadrantSystem.GetHashKeyByQuadrant(qiterator.quadrant); //получаем все энтити в квадранте QuadrantSystem.QuadrandEntityData qdata; NativeMultiHashMapIterator <int> iterator; if (quadrantMap.TryGetFirstValue(key, out qdata, out iterator)) { do { if (processData.maxHitCount <= 0) { break; } //ну и проверяем на столкновение и создаём RegisteredHitData var hit = false; if (projectileMoved) { hit = ANU.Utils.Math.IsSegmentIntersectsPoint( projectileData.previousProjectilePosition.ToF2(), translation.Value.ToF2(), qdata.position.ToF2(), radius ); } else { hit = math.distancesq(translation.Value.ToF2(), qdata.position.ToF2()) <= radSqr; } //если попал и попал не в своего if (hit && (processData.ownerFaction == FactionComponentData.Faction.NEUTRAL || processData.ownerFaction != qdata.faction)) { registegedHits.TryAdd( qdata.entity, new RegisteredHitData() { entity = qdata.entity, processData = new ProcessProjectileCollisionTag() { hittedByProjectile = true, processData = processData.processData } } ); processData.maxHitCount--; } } while (quadrantMap.TryGetNextValue(out qdata, ref iterator)); } } while (QuadrantSystem.TryGetNextQuadrantInRadius(ref qiterator)); } }