@Papst: Hast du ne ungefähre Ahnung nach was ich suchen könnte um das zu finden?
Ankündigung
Einklappen
Keine Ankündigung bisher.
[Erledigt] 2D schlagschatten berechnen
Einklappen
Neue Werbung 2019
Einklappen
X
-
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 === 0 && $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;
}
}
?>
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), $obstacles, true);
$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>";
?>
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
-
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
closedWer misst, misst Mist.
Kommentar
Kommentar