Term::Animation二维对象碰撞检测异常问题求助
Perl Term::Animation 2.0 二维形状碰撞检测失效修复
问题根源
你的代码存在两个核心问题导致二维碰撞失效:
- 动物实体缺少移动逻辑:仅在
callback_args中存储了移动方向,但没有实现位置更新的回调,动物无法按照预期移动; - 碰撞后未调整位置:即使触发碰撞反转方向,动物当前位置仍处于碰撞区域,下一帧会继续穿过线条。
修复方案
1. 添加动物移动回调
给动物实体添加update回调函数,根据callback_args中的方向和速度更新位置:
sub update_animal { my ($animal, $anim, $delta) = @_; my ($x_dir, $y_dir, $z_dir, $speed) = @{$animal->callback_args}; $speed ||= 1; # 默认移动速度 my ($x, $y, $z) = @{$animal->position}; # 根据方向更新X轴位置 $x += $x_dir * $speed; $animal->position([$x, $y, $z]); }
在add_animal的new_entity调用中添加update参数:
my $animal = $anim->new_entity( type => 'animal', position => [3, $y, 1], shape => $shape, color => $mask, callback_args => [1, 0, 0, 1], # 最后一个参数设为速度 die_offscreen => 1, collision_handler => \&animal_collision, physical => 1, update => \&update_animal, # 添加移动回调 );
2. 优化碰撞处理逻辑
在碰撞反转方向后,将动物位置回退一个单位,避免卡在碰撞区域:
sub animal_collision { my ($animal, $anim) = @_; my $collisions = $animal->collisions(); foreach my $col_obj (@{$collisions}) { if ($col_obj->type eq 'background') { my $x_dir = $animal->callback_args->[0]; # 反转X方向 $animal->callback_args->[0] = -$x_dir; # 回退位置,脱离碰撞区域 my ($x, $y, $z) = @{$animal->position}; $x += -$x_dir * 1; $animal->position([$x, $y, $z]); } } }
3. 验证碰撞掩码
你的mask使用g字符作为碰撞区域标记,符合Term::Animation的要求(非空格字符都会被视为碰撞区域),只需确保mask的形状与shape完全对齐即可。
完整修复后代码
use strict; use warnings; use Term::Animation 2.0; use Term::Animation::Entity; use Time::HiRes qw(time); use Data::Dumper; use Curses; main(); sub add_animal { my ($anim, $y) = @_; $y = $y - 5; my $shape = q{ __ / _) _.----._/ / / / __/ ( | ( | /__.-'|_|--|_| }; my $mask = q{ gg g gg ggggggggg g g g ggg g g g g gggggggggggggg }; # Add the animal to the animation my $animal = $anim->new_entity( type => 'animal', position => [3, $y, 1], shape => $shape, color => $mask, callback_args => [1, 0, 0, 1], die_offscreen => 1, collision_handler => \&animal_collision, physical => 1, update => \&update_animal, ); } sub update_animal { my ($animal, $anim, $delta) = @_; my ($x_dir, $y_dir, $z_dir, $speed) = @{$animal->callback_args}; $speed ||= 1; my ($x, $y, $z) = @{$animal->position}; $x += $x_dir * $speed; $animal->position([$x, $y, $z]); } sub animal_collision { my ($animal, $anim) = @_; my $collisions = $animal->collisions(); foreach my $col_obj (@{$collisions}) { if ($col_obj->type eq 'background') { my $x_dir = $animal->callback_args->[0]; $animal->callback_args->[0] = -$x_dir; # 回退位置避免持续碰撞 my ($x, $y, $z) = @{$animal->position}; $x += -$x_dir * 1; $animal->position([$x, $y, $z]); } } } sub add_background { my ($anim, $screen_width, $screen_height) = @_; my $half_width = int($screen_width / 2); my $ground_level = int($screen_height * 0.7); for my $y (0..($screen_height)) { $anim->new_entity( type => 'background', shape => ['|'], position => [$half_width, $y, 1], color => ['w'], physical => 1, ); } } sub main { my $anim = Term::Animation->new(); $anim->color(1); halfdelay(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); add_background($anim, $screen_width, $screen_height); my $animal = add_animal($anim, ($ground_level - 1)); # animation loop while(1) { $anim->animate(); # use getch to control the frame rate, and get input at the same time. my $input = getch(); if($input eq 'q') { quit(); } } $anim->end(); }
内容的提问来源于stack exchange,提问作者Sam Dorfman
相关产品推荐
相关产品推荐

