* Editar: se corrigió el error en JavaScript que causaba un error en Firefox *
Editar: solo se agregó la capacidad de escalar hexágonos al código fuente PHP. Pequeños de 1/2 tamaño o 2x jumbo, todo depende de ti :)
No estaba muy seguro de cómo poner todo esto por escrito, pero descubrí que era más fácil escribir el código para un ejemplo completo en vivo. La página (enlace y fuente a continuación) genera dinámicamente un mapa hexadecimal con PHP y usa Javascript para manejar los clics del mapa. Al hacer clic en un hex, resalta el hex.
El mapa se genera aleatoriamente, pero debería poder usar su propio código para rellenar el mapa. Está representado por una simple matriz 2d, con cada elemento de la matriz que contiene el tipo de terreno presente en ese hex.
Haga clic en mí para probar el ejemplo de mapa hexadecimal
Para usar, haga clic en cualquier hex para resaltarlo.
En este momento está generando un mapa de 10x10, pero puede cambiar el tamaño del mapa en PHP para que sea del tamaño que desee. También estoy usando un conjunto de fichas del juego Wesnoth para el ejemplo. Tienen 72x72 píxeles de altura, pero la fuente también le permite establecer el tamaño de sus mosaicos hexagonales.
Los hexes están representados por imágenes PNG con áreas "fuera del hex" establecidas como transparentes. Para colocar cada hexágono, estoy usando CSS para establecer la posición absoluta de cada mosaico, calculada por la coordenada de la cuadrícula hexadecimal. El mapa está encerrado en un solo DIV, lo que debería facilitarle la modificación del ejemplo.
Aquí está el código de la página completa. También puede descargar la fuente de demostración (incluidas todas las imágenes hexadecimales).
<?php
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// :: HEX.PHP
// ::
// :: Author:
// :: Tim Holt, [email protected]
// :: Description:
// :: Generates a random hex map from a set of terrain types, then
// :: outputs HTML to display the map. Also outputs Javascript
// :: to handle mouse clicks on the map. When a mouse click is
// :: detected, the hex cell clicked is determined, and then the
// :: cell is highlighted.
// :: Usage Restrictions:
// :: Available for any use.
// :: Notes:
// :: Some content (where noted) copied and/or derived from other
// :: sources.
// :: Images used in this example are from the game Wesnoth.
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// --- Turn up error reporting in PHP
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
// --- Define some constants
$MAP_WIDTH = 10;
$MAP_HEIGHT = 10;
$HEX_HEIGHT = 72;
// --- Use this to scale the hexes smaller or larger than the actual graphics
$HEX_SCALED_HEIGHT = $HEX_HEIGHT * 1.0;
$HEX_SIDE = $HEX_SCALED_HEIGHT / 2;
?>
<html>
<head>
<title>Hex Map Demo</title>
<!-- Stylesheet to define map boundary area and hex style -->
<style type="text/css">
body {
/*
margin: 0;
padding: 0;
*/
}
.hexmap {
width: <?php echo $MAP_WIDTH * $HEX_SIDE * 1.5 + $HEX_SIDE/2; ?>px;
height: <?php echo $MAP_HEIGHT * $HEX_SCALED_HEIGHT + $HEX_SIDE; ?>px;
position: relative;
background: #000;
}
.hex-key-element {
width: <?php echo $HEX_HEIGHT * 1.5; ?>px;
height: <?php echo $HEX_HEIGHT * 1.5; ?>px;
border: 1px solid #fff;
float: left;
text-align: center;
}
.hex {
position: absolute;
width: <?php echo $HEX_SCALED_HEIGHT ?>;
height: <?php echo $HEX_SCALED_HEIGHT ?>;
}
</style>
</head>
<body>
<script>
function handle_map_click(event) {
// ----------------------------------------------------------------------
// --- This function gets a mouse click on the map, converts the click to
// --- hex map coordinates, then moves the highlight image to be over the
// --- clicked on hex.
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// --- Determine coordinate of map div as we want the click coordinate as
// --- we want the mouse click relative to this div.
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// --- Code based on http://www.quirksmode.org/js/events_properties.html
// ----------------------------------------------------------------------
var posx = 0;
var posy = 0;
if (event.pageX || event.pageY) {
posx = event.pageX;
posy = event.pageY;
} else if (event.clientX || e.clientY) {
posx = event.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posy = event.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
// --- Apply offset for the map div
var map = document.getElementById('hexmap');
posx = posx - map.offsetLeft;
posy = posy - map.offsetTop;
//console.log ("posx = " + posx + ", posy = " + posy);
// ----------------------------------------------------------------------
// --- Convert mouse click to hex grid coordinate
// --- Code is from http://www-cs-students.stanford.edu/~amitp/Articles/GridToHex.html
// ----------------------------------------------------------------------
var hex_height = <?php echo $HEX_SCALED_HEIGHT; ?>;
x = (posx - (hex_height/2)) / (hex_height * 0.75);
y = (posy - (hex_height/2)) / hex_height;
z = -0.5 * x - y;
y = -0.5 * x + y;
ix = Math.floor(x+0.5);
iy = Math.floor(y+0.5);
iz = Math.floor(z+0.5);
s = ix + iy + iz;
if (s) {
abs_dx = Math.abs(ix-x);
abs_dy = Math.abs(iy-y);
abs_dz = Math.abs(iz-z);
if (abs_dx >= abs_dy && abs_dx >= abs_dz) {
ix -= s;
} else if (abs_dy >= abs_dx && abs_dy >= abs_dz) {
iy -= s;
} else {
iz -= s;
}
}
// ----------------------------------------------------------------------
// --- map_x and map_y are the map coordinates of the click
// ----------------------------------------------------------------------
map_x = ix;
map_y = (iy - iz + (1 - ix %2 ) ) / 2 - 0.5;
// ----------------------------------------------------------------------
// --- Calculate coordinates of this hex. We will use this
// --- to place the highlight image.
// ----------------------------------------------------------------------
tx = map_x * <?php echo $HEX_SIDE ?> * 1.5;
ty = map_y * <?php echo $HEX_SCALED_HEIGHT ?> + (map_x % 2) * (<?php echo $HEX_SCALED_HEIGHT ?> / 2);
// ----------------------------------------------------------------------
// --- Get the highlight image by ID
// ----------------------------------------------------------------------
var highlight = document.getElementById('highlight');
// ----------------------------------------------------------------------
// --- Set position to be over the clicked on hex
// ----------------------------------------------------------------------
highlight.style.left = tx + 'px';
highlight.style.top = ty + 'px';
}
</script>
<?php
// ----------------------------------------------------------------------
// --- This is a list of possible terrain types and the
// --- image to use to render the hex.
// ----------------------------------------------------------------------
$terrain_images = array("grass" => "grass-r1.png",
"dirt" => "dirt.png",
"water" => "coast.png",
"path" => "stone-path.png",
"swamp" => "water-tile.png",
"desert" => "desert.png",
"oasis" => "desert-oasis-tile.png",
"forest" => "forested-mixed-summer-hills-tile.png",
"hills" => "hills-variation3.png",
"mountain" => "mountain-tile.png");
// ==================================================================
function generate_map_data() {
// -------------------------------------------------------------
// --- Fill the $map array with values identifying the terrain
// --- type in each hex. This example simply randomizes the
// --- contents of each hex. Your code could actually load the
// --- values from a file or from a database.
// -------------------------------------------------------------
global $MAP_WIDTH, $MAP_HEIGHT;
global $map, $terrain_images;
for ($x=0; $x<$MAP_WIDTH; $x++) {
for ($y=0; $y<$MAP_HEIGHT; $y++) {
// --- Randomly choose a terrain type from the terrain
// --- images array and assign to this coordinate.
$map[$x][$y] = array_rand($terrain_images);
}
}
}
// ==================================================================
function render_map_to_html() {
// -------------------------------------------------------------
// --- This function renders the map to HTML. It uses the $map
// --- array to determine what is in each hex, and the
// --- $terrain_images array to determine what type of image to
// --- draw in each cell.
// -------------------------------------------------------------
global $MAP_WIDTH, $MAP_HEIGHT;
global $HEX_HEIGHT, $HEX_SCALED_HEIGHT, $HEX_SIDE;
global $map, $terrain_images;
// -------------------------------------------------------------
// --- Draw each hex in the map
// -------------------------------------------------------------
for ($x=0; $x<$MAP_WIDTH; $x++) {
for ($y=0; $y<$MAP_HEIGHT; $y++) {
// --- Terrain type in this hex
$terrain = $map[$x][$y];
// --- Image to draw
$img = $terrain_images[$terrain];
// --- Coordinates to place hex on the screen
$tx = $x * $HEX_SIDE * 1.5;
$ty = $y * $HEX_SCALED_HEIGHT + ($x % 2) * $HEX_SCALED_HEIGHT / 2;
// --- Style values to position hex image in the right location
$style = sprintf("left:%dpx;top:%dpx", $tx, $ty);
// --- Output the image tag for this hex
print "<img src='$img' alt='$terrain' class='hex' style='zindex:99;$style'>\n";
}
}
}
// -----------------------------------------------------------------
// --- Generate the map data
// -----------------------------------------------------------------
generate_map_data();
?>
<h1>Hex Map Example</h1>
<a href='index.phps'>View page source</a><br/>
<a href='hexmap.zip'>Download source and all images</a>
<!-- Render the hex map inside of a div block -->
<div id='hexmap' class='hexmap' onclick='handle_map_click(event);'>
<?php render_map_to_html(); ?>
<img id='highlight' class='hex' src='hex-highlight.png' style='zindex:100;'>
</div>
<!--- output a list of all terrain types -->
<br/>
<?php
reset ($terrain_images);
while (list($type, $img) = each($terrain_images)) {
print "<div class='hex-key-element'><img src='$img' alt='$type'><br/>$type</div>";
}
?>
</body>
</html>
Aquí hay una captura de pantalla del ejemplo ...
Definitivamente podría usar algunas mejoras. Noté en un comentario anterior que dijiste que estabas familiarizado con jQuery, lo cual es bueno. No lo usé aquí para simplificar las cosas, pero sería bastante útil de usar.
Debería escribir un pequeño motor de diseño de mosaico de JavaScript que mapee las coordenadas del mosaico de la base de datos en una vista en la página web, ya que esto le permite externalizar el tiempo de procesamiento de la CPU a la computadora del jugador. No es difícil de hacer y puedes hacerlo en pocas páginas de código.
Esencialmente, estará escribiendo una capa delgada de PHP cuyo único propósito es entregar datos de coordenadas al cliente desde su base de datos, preferiblemente en respuesta a una llamada AJAX desde su página web. Probablemente usaría un formato de datos JSON para un análisis fácil, y luego el mapa que genera y muestra la parte se escribiría en javascript y se ejecutaría en el cliente usando una biblioteca como jQuery como lo sugiere numo16. Esta parte es relativamente fácil de hacer y se aplican los mismos conceptos que en las aplicaciones de juegos reales, por lo que la lista de artículos de los patos comunistas le explicará la parte de visualización hexadecimal.
Para la visualización de gráficos de mapas en la pantalla de los jugadores, recomendaría que utilice la técnica CSS Sprites que le permite almacenar todos sus mosaicos de mapas en un solo archivo. Para el posicionamiento, usaría coordenadas absolutas para la imagen de mosaico envuelta en un div, que nuevamente está en un div de contenedor relativamente posicionado.
Si aplica eventos de clic jQuery a estos divs de ajuste de imagen, puede hacer que se pueda hacer clic en el mapa fácilmente sin tener que rastrear manualmente las posiciones del mouse como se sugiere. Diseñe el contenedor div con un recorte de desbordamiento para recortar los bordes del mapa para que sean cuadrados en lugar de los mosaicos hexagonales de líneas irregulares para que el mapa se vea bien. :)
fuente
Creo que a medida que los datos se leen desde la base de datos, cada mosaico se creará como una imagen cuadrada con un mapa de imagen hexagonal en cualquier posición especificada por su punto (x, y). Lo que significa que tendrá que crear sus imágenes de mosaico como hexágonos con un canal alfa vacío circundante, para que pueda superponer sus mosaicos un poco y hacer que parezcan encajar. Es posible que desee consultar jQuery para ayudar a pulir los gráficos y el lado de la interfaz de usuario (animación, ajax más rápido y fácil, manejo fácil de eventos, etc.).
fuente
Me temo que no hablo PHP, así que no puedo hacer ejemplos de código. Sin embargo, aquí hay una buena lista de recursos que pueden ayudarlo. :)
Aquí hay una buena lista de artículos de cuadrícula isométrica / hexagonal en Gamedev; que van desde cómo lidiar con los cordones hexagonales hasta el almacenamiento en caché de fichas . (Por supuesto, algunas de las cosas no serán relevantes ya que son principalmente ... ¿cuál es la palabra? En una PC, no en un navegador web).
En cuanto a la visualización gráfica, simplemente agregue transparencia a una imagen cuadrada de un mosaico hexagonal.
'Clickable' sería algo así como:
No tengo idea de cuánto tienen los eventos de usuario y la conexión de bases de datos a PHP, por lo que es posible que tenga que buscar otros lenguajes y marcos para eso.
Te deseo suerte. :)
fuente
Siguiendo el enfoque de Fuu, tengo una versión funcionando que se basa exclusivamente en javascript y jQuery en el navegador para representar el mapa hexadecimal. En este momento hay una función que genera una estructura de mapa aleatorio en JSON (de dos mosaicos posibles) más o menos así:
mapa var = [["océano," desierto "," desierto "], [" desierto, "desierto", "océano"], ["océano," desierto "," océano "]]
... pero es fácil imaginar que la página web emita una llamada Ajax para obtener dicha estructura de mapa de un servidor en lugar de generar el código en sí.
El código está disponible en jsfiddle , desde donde también puede encontrar un enlace a una publicación de blog que lo explica, y un enlace de github si está interesado.
fuente