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

Perl Term::Animation碰撞检测失效,实体碰撞未反转方向求助

问题排查与修复方案

1. 缺失实体移动逻辑

你的动物实体没有设置move_handler回调,导致它不会根据callback_args里的方向值移动。必须添加移动处理函数来更新实体位置:

sub animal_move {
    my ($animal, $anim, $delta) = @_;
    my ($x_dir, $y_dir, $z_dir, $speed) = @{$animal->callback_args};
    # 根据方向更新位置
    my ($x, $y, $z) = @{$animal->position};
    $animal->position( [$x + $x_dir*$speed, $y + $y_dir*$speed, $z + $z_dir*$speed] );
}

然后在add_animal里添加move_handler和碰撞类型参数:

my $animal = $anim->new_entity(
    type => 'animal',
    position => [3, $y, 1],
    shape => '*',              
    color => 'r',
    callback_args => [1, 0, 0, 1], # 最后一个值为移动速度
    die_offscreen => 0,
    coll_handler => \&animal_collision,
    move_handler => \&animal_move, # 新增移动回调
    coll_type => 'animal', # 新增碰撞类型标识
);

2. 背景实体未配置碰撞属性

背景的竖线实体没有设置coll_type,Term::Animation默认不会检测无碰撞类型实体的碰撞。修改add_background里的实体创建代码:

$anim->new_entity(
    shape => ['|'],
    position => [$half_width, $y, 21],
    color => ['w'],
    coll_type => 'obstacle', # 新增障碍物碰撞类型
);

3. 碰撞处理函数逻辑优化

当前碰撞处理函数没有判断碰撞对象类型,且未处理实体重叠问题,修改如下:

sub animal_collision {
    my ($animal, $anim) = @_;
    my $collisions = $animal->collisions();
    return unless $collisions && @$collisions;

    foreach my $col_obj (@{$collisions}) {
        # 仅处理与障碍物的碰撞
        next unless $col_obj->coll_type eq 'obstacle';

        my ($x_dir) = @{$animal->callback_args};
        # 反转X方向
        $animal->callback_args->[0] = -$x_dir;
        
        # 轻微回退位置,避免卡在障碍物中
        my ($x, $y, $z) = @{$animal->position};
        $animal->position( [$x + (-$x_dir)*1, $y, $z] );
        last; # 处理一次碰撞即可退出循环
    }
}

4. 避免重复创建实体

外层循环每次resize都会重复创建实体,调整main函数确保先清空旧实体再创建新的:

sub main {
    my $anim = Term::Animation->new();
    $anim->color(1);
    halfdelay(1);
    my $paused = 0;

    while(1) {
        my $screen_width = $anim->width();
        my $screen_height = $anim->height();
        my $half_width = int($screen_width / 2);
        my $ground_level = int($screen_height * 0.7);

        $anim->remove_all_entities(); # 先清空旧实体
        add_background($anim, $screen_width, $screen_height);
        add_animal($anim, ($ground_level - 1));

        # animation loop
        while(1) {
            my $current_time = time();
            $anim->animate() unless($paused);

            my $input = getch();
            if($input eq 'q') { quit(); }
            if($input eq 'r' || $input eq KEY_RESIZE()) { last; }
            if($input eq 'p') { $paused = !$paused; }
        }
        $anim->update_term_size();
    }
    $anim->end();
}

关键原理说明

  • Term::Animation的碰撞检测依赖实体的coll_type属性,只有当两个实体都设置该属性时才会触发检测。
  • move_handler是实体每一帧更新位置的必要回调,没有它实体不会移动,自然也不会触发碰撞。
  • 碰撞后回退位置可以避免实体卡在障碍物中,因为碰撞触发时实体已经与障碍物重叠,反转方向后需要稍微离开重叠区域。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:02:13