如何在终端尺寸变化时用Curses实现Perl动画重绘
解决Perl Term::Animation终端尺寸变化后无法重绘动画的问题
问题分析
你的代码存在几个关键问题导致终端 resize 后实体无法重绘:
- 错误的变量声明:
my $entity->{position}中的my会创建新的词法变量,而非修改原有实体的位置属性,导致原实体位置未更新。 - 未处理Curses的resize事件:
getch()默认是阻塞模式,会错过终端尺寸变化时触发的KEY_RESIZE事件,且单纯轮询屏幕尺寸不够可靠。 - 缺少必要的画面重置步骤:更新终端尺寸后,需要清除旧画面并确保动画环境正确重置,否则旧的渲染内容会干扰新画面。
修正后的代码
#!/usr/bin/env perl use Term::Animation; use Term::Animation::Entity; use Curses; # 初始化动画对象(补充你原本的实体声明代码) my $anim1 = Term::Animation->new(); my $entity = Term::Animation::Entity->new( # 这里填入你原本的实体参数,比如shape、color等 ); $anim1->add_entity($entity); # 获取初始屏幕尺寸 my ($width, $height) = $anim1->screen_size(); # 设置窗口非阻塞,避免getch()阻塞导致错过resize事件 nodelay($anim1->window(), 1); # 启用keypad捕获特殊键(比如KEY_RESIZE) keypad($anim1->window(), 1); # 初始化实体到屏幕中间 $entity->{position} = [$height / 2 - 7, $width / 2 - 25, 0]; while (1) { # 渲染当前帧 $anim1->animate(); # 处理用户输入和resize事件 my $input = getch(); if (defined $input) { if ($input eq 'c') { last; # 按'c'退出 } elsif ($input == KEY_RESIZE) { # 捕获终端resize事件 my ($new_width, $new_height) = $anim1->screen_size(); $width = $new_width; $height = $new_height; # 更新实体到新屏幕的中间位置(去掉my,直接修改原有实体) $entity->{position} = [$height / 2 - 7, $width / 2 - 25, 0]; # 更新终端尺寸并清除旧画面 $anim1->update_term_size(); # 强制清除屏幕,避免残留旧内容 clear(); } } # 控制动画帧率,避免过度占用CPU napms(50); } # 退出时恢复终端设置 endwin();
关键修正点说明
- 去掉
my直接修改$entity->{position},确保原有实体的位置被更新。 - 使用
nodelay()设置非阻塞输入,keypad()启用特殊键捕获,确保能及时响应KEY_RESIZE事件。 - 触发resize时调用
clear()清除旧画面,配合update_term_size()重置动画的终端环境。 - 添加
napms()控制帧率,减少CPU占用。 - 最后调用
endwin()恢复终端正常状态,避免退出后终端显示异常。
内容的提问来源于stack exchange,提问作者Sam Dorfman
相关产品推荐
相关产品推荐

