Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
I'm planning to put this on CPAN next. Could someone let me know what namespace it should go in?

package Sprite; use 5.006; use strict; #use warnings; use Gtk; use Gtk::Gdk::ImlibImage; use Gnome; #use Data::Dumper; sub _debug; #require Exporter; =head1 NAME Sprite - Perl module to do C64 style sprites =head1 SYNOPSIS use Gtk; use Gnome; init Gnome "test.pl"; use Sprite; my $mw = new Gtk::Window( "toplevel" ); my($canvas) = Gnome::Canvas->new() ; $mw->add($canvas ); $canvas->show; my $croot = $canvas->root; my $sprites = new Sprite($croot); my $p1 = $sprites->create("./player1.xpm", 100, 0); $sprites->slide_to_time($p1,5000, 100, 100); my $p2 = $sprites->create("./player2.xpm", 0, 0); $sprites->slide_to_speed($p2,10, 100, 100); $sprites->set_collision_handler(\&Bang); $mw->show; Gtk->main; sub Bang { print "Bang!\n"; exit; } =head1 DESCRIPTION Sprite is a module to bring back the simple graphics programming of th +e C64 (hopefully without the lookslikearse component). You can decla +re pictures to be 'sprites' on the canvas, and then move them around +and crash them into each other. The canvas is the Gnome::Canvas object. You have to have a Gtk::Canva +s object before starting Sprite. =head1 METHODS =over 4 =cut #our @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not expo +rt # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. # This allows declaration use Sprite ':all'; # If you do not need this, moving things directly into @EXPORT or @EXP +ORT_OK # will save memory. our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( ); our $VERSION = '0.01'; # Preloaded methods go here. =item new Sprite( $canvas_root ); The new method takes one argument, the canvas root object for the canv +as you want to draw on. You may obtain the canvas root from your canvas like this: my $croot = $canvas->root; =cut sub new { _debug "New sprite manager created"; my $self = bless {}, ref($_[0]) || $_[0] || __PACKAGE__; $self->{sprite} = {}; $self->{croot} = $_[1]; $self->{cgroup} = {}; return $self; } =item $sprite_number = $sprites->create("/path/to/filename", 10, 20); Create will load an image file (right now, only xpm format) from disk +and make a sprite out of it. The two numbers are the x and y positio +n on the canvas. =cut sub create { my ($self, $filename, $x, $y) = @_; my $img = Gtk::Gdk::ImlibImage->load_image($filename) || die " +Could not load requested tile, $filename. $!"; my ( $cg, $cg_index ) = $self->_get_new_cgroup(); $cg->hide; my $imgitem = $cg->new($cg, "Gnome::CanvasImage", 'image' => $img, 'x' => $x, 'y' => $y, width => $img->rgb_width, height => $img->rgb_height, ); $cg->{x} = $x; $cg->{y} = $y; $cg->{width} = $img->rgb_width; $cg->{height} = $img->rgb_height; #$cg->{radius} = sqrt($cg->{width}**2 + $cg->{height}**2)/2; $cg->{radius} = ($cg->{width} + $cg->{height})/4; $cg->{cx} = $cg->{x} + $cg->{width}/2; $cg->{cy} = $cg->{y} + $cg->{height}/2; my $index = $self->_add_sprite($cg); $cg->{index} = $index; return $index; } =item $sprites->show( $sprite_number ); Makes the sprite appear on the canvas =cut sub show { my ($self, $item) = @_; $self->{sprite}->{$item}->show; } =item $sprites->hide( $sprite_number ); Make the sprite picture disappear from the canvas. Note that it can s +till collide with other sprites. If you don't want it to hit anythin +g, move it out of the way or ignore it in your own collision handler. =cut sub hide { my ($self, $item) = @_; $self->{sprite}->{$item}->hide; } =item $sprites->destroy( $sprite_number ); Completely destroys a sprite. =cut sub destroy { } sub update_sprite { my ($self, $item) = @_; my $cg = $self->{sprite}->{$item}; $cg->{cx} = $cg->{x} + $cg->{width}/2; $cg->{cy} = $cg->{y} + $cg->{height}/2; } =item $sprites->move_to( $sprite_number, 10, 20 ); Teleports the sprite named in $sprite_number to the position given imm +ediately. Contrast slide_to_xxx functions. =cut sub move_to { my ( $self, $index, $x, $y) = @_; #_debug "Moving sprite number $index"; #_debug "Moving sprite with index $index and reef ", ref( $se +lf->{sprite}->{$index}), "\n"; return unless (ref( $self->{sprite}->{$index}) =~ /CanvasGroup +/i); my $deltax = $x-$self->{sprite}->{$index}->{x}; my $deltay = $y-$self->{sprite}->{$index}->{y}; $self->{sprite}->{$index}->{x} = $x; $self->{sprite}->{$index}->{y} = $y; _debug "time: ", time(), " index: $index x: $x, y: $y\n"; $self->{sprite}->{$index}->move($deltax, $deltay); } =item $sprites->slide_to_time( $sprite_number, $time, 10, 20 ); Will make the sprite $sprite_number 'slide' across the canvas to the p +osition 10, 20. It will take $time seconds to do so. Slow speeds wi +ll appear jerky. =cut sub slide_to_time { my ( $self, $index, $time, $x, $y) = @_; if ( $time ==0 ) { #The user really wanted move_to $self->move_to($index, $x, $y); #Aren't I a nice guy? return; } #$self->velocity($index, 1, 1); my $deltax = $x-$self->{sprite}->{$index}->{x}; my $deltay = $y-$self->{sprite}->{$index}->{y}; my $distance = sqrt($deltax**2 + $deltay**2); my $speed = $distance / $time; my $vx = $deltax / $time*1000; my $vy = $deltay / $time*1000; $self->velocity($index, $vx, $vy); my $larger = (abs($deltax)>abs($deltay)) ? $deltax : $deltay; $self->{sprite}->{$index}->{timeout} = $time; _debug "Moving sprite $index to $x, $y (distance $distance) at + speed $vx, $vy for $time milliseconds\n"; } sub _delta { my ($self, $index, $x, $y) = @_; my $deltax = $x-$self->{sprite}->{$index}->{x}; my $deltay = $y-$self->{sprite}->{$index}->{y}; return ($deltax, $deltay); } =item $sprites->slide_to_speed( $sprite_number, $speed, 10, 20); Will 'slide' the sprite $sprite_number to the position 10, 20. It wil +l move at a speed of $speed pixels per second. =cut sub slide_to_speed { my ( $self, $index, $speed, $x, $y) = @_; if ( $speed ==0 ) { #The user really wanted move_to $self->move_to($index, $x, $y); #Aren't I a nice guy? return; } my ($deltax, $deltay) = $self->_delta($index, $x, $y); my $distance = sqrt($deltax**2 + $deltay**2); my $time = $distance / $speed; my $vx = $deltax / $time; my $vy = $deltay / $time; _debug "Moving sprite $index to $x, $y at $vx, $vy for $time m +illiseconds"; $self->velocity($index, $vx, $vy); $self->{sprite}->{$index}->{timeout} = $time * 1000; } =item $sprites->pos( $sprite_number); Returns the x and y coordinates of $sprite_number =cut sub pos { my ($self, $index) = (shift, shift); _debug "Returning position for sprite number $index"; return $self->{sprite}->{$index}->{x}, $self->{sprite}->{$inde +x}->{y}; } =item $sprites->velocity( $sprite_number, 5, 6); Sets the speed of $sprite_number. The numbers are the x and y speeds. + Negative numbers will make the sprite go backwards. =cut sub velocity { my ( $self, $index, $vx, $vy) = @_; my $larger = abs((abs($vx)>abs($vy)) ? $vx : $vy); if ( $larger == 0 ) { $self->{sprite}->{$index}->{vx} = 0; $self->{sprite}->{$index}->{vy} = 0; Gtk->timeout_remove($self->{sprite}->{$index}->{timer} +); return; } $self->{sprite}->{$index}->{interval} = 1000/$larger; $vx /= $larger; $vy /= $larger; _debug "vx: $vx, vy: $vy interval ", $self->{sprite}->{$index} +->{interval}, "\n"; $self->{sprite}->{$index}->{vx} = $vx; $self->{sprite}->{$index}->{vy} = $vy; $self->{sprite}->{$index}->{timer} = Gtk->timeout_add( $self-> +{sprite}->{$index}->{interval}, \&tick, $self, $index); } sub tick { #shift; my ($self, $i) = @_; my $newx = $self->{sprite}{$i}{x} + $self->{sprite}{$i}{vx +}; my $newy = $self->{sprite}->{$i}->{y} + $self->{sprite}->{ +$i}->{vy}; if ( $self->{sprite}->{$i}->{timeout} > 0 ) { $self->{sprite}->{$i}->{timeout} -= $self->{sprite +}->{$i}->{interval}; #print "Timeout is ", $self->{sprite}->{$i}->{time +out}, " interval is ", $self->{sprite}->{$i}->{interval}, "\n"; if ( $self->{sprite}->{$i}->{timeout} < 1 ) { $self->velocity($i, 0,0); } } #_debug "Calling move_to from tick loop for sprite number +$i\n"; $self->move_to( $i, $newx, $newy); $self->update_sprite( $i ); $self->check_coll($i) if $self->{collision_handler}; return 1; } sub check_coll { my ($self, $item) = @_; my $cg = $self->{sprite}->{$item}; foreach my $si ( keys %{$self->{sprite}} ) { next if ( $si eq $item); my $sp = $self->{sprite}->{$si}; next unless $sp; my $centre_dist = sqrt( ($cg->{x} - $sp->{x})**2 + ($ +cg->{y} - $sp->{y})**2); if ( ($centre_dist - $cg->{radius} -$sp->{radius} ) < +0 ) { _debug "Collision between $cg->{x}, $cg->{y} rad +ius $cg->{radius} and $sp->{x}, $sp->{y} radius $sp->{radius}\n"; &{$self->{collision_handler}}($item, $si); } } } =item $sprites->set_collision_handler ( \&collision_handler ); Name a function that will be called when two sprites collide. Note th +at the collision detection system is extremely crappy right now. It +turns out that it is very difficult to efficiently detect collisions. Your function will be called like this: collision_handler( $sprite_number, $sprite_number); where the two sprite numbers are the two sprites that collided. Multi +ple sprites colliding will cause many collision handler callbacks. Note well that if you set the collision handler Sprite.pm will check e +very single sprite for collisions every animation loop. I haven't op +timised this, so you will notice a massive slowdown as you add more s +prites. To switch collisions checking off, set the handler to undef: $sprites->set_collision_handler ( undef ); =cut sub set_collision_handler { my ($self, $handler) = @_; $self->{collision_handler} = $handler; } { my $next_sprite=1; sub _add_sprite { my ( $self, $sprite) = @_;; $self->{sprite}->{$sprite} = $sprite;; #my $ind = $next_sprite; #$next_sprite++; return $sprite; } } { my $next_group=1; sub _get_new_cgroup { my $self = shift; $self->{cgroup}->{$next_group} = $self->{croot}->new($self +->{croot}, "Gnome::CanvasGroup"); my $ref = $self->{cgroup}->{$next_group}; my $ind = $next_group; $next_group++; return $ref, $ind; } } sub _debug { # print @_, "\n"; } + 1; __END__ =head1 EXPORT Nothing. =head1 AUTHOR jepri of PerlMonks, E<lt>jeremy.price@member.sage-au.org.auE<gt> =head1 SEE ALSO L<perl>, man Gnome::reference, man Gtk::reference, Gnome::Canvas. =cut

In reply to Gtk::Sprite by jepri

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (3)
As of 2024-04-18 23:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found