Search code examples
javascriptjavascript-objects

Why is my method running twice and resetting the object value I'm trying to change?


I declare an Object called gameRooms, which contains Objects representing the rooms and their properties. Then I declare gameState and include a property for 'currentRoom.' When the game starts and I set the 'currentRoom' variable to 'Graveyard' via the ChangeRoom() method, it works just fine.

However, when I click a button that executes the function declared in a room's func property, then function writes: "You Enter The Main Hall. You Enter The Graveyard." ...to the window. When I check the console, I'm still in the Graveyard. Why?

JSfiddle here: https://jsfiddle.net/SirenKing/fz8pg05L/2/

    gameRooms = {
        Graveyard: {
            description: 'The graveyard is small, enclosed by tall walls. The tombstones are weathered and worn. The names are hard to make out. An abandoned shed sits in one corner. A closed door leads into the castle.',
            name: "Graveyard",
            navButtons: [
                {
                    name: "Go Inside",
                    state: "locked",
                    func: function () {
                        ChangeRoom( gameRooms.MainHall );
                    },
                    id: "tomainhall",
                },
              (etc etc etc, more rooms and buttons...)
            ],
        },
    }
    gameState = {
        State: {
                currentRoom: null,
                actionIDs: [ "wakeup" ],
                navigationIDs: [],
                inventoryIDs: [],
                globalMenuIDs: [],
                health: 100,
        }
    };
function ChangeRoom( room ) {
    gameState.State.currentRoom = room;
    Say( "You enter the " + room.name );
    UpdateNavigation( );
    UpdateActions( );
    
    return gameState.State.currentRoom;
};

function Say(content) {
    let comment = content;
    let newParagraph = document.createElement('p');
    newParagraph.textContent = comment;
    let newestParagraph = document.getElementById("narrative").appendChild(newParagraph);
    document.getElementById("narrative").id = "old";
    newestParagraph.id = "narrative";
    scrollTo(0,document.body.scrollHeight);
};

The HTML, and the button-constructing method, are here:



<html>
    <body>
        <div style="width:40%;" id="narrative"></div>

        <div id="nav" style="top:200px; right:100px; position:fixed;">
            <label>Navigate</label>
        </div>  
    </body>
</html>


function UpdateNavigation( ) {

    let oldNavigation = gameState.State.navigationIDs;
    console.log(oldNavigation);
    console.log("removing old nav buttons by id");
    
    for (i = 0; i < oldNavigation.length; i++) {
        // for ids in gameState.State.navigationIDs, remove the button elements by those ids
        let elem = document.getElementById( gameState.State.navigationIDs[i] );
        elem.remove();
    }
    
    gameState.State.navigationIDs = [];
    let navs = GetCurrentRoom().navButtons;
    let roomName = GetCurrentRoom().name;
    console.log( roomName, "'s navButtons are ", navs);
    console.log("building new list of nav button ids");
    
    for (i = 0; i < navs.length; i++) {
        gameState.State.navigationIDs.push( navs[i].id );
    };
    
    let currentNavigation = gameState.State.navigationIDs;
    console.log(currentNavigation);
    console.log("building nav buttons from list of ids");
    
    for (i = 0; i < currentNavigation.length; i++) {

        // for objects in room.navButtons, create new action buttons with ids of the rooms you can enter
        // add innerHTML and onclick and type to the button, then append it into the navsDiv

        elem = document.createElement("button");
        elem.innerHTML = navs[i].name ;
        elem.type = "button";
        elem.id = currentNavigation[i];
        elem.onclick = GetCurrentRoom().navButtons[i].func;
        let navsDiv = document.getElementById( "nav" );
        navsDiv.lastElementChild.appendChild(elem);
    };

};

Solution

  • There are a few problems with your code; Say() does nothing with its second parameter, and should either do so, or concatenate the parameters sent to it: function Say(one, two) { return one + two; } or Say(one + two);... But mainly, the largest problem is that you append your buttons to the label element.

    If this element were anything but a label, your code would work without issue. This is because the label element propagates click or touch events to the element(s) within it, so every time you click either of the buttons in that label element, the element clicks both buttons at once.

    Thus, the simple fix is to remove the code that appends the buttons to the label:

    navsDiv.lastElementChild.appendChild(elem);
    

    Should be changed to:

    navsDiv.appendChild(elem);
    

    This of course goes the same for any code that appends buttons to the label elements. Also relevant is your UpdateActions() function, where you append content to the last child... A label.

    Fixed fiddle