You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AS3游戏开发角色非预期下落 falling布尔值判定异常问题

AS3平台游戏角色穿透下落问题修复

问题描述

  • 实现角色未站在物体顶部时自动下落的功能后,布尔变量falling会在不满足触发条件时持续保持为true
  • 角色短暂停驻在平台后会穿透平台下落,已确认诱因是velocity数值增长后超出地板判定范围,在代码其他位置重置velocity后问题仍存在
  • 已在gameEngine函数的if(falling)代码块中标记了临时解决方案的注释,原始代码如下:
// Imports
import flash.events.KeyboardEvent;
import flash.events.Event;

// Constants that can be edited
const grav:Number = 0.05;
const jumpPow:Number = 15;
const walkingDistance = 50; 

// Variables
var jumpVel:Number = jumpPow;
var velocity:Number = 0;
var dt:Number = 0;
var movingCount:Number = 0;
var newX:Number = 0;
var newY:Number = 0;
var charCornerHit:Number = 0; // 0 = TL 1 = TR 2 = BR 3 = BL (clockwise)
var jumping:Boolean = false;
var falling:Boolean = false;
var movingRight:Boolean = false;
var movingLeft:Boolean = false;
var hitDetVal:Boolean = false; // false
var floorHit:Boolean = false;
var object1Hit:Boolean = false;
var cCnrTL:Array = new Array(char.x, char.y);
var cCnrTR:Array = new Array(char.x + char.width, char.y);
var cCnrBR:Array = new Array(char.x + char.width, char.y + char.height);
var cCnrBL:Array = new Array(char.x, char.y + char.height);
var charCorners:Array = new Array(cCnrTL, cCnrTR, cCnrBR, cCnrBL); // Clockwise

addEventListener(Event.ENTER_FRAME, gameEngine);

function gameEngine(evt:Event):void{
    stage.addEventListener(KeyboardEvent.KEY_DOWN, moveCharacter);
    
    charCorners[0][0] = char.x;
    charCorners[0][1] = char.y;
    charCorners[1][0] = char.x + char.width;
    charCorners[1][1] = char.y;
    charCorners[2][0] = char.x + char.width;
    charCorners[2][1] = char.y + char.height;
    charCorners[3][0] = char.x;
    charCorners[3][1] = char.y + char.height;
    
    //trace(char.y);
    
    // Check if char is standing on something
    // Supposed to only check when character is not falling
    if (falling == false) {
        //trace(char.y + char.height + 1)
        hitDetection(0, char.y + char.height + 1)
        if (hitDetVal == false) {
            falling = true;
            hitDetVal = false;
            trace("not standing");
        }
        else {trace("standing on something");}
    }
    
    // Move char loop
    if (movingRight){
        if (movingCount == walkingDistance) {
            movingCount = 0
            movingRight = false;
        } else {
            char.x+=1
            movingCount += 1;
        }
    } else if (movingLeft) {
        if (movingCount == walkingDistance) {
            movingCount = 0
            movingLeft = false;
        } else {
            char.x-=1
            movingCount += 1;
        }
    }

    //trace(velocity)
    if (falling) {
        dt += 1
        velocity = velocity + grav*dt
        
        hitDetection(0, velocity)
        if (hitDetVal) {
            falling = false;
            hitDetVal = false;
            // TEMPORARY SOLUTION - Stopped character from falling past the floor but still ran falling condition
            //velocity = 0;
            //dt = 0;
            if (floorHit) {
                if (char.y < floor.y){
                    char.y = floor.y - char.height;
                    floorHit = false;
                    trace("Char Stopped falling")
                }
            } else if (object1Hit) {
                if (char.y - char.height < object1.y){
                    char.y = object1.y - char.height;
                    object1Hit = false;
                    trace("Char Stopped falling")
                }
            }
        } else {
            char.y += velocity;
        }
    } else {
        if (jumping) {
            
        }
        velocity = 0;
        dt = 0;
    }
}

function moveCharacter(event:KeyboardEvent):void{
    if(event.keyCode == Keyboard.LEFT){
        if(movingRight){
            movingRight = false;
            trace("STOPPED")
        } else {
            movingCount = 0
            movingLeft = true;
            trace("LEFT");
        }
    }
    if(event.keyCode == Keyboard.RIGHT){
        if(movingLeft){
            movingLeft = false;
            trace("STOPPED")
        } else {
            movingCount = 0
            movingRight = true;
            trace("RIGHT");
        }
    }
    if(event.keyCode == Keyboard.UP){
        jumping = true;
        trace("UP");
    }
}

function hitDetection(distX:Number, distY:Number) {
    for (var i:uint = 0; i < charCorners.length; i++) {
        newX = charCorners[i][0] + distX; 
        newY = charCorners[i][1] + distY;
        if (floor.hitTestPoint(newX, newY, true)){
            hitDetVal = true;
            floorHit = true;
            charCornerHit = i;
            break;
        } else if (object1.hitTestPoint(newX, newY, true)){
            hitDetVal = true;
            object1Hit = true;
            charCornerHit = i;
            break;
        }
    }
}

核心问题点

  1. 碰撞检测函数状态残留:hitDetection没有在入口处重置hitDetVal/floorHit/object1Hit三个标记,上次检测的结果会残留到本次,导致判定完全失真。
  2. 站立检测传参错误:站立检测时把绝对坐标char.y + char.height +1当成了偏移量传入,检测点直接被甩到角色下方极远位置,根本碰不到脚下的平台,自然会持续判定角色悬空,把falling设为true。
  3. 落地状态重置被注释:被注释掉的velocity = 0和dt = 0是必须的逻辑,落地后不重置下落速度和重力累计时间,速度会持续累加,单帧位移过大直接穿过碰撞体。
  4. 键盘监听重复注册:把键盘监听写在ENTER_FRAME循环里,每帧都会新增一个监听,按一次键会触发多次移动逻辑,运行越久越卡。
  5. 跳跃逻辑缺失:按上键只改了jumping标记,没有给向上的初速度,跳跃功能完全没生效。

修复方案

直接按以下点改代码即可:

  • 把stage.addEventListener(KeyboardEvent.KEY_DOWN, moveCharacter);移到gameEngine函数外面,和ENTER_FRAME监听放在一起,只注册一次。
  • 在hitDetection函数最开头加三行重置状态的代码:
    hitDetVal = false;
    floorHit = false;
    object1Hit = false;
    
  • 修正站立检测的传参,把hitDetection(0, char.y + char.height + 1)改成hitDetection(0, 1),只检测角色脚下1像素位置是否有平台。
  • 取消velocity = 0;和dt = 0;两行的注释,落地时必须重置下落速度和重力累计值。
  • 补全跳跃逻辑,在非下落状态检测到jumping为true时,给velocity赋值为-jumpPow,把falling设为true,再把jumping重置为false。

内容的提问来源于stack exchange,提问作者Goat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 19:45:58