GML [SOLVED] Seeking advice on how to improve tile targeting/highlighting system

Papa Doge

Member
I'm working on a top-down game that's a combination of tower defense and farming sim. In this game, there are different actions the player can do like shoot a gun, plow the ground, water the ground, plant seeds, and place sentries (aka turrets).

The system I'm using to accomplish all this now is based on the player object colliding with a "soil object" that contains different variables to track its state. To give feedback to the player on what tiles they can interact with, I'm using various shaders to change the appearance of the tiles the player is interacting with.

Check out the screenshot to see what I have so far. Here's the code I have in the "soil" object's draw event...

Code:
draw_self(); // Draw the soil as normal...

/* -------------------- */

// COLLISION VARIABLES

has_sentry = place_meeting(x,y,obj_sentry_parent);
has_enemy = place_meeting(x,y,obj_enemy_parent);
has_crop = place_meeting(x,y,obj_crop_parent);
has_portal = place_meeting(x,y,obj_portal);

/* -------------------- */

// PLOWING

if (highlighted == true) && (obj_player_accessories.loadout == playerLoadout.plows) { // If this soil should be highlighted and the player is trying plow...
    if (has_sentry) || (has_enemy) || (has_crop) || (has_portal) { // IF this tile has something obstructing this action...
        shader_set(sha_red); // Apply the appropriate highlight shader...
        draw_self(); // Then draw again with the shader applied...
        shader_reset(); // Then reset the shader to its normal state...
    } else { // ELSE IF nothing is preventing this action from being taken...
        if (obj_player_accessories.plowing == true) { // IF the player is plowing the tiles underneath them...
            plowed = true; // Then this tile is now set to plowed...
        }
        shader_set(sha_black); // Apply the appropriate highlight shader...
        draw_self(); // Then draw again with the shader applied...
        shader_reset(); // Then reset the shader to its normal state...
    }
}

/* -------------------- */

// WATERING

if (highlighted == true) && (obj_player_accessories.loadout == playerLoadout.watering_cans) { // If this soil should be highlighted and the player is trying to water...
    if (has_sentry) || (has_enemy) || (has_crop) || (has_portal) || (!plowed) { // IF this tile has something obstructing this action OR has not been plowed...
        shader_set(sha_red); // Apply the appropriate highlight shader...
        draw_self(); // Then draw again with the shader applied...
        shader_reset(); // Then reset the shader to its normal state...
    } else { // ELSE IF nothing is preventing this action from being taken...
        if (obj_player_accessories.watering == true) { // IF the player is watering the tiles underneath them...
            watered = true; // Then this tile is now set to watered...
        }
        shader_set(sha_blue); // Apply the appropriate highlight shader...
        draw_self(); // Then draw again with the shader applied...
        shader_reset(); // Then reset the shader to its normal state...
    }
}

/* -------------------- */

// SEEDING

if (highlighted == true) && (obj_player_accessories.loadout == playerLoadout.seed_spreaders) { // If this soil should be highlighted and the player is trying to seed...
    if (has_sentry) || (has_enemy) || (has_crop) || (has_portal) || (!plowed) { // IF this tile has something obstructing this action OR has not been plowed...
        shader_set(sha_red); // Apply the appropriate highlight shader...
        draw_self(); // Then draw again with the shader applied...
        shader_reset(); // Then reset the shader to its normal state...
    } else { // ELSE IF nothing is preventing this action from being taken...
        if (obj_player_accessories.seeding == true) { // IF the player is seeding the tiles underneath them...
            if (obj_scoreboard.credits >= seed_cost) { // IF the player has enough credits to cover the cost of the seed...
                obj_scoreboard.credits -= seed_cost; // Subtract the cost of the seeds from the player's credits...
                seeded = true; // Then this tile is now set to seeded...
            }
        }
        shader_set(sha_green); // Apply the appropriate highlight shader...
        draw_self(); // Then draw again with the shader applied...
        shader_reset(); // Then reset the shader to its normal state...
    }
}

/* -------------------- */

// CONSTRUCTING

if (highlighted == true) && (obj_player_accessories.loadout == playerLoadout.construction_tools) { // If this soil should be highlighted and the player is trying to seed...
    if (has_sentry) || (has_enemy) || (has_crop) || (has_portal) || (!plowed) { // IF this tile has something obstructing this action OR has not been plowed...
        shader_set(sha_red); // Apply the appropriate highlight shader...
        draw_self(); // Then draw again with the shader applied...
        shader_reset(); // Then reset the shader to its normal state...
    } else { // ELSE IF nothing is preventing this action from being taken...
        shader_set(sha_green); // Apply the appropriate highlight shader...
        draw_self(); // Then draw again with the shader applied...
        shader_reset(); // Then reset the shader to its normal state...
        with (other) { // When the player's mouse is inside of the safe construction area...
            if (position_meeting(mouse_x,mouse_y,other)) { // Figure out which tile the player's mouse is on...
                draw_rectangle_color(x-32,y-32,x+32,y+32,c_green,c_green,c_green,c_green,false); // Then draw a rectangle to show where the sentry might be placed...
                if (mouse_check_button_pressed(mb_left)) { // IF the player clicks to build a sentry on this safe spot...
                    if (obj_scoreboard.credits >= seed_cost) { // IF the player has enough credits to cover the cost of a sentry...
                        instance_create_layer(x,y,"Sentry_Bottoms",obj_sentry_bottom); // Create a new sentry in the spot designated...
                        obj_scoreboard.credits -= sentry_cost;
                    }
                }
            }
           
        }
    }
}
This is all functional, but creates an experience that leaves a lot to be desired. I'm looking for advice from anyone that has tackled this kind of system before and feels like they have a better solution I can try.
 

Attachments

YoSniper

Member
I think you're off to a good start, but you can compress some of the states and conditions to simplify your code.

Code:
draw_self(); // Draw the soil as normal...

/* -------------------- */

// COLLISION VARIABLES

has_sentry = place_meeting(x,y,obj_sentry_parent);
has_enemy = place_meeting(x,y,obj_enemy_parent);
has_crop = place_meeting(x,y,obj_crop_parent);
has_portal = place_meeting(x,y,obj_portal);

// SIMPLIFICATION STATE VARIABLE(S)

var occupied = has_sentry or has_enemy or has_crop or has_portal; //Make this easier, as it applies to all conditions below...
var conflicted = occupied;
if obj_player_accessories.loadout != playerLoadout.plows {
    conflicted = conflicted or not plowed
}

if highlighted {
    //First, apply shader
    var shade_color = sha_green;
    if conflicted {
        shade_color = sha_red;
    } else if obj_player_accessories.loadout == playerLoadout.watering_can {
        shade_color = sha_blue;
    }
    shader_set(shade_color); // Apply the appropriate highlight shader...
    draw_self(); // Then draw again with the shader applied...
    shader_reset(); // Then reset the shader to its normal state...
    
    //Next, check mouse interaction
    switch(obj_player_accessories.loadout) {
        case playerLoadout.plows: //Plowing
            if not conflicted and position_meeting(mouse_x, mouse_y, other) {
                draw_rectangle_color(other.x-32,other.y-32,other.x+32,other.y+32,c_green,c_green,c_green,c_green,false); // Then draw a rectangle to show where the sentry might be placed...
                if (mouse_check_button_pressed(mb_left)) and (obj_scoreboard.credits >= seed_cost) { // IF the player clicks AND has enough credits to cover the cost of a sentry...
                    instance_create_layer(other.x, other.y, "Sentry_Bottoms", obj_sentry_bottom); // Create a new sentry in the spot designated...
                    obj_scoreboard.credits -= sentry_cost;
                }
            }
            break;
        
        case playerLoadout.watering_cans {
            if not conflicted and obj_player_accessories.watering { // IF the player is watering the tiles underneath them...
                watered = true; // Then this tile is now set to watered...
            }
            break;
        
        //Add in similar code for other states here. I would, but I"m out of time.
    }
}
 
Top