Answers:
*编辑:修复了导致Firefox错误的JavaScript错误*
编辑:刚刚添加了将十六进制缩放到PHP源代码的功能。微小的1/2尺寸或2x超大尺寸,一切由您决定:)
我不太确定如何将其全部编写出来,但是发现仅编写完整示例的代码会更容易。该页面(下面的链接和源代码)使用PHP动态生成一个十六进制地图,并使用Javascript处理地图点击。单击十六进制会突出显示该十六进制。
该地图是随机生成的,但是您应该能够使用自己的代码来填充地图。它由一个简单的2d数组表示,每个数组元素都保存该十六进制中存在的地形类型。
若要使用,请单击任何十六进制以突出显示它。
现在它正在生成10x10的地图,但是您可以在PHP中将地图大小更改为所需的任何大小。我还使用了Wesnoth游戏中的一组图块作为示例。它们的高度为72x72像素,但是通过源也可以设置十六进制图块的大小。
十六进制由PNG图像表示,“十六进制外”区域设置为透明。为了定位每个十六进制,我正在使用CSS设置每个瓷砖的绝对位置,该绝对位置由十六进制网格坐标计算得出。该地图包含在单个DIV中,这将使您更轻松地修改示例。
这是完整的页面代码。您也可以下载演示源(包括所有十六进制图像)。
<?php
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// :: HEX.PHP
// ::
// :: Author:
// :: Tim Holt, tim.m.holt@gmail.com
// :: 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>
这是示例的屏幕截图...
肯定可以使用一些改进。我在之前的评论中注意到您说您熟悉jQuery,这很好。我在这里没有使用它来使事情保持简单,但是使用它将非常有用。
您应该编写一个小的javascript拼贴布局引擎,该引擎将数据库拼贴坐标映射到网页上的视图中,因为这使您可以将cpu处理时间外包给播放器计算机。这并不难,您可以在几页代码中完成。
因此,从本质上讲,您将编写PHP的薄层,其目的仅是将坐标数据从数据库传递到客户端,最好是响应网页上的AJAX调用。您可能会使用JSON数据格式进行轻松解析,然后使用javascript编写地图生成和显示部分,并使用numo16建议的类似jQuery的库在客户端上执行。该部分相对容易实现,并且与真实游戏应用程序中的概念相同,因此共产鸭子的文章列表将向您说明十六进制显示部分。
为了在玩家屏幕上显示地图图形,我建议您使用CSS Sprites技术,该技术可将所有地图图块存储在一个文件中。对于定位,您将对包裹在div中的图块图像使用绝对坐标,该绝对坐标再次位于相对定位的容器div中。
如果将jQuery click事件应用于这些图像包装div,则可以轻松使地图可单击,而无需按照建议手动跟踪鼠标位置。使用溢出剪裁为容器div设置样式,以将地图边缘修剪为正方形(而不是锯齿状的六边形图块),以使地图看起来更美观。:)
恐怕我不会讲PHP,因此无法编写代码示例。但是,这里有一个不错的资源列表,可能会对您有所帮助。:)
这是 Gamedev上等距/六边形网格文章的不错列表;从如何处理六边形坐标到缓存瓷砖等等。(当然,其中一些内容是无关紧要的,因为它主要是……什么意思?在PC而非Web浏览器上。)
对于图形显示,只需将透明度添加到六角形瓷砖的正方形图像即可。
“可点击”类似于:
if mouse button down on app:
take screen coordinates of mouse
Compare to screen coordinates of tiles
我不知道用户事件和PHP的数据库连接方式有多少,因此您可能需要研究其他语言和框架。
祝你好运。:)
遵循Fuu的方法,我得到了一个版本的工作,该版本完全依靠浏览器中的javascript和jQuery来呈现十六进制地图。现在有一个函数可以在JSON中(从两个可能的图块中)或多或少地生成一个随机映射结构,如下所示:
var map = [[[“ ocean,” desert“,” desert“],[” desert,“ desert”,“ ocean”],[“ ocean,” desert“,” ocean“]]
...但是很容易想象让网页发出Ajax调用以从服务器获取这样的地图结构,而不是自己生成代码。
该代码位于jsfiddle上,在这里您还可以找到指向说明它的博客文章的链接,以及感兴趣的github链接。