• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Selecting An Object with a Gamepad

S

SebtheDev()

Guest
Hey there,
For my upcoming game - PlayUSA we are implementing controller support, the problem is that as the map has cities on it I need to have the cities selectable, but since it is very unlikely that a user is going to select the exact direction of the city so I was wondering if any of you guys knew a good way to do this!

My Code:
Code:
if(instance_exists(obj_map_city)) {
    if ((gamepad_axis_value(0, gp_axislh) != 0) || (gamepad_axis_value(0, gp_axislv) != 0) and game_state = 2) {
        var haxis = gamepad_axis_value(0, gp_axislh);
        var vaxis = gamepad_axis_value(0, gp_axislv);
        direction = point_direction(0, 0, haxis, vaxis);
        var new_parent = collision_line_first(x,y,x+lengthdir_x(640,direction),y+lengthdir_y(360,direction),obj_map_city,true,parent);
        show_message(new_parent);
        x = new_parent.x;
        y = new_parent.y;
        parent = new_parent;
    } else if(parent != 0) {
        x = parent.x;
        y = parent.y;
    }
}
And the collision_line_first script (I got this online):
Code:
///@desc collision_line_first
///@param x1
///@param y1
///@param x2
///@param y2
///@param object
///@param prec
///@param notme
/// collision_line_first(x1,y1,x2,y2,object,prec,notme)
//
//  Returns the instance id of an object colliding with a given line and
//  closest to the first point, or noone if no instance found.
//  The solution is found in log2(range) collision checks.
//
//      x1,y2       first point on collision line, real
//      x2,y2       second point on collision line, real
//      object      which objects to look for (or all), real
//      prec        if true, use precise collision checking, bool
//      notme       if true, ignore the calling instance, bool
//
/// GMLscripts.com/license
{
    var ox,oy,dx,dy,object,prec,notme,sx,sy,inst,i;
    ox = argument0;
    oy = argument1;
    dx = argument2;
    dy = argument3;
    object = argument4;
    prec = argument5;
    notme = argument6;
    sx = dx - ox;
    sy = dy - oy;
    inst = collision_line(ox,oy,dx,dy,object,prec,notme);
    if (inst != noone) {
        while ((abs(sx) >= 1) || (abs(sy) >= 1)) {
            sx /= 2;
            sy /= 2;
            i = collision_line(ox,oy,dx,dy,object,prec,notme);
            if (i) {
                dx -= sx;
                dy -= sy;
                inst = i;
            }else{
                dx += sx;
                dy += sy;
            }
        }
    }
    return inst;
}
Help would be greatly appreciated (and maybe rewarded!)

Thanks,
Seb
 

obscene

Member
Well you didn't really describe exactly what you're doing very well... but you have cities on a map and you want the player to just point the stick at them from the center of the screen or something?

Probably the easiest way would be to just set zones for each.

if dir => 0 & dir < 45 selected_city=1;
else if dir >=45 && dir <90 selected_city=2;

You could also calculate a point on a line based on the stick angle and then just use instance_nearest if you're using objects for your cities and they are fairly spaced out.
 
S

SebtheDev()

Guest
Hi,
Thanks for the response! My game has many icons, this screenshot will help:

So that solution won't work. Do you have any other ideas?

Thanks so much,
Seb
 
S

SebtheDev()

Guest
The game is going to be on console so the cursor won't be usable.
 

lazertrax

Member
Make an object that simulates a cursor and moves according to stick angle, then with simple collision check which city marker is colliding with it.
 
S

SebtheDev()

Guest
Hmm, it is just that is quite counter-intuitive, are you sure there is no other way to do it?
 

Bingdom

Googledom
I don't see how a cursor wouldn't work. It would be a lot more difficult to select cities the way you are describing. What if you're trying to aim towards a city that's behind another city?
 
Last edited:

Seryal

Member
Couldn't you assign each marker with a variable and cycle through them by hitting either left or right? A lot of games do that opposed to using a cursor. You could even make the icon highlighted, or larger in size when it's being 'hovered'. You could use like an instance_nearest and the direction of the key to determine which city to highlight/hover next.

-Sorry if that doesn't make sense..
 
S

SebtheDev()

Guest
@Seryal Thanks for your response - is there a way to have a direction for instance_nearest? I haven't seen that.
 
D

Deanaro

Guest
You could use a raycast from the current selected city and go to whichever object the raycast hits first.
 
I'd try something like this:

1. get the directional input, and set a range of acceptable angles (ie, "right" gets icons <= 45 and >= 315, "up" gets >= 45 and <= 135)
2. set a "nearest icon distance" value as something impossibly huge
3. scan through every icon, and if it is both in the angle range and its distance is less than the "nearest icon distance," set it as your new selected icon, and also set the nearest angle distance to that icon's distance.

There might be a simpler way to do it, but that way you'd end up with the closest icon "approximately" in whatever direction the player presses. You'd probably have to test a lot and finesse the angle range. If it's too wide (like the 90 degree increment I suggested) you'll select icons that don't look like they're the ones you wanted, and if it's too narrow there would be icons that look like they can be selected from the current position but actually can't. And if you had only icons that were at a diagonal angle away from each other, you might not be able to pick anything!
 

Seryal

Member
I'll have to wait for my license to be renewed so that I can mock up an example of what I was referring to. The trial does not allow for all of the functions I need. If you haven't found a solution in a week or so, I'll make an example project as soon as I can for you.
 

Seryal

Member
Hm, so using the method I was thinking of I was able to create a system that will move through an array of city IDs regardless the number of cities shown, and in any position, and it's working just fine; however I see your original issue showing up in my code as well; where the next highlighted city is not necessarily "the nearest one in the direction pointed at" from the previous city. I think, with using the other member's suggestions I can implement this directional feature; but I'm taking a break from it now. I just wanted to let you know that I was able to work on it tonight and have not forgotten about your dilemma!
 

Electros

Member
One option could be to restrict navigation inputs to up down left right only. You could then have a 2D array / ds_grid where each territory has its own entry, then within that contains pointers for which territory to navigate to if the user selects up, down, left or right. For the territories at the edge, you could either wrap around or simply have no action if the user tries to go over the edge (if no pointer contained for that direction).

MapDMockup.png

To try and avoid confusion where there could be two (or more) potential territories (e.g. in the first pic, right navigation could go to blue or yellow), for each territory with a navigation option, it would probably be a good idea to have visual pointers to the territory that would be traversed to. These draw positions for the pointers could again be contained as data within the array / ds_grid, and drawn for the selected territory.
 
Top