/* Separa la pelota según la información en mtv. */ private void Separate(MinimumTranslationVector mtv) { /* Calculo el vector de la separación. */ Vector displacement = mtv.axis.NewWithLength(mtv.overlap); /* Le sumo este vector a la posición de la pelota. */ this.lastPosition = this.position.Copy(); this.position.Sum(displacement); }
/* Función estática que recibe dos polígonos y aplica el teorema SAT. Devuelve un * vector de traslación mínimo con la información de la colisión. Si ese vector es null, * no ha habido colisión; si tiene valor, la ha habido. */ private static MinimumTranslationVector SATCollision(Polygon polygon1, Polygon polygon2) { /* Declaro el resultado del algoritmo, un vector de traslación mínimo. */ MinimumTranslationVector result = new MinimumTranslationVector(); List <Vector> axes = new List <Vector>(); Vector axisWithMinOverlap = null; double minOverlap = double.MaxValue; /* Añado los ejes del primer polígono. */ for (int i = 0; i < polygon1.Yaxes.Count; i++) { axes.Add(polygon1.Yaxes[i]); } /* Añado los ejes del segundo polígono. */ for (int j = 0; j < polygon2.Yaxes.Count; j++) { axes.Add(polygon2.Yaxes[j]); } /* Recorro cada eje. */ Projection polygon1Projection; Projection polygon2Projection; double overlap; for (int k = 0; k < axes.Count; k++) { /* Obtengo las proyecciones de cada figura. */ polygon1Projection = new Projection(axes[k], polygon1); polygon2Projection = new Projection(axes[k], polygon2); /* Compruebo si se solapan. */ overlap = Projection.Overlap(polygon1Projection, polygon2Projection); if (overlap == 0) { /* No hay solapamiento entre estas dos proyecciones, por * tanto no hay solapamiento. */ result.axis = null; result.overlap = 0; return(result); } else if (overlap < minOverlap) { /* Me quedo con este. */ minOverlap = overlap; axisWithMinOverlap = axes[k]; } } /* No ha habido separación en ningún eje, así que hay colisión * y devolvemos el mtv relleno con los mejores valores. */ result.axis = axisWithMinOverlap.Copy(); result.overlap = minOverlap; return(result); }
/* Comprueba que el eje que marca mtv apunta desde el polígono hacia la pelota, * para sacarla hacia afuera. */ private void CheckSATAxisDirection(MinimumTranslationVector mtv, Polygon polygon) { /* Calculo un vector desde el centroide de la pelota hasta el centroide * del polígono. */ Vector ballDirection = Vector.Subtract(polygon.Centroid, this.position); ballDirection.Normalize(); if (Vector.DotProduct(mtv.axis, ballDirection) > 0) { /* Ambos vectores van en la misma dirección, así que * hay que cambiar el eje de mtv de sentido. */ mtv.axis.X *= -1; mtv.axis.Y *= -1; } }
/* Recibe un vector de traslación mínimo procedente del SAT y un polígono, * y tiene que rebotar del polígono según el valor del vector. */ public void Bounce(MinimumTranslationVector mtv, Polygon polygon) { /* Compruebo que el eje del mtv es el que lleva * la bola hacia afuera del polígono. */ this.CheckSATAxisDirection(mtv, polygon); /* Primero separo la pelota del polígono la cantidad * requerida por mtv. */ this.Separate(mtv); /* Reflejo la velocidad sobre el eje mtv. */ this.Deflect(mtv.axis); /* Compruebo que la velocidad no se ha salido de los límites. */ this.CheckVelocityLimit(); }
/* Gestiona la colisión de este polígono con una pelota, aplicando * el teorema SAT. */ public bool HandleCollisionSAT(Ball ball) { /* Actualizamos el polígono de colisión de la pelota. */ ball.UpdateCollisionPolygon(); /* Aplico el teorema de separación de ejes y guardo el resultado en mtv. */ MinimumTranslationVector mtv = SATCollision(this, ball.Polygon); if (mtv.MeansCollision()) { /* El resultado de SAT es una colisión, así que tenemos que rebotar la * pelota de este polígono. */ Console.WriteLine(DateTime.UtcNow + " voy a aplicar bounce"); ball.Bounce(mtv, this); return(true); } return(false); }