Similar Posts

7 Comments

  1. Another excellent tutorial! As clean and understandable as anything.

    I’m excited to see how it’ll all be changed for the 2.3 update – plus I’ll be able to test it on the ol Mac to see if they’ve fixed that nasty recursion problem.

    1. Fact is that we don’t really know how long it will take for the 2.3 update to go public. It could be months. In the meantime I think I’ll fix the Mac bug (which is actually due to a return from a loop inside a with statement). As I learned from the YoYo bug tracker, it’s not really a recursion bug. It is fixable and I’ll work with a friend (who owns a Mac) to test out the solution. I’ll write a new article on how to fix that specific bug so you can keep on working on your project in 2.2.x. Bottom line: I wouldn’t hold my breath for 2.3 (unfortunately).

  2. Another excellent tutorial; thanks for all your hard work.

    I prefer to avoid adding member xprevious and yprevious variables to the objects, and I hope this doesn’t bite me if I continue to follow your tutorials. As I add more movement scripts (if it ends up being necessary), I’ll feel the need to always preserve their previous x/y coordinates, or else I won’t be able to trust those member variables. If they exist, I might be tempted to use them in other circumstances, which could lead to difficult to debug scenarios if I’m not careful.

    My first instinct was to make can_move_x() and can_move_y() and then looping twice on the instances, but that felt a bit messy since I’d also need can_move_on_slope().

    I decided to include the previous x/y coordinates in the list:

    ds_list_add(
    instances_that_have_moved_with_previous_xy_list,
    instance_to_move,
    instance_to_move.x,
    instance_to_move.y);

    My reset_instance_with_xy_list_position() does this:

    /// @param instances_with_previous_xy_list
    var instances_with_previous_xy_list = argument0;

    var size = ds_list_size(instances_with_previous_xy_list);

    for (var i = 0; i < size; i += 3) {

    var instance = instances_with_previous_xy_list[| i + 0];
    var X = instances_with_previous_xy_list[| i + 1];
    var Y = instances_with_previous_xy_list[| i + 2];

    instance.x = X;
    instance.y = Y;

    }

  3. I like to create data structures at the beginning of the script and delete them at the end. Limiting where they can be created/destroyed helps me mitigate memory leaks.

    Here’s what my move_platform_y() script looks like; I use some different variable names and I also have functions for creating/destroying data structures that help me track memory leaks:

    /// @param yvel
    var _yvel = argument0;
    var _ydir = sign(_yvel);

    var has_hit_wall = false;

    // Create collision list
    var colliding_instance_list = create_list(“move_platform_y().colliding_instance_list”);
    var instances_that_have_moved_with_previous_xy_list = create_list(“move_platform_y().instances_that_have_moved_with_previous_xy_list”);

    repeat abs(_yvel) {

    // Colliding with solid
    if is_colliding_y(_ydir) {
    has_hit_wall = true;
    break;
    }

    // Going downward
    if _ydir > 0 {

    if !move_platform_y_downwards(
    colliding_instance_list,
    instances_that_have_moved_with_previous_xy_list ) {

    has_hit_wall = true;
    break;

    }

    }

    // Going upward
    else if _ydir < 0 {

    if !move_platform_y_upwards(
    colliding_instance_list,
    instances_that_have_moved_with_previous_xy_list ) {

    has_hit_wall = true;
    break;
    }

    }

    // If everything went good, move.
    y += _ydir;
    }

    unregister_and_destroy_list(colliding_instance_list);
    unregister_and_destroy_list(instances_that_have_moved_with_previous_xy_list);

    if has_hit_wall {
    return false;
    }

    return true;

      1. Hey David! Thanks for sharing your gists. I really dig exploring how others approach the same problems 🙂

        I tend to return a lot during cycles so I can’t really afford to destroy data structures at the end of the scripts and yes, I need to take extra care for memory leaks. Interestingly your approach (of not returning during cycles) should have spared you the MacOS bug I encounter when returning from a loop inside a with statement. You simply break from the loop and return the result at the end. Which is basically the fix I’m writing for my move_x and move_y scripts (having said that, I still prefer to return but it’s a personal preference).

        Anyway I used this very same approach (checking if movement is possible, moving and then resetting positions) in my moving boxes prototype. I still have very similar code in that project (I can send it to you if you like). Admittedly I still have to fix moving stacked boxes on slopes but that’s a whole different story 😛

        I remember having scripts like

        • can_push
        • can_carry
        • can_move_x
        • can_move_y

        and a bunch of lists oddly named like items_marked_for_movement_x, items_marked_for_movement_y and items_that_cannot_move or something like that. I also went down the rabbit hole for slopes because I had to move x and y separately and I remember making a bit of a mess when refactoring slope_move to actually avoid moving items inside that script.

        I still feel that marking items for movement and then iterating is the way to go for complex problems (like stacked boxes on slopes) but I have to find a clean way to write code for that. I don’t like the mess I wrote for those prototypes.

        Going back to your xprevious and yprevious considerations, you’d be absolutely right to be wary of using them. Especially using them like I did in this article 😛

        In fact if I were to increase the yvel of the vertical platform to, say, 13, and let’s say that the platform stops at the 6th iteration of the movement loop, my instances’ positions would be set back to the wrong previous values, because I don’t manually update them at the end of each successful cycle (platform’s cycle, not single instance move_x/move_y cycles). In my case I’ll write how to fix this in the next article. I can’t see where you update the xprev/yprev (X/Y in your case) but you might or might not suffer from the same issue. Let me know if you do (try increasing the vertical speed and put more objects on the vertical platform, for example, with something blocking only one of them).

        You might find this code useful to visually debug at very high speeds (I have this in the begin step of a controller)

        var spd = keyboard_check(vk_shift) ? 1 : 60
        game_set_speed(spd, gamespeed_fps)

        Again, thanks for your thoughts and code, really appreciated!

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.