Z-Axis Movement (3D/2.5D Game, Tutorial #3)
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).
Status | Released |
Category | Assets |
Rating | Rated 5.0 out of 5 stars (1 total ratings) |
Author | frothzon |
Code license | MIT License |
Asset license | Creative Commons Attribution v4.0 International |
Comments
Log in with itch.io to leave a comment.
Im a newbie in game making. My question is how do i create elevated platforms in z space?. Thanks for you work.
It is all done in code.
Your work is fabulous! As a newbie to programming I feel I will get far with your tutorials. Thanks for sharing your knowledge