Ankündigung

Einklappen
Keine Ankündigung bisher.

[Erledigt] 2D schlagschatten berechnen

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • #16
    @Papst: Hast du ne ungefähre Ahnung nach was ich suchen könnte um das zu finden?
    Wer misst, misst Mist.

    Kommentar


    • #17
      ahh cool dankem hab auch gesucht bis gerade ... da haste das wohl schon geschrieben als ich gerade fragen wollte

      vielen dank
      Wer misst, misst Mist.

      Kommentar


      • #18
        Leider ist die Lösung etwas ungenau für meine Verwendungszwecke.

        Ich werde wohl doch die winkel berechnen müssen und diese dann umständlich in x und y Versatz für jede Schattenseite quantisieren.
        Wer misst, misst Mist.

        Kommentar


        • #19
          Hab mich mal selbst dran versucht.
          Es scheint zu funktionieren. Habe es ein wenig getestet und hab noch keine Fehler gefunden.

          Allerdings ist der Quelltext wohl alles andere als übersichtlich und sicher alles andere als optimal.

          Aber Hauptsache es funzt.

          MapShadow.class.php
          PHP-Code:
          <?php

          class MapShadow
          {
              private 
          $view_x;
              private 
          $view_y;
              private 
          $shadow_start;     // Liste der Start-Winkel
              
          private $shadow_end;       // Liste der End-Winkel
              
          private $shadow_distance;  // Liste der Entfernungen
              
          private $shadow_num;

              public function  
          __construct($view_x$view_y)
              {
                  if( !
          is_int($view_x) || !is_int($view_y) )
                      throw new 
          InvalidArgumentException("Argumente 1 und 2 muessen vom Typ Integer sein.");

                  
          $this->view_x $view_x;
                  
          $this->view_y $view_y;

                  
          $this->shadow_start = array();
                  
          $this->shadow_end = array();
                  
          $this->shadow_distance = array();
              }

              public function 
          addObstacle($x$y)
              {
                  if( !
          is_int($x) || !is_int($y) )
                      throw new 
          InvalidArgumentException("Argumente 1 und 2 muessen vom Typ Integer sein.");

                  
          $delta_x $x $this->view_x;
                  
          $delta_y $y $this->view_y;

                  
          // Die beiden entscheidenen Ecken des Hindernis ermitteln
                  
          if($delta_x 0) {
                      if(
          $delta_y 0) {
                          
          // Quadrant oben links
                          
          $edge1_x $delta_x 0.5;
                          
          $edge1_y $delta_y 0.5;
                          
          $edge2_x $delta_x 0.5;
                          
          $edge2_y $delta_y 0.5;
                      }
                      else if(
          $delta_y 0) {
                          
          // Quadrant unten links
                          
          $edge1_x $delta_x 0.5;
                          
          $edge1_y $delta_y 0.5;
                          
          $edge2_x $delta_x 0.5;
                          
          $edge2_y $delta_y 0.5;
                      }
                      else {
                          
          // Horizontale links (Sonderfall: $edge1_angle > $edge2_angle)
                          
          $edge1_x $edge2_x $delta_x 0.5;
                          
          $edge1_y $delta_y 0.5;
                          
          $edge2_y $delta_y 0.5;
                      }
                  }
                  else if(
          $delta_x 0) {
                      if(
          $delta_y 0) {
                          
          // Quadrant oben rechts
                          
          $edge1_x $delta_x 0.5;
                          
          $edge1_y $delta_y 0.5;
                          
          $edge2_x $delta_x 0.5;
                          
          $edge2_y $delta_y 0.5;
                      }
                      else if(
          $delta_y 0) {
                          
          // Quadrant unten rechts
                          
          $edge1_x $delta_x 0.5;
                          
          $edge1_y $delta_y 0.5;
                          
          $edge2_x $delta_x 0.5;
                          
          $edge2_y $delta_y 0.5;
                      }
                      else {
                          
          // Horizontale rechts
                          
          $edge1_x $edge2_x $delta_x 0.5;
                          
          $edge1_y $delta_y 0.5;
                          
          $edge2_y $delta_y 0.5;
                      }
                  }
                  else {
                      if(
          $delta_y 0) {
                          
          // Vertikale oben
                          
          $edge1_x $delta_x 0.5;
                          
          $edge2_x $delta_x 0.5;
                          
          $edge1_y $edge2_y $delta_y 0.5;
                      }
                      else if(
          $delta_y 0) {
                          
          // Vertikale unten
                          
          $edge1_x $delta_x 0.5;
                          
          $edge2_x $delta_x 0.5;
                          
          $edge1_y $edge2_y $delta_y 0.5;
                      }
                      else
                          throw new 
          InvalidArgumentException("Argument darf nicht dem Blickpunkt entsprechen.");
                  }

                  
          // Entfernungen berechnen
                  
          $center_distance sqrt$delta_x $delta_x $delta_y $delta_y );
                  
          $edge1_distance sqrt$edge1_x $edge1_x $edge1_y $edge1_y );
                  
          $edge2_distance sqrt$edge2_x $edge2_x $edge2_y $edge2_y );

                  
          // Winkel berechnen (-180°;180°] bzw. (-pi;pi] (Polarkoordinaten)
                  
          $edge1_angle acos($edge1_x $edge1_distance);
                  
          $edge2_angle acos($edge2_x $edge2_distance);
                  if(
          $edge1_y 0$edge1_angle *= -1;
                  if(
          $edge2_y 0$edge2_angle *= -1;

                  
          // Abschliessen
                  
          if($edge1_angle $edge2_angle) {
                      
          // Sonderfall (Horizontale links)
                      
          $this->shadow_start[] = $edge1_angle;
                      
          $this->shadow_end[] = 3.15// Pi
                      
          $this->shadow_distance[] = $center_distance;

                      
          $this->shadow_start[] = -3.15// -Pi
                      
          $this->shadow_end[] = $edge2_angle;
                      
          $this->shadow_distance[] = $center_distance;

                      
          $this->shadow_num += 2;
                  }
                  else {
                      
          $this->shadow_start[] = $edge1_angle;
                      
          $this->shadow_end[] = $edge2_angle;
                      
          $this->shadow_distance[] = $center_distance;

                      
          $this->shadow_num++;
                  }

                  return 
          true;
              }


              public function 
          isVisible($x$y)
              {
                  if( !
          is_int($x) || !is_int($y) )
                      throw new 
          InvalidArgumentException("Argumente 1 und 2 muessen vom Typ Integer sein.");

                  
          $delta_x $x $this->view_x;
                  
          $delta_y $y $this->view_y;

                  if(
          $delta_x === && $delta_y === 0)
                      return 
          true;

                  
          // Entfernung ermitteln
                  
          $distance sqrt($delta_x $delta_x $delta_y $delta_y);

                  
          // Winkel ermitteln
                  
          $angle acos($delta_x $distance);
                  if(
          $delta_y 0$angle *= -1;

                  
          // Teste, ob Feld im Schatten liegt
                  
          $boundary_point false;
                  
          $visible true;
                  for(
          $i=0$i<$this->shadow_num$i++)
                  {
                      if( (
          $angle $this->shadow_start[$i]) || ($angle $this->shadow_end[$i]) )
                          continue;

                      if( 
          $distance $this->shadow_distance[$i] )
                          continue;

                      if( (
          $angle == $this->shadow_start[$i]) || ($angle == $this->shadow_end[$i]) ) {
                          
          // Beruehrpunkt
                          
          if($boundary_point === true) {
                              
          $visible false;
                              break;
                          }
                          
          $boundary_point true;
                          continue;
                      }

                      
          $visible false;
                      break;
                  }

                  return 
          $visible;
              }

          }

          ?>
          beispiel.php
          PHP-Code:
          <?php

          require "MapShadow.class.php";

          // Beispieldatensatz #1 aus Datenbank
          $obstacles = array(
              array(-
          2,-1),
              array(-
          2,0),  // Sonderfall Test
              
          array(-2,2),
              array(-
          1,2),
              array(
          1,0)
          );

          // Beispieldatensatz #2 aus Datenbank
          $obstacles = array(
              array(-
          3,-2),  // Boundary Point Test
              
          array(-2,-3),  // Boundary Point Test
              
          array(1,-1),
              array(
          1,0),
              array(
          2,0),
              array(
          1,3),
              array(-
          2,1),
              array(-
          2,2)
          );

          $player_x 0;
          $player_y 0;

          $map = new MapShadow($player_x$player_y);  // Blickpunkt im Mittelpunkt der Map (die Position des Spielers)

          foreach($obstacles as $item)
              
          $map->addObstacle($item[0], $item[1]);


          echo 
          "<pre>";

          for(
          $y=-20$y<=20$y++)
          {
              for(
          $x=-20$x<=20$x++)
              {
                  
          $is_visible $map->isVisible($x$y);
                  
          $is_obstacle in_array( array($x$y), $obstaclestrue);
                  
          $is_view = ($x == $player_x && $y == $player_y);

                  
          $char " ";
                  if(!
          $is_visible$char "X";
                  if(
          $is_obstacle$char "#";
                  if(
          $is_view$char ".";

                  echo 
          $char" ";
              }

              echo 
          "\n";
          }

          echo 
          "</pre>";

          ?>
          //EDIT: Im Konstruktor ist noch ein Fehler. So muss es sein:

          PHP-Code:
              public function  __construct($view_x$view_y)
              {
                  if( !
          is_int($view_x) || !is_int($view_y) )
                      throw new 
          InvalidArgumentException("Argumente 1 und 2  muessen vom Typ Integer sein.");

                  
          $this->view_x $view_x;
                  
          $this->view_y $view_y;

                  
          $this->shadow_start = array();
                  
          $this->shadow_end = array();
                  
          $this->shadow_distance = array();

                  
          $this->shadow_num 0;
              } 
          Angehängte Dateien

          Kommentar


          • #20
            Uff wollte gerade meine Lösung zeigen und mich hier ein wenig wichtig machen, aber das traue ich mich jetzt nichtmehr ^^
            Werde in jedem Fall deine Lösung testen denn die ist auf den ersten Blick sehr viel besser.

            Ich habe einfach die winkel genommen und den versatz berechnet und damit dann die schatten ausgegeben. Ist bei mir aber die endlange if elseif liste, die dann den Versatz je Schattenkante ausgibt .. da kommt mir deine Programmierung schon entgegen.

            Vielen Dank
            wird umgesetzt
            closed
            Wer misst, misst Mist.

            Kommentar

            Lädt...
            X