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

Replies are listed 'Best First'.
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?

        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.

        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