Tips matemáticos de geometría para programación de videojuegos

danii . jueves 8 de noviembre de 2012. a las 11:58

Tips matemáticos para programación de videojuegos

A la hora de programar un videojuego (o muchos proyectos de corte más visual/interactivo) es casi imposible que no necesitemos echar mano de ciertas fórmulas matemáticas (más concretamente geométricas) para comparar las posiciones relativas de nuestros elementos gráficos en la pantalla. La geometría en dos dimensiones es relativamente sencilla pero aún así en este post presento un ejemplo que sin ser muy complicado echa mano de una serie de fórmulas que quizás no recordemos de memoria (sobre todo la última).

Ejemplo en funcionamiento: Puedes arrastrar el robot, o cualquiera de las cuatro estrellas que conforman los «bordes». El robot se encarará hacia el «borde» más cercano

Get Adobe Flash player

  • Ángulo entre dos puntos. Es muy sencillo de calcular gracias a la función atan2, una variante muy útil de la arcotangente y que se encuentra presente en la mayoría de lenguajes de programación (o librerías matemáticas, en su defecto). Cuidado con el único gotcha que tiene esta función, y es que se debe pasar como primer parámetro la coordenada y del punto, y como segundo la coordenada x, al contrario que en casi todas las demás funciones del universo conocido.

    
    		//ángulo en grados entre dos puntos
    		private function rotationDegreesTwoPoints(p1:Point, p2:Point):Number
    		{
    			return 180*Math.atan2(p2.y - p1.y, p2.x- p1.x)/Math.PI;
    		}
    
    
  • Distancia entre dos puntos. La fórmula de la distancia euclídea debería ser de sobras conocida por todos. Tan sólo un apunte de optimización: si podemos, hemos de evitar computar la raíz cuadrada, ya que es una operación bastante costosa de calcular para el procesador. Por ejemplo, si lo que queremos es comparar distancias para ver qué elementos están más cerca o más lejos, no será necesario en absoluto computar las raíces cuadradas de todos los valores, ya que los órdenes relativos se mantienen al elevar al cuadrado. En notación matemática chapucera se podría expresar así:

    (x > y) <-> (x*x > y*y)

    Si queremos medir un radio de alcance o valor umbral para algún efecto, podemos operar todo el tiempo con el radio/umbral al cuadrado (pre calculado) para ahorrarnos la molesta raíz cuadrada.

    
      //elevar nuúmero al cuadrado (más rápido que pow)
      function sqr(x:Number):Number
      { 
        return x * x; 
      }
    		
      //Distancia enter dos puntos (al cuadrado)
      function distBetweenPointsSquared(v:Point, w:Point):Number
      { 
        return sqr(v.x - w.x) + sqr(v.y - w.y);
      }
    
    
  • A partir de esta fórmula podemos construir otra que también resulta muy útil, Distancia entre punto y segmento. Como en el caso anterior, evitaremos computar la raíz cuadrada y devolveremos el valor de la distancia al cuadrado. Es bastante más complicada ya que tenemos que contemplar todas las posibilidades:

    
      //distancia mínima entre punto p y segmento vw
      function distToSegmentSquared(p:Point, v:Point, w:Point):Number
      {
        var longSeg:Number = distBetweenPointsSquared(v, w);
    
        if (longSeg == 0) return distBetweenPointsSquared(p, v);
    
        var t:Number = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / longSeg;
    
        if (t < 0) return distBetweenPointsSquared(p, v);
    
        if (t > 1) return distBetweenPointsSquared(p, w);
    
        return distBetweenPointsSquared(p, 
          new Point(
            v.x + t * (w.x - v.x),
            v.y + t * (w.y - v.y)) 
          );
      }
    

Aunque las funciones que presento están en ActionScript 3, son triviales de portar a otros lenguajes con sintaxis similar como JavaScript, Java o C++. ¡Espero que os resulten útiles!

Etiquetas: , , , ,

6 Comentarios
» Feed RSS de los Comentarios

  1. antuansoft dice:

    Un gran trabajo!!! gracias por estas notas y sobre todo por los ejemplos.

    Gracias!!!

  2. Marcos dice:

    Grandes!!

    Me habéis recordado las buenas batallas con las tangentes en las detecciones para colisiones de objetos circulares. El ángulo entre dos puntos con atan2 es mítico… y super útil!!

  3. Carlos dice:

    Sencillamente genial!!! los ejemplos son muy praticos, y van derecho a mis funciones de uso comun

  4. alfonsofonso dice:

    downloading source…

  5. danii dice:

    Gracias a todos por el feedback, me alegro mucho que os hayan parecido útiles los ejemplos y el código fuente, que realmente es el alma de este post. Tras la buena acogida, creo que miraré de escribir más posts de este estilo… que así da gusto leñe 😉

    jajaj Marcos me he reído mucho con lo de «batallas», la verdad es que casi siempre que toco algo de matemática angular, rotaciones etc son unas peleas absurdas, entre los ángulos en radianes o grados, medidos de 0 a 360 o de -PI a PI, que los tweenings de rotaciones vayan en el sentido correcto y no dando toda la vuelta absurdamente… en fin, para qué decir más, batallitas!!

  6. alejandro dice:

    oigan me prodian apoyar con codigos o ejemplos para hacer calculos de derivada de calculo diferencial en flash8

Enviar comentario