HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Button click handlers for a JavaScript text-based adventure game

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
clickhandlersjavascripttextadventuregameforbuttonbased

Problem

I'm pretty new to JavaScript, and I'm trying to created a text-based game. I've written a few scenarios and based on the player's decision I have different scenarios written out. As of now I have the code written and it works but I feel like I can be more efficient with an if else statement in my js.

Here's what I have so far in terms of player decisions.



$(document).ready(function(){

$(".sit_1, .sit_2, .sit_3a, .sit_3b, .sit_4a").hide();
$(".choice_1, .choice_2a, .choice_2b, .choice_3a, .choice_3b, .choice_4a, .choice_4b").hide();
$(".sit_1").fadeIn(2000);
$(".choice_1").fadeIn(4000);


$(".choice_1").click(function(){
$(".sit_1").hide();
$(".choice_1").hide();
$(".sit_2").fadeIn(4000);
$(".choice_2a").fadeIn(8000);
$(".choice_2b").fadeIn(8000);


});


$(".choice_2a").click(function(){
$(".sit_2").hide();
$(".choice_2a").hide();
$(".choice_2b").hide();
$(".sit_3a").fadeIn(4000);




});


$(".choice_2b").click(function(){
$(".sit_2").hide();
$(".choice_2a").hide();
$(".choice_2b").hide();
$(".sit_3b").fadeIn(4000);
$(".choice_3a").fadeIn(4000);
$(".choice_3b").fadeIn(4000);



});


$(".choice_3a").click(function(){
$(".sit_3b").hide();
$(".choice_3a").hide();
$(".choice_3b").hide();
$(".sit_4a").fadeIn(3000);
$(".choice_4a").fadeIn(4000);
$(".choice_4b").fadeIn(4000);



});


});

`




You are lost in the woods.



You find a cave. Do you go inside or go look for food?



You walk int

Solution

You are falling into a conceptual trap of trying to define javascript behaviors for each element on the page by numbering each and every one with a different id or class name (i.e. choice_*). Any time you see this pattern in your coding, this should be a red flag that there is probably a better approach to your problem (which is why I think you are asking for this review).

With jQuery (or really javascript in general), you should be thinking in terms of what the behavior of an element is supposed to be using classes to identify elements which need to exhibit similar behavior, much in the same way you use classes to define elements that have common CSS stylings. For example, all of your choice buttons fundamentally have the same behavior. That is, they hide other options and expose a new situation. Because this basic behavior is common, there is no reason that you need to duplicate code for each of these buttons.

So the question then becomes how do you generalize your code to have a single onclick handler for all of the choice buttons?

To do this, you have to have an understanding of which buttons expose which situations - something you are now implementing via choice_* class naming.

In jQuery/javascript, there are probably two main strategies to do this. One is to tie the elements together via their hierarchy in the DOM and to traverse the DOM hierarchy to hide/show related elements based on their location relative to each other on the DOM. For example, when hiding/showing elements, you might hide all the siblings in same level of DOM as the one you are trying to show.

The other main approach is to use data attributes to describe how elements should interact with one another.

I will focus on the data attribute approach here as I think this makes the most sense for your use case. You have a potentially complex set of interactions in a "Choose Your Own Adventure" style of game where you ultimately may have multiple story branches each which could lead to different situations via different paths. This would likely be hard to model via HTML hierarchy alone once you move beyond just a trivial proof of concept. Data attributes are also a powerful tool for a budding javascript developer to learn.

I would propose some changes to your HTML to make each "situation" its own self-contained set of HTML elements, like the concept of a page. You could then hide/show each situation (including choices) as a single entity. I also think in this case it makes your HTML much easier to read and maintain.


    
        
            You are lost in the woods.
        
        
    
    
        
            You find a cave. Do you go inside or go look for food? 
        
        
        
    
    
        
            You walk into the cave.
        
    
    
        
            You walk away from the cave, to search for food. You find berries. Do you eat them or not? 
        
        
        
    
    
        
            You eat the berries.
        
    
    
        
            You ignore the berries. You are still hungry.
        
    


Note that we apply a data attribute called situation on the container of each situation "page" to uniquely identify it amongst all situations. We also have data attributes on each option specifying the situation-target that option relates to (i.e. which situation will be shown when the button is clicked).

I have added another class situation_default to show which situation(s) are visible for display on initial page load.

Finally, I have also introduced a class for situation_text here that is not used in the javascript at all, but could perhaps give you a handle for applying CSS styling.

You use these data attributes within your javascipt to implement the logic as to what situation is shown when an option is clicked.

```
$(document).ready(function() {
// Create jQuery handle to all situations.
// Having this outside click handler allows you to access it while
// preventing you from having to query the DOM every time you want to
// act on this selection of elements as a whole.
var $allSituations = $('.situation');

// Get selector for default situation(s) which will show on page load
var $defaultSituation = $('.default_situation');

// Show default situation(s)
$allSituations.hide();
$defaultSituation.fadeIn(2000);

$('.situation_choice').on('click', function() {
// Find target situation element for this choice.
// We use the 'situation-target' data attribute for the
// clicked element, this, within the handler to determine
// the target.
var targetName = $(this).data('situation-target');
var $target = $('.situation[data-situation="' + targetName + '"]')

// if we find a single target element, we can now show it
if($target.length === 1) {
// hide all situations
$allSituations.hide();
// show target eleme

Code Snippets

<html>
    <div class="situation default_situation" data-situation="start">
        <div class="situation_text">
            You are lost in the woods.
        </div>
        <input type="button" class="situation_choice"
            value="Continue on..."
            data-situation-target="found_cave">
    </div>
    <div class="situation" data-situation="found_cave">
        <div class="situation_text">
            You find a cave. Do you go inside or go look for food? 
        </div>
        <input type="button" class="situation_choice"
            value="Go inside"
            data-situation-target="enter_cave">
        <input type="button" class="situation_choice"
            value="Look for food"
            data-situation-target="food_search">
    </div>
    <div class="situation" data-situation="enter_cave">
        <div class="situation_text">
            You walk into the cave.
        </div>
    </div>
    <div class="situation" data-situation="food_search">
        <div class="situation_text">
            You walk away from the cave, to search for food. You find berries. Do you eat them or not? 
        </div>
        <input type="button" class="situation_choice"
            value="Eat the berries"
            data-situation-target="eat_berries">
        <input type="button" class="situation_choice"
            value="Don't eat the berries"
            data-situation-target="ignore_berries">
    </div>
    <div class="situation" data-situation="eat_berries">
        <div class="situation_text">
            You eat the berries.
        </div>
    </div>
    <div class="situation" data-situation="ignore_berries">
        <div class="situation_text">
            You ignore the berries. You are still hungry.
        </div>
    </div>
</html>
$(document).ready(function() {
    // Create jQuery handle to all situations.
    // Having this outside click handler allows you to access it while
    // preventing you from having to query the DOM every time you want to
    // act on this selection of elements as a whole.
    var $allSituations = $('.situation');

    // Get selector for default situation(s) which will show on page load
    var $defaultSituation = $('.default_situation');

    // Show default situation(s)
    $allSituations.hide();
    $defaultSituation.fadeIn(2000);

    $('.situation_choice').on('click', function() {
        // Find target situation element for this choice.
        // We use the 'situation-target' data attribute for the
        // clicked element, this, within the handler to determine
        // the target.
        var targetName = $(this).data('situation-target');
        var $target = $('.situation[data-situation="' + targetName + '"]')

        // if we find a single target element, we can now show it
        if($target.length === 1) {
            // hide all situations
            $allSituations.hide();
            // show target element
            $target.fadeIn(4000);
        }
    });
});

Context

StackExchange Code Review Q#136553, answer score: 6

Revisions (0)

No revisions yet.