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
相关产品推荐
相关产品推荐

