Beefy Boxes and Bandwidth Generously Provided by pair Networks Cowboy Neal with Hat
more useful options
 
PerlMonks  

SDLx handlers and Moose

by Ransom (Beadle)
on May 24, 2012 at 19:21 UTC ( #972299=perlquestion: print w/ replies, xml ) Need Help??
Ransom has asked for the wisdom of the Perl Monks concerning the following question:

Hey monks, back again with another puzzler.

I'm testing out SDL and SDLx, as well as learning Moose. According to the SDLx docs, when setting up move and show handler callbacks, SDLx will automatically pass some variables in. Namely, ($step, $app, $time) = @_;. This was all well and good when I was practicing outside of Moose. All values were passed correctly.

Once Moose was incorporated, I passed an object method as the callback instead of a sub in the main file. Now when the callback is called, I only receive the blessed hashref of the object, none of the $step, $app, or $time values. This effectively breaks my movement and drawing methods.

The main code is like this:
#! /opt/perl/bin/perl package game; use strict; use warnings; use SDL; use SDL::Event; use SDL::Events; use SDLx::App; use Switch; use Mob; my $app = SDLx::App->new( w => 400, h => 400, t => "Pew Pew", hw_surface => 1, double_buf => 1, dt => .1, delay => 10, ); SDL::Events::enable_key_repeat(10, 10); my $ship = Mob->new(); $app->add_event_handler(\&moveship); $app->add_move_handler ( \&{$ship->move} ); $app->add_show_handler ( \&{$ship->draw} ); sub moveship { my $event = shift; my $controller = shift; if ($event->type == SDL_KEYDOWN) { switch($event->key_sym()) { case SDLK_UP { $ship->{velocity}->{y} -= 1} case SDLK_DOWN { $ship->{velocity }->{y} += 1} case SDLK_LEFT{ $ship->{velocity }->{x} -= 1} case SDLK_RIGHT{ $ship->{velocity }->{x} += 1} } } } $app->run;
and the Moose class is as follows:
#! /opt/perl/bin/perl package Mob; use Moose; use Data::Dumper; has 'position' => (is => 'rw', builder => 'build_pos'); has 'velocity' => (is => 'rw', builder => 'build_vel'); sub build_pos { return {x => 0, y => 0}; } sub build_vel { return {x => 0, y => 0}; } sub move { print Dumper("Move", @_); } sub draw { print Dumper("Draw", @_); } 1;

As you can see, I've stripped the methods of anything useful in order to just print the argument lists. The counter example of this is to move the callback method to the main file, in which it will pass all the values the documentation specifies.

How can I get the values from SDLx app stuff into my Moose method calls?

Occasionally putting words into a post is beyond my ability so please don't hesitate to ask me for more information or a better description.

Ransom

Comment on SDLx handlers and Moose
Select or Download Code
Re: SDLx handlers and Moose
by chromatic (Archbishop) on May 24, 2012 at 20:36 UTC

    You have to pass the parameters from the callback to your method, something like:

    $app->add_move_handler ( sub { $ship->move( @_ ) } ); $app->add_show_handler ( sub { $ship->draw( @_ ) } );

    Improve your skills with Modern Perl: the free book.

      Alright so that works like a charm. My new question is why must I use the sub keyword when adding the methods as callbacks? Shouldn't it already be obvious I'm calling a method in a class? I'm assuming I'm missing some knowledge about perl oop but I've read just about everything I can get my hands on.

      Anyway thank you for your quick help and accurate response (I admit I was pretty darn skeptical).

      Ransom

        My new question is why must I use the sub keyword when adding the methods as callbacks?

        Because of everything :) see Tutorials: Closure on Closures or read about it in chromatic's free book

        My new question is why must I use the sub keyword when adding the methods as callbacks?

        How else is Perl to know that you mean to pass a function reference? Remember that curly braces in Perl 5 can mean any of three things: a hash reference, a block, or an anonymous function passed to a prototyped function.

        In effect, the code I posted:

        $app->add_move_handler ( sub { $ship->move( @_ ) } ); $app->add_show_handler ( sub { $ship->draw( @_ ) } );

        ... is a shorter version of this code, using anonymous functions instead:

        sub move_ship { $ship->draw( @_ ); } sub draw_ship { $ship->draw( @_ ); } $app->add_move_handler( \&move_ship ); $app->add_show_handler( \&draw_ship );

        ... or even:

        my $move_ship = sub { $ship->move( @_ ) }; my $draw_ship = sub { $ship->draw( @_ ) }; $app->add_move_handler( $move_ship ); $app->add_show_handler( $draw_ship );

        Do you follow so far?

        A callback is a reference to a function. If you put a method call where a callback is needed, it won't work as expected.

        # The first one is wrong. It adds a reference to an subroutine named f +or the return value of $ship->move (or \&1) # because print returns 1 when it is successful. $app->add_move_handler ( \&{$ship->move} ); $app->add_move_handler ( sub { $ship->move( @_ ) } );

        Try this to verify that:

        #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; $Data::Dumper::Deparse = 1; use Mob; my $ship = Mob->new(); my $first = \&{$ship->move}; print "first: ", Dumper( $first ); my $second = sub { $ship->move( @_ ) }; print "second: ", Dumper( $second ); # &$first(); # Uncomment to see the error 'Undefined subroutine &main: +:1 called at ./test.pl line 17.' &$second( 1, 2 );

        Update: chromatic replied while I was typing this up with more thorough answers than mine.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://972299]
Approved by herveus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (8)
As of 2013-05-20 06:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best material for plates (tableware) is:









    Results (404 votes), past polls