• 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!

SOLVED Vehicle Mechanics

Hi All!

So I'm making this pixel RPG-styled game, anyways, I'm trying to add "vehicles".

I was able to get the vehicle moving and whatnot, the next thing I'm trying to do is have it where my player can enter/exit the said vehicle.

I figure I just make it where the player turns invisible and reposition itself to the vehicle, the problem is, I'm pretty much new to all this and I'm not quite sure how to do that, or if that's even the best way of doing this.

I've been following tutorials on Youtube and getting a better understanding as I go, so thanks in advance for helping little 'ol me!

Here's a copy of the vehicle's code:

***CREATE***

GML:
//movement configs
xspd = 0;
yspd = 0;

move_spd = 2;


sprite[RIGHT] = spr_gatty_wagon_base_right;
sprite[UP] = spr_gatty_wagon_base_up;
sprite[LEFT] = spr_gatty_wagon_base_left;
sprite[DOWN] = spr_gatty_wagon_base_down;

face = RIGHT;
***STEP***
Code:
//direction control movements
right_key = keyboard_check(ord("D")) || keyboard_check(vk_right);
left_key = keyboard_check(ord("A")) || keyboard_check(vk_left);
up_key = keyboard_check(ord("W")) || keyboard_check(vk_up);
down_key = keyboard_check(ord("S")) || keyboard_check(vk_down);
//attack_key = keyboard_check(vk_space);

//get xspd and yspd
xspd = (right_key - left_key) * move_spd;
yspd = (down_key - up_key) * move_spd;

//collision func.
if place_meeting(x + xspd, y, obj_wall) == true
    {
    xspd = 0;
    }
if place_meeting(x, y + yspd, obj_wall) == true
    {
    yspd = 0;
    }
    
if keyboard_check(ord("E"))
    {
    riding = true;
    //set sprite
    mask_index = sprite[RIGHT];
    if yspd == 0
        {
        if xspd > 0 {face = RIGHT};
        if xspd < 0 {face = LEFT};
        }
    if xspd == 0
        {
        if yspd > 0 {face = DOWN};
        if yspd < 0 {face = UP};
        }
    sprite_index = sprite[face];

    //move the gatty wagon
    x += xspd;
    y += yspd;
    
    //animate
    if xspd == 0 && yspd == 0
        {
        image_index = 0;
        }

    }
//depth
depth = -bbox_bottom;
And the player's:

***CREATE***


Code:
//health of player
hp = 50;
hp_max = 100;

healthbar_width = 200;
healthbar_hieght = 24;
healthbar_x = 1250 - (healthbar_width/2)
healthbar_y = ystart - 50;

inventory_x = 35;
inventory_y = ystart - 70;

//status
riding = false;

//player's bacon bits
bits = 0;

//player's level
xp = 0;
lvl = 1;

//movement configs
xspd = 0;
yspd = 0;

move_spd = 1;


sprite[RIGHT] = spr_player_right;
sprite[UP] = spr_player_up;
sprite[LEFT] = spr_player_left;
sprite[DOWN] = spr_player_down;

face = DOWN;
***STEP***

Code:
//direction control movements
right_key = keyboard_check(ord("D")) || keyboard_check(vk_right);
left_key = keyboard_check(ord("A")) || keyboard_check(vk_left);
up_key = keyboard_check(ord("W")) || keyboard_check(vk_up);
down_key = keyboard_check(ord("S")) || keyboard_check(vk_down);
//attack_key = keyboard_check(vk_space);

//get xspd and yspd
xspd = (right_key - left_key) * move_spd;
yspd = (down_key - up_key) * move_spd;

//pause
if instance_exists(obj_pauser)
    {
    xspd = 0;
    yspd = 0;
    }


//set sprite
mask_index = sprite[DOWN];
if yspd == 0
    {
    if xspd > 0 {face = RIGHT};
    if xspd < 0 {face = LEFT};
    }
if xspd == 0
    {
    if yspd > 0 {face = DOWN};
    if yspd < 0 {face = UP};
    }
sprite_index = sprite[face];


//collision func.
if place_meeting(x + xspd, y, obj_wall) == true
    {
    xspd = 0;
    }
if place_meeting(x, y + yspd, obj_wall) == true
    {
    yspd = 0;
    }


//move the player
x += xspd;
y += yspd;


//animate
if xspd == 0 && yspd == 0
    {
    image_index = 0;
    }

if riding == true
    {
    //object_set_visible(obj_player, false);
    
    }

//depth
depth = -bbox_bottom;
Screenshot 2021-12-08 151058.png
 
Last edited:
First off, please format your code properly with Insert -> code, otherwise it's unreadable.

As for your problem, this is not a coding problem, but a logic problem.
You say you just make the player invisible, but that's not going to work. Most likely player and vehicule are not going to go at the same speed. And invisibility won't prevent your player to respond to inputs either. In the end, if all goes well, you'll 'get out the car' with an offset between player and vehicule.
A way around would be to 'stick' your player to the car, I hear you say, but even then, say you press 'fire' or 'jump', nothing will prevent the player to shoot or uses the actions he's allowed to do on foot.

Now, what you should do, although there are many options, is to have a player state that holds values like 'in_car', 'on_foot', etc... and use that variable to determine what your input does.
The concept:
GML:
if player_transportation == "in_car" {
    //car input code
} else
if player_transportation == "by_foot"{
    //player on foot code
}
I also suggest you use a switch instead of if/else, this was just to make it 100% easy to understand.
 
First off, please format your code properly with Insert -> code, otherwise it's unreadable.

As for your problem, this is not a coding problem, but a logic problem.
You say you just make the player invisible, but that's not going to work. Most likely player and vehicule are not going to go at the same speed. And invisibility won't prevent your player to respond to inputs either. In the end, if all goes well, you'll 'get out the car' with an offset between player and vehicule.
A way around would be to 'stick' your player to the car, I hear you say, but even then, say you press 'fire' or 'jump', nothing will prevent the player to shoot or uses the actions he's allowed to do on foot.

Now, what you should do, although there are many options, is to have a player state that holds values like 'in_car', 'on_foot', etc... and use that variable to determine what your input does.
The concept:
GML:
if player_transportation == "in_car" {
    //car input code
} else
if player_transportation == "by_foot"{
    //player on foot code
}
I also suggest you use a switch instead of if/else, this was just to make it 100% easy to understand.
My bad about the thread, fixed it.

I think I understand what you said, that makes better sense, I think I was just overthinking it.

Thanks for your help and understanding!
 
[UPDATE]
Thanks to the help above, I was able to get further into the process. Though, I've run into something else I'm not sure how to do...

I got the concept of "sticking" the player to the vehicle, the only thing is that it's not staying with the vehicle, my character just stays in one spot while the vehicle drives away.

I have it where the player basically pauses when it enters the vehicle and moves to its x and y position.

Also, I can't seem to have the player "exit" the vehicle. I might have complicated the code and made it pretty choppy, sorry about that.

Here's a copy of the code so far:
GML:
//player CREATE

//trans status
on_ride = false;
on_foot = true;
player_transportation = on_foot;

//player's bacon bits
bits = 0;

//player's level
xp = 0;
lvl = 1;

//movement configs
xspd = 0;
yspd = 0;

move_spd = 1;


sprite[RIGHT] = spr_player_right;
sprite[UP] = spr_player_up;
sprite[LEFT] = spr_player_left;
sprite[DOWN] = spr_player_down;

face = DOWN;

//player STEP

if keyboard_check(ord("E")) && place_meeting(x, y, obj_gatty_wagon)
    {
    player_transportation = on_ride;
    
    
    
    }
    
if keyboard_check(ord("E")) && player_transportation == on_ride
    {
    on_foot = true;
    on_ride = false;
    }

if player_transportation == on_ride {
    //car input code
    on_foot = false;
    
    xspd = 0;
    yspd = 0;
    
    } else
    if player_transportation == on_foot {
    //player on foot code
    on_ride = false;
    
    //direction control movements
    right_key = keyboard_check(ord("D")) || keyboard_check(vk_right);
    left_key = keyboard_check(ord("A")) || keyboard_check(vk_left);
    up_key = keyboard_check(ord("W")) || keyboard_check(vk_up);
    down_key = keyboard_check(ord("S")) || keyboard_check(vk_down);
    //attack_key = keyboard_check(vk_space);

    //get xspd and yspd
    xspd = (right_key - left_key) * move_spd;
    yspd = (down_key - up_key) * move_spd;

    //pause
    if instance_exists(obj_pauser)
        {
        xspd = 0;
        yspd = 0;
        }


    //set sprite
    mask_index = sprite[DOWN];
    if yspd == 0
        {
        if xspd > 0 {face = RIGHT};
        if xspd < 0 {face = LEFT};
        }
    if xspd == 0
        {
        if yspd > 0 {face = DOWN};
        if yspd < 0 {face = UP};
        }
    sprite_index = sprite[face];


    //collision func.
    if place_meeting(x + xspd, y, obj_wall) == true
        {
        xspd = 0;
        }
    if place_meeting(x, y + yspd, obj_wall) == true
        {
        yspd = 0;
        }


    //move the player
    x += xspd;
    y += yspd;


    //animate
    if xspd == 0 && yspd == 0
        {
        image_index = 0;
        }
    }

//depth
depth = -bbox_bottom;

//vehicle CREATE

//movement configs
xspd = 0;
yspd = 0;

move_spd = 2;


sprite[RIGHT] = spr_gatty_wagon_base_right;
sprite[UP] = spr_gatty_wagon_base_up;
sprite[LEFT] = spr_gatty_wagon_base_left;
sprite[DOWN] = spr_gatty_wagon_base_down;

face = RIGHT;

//vehicle STEP

//direction control movements
right_key = keyboard_check(ord("D")) || keyboard_check(vk_right);
left_key = keyboard_check(ord("A")) || keyboard_check(vk_left);
up_key = keyboard_check(ord("W")) || keyboard_check(vk_up);
down_key = keyboard_check(ord("S")) || keyboard_check(vk_down);
//attack_key = keyboard_check(vk_space);

//get xspd and yspd
xspd = (right_key - left_key) * move_spd;
yspd = (down_key - up_key) * move_spd;

//collision func.
if place_meeting(x + xspd, y, obj_wall) == true
    {
    xspd = 0;
    }
if place_meeting(x, y + yspd, obj_wall) == true
    {
    yspd = 0;
    }
    

//set sprite
mask_index = sprite[RIGHT];
if yspd == 0
    {
    if xspd > 0 {face = RIGHT};
    if xspd < 0 {face = LEFT};
    }
if xspd == 0
    {
    if yspd > 0 {face = DOWN};
    if yspd < 0 {face = UP};
    }
sprite_index = sprite[face];

if obj_player.player_transportation == obj_player.on_ride
    {
    //move the gatty wagon
    x += xspd;
    y += yspd;
    
    
    //animate
    if xspd == 0 && yspd == 0
        {
        image_index = 0;
        }
    
    }
    
    
//depth
depth = -bbox_bottom;
 
Well, for one thing, there's not really any point to the on_foot and on_ride variables, and assigning player_transportation to them is definitely a strange way of doing things that could easily introduce bugs. Set up an enum and toggle player_transportation between the enum states:

Player Create
GML:
enum move_states {
   WALK,
   RIDE
}
player_transportation = move_states.WALK;
Player Step
GML:
if (keyboard_check_released(ord("E"))) { // Player releases E
   if (player_transportation == move_states.WALK) { // First we check what state the player currently is in
      if (place_meeting(x,y,obj_gatty_wagon)) { // If the player is in the walk state, they're probably trying to get into the vehicle, so we check proximity with the vehicle
         player_transportation = move_states.RIDE; // If they are close enough, we set the player state to ride
      }
   }
   else { // Otherwise the player is in the ride state
      player_transportation = move_states.WALK; // So we can just set the state to walk to get them out of the vehicle
   }
}
Then, we want to remove this convoluted code:
GML:
if player_transportation == on_ride {
    //car input code
    on_foot = false;
//...
} else
    if player_transportation == on_foot {
    //player on foot code
    on_ride = false;
on_foot and on_ride are completely unnecessary, as player_transportation already holds what state we are in now. So we can change it to this:

Player Step
GML:
switch (player_transformation) { // Switch is a fancy if statement
   case move_states.WALK: // The code within a case will only run if player_transformation is equal to the case value, in this case the value is move_states.WALK so all the following code up until the break; will only run if player_transformation equals move_states.WALK

      //direction control movements
       right_key = keyboard_check(ord("D")) || keyboard_check(vk_right);
       left_key = keyboard_check(ord("A")) || keyboard_check(vk_left);
       up_key = keyboard_check(ord("W")) || keyboard_check(vk_up);
       down_key = keyboard_check(ord("S")) || keyboard_check(vk_down);
       //attack_key = keyboard_check(vk_space);

       //get xspd and yspd
       xspd = (right_key - left_key) * move_spd;
       yspd = (down_key - up_key) * move_spd;

       //pause
       if instance_exists(obj_pauser)
           {
           xspd = 0;
           yspd = 0;
           }


       //set sprite
       mask_index = sprite[DOWN];
       if yspd == 0
           {
           if xspd > 0 {face = RIGHT};
           if xspd < 0 {face = LEFT};
           }
       if xspd == 0
           {
           if yspd > 0 {face = DOWN};
           if yspd < 0 {face = UP};
           }
       sprite_index = sprite[face];


       //collision func.
       if place_meeting(x + xspd, y, obj_wall) == true
           {
           xspd = 0;
           }
       if place_meeting(x, y + yspd, obj_wall) == true
           {
           yspd = 0;
           }

       //animate
       if xspd == 0 && yspd == 0
           {
           image_index = 0;
           }

   break;
   case move_states.RIDE:

      xspd = 0;
      yspd = 0;

   break;
}

// We can move the actual movement outside of the player_transformation relevant code, because if the player is in the ride state, then xspd and vspd are equal to 0 and it doesn't matter if we add 0 to x and y
x += xspd;
y += yspd;
Finally, we get to the vehicle code. The most immediate thing to notice is you are not moving the player there, so of course the player will just stand still and not go anywhere. Let's assume you want the players x and y to be exactly where the vehicles x and y are. Also, I always think it's a bad idea to reference objects using dot notation, so we're going to use a with() statement to implicitly ask whether the player object exists or not and get the data from the player that way.

Replace this code:
GML:
if obj_player.player_transportation == obj_player.on_ride
    {
    //move the gatty wagon
    x += xspd;
    y += yspd;


    //animate
    if xspd == 0 && yspd == 0
        {
        image_index = 0;
        }

    }
With this code:

Vehicle Step
GML:
var _player_riding = false; // If the player doesn't exist or can't be accessed, we want the vehicle to act as though it's not being ridden, so we start off with a false value to this local variable

var _xx = x; // Then we want to store some of the car instance variables in local variables, so they can be easily accessed in the with() statement
var _yy = y;
var _hspd = hspd;
var _vspd = vspd;

with (obj_player) {
   if (player_transportation == move_states.RIDE) { // Check if the player is in ride state
      _player_riding = true; // If it is we set the local variable we are using to store whether the player is riding or not to true
      x = _x+_hspd; // Then we set the players x and y to the local variables we stored the cars instance variables in (x and y (plus the cars hspd and vspd, so the player doesn't lag a frame behind))
      y = _y+_vspd;
   }
}
if (_player_riding) { // If this is true, we know the player is riding
   x += hspd; // So do the riding stuff
   y += vspd;
   if xspd == 0 && yspd == 0
        {
        image_index = 0;
        }
}
This code isn't the most optimal way of handling all of this, but I think it's probably the easiest to convert your current code into (and I hope there isn't any bugs in it, lol). I think you need to spend a little more time thinking about how the code should flow when you're writing it. Make sure to do revisions and look for places where you are either duplicating data (as was the case with the on_ride and on_foot variables) that you could condense into a simpler form somehow, or places where functionality you wanted might be applicable (such as moving the player when the car moves so the player doesn't just stand there). FSM (finite state machines) are a godsend when it comes to these types of problems where you have two or more "states" that something could potentially be in that have divergent behaviour (in this case, our two states are walking or riding, both have distinct behaviour but they can be switched between at any point, so we implement a simple FSM to handle it). There's plenty of tutorials online going over how they work and how to implement them, so having a look over any of those would probably be a good idea. Good luck with your future coding =)
 
Last edited:
Well, for one thing, there's not really any point to the on_foot and on_ride variables, and assigning player_transportation to them is definitely a strange way of doing things that could easily introduce bugs. Set up an enum and toggle player_transportation between the enum states:

Player Create
GML:
enum move_states {
   WALK,
   RIDE
}
player_transportation = move_states.WALK;
Player Step
GML:
if (keyboard_check_released(ord("E")) { // Player releases E
   if (player_transportation == move_states.WALK) { // First we check what state the player currently is in
      if (place_meeting(x,y,obj_gatty_wagon)) { // If the player is in the walk state, they're probably trying to get into the vehicle, so we check proximity with the vehicle
         player_transportation = move_states.RIDE; // If they are close enough, we set the player state to ride
      }
   }
   else { // Otherwise the player is in the ride state
      player_transportation = move_states.WALK; // So we can just set the state to walk to get them out of the vehicle
   }
}
Then, we want to remove this convoluted code:
GML:
if player_transportation == on_ride {
    //car input code
    on_foot = false;
//...
} else
    if player_transportation == on_foot {
    //player on foot code
    on_ride = false;
on_foot and on_ride are completely unnecessary, as player_transportation already holds what state we are in now. So we can change it to this:

Player Step
GML:
switch (player_transformation) { // Switch is a fancy if statement
   case move_states.WALK: // The code within a case will only run if player_transformation is equal to the case value, in this case the value is move_states.WALK so all the following code up until the break; will only run if player_transformation equals move_states.WALK

      //direction control movements
       right_key = keyboard_check(ord("D")) || keyboard_check(vk_right);
       left_key = keyboard_check(ord("A")) || keyboard_check(vk_left);
       up_key = keyboard_check(ord("W")) || keyboard_check(vk_up);
       down_key = keyboard_check(ord("S")) || keyboard_check(vk_down);
       //attack_key = keyboard_check(vk_space);

       //get xspd and yspd
       xspd = (right_key - left_key) * move_spd;
       yspd = (down_key - up_key) * move_spd;

       //pause
       if instance_exists(obj_pauser)
           {
           xspd = 0;
           yspd = 0;
           }


       //set sprite
       mask_index = sprite[DOWN];
       if yspd == 0
           {
           if xspd > 0 {face = RIGHT};
           if xspd < 0 {face = LEFT};
           }
       if xspd == 0
           {
           if yspd > 0 {face = DOWN};
           if yspd < 0 {face = UP};
           }
       sprite_index = sprite[face];


       //collision func.
       if place_meeting(x + xspd, y, obj_wall) == true
           {
           xspd = 0;
           }
       if place_meeting(x, y + yspd, obj_wall) == true
           {
           yspd = 0;
           }

       //animate
       if xspd == 0 && yspd == 0
           {
           image_index = 0;
           }

   break;
   case move_states.RIDE:

      xspd = 0;
      yspd = 0;

   break;
}

// We can move the actual movement outside of the player_transformation relevant code, because if the player is in the ride state, then xspd and vspd are equal to 0 and it doesn't matter if we add 0 to x and y
x += xspd;
y += yspd;
Finally, we get to the vehicle code. The most immediate thing to notice is you are not moving the player there, so of course the player will just stand still and not go anywhere. Let's assume you want the players x and y to be exactly where the vehicles x and y are. Also, I always think it's a bad idea to reference objects using dot notation, so we're going to use a with() statement to implicitly ask whether the player object exists or not and get the data from the player that way.

Replace this code:
GML:
if obj_player.player_transportation == obj_player.on_ride
    {
    //move the gatty wagon
    x += xspd;
    y += yspd;
 
 
    //animate
    if xspd == 0 && yspd == 0
        {
        image_index = 0;
        }
 
    }
With this code:

Vehicle Step
GML:
var _player_riding = false; // If the player doesn't exist or can't be accessed, we want the vehicle to act as though it's not being ridden, so we start of with a false value to this local variable

var _xx = x; // Then we want to store some of the car instance variables in local variables, so they can be easily accessed in the with() statement
var _yy = y;
var _hspd = hspd;
var _vspd = vspd;

with (obj_player) {
   if (player_transportation == move_states.RIDE) { // Check if the player is in ride state
      _player_riding = true; // If it is we set the local variable we are using to store whether the player is riding or not to true
      x = _x+_hspd; // Then we set the players x and y to the local variables we stored the cars instance variables in (x and y (plus the cars hspd and vspd, so the player doesn't lag a frame behind))
      y = _y+_vspd;
   }
}
if (_player_riding) { // If this is true, we know the player is riding
   x += hspd; // So do the riding stuff
   y += vspd;
   if xspd == 0 && yspd == 0
        {
        image_index = 0;
        }
}
This code isn't the most optimal way of handling all of this, but I think it's probably the easiest to convert your current code into (and I hope there isn't any bugs in it, lol). I think you need to spend a little more time thinking about how the code should flow when you're writing it. Make sure to do revisions and look for places where you are either duplicating data (as was the case with the on_ride and on_foot variables) that you could condense into a simpler form somehow, or places where functionality you wanted might be applicable (such as moving the player when the car moves so the player doesn't just stand there). FSM (finite state machines) are a godsend when it comes to these types of problems where you have two or more "states" that something could potentially be in that have divergent behaviour (in this case, our two states are walking or riding, both have distinct behaviour but they can be switched between at any point, so we implement a simple FSM to handle it). There's plenty of tutorials online going over how they work and how to implement them, so having a look over any of those would probably be a good idea. Good luck with your future coding =)
Oh WOW! Thank you! I get so much help on here. This makes a lot of sense. I think my problem is that I just jumped into this without any idea really, so I've been learning as I go and trying to watch tutorials as much I can. I really enjoy this as a hobby if nothing else, so that's what keeps me going, lol. I'll give this a shot, I think I got this. I'm pretty sure this won't be the last anyone hears from me...
 
[UPDATE]

With a tiny bit of tweaking and messing around from the help @RefresherTowel gave, I was able to get it all worked out, I can enter/exit the vehicle, I made it where the character turns invisible/visble. Thanks a bunch for the help so for ya'll!


So, the only thing is that the vehicle shakes when I'm riding around, I had this issue before on a previous game I was working on with a different game design platform. I'm going to do some research, I'm sure it will be relatively easy to find about, just letting y'all know!
 

CMAllen

Member
If the vehicle is its own object 'following' the player, I know the answer -- it's an execution-order problem. It's a common mistake. One object's actions is dependent on the actions of another object. When these objects execute their code in the right order, it's not a problem. But when they don't, the first object's is running its code before the object it's dependent on has executed its own, so the first object is actually executing its code relative to the object its dependent on from the *previous* frame/step. The result is that the first object is a frame/step out of sync.

The solution:
Move the wagon via the player, instead of the wagon moving itself to wherever it thinks the player is -- just rip all that movement code from the wagon's step event. Instead, keep the instance ID of the wagon stored to the player object, and after the player object runs its movement code, update the wagon to the player's position.
 
If the vehicle is its own object 'following' the player, I know the answer -- it's an execution-order problem. It's a common mistake. One object's actions is dependent on the actions of another object. When these objects execute their code in the right order, it's not a problem. But when they don't, the first object's is running its code before the object it's dependent on has executed its own, so the first object is actually executing its code relative to the object its dependent on from the *previous* frame/step. The result is that the first object is a frame/step out of sync.
Ah, I remember hearing about something like that. Thanks for the info! I'll see what I can do, it's not really bothering me too much, as it kinda fits the "theme" of the vehicle but I would like to see how it looks otherwise.

Is there a way I could maybe "stop" the first object's code that is causing that? Such as if a variable is set to true/false, one object is "inactive/active".
 

CMAllen

Member
I should also point out that if the player is supposed to be a passenger on the wagon, and the wagon is following a predetermined path (the player object is just a passenger, rather than controlling the wagon), you would disable player movement while acting as a passenger, and the wagon object controls the player object's movement.

(also, see above edit)
 
I should also point out that if the player is supposed to be a passenger on the wagon, and the wagon is following a predetermined path (the player object is just a passenger, rather than controlling the wagon), you would disable player movement while acting as a passenger, and the wagon object controls the player object's movement.

(also, see above edit)
Awesome! Thanks for the help! The wagon is supposed to be controlled by the player, so that's where it got a little complicated for me.

Just wait until I TRY to do what I have planned next, I'm wanting to add a turret on top of the wagon as a separate object that is controlled via mouse and follow the pointer. At least that's how I think I could get it to work in my head... As well as adding other types of "vehicles", so I'm going to have to make sure the code is somewhat universal(maybe), being that each vehicle I'm going to add is going to have different functions...

Thanks again!
 

CMAllen

Member
Similar idea there -- the turret doesn't move itself (though it would turn itself). Instead the wagon moves the turret. And if the player object is controlling the wagon, then the player object also moves the turret.
 
I think my problem is that I just jumped into this without any idea really
A little late in the year, but still, this seriously deserves to be in line for the award of 'Best self-awareness among new members' in 2021.
I think you're going to get the hang of this, eventuallyšŸ‘Œ

Just wait until I TRY to do what I have planned next, I'm wanting to add a turret on top of the wagon as a separate object that is controlled via mouse and follow the pointer. At least that's how I think I could get it to work in my head... As well as adding other types of "vehicles", so I'm going to have to make sure the code is somewhat universal(maybe), being that each vehicle I'm going to add is going to have different functions...
This method has no limit. As long as player_transportation is set to the right thing, you could have horses, cars, planes, shoes, skatebaards, rollerblades and jet-skis...
Just add new enums, make sure you change player_transportation at the right time for the right thing, and keep organized in your input code so you don't confuse yourself.
Principle is the same, but, one thing you'll learn soon enough, is that the difficulty of a project is exponentially proportional to it's scope. It's definitly not a linear scale at any rate!
 
Another thing to point out is that if you're looking for maximum flexibility you can abstract the controls away into another object and simply pass it an instance id, which it applies the controls to. So something along these lines, have an object called obj_controller (or whatever) that is going to handle the actual movement and then just pass it the instance id of any instance you want to actually control:

obj_controller Create
GML:
current_instance = obj_player; // We start initially by controlling the player
obj_controller Step
GML:
var _hspd_multiplier = 0; // By multiplying the hspd and vspd of an instance with these, we can decide which direction to move in, and if they're both 0, no movement will be applied
var _vspd_multiplier = 0;
if (key_left) { // key_left, etc, in this example are just the inputs received from the keyboard
   _hspd_multiplier = -1;
}
else if (key_right) {
   _hspd_multiplier = 1
}
if (key_up) {
   _vspd_multiplier = -1;
}
else if (key_down) {
   _vspd_multiplier = 1;
}
with (current_instance) { // As the id stored in current_instance changes, the movement will be applied to different instances because of this with() statement
   x += hspd*_hspd_multiplier;
   y += vspd*_vspd_multiplier;
}
Then you can just overwrite current_instance with a new instance id anytime you want to start controlling something new (in the code below, I'm assuming there's an object called obj_vehicle which is the parent of any vehicle objects the player can ride):
GML:
if (keyboard_check_released(ord("E"))) { // Player releases E
   var _cx = 0;
   var _cy = 0;
   with (current_instance) { // First we grab the position of the instance currently being controlled
      _cx = x;
      _cy = y;
   }
   var _inst = instance_place(_cx,_cy,obj_vehicle); // Then we use the position of the controlled instance to check if it is colliding with a new instance that can be controlled
   if (instance_exists(_inst)) { // If _inst holds a valid instance id
      with (obj_controller) {
         current_instance = _inst; // We set current_instance to that instance id, therefore passing control to the new instance
      }
   }
}
Of course, anything you want to control has to have a hspd and vspd variable setup in it's Create Event, otherwise it'll throw an error (and as I said before, in this example anything controllable needs to be a child of obj_vehicle), but apart from that, this would let you switch between controlling anything you want. It's just an example and the code would definitely need to be adapted to suit the needs of each individual game, but it's at least something to get the brain juices flowing in regards to better abstraction and flexibility when it comes to this sort of "swapping control between different instances" type of thing.
 
Thanks, everyone! You're all a big help! And funny. :banana:

I definitely know there's a whole lot to learn and that I'll always be learning, I'm a very visual person, so these examples really help a lot. I wish more people tried making their own games in some way. Imagine the scope of it all...
 
Top