/// <summary> /// Construye un circulo según las opciones dadas /// </summary> /// <param name="id">Id del body</param> /// <param name="owner">Owner del body</param> /// <param name="isSolid">Si el body es sólido</param> /// <param name="relativeToFacing">Determina si se debe tomar en cuenta la dirección /// a la que está mirando la entidad para posicionar el body /// relativo a esa dirección</param> /// <param name="radius">Radio del circulo</param> /// <returns>Circulo generado</returns> public static Sphere CreateCircle(string id, IEntity owner, bool isSolid, bool relativeToFacing, float radius) { Sphere sphere = new Sphere(id, Vector2.Zero, radius, owner, isSolid); if (relativeToFacing) { bool facingRight = owner.getState(EntityState.FacingRight); if (facingRight != true) { sphere.MirrorHorizontal(owner.getVectorProperty(EntityProperty.Position)); } } return sphere; }
/// <summary> /// Verifica si este poligono esta colisionando o va a colisionar /// con una esféra dada. /// Para esto se ubica el punto centro de la esfera en la región de voronoi /// que le corresponde según el poligono, de forma que obtenemos el punto /// mas cercano de la esfera al poligono junto al respectivo eje. /// </summary> /// <param name="sphere">Esféra con la cual se hará la verificacion</param> /// <param name="distance">Distancia por la cual se movera este poligono</param> /// <param name="result">Referencia del objeto que contendrá la información necesaria sobre /// si se esta intersectando, si se intersectará y la distancia necesaria /// para evitar una intersección</param> protected override CollisionResult IntersectWithSphere(Sphere sphere, ref Vector2 distance) { CollisionResult result = new CollisionResult(); result.triggeringBody = this; result.affectedBody = sphere; // Empezamos asumiendo que las dos figuras no // se encuentran intersectando result.intersect = false; result.willIntersect = false; // Se toman tanto la cantidad de puntos // como la cantidad de lados del poligono int sideCountPolygon = this.sides.Count; int pointCountPolygon = this.vertices.Count; // Dos valores distintos para guardar float minIntervalDistanceAfterMove = float.PositiveInfinity; float minIntervalDistance = float.PositiveInfinity; Vector2 translationAxis = new Vector2(); // Ahora se estudia cada lado del poligono para verificar si el centro // de la esfera se encuentra perpendicular a algun punto de ese lado for (int sideIndex = 0; sideIndex < sideCountPolygon; sideIndex++) { Line currentSide = this.sides[sideIndex]; // Se crea un vector paralelo al lado donde puedan proyectase // ambos puntos del lado actual mas el centro de la esfera Vector2 axis = new Vector2(currentSide.Edge.X, currentSide.Edge.Y); axis.Normalize(); float minA = Vector2.Dot(axis, currentSide.StartPoint); float maxA = Vector2.Dot(axis, currentSide.EndPoint); float centerB = Vector2.Dot(axis, sphere.Center); float velocityProjection = Vector2.Dot(axis, distance); // Se realiza un chequeo preliminar antes de sumar el vector // de distancia #region Verificaciones de intersección actual // Si el punto centro se encuentra perpendicular a algun // punto del lado actual, entonces la esfera puede encontrarse en esa region if (minA <= centerB && maxA >= centerB) { // Creamos un eje perpendicular a la linea para obtener la distancia // entre un punto de la linea y el centro de la esfera axis = new Vector2(-currentSide.Edge.Y, currentSide.Edge.X); axis.Normalize(); // Ya que el eje es perpendicular, tanto el punto inicial de la linea // como el final terminan en la misma posicion al ser proyectados float pointA = Vector2.Dot(axis, currentSide.EndPoint); float pointB = Vector2.Dot(axis, sphere.Center); // Se obtiene el intervalo y se guarda en caso de que sea menor // al intervalo anterior (La esfera se encontrara en la region de voronoi // que tenga el punto mas cercano desde la esfera hacia el poligono) float intervalDistance = Math.Abs(pointA - pointB); if (intervalDistance < minIntervalDistance) { minIntervalDistance = intervalDistance; } } #endregion // Aplicamos la proyeccion de velocidad a el lado actual if (velocityProjection < 0) { minA += velocityProjection; } else { maxA += velocityProjection; } // Si el punto centro se encuentra perpendicular a algun // punto del lado actual, entonces la esfera puede encontrarse en esa region if (minA <= centerB && maxA >= centerB) { // Creamos un eje perpendicular a la linea para obtener la distancia // entre un punto de la linea y el centro de la esfera axis = new Vector2(-currentSide.Edge.Y, currentSide.Edge.X); axis.Normalize(); // Volvemos a aplicar la proyeccion de velocidad puesto que // esta vez estamos proyectando en un diferente eje velocityProjection = Vector2.Dot(axis, distance); // Ya que el eje es perpendicular, tanto el punto inicial de la linea // como el final terminan en la misma posicion al ser proyectados float pointA = Vector2.Dot(axis, currentSide.EndPoint) + velocityProjection; float pointB = Vector2.Dot(axis, sphere.Center); // Se obtiene el intervalo y se guarda en caso de que sea menor // al intervalo anterior (La esfera se encontrara en la region de voronoi // que tenga el punto mas cercano desde la esfera hacia el poligono) float intervalDistance = Math.Abs(pointA - pointB); if (intervalDistance < minIntervalDistanceAfterMove) { minIntervalDistanceAfterMove = intervalDistance; translationAxis = axis; Vector2 d = this.Center - sphere.Center; if (Vector2.Dot(d, translationAxis) < 0) { translationAxis = -translationAxis; } } } } // Luego se estudia la distancia entre cada vertice del poligono // contra el centro de la esfera, si se encuentra alguna distancia // menor que las ya guardadas entonces se guarda for (int pointIndex = 0; pointIndex < pointCountPolygon; pointIndex++) { Vector2 currentPoint = this.vertices[pointIndex]; // Creamos una linea que vaya desde el vertice hasta el centro // de la esfera, sumandole el vector de distancia al vertice Line line = new Line(currentPoint + distance, sphere.Center); Vector2 axis = new Vector2(line.Edge.X, line.Edge.Y); axis.Normalize(); if (line.Lenght < minIntervalDistanceAfterMove) { minIntervalDistanceAfterMove = line.Lenght; translationAxis = axis; Vector2 d = this.Center - sphere.Center; if (Vector2.Dot(d, translationAxis) < 0) { translationAxis = -translationAxis; } } // Misma verificacion sin sumar el vector de distancia #region Verificaciones de intersección actual line = new Line(currentPoint, sphere.Center); axis = new Vector2(line.Edge.X, line.Edge.Y); axis.Normalize(); if (line.Lenght < minIntervalDistance) { minIntervalDistance = line.Lenght; } #endregion } // Se verifica si el poligono intersecta bool isInside = this.PointInBody(sphere.Center); if (isInside || minIntervalDistance < sphere.Radius) { result.intersect = true; } // Se verifica si intersectaran y aplica un vector de transicion // diferente dependiendo de si el centro de la esfera se encuentra // dentro o fuera del poligono isInside = this.PointInBody(sphere.Center - distance); if (isInside) { result.minimumTranslationVector = translationAxis * (sphere.Radius + minIntervalDistanceAfterMove); result.willIntersect = true; } else if (minIntervalDistanceAfterMove < sphere.Radius) { result.minimumTranslationVector = translationAxis * Math.Abs(sphere.Radius - minIntervalDistanceAfterMove); result.willIntersect = true; } result.translationAxis = translationAxis; return result; }
/// <summary> /// Construye un circulo según las opciones dadas /// </summary> /// <param name="id">Id del body</param> /// <param name="owner">Owner del body</param> /// <param name="isSolid">Si el body es sólido</param> /// <param name="relativeToFacing">Determina si se debe tomar en cuenta la dirección /// a la que está mirando la entidad para posicionar el body /// relativo a esa dirección</param> /// <param name="radius">Radio del circulo</param> /// <param name="startPosition">Coordenadas de inicio del body</param> /// <param name="startCenter">Determina si las coordenadas de inicio se refieren /// al punto de inicio desde donde se crea el body o al centro del mismo</param> /// <param name="layer">Capa de colisión donde se encontrará el body</param> /// <returns>Circulo generado</returns> public static Sphere CreateCircle(string id, IEntity owner, bool isSolid, bool relativeToFacing, float radius, Vector2 startPosition, bool startCenter, float layer) { if (startCenter) { startPosition.X -= radius; startPosition.Y -= radius; } Sphere sphere = new Sphere(id, startPosition, radius, owner, isSolid); sphere.Layer = layer; if (relativeToFacing) { bool facingRight = owner.getState(EntityState.FacingRight); if (facingRight != true) { sphere.MirrorHorizontal(owner.getVectorProperty(EntityProperty.Position)); } } return sphere; }
/// <summary> /// Verifica si este cuerpo esta colisionando o va a colisionar /// con una esféra dada /// </summary> /// <param name="sphere">Esféra con la cual se hará la verificacion</param> /// <param name="distance">Distancia por la cual se movera este cuerpo</param> /// <param name="result">Referencia del objeto que contendrá la información necesaria sobre /// si se esta intersectando, si se intersectará y la distancia necesaria /// para evitar una intersección</param> protected abstract CollisionResult IntersectWithSphere(Sphere sphere, ref Vector2 distance);
/// <summary> /// Verifica si esta esfera esta colisionando o va a colisionar /// con otra esféra dada /// </summary> /// <param name="sphere">Segunda esféra con la cual se hará la verificacion</param> /// <param name="distance">Distancia por la cual se movera la esfera principal (this)</param> /// <param name="result">Referencia del objeto que contendrá la información necesaria sobre /// si se esta intersectando, si se intersectará y la distancia necesaria /// para evitar una intersección</param> protected override CollisionResult IntersectWithSphere(Sphere sphere, ref Vector2 distance) { CollisionResult result = new CollisionResult(); result.triggeringBody = this; result.affectedBody = sphere; float distanceBetween = 0; distanceBetween = Vector2.Distance(this.center, sphere.center); result.intersect = distanceBetween < this.radius + sphere.radius; distanceBetween = Vector2.Distance(this.center, sphere.center + distance); result.willIntersect = distanceBetween < this.radius + sphere.radius; if (result.willIntersect) { Vector2 translationAxis = new Vector2((this.center.X) - (sphere.center.X + distance.X), (this.center.Y) - (sphere.center.Y + distance.Y)); translationAxis = Vector2.Normalize(translationAxis); result.translationAxis = translationAxis; result.minimumTranslationVector = translationAxis * ((this.radius + sphere.radius) - distanceBetween); } return result; }