linuxperlanimationterminalcurses

perl term animation collision detection not working


I'm trying to make a perl terminal animation where an enitity reverses direction when it collides with another object. Here is the code I have so far:

use Term::Animation 2.0;
use Term::Animation::Entity;
use Time::HiRes qw(time);
use Data::Dumper;
use Curses;
use strict;
use warnings;


main();

sub add_animal {
    my ($anim, $y) = @_;

    # Add the animal to the animation
    my $animal = $anim->new_entity(
        type => 'animal',
        position => [3, $y, 1],
        shape => '*',              
        color => 'r',
        callback_args => [1, 0, 0, 0],
        die_offscreen => 0,
        coll_handler => \&animal_collision, 
    );
}

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

  foreach my $col_obj (@{$collisions}) {
    # Get the current x direction from the callback_args
    my $x_dir = $animal->callback_args->[0];

    # Reverse the direction
    $animal->callback_args->[0] = -$x_dir;
  }
}



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(
            shape => ['|'],
            position => [$half_width, $y, 21],
            color => ['w'], 
        );
    }
}

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);

      add_background($anim, $screen_width, $screen_height);
      add_animal($anim, ($ground_level - 1));

      # animation loop
      while(1) {
          my $current_time = time();

          # run and display a single animation frame
          $anim->animate() unless($paused);

          # use getch to control the frame rate, and get input at the same time.
          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->remove_all_entities();
  }

  $anim->end();
}

As of now, the animal object passes through the other object without any change of direction. Please let me know what is wrong with the collision detector or any other issues.


Solution

  • Collision detection is done for physical objects only. Add physical => 1 to both objects. Also the model has 3 dimensions so you need to have the objects in the same z plane if you want them to collide.

    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) = @_;
    
        # Add the animal to the animation
        my $animal = $anim->new_entity(
            type => 'animal',
            position => [3, $y, 21],
            shape => '*',
            color => 'r',
            callback_args => [1, 0, 0, 0],
            die_offscreen => 0,
            coll_handler => \&animal_collision,
            physical => 1,
        );
    }
    
    sub animal_collision {
      my ($animal, $anim) = @_;
      my $collisions = $animal->collisions();
      #return unless defined $collisions;
      foreach my $col_obj (@{$collisions}) {
        # Get the current x direction from the callback_args
        my $x_dir = $animal->callback_args->[0];
    
        # Reverse the direction
        $animal->callback_args->[0] = -$x_dir;
      }
    }
    
    
    
    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(
                shape => ['|'],
                position => [$half_width, $y, 21],
                color => ['w'],
                physical => 1,
            );
        }
    }
    
    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);
    
          add_background($anim, $screen_width, $screen_height);
          my $animal = add_animal($anim, ($ground_level - 1));
          # animation loop
          while(1) {
              my $current_time = time();
    
              # run and display a single animation frame
              $anim->animate() unless($paused);
    
              # use getch to control the frame rate, and get input at the same time.
              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->remove_all_entities();
      }
    
      $anim->end();
    }