// step 事件
show_debug_message("onGround = " + string(onGround));

// 获取控件
getControls();

// X 移动
// 方向
moveDir = rightKey - leftKey;

// 获取人脸方向
if (moveDir != 0) {
    face = moveDir;
}

// 获取水平速度
runType = runKey;
xspd = moveDir * moveSpd[runType];

// 碰撞检测
var subPixel = 0.5;
if (place_meeting(x + xspd, y, obj_wall)) {
    // 检查是否有斜面
    if (!place_meeting(x + xspd, y - abs(xspd) - 1, obj_wall)) {
        while (place_meeting(x + xspd, y, obj_wall)) {
            y -= subPixel;
        }
    } else {
        // 检查是否有Ceiling slopes, 否则进行正常碰撞检测
        if (!place_meeting(x + xspd, y + abs(xspd * 2) + 1, obj_wall)) {
            while (place_meeting(x + xspd, y, obj_wall)) {
                y += subPixel;
            }
        } else {
            // 移动上面的墙壁
            var pixelCheck = subPixel * sign(xspd);
            while (!place_meeting(x + pixelCheck, y, obj_wall)) {
                x += pixelCheck;
            }

            // 设置xspd为0
            xspd = 0;
        }
    }
} else {
    // 满地而下
    if (yspd <= 0 && !place_meeting(x + xspd, y + 1, obj_wall) && place_meeting(x + xspd, y + abs(xspd) + 1, obj_wall)) {
        while (!place_meeting(x + xspd, y + subPixel, obj_wall)) {
            y += subPixel;
        }
    }

    // 移动
    x += xspd;
}

// Y 移动
// 重力
if (coyoteHangTimer > 0) {
    // 减少计时器
    coyoteHangTimer--;
} else {
    // 应用重力
    yspd += grav;
    // 不在地面上
    setOnGround(false);
}

// 重置/准备跳跃变量
if (onGround) {
    jumpCount = 0;
    coyoteJumpTimer = coyoteHangFrames;
} else {
    // 当玩家在空中时,保证他们不能多跳
    coyoteJumpTimer--;

    // 如果玩家想跳,而计时器超出,则允许跳跃
    if (jumpCount == 0 && coyoteJumpTimer <= 0) {
        jumpCount = 1;
    }
}

// 获得跳跃计时器
if (!jumpKey) {
    jumpHoldTimer = 0;
}

// 跳跃 (持续按住跳跃键)
if (jumpHoldTimer > 0) {
    // 设置yspd为跳跃速度
    var index = clamp(jumpCount - 1, 0, array_length(jspd) - 1);
    yspd = jspd[index];

    // 减少计时器
    jumpHoldTimer--;
}

// Y 碰撞检测和移动
#region
    // 限制下落速度
    if (yspd > termVel) {
        yspd = termVel;
    }

    // 上方向Y 碰撞检测
    if (yspd < 0 && place_meeting(x, y + yspd, obj_wall)) {
        // 突进斜面的顶部
        var slopeSlide = false;
        // 左侧斜面
        if (moveDir != 1 && !place_meeting(x - abs(yspd) - 1, y + yspd, obj_wall)) {
            while (place_meeting(x, y + yspd, obj_wall)) {
                x -= 1;
            }
            slopeSlide = true;
        } else if (moveDir != -1 && !place_meeting(x + abs(yspd) + 1, y + yspd, obj_wall)) {
            while (place_meeting(x, y + yspd, obj_wall)) {
                x += 1;
            }
            slopeSlide = true;
        } else {
            // 正常Y 碰撞检测
            if (!slopeSlide) {
                // 移动到墙壁精确地
                var pixelCheck = subPixel * sign(yspd);
                while (!place_meeting(x, y + pixelCheck, obj_wall)) {
                    y += pixelCheck;
                }

                // 滬 (可选)
                if (yspd < 0) {
                    jumpHoldTimer = 0;
                }

                // 设定yspd为0以碰撞
                yspd = 0;

                // 告知游戏我们已经处于地面上
                setOnGround(true);
            }
        }
    }

    // 地面Y 碰撞检测
    // 检测是否有以下方块 (半像素)
    var clamYspd = Math.max(0, yspd);
    var list = ds_list_create(); // 为每个碰撞实例创建数据集列表
    var array = array_create(0);
    array_push(array, obj_wall, obj_SemiSolidWall);
    // 检测碰撞和添加实体
    var listSize = instance_place_list(x, y + 1 + clamYspd + moveplatMaxYspd, array, list, false);

    // 遍历碰撞实例并仅保留顶部低于玩家的实例
    for (var i = 0; i < listSize; i++) {
        // 实例对象
        var listInst = list[i];

        // 避免磁石
        if ((listInst.yspd <= yspd || (myFloorPlat && yspd == 0)) && (listInst.yspd > 0 || place_meeting(x, y + 1 + clamYspd, listInst))) {
            // 返回实体的底部
            if (listInst.object_index == obj_wall ||
                object_is_ancestor(listInst.object_index, obj_wall) ||
                listInst.object_index == obj_SemiSolidMovePlat ||
                bbox_bottom < listInst.bbox_top - listInst.yspd) {
                // 返回最高的实体
                if (!myFloorPlat ||
                    listInst.bbox_top + listInst.yspd < myFloorPlat.bbox_top + myFloorPlat.yspd ||
                    listInst.bbox_top + listInst.yspd < bbox_bottom) {
                    myFloorPlat = listInst;
                }
            }
        }
    }

    // 销毁 DS 列表以避免内存泄漏
    ds_list_destroy(list);

    // 最后一次检查以确保.floorPlatform 位于我们下方
    if (myFloorPlat && !place_meeting(x, y + moveplatMaxYspd, myFloorPlat)) {
        myFloorPlat = noone;
    }

    // 向地面跳跃
    if (myFloorPlat) {
        // 移动精确到墙壁
        var subPixel = 0.5;
        while (!place_meeting(x, y + subPixel, myFloorPlat) &&
            !place_meeting(x, y, obj_wall)) {
            y += subPixel;
        }

        // 确保我们不结束于一个半透实体下面
        if (myFloorPlat.object_index == obj_SemiSolidWall ||
            object_is_ancestor(myFloorPlat.object_index, obj_SemiSolidWall) ||
            myFloorPlat.object_index == obj_SemiSolidMovePlat) {
            while (place_meeting(x, y, myFloorPlat)) {
                y -= subPixel;
            }
        }

        // 碰撞
        yspd = 0;
        setOnGround(true);
    }

    // 跳跃准备
    if (jumpKeyBuffered && onGround) {
        // 基准
        var index = 0;

        // 应用跳跃速度
        yspd = jspd[index];

        // 设定跳跃计时器
        jumpHoldTimer = jumpHoldFrames[index];

        // 将玩家设为离地状态
        setOnGround(false);

        // 清空跳跃缓冲
        jumpKeyBuffered = 0;

        // 重置小幅度跳跃计时器
        coyoteJumpTimer = 0;
    }

    // 移动
    y += yspd;
#endregion

// 精灵控制
// 行走
if (Math.abs(xspd) > 0) {
    sprite_index = walkSpr;
}

// Running
if (Math.abs(xspd) >= moveSpd[1]) {
    sprite_index = runSpr;
}

// 未移动
if (xspd == 0) {
    sprite_index = idleSpr;
}

// 空中
if (!onGround) {
    sprite_index = jumpSpr;
}

// 设定碰撞遮蔽物
mask_index = idleSpr;
// create 事件
setOnGround(true);

// 设定玩家属性
depth = -30;
controlsSetup();
face = 1;
maskSpr = spr_Waluigi;
idleSpr = spr_Waluigi;
walkSpr = spr_walugi_run;
runSpr = spr_walugi_dash;
jumpSpr = spr_walugi_jump;

// 移动
moveDir = 0;
runType = 0;
moveSpd[0] = 4;
moveSpd[1] = 5.5;
xspd = 3;
yspd = 0;

// 跳跃
grav = 0.275;
termVel = 8;
onGround = true;
jumpMax = 1;
jumpCount = 0;
jumpHoldTimer = 0;
    // 跳跃速度
    jspd[0] = -3.15;
    jumpHoldFrames[0] = 18;
    jspd[1] = -2.85;
    jumpHoldFrames[1] = 10;

// 小幅度时间
// 应用重力
coyoteHangFrames = 2;
coyoteHangTimer = 0;

// 跳跃缓冲时间
coyoteJumpFrames = 10;
coyoteJumpTimer = 0;

// 移动平台
myFloorPlat = noone;
moveplatXspd = 0;
moveplatMaxYspd = termVel;