A downloadable asset pack

In this tutorial series we are adding moving platforms and slope handling to the z-axis collision system, this continues off from Tutorial #2 Here. (Make sure to download the tutorial package if you want to save some time typing out code, or if you don't quite understand how it is implemented)

Part 1: Updating position struct for moving platforms

In the position struct we will need to save the object data for the platform the player is standing on so we can adjust the player motion to match the platform motion. We will add the variable "floor_obj", and a method called "get_floor_vector()"

function init_zaxis(_height=16){
    position = {
        z: 0,            /// position on z axis
        z_speed: 0,        /// speed in z direction
        z_gravity: 0.5,    /// accelerate down 
        z_ground: 0,    /// lowest position you can fall to
        z_height: _height,    /// height of object
        z_step: 4,        /// climb on object a little higher
        floor_obj: noone,
        z_top: function(){
            return z + z_height;    
        },
        get_floor_vector: function(){
            var _floor_vec = [0,0,0];
            /// if on the ground and object is beneath
            if(self.floor_obj >= 0 && instance_exists(self.floor_obj)){
                /// additional check for overlapping objects
                var _floor_pos = self.floor_obj.position;
                /// platform is moving, we can check within the 
                /// bounds of z_step for collision
                if(abs(self.z - _floor_pos.z_top()) <= self.z_step){
                    /// [xspeed, ypseed, zspeed]
                    _floor_vec = [self.floor_obj.hspeed,
                        self.floor_obj.vspeed,
                        self.floor_obj.position.z_speed
                    ];
                }
            }
            return _floor_vec;
        }
        
   };
}

The method "get_floor_vector" will return the xspeed, ypseed, and z_speed of the floor object. We will use this to match the players movement to the movement of the platform they are standing on. In addition, we also need to make sure that when we fall on an object, our z_speed matches the surface we hit. If we land on a plaform, our z_speed should be exactly equal to the platform's z_speed, logically. We will need to modify the "update_zaxis()" function in the following way:


function update_zaxis(){
    /// always move when speed is applied
    position.z += position.z_speed;
    /// move in z direction, 
    /// Z_Axis is assumed to point in the -Y direction (+z)
    /// therefore, positive z_speed is up, -z_speed is down
    if(position.z > position.z_ground){
        position.z_speed -= position.z_gravity;
    } else {
        /// if below ground, adjust to ground position
        position.z = max(position.z, position.z_ground);
        /// if falling, stop falling
        /// get minimum speed [xspeed, yspeed, zspeed], use only zspeed
        var _floor_spd = position.get_floor_vector();
        position.z_speed = max(position.z_speed, _floor_spd[2]);
    }
}

Part 2: Saving the platform object id

We will need to save the current platform object if the player is standing on it. To do this, we simply add the object id from the "upgrade_zground()" method to the "floor_obj" variable. The default value for the ID stored in "floor_obj" will need to be set to the keyword noone (which is the same as setting it equal to -4) so we don't continue being affected by it after we change platforms or fall to the ground.

function update_zground(_targets){
    /// check for collision
    var _list = ds_list_create();
    /// default lowest point
    position.z_ground = 0;
    position.floor_obj = noone;
    
    if(instance_place_list(x, y, _targets, _list, 0)){
    
        /// loop through all collision instances
        for(var _i = 0; _i < ds_list_size(_list); _i++){
            var _collide = _list[| _i];
        
            /// if collision occurs, we want to get on top of that object if possible
            if(_collide != noone && variable_instance_exists(_collide, "position")){
                var _pos2 = _collide.position;
                /// if self is above the top of the other object, z_ground will now be at that height
                if(position.z + position.z_step > _pos2.z_top()){
                    position.z_ground = max(position.z_ground, _pos2.z_top());
                    position.floor_obj = _collide;
                } 
            }
        }
    }
    /// remove list to clear memory
    ds_list_destroy(_list);
}

Part 3: Updating the player code

We now have the functionality to move with the platform object, but we still need to implement it in the player step event. Add the following into the movement code anywhere after "update_zground(obj_block);"

/// platform motion tracking [xspeed, yspeed, zspeed]
var platform_speed = position.get_floor_vector();
x += platform_speed[0];
y += platform_speed[1];

The changes in our code will make the jump code fail to work correctly when we are on a moving platform or slope. We need to change the jump code in the step event to this:

/// jump
if(keyboard_check_pressed(vk_space)){
    var _jump_spd = 6;
    if(abs(position.z - position.z_ground) < position.z_step){
        position.z_speed += _jump_spd;
    }
}

Part 4: Adding Platforms and Slopes

We will create a sloped platform to test out the changes we have made. Create a new object for your sloped platform and name it obj_platform. Add obj_block as its parent so the collision code will carry over to the new object. Add any sprite you want (slope sprite is preferable). Then, we want to create a new script called "update_slope_object" and put the following code in it. 


function update_slope_object(_player, _z1, _z2, _on_yaxis=0){
    /// change height based on player position
    /// z1 = top or left
    /// z2 = bottom or right
    /// on_yaxis -> slope is on yaxis
    
    var _ds = 0;    /// ratio between 0 and 1
    if(_on_yaxis){
        /// slope is on the Y axis, top z1 bottom z2
        _ds = (_player.y - bbox_top) / (bbox_bottom - bbox_top);
    } else {
        // slope is on the X axis, left z1, right z2
        _ds = (_player.x - bbox_left) / (bbox_right - bbox_left);
    }
    _ds = clamp(_ds, 0, 1);
    
    /// "height" changes depending on your position (like a slope)
    position.z_height = lerp(_z1, _z2, _ds);
}

The function calculates a ratio between 0 and 1 based on the player's position and the slope's position, and then uses that ratio to linearly interpolate between the two height values provided. The resulting height value is assigned to the "z_height" variable of the slope.

Now, lets add some functionality to our new object. In the step event paste in the following code:  (grab "wave" from the example project)


var z_previous = position.z;
position.z = wave(16,64,5,0);
hspeed = wave(-1,1,2.5,0);
/// calculate the speed
position.z_speed = position.z - z_previous;
/// update slope parameters
update_slope_object(obj_player, 0, 16);

Then, go into the draw event of obj_block and paste the following code:

var yy = y;
/// shadow
draw_set_alpha(0.5);
var pos = [x, y];
draw_circle_color(pos[0],pos[1]-position.z_ground,8,c_black,c_black,0);
draw_set_alpha(1);
y -= position.z;
/// draw player at Z position
draw_self();
y = yy;

Conclusion

We now have a working z-axis system that can handle platforms, slopes, and movement but we still will have some issues with collisions (it is possible to get stuck in objects). We will address the collision problem and add submersion / floating / swimming to the z-axis system in the next tutorial (Tutorial 4).

StatusReleased
CategoryAssets
Rating
Rated 5.0 out of 5 stars
(1 total ratings)
Authorfrothzon
Code licenseMIT License
Asset licenseCreative Commons Attribution v4.0 International

Download

Download
z-axis-tutorial_partC.zip 23 kB

Comments

Log in with itch.io to leave a comment.

Your work is fabulous! As a newbie to programming I feel I will get far with your tutorials. Thanks for sharing your knowledge