GM:S 1.4 [SOLVED] Corner Collision Causing Incorrect X and Y Values?

Discussion in 'Programming' started by Storm1208, Jun 14, 2019.

  1. Storm1208

    Storm1208 Member

    Joined:
    Dec 12, 2017
    Posts:
    11
    Hey All! I'm currently working on a recreation of the popular platformer "VVVVVV" and started using the view system in GameMaker to make small, 640x480 levels in my project. These levels are all contained within one room, and when the player walks far enough out of one view it switches to another to go to the next "level".

    Here's the code I typed up to test out this system:
    Code:
    if((obj_player.x = room_width/2))/*one level is 640x480 and room is 1280x960,
    so the player being at half the width of the room means it's time to "switch levels"*/
    {
           if(view_visible[0])
           {
                view_visible[0] = false;//turning off camera for first level
                view_visible[1] = true;//turning on camera for second level
                obj_titlecards.image_index = 1;//showing level name
           }
           else if(view_visible[1])//vice versa if going from level 1 to 0
           {
                view_visible[1] = false;
                view_visible[0] = true;
                obj_titlecards.image_index = 0;
           }
    }
    
    The system was working perfectly until I noticed a small bug. For some reason, if my player object encounters a corner (i.e. they are standing on the ground and also colliding with a "wall" in front of them) the view switching no longer works. I've been able to recreate the bug consistently and here's some pictures of my player encountering corners for reference:
    corner error.PNG corner error 2.PNG
    After the player collides with the floor and wall in a way like shown in the images, the views will no longer switch to show you which levels you're in. I concluded that this must have had something to do with how my collision code was affecting my player's x or y values but I can't seem to spot anything wrong with them.

    Horizontal Collision:
    Code:
    //Horizontal Collision
    if(place_meeting(x+hsp,y,obj_ground)) //if we're about to collide with a ground tile
    {
        while(!place_meeting(x+sign(hsp),y,obj_ground))//keep moving until...
        {
            x += sign(hsp);
        }
        hsp = 0; //BAM - stop moving
    }
    x += hsp;
    
    Vertical Collision:
    Code:
    //Vertical Collision
    if(place_meeting(x,y+vsp,obj_ground)) //if we're about to collide with a ground tile
    {
        while(!place_meeting(x,y+sign(vsp),obj_ground))//keep moving until...
        {
            y += sign(vsp);
        }
        vsp = 0; //BAM - stop moving
        flip = 1;
    }
    y += vsp;
    if(vsp != 0)
    {
        flip = 0;
    }
    
    I used the "show_debug_message()" code to track my player's x value and everything seems normal even after contacting the corner. I'm not entirely sure what's causing the bug but I appreciate any and all help anyone can give me!
     
  2. Bayesian

    Bayesian Member

    Joined:
    Sep 13, 2016
    Posts:
    414
    The issue is not in the code you posted. I must be in your view or camera settings. You should be using mod to trigger the camera stages as that will give you room and resolution independence although that specify doesn't matter for a re-make it would still be the best system
     
    Storm1208 likes this.
  3. TsukaYuriko

    TsukaYuriko Q&A Spawn Camper Forum Staff Moderator

    Joined:
    Apr 21, 2016
    Posts:
    1,470
    I think it actually is in the code that was posted.

    You are checking whether the player is exactly at a specific coordinate. If your player is even a fraction of a pixel away from that, this code is not going to run. I second restructuring your code to determine the room the player is in by using the mod operator, as this will not be bound to the player being at an exact coordinate at all. To check whether the player has entered a new room, keep a copy of the player's room coordinates at all time - if the current coordinates have different values than they did in the last step, you've just changed rooms.


    The original issue aside, I can see a second, not yet fully apparent issue unfolding soon. You're currently using the view system in a way where every room has its own view assigned to it. However, you are limited to having a maximum of 8 views at any given time, whether visible or not, so your current approach will work until you have exactly 8 rooms. You won't be able to add more than 8 rooms like this.

    I suggest to instead have just one view and change its coordinates accordingly, by manipulating the view_xview and view_yview variables to be in the top-left corner of the room the player is currently in. Since all rooms are the same size, the rest will take care of itself.
     
    Storm1208 likes this.
  4. Storm1208

    Storm1208 Member

    Joined:
    Dec 12, 2017
    Posts:
    11
    Your explanation makes sense and I now see why the bug was arising, but I'm a little confused on what you and Bayesian mean about implementing the mod operator. How exactly would I apply the mod operator to my code in this situation. In your post you said that I should keep a copy of the player's room coordinates at all times and reference them with the coordinates of the current step. Are you saying I should mod the coordinates of the current step by the ones from the previous step or am I misunderstanding. When you say "room coordinates", do you mean the x and y values of my player object in the room itself, or within the view for the current level?

    Also, thank you for the tip on the view system. That would've quickly become an issue if I didn't resolve it now!
     
  5. TsukaYuriko

    TsukaYuriko Q&A Spawn Camper Forum Staff Moderator

    Joined:
    Apr 21, 2016
    Posts:
    1,470
    You could use the mod operator like this:
    Imagine that your sub-rooms are in a grid. The grid starts in the top-left corner, at 0,0. The room to the right of it is at 1,0 in that grid. Each grid cell contains a sub-room.

    You can get the player's position in this "grid" by applying the mod operator to its position.
    x mod subroom width is the x position in the grid.
    y mod subroom height is the y position in the grid.

    When I said "room coordinates", I meant the player's coordinates in this imaginary grid.


    Do you know the built-in variables xprevious and yprevious? They keep track of the position the instance was at during the previous step.
    What I was suggesting regarding "keeping a copy of the room coordinates" is to do the same, but with the player's coordinates in the sub-room grid.
    This way, you can compare them to the player's current sub-room grid coordinates to check if they entered a new room.
     
    Storm1208 likes this.
  6. Storm1208

    Storm1208 Member

    Joined:
    Dec 12, 2017
    Posts:
    11
    Thank you for the clarification! Your explanation helped clear up the logic for me and it makes a lot of sense. I actually ended up implementing a different system founded on similar principles to yours, but it seems to be working so far so I think I'm going to leave it for the time being.

    I changed my camera control and made use of GameMakers view_xview, view_yview, view_hview, and view_wview features. If my player object's x value surpasses that of the current view's x position plus its width (i.e. it's outside of the current view's right side) the view will shift to move to the next level. Since the entire view shifts, there's no risk of the code executing again until you surpass the borders of the new view (i.e. you "exit" the new cell in the grid); and since the check for exiting the view is less precise, the glitch I was having earlier stopped occurring. Here's a look at the code for reference:

    Code:
    //controlling the camera and level names
           if(obj_player.x > view_xview[0] + view_wview[0])
           {
                view_xview[0] += view_wview[0];
                obj_titlecards.x += view_wview[0];
           }
           else if(obj_player.x < view_xview[0])
           {
                view_xview[0] -= view_wview[0];
                obj_titlecards.x -= view_wview[0];
           }else if(obj_player.y > view_yview[0] + view_hview[0])
           {
                view_yview[0] += view_hview[0];
                obj_titlecards.y += view_wview[0];
           }else if(obj_player.y < view_yview[0])
           {
                view_yview[0] -= view_hview[0];
                obj_titlecards.y -= view_wview[0];
           }
    
    This results in a system that adheres similarly to the grid like system you outlined, but in a slightly different way. This system seems to be working so far but I'll definitely keep your implementation in mind in case I run into any issues with this one.

    Also, thank you for letting me know about xprevious and yprevious, I was actually unaware that they existed in GameMaker and I can certainly see myself utilizing them in the future!

    Thank you so much for your help everyone! I'm going to go ahead and mark the thread as "SOLVED"!
     
    TsukaYuriko likes this.

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