Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Diagnostics;
- using Duality;
- using Duality.Resources;
- using Duality.Components;
- using Duality.Input;
- using static Tutorial.Game;
- //using static Duality.MathF;
- namespace Tutorial
- {
- public class UnitHandlerCollisionHash : Component, ICmpUpdatable, ICmpInitializable
- {
- public Grid<List<Unit>> Hash { get; set; } = new Grid<List<Unit>>(20, 20);
- public int HashWidth { get; set; } = 20;
- public int HashHeight { get; set; } = 20;
- public int HashGridSize { get; set; } = G * 3;
- public Rect hashBoundaries;
- float interval = 30;
- float timer = 0;
- int collisionChecks = 0;
- int collisions = 0;
- void ICmpInitializable.OnInit(InitContext context)
- {
- if (context != InitContext.Activate) return;
- for (var i = 0; i < HashWidth; i++)
- for (var j = 0; j < HashHeight; j++)
- Hash[i, j] = new List<Unit>();
- hashBoundaries = new Rect(0, 0, HashWidth, HashHeight);
- }
- void ICmpInitializable.OnShutdown(ShutdownContext context)
- {
- }
- void ICmpUpdatable.OnUpdate()
- {
- if (timer >= interval)
- {
- var watch = Stopwatch.StartNew();
- CheckCollisionBetweenUnits();
- watch.Stop();
- if (Game.Keyboard.KeyPressed(Key.V))
- {
- var log = Scene.Current.FindComponent<HelperConsole>();
- var count = Scene.Current.FindComponents<Unit>().Count();
- log.SetText("Checks / Collisions: " + collisionChecks + "/" + collisions + " (Units: " + count + " / Time taken: " + watch.Elapsed + ")");
- }
- timer = 0;
- }
- timer += Time.TimeMult;
- }
- void CheckCollisionBetweenUnits()
- {
- //Let's get units' list and count
- var units = Scene.Current.FindComponents<Unit>();
- var count = units.Count();
- //Let them all coliide
- for (var i = 0; i < count; i++)
- {
- var thisUnit = units.ElementAt(i);
- var thisUnitTransf = thisUnit.GameObj.Transform;
- thisUnit.checks = 0;
- //Update collision rectangle and enable collision
- thisUnit.CheckCollisionUnits = true;
- thisUnit.CollisionRect = new Rect(thisUnitTransf.Pos.X - 3, thisUnitTransf.Pos.Y - 3, 6, 6);
- //Add to a hash and delete from previous, if needed
- if (thisUnit.Hash.X == -1000)
- {
- var gridPos = new Point2((int)MathF.Floor(thisUnitTransf.Pos.X / HashGridSize), (int)MathF.Floor(thisUnitTransf.Pos.Y / HashGridSize));
- Log.Game.Write("Added to Hash[" + gridPos.X + ", " + gridPos.Y + "].");
- thisUnit.Hash = gridPos;
- Hash[gridPos.X, gridPos.Y].Add(thisUnit);
- }
- else//If I'm already in a hash
- {
- var gridPos = new Point2((int)MathF.Floor(thisUnitTransf.Pos.X / HashGridSize), (int)MathF.Floor(thisUnitTransf.Pos.Y / HashGridSize));
- //If I'm not in the same hash any more
- if (thisUnit.Hash != gridPos)
- {
- //Remove from previous
- Hash[thisUnit.Hash.X, thisUnit.Hash.Y].Remove(thisUnit);
- //Add to the new one
- if (hashBoundaries.Contains(gridPos))
- {
- thisUnit.Hash = gridPos;
- Hash[gridPos.X, gridPos.Y].Add(thisUnit);
- }
- else
- {
- thisUnit.Hash = new Point2(-1000, -1000);
- }
- }
- }
- }
- //Debugging purposes
- collisionChecks = 0;
- collisions = 0;
- //TimeSpan time = new TimeSpan();
- for (var i = 0; i < HashWidth; i++)
- {
- for (var j = 0; j < HashHeight; j++)
- {
- CheckCollisionsOfUnitsInHash(i, j);
- }
- }
- }
- void CheckCollisionsOfUnitsInHash(int x, int y)
- {
- //This will loop through all of the units in this hash
- for (var i = 0; i < Hash[x, y].Count; i++)
- {
- var unitA = Hash[x, y].ElementAt(i);
- if (!unitA.CheckCollisionUnits) continue;
- unitA.CheckCollisionUnits = false;
- var topLeftX = (int) Math.Max(0, unitA.CollisionRect.TopLeft.X / HashGridSize);
- var topLeftY = (int) Math.Max(0, unitA.CollisionRect.TopLeft.Y / HashGridSize);
- var bottomRightX = (int) Math.Min(HashWidth, unitA.CollisionRect.BottomRight.X / HashGridSize);
- var bottomRightY = (int) Math.Min(HashHeight, unitA.CollisionRect.BottomRight.Y / HashGridSize);
- //Now let's loop through its hash (and neighbours, if needed)
- for (var a = topLeftX; a <= bottomRightX; a++)
- {
- for (var b = topLeftY; b <= bottomRightY; b++)
- {
- for (var c = 0; c < Hash[a, b].Count; c++)
- {
- var unitB = Hash[a, b].ElementAt(c);
- unitA.checks++;
- unitB.checks++;
- if (!unitB.CheckCollisionUnits) continue;
- collisionChecks++;
- //If colliding!
- if (unitA.CollisionRect.Intersects(unitB.CollisionRect))
- {
- //Let's make one of them stop based on movement priority
- unitA.CollisionEnd(unitB);
- //Disable the other as well and +1 to collisions
- //unitB.CheckCollisionUnits = false;
- collisions++;
- break;
- }
- }
- }
- }
- }
- /*
- //Loop through all of the units
- for (var i = 0; i < count; i++)
- {
- //Get current unit and if it's collided with someone this frame, skip
- var unitA = units.ElementAt(i);
- if (!unitA.CheckCollisionUnits) continue;
- //Deactivate collision and get GameObject
- unitA.CheckCollisionUnits = false;
- var colliderA = unitA.GameObj;
- //Loop through all of the OTHER units
- for (var j = 0; j < count; j++)
- {
- //Get the others and skip if necessary
- var unitB = units.ElementAt(j);
- if (!unitB.CheckCollisionUnits) continue;
- collisionChecks++;
- //Get the other and collision vector
- var colliderB = unitB.GameObj;
- //var collision = (colliderA.Transform.Pos - colliderB.Transform.Pos);
- //If colliding!
- if (unitA.CollisionRect.Intersects(unitB.CollisionRect))
- {
- //Let's make one of them stop based on movement priority
- unitA.CollisionEnd(unitB);
- //Disable the other as well and +1 to collisions
- unitB.CheckCollisionUnits = false;
- collisions++;
- break;
- }
- }
- }
- }*/
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement