1. Hey! Guest! The 32nd GMC Jam will take place between Feb 22nd, 12:00 UTC (Friday noon) and Feb 25th, 12:00 UTC (Monday noon). Why not join in! Click here to find out more!
    Dismiss Notice

GML for_loop/math problem, making buttons display properly

Discussion in 'Programming' started by Dr_Nomz, Feb 4, 2019.

  1. Dr_Nomz

    Dr_Nomz Member

    Joined:
    Oct 31, 2016
    Posts:
    477
    I have a chest that displays it's inventory slots (buttons) when opened, and I got it set up to have multiple pages for it's inventory, which is great, except that it isn't displaying correctly.

    The way it works is it's in a case statement, once the next page button is pressed, it switches the case(page) from 0 to 1, displaying the for loop for the rest of the slots instead.

    But it shows them like it would if they were all drawn at the same time, because of how it's set up, even though it's supposed to start from the top just like the first loop.

    This is the first loop:
    Code:
      for (c = 0; c < 10; c += 1){
        var ix = x1+840+((c%2)*104);
        var iy = y2+101+(floor(c/2)*104);
        draw_sprite(spr_Item_Slot_3,0,ix,iy)
        button[c].show_button=true;
        button[c].x = ix;
        button[c].y = iy;
      }
    On the second, it has for(c = 10; c < 20; c += 1) and displays them below where the old buttons used to be. How do I make it so they display correctly, just like the first ones?
     
  2. RefresherTowel

    RefresherTowel Member

    Joined:
    Jul 13, 2016
    Posts:
    913
    Create
    Code:
    inv_pos = 0;
    
    Draw
    Code:
     for (c = inv_pos; c < inv_pos+10; c += 1){
       var ix = x1+840+(((c mod max_inv_no)%2)*104);
       var iy = y2+101+(floor((c mod max_inv_no)/2)*104);
       draw_sprite(spr_Item_Slot_3,0,ix,iy)
       button[c].show_button=true;
       button[c].x = ix;
       button[c].y = iy;
      }
    Next Page Click
    Code:
    inv_pos += 10;
    inv_pos = inv_pos mod max_inv_no+1; // This'll set it back to 0 if you go past the max number of inventory slots
    
    Probably the easiest way to do what you want with the least tweaking of your current code.

    EDIT: I didn't see the maths in your code, hahaha, coolgiraffe has done what I should've when I posted this. I also changed the maths in this post so it should work properly.
     
    Last edited: Feb 4, 2019
    Dr_Nomz likes this.
  3. CoolGiraffe1

    CoolGiraffe1 Member

    Joined:
    Feb 3, 2019
    Posts:
    38
    I'm not sure if understand the problem correctly, but if you want each page to be shown in the same position you might want to add some variables.
    Code:
    var currentPage = 0; //which page is displayed
    var pageSize = 10; //how many slots are in each page
    
    for (c = 0; c <10; c += 1){
       var ix = x1+840+((c%2)*104);
       var iy = y2+101+(floor(c/2)*104);
       draw_sprite(spr_Item_Slot_3,0,ix,iy)
    
       var pos = c + (currentPage * pageSize); //for example: if the second page is displayed and c = 2, then pos = 2+1*10 = 12
    
       button[pos].show_button=true;
       button[pos].x = ix;
       button[pos].y = iy;
      }
    let me know if this works since its pretty hard for me to understand your code :)
     
    Dr_Nomz likes this.
  4. Dr_Nomz

    Dr_Nomz Member

    Joined:
    Oct 31, 2016
    Posts:
    477
    I definitely LIKE where this is going, but I can't seem to implement it properly. First try didn't seem to change the pages at all, second caused a crash.

    Here, I'll just post the code here and let you take a look, this is the FULL draw event. Bare in mind it's pretty massive, but it'll give you a better idea of how works.

    Create event first:
    Code:
    alpha = false;
    buffer=0;
    page=0;
    
    global.container_transfer = false;
    show_container = false;
    container_space = 20;
    
    for (var c = 0; c < container_space; c += 1) {
      button[c] = instance_create(0, 0, obj_Box_slot2);
      with (button[c]) {
        show_button=false;
        container_slot[c] = -1;
        container_count[c] = 0;
        slot = c;
        number = c;
      }
    }
    Code:
    ///Draw Box Inventory
    draw_self();
    //Key press events
    if keyboard_check_pressed(vk_escape){
      show_container=false
    }
    if global.container_transfer=false{
    if (point_in_rectangle(mouse_x,mouse_y,bbox_left-buffer,bbox_top-buffer,bbox_right+buffer,bbox_bottom+buffer)){
    if keyboard_check_pressed(ord("E")){
      show_container=!show_container;
      global.container_transfer=!global.container_transfer;
      if showInv=false{
        showInv=true;
      }
    }
    }
    }
    if keyboard_check_pressed(ord('0')) && showInv=true{
      alpha = true
    }
    if keyboard_check_pressed(ord('9')) && showInv=true{
      alpha = false
    }
    
    if show_container=true{
      var x1,x2,y1,y2;
      x1 = view_xview[0];
      x2 = x1 + view_wview[0];
      y1 = view_yview[0];
      y2 = y1 + 104;
     
      if alpha = true{
      draw_set_alpha(0.8);
      draw_sprite(spr_Inventory_6,0,x2+310,y1+150);
      draw_set_alpha(1);
      }
      if alpha = false{
      draw_sprite(spr_Inventory_6,0,x2+310,y1+150);
      draw_set_alpha(1);
      }
     
      //Draw pages
      switch(page){
      case 0:{ //Page 0
      for (c = 10; c < 20; c += 1){
      button[c].show_button=false;}
        for (c = 0; c < 10; c += 1){
        var ix = x1+840+((c%2)*104);
        var iy = y2+101+(floor(c/2)*104);
        draw_sprite(spr_Item_Slot_3,0,ix,iy)
        button[c].show_button=true;
        button[c].x = ix;
        button[c].y = iy;
      }}break;
      case 1:{ //Page 1
      for (c = 0; c < 10; c += 1){
      button[c].show_button=false;}
        for (c = 10; c < 20; c += 1){
        var ix = x1+840+((c%2)*104);
        var iy = y2+101+(floor(c/2)*104);
        draw_sprite(spr_Item_Slot_3,0,ix,iy)
        button[c].show_button=true;
        button[c].x = ix;
        button[c].y = iy;
      }}break;
      }//Draw pages end */
     
      //Close the inventory.
      if keyboard_check_pressed(vk_tab){
        show_container=false;
        global.container_transfer=false;
      }
    //Draw next page buttons.
    var xx,yy;
      xx = view_xview[0];
      yy = view_yview[0];
    
      draw_set_font(fnt_1);
      draw_set_color(c_yellow);
      draw_text(xx+600,yy+100,page);
      draw_sprite(spr_Item_Slot_3,0,xx+650,yy+350);
      draw_sprite(spr_Item_Slot_3,0,xx+650,yy+450);
      if(point_in_rectangle(mouse_x,mouse_y,xx+600,yy+300,xx+700,yy+400)){
        draw_set_color(c_white);
        draw_rectangle(xx+600,yy+300,xx+700,yy+400,0);
        if mouse_check_button_pressed(mb_left){
          page=0;
      }}
      if(point_in_rectangle(mouse_x,mouse_y,xx+600,yy+400,xx+700,yy+500)){
        draw_set_color(c_white);
        draw_rectangle(xx+600,yy+400,xx+700,yy+500,0);
        if mouse_check_button_pressed(mb_left){
          page=1;
      }}
    } //Hide buttons
    if show_container=false{
      for (c = 0; c < container_space; c += 1){
        button[c].show_button=false;
      }
    }
     
  5. Dr_Nomz

    Dr_Nomz Member

    Joined:
    Oct 31, 2016
    Posts:
    477
    Basically it's a heavily modified version of this tutorial:

    Also making heavy use of his mouse cursor tutorial, part of his expanded tutorial series:


    Basically what I'm doing with it is making it so it starts out on "page 0", and every time I hit the one of the buttons drawn, it'll change the page, switching the case to draw the other buttons and hide the first page. (Since each button has it's own "visible" value)

    But I MUCH prefer the concept Refresher gave. So I'd like instead for the buttons to function like he intended, being a page UP/DOWN respectively would be REALLY awesome.

    Container_Space is essentially the "maxItems" value of the chest, meaning if I just used it as is, it would draw 20 inventory slots on the screen. However, I only want about 10 of those at a time to be displayed, hence the page variable.

    The reason I need that variable at all is because it won't work otherwise. It needs to start off with it's maximum inventory slots, and use all of them from start to finish. It's pretty limiting in that way, but this system in it's current form has no real need for a "dynamic" inventory that grows or shrinks anyway, and I prefer the page setup I have now. (It's also WAY more simple to manage and deal with with in code and in game.)
     
    Last edited: Feb 9, 2019
  6. Dr_Nomz

    Dr_Nomz Member

    Joined:
    Oct 31, 2016
    Posts:
    477
    Hey CoolGiraffe got it! Thanks! :D Now I need to implement the page up and down idea Refresher had.

    Code:
    //Draw pages
      switch(page){
      case 0:{ //Page 0
      for (c = 10; c < 20; c += 1){
      button[c].show_button=false;}
      }break;
      case 1:{ //Page 1
      for (c = 0; c < 10; c += 1){
      button[c].show_button=false;}
      }break;
      }//Draw pages end */
     
      //Close the inventory.
      if keyboard_check_pressed(vk_tab){
        show_container=false;
        global.container_transfer=false;
      }
    //Draw next page buttons.
    
    //Everything down here requires better optimization, but the major thing is up there.^
    
    var xx,yy;
      xx = view_xview[0];
      yy = view_yview[0];
    
      draw_set_font(fnt_1);
      draw_set_color(c_yellow);
      draw_text(xx+600,yy+100,page);
      draw_sprite(spr_Item_Slot_3,0,xx+650,yy+350);
      draw_sprite(spr_Item_Slot_3,0,xx+650,yy+450);
      if(point_in_rectangle(mouse_x,mouse_y,xx+600,yy+300,xx+700,yy+400)){
        draw_set_color(c_white);
        draw_rectangle(xx+600,yy+300,xx+700,yy+400,0);
        if mouse_check_button_pressed(mb_left){
          page+=1;
      }}
      if(point_in_rectangle(mouse_x,mouse_y,xx+600,yy+400,xx+700,yy+500)){
        draw_set_color(c_white);
        draw_rectangle(xx+600,yy+400,xx+700,yy+500,0);
        if mouse_check_button_pressed(mb_left){
          page-=1;
      }}
      if page>1{
      page=0;}
      if page<0{
      page=1;}
    The way my buttons work is they have their own local variable determining if they're visible or not, so every time the inventory closes each button has to be hidden by updating it's show_button variable. This is equally true for changing pages, hiding the first ones, then showing the latter ones.

    This code works fine, but it's already unmanageable and it'll be even worse with more that two pages. The main thing is that it has to be able to use a for loop to hide the correct buttons based on what the current page is.

    The other thing is I really need a better way to draw my buttons
     
  7. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    6,046
    Try not to think in terms of absolutes. Your code says if page is greater than 1; that's an absolute. Your page_count is ceil(container_space/10). So page=page mod page_count (sometimes negatives don't give the right modulo, so the longhand method may be required).

    The slots you'd show are the range of [page*10, page*10+9]. This even means you don't need to specify how many slots in the create event, you could just specify how many pages the chest will have. Up to you.
     
  8. Dr_Nomz

    Dr_Nomz Member

    Joined:
    Oct 31, 2016
    Posts:
    477
    This is how I did it, up button didn't work, page down button gave an out of range error:
    Code:
        if mouse_check_button_pressed(mb_left){
          page+=1;
          page=page mod pageSize;
      }
    I still need at least 2 buttons, 1 for moving the pages up and one for moving them down. (In my case I used page-=1)

    I also really need this optimized too:
    Code:
      switch(page){
      case 0:{ //Page 0
      for (c = 10; c < 20; c += 1){
      button[c].show_button=false;}
      }break;
      case 1:{ //Page 1
      for (c = 0; c < 10; c += 1){
      button[c].show_button=false;}
      }break;
      }
    So that it automatically knows which buttons to hide based on what page is being used. Like it's fine as is, it works, but I need to manually code it for every page I decide to add.
     
  9. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    6,046
    Why is page 0 using buttons 10 thru 19, but page 1 is buttons 0 thru 9? Page 0 should use buttons 0 thru 9 and page 1 should use buttons 10 thru 19. Then it's a no-brainer:

    for(var p=0; p<pageCount; p++)
    for(var c=0; c<10;c++) {
    button[c+p*10].show_button=p==page;​
    }
     
  10. Dr_Nomz

    Dr_Nomz Member

    Joined:
    Oct 31, 2016
    Posts:
    477
    That's weird, had an unexpected symbol at the end I couldn't see... after it says page;
    Any reason for that? Otherwise I'm testing it right now.

    Code:
    Push :: Execution Error - Variable Index [0,20] out of range [1,20] - -1.button(100025,20)
     at gml_Object_obj_Box_2_DrawEvent_1 (line 58) -   button[c+p*10].show_button=p==page;
    ############################################################################################
    --------------------------------------------------------------------------------------------
    stack frame is
    gml_Object_obj_Box_2_DrawEvent_1 (line 58)
    Uh you're not supposed to put anything in button[c]'s brackets.

    "c" is the variable that determines the ID of the button, so filling the brackets creates that error.

    Also how is your code setting the button's show_button variable to true/false? I can't tell where that would be happening.

    Code:
    for(var p=0; p<pageSize; p++){
      for(var c=0; c<10;c++) {
      button[c].show_button=p==page; //+p*10
      }}
    That kept it from crashing when opened, but trying to set the page higher just sets it back to 0. And lowering the page number crashes the game.
     
    Last edited: Feb 14, 2019 at 10:29 AM
  11. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    6,046
    What are you setting pageSize to?

    The error is saying your array wasn't set right and/or pageSize is wrong. The fact it was trying to go up to 20 in the error message suggests perhaps also your version of GMS1 is running arithmetic operations out of order...

    button[(p*10)+c].show_button=p==page;

    Assuming container_space is always a multiple of 10 and pageSize is always equal to container_space/10, then that line should work.

    The reason your alteration caused the error message to go away is because you only look at button[0] thru button[9]; but doesn't properly address the out of bounds error. It also doesn't cover the other 10 buttons.

    show_button is getting set to true or false by the formula p==page.

    The invisible character was probably the TAB character. lol My bad.
     
  12. Dr_Nomz

    Dr_Nomz Member

    Joined:
    Oct 31, 2016
    Posts:
    477
    Tab can be typed as a character? Huh. Well I'll take a look at this and see what I can do.

    EDIT:
    Code:
    Push :: Execution Error - Variable Index [0,20] out of range [1,20] - -1.button(100025,20)
     at gml_Object_obj_Box_2_DrawEvent_1 (line 58) -   button[(p*10)+c].show_button=p==page;
    Yeah, still out of range. You can't have ANYTHING in that array at all other than the C, or it won't work. :/

    Code:
    page=0;
    container_space = 20;
    Also just to point out what the variables are, page is what page of slots is displayed currently, so if it changes to 1, slots 10-20 or whatever are displayed, for example.

    Container space is what creates the item slots. 20 is what it has when it's created, and that variable can't be changed later on in game.
    Code:
      var pageSize = 10; //how many slots are in each page
    And in the draw event I use this var for determining how many slots are displayed in each page, basically Giraffe's code.

    Here I'll just post my Draw Event for the relevent code, maybe looking it over will give a better idea of how it works.
    Code:
    var pageSize = 10; //how many slots are in each page
      for (c = 0; c <10; c += 1){
        var ix = x1+840+((c%2)*104);
        var iy = y2+101+(floor(c/2)*104);
        draw_sprite(spr_Item_Slot_3,0,ix,iy)
        var pos = c + (page * pageSize); //for example: if the second page is displayed and c = 2, then pos = 2+1*10 = 12
        //Code by CoolGiraffe
        button[pos].show_button=true;
        button[pos].x = ix;
        button[pos].y = iy;
      } //Draw Buttons end
     
      //Draw pages
      for(var p=0; p<pageSize; p++){
      for(var c=0; c<10;c++) {
      button[(p*10)+c].show_button=p==page;
      }}

    EDIT: Just messed around a bit, got it to work properly-ish with pos.
    Code:
    for(var p=0; p<pageSize; p++){
      for(var c=0; c<10;c++) {
      button[pos].show_button=p==page;
      }}
    Except that it doesn't hide any of the buttons at all, and going UP a page with page+=1 doesn't set it back to 0, it just gives an out of range error. Same for trying to go back down.
     
    Last edited: Feb 14, 2019 at 9:21 PM
  13. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    6,046
    Oh, I thought pageSize was an odd name...

    Code:
    var pageCount = ceil(container_space/10);
    for(var p=0; p<pageCount; p++)
    for(var c=0; c<pageSize; c++)
    {
    if (p*pageSize)+c < container_space
    button[(p*pageSize)+c].show_button=p==page;
    else break;
    }
     
    Dr_Nomz likes this.
  14. Dr_Nomz

    Dr_Nomz Member

    Joined:
    Oct 31, 2016
    Posts:
    477
    It seems to work great! :D Except for the small detail that it doesn't let me go over/under the total page count without breaking it.
    Code:
    Push :: Execution Error - Variable Index [0,20] out of range [1,20] - -1.button(100025,20)
     at gml_Object_obj_Box_2_DrawEvent_1 (line 50) -     button[pos].show_button=true;
    Is there a way to have it automatically recognize that it has to go back to page 0 if it goes over, and page 1 if it goes under, so it doesn't crash like this?

    Or do I have to keep using this?
    if page>1{
    page=0;}
    if page<0{
    page=1;}
    I don't really mind this, but it would be SO nice if I didn't have to manually code for this check every time I make an object or add a page.
     
  15. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    6,046
    That's what the mod was for. At least for going up.
    Code:
    var pageCount = ceil(container_space/10);
    
    
    if mouse_check_button_pressed(mb_left){
         page+=1;
         page=page mod pageCount;
      }
    It didn't work before for the same reason - the first time we used pageSize instead of pageCount.
     

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