GMS 2 get location of point in max range (grid based)

Discussion in 'Programming' started by trentallain, Jun 29, 2019.

  1. trentallain

    trentallain Member

    Joined:
    Aug 6, 2016
    Posts:
    521
    Okay so I got the AI working thanks to the kind people in my other post, however I have a new issue now. What my AI is currently doing, is moving next to the closest opposing unit. What I want to do is make it move so that that the AI unit is attacking from it's furthest attack range distance, as this makes more sense.

    Obviously if the AI unit's attack range is only 1, then it can keep moving up to the target, however I don't know how to do it if the range is greater than that. The unit's can not move diagonally.

    Here's a diagram I made (with made up symbols):
    example_diagram.png

    The red square is the AI unit. The blue square is it's target that it wants to attack. The pink cross is the location I want to know how to find. The dotted line is just an example path of how to get there. The green squares are the locations that are within range at the point I want to find.

    How do I find the ideal location (pink cross's location) so that the AI unit is moving to it's maximum range that it can attack from? Also, the AI unit could be anywhere on the grid, not just the location in the diagram.

    Not sure on how to approach this.
     
  2. Turkish Coffee

    Turkish Coffee Member

    Joined:
    Nov 25, 2016
    Posts:
    559
    I would just use
    Code:
    if (point_distance(...) =< MaxRange)
     {
      //execute attack
     }
    
    maybe thats what you want? or you want grid based checking?

    Edit: you can draw the range to see it in game with "draw_circle(x,y,MaxRange,true);" in a Draw Event
     
  3. trentallain

    trentallain Member

    Joined:
    Aug 6, 2016
    Posts:
    521
    Oh oops, grid based
    Edit: And I need the location to move to
    Edit 2: and if it is already in range, it should move away from its target (so that the target is in range but it is as far away as it can go)
     
  4. trentallain

    trentallain Member

    Joined:
    Aug 6, 2016
    Posts:
    521
  5. RefresherTowel

    RefresherTowel Member

    Joined:
    Jul 13, 2016
    Posts:
    1,175
    Grid based point_distance should still work fine. Instead of pixels, imagine the input to the point_direction as grid squares. Just make sure your max range is based off of the grid distance, not the pixel distance.
    Code:
    if (point_distance(grid_x,grid_y,target_grid_x,target_grid_y) >= max_range) {
       // movement here
    }
     
    trentallain likes this.
  6. trentallain

    trentallain Member

    Joined:
    Aug 6, 2016
    Posts:
    521
    That just finds whether something is in range. How can I find a position that is the furthest square away from a target and within its own attack range?
     
  7. JackTurbo

    JackTurbo Member

    Joined:
    Oct 19, 2016
    Posts:
    821
    Simplest approach would be to path find directly to the enemy performing a rage check after each square of movement and stop as soon as you are in range
     
    trentallain likes this.
  8. trentallain

    trentallain Member

    Joined:
    Aug 6, 2016
    Posts:
    521
    Thanks, that concept is easier than what I was thinking!
    Here's what I came up with to try and do this, however none of the units move.

    Key words:
    MP = movement points (who many squares you can move)
    Range = the radius that you can attack from

    Here's code:
    Code:
    // If there are AI units to be controlled
    if ds_priority_size(ai_unit_priority) > 0 {
        // Get the AI unit that is the closest to the player
        var _ai_unit = ds_priority_find_min(ai_unit_priority);
        // If AI can input
        switch (ai_state) {
            case menu.inputting:
                // Create AI mp grid
                var _grid_w = ds_grid_width(global.grid);
                var _grid_h = ds_grid_height(global.grid);
                var _ai_mp_grid = mp_grid_create(0,0,_grid_w,_grid_h,grid.size,grid.size);
                // Find closest player unit
                var _ai_target = ai_get_closest(_ai_unit.x,_ai_unit.y);
                // If the unit isn't trying to move to it's current cell
                if _ai_unit.grid_x != _ai_target.grid_x && _ai_unit.grid_y != _ai_target.grid_y {
                    // Convert global.grid to an mp grid
                    for (var u = 0; u < _grid_w; u++) {
                        for (var v = 0; v < _grid_h; v++) {
                            // If the grid position isn't free
                            if global.grid[# u, v] != -1 {
                                // Set that position as taken in the mp grid
                                mp_grid_add_cell(_ai_mp_grid, u, v);
                            }
                        }
                    }
                    // Clear starting position and clear target position
                    mp_grid_clear_cell(_ai_mp_grid,_ai_unit.grid_x,_ai_unit.grid_y);
                    mp_grid_clear_cell(_ai_mp_grid,_ai_target.grid_x,_ai_target.grid_y);
                    // If there is a path
                    with (_ai_unit) {
                        // Tell the unit that AI is controlling it
                        ai_selected = id;
                        // Tell the unit its target
                        ai_target = _ai_target;
                        // Clear path points
                        path_clear_points(ai_path);
                        // Create the path regardless if you can fully traverse it
                        mp_grid_path(_ai_mp_grid, ai_path, grid_x * grid.size + 10, grid_y * grid.size + 10, _ai_target.grid_x * grid.size + 10, _ai_target.grid_y * grid.size + 10, false)
                        // Delete end point of the path (because this is where the target is)
                        path_delete_point(ai_path, path_get_number(ai_path) - 1);       
                        // Delete points that are either exceeding MP or are blocked
                        var _path_end = -1;
                        // Find where/if the path breaks
                        for (var i = 0; i < path_get_number(ai_path); ++i) {
                            // Get path's grid coordinates at this position
                            var _xpos = path_get_x(ai_path, i) div grid.size;
                            var _ypos = path_get_y(ai_path, i) div grid.size;
                            // Check if target is in range yet
                            var _in_range = point_distance(grid_x, grid_y, ai_target.x, ai_target.y) < range;
                            // If the path is larger than MP, or the position is taken on the grid, or the target is now within range
                            if path_get_number(ai_path) > mp || global.grid[# _xpos, _ypos] != -1 || _in_range {
                                // Set this point as the point to end the path at
                                _path_end = i;
                                break;
                            }
                        }
                        // If the path has broken somewhere
                        if _path_end != -1 {
                            for (var i = _path_end; i < path_get_number(ai_path); ++i) {
                                // Delete all remaining points
                                path_delete_point(ai_path, i);
                            }
                        }
                        other.ai_state = menu.paused;
                        // Update grid coordinates
                        global.grid[# grid_x, grid_y] = -1;
                        // Get the end point of the path in grid coordinates
                        var _end_x = path_get_point_x(ai_path, path_get_number(ai_path) - 1) div grid.size;
                        var _end_y = path_get_point_y(ai_path, path_get_number(ai_path) - 1) div grid.size;
                        global.grid[# _end_x, _end_y] = id;
                        grid_x = _end_x;
                        grid_y = _end_y;
                        // Follow the path
                        path_start(ai_path, 3, path_action_stop, false);   
                    }
                }
                // Clean up
                mp_grid_destroy(_ai_mp_grid);
                ds_priority_delete_min(ai_unit_priority);
                break;
        }   
    }
    else {
        if ai_state == menu.inputting {
            // Change turns and clean up
            global.turn = "ally";
            global.menu_state = menu.inputting;
            global.created_ai_controller = false;
            ds_priority_destroy(ai_unit_priority);
            instance_destroy();
        }
    }
    
    And here's the original code that worked, but only moved the units without taking into account MP, Range, or getting as close as possible even if a target unit is surrounded already
    Code:
    // If there are AI units to be controlled
    if ds_priority_size(ai_unit_priority) > 0 {
        // Get the AI unit that is the closest to the player
        var _ai_unit = ds_priority_find_min(ai_unit_priority);
        // If AI can input
        switch (ai_state) {
            case menu.inputting:
                // Create AI mp grid
                var _grid_w = ds_grid_width(global.grid);
                var _grid_h = ds_grid_height(global.grid);
                var _ai_mp_grid = mp_grid_create(0,0,_grid_w,_grid_h,grid.size,grid.size);
                // Find closest player unit
                var _ai_target = ai_get_closest(_ai_unit.x,_ai_unit.y);
                // If the unit isn't trying to move to it's current cell
                if _ai_unit.grid_x != _ai_target.grid_x && _ai_unit.grid_y != _ai_target.grid_y {
                    // Convert global.grid to an mp grid
                    for (var u = 0; u < _grid_w; u++) {
                        for (var v = 0; v < _grid_h; v++) {
                            // If the grid position isn't free
                            if global.grid[# u, v] != -1 {
                                // Set that position as taken in the mp grid
                                mp_grid_add_cell(_ai_mp_grid, u, v);
                            }
                        }
                    }
                    // Clear starting position and add target position
                    mp_grid_clear_cell(_ai_mp_grid,_ai_unit.grid_x,_ai_unit.grid_y);
                    mp_grid_clear_cell(_ai_mp_grid,_ai_target.grid_x,_ai_target.grid_y);
                    // If there is a path
                    with (_ai_unit) {
                        // Tell the unit that AI is controlling it
                        ai_selected = id;
                        // Tell the unit its target
                        ai_target = _ai_target;
                        // Clear path points
                        path_clear_points(ai_path);
                        // If there is a path
                        if mp_grid_path(_ai_mp_grid, ai_path, grid_x * grid.size + 10, grid_y * grid.size + 10, _ai_target.grid_x * grid.size + 10, _ai_target.grid_y * grid.size + 10, false) {
                            // Delete end point of the path (because this is where the target is)
                            path_delete_point(ai_path, path_get_number(ai_path) - 1);                   
                            other.ai_state = menu.paused;
                            // Update grid coordinates
                            global.grid[# grid_x, grid_y] = -1;
                            // Get the end point of the path in grid coordinates
                            var _end_x = path_get_point_x(ai_path, path_get_number(ai_path) - 1) div grid.size;
                            var _end_y = path_get_point_y(ai_path, path_get_number(ai_path) - 1) div grid.size;
                            global.grid[# _end_x, _end_y] = character;
                            grid_x = _end_x;
                            grid_y = _end_y;
                            // Follow the path
                            path_start(ai_path, 3, path_action_stop, false);   
                        }
                    }
                }
                // Clean up
                mp_grid_destroy(_ai_mp_grid);
                ds_priority_delete_min(ai_unit_priority);
                break;
        }   
    }
    else {
        if ai_state == menu.inputting {
            // Change turns and clean up
            global.turn = "ally";
            global.menu_state = menu.inputting;
            global.created_ai_controller = false;
            ds_priority_destroy(ai_unit_priority);
            instance_destroy();
        }
    }
    
     
  9. trentallain

    trentallain Member

    Joined:
    Aug 6, 2016
    Posts:
    521
  10. trentallain

    trentallain Member

    Joined:
    Aug 6, 2016
    Posts:
    521
    I realised that I was using path_get_x instead of path_get_point_x for one part, however still can't find why nothing is moving.

    Code:
    // If there are AI units to be controlled
    if ds_priority_size(ai_unit_priority) > 0 {
        // Get the AI unit that is the closest to the player
        var _ai_unit = ds_priority_find_min(ai_unit_priority);
        // If AI can input
        switch (ai_state) {
            case menu.inputting:
                // Create AI mp grid
                var _grid_w = ds_grid_width(global.grid);
                var _grid_h = ds_grid_height(global.grid);
                var _ai_mp_grid = mp_grid_create(0,0,_grid_w,_grid_h,grid.size,grid.size);
                // Find closest player unit
                var _ai_target = ai_get_closest(_ai_unit.x,_ai_unit.y);
                // If the unit isn't trying to move to it's current cell
                if _ai_unit.grid_x != _ai_target.grid_x && _ai_unit.grid_y != _ai_target.grid_y {
                    // Convert global.grid to an mp grid
                    for (var u = 0; u < _grid_w; u++) {
                        for (var v = 0; v < _grid_h; v++) {
                            // If the grid position isn't free
                            if global.grid[# u, v] != -1 {
                                // Set that position as taken in the mp grid
                                mp_grid_add_cell(_ai_mp_grid, u, v);
                            }
                        }
                    }
                    // Clear starting position and clear target position
                    mp_grid_clear_cell(_ai_mp_grid,_ai_unit.grid_x,_ai_unit.grid_y);
                    mp_grid_clear_cell(_ai_mp_grid,_ai_target.grid_x,_ai_target.grid_y);
                    // If there is a path
                    with (_ai_unit) {
                        // Tell the unit that AI is controlling it
                        ai_selected = id;
                        // Tell the unit its target
                        ai_target = _ai_target;
                        // Clear path points
                        path_clear_points(ai_path);
                        // Create the path regardless if you can fully traverse it
                        mp_grid_path(_ai_mp_grid, ai_path, grid_x * grid.size + 10, grid_y * grid.size + 10, _ai_target.grid_x * grid.size + 10, _ai_target.grid_y * grid.size + 10, false)
                        // Delete end point of the path (because this is where the target is)
                        path_delete_point(ai_path, path_get_number(ai_path) - 1);       
                        // Delete points that are either exceeding MP or are blocked
                        var _path_end = -1;
                        // Find where/if the path breaks
                        for (var i = 0; i < path_get_number(ai_path); ++i) {
                            // Get path's grid coordinates at this position
                            var _xpos = path_get_point_x(ai_path, i) div grid.size;
                            var _ypos = path_get_point_y(ai_path, i) div grid.size;
                            // Check if target is in range yet
                            var _in_range = point_distance(_xpos, _ypos, ai_target.x, ai_target.y) < range;
                            // If the path is larger than MP, or the position is taken on the grid, or the target is now within range
                            if path_get_number(ai_path) > mp || global.grid[# _xpos, _ypos] != -1 || _in_range {
                                // Set this point as the point to end the path at
                                _path_end = i;
                                break;
                            }
                        }
                        // If the path has broken somewhere
                        if _path_end != -1 {
                            for (var i = _path_end; i < path_get_number(ai_path); ++i) {
                                // Delete all remaining points
                                path_delete_point(ai_path, i);
                            }
                        }
                        other.ai_state = menu.paused;
                        // Update grid coordinates
                        global.grid[# grid_x, grid_y] = -1;
                        // Get the end point of the path in grid coordinates
                        var _end_x = path_get_point_x(ai_path, path_get_number(ai_path) - 1) div grid.size;
                        var _end_y = path_get_point_y(ai_path, path_get_number(ai_path) - 1) div grid.size;
                        global.grid[# _end_x, _end_y] = id;
                        grid_x = _end_x;
                        grid_y = _end_y;
                        // Follow the path
                        path_start(ai_path, 3, path_action_stop, false);   
                    }
                }
                // Clean up
                mp_grid_destroy(_ai_mp_grid);
                ds_priority_delete_min(ai_unit_priority);
                break;
        }   
    }
    else {
        if ai_state == menu.inputting {
            // Change turns and clean up
            global.turn = "ally";
            global.menu_state = menu.inputting;
            global.created_ai_controller = false;
            ds_priority_destroy(ai_unit_priority);
            instance_destroy();
        }
    }
    
     
    Last edited: Jul 7, 2019

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice