private static void SendCollision(BoundSetAspect boundSet1, BoundSetAspect boundSet2) { if (boundSet1.GetOwner().GetType() == typeof(Shell) && boundSet2.GetOwner().GetType() != typeof(Shell)) { Shell shell = (Shell)boundSet1.GetOwner(); if (shell.ShellOwner != boundSet2.GetOwner()) { Ship target = (Ship)boundSet2.GetOwner(); //target.RearCannon.PerformShoot(); MessageDispatcher.Post(new BoundSetCollision(boundSet1, boundSet2)); } } else if (boundSet2.GetOwner().GetType() == typeof(Shell) && boundSet1.GetOwner().GetType() != typeof(Shell)) { Shell shell = (Shell)boundSet2.GetOwner(); if (shell.ShellOwner != boundSet1.GetOwner()) { Ship target = (Ship)boundSet1.GetOwner(); //target.RearCannon.PerformShoot(); MessageDispatcher.Post(new BoundSetCollision(boundSet1, boundSet2)); } } else MessageDispatcher.Post(new BoundSetCollision(boundSet1, boundSet2)); }
internal static void CheckIntersection(BoundSetAspect boundSet1, BoundSetAspect boundSet2) { Pair<BoundSetAspect> pair = new Pair<BoundSetAspect>(boundSet1, boundSet2); // если объекты пересекаются, то ищем их в словаре. // если нашли, то НЕ генерируем событие Collision // если не нашли, то генерируем событие Collision и заносим их в словарь if (boundSet1.IntersectsWith(boundSet2)) { if (!collisions.ContainsKey(pair)) { collisions.Add(pair, 0); SendCollision(boundSet1, boundSet2); } } // объекты не пересекаются. // нужно удалить их из словарей, если они там есть, // и сгенерировать событие NotCollision, если они там были else { if (collisions.ContainsKey(pair)) { collisions.Remove(pair); SendNotCollision(boundSet1, boundSet2); } } }
internal static void RemoveAspect(BoundSetAspect boundSetAspect) { Pair<BoundSetAspect>[] pairs = new Pair<BoundSetAspect>[collisions.Keys.Count]; collisions.Keys.CopyTo(pairs, 0); foreach (Pair<BoundSetAspect> pair in pairs) { if (pair.First == boundSetAspect) { Pair<BoundSetAspect> newPair = new Pair<BoundSetAspect>(null, pair.Second); collisions.Remove(pair); if (pair.Second != null) collisions.Add(pair, 0); SendNotCollision(boundSetAspect, pair.Second); } else if (pair.Second == boundSetAspect) { Pair<BoundSetAspect> newPair = new Pair<BoundSetAspect>(pair.First, null); collisions.Remove(pair); if (pair.First != null) collisions.Add(pair, 0); SendNotCollision(boundSetAspect, pair.First); } } }
/// <summary> /// Конструктор /// </summary> /// <param name="shipVerts"></param> private Ship(PointF position, float length, float width) { float depth = 0; List<Vector3> shipVerts = new List<Vector3>(); shipVerts.Add(new Vector3(-1f * width / 2 + position.X, -1f * length / 2 + position.Y, depth)); shipVerts.Add(new Vector3(-1f * width / 2 + position.X, 0.25f * length / 2 + position.Y, depth)); shipVerts.Add(new Vector3(0 * width / 2 + position.X, 1f * length / 2 + position.Y, depth)); shipVerts.Add(new Vector3(1f * width / 2 + position.X, 0.25f * length / 2 + position.Y, depth)); shipVerts.Add(new Vector3(1f * width / 2 + position.X, -1f * length / 2 + position.Y, depth)); shipVerts.Add(new Vector3(-1f * width / 2 + position.X, -1f * length / 2 + position.Y, depth)); //mechanics = VehicleWithGearboxAspect.Create(this); physics = PhysicsAspect.Create(this); mass = MassAspect.Create(this); Thruster thruster1 = Thruster.Create(this, physics.Facing); Thruster thruster2 = Thruster.Create(this, physics.Facing); IList<Thruster> thrusters = new List<Thruster>(2); thrusters.Add(thruster1); thrusters.Add(thruster2); thrusterController = ThrusterController.Create(this, thrusters); graphics = GraphicsAspect.Create(this, shipVerts, 3, Color.White, Color.Red); bounds = BoundSetAspect.Create(this, shipVerts); //bounds.GetOuterContour(); bounds.SetAttribute(Strings.CollisionDetectionSpeedType, Strings.CollisionDetectionSpeedTypeSlowOrStatic); rearCannon = Weapon.Create(this, Side.Rear); leftCannon = Weapon.Create(this, Side.Left); rightCannon = Weapon.Create(this, Side.Right); damage = DamageAspect.Create(this, 100); messageHandler.Handlers.Add(typeof(Kill), HandleKill); messageHandler.Handlers.Add(typeof(BoundSetCollision), HandleBoundSetCollision); }
public Shell(Vector3 position, Vector3 cannonFacing, Vector3 cannonVelocity, float startSpeed, object shellOwner) { int segments = 8; List<Vector3> vertices = new List<Vector3>(segments + 1); //float unitradius = (float)Math.Sqrt(8); float angleStep = (float)(2 * Math.PI / segments); for (int i = 0; i < segments; i++) { vertices.Add(new Vector3((float)Math.Cos(angleStep * i) * radius, (float)Math.Sin(angleStep * i) * radius, 0)); } vertices.Add(new Vector3(radius, 0, 0)); graphics = GraphicsAspect.Create(this, vertices, position, 1, Color.White, Color.Red); // вычисляем вектор полёта снаряда - сумма импульса выстрела и собственной скорости оружия cannonFacing.NormalizeFast(); Vector3 shootVelocity = cannonFacing * startSpeed + cannonVelocity; Vector2 shootDirection = shootVelocity.Xy; shootDirection.NormalizeFast(); //physics = new PhysicsAspect(this, position, shootVelocity.Xy, startSpeed); physics = PhysicsAspect.Create(this, position, shootDirection, shootVelocity.LengthFast); bounds = BoundSetAspect.Create(this, null); BoundsAspect bound = CircleBoundsAspect.Create(bounds, position.Xy, radius); bounds.AddBound(bound); // снаряд будет быстродвижущимся объектом, для него особый алгоритм определения столкновений bounds.SetAttribute(Strings.CollisionDetectionSpeedType, Strings.CollisionDetectionSpeedTypeFast); damage = DamageAspect.Create(this, 1); //physics = new PhysicsAspect(this, position, Vector2.Zero, 0); //timer = DestroyByTimerAspect.Create(this, new TimeSpan(0, 0, 0, 2, 500)); timer = DestroyByTimerAspect.Create(this, new TimeSpan(0, 0, 0, 1, 0)); this.shellOwner = shellOwner; this.name = "shell"; MessageDispatcher.RegisterHandler(typeof(SetPosition), bounds); MessageDispatcher.RegisterHandler(typeof(SetPosition), graphics); MessageDispatcher.RegisterHandler(typeof(DestroyChildrenOf), this); MessageDispatcher.RegisterHandler(typeof(Kill), this); messageHandler.Handlers.Add(typeof(Kill), HandleKill); }
private static void SendNotCollision(BoundSetAspect boundSet1, BoundSetAspect boundSet2) { MessageDispatcher.Post(new BoundSetNotCollision(boundSet1, boundSet2)); }
private static bool SlowWithFastCollisionDetection(BoundSetAspect slowBoundSet, BoundSetAspect fastBoundSet) { foreach (BoundsAspect bound in slowBoundSet.bounds) { foreach (Triangle<Vector2> stretchedOutlinePart in fastBoundSet.stretchedOutline) { // где-то тут должна быть проверка на пересечение с самим собой, но это вроде бы не возможно if (bound.IntersectsWith(stretchedOutlinePart)) return true; } } return false; }
protected bool IntersectSlowAndFastBounds(BoundSetAspect slowBoundSet, BoundSetAspect fastBoundSet) { // для круглых быстрых объектов границами является вытянутая часть + круг if (fastBoundSet.IAmCircle) { // сначала проверяем вытянутый след if (SlowWithFastCollisionDetection(slowBoundSet, fastBoundSet)) return true; // потом - новое положение круга foreach (BoundsAspect bound in slowBoundSet.bounds) { foreach (BoundsAspect bound2 in fastBoundSet.bounds) { if (bound != bound2) if (bound.IntersectsWith(bound2)) return true; } } return false; } else { return SlowWithFastCollisionDetection(slowBoundSet, fastBoundSet); } }
protected bool IntersectFastAndFastBounds(BoundSetAspect fastBoundSet1, BoundSetAspect fastBoundSet2) { // проверка вытянутых частей // foreach (Triangle<Vector2> stretchedOutlinePart1 in fastBoundSet1.stretchedOutline) { foreach (Triangle<Vector2> stretchedOutlinePart2 in fastBoundSet2.stretchedOutline) { if (Misc.TriangleIntersectsWithTriangle(stretchedOutlinePart1, stretchedOutlinePart2)) return true; } } // для круглых быстрых объектов границами является вытянутая часть + круг if (fastBoundSet1.IAmCircle) { // в данной ситуации у fastBoundSet1 проверяется только его круг со следом fastBoundSet2 if (SlowWithFastCollisionDetection(fastBoundSet1, fastBoundSet2)) return true; } if (fastBoundSet2.IAmCircle) { // в данной ситуации у fastBoundSet2 проверяется только его круг со следом fastBoundSet1 if (SlowWithFastCollisionDetection(fastBoundSet2, fastBoundSet1)) return true; } // прроверка столкновения кругов у обоих объектов // if (fastBoundSet1.IAmCircle && fastBoundSet2.IAmCircle) { // ! всегда считаем, что первый параметр - это this return DiscreteCollisionDetection(fastBoundSet2); } return false; }
protected bool DiscreteCollisionDetection(BoundSetAspect boundSet) { if ((this.position - boundSet.position).LengthFast > this.radius + boundSet.radius) return false; foreach (BoundsAspect bound in this.bounds) { foreach (BoundsAspect bound2 in boundSet.bounds) { if (bound != bound2) if (bound.IntersectsWith(bound2)) return true; } } return false; }
public bool IntersectsWith(BoundSetAspect boundSet) { // первый тик - стандартное определение столкновения if (this.previousContour == null && boundSet.previousContour == null) { return DiscreteCollisionDetection(boundSet); } else { string otherCdSpeedType = null; string thisCdSpeedType = null; BoundSetAspect fastBoundSet = null; BoundSetAspect slowBoundSet = null; if (boundSet.ReflectionAttributes.GetAttribute(Strings.CollisionDetectionSpeedType, out otherCdSpeedType) && this.ReflectionAttributes.GetAttribute(Strings.CollisionDetectionSpeedType, out thisCdSpeedType)) { // медленный - быстрый // if (otherCdSpeedType == Strings.CollisionDetectionSpeedTypeFast && thisCdSpeedType == Strings.CollisionDetectionSpeedTypeSlowOrStatic) { slowBoundSet = this; fastBoundSet = boundSet; bool result = IntersectSlowAndFastBounds(slowBoundSet, fastBoundSet); return result; } // быстрый - медленный // if (otherCdSpeedType == Strings.CollisionDetectionSpeedTypeSlowOrStatic && thisCdSpeedType == Strings.CollisionDetectionSpeedTypeFast) { slowBoundSet = boundSet; fastBoundSet = this; bool result = IntersectSlowAndFastBounds(slowBoundSet, fastBoundSet); return result; } // медленный - медленный // if (otherCdSpeedType == Strings.CollisionDetectionSpeedTypeSlowOrStatic && thisCdSpeedType == Strings.CollisionDetectionSpeedTypeSlowOrStatic) { return DiscreteCollisionDetection(boundSet); } // быстрый - быстрый // return IntersectFastAndFastBounds(this, boundSet); } else // непонятно, какой тип - считаем обычными дискретными объектами { return DiscreteCollisionDetection(boundSet); } #region Old //ICollection<ICollection<Vector2>> myNotExcludedParts = new LinkedList<ICollection<Vector2>>(); //ICollection<ICollection<Vector2>> otherNotExcludedParts = new LinkedList<ICollection<Vector2>>(); //foreach (Triangle<Vector2> stretchedOutlinePart in stretchedOutline) //{ // // каждый раз получаем массив контуров, из которых состоит разница нового и старого контуров // // stretchedOutline - это набор треугольников, поэтому их разность с исходным контуром не должна, по идее, давать полигоны с дырками // // поэтому каждую полученную часть можно триангулировать // foreach (var triangle in this.Triangulated) // { // // возвращается коллекция полигонов // ICollection<ICollection<Vector2>> differencePart = // WeilerAtherton.Process( // new CircularLinkedList<Vector2>(stretchedOutlinePart), // new CircularLinkedList<Vector2>(previousContour, true), // Operation.Difference); // if (differencePart.Count != 0) // foreach (var part in differencePart) // myNotExcludedParts.Add(part); // } //} //foreach (Triangle<Vector2> stretchedOutlinePart in boundSet.stretchedOutline) //{ // // каждый раз получаем массив контуров, из которых состоит разница нового и старого контуров // // stretchedOutline - это набор треугольников, поэтому их разность с исходным контуром не должна, по идее, давать полигоны с дырками // // поэтому каждую полученную часть можно триангулировать // // возвращается коллекция полигонов // ICollection<ICollection<Vector2>> differencePart = // WeilerAtherton.Process( // new CircularLinkedList<Vector2>(stretchedOutlinePart), // new CircularLinkedList<Vector2>(boundSet.previousContour, true), // Operation.Difference); // if (differencePart.Count != 0) // foreach (var part in differencePart) // otherNotExcludedParts.Add(part); //} ////stretchedOutline - previousContour #endregion } return false; }
public static BoundSetAspect Create(object owner, IList<Vector3> vertices) { BoundSetAspect aspect = new BoundSetAspect(owner, vertices); aspect.RegisterAllStuff(); aspect.SetAttribute(Strings.CollisionDetectionSpeedType, Strings.CollisionDetectionSpeedTypeSlowOrStatic); return aspect; }