Bildausschnitt anzeigen lassen

Joe

Erfahrenes Mitglied
Guten Abend.

Da mir das grundsätzliche Verständniss zum Aufbau einer Karte fehlt mache ich mir grad theoretische Gedanken wie ich das ganze am besten angehen kann.
Folgendes:
Ich habe mir mir eine relativ grosse Map mit dem Programm L3DT erstellt und möchte nur einen Teil der Karte anzeigen lassen.

Jeder User bekommt bereits automatisch per Random eine x/y Position zugewiessen welche in der DB entsprechend eingetragen wird.
Dabei ist das "Spielfeld" 200*200 gross.

Jetzt zu meinem Überlegungen wie ich den Ausschnitt realisieren könnte.
Ich lese aus der DB die entsprechende POS des Users aus zb. 50/50. Die Grund oder Hintergrundkarte/png hat eine grösse von 2000x2000 Pixel. Das ergibt eine einzelne Feldgrösse von 10*10 Pixel. Also wäre der Mittelpunkt des Auschnittes bei 500x500 Pixel zu finden. Das DIV in dem der Auschnitt angezeigt wird soll (alles theoretisch) 400x400 Pixel gross sein. Davon liegt der Mittelpunkt bei 200x200.
Die Diffrenz davon ist also den User Mittelpunk dazu zu rechnen bzw abzuziehen um den relevanten Ausschnitt zu bekommen.

POS 50/50 x 10/10 = 500x 500y
Oben links = 500/500 -200/-200 = 300/300
Unten rechts= 500/500 +200/+200 = 700/700

Der Auschnitt wäre also bei 300/300 bis 700/700 Pixel

Soweit so gut leider weiss ich aber nicht wie ich diesen Bereich der Karte.png nun darstellen kann also welcher Befehl schneidet mir nun den Teil aus?
Ich dachte an Imagecopy allerdings komm ich mit der Syntax nicht ganz klar wie könnte der Befehl mit Syntax auf das BSP heissen?


Tut mir leid wenn ich mich so umständlich ausgedrückt habe gans so einfach ist das Thema für mich nicht.
Vielen dank fürs helfen.

________________

Habe nun erstmal folgenden Code zum anzeigen irgendeines Ausschnitts:
PHP:
<div id=content>

<?php
error_reporting(E_ALL);
$size = array(543,432); // Breite und Höhe des Auschnitts
$point = array(100,100); // Koordinaten, ab wo kopiert werden soll (erst X, dann Y).
$image = imagecreatefromjpeg("img/MAP1.jpg"); // Original einlesen
$new = imagecreatetruecolor($size[0],$size[1]); // Neues Bild leer erstellen
imagecopyresized($new, $image, 0,0, $point[0],$point[1],$size[0],$size[1], $size[0],$size[1]); // Ausschnitt rüberkopieren
imagejpeg($new,"img/neu.jpg",100); // Neues Bild speichern
echo "<img src=("img/neu.jpg")>";
?>


</div>
GD ist bereits installiert.
Aber das Bild neu.jpg wird garnicht erst erstellt, jedenfalls ist es nicht auf dem Server zu finden. Eine Fehlermeldung kommt auch nicht.
Ich habe vor das Bild nach dem Skript über CSS einzubinden oder mit dem img-Tag anzeigen zu lassen ich hoffe dafür benötigt es kein Header denn den nach zig Html aufrufen und Includes würde ich es nicht gebacken bekommen.

Aber wieso wird erst gar kein Bild neu erstellt und auf dem Server abgespeichert?
 
Zuletzt bearbeitet:
Von der ganzen Karte soll nur ein 400 Pixel im Quadrat großer Ausschnitt angezeigt werden?
Warum so einen rechenintensiven Prozess über die GD Lib?
Reicht es nicht mit einer dynamisch zugewiesenen Werten für die CSS Eigenschaft background-position zu arbeiten?
 
Also meine bisherige Lösung sieht nun so aus:
PHP:
<div id=content>
<div id=mappic>
<?php
error_reporting(E_ALL);
$size = array(543,432); // Breite und Höhe des Auschnitts (entspricht meinem Div)
$point = array($UserMapX*10-5,$UserMapY*10-5); // Koordinaten, ab wo kopiert werden soll (erst X, dann Y) abhängig von den Userkords.
$image = imagecreatefromjpeg("img/MAP1.jpg") ; // Original einlesen
$new = imagecreatetruecolor($size[0],$size[1]); // Neues Bild leer erstellen
imagecopyresampled($new, $image, 0,0, $point[0],$point[1],$size[0],$size[1], $size[0],$size[1]); // Ausschnitt rüberkopieren
imagejpeg($new,"img/neu.jpg",100); // Neues Bild speichern
echo "<img src='img/neu.jpg'>"; // Bild anzeigen
?>
</div>
</div>
Das ist auch soweit ganz ok und funktioniert soweit (weiss jetzt nicht wie es aussieht wenn man die Pos1/1 hätte)

@Spelman:
Ja wie gesagt ich hatte gar keine Idee wie ich so eine Karte verwirklichen kann. Wie rechenintensiv das ganze nun ist im Gegensatz zu einer CSS-Variante weiss ich nicht. Ein Kartenauschnitt auf obrige Weisse hat eine Grösse von 189,31 KB was ich auch nicht unbedingt als optimal empfinde aber es läd relativ schnell. ka wie sich das bei ca 5000 Usern auswirken würde.
Unklar dabei ist mir völlig wo eigentlich das
PHP:
imagejpeg($new,"img/neu.jpg",100); // Neues Bild speichern
abgespeichert wird ? temporär in den Browsercache?

Wärest du so freundlich mir mal ein BSP für "dynamisch zugewiesenene Werte für die CSS Eigenschaft background-position" zu geben? Kann mir jetzt im ersten Augenblick nichts so richtig drunter vorstellen.

Danke für deine Antwort Grüsse Joe.
 
Sie wird (wenn nicht gecached) stets neu berechnet. naja, optimiert ist das nicht, ich würde auf Umrechnungen per php verzichten. zwei Möglichkeiten:

(1) wie schon beschrieben per css die background-position setzen.
(2) mit tiling arbeiten und die map in 10x10px große Stücke unterteilen, dann die nötigen Stück anzeigen lassen.

Das erste muss stets die ganze Map anzeigen (was nach einem kompletten Load der Seite nicht mehr von belang ist, da sie lokal im Cache liegt) und beim Zweiten wird nur geladen, was wirklich benötigt wird und von Tile zu Tile kann anders komprimiert werden, ergo kann die Summe der Tiles kleiner als die ganze Map sein.

mfg chmee
 
Also habe jetzt krampfhaft nach nen Prog zwecks Tiling gesucht: The Castles Splitimage
Das macht zwar soweit automatisch Slices (gibt massig Progs da muss man selbst schneiden bei ca 40001 Tiles kein Fun),
allerdings wird aus einen ehemals 3,4 MB jpeg 40001 jpeg die insgesamt etwas über 17 MB gross sind. Hinzu kommt das sie dann entweder nach Buchstaben oder Zahlen durchnummeriert werden. Wäre da freilich besser wenn ich ihnen gleich einfach Kords als Namen automatisch geben könnte (zb 1/1.jpg).

Bei meinem Div würden dann 55x44 Tiles aufgebaut werden um den Kartenauschnitt zu zeigen. Die Frage ist würde das nicht ungleich mehr Zeit in Anspruch nehmen die Tiles einzeln (in Schleife) zu laden? Kann man es irgendwie so machen das er erst das gesammte Bild lädt und erst anzeigt wenns fertig aufgebaut ist? Stelle mir grad vor das es recht komisch aussieht wenn der Browser zwar schnell dennoch sichbar 55x44 Tiles nacheinander aufbaut.

Ist die Tiling Methode wirklich weniger rechenintensiv als die PHP Imagecopy Methode?
Auf jeden Fall erscheinen mir die Tiles besser geeignet um später dann auch Gebäudeicons oder Grafiken anzuzeigen.
 
Der elegante (und gängige) Weg wäre eigentlich, eine Welt aus zB 32 verschiedenen Tiles zusammenzubauen. Zudem kannst Du ein initialen Preload der Tiles anstoßen - weiter optimierend kannst Du auch noch die Sprite-Technik anwenden.

Das mit der verzögerten Darstellung müsste man ausprobieren, eine Lösung dagegen wäre, den jeweiligen Layer erstmal per css auf hide zu stellen und nach zB 2sek. auf visible umzuschalten.

Weblinks:
Tilemapeditor mit XML-Ausgabe - http://mapeditor.org/
Tilebased Gameengine in Javascript - http://game.tyler-dewitt.com/
CSS Sprites - http://www.alistapart.com/articles/sprites/

mfg chmee

p.s.: Da wir hier in php sind, ist der Aufbau des HTML-Teils idR erledigt, bevor die Seite dargestellt wird. Sprich, wenn die Tiles schon mal geladen wurden (zB beim ersten Start oder per Preload), liegen die Sachen lokal im Cache und sollte keine Verzögerung verursachen.
 
Wollte gerne mal meine bisherige Lösung zur Karte hier zeigen. Ich denke das es bestimmt den ein oder andren helfen könnte.
Auf der Karte werden jetzt zusätzlich die Positionen angezeigt und ein Title angezeigt der Position und Koordinaten wiedergibt ähnlich einem Mouseover-event.
Optional kann man auch Links mit einbetten um so zb das Profil aufzurufen.

PHP:
<div id=content>
<div id=mappic>
<?php
error_reporting(E_ALL);
$SlicepointX = $UserMapX*10-277;  // Auschnittspunkt X
$SlicepointY = $UserMapY*10-220;    // Auschnittspunkt Y
$DIVmitteX=271.5;
$DIVmitteY=216;                     // Mitte des Divs/ angezeigter Bereich der Karte
$NearestKoordsX1 = $UserMapX-28;
$NearestKoordsX2 = $UserMapX+28;
$NearestKoordsY1 = $UserMapY-22;
$NearestKoordsY2 = $UserMapY+22;    // Erfassung aller Spieler des Kartenausschnittes 

if ($UserMapX<28) {                 // Abweichende Berechnung bei Kartenrandnähe ansonsten
	$SlicepointX = 0;               // wird Spieler immer auf der Mitte angezeigt
	$NearestKoordsX1 = 0;
	$NearestKoordsX2 = 56;
	$DIVmitteX=276-((28-$UserMapX)*10);
}
if ($UserMapX>172) {
	$SlicepointX = 1457;
	$NearestKoordsX2 = 201;
	$NearestKoordsX1 = 145;
	$DIVmitteX=257+(($UserMapX-172)*10);	
}
if ($UserMapY<22) {
	$SlicepointY = 0;
	$NearestKoordsY1 = 0;
	$NearestKoordsY2 = 44;
	$DIVmitteY=216-((22-$UserMapY)*10);
}
if ($UserMapY>178) {
	$SlicepointY = 1568;
	$NearestKoordsY2 = 201;
	$NearestKoordsY1 = 156;
	$DIVmitteY=206+(($UserMapY-178)*10);
}

//// Kartenausschnitt ohne Spielerposition
$Mapowner = $Username;
$size = array(543,432);                        				// Breite und Höhe des Auschnitts
$point = array($SlicepointX,$SlicepointY);     				// Koordinaten, ab wo kopiert werden soll (erst X, dann Y).
$image = imagecreatefromjpeg("img/MAP1.jpg") ;  			// Original einlesen
$new = imagecreatetruecolor($size[0],$size[1]); 			// Neues Bild leer erstellen
imagecopyresampled($new, $image, 0,0, $point[0],$point[1],
					$size[0],$size[1], $size[0],$size[1]);  // Ausschnitt rüberkopieren
imageJPEG($new,"img/MAP1_$Mapowner.jpg",100);           	// Bild speichern

//// Alle relevanten Spieler aus Datenbank lesen, Position berechnen und Punkt in Karte zeichnen.
echo "<map name=\"map\">";			//HTMLCode Anfangstag soll ein "Mouseover" zum anzeigen der Namen und Positionen gennerieren.
{
$sql = "SELECT
			Username,
			PosX,
			PosY
		FROM
			User
		WHERE
			PosX >=$NearestKoordsX1 AND PosX < $NearestKoordsX2 AND
			PosY >=$NearestKoordsY1 AND PosY < $NearestKoordsY2";
	$result = $db->query($sql);
	if (!$result) {
		die ('Etwas stimmte mit dem Query nicht: '.$db->error);
	}
	while ($row = $result->fetch_assoc()) {
		$PosXOtherPlayer= $row["PosX"];
		$PosYOtherPlayer= $row["PosY"];
		$User= $row["Username"];
		$Points = array(($PosXOtherPlayer - $UserMapX)*10+$DIVmitteX-5-1,   // Koordinaten, ab wo kopiert werden soll (erst X, dann Y).
						($PosYOtherPlayer - $UserMapY)*10+$DIVmitteY-5-1);  // Berechnung aller Positionen der erfassten Spieler
		$new = imageCreateFromJPEG("img/MAP1_$Mapowner.jpg"); //Original
		sleep(0.1);
		if (($PosXOtherPlayer==$UserMapX) AND ($PosYOtherPlayer==$UserMapY)) {
			$grafix = imageCreateFromGIF("img/list12x12-dot18.gif");        // roten Punkt zeichnen für die eigne Position
		}
		else {
			$grafix = imageCreateFromGIF("img/list12x12-dot19.gif");        // schwarzer Punkt für alle andren Spieler
		}
		imageCopyResampled($new, $grafix,
               $Points[0],$Points[1],   /* imagecopy() an berechnete Stelle ($Points) in $new, */
               0, 0,     				/* der zu kopierende Bereich beginnt in $ballgrey bei ( 0, 0) */
               12, 12,12,12);      			/* und ist x Pixel breit und y Pixel hoch */
		imageJPEG($new,"img/MAP1_$Mapowner.jpg",100);
		$Titlepos = array(($PosXOtherPlayer - $UserMapX)*10+$DIVmitteX-5-1,
						  ($PosYOtherPlayer - $UserMapY)*10+$DIVmitteY-5-1,
						  ($PosXOtherPlayer - $UserMapX)*10+$DIVmitteX,				//Array für Title(und oder Link)-generirung Positionen
						  ($PosYOtherPlayer - $UserMapY)*10+$DIVmitteY);
		echo "<area shape=\"rect\" coords=\"$Titlepos[0],$Titlepos[1],$Titlepos[2],$Titlepos[3]\" 
				href=\"\" title=\"$User: $PosXOtherPlayer,$PosYOtherPlayer\">\n";   //HTMLCode Position und Titel
	}
}
/**
 * Formel für Positionsanzeige aller Spieler des Kartenausschnittes:
 * ($PosXOtherPlayer - $UserMapX) * 10 (Feld =10*10Pixel bei Feldgrösse 200*200 (Karte ist 2000*2000 Pixel) + 
 * $DIVmitteX(DIV/BildMittelPunktberechnung) -5 Mitte des Feldes(Feld 10*10) -1 Rest des ball.gif (teils transparent deswegen keine Überlagerung)
 * ($PosYOtherPlayer - $UserMapY) * 10 (Feld =10*10Pixel bei Feldgrösse 200*200 (Karte ist 2000*2000 Pixel) + 
 * $DIVmitteX(DIV/BildMittelPunktberechnung) -5 Mitte des Feldes -4 Mitte des ball.gif (teils transparent deswegen keine Überlagerung)
 * $Points = array(($PosXOtherPlayer - $UserMapX)*10+$DIVmitteX-5-1,
					($PosYOtherPlayer - $UserMapY)*10+$DIVmitteY-5-1); */

echo "</map>"; 															//HTMLCode schliessendes Maptag.. erst hier ist die Maptabelle vollständig.
echo "<img src='img/MAP1_$Mapowner.jpg' width='543' height='432' border='0' alt='Karte' usemap='#map'>"; //zeigt Karte mit Positionen und Mouseover
?>
</div>
</div>

Wie man erkennt alles mit PHP bzw GD-Lib gelöst. Die Seite baut sich dennoch sehr schnell auf und durch die dynamischen Bildnamen wird auch der gleichzeitige Zugriff von mehreren Usern verhindert.

Würde mich freuen wenn noch jemand Tips hat wie man etwas verbessern könnte (Bin nach wie vor noch Anfänger).

Abschliessend überlege ich das ganze so umzuschreiben das PHP einmalig wenn noch nicht vorhanden selbst das Tile schneidet und dauerhaft speichert.
Bisher sehe ich aber keine Nachteile zu der normalen Tabellen Tiling-Methode.
 
Zuletzt bearbeitet:
Zurück