JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

Explore test.

<hr>
<!-- Testing only! -->
<div id='nq-testing'>
    <!--<button id='nq-test-heal'>Heal</button>--> 
    <select id='nq-test-locations'></select>
    <button id='nq-test-teleport'>Teleport there!</button> --- 
    <select id='nq-test-dialogues'></select>
    <button id='nq-test-dialogue'>Start dialogue!</button>
</div>

<div id='nq-container'>

    <!-- Scene -->
    <div id='nq-scene'>
    
        <!-- Background/view of the area -->
        <div id='nq-scene-bg'></div>
        
        <!-- Overlay image, above bg. Optional -->
        <div id='nq-scene-illus'></div>
        
        <!-- Beast sprite may appear here -->
        <div id='nq-scene-sprite'></div>
        
        <!-- If find an item, image here -->
        <div id='nq-scene-item'></div>

        <!-- All events will have text here. -->
        <!-- Some will have choices to click. -->
        <div id='nq-scene-dialogue'>
            <div id='nq-scene-text'></div>
            <div id='nq-scene-choices'></div>
        </div>
        
        <!-- Panels at each side. Optional -->
        <div id='nq-scene-left'></div>
        <div id='nq-scene-right'></div>

    </div>
    
    <!-- Controls and status -->
    <div id='nq-controls'>

        <!-- Minimap -->
        <div id='nq-map-container'>[tiles here]</div>
    
        <!-- Info about tile you're currently on -->
        <div id='nq-region-name'>[region name]</div>
        <div id='nq-region-desc'>[region desc]</div>
    
        <!-- Choose direction to move in -->
        <div id='nq-compass'>
            <div class='nq-arrow nq-n' data-dir='n'>N</div>
            <div class='nq-arrow nq-s' data-dir='s'>S</div>
            <div class='nq-arrow nq-e' data-dir='e'>E</div>
            <div class='nq-arrow nq-w' data-dir='w'>W</div>
            <div class='nq-arrow nq-ne' data-dir='ne'>NE</div>
            <div class='nq-arrow nq-nw' data-dir='nw'>NW</div>
            <div class='nq-arrow nq-se' data-dir='se'>SE</div>
         ...

CSS

/* Stop padding, borders etc changing sizes. */
div, span, img, button, p, a {
    box-sizing: border-box;
}

body {
    background-image: url("https://cmkt-image-prd.freetls.fastly.net/0.1.0/ps/6822548/600/400/m2/fpnw/wm1/hl4nswi37es20ha9edxwgr75t4paw77olrgrdokhzkt3glthhpt4asdkekl3qbpn-.jpg?1565862124&s=c83b2af95cc7a12a6d82ac4bbbee4f6b");
    background-size: 100% 120%; /* cover */
    background-position: center;
    background-attachment: fixed;
}

#nq-container {
    width: 800px;
    margin: 20px auto;
}


/* HP and EXP, both yours and enemy's. */
.bar-outer {
    display: inline-block;
    width: 120px;
    height: 20px;
    position: relative;
    border-radius: 3px;
}
.bar-inner {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
}

/* Containers. */
.hp-outer {
    border: 1px solid darkgreen;
}
.exp-outer {
    border: 1px solid brown;
}
/* Inner sections. Width will vary. */
.hp-inner {
    background-color: green;
}
.exp-inner {
    background-color: gold;
}


/* SCENE */

/* BG image fills whole section. */
#nq-scene {
    border: 1px solid black;
    position: relative;
    width: 800px;
    height: 300px;
}
#nq-scene-bg {
    z-index: -2;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
#nq-scene-bg img {
    width: 100%;
    height: 100%;
}
/* Overlay image */
#nq-scene-illus{
    display: none;
    z-index: -1;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
#nq-scene-illus img {
    width: 100%;
    height: 100%;
}


/* Other sections on top of bg image. */
#nq-scene-dialogue {
    position: absolute;
    bottom: 10px;
    left: 150px;
    width: 500px;
    max-height: 160px;
    padding: 10px;
    background-color: rgba(0, 0, 0, 0.6);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5);
    border: 1px solid #000;
    display: flex;
    flex-flow: column;
    align-items: center;
}
#nq-scene-text {
    color: #fff;
}
#nq-scene-choices {
   ...

JavaScript

// This object acts like a database.
const db = {

    // Paths for loading images
    tilePath: "http://images.neopets.com/nq/tp/",
    enemyPath: "http://images.neopets.com/nq/m/",
    
    // Map landmarks. Can teleport between them, for testing.
    cities: [
        {id: 1, name: "Capital City", map: 1, x: 7, y: 0},
        //{id: 2, name: "Jungle Ruins", map: 1, x: 8, y: 8},
        //{id: 3, name: "Swamp Edge City", map: 1, x: 12, y: 4},
        //{id: 4, name: "Temple of Ice", map: 1, x: 15, y: 11},
        //{id: 5, name: "Mountain Fortress", map: 1, x: 16, y: 13},
        {id: 6, name: "Magic Statue", map: 2, x: 6, y: 6},
        {id: 7, name: "Circle Palace", map: 3, x: 6, y: 6}
    ],
    
    
    
    // Player inventory is stored elsewhere
    items: [
        {id: 1, name: "Healing Potion"},
        {id: 2, name: "Crystal Ball"},
        {id: 3, name: "Quartz"},
        {id: 4, name: "Diamond"},
        {id: 5, name: "Tropical Fruits"},
        {id: 6, name: "Gold Nugger"},
        {id: 7, name: "Rusty Medallion"},
        {id: 8, name: "Fancy Hat"}
    ],
   
    // What image URL to use for each tile number.
    terrainTiles: [
        "water", // handled differently
        "grassland",
        "desert",
        "castle",
        "ruins",
        "hills",
        "dirt",
        "forest",
        "mountain",
        "city",
        "jungle",
        "cave",
        "stone",
        "swamp",
        "dungeon",
        "dungeon_barrel",
        "dungeon_chair",
        "dungeon_table",
        "dungeon_pillar",
        "dungeon_crate"
      ],
    // These appear on top of any terrain. Separate IDs
    spriteTiles: [
          "dungeon_up",
          "dungeon_down",
          "cave_ent",
          "cave_exit",
          "dungeon_portal",
          "dungeon_door",
          "dungeon_door",
          "dungeon_door",
          "dungeon_door"
      ],
      
      
    // 'tiles' = which terrain images to display.
    // 'regions' = which enemies...