브라우저 기반 전략 게임을 위해 데이터베이스에서 PHP로 육각 세계지도를 만드는 방법


28

PHP 브라우저 기반 전략 게임에 대한 육각 세계지도를 만들려고합니다. ID, 유형, x, y 및 점유 된 행 당 데이터를 사용하여 데이터베이스에 테이블을 만들었습니다. 여기서 type은 타일 종류이며 숫자로 정의됩니다. 예를 들어 1은 잔디입니다. 지도 자체는 25 x 25입니다.

클릭 가능한 타일과 화살표가 있는지도를 탐색 할 수있는 가능성이있는 데이터베이스에서지도를 그려보고 싶습니다. 나는 이것으로 시작하는 방법에 대한 실마리가 없으며 어떤 도움이라도 감사 할 것입니다.

답변:


38

* 편집 : 파이어 폭스에서 오류를 일으킨 자바 스크립트의 오류 수정 *

편집 : 방금 PHP 소스 코드로 헥스를 확장하는 기능이 추가되었습니다. 작은 1/2 크기의 것 또는 2x 점보, 그것은 모두 당신에게 달려 있습니다 :)

이 모든 것을 어떻게 작성해야할지 잘 모르겠지만 전체 예제를위한 코드를 작성하는 것이 더 쉽다는 것을 알았습니다. 페이지 (아래 링크 및 소스)는 PHP로 16 진맵을 동적으로 생성하고 Javascript를 사용하여 맵 클릭을 처리합니다. 16 진수를 클릭하면 16 진수가 강조 표시됩니다.

맵은 무작위로 생성되지만 맵을 채우는 대신 고유 코드를 사용할 수 있습니다. 간단한 2D 배열로 표시되며 각 배열 요소는 16 진수로 존재하는 지형 유형을 보유합니다.

16 진수 맵 예제를 사용하려면 클릭하십시오

사용하려면 16 진수를 클릭하여 강조 표시하십시오.

지금은 10x10 맵을 생성하고 있지만 PHP에서 맵 크기를 원하는 크기로 변경할 수 있습니다. 또한 예를 들어 게임 Wesnoth의 타일 세트를 사용하고 있습니다. 높이는 72x72 픽셀이지만 소스를 사용하여 16 진 타일의 크기를 설정할 수도 있습니다.

16 진수는 "16 진수 외부"영역이 투명하게 설정된 PNG 이미지로 표시됩니다. 각 16 진수를 배치하기 위해 CSS를 사용하여 16 진수 그리드 좌표로 계산 된 각 타일의 절대 위치를 설정합니다. 맵은 단일 DIV로 묶여 있으므로 예제를보다 쉽게 ​​수정할 수 있습니다.

전체 페이지 코드는 다음과 같습니다. 데모 소스 (모든 16 진 이미지 포함)를 다운로드 할 수도 있습니다 .

<?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>

다음은 예제의 스크린 샷입니다.

16 진지도 예

확실히 몇 가지 개선 사항을 사용할 수 있습니다. 이전 의견에서 당신이 jQuery에 익숙하다고 말한 것을 알았습니다. 나는 여기에 물건을 단순하게 유지하기 위해 사용하지는 않았지만 사용하는 것이 매우 유용 할 것입니다.


1
kudos you :)
Fuu

1
Fuu의 예를 확실히보십시오. 16 진수 이미지를 배치하고 jQuery 및 JSON에 대한 제안과 결합 된 클릭을 결정하는 내 방법을 사용할 수 있습니다. 오,지도에서 하이라이트를 어떻게 오버레이하는지 볼 수 있습니다. 이미지 일뿐이지만 z-index 스타일 속성을 타일보다 높은 수로 설정했습니다. 이는 나중에 그립니다. 같은 아이디어를 사용하여 플레이어, 마커, 떠 다니는 구름, 원하는 일을 오버레이 할 수 있습니다.
Tim Holt

Erk-Firefox에서 테스트하지 않았습니다. 클릭 위치를 결정하기 위해 코드를 새로운 코드로 업데이트했으며 Firefox에서 작동합니다. 이것이 jQuery를 사용하는 이유이므로 다음과 같은 것에 대해 걱정할 필요가 없습니다. :
Tim Holt

1
데모에서 각 div에 zindex : 99를 사용한다는 것을 알 수 있습니다. z-index : 99 여야하지만 필요하지는 않습니다.
corymathews

@corymathews 실제로 포레스트 타일의 오른쪽에있는 나무와 같이 타일에서 '나오는'것을 고려하는 구현의 시작처럼 보입니다. 다른 타일이 트리 (현재 동작)와 겹치지 않도록 인덱스를 변경해야합니다.
Jonathan Connell

11

CPU 타일 처리 시간을 플레이어 컴퓨터에 아웃소싱 할 수 있기 때문에 데이터베이스 타일 좌표를 웹 페이지의보기에 매핑하는 작은 자바 스크립트 타일 레이아웃 엔진을 작성해야합니다. 어려운 일이 아니며 몇 페이지의 코드로 할 수 있습니다.

따라서 본질적으로 웹에서 AJAX 호출에 대한 응답으로 데이터베이스에서 클라이언트로 좌표 데이터를 전달하는 것이 목적인 얇은 계층의 PHP를 작성하게됩니다. 구문 분석을 쉽게하기 위해 JSON 데이터 형식을 사용하고 맵 생성 및 표시 부분을 javascript로 작성하고 numo16에서 제안한 jQuery와 같은 라이브러리를 사용하여 클라이언트에서 실행합니다. 이 부분은 비교적 쉽게 수행 할 수 있으며 실제 게임 응용 프로그램에서와 동일한 개념이 적용되므로 공산주의 오리 기사 목록에 16 진 표시 부분이 설명되어 있습니다.

플레이어 화면에 맵 그래픽을 표시 하려면 모든 맵 타일을 단일 파일에 저장할 수 있는 CSS 스프라이트 기법을 사용하는 것이 좋습니다 . 위치 지정을 위해 div로 래핑 된 타일 이미지에 절대 좌표를 사용합니다.이 이미지는 다시 상대적으로 배치 된 컨테이너 div에 있습니다.

이 이미지 래핑 div에 jQuery 클릭 이벤트를 적용하면 제안 된대로 마우스 위치를 수동으로 추적하지 않고도지도를 쉽게 클릭 할 수 있습니다. 오버 플로우 클리핑으로 컨테이너 div의 스타일을 지정하여 맵 가장자리를 들쭉날쭉 한 선 육각 타일 대신 정사각형으로 잘라 맵을보기 좋게 만듭니다. :)


대단히 감사합니다. jQuery는 놀라운 라이브러리이므로 이미 익숙합니다! 다시 감사합니다!
fabianPas

확실히 jQuery-멋진 언어를 사용하십시오. Fuu, 당신의 대답은 분명히 나의 것보다 더 우아합니다. 예를 들어 더 많은 시간을 주면 내가 갈 길입니다. jQuery + JSON은지도 데이터를 얻는 방법입니다.
Tim Holt

1

내 생각은 데이터베이스에서 데이터를 읽을 때 각 타일은 (x, y) 지점으로 지정된 위치에 육각형 이미지 맵이있는 정사각형 이미지로 생성된다는 것입니다. 즉, 타일 이미지를 주변의 빈 알파 채널이있는 육각형으로 만들어야 타일을 약간 겹쳐서 서로 맞도록 표시 할 수 있습니다. jQuery를 조사하여 그래픽 및 UI 측면 (애니메이션, 더 빠르고 쉬운 아약스, 쉬운 이벤트 처리 등)을 개선 할 수 있습니다.


1

PHP를 사용하지 못해서 코드 예제를 작성할 수 없습니다. 그러나 다음은 도움이 될만한 유용한 리소스 목록입니다. :)

다음은 Gamedev의 등각 / 육각 그리드 기사 목록 입니다. 육각형 좌표다루는 방법에서 타일 ​​캐싱에 이르기까지 다양 합니다 . (물론 웹 브라우저가 아닌 PC에서 주로 단어가 무엇입니까?) 때문에 일부 내용은 관련이 없습니다.

그래픽 디스플레이의 경우, 단순히 육각형 타일의 정사각형 이미지에 투명성을 추가하십시오.

'클릭 가능'은 다음과 같습니다.

if mouse button down on app:  
take screen coordinates of mouse  
Compare to screen coordinates of tiles

사용자 이벤트와 데이터베이스 연결 방식이 PHP에 얼마나 많은지 알지 못하므로 다른 언어와 프레임 워크를 조사해야 할 수도 있습니다.

행운이 있기를 바랍니다. :)


브라우저 기반 게임에서도 훨씬 더 필요하지 않은 경우 저수준 프로그래밍 트릭이 인정됩니다.
Tor Valamo

1

Fuu의 접근 방식에 따라 브라우저에서 16 진수 맵을 렌더링하기 위해 브라우저의 javascript 및 jQuery에 전적으로 의존하는 버전이 작동합니다. 현재 JSON에서 임의의 두 개의 타일 중 임의의 맵 구조를 다음과 같이 생성하는 함수가 있습니다.

var map = [[ "ocean,"사막 ","사막 "], ["사막, "사막", "바다"], [ "바다,"사막 ","바다 "]]

...하지만 웹 페이지가 Ajax 호출을 발행하여 코드 자체를 생성하는 대신 서버에서 이러한 맵 구조를 얻는다고 상상하기 쉽습니다.

코드는 jsfiddle 에 있으며 블로그 게시물에 대한 링크와 관심있는 경우 github 링크를 찾을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.