<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Daniel Ruoso</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/" />
    <link rel="self" type="application/atom+xml" href="http://daniel.ruoso.com/atom.xml.en" />
    <id>tag:daniel.ruoso.com,2010-07-01://6</id>
    <updated>2011-02-24T13:40:08Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.1-en-master-r4611-2aa2e8ea-20110318</generator>

<entry>
    <title>Art? Garbage?</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/arte_lixo.html.en" />
    <id>tag:daniel.ruoso.com,2011://6.238</id>

    <published>2011-02-24T13:34:31Z</published>
    <updated>2011-02-24T13:40:08Z</updated>

    <summary>the advantage of walking to work in the morning is you see the scenes of an awekening city......</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[the advantage of walking to work in the morning is you see the scenes of an awekening city...<div><a href="http://daniel.ruoso.com/assets_c/2011/02/IMG_20110224_081034-73.html.en" onclick="window.open('http://daniel.ruoso.com/assets_c/2011/02/IMG_20110224_081034-73.html.en','popup','width=2592,height=1936,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://daniel.ruoso.com/assets_c/2011/02/IMG_20110224_081034-thumb-640x478-73.jpg" width="640" height="478" alt="IMG_20110224_081034.jpg" class="mt-image-none" style="" /></a></div><div><br /></div>]]>
        
    </content>
</entry>

<entry>
    <title>Producing ODF spreadsheets</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/odf_spreadsheets.html.en" />
    <id>tag:daniel.ruoso.com,2010://6.216</id>

    <published>2010-07-20T19:42:23Z</published>
    <updated>2010-07-20T19:56:49Z</updated>

    <summary>So I asked the LazyWeb what was the minimum boilerplate to produce a ODF spreadsheet and got no answer. So here is my jorney.Long story short: I have a XML database, I need to take data out and send to...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
    <category term="dataformats" label="Data Formats" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="database" label="Database" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="html" label="HTML" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="metadata" label="Metadata" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="opendocument" label="OpenDocument" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="openofficeorg" label="OpenOffice.org" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="xml" label="XML" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="zipfileformat" label="ZIP (file format)" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[So I asked the LazyWeb what was the minimum boilerplate to produce a ODF spreadsheet and got no answer. So here is my jorney.<br /><br />Long story short: I have a XML database, I need to take data out and send to a customer in a user-friendly format, the data-set is too big for the OpenOffice html parser to be nice, so I decided to produce the .ods file on my own.<br /><br />How does an ODF file look like? well, it's just a zip file with some standard metadata and a content.xml file. How to have an easy boilerplate for the zip file? Simple save an empty spreadsheet in calc and then replace the content.xml file inside it.<br /><br />So, the remaining question is: How to produce the ODF XML?<br /><br />What I did was, open the original content.xml and start to strip away anything that seemed useless. Repeat it untill things stop working. <br /><br />So this is an unoficial guide for people writing ODF spreadsheet documents on their own. This is the bare minimum XML I got:<br /><br /><br />

<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;office:document-content<br /> xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"<br /> xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"<br /> xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"   <br /> office:version="1.1"&gt;<br /><br /> &lt;office:body&gt;<br />  &lt;office:spreadsheet&gt;<br /><br />   &lt;table:table table:name="Minha Planilha"&gt;<br /><br />    &lt;table:table-row&gt;<br />     &lt;table:table-cell&gt;<br />      &lt;text:p&gt;a&lt;/text:p&gt;<br />     &lt;/table:table-cell&gt;<br />     &lt;table:table-cell&gt;<br />      &lt;text:p&gt;1&lt;/text:p&gt;<br />     &lt;/table:table-cell&gt;<br />    &lt;/table:table-row&gt;<br /><br />    &lt;table:table-row&gt;<br />     &lt;table:table-cell&gt;<br />      &lt;text:p&gt;b&lt;/text:p&gt;<br />     &lt;/table:table-cell&gt;<br />     &lt;table:table-cell&gt;<br />      &lt;text:p&gt;2&lt;/text:p&gt;<br />     &lt;/table:table-cell&gt;<br />    &lt;/table:table-row&gt;<br /><br />   &lt;/table:table&gt;   <br /><br />  &lt;/office:spreadsheet&gt;<br /> &lt;/office:body&gt;<br />&lt;/office:document-content&gt;</pre>

<div style="margin-top: 10px; height: 15px;" class="zemanta-pixie"><a class="zemanta-pixie-a" href="http://www.zemanta.com/" title="Enhanced by Zemanta"><img style="border: medium none ; float: right;" class="zemanta-pixie-img" src="http://img.zemanta.com/zemified_e.png?x-id=de6af968-e9d7-41d4-80a1-e781371e730c" alt="Enhanced by Zemanta" /></a><span class="zem-script more-related pretty-attribution"><script type="text/javascript" src="http://static.zemanta.com/readside/loader.js" defer="defer"></script></span></div>]]>
        
    </content>
</entry>

<entry>
    <title>Transactional and Authorized Methods in your Catalyst Model Class</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/transaction-authorization.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.168</id>

    <published>2010-06-01T17:49:02Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>In a previous post I have showed how to implement a hack to have transactions and authorization around Catalyst model classes. I am now proud to say that after some uploads and a fix in MooseX::Method::Signatures (this post requires at...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="catalyst" label="catalyst" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="moose" label="moose" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>In a <a href="http://daniel.ruoso.com/categoria/perl/transactions-and-authorization">previous post</a> I have showed how to implement a hack to have transactions and authorization around Catalyst model classes. I am now proud to say that after some uploads and a fix in MooseX::Method::Signatures (this post requires at least version 0.31 of that module), you can now write very elegant model classes.</P></p>

<p><P>The requirement is simple, you usually need your model methods to be enclosed in transactions and to be subject to some kind of authorization mechanism. Now the code looks like:</P></p>

<p><PRE><br />
package MyApp::Model::MyModel;<br />
use Moose;<br />
use MooseX::Method::Signatures;<br />
use aliased 'MooseX::Meta::Method::Transactional';<br />
use aliased 'MooseX::Meta::Method::Authorized';<br />
extends 'Catalyst::Model';<br />
with 'Catalyst::Component::InstancePerContext';</p>

<p>has user =&gt; (is =&gt; 'ro');<br />
has schema =&gt; (is =&gt; 'ro');</p>

<p>sub build_per_context_instance {<br />
    my ($self, $c) = @_;<br />
    return MyApp::Model::MyModel-&gt;new<br />
        ({ user =&gt; $c-&gt;user, schema =&gt; $self-&gt;model('DBIC') });<br />
}</p>

<p>method get_product_price($product) does Transactional does Authorized(requires =&gt; ['customer']) {<br />
    return $product-&gt;prices-&gt;find({ 'me.listing' =&gt; "base" });<br />
};</p>

<p>method get_product_minprice($product) does Transactional does Authorized(requires =&gt; ['seller']) {<br />
    return $product-&gt;prices-&gt;find({ 'me.listing' =&gt; "minimum" });<br />
};</p>

<p>1;<br />
</PRE></p>

<p><P>Of course you also need MooseX::Meta::Method::Transactional, MooseX::Meta::Method::Authorized and Catalyst::Component::InstancePerContext for this code to work. But it certainly is very pretty.</P></p>]]>
        
    </content>
</entry>

<entry>
    <title>Writing Games in Perl - Part 7 - Game Map</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/games-perl-7.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.156</id>

    <published>2010-05-03T00:29:32Z</published>
    <updated>2010-07-01T19:42:22Z</updated>

    <summary>Following posts 1, 2, 3, 4, 5 and 6 on the subject of writing games in Perl, now we are going to add support for maps. At this moment, the initial ball position, as well as the walls are being...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="games" label="games" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sdl" label="sdl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>Following<br />
posts <a href="http://daniel.ruoso.com/categoria/perl/games-perl-1">1</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-2">2</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-3">3</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-4">4</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-5">5</A> and<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-6">6</A> on<br />
the subject of writing games in Perl, now we are going to add support<br />
for maps.</P></p>

<p><P>At this moment, the initial ball position, as well as the walls are<br />
being defined in Perl code, during the controller initialization. What<br />
we are going to do now is creating a serialization format that<br />
describes our simulated universe, then have a set of maps in a<br />
directory navigating through them as the goals in each map are<br />
achieved.</P></p>

<h3>The Map Format</h3>

<p><P>There are several options to serialize and deserialize data, some<br />
are easier to use, others provide more introspection and others are<br />
better performant. I've read once a good advice in game development,<br />
which is: keep your map format accessible to art people.</P></p>

<p><P>A lot of people hate XML, I'm not of that club, I do like XML a<br />
lot, specially because it allows introspection and validation via XML<br />
Schema. And after the advent of XML::Compile::Schema, it's very simple<br />
to handle XML in Perl. Basically, once you have a XML Schema, you can<br />
think just in Perl data structures that will be<br />
serialized/deserialized from/to XML with associated validation.</P></p>

<p><P>That being said, let's proceed to our map format, which is going to<br />
be expressed as a XML Schema Definition:</P></p>

<p><PRE><br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;xs:schema<br />
   xmlns:xs="http://www.w3.org/2001/XMLSchema"<br />
   targetNamespace="http://daniel.ruoso.com/categoria/perl/games-perl-7"<br />
   elementFormDefault="qualified"&gt;<br />
  &lt;xs:element name="map"&gt;<br />
    &lt;xs:complexType&gt;<br />
      &lt;xs:sequence&gt;<br />
        &lt;xs:element name="ball"&gt;<br />
          &lt;xs:complexType&gt;<br />
            &lt;xs:attribute name="radius" type="xs:float" /&gt;<br />
            &lt;xs:attribute name="x" type="xs:float" /&gt;<br />
            &lt;xs:attribute name="y" type="xs:float" /&gt;<br />
          &lt;/xs:complexType&gt;<br />
        &lt;/xs:element&gt;<br />
        &lt;xs:element name="goal"&gt;<br />
          &lt;xs:complexType&gt;<br />
            &lt;xs:attribute name="x" type="xs:float" /&gt;<br />
            &lt;xs:attribute name="y" type="xs:float" /&gt;<br />
          &lt;/xs:complexType&gt;<br />
        &lt;/xs:element&gt;<br />
        &lt;xs:element name="wall" maxOccurs="unbounded"&gt;<br />
          &lt;xs:complexType&gt;<br />
            &lt;xs:attribute name="x" type="xs:float" /&gt;<br />
            &lt;xs:attribute name="y" type="xs:float" /&gt;<br />
            &lt;xs:attribute name="w" type="xs:float" /&gt;<br />
            &lt;xs:attribute name="h" type="xs:float" /&gt;<br />
          &lt;/xs:complexType&gt;<br />
        &lt;/xs:element&gt;<br />
      &lt;/xs:sequence&gt;<br />
    &lt;/xs:complexType&gt;<br />
  &lt;/xs:element&gt;<br />
&lt;/xs:schema&gt;<br />
</PRE></p>

<p><P>What the above means is:</P></p>

<p><UL><br />
 <LI>The root element is "map", it is composed as a sequence.<br />
 <LI>The first element in the "map" sequence is "ball", it should appear once<br />
     and only once, it has "radius", "x" and "y" as attributes.</LI><br />
 <LI>The second element is "goal" it also should appear only once and has "x"<br />
     and "y" as attributes.<br />
 <LI>Finally, the third element is "wall" which can happen more than once and has<br />
     "x", "y", "w" and "h" as attributes.</LI><br />
</UL></p>

<p><P>In Perl data structures that will mean the following:</P></p>

<p><UL><br />
 <LI>The main "map" structure is a hash, with "ball", "goal" and<br />
     "wall" as keys.<br />
 <LI>The value for "ball" will be another hash, with "radius", "x" and "y"<br />
     as keys and the floats as values</LI><br />
 <LI>The value for "goal" will be another hash, with "x" and "y" as keys<br />
     and the floats as values</LI><br />
 <LI>The value for "wall" is going to be an arrayref containing one hash<br />
     for each wall define, where those will have "x", "y", "w" and "h" as<br />
     keys with the floats as values</LI><br />
</UL></p>

<p><P>The map currently implemented in Perl code would be the following<br />
perl structure:</P></p>

<p><PRE><br />
{ ball =&gt; { radius  =&gt; 0.5,<br />
            x       =&gt; 4,<br />
            y       =&gt; 10 },<br />
  goal =&gt; { x       =&gt; 10,<br />
            y       =&gt; 12.5 },<br />
  wall =&gt; [{ x =&gt; 0, y =&gt; 0, w =&gt; 20, h =&gt; 1 },<br />
           { x =&gt; 0, y =&gt; 0, h =&gt; 20, w =&gt; 1 },<br />
           { x =&gt; 20, y =&gt; 0, h =&gt; 20, w =&gt; 1 },<br />
           { x =&gt; 0, y =&gt; 20, w =&gt; 21, h =&gt; 1 },<br />
           { x =&gt; 7, y =&gt; 0, h =&gt; 9, w =&gt; 1 },<br />
           { x =&gt; 7, y =&gt; 11, h =&gt; 9, w =&gt; 1 },<br />
           { x =&gt; 12, y =&gt; 0, h =&gt; 9, w =&gt; 1 },<br />
           { x =&gt; 12, y =&gt; 11, h =&gt; 9, w =&gt; 1 },<br />
           { x =&gt; 9.2, y =&gt; 11, h =&gt; 1, 1.6 } ] }<br />
</PRE></p>

<p><P>That same structure as XML looks like:</P></p>

<p><PRE><br />
&lt;?xml version="1.0"?&gt;<br />
&lt;map xmlns="http://daniel.ruoso.com/categoria/perl/games-perl-7"&gt;<br />
 &lt;ball radius="0.5" x="4" y="10"/&gt;<br />
 &lt;goal x="10" y="12.5"/&gt;<br />
 &lt;wall x="0" y="0" w="20" h="1"/&gt;<br />
 &lt;wall x="0" y="0" w="1" h="20"/&gt;<br />
 &lt;wall x="20" y="0" w="1" h="20"/&gt;<br />
 &lt;wall x="0" y="20" w="21" h="1"/&gt;<br />
 &lt;wall x="7" y="0" w="1" h="9"/&gt;<br />
 &lt;wall x="7" y="11" w="1" h="9"/&gt;<br />
 &lt;wall x="12" y="0" w="1" h="9"/&gt;<br />
 &lt;wall x="12" y="11" w="1" h="9"/&gt;<br />
 &lt;wall x="9.2" y="11" w="1.6" h="1"/&gt;<br />
&lt;/map&gt;<br />
</PRE></p>

<p><P>With the advantage that non-Perl-Programmers can edit this map in a<br />
very confortable way. They can even validate the XML outside our game<br />
by using the XML Schema.</P></p>

<p><P>We're going to use a "maps" directory where we're going to load the<br />
maps in alphabetical order, so I'm going to save it as<br />
"zz_original_map.xml".</P></p>

<h3>Loading the map</h3>

<p><P>As the various objects were being created in the InGame controller<br />
initialization, we're simply going to replace the hard-coded<br />
initialization for the map-based loading.</P></p>

<p><P>The first step, which might happen at compile time, is building the<br />
XML::Compile::Schema closure that will parse the map.</P></p>

<p><PRE><br />
use XML::Compile::Schema;<br />
use XML::Compile::Util qw(pack_type);<br />
use constant MAP_NS =&gt; 'http://daniel.ruoso.com/categoria/perl/games-perl-7';<br />
my $s = XML::Compile::Schema-&gt;new('schema/map.xsd');<br />
my $r = $s-&gt;compile('READER', pack_type(MAP_NS, 'map'),<br />
                    sloppy_floats =&gt; 1);<br />
</PRE></p>

<p><P>$r is a code-reference that you call sending the xml document.</P></p>

<p><P>We also want to add a new attribute to the controller which will<br />
provide the map name:</P></p>

<p><PRE><br />
has 'mapname' =&gt; ( is =&gt; 'ro',<br />
                   isa =&gt; 'Str',<br />
                   required =&gt; 1 );<br />
</PRE></p>

<p><P>For simplification sake, we're going to just send the name of the<br />
first map in the controller -&gt;new call:</P></p>

<p><PRE><br />
my $controller = InGame-&gt;new({ main_surface =&gt; $surf,<br />
                               mapname =&gt; 'maps/zz_original_map.xml' });<br />
</PRE></p>

<p><br />
<P>And the InGame initialization code now looks like:</P></p>

<p><PRE><br />
sub BUILD {<br />
    my $self = shift;</p>

<p>    my $background = Plane-&gt;new({ main =&gt; $self-&gt;main_surface,<br />
                                  color =&gt; 0xFFFFFF });</p>

<p>    my $camera = Camera-&gt;new({ pixels_w =&gt; $self-&gt;main_surface-&gt;width,<br />
                               pixels_h =&gt; $self-&gt;main_surface-&gt;height,<br />
                               pointing_x =&gt; $self-&gt;ball-&gt;cen_h,<br />
                               pointing_y =&gt; $self-&gt;ball-&gt;cen_v });</p>

<p>    my $map = $r-&gt;($self-&gt;mapname);</p>

<p>    # first, let's set the ball position and radius.<br />
    $self-&gt;ball-&gt;cen_h($map-&gt;{ball}{x});<br />
    $self-&gt;ball-&gt;cen_v($map-&gt;{ball}{y});<br />
    $self-&gt;ball-&gt;radius($map-&gt;{ball}{radius});</p>

<p>    # attach the ball to the camera.<br />
    $self-&gt;ball-&gt;add_rect_moving_listener($camera);</p>

<p>    # create the ball view<br />
    my $ball_view = FilledRect-&gt;new({ color =&gt; 0x0000FF,<br />
                                      camera =&gt; $camera,<br />
                                      main =&gt; $self-&gt;main_surface,<br />
                                      x =&gt; $self-&gt;ball-&gt;pos_h,<br />
                                      y =&gt; $self-&gt;ball-&gt;pos_v,<br />
                                      w =&gt; $self-&gt;ball-&gt;width,<br />
                                      h =&gt; $self-&gt;ball-&gt;height });<br />
    $self-&gt;ball-&gt;add_rect_moving_listener($ball_view);</p>

<p>    # now create the goal<br />
    $self-&gt;goal(Point-&gt;new($map-&gt;{goal}));<br />
    my $goal_view = FilledRect-&gt;new({ color =&gt; 0xFFFF00,<br />
                                      camera =&gt; $camera,<br />
                                      main =&gt; $self-&gt;main_surface,<br />
                                      x =&gt; $self-&gt;goal-&gt;x - 0.1,<br />
                                      y =&gt; $self-&gt;goal-&gt;y - 0.1,<br />
                                      w =&gt; 0.2,<br />
                                      h =&gt; 0.2 });</p>

<p>    $self-&gt;views([]);<br />
    push @{$self-&gt;views}, $background, $ball_view, $goal_view;<br />
    $self-&gt;walls([]);</p>

<p>    # now we need to build four walls, to enclose our ball.<br />
    foreach my $rect (map { Rect-&gt;new($_) } @{$map-&gt;{wall}}) {</p>

<p>        my $wall_model = Wall-&gt;new({ pos_v =&gt; $rect-&gt;y,<br />
                                     pos_h =&gt; $rect-&gt;x,<br />
                                     width =&gt; $rect-&gt;w,<br />
                                     height =&gt; $rect-&gt;h });</p>

<p>        push @{$self-&gt;walls}, $wall_model;</p>

<p>        my $wall_view = FilledRect-&gt;new({ color =&gt; 0xFF0000,<br />
                                          camera =&gt; $camera,<br />
                                          main =&gt; $self-&gt;main_surface,<br />
                                          x =&gt; $rect-&gt;x,<br />
                                          y =&gt; $rect-&gt;y,<br />
                                          w =&gt; $rect-&gt;w,<br />
                                          h =&gt; $rect-&gt;h });</p>

<p>        push @{$self-&gt;views}, $wall_view;</p>

<p>    }</p>

<p>}<br />
</PRE></p>

<p><P>At this point, the game is fully functional with the original map,<br />
now we can proceed to the next point.</P></p>

<h3>Map cycling</h3>

<p><P>We already have a goal in each map, so we need to react when the<br />
goal is reached so the next map is loaded. As you might have noticed,<br />
the InGame controller is completely tied to each map, so what we need<br />
to do is replace the controller instance by one with the new map.</P></p>

<p><P>There's one important point in the way our ball.pl script handles<br />
the main loop, it is not fully delegated to the controller, but it<br />
tries to handle the global events before it sends it to the<br />
controller.</P></p>

<p><P>What this means is that we can use an User SDL event to signal the<br />
main application that the goal for this controller instance was<br />
already achieved and that it should initialize the next<br />
controller.</P></p>

<p><P>So, first we're going to fire the event in the InGame controller as<br />
soon as the ball reaches the goal:</P></p>

<p><PRE><br />
    if (collide_goal($ball, $self-&gt;goal, $frame_elapsed_time)) {<br />
        my $event = SDL::Event-&gt;new();<br />
        $event-&gt;type( SDL_USEREVENT );<br />
        SDL::Events::push_event($event);<br />
    }<br />
</PRE></p>

<p><P>We're not doing putting any additional data in the event because<br />
this is the only user event we have in the game, we could use the<br />
event_code and the two pointers for data in the SDL::Event if we<br />
wanted to have a better qualification of the event.</P></p>

<p><P>Now we just need to handle that event. First, we're going to get the list<br />
of available maps in the beggining of ball.pl:</P></p>

<p><PRE><br />
my @maps = sort &lt;maps/*.xml&gt;;<br />
</PRE></p>

<p><P>Then we're going to replace the hard-coded map selection with<br />
the first map in that array.</P></p>

<p><PRE><br />
my $controller = InGame-&gt;new({ main_surface =&gt; $surf,<br />
                               mapname =&gt; shift @maps });<br />
</PRE></p>

<p><P>And, finally, handle the SDL_USEREVENT replacing the controller<br />
with a new instance while there are still maps in @maps.</P></p>

<p><PRE><br />
    while (SDL::Events::poll_event($sevent)) {<br />
        my $type = $sevent-&gt;type;<br />
        if ($type == SDL_QUIT) {<br />
            exit;<br />
            my $nextmap = shift @maps;<br />
            if ($nextmap) {<br />
                $controller = InGame-&gt;new({ main_surface =&gt; $surf,<br />
                                            mapname =&gt; $nextmap });<br />
            } else {<br />
                print 'Finished course in '.(($now - $first_time)/1000)."\n";<br />
                exit;<br />
            }<br />
        } elsif ($controller-&gt;handle_sdl_event($sevent)) {<br />
            # handled.<br />
        } else {<br />
            # unknown event.<br />
        }<br />
    }<br />
</PRE></p>

<p><P>As usual, follows a small video of the game, where it starts in one<br />
map and when the goal is achieved, the second map is loaded.</P></p>

<p><object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/GYLqmoKwG3A&amp;hl=pt_BR&amp;fs=1&amp;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/GYLqmoKwG3A&amp;hl=pt_BR&amp;fs=1&amp;" type="application/x-shockwave-flash" allowfullscreen="true" width="480" height="385"></embed></object></p>]]>
        
    </content>
</entry>

<entry>
    <title>Simplifying the Deployment of Catalyst Perl Applications in Shared Hosting</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/catalyst-shared-hosting.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.157</id>

    <published>2010-04-24T14:46:47Z</published>
    <updated>2010-07-01T19:42:22Z</updated>

    <summary>Deploying Perl in shared hosting environments used to be an unpleasant experience, since most hosting providers would refuse to install and keep up-to-date CPAN modules. Fortunally this is no longer the case, since the advent of local::lib, which allows the...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="catalyst" label="catalyst" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>Deploying Perl in shared hosting environments used to be an unpleasant experience, since most hosting providers would refuse to install and keep up-to-date CPAN modules. Fortunally this is no longer the case, since the advent of local::lib, which allows the build and installing of modules in a private directory. But this still required the user to have shell access to the machine, in order to bootstrap the local::lib and install all the dependencies.</P></p>

<p><P>The most problematic is not just requiring shell access, but actually requiring the compiler toolkit as well as the development headers for libraries such as libpq-dev (for the DBD::Pg module) or libxml2-dev (for the XML::LibXML module). This would certainly be a problem for a lot of hosting providers.</P></p>

<p><P>The last time I started building a local::lib bootstrap I came to the following realization. The machine I'm using is a Debian Lenny, the machine in the hosting provider is a Debian Lenny, so all I need to do is bootstrap the local::lib in my own machine (actually doing it inside a fresh debootstrapped chroot, to actually installing every non-core module by cpan). Then I just created a tarball with it and sent to the server and voilà, it just worked.</P></p>

<p><P>Of course my chroot required all the development headers as well as the compiler toolchain, but when I move the local::lib dir to the server, everything is already compiled, so I just need to make sure the postgresql client library is installed (which was already the case) as well as the libxml2 package (which was also the case).</P></p>

<p><P>So I realized this image can be re-used in any hosting provider using Debian-Lenny- i386. As I wouldn't like to have my blog shutdown due to excess traffic, I've uploaded the file to <a href="http://rapidshare.com/files/379625660/task-catalyst_local-lib_Debian-Lenny-i386.tgz">rapidshare</a>, feel free to take it to a more convenient place (please tell me the link so I can add it here) -- I have removed the manpages in order to reduce the file size (reduced about 50%). <B>UPDATE:</B> arcanez has kindly provided <a href="http://enotime.net/task-catalyst_local-lib_Debian-Lenny-i386.tgz">two</A> <A HREF="http://warpedreality.org/task-catalyst_local-lib_Debian-Lenny-i386.tgz">other</a> mirrors, and arw__ provided a <a href="http://wwwcip.cs.fau.de/~snalwuer/task-catalyst_local-lib_Debian-Lenny-i386.tgz">third</A> for that file so you don't need to suffer from rapidshare. </P></p>

<p><br />
<P>How to use it?</P></p>

<p><P>Simply unpack it into your user's account, it will create a "perl5" directory, if your hosting provider doesn't allow shell access, simply unpack it anywhere into your local machine and use the ftp client to send all the files (remember to set binary mode, since there will be binary files in there).</P></p>

<p><P>Then you need to include that path into your Perl's include directory, you can:</P></p>

<p><UL><br />
<LI>set the PERL5LIB environment directory with /home/youruser/perl5/lib/perl5:/home/youruser/perl5/lib/perl5/i486-linux-gnu-thread-multi</LI><br />
<LI>add -I/home/youruser/perl5/lib/perl5 -I/home/youruser/perl5/lib/perl5/i486-linux-gnu-thread-multi in the #!/usr/bin/perl line</LI><br />
<LI>use lib '/home/youruser/perl5/lib/perl5'; use lib  '/home/youruser/perl5/lib/perl5/i486-linux-gnu-thread-multi'; # into your fastcgi script</LI><br />
</UL></p>

<p><P>If more people think this is a good idea, we might eventually start having different prebuilt images, since that is completely OS-Version specific. The image I built is intended for use <B>ONLY</B> on Debian Lenny i386 machines, it will fail and segfault miserably if you try to use it in other OS and/or version.</P></p>]]>
        
    </content>
</entry>

<entry>
    <title>Writing Games in Perl - Part 6 - Math for dummies</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/games-perl-6.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.158</id>

    <published>2010-04-19T17:05:55Z</published>
    <updated>2010-07-01T19:42:22Z</updated>

    <summary>Following posts 1, 2, 3, 4 and 5 on the subject of writing games in Perl, now we are going to fix the math in the game. In the first post, I used a very naive simplification of the movement...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sdl" label="sdl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="snippet" label="snippet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>Following<br />
posts <a href="http://daniel.ruoso.com/categoria/perl/games-perl-1">1</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-2">2</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-3">3</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-4">4</A> and<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-5">5</A> on<br />
the subject of writing games in Perl, now we are going to fix the math<br />
in the game.</P></p>

<p><P>In the first post, I used a very naive simplification of the<br />
movement calculation. I simply considered that the velocity was<br />
constant during the time of the frame and recalculated the final<br />
velocity after the frame so it would affect the next calculation.</P></p>

<p><P>I have to confess that I didn't do it just for the simplification<br />
of the code. I did it because of my lack of good understanding of<br />
math. Some people have noticed that I should've used<br />
a <a href="en.wikipedia.org/wiki/Runge–Kutta_methods">Runge-Kutta</a><br />
method to solve the problem, but, honestly, the math language is<br />
something that really requires a level of practice I simply don't have<br />
(I've been working on Information Systems for 12 years, now it's the<br />
first time I really miss calculus knowledge).</P></p>

<p><P>The problem I was trying to solve is: Considering I have a ball<br />
that is falling at a speed of 3 m/s with a gravity of 9.8 m/s², how<br />
far would it fall after 25 miliseconds (about 40 FPS). I'm strongly<br />
visually-oriented, so let me try to represent in some ascii-art what I<br />
was trying to find out.</P></p>

<p><PRE><br />
position | .<br />
         |  I<br />
         |   .<br />
         |<br />
         |    .<br />
         |   <br />
         |<br />
         |     F<br />
         |<br />
         |<br />
         |      .<br />
         0-------------------------<br />
          time<br />
</PRE></p>

<p><P>I was considering I had defined the position I (initial) and I<br />
wanted to know which was the position F (final).</P></p>

<p><P>It was only after I shared the problem with Edilson (a colleague<br />
that works in the same place as I do), and after he present me a sheet<br />
full of math calculations which I simply ignored, since I couldn't<br />
understand, and then he said me: "You're looking at the wrong graphic,<br />
this graphic is derived from another graphic, which is velocity vs<br />
time".</P></p>

<p><P>This was a very important realization for me, bear with me: Let's<br />
simplify the problem a bit, let's consider we have a constant<br />
velocity. The graphic of velocity vs time would be something like:</P></p>

<p><PRE><br />
velocity |<br />
         |<br />
         |<br />
         |<br />
         |<br />
         |<br />
         |.......I..........F.....<br />
         |<br />
         |<br />
         |<br />
         |<br />
         0-------------------------<br />
          time<br />
</PRE></p>

<p><P>You probably remember that in order to find out how much an object<br />
moved in a given time-frame, the formula would be:</P></p>

<p><PRE><br />
     ΔS = Δt * v<br />
</PRE></p>

<p><P>As I said before, I'm a very visually-oriented person, and at that<br />
point I figured out the following:</P></p>

<p><PRE><br />
velocity |<br />
         |<br />
         |<br />
         |<br />
         |<br />
         |<br />
         |       I..........F     <br />
         |       |          |<br />
         |       |          |<br />
         |       |          |<br />
         |       |          |<br />
         0-------------------------<br />
          time<br />
</PRE></p>

<p><P>Wait, that's a rectangle, its width is Δt and it's height is v,<br />
so the distance travelled is the area of the rectangle.</P></p>

<p><P>WAIT! That's the definition of Integral I've been reading in math<br />
books for a while and that never really meant anything to me because<br />
of all the math blabbering that really require consistent math<br />
practice to actually understand anything.</P></p>

<p><P>So now that I feel a lot less dumb, let's proceed to the problem at<br />
hand. The velocity in our game is lineary-variable, which means that<br />
its graphic over time will look like:</P></p>

<p><PRE><br />
velocity |                  .<br />
         |                .<br />
         |              .<br />
         |            F<br />
         |          .<br />
         |        .<br />
         |      .<br />
         |    I<br />
         |  .<br />
         |.<br />
         |<br />
         0-------------------------<br />
          time<br />
</PRE></p>

<p><P>The intial grahic on the position over time at the beggining of<br />
this post is derived from this graphic -- and this is actually the<br />
meaning of derivative -- so the distance travelled in a given time<br />
frame is the area of the trapezoid representing that time frame:</P></p>

<p><PRE><br />
velocity |<br />
         |<br />
         |<br />
         |            F<br />
         |          . |<br />
         |        .   |<br />
         |      .     |<br />
         |    I       |<br />
         |    |       |<br />
         |    |       |<br />
         |    |       |<br />
         0-------------------------<br />
          time<br />
</PRE></p>

<p><P>So, the answer to my initial question is just a matter of<br />
calculating that area:</P></p>

<p><PRE><br />
     Δs = ((vI + vF) * Δt)/2<br />
</PRE></p>

<p><P>It looks pretty easy now, and, in fact, I feel quite dumb for<br />
taking so long to realize that. But anyway, that is probably all the<br />
required math for a lot of games. I hope I wasn't the only one who had<br />
a hard time understading all that, and, anyway, now I can start to<br />
understand more complex integral and derivative calculations.</P></p>

<p><P>So, let's apply that to the code in our game, which happens to be<br />
at the Ball.pm file.</P></p>

<p><PRE><br />
sub time_lapse {<br />
  my ($self, $old_time, $new_time) = @_;<br />
  my $elapsed = ($new_time - $old_time)/1000; # convert to seconds...</p>

<p>  my $vf_h = $self-&gt;vel_h + $self-&gt;acc_h * $elapsed;<br />
  my $vf_v = $self-&gt;vel_v + ($self-&gt;acc_v - g) * $elapsed;</p>

<p>  my $ds_h = (($self-&gt;vel_h + $vf_h) * $elapsed) / 2;<br />
  my $ds_v = (($self-&gt;vel_v + $vf_v) * $elapsed) / 2;</p>

<p>  $self-&gt;vel_h($vf_h);<br />
  $self-&gt;vel_v($vf_v);<br />
  $self-&gt;cen_h($self-&gt;cen_h + $ds_h);<br />
  $self-&gt;cen_v($self-&gt;cen_v + $ds_v);<br />
}<br />
</PRE></p>

<p><P>I also fixed the code in the main loop that was re-calculating that<br />
instead of calling time_lapse.</P></p>

<p><PRE><br />
    foreach my $wall (@{$self-&gt;walls}) {<br />
        if (my $coll = collide($ball, $wall, $frame_elapsed_time)) {<br />
            # need to place the ball in the result after the bounce given<br />
            # the time elapsed after the collision.<br />
            $ball-&gt;time_lapse($oldtime, $oldtime + (($coll-&gt;time)*1000) - 1);</p>

<p>            if (defined $coll-&gt;axis &amp;&amp;<br />
                $coll-&gt;axis eq 'x') {<br />
                $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
            } elsif (defined $coll-&gt;axis &amp;&amp;<br />
                     $coll-&gt;axis eq 'y') {<br />
                $ball-&gt;vel_v($ball-&gt;vel_v * -1);<br />
            } elsif (defined $coll-&gt;axis &amp;&amp;<br />
                     ref $coll-&gt;axis eq 'ARRAY') {<br />
                my ($xv, $yv) = @{$coll-&gt;bounce_vector};<br />
                $ball-&gt;vel_h($xv);<br />
                $ball-&gt;vel_v($yv);<br />
            } else {<br />
                warn 'BAD BALL!';<br />
                $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
                $ball-&gt;vel_v($ball-&gt;vel_v * -1);<br />
            }<br />
            return $self-&gt;handle_frame($oldtime + ($coll-&gt;time*1000), $now);<br />
        }<br />
    }<br />
</PRE></p>

<p><P>I'm not going to post any video for this post, since there's no<br />
visual difference. But I hope the ascii-art graphics are good enough.</P></p>]]>
        
    </content>
</entry>

<entry>
    <title>Writing Games in Perl - Part 5 - Creating a Goal</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/games-perl-5.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.159</id>

    <published>2010-04-12T01:51:20Z</published>
    <updated>2010-07-01T19:42:22Z</updated>

    <summary>Following posts 1, 2, 3 and 4 on the subject of writing games in Perl, now we are going to add a goal to our game. Currently we have a bouncing ball with that collides in walls and have a...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sdl" label="sdl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="snippet" label="snippet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>Following<br />
posts <a href="http://daniel.ruoso.com/categoria/perl/games-perl-1">1</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-2">2</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-3">3</A> and<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-4">4</A><br />
on the subject of writing games in Perl, now we are going to add<br />
a goal to our game.</P></p>

<p><P>Currently we have a bouncing ball with that collides in walls and<br />
have a camera following it. Now we are about to add a goal to the<br />
game. The idea is that you should get the ball to hit some specific<br />
point, considering the gravity and the 100% efficient bounce, making<br />
the ball go through some small places might be an interesting<br />
challenge.</P></p>

<p><P>The first thing we're going to do is change the walls<br />
configuration, so we make a more challenging setup, currently we have<br />
a box with a wall of half the height in the middle, let's make it a<br />
bit more interesting, let's change the walls initialization code to<br />
the following.</P></p>

<p><PRE><br />
    foreach my $rect ( Rect-&gt;new({ x =&gt; 0,<br />
                                   y =&gt; 0,<br />
                                   w =&gt; 20,<br />
                                   h =&gt; 1 }), # left wall<br />
                       Rect-&gt;new({ x =&gt; 0,<br />
                                   y =&gt; 0,<br />
                                   h =&gt; 20,<br />
                                   w =&gt; 1 }), # bottom wall<br />
                       Rect-&gt;new({ x =&gt; 20,<br />
                                   y =&gt; 0,<br />
                                   h =&gt; 20,<br />
                                   w =&gt; 1 }), # right wall<br />
                       Rect-&gt;new({ x =&gt; 0,<br />
                                   y =&gt; 20,<br />
                                   w =&gt; 21,<br />
                                   h =&gt; 1 }), # top wal<br />
                       Rect-&gt;new({ x =&gt; 7,<br />
                                   y =&gt; 0,<br />
                                   h =&gt; 9,<br />
                                   w =&gt; 1 }), # middle-left bottom<br />
                       Rect-&gt;new({ x =&gt; 7,<br />
                                   y =&gt; 11,<br />
                                   h =&gt; 9,<br />
                                   w =&gt; 1 }), # middle-left top<br />
                       Rect-&gt;new({ x =&gt; 12,<br />
                                   y =&gt; 0,<br />
                                   h =&gt; 9,<br />
                                   w =&gt; 1 }), # middle-right bottom<br />
                       Rect-&gt;new({ x =&gt; 12,<br />
                                   y =&gt; 11,<br />
                                   h =&gt; 9,<br />
                                   w =&gt; 1 }), # middle-right top<br />
                     ) {<br />
      # ...<br />
    }<br />
</PRE></p>

<p><P>This creates two small passages in the middle of two vertical<br />
walls, not really hard, but kinda entertaining to get the ball to go<br />
through those. But in order to make it actually hard, let's add<br />
another wall:</P></p>

<p><PRE><br />
                       Rect-&gt;new({ x =&gt; 9.2,<br />
                                   y =&gt; 11,<br />
                                   h =&gt; 1,<br />
                                   w =&gt; 1.6 }), # chamber<br />
</PRE></p>

<p><P>Now we have a small chamber created between the two vertical<br />
lines. It's kinda tricky to get the ball in there, I personally took<br />
some minutes.</P></p>

<p><P>But while I was testing this map, a bug appeared, and this is<br />
actually an important bug. Since the collision was pretty simplified<br />
to handle just one wall at the beginning, I was inadvertedly<br />
positioning the ball at the target destination after it bounced. This<br />
was ok when I had just one wall, but when I have more, and more<br />
importantly, when they are really close to each other, I might<br />
position the ball over another wall when detecting a collision, and<br />
that just, well, you have a ball inside a wall, unless you're watching<br />
the X Files, this can't be good.</P></p>

<p><P>The problem, as you might have noticed, happens when I calculate<br />
the target position after the bounce, so what we're going to do is<br />
simply stop trying to guess that. We're going to position the ball in<br />
the exactly spot before the collision with the bouncing velocities and<br />
recalculate the whole frame from that instant on.</P></p>

<p><P>This will actually mean a simplification of the code, that will<br />
look like:</P></p>

<p><PRE><br />
    foreach my $wall (@{$self-&gt;walls}) {<br />
        if (my $coll = collide($ball, $wall, $frame_elapsed_time)) {<br />
            # need to place the ball in the result after the bounce given<br />
            # the time elapsed after the collision.<br />
            my $collision_remaining_time = $frame_elapsed_time - $coll-&gt;time;<br />
            my $movement_before_collision_h = $ball-&gt;vel_h * ($coll-&gt;time - 0.001);<br />
            my $movement_before_collision_v = $ball-&gt;vel_v * ($coll-&gt;time - 0.001);<br />
            $ball-&gt;cen_h($ball-&gt;cen_h + $movement_before_collision_h);<br />
            $ball-&gt;cen_v($ball-&gt;cen_v + $movement_before_collision_v);<br />
            if ($coll-&gt;axis eq 'x') {<br />
                $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
            } elsif ($coll-&gt;axis eq 'y') {<br />
                $ball-&gt;vel_v($ball-&gt;vel_v * -1);<br />
            } elsif (ref $coll-&gt;axis eq 'ARRAY') {<br />
                my ($xv, $yv) = @{$coll-&gt;bounce_vector};<br />
                $ball-&gt;vel_h($xv);<br />
                $ball-&gt;vel_v($yv);<br />
            } else {<br />
                warn 'BAD BALL!';<br />
                $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
                $ball-&gt;vel_v($ball-&gt;vel_v * -1);<br />
            }<br />
            return $self-&gt;handle_frame($oldtime + ($coll-&gt;time*1000), $now);<br />
        }<br />
    }<br />
    $ball-&gt;time_lapse($oldtime, $now);<br />
</PRE></p>

<p><P>Now, to add a goal, we're going to add another set of objects, the<br />
goal itself, which is simply a point, and the view, which I'm also<br />
going to reuse the filled rect view. First I'm going to create a Point<br />
object akin to the Rect I have created earlier.</P></p>

<p><PRE><br />
package BouncingBall::Event::Point;<br />
use Moose;</p>

<p>has x =&gt; ( is =&gt; 'ro',<br />
           isa =&gt; 'Num',<br />
           required =&gt; 1 );<br />
has y =&gt; ( is =&gt; 'ro',<br />
           isa =&gt; 'Num',<br />
           required =&gt; 1 );<br />
</PRE></p>

<p><P>Now I'm going to add that point object to the controller as an<br />
attribute:</P></p>

<p><PRE><br />
use aliased 'BouncingBall::Event::Point';</p>

<p>has 'goal' =&gt; ( isa =&gt; 'rw',<br />
                isa =&gt; Point );<br />
</PRE></p>

<p><P>And now initialize both the goal and the view for it.</P></p>

<p><PRE><br />
    $self-&gt;goal(Point-&gt;new({ x =&gt; 10, y =&gt; 12.5 }));<br />
    my $goal_view = FilledRect-&gt;new({ color =&gt; 0xFFFF00,<br />
                                      camera =&gt; $camera,<br />
                                      main =&gt; $self-&gt;main_surface,<br />
                                      x =&gt; $self-&gt;goal-&gt;x - 0.1,<br />
                                      y =&gt; $self-&gt;goal-&gt;y - 0.1,<br />
                                      w =&gt; 0.2,<br />
                                      h =&gt; 0.2 });</p>

<p>    $self-&gt;views([]);<br />
    push @{$self-&gt;views}, $background, $ball_view, $goal_view;<br />
</PRE></p>

<p><P>Ok, now that we can see our goal, we just need to detect when the<br />
goal was achieved:</P></p>

<p><PRE><br />
sub collide_goal {<br />
    my ($ball, $goal, $time) = @_;<br />
    my $rect = hash2point({ x =&gt; $goal-&gt;x, y =&gt; $goal-&gt;y });<br />
    my $circ = hash2circle({ x =&gt; $ball-&gt;cen_h, y =&gt; $ball-&gt;cen_v,<br />
                             radius =&gt; $ball-&gt;radius,<br />
                             xv =&gt; $ball-&gt;vel_h,<br />
                             yv =&gt; $ball-&gt;vel_v });<br />
    return dynamic_collision($circ, $rect, interval =&gt; $time);<br />
}<br />
#...<br />
sub reset_ball {<br />
    my ($self) = @_;<br />
    $self-&gt;ball(Ball-&gt;new());<br />
}<br />
#...<br />
if (collide_goal($ball, $self-&gt;goal, $frame_elapsed_time)) {<br />
    $self-&gt;reset_ball();<br />
}<br />
</PRE></p>

<p><P>Ok, not very exciting, but something does happen, and that's a<br />
first step.</P></p>

<p><P>As usual, follows a small video of the game:</P></p>

<p><object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/RPKKZ0EUZss&amp;hl=pt_BR&amp;fs=1&amp;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/RPKKZ0EUZss&amp;hl=pt_BR&amp;fs=1&amp;" type="application/x-shockwave-flash" allowfullscreen="true" width="480" height="385"></embed></object></p>]]>
        
    </content>
</entry>

<entry>
    <title>Writing Games in Perl - Part 4 - Implementing a Camera</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/games-perl-4.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.160</id>

    <published>2010-03-31T03:19:05Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>Following posts 1, 2 and 3 on the subject of writing games in Perl, now we are going to add a camera. Up to this point, we&apos;ve been coupling the positional information in our simulated universe with the screen position....</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sdl" label="sdl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="snippet" label="snippet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>Following<br />
posts <a href="http://daniel.ruoso.com/categoria/perl/games-perl-1">1</A>,<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-2">2</A> and<br />
<a href="http://daniel.ruoso.com/categoria/perl/games-perl-2">3</A><br />
on the subject of writing games in Perl, now we are going to add<br />
a camera.</P></p>

<p><P>Up to this point, we've been coupling the positional information in<br />
our simulated universe with the screen position. This is very easy to<br />
do, but very limiting as well, how can we represent off-screen<br />
elements that way?</P></p>

<p><P>Our next step is to implement a camera. The idea is quite simple,<br />
instead of asking for each model object to render itself, We're going<br />
to:</P></p>

<p><OL><br />
<LI>Initialize a view object for each of the model objects.</LI><br />
<LI>Detect which model objects are in the current view sight of the<br />
camera.</LI><br />
<LI>Send to the view objects the positional information of the model<br />
objects.<br />
<LI>Ask the view objects to draw themselves.<br />
</OL></p>

<p><P>At this point you might have noticed that I'm using the terms<br />
"model" and "view" as a direct reference to the Model-View-Controller<br />
architecture, and that's precisely my intention. The basic idea is:<br />
The model is only responsible for managing the simulation of our<br />
universe, while the view is only responsible for turning that<br />
simulation visible to the user. The Controller here is the code that<br />
implements the main loop, receiving the user events, and coordinating<br />
the FPS management.</P></p>

<p><P>I could list several reasons on why having the model and the view<br />
as separated objects is a good idea, but I'd like two point just two<br />
of them, since these are going to be future topics in this<br />
tutorial:</P></p>

<p><OL><br />
<LI>You can apply "themes" to the visualization, like "hi-res" and<br />
"low-res" simply by changing the initialization of the view, adding<br />
support for zoom and rotation is also very simple.<br />
<LI>You can have the calculations on the simulation side in a<br />
different thread then the rendering of the objects, enabling our game<br />
to take advantage on multi-core systems.</LI><br />
</OL></p>

<h3>Code Layout</h3>

<p><P>The first thing I'm going to do is reorganize our current module<br />
layout. Up to this point our code had:</p>

<p><UL><br />
<LI>ball.pl<br />
<LI>lib/Ball.pm</LI><br />
<LI>lib/Wall.pm</LI><br />
<LI>lib/Util.pm</LI><br />
</UL></p>

<p><P>But now we're going to need a different layout, here is our target<br />
organization:</P></p>

<p><DL><br />
<DT>ball.pl</DT><br />
<DD>This is still going to be our main script, but we're going to have<br />
less code in it.</DD><br />
<DT>lib/BouncingBall/Model/Ball.pm</DT><br />
<DD>Yes, I named our game BouncingBall, and the first model class is<br />
the ball itself, it will look much like the current code, but the<br />
"get_rect" and the "draw" methods won't be there.<br />
<DT>lib/BouncingBall/Model/Wall.pm</DT><br />
<DD>This looks like our current Wall code, but as with the ball,<br />
"get_rect" and "draw" won't be there.</DD><br />
<DT>lib/BouncingBall/Controller/InGame.pm</DT><br />
<DD>At this point we're only going to have one controller, but the<br />
general idea is that we're going to have one controller for each of<br />
the main states of the game, like "MainMenu", "Paused", "InGame",<br />
"GameOver" etc. The InGame controller will implement the code that is<br />
currently inside the main loop of ball.pl</DD><br />
<DT>lib/BouncingBall/View.pm</DT><br />
<DD>This defines the types for the things that implement draw.</DD><br />
<DT>lib/BouncingBall/View/Plane.pm</DT><br />
<DD>This implements the background.</DD><br />
<DT>lib/BouncingBall/View/FilledRect.pm</DT><br />
<DD>Currently, our ball and our wall are just filled rectangles, so<br />
we're going to preserve that for now. This is interesting to make the<br />
view vs model point even more clear. The view doesn't need to be aware<br />
of what it is representing, as long as it knows how to do it. In our<br />
case, it doesn't need to know if it is representing a Ball or a Wall,<br />
it simply needs to know where it is and what color to paint.</DD><br />
<DT>lib/BouncingBall/View/MainSurface.pm</DT><br />
<DD>This class represents the main application surface, it is special<br />
because it needs to configure the video mode, but it is also a<br />
dependency for the FilledRect view, since it needs to blit itself<br />
somewhere.</DD><br />
<DT>lib/BouncingBall/View/Camera.pm</DT><br />
<DD>This is the view class that will implement the mapping of<br />
coordinates from the simulated universe to the MainSurface, the<br />
FilledRect also depends on this class.</DD><br />
<DT>lib/BouncingBall/Event/RectMoved.pm</DT><br />
<DD>Typed event that describes the movement of some object represented<br />
by its enclosing rect.</DD><br />
<DT>lib/BouncingBall/Event/Rect.pm</DT><br />
<DD>Object describing a simple rect (using floating-point instead of<br />
integer), to be used by RectMoved.</DD><br />
<DT>lib/BouncingBall/Event/MovingRectObservable.pm</DT><br />
<DD>Moose role that implements the logic for being a class that can be<br />
observed.</DD><br />
<DT>lib/BouncingBall/Event/MovingRectObserver.pm</DT><br />
<DD>Moose role that defines the type of the observer class.</DD><br />
</DL></p>

<h3>General flow</h3>

<p><OL><br />
<LI>ball.pl initializes the BouncingBall module.<br />
<LI>BouncingBall initializes the MainSurface view, as this view is<br />
special and is preserved during the entire application lifetime,<br />
independent of the controller in charge right now.</LI><br />
<LI>As we don't implement game menu or any other fancy stuff, we go<br />
directly to the game. That means we'll initialize the InGame<br />
Controller.</LI><br />
<LI>The connection between the views and the models is defined by the<br />
controller, so it needs to initialize the models, the views and<br />
connect them together.</LI><br />
<LI>After the initialization, we're ready for the game loop, which is,<br />
at this point, entirely handled by the InGame controller.</LI><br />
</OL></p>

<h3>The case for Observers</h3>

<p><P>A naive implementation of the connection between the models and the<br />
views would be, at each step, to fetch the relevant information from<br />
the model and set it into the view. Or possibly have the view itself<br />
fetch the data from the model. But there's one important point to<br />
consider, if the model and the view ends in a different thread,<br />
accessing each other's data would become significantly complicated.</P></p>

<p><P>That being said, a different mechanism for view-model integration<br />
is necessary. If we go to the way GUI toolkits work, we'll notice a<br />
pattern called "The Observer Pattern", basically, one object registers<br />
itself as "observing" the other. When that specific type of event<br />
happens, a pre-defined method is called in the observing object.</P></p>

<p><P>So what we're going to do is to preserve a local cache of the<br />
information that view needs from the model, use it directly and get it<br />
updated using the observer pattern. That way we have the model and the<br />
view decoupled in terms of threading.</P></p>

<h3>To the code</h3>

<p><P>The first thing we need to do is porting our Ball and Wall into<br />
proper model objects, at first, simply removing the "get_rect" and<br />
"draw" methods. I'm not going to put all its code again here, but<br />
renaming the modules and removing that methods is the only thing I'm<br />
doing right now. The time_lapse is also simplfied to remove the<br />
automatic bounce, we're going to put extra walls to enclose the<br />
ball.</P></p>

<p><P>Now we need to step-by-step get to the final code layout presented<br />
earlier, let's start by the view classes, and in that case, let's get<br />
the most important view class, the MainSurface.</P></p>

<p><PRE><br />
package BouncingBall::View::MainSurface;<br />
use Moose;<br />
use SDL ':all';<br />
use SDL::Video;# ':all';</p>

<p>has 'surface' =&gt; (is =&gt; 'rw');<br />
has 'width' =&gt; (is =&gt; 'ro', default =&gt; 800);<br />
has 'height' =&gt; (is =&gt; 'ro', default =&gt; 600);<br />
has 'depth' =&gt; (is =&gt; 'ro', default =&gt; 32);</p>

<p>sub BUILD {<br />
    my ($self) = @_;</p>

<p>    die 'Cannot init ' . SDL::get_error()<br />
      if ( SDL::init( SDL_INIT_VIDEO ) == -1 );</p>

<p>    $self-&gt;surface<br />
      ( SDL::Video::set_video_mode<br />
        ( $self-&gt;width, $self-&gt;height, $self-&gt;depth,<br />
          SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL ))<br />
        or die 'Error initializing video.';</p>

<p>    return 1;<br />
}<br />
</PRE></p>

<p><P>Here we use Moose object initialization to initialize the SDL Video<br />
subsystem and get a new surface for the required videomode. This is a<br />
bit different then what we were doing in the original ball.pl, but not<br />
much. The most important difference is that we're now using double<br />
hardware buffering, which is more efficient then doing individual<br />
updates.</P></p>

<p><P>Now we need the Plane view, which implements the background.</P></p>

<p><PRE><br />
package BouncingBall::View::Plane;<br />
use Moose;<br />
use SDL::Video ':all';<br />
use SDL::Surface;</p>

<p>with 'BouncingBall::View';<br />
has color     =&gt; ( is =&gt; 'rw',<br />
                   default =&gt; 0 );<br />
has surface   =&gt; ( is =&gt; 'rw' );<br />
has rect_obj  =&gt; ( is =&gt; 'rw' );<br />
has color_obj =&gt; ( is =&gt; 'rw' );<br />
has main      =&gt; ( is =&gt; 'ro',<br />
                   required =&gt; 1 );</p>

<p>sub BUILD {<br />
    my ($self) = @_;<br />
    $self-&gt;_init_surface;<br />
    $self-&gt;_init_color_object;<br />
    $self-&gt;_init_rect;<br />
    $self-&gt;_fill_rect;<br />
    return 1;<br />
}</p>

<p>sub _init_surface {<br />
    my ($self) = @_;<br />
    $self-&gt;surface<br />
      ( SDL::Surface-&gt;new<br />
        ( SDL_SWSURFACE,<br />
          $self-&gt;main-&gt;width,<br />
          $self-&gt;main-&gt;height,<br />
          $self-&gt;main-&gt;depth,<br />
          0, 0, 0, 255 ) );<br />
    return 1;<br />
}</p>

<p>sub _init_color_object {<br />
    my ($self) = @_;<br />
    $self-&gt;color_obj<br />
      ( SDL::Video::map_RGB<br />
        ( $self-&gt;main-&gt;surface-&gt;format,<br />
          ((0xFF0000 &amp; $self-&gt;color)&gt;&gt;16),<br />
          ((0x00FF00 &amp; $self-&gt;color)&gt;&gt;8),<br />
          0x0000FF &amp; $self-&gt;color ));<br />
    return 1;<br />
}</p>

<p>sub _init_rect {<br />
    my ($self) = @_;<br />
    $self-&gt;rect_obj<br />
      ( SDL::Rect-&gt;new<br />
        ( 0, 0,<br />
          $self-&gt;main-&gt;width,<br />
          $self-&gt;main-&gt;height ) );<br />
    return 1;<br />
}</p>

<p>sub _fill_rect {<br />
    my ($self) = @_;<br />
    SDL::Video::fill_rect<br />
        ( $self-&gt;surface,<br />
          $self-&gt;rect_obj,<br />
          $self-&gt;color_obj );<br />
    return 1;<br />
}</p>

<p>after 'color' =&gt; sub {<br />
    my ($self, $color) = @_;<br />
    if ($color) {<br />
        $self-&gt;_init_color_object;<br />
        $self-&gt;_fill_rect;<br />
    }<br />
    return 1;<br />
};</p>

<p>sub draw {<br />
    my ($self) = @_;<br />
    SDL::Video::blit_surface<br />
        ( $self-&gt;surface, $self-&gt;rect_obj,<br />
          $self-&gt;main-&gt;surface, $self-&gt;rect_obj );<br />
    return 1;<br />
}<br />
</PRE></p>

<p><P>Now we need the Camera view, which is going to implement the logic<br />
on translating the coordinates from each object to the current<br />
visualization. This is a very important decoupling in our logic,<br />
because it is here that we relativize the points from the simulated<br />
universe to the screen. And this is going to be done by setting a<br />
camera position which is going to serve as pivot in the coordinate<br />
translation.</P></p>

<p><P>This is going to be implemented through three methods in our<br />
camera, one that converts a distance in meters to pixels, other that<br />
converts a coordinate to the screen and finally one that checks if a<br />
coordinate is visible at that moment.</P></p>

<p><PRE><br />
package BouncingBall::View::Camera;<br />
use Moose;</p>

<p>with 'BouncingBall::Event::RectMovingObserver';</p>

<p>has pointing_x =&gt; ( is =&gt; 'rw',<br />
                    default =&gt; 0 );<br />
has pointing_y =&gt; ( is =&gt; 'rw',<br />
                    default =&gt; 0 );<br />
has dpi        =&gt; ( is =&gt; 'rw',<br />
                    default =&gt; 0.96 );<br />
has pixels_w   =&gt; ( is =&gt; 'ro',<br />
                    required =&gt; 1 );<br />
has pixels_h   =&gt; ( is =&gt; 'ro',<br />
                    required =&gt; 1 );</p>

<p>sub m2px {<br />
    my ($self, $input) = @_;<br />
    return int((($input) * ($self-&gt;dpi / 0.0254)) + 0.5);<br />
}</p>

<p>sub px2m {<br />
    my ($self, $input) = @_;<br />
    return ($input) / ($self-&gt;dpi / .0254);<br />
}</p>

<p>sub width {<br />
    my ($self) = @_;<br />
    return $self-&gt;px2m($self-&gt;pixels_w);<br />
}</p>

<p>sub height {<br />
    my ($self) = @_;<br />
    return $self-&gt;px2m($self-&gt;pixels_h);<br />
}</p>

<p>sub translate_point {<br />
    my ($self, $x, $y) = @_;<br />
    my $uplf_x = $self-&gt;pointing_x - ($self-&gt;width / 2);<br />
    my $uplf_y = $self-&gt;pointing_y - ($self-&gt;height / 2);<br />
    my $rel_x = $x - $uplf_x;<br />
    my $rel_y = $y - $uplf_y;<br />
    my $pix_x = $self-&gt;m2px($rel_x);<br />
    my $pix_y = $self-&gt;m2px($rel_y);<br />
    my $inv_y = $self-&gt;pixels_h - $pix_y;<br />
    return ($pix_x, $inv_y);<br />
}</p>

<p>sub translate_rect {<br />
    my ($self, $x, $y, $w, $h) = @_;<br />
    my ($pix_x, $inv_y) = $self-&gt;translate_point($x, $y);<br />
    my $pix_h = $self-&gt;m2px($h);<br />
    my $pix_w = $self-&gt;m2px($w);<br />
    return ($pix_x, $inv_y - $pix_h, $pix_w, $pix_h);<br />
}</p>

<p>sub is_visible {<br />
    my ($self, $x, $y) = @_;<br />
    my ($tx, $ty) = $self-&gt;translate($x, $y);<br />
    if ($tx &gt; 0 &amp;&amp; $ty &gt; 0 &amp;&amp;<br />
        $tx &lt; $self-&gt;pixels_w &amp;&amp;<br />
        $ty &lt; $self-&gt;pixels_h) {<br />
        return 1;<br />
    } else {<br />
        return 0;<br />
    }<br />
}<br />
</PRE></p>

<p><P>The Camera requires the information from the MainSurface on the<br />
ammount of pixels it has to be able to do the translations.</P></p>

<p><P>Now we need to implement the FilledRect view class.</P></p>

<p><PRE><br />
package BouncingBall::View::FilledRect;<br />
use Moose;<br />
use SDL::Video ':all';<br />
use SDL::Surface;</p>

<p>with 'BouncingBall::View';<br />
with 'BouncingBall::Event::RectMovingObserver';</p>

<p>has x         =&gt; ( is =&gt; 'rw',<br />
                   default =&gt; 0 );<br />
has y         =&gt; ( is =&gt; 'rw',<br />
                   default =&gt; 0 );<br />
has w         =&gt; ( is =&gt; 'rw',<br />
                   default =&gt; 0 );<br />
has h         =&gt; ( is =&gt; 'rw',<br />
                   default =&gt; 0 );<br />
has color     =&gt; ( is =&gt; 'rw',<br />
                   default =&gt; 0 );<br />
has rect_obj  =&gt; ( is =&gt; 'rw' );<br />
has surface   =&gt; ( is =&gt; 'rw' );<br />
has color_obj =&gt; ( is =&gt; 'rw' );<br />
has camera    =&gt; ( is =&gt; 'rw',<br />
                   required =&gt; 1 );<br />
has main      =&gt; ( is =&gt; 'rw',<br />
                   required =&gt; 1 );</p>

<p>sub BUILD {<br />
    my ($self) = @_;<br />
    $self-&gt;_init_surface;<br />
    $self-&gt;_init_color_object;<br />
    $self-&gt;_init_rect;<br />
    $self-&gt;_fill_rect;<br />
    return 1;<br />
}</p>

<p>sub _init_surface {<br />
    my ($self) = @_;<br />
    $self-&gt;surface<br />
      ( SDL::Surface-&gt;new<br />
        ( SDL_SWSURFACE,<br />
          $self-&gt;camera-&gt;m2px($self-&gt;w),<br />
          $self-&gt;camera-&gt;m2px($self-&gt;h),<br />
          $self-&gt;main-&gt;depth,<br />
          0, 0, 0, 255 ) );<br />
    return 1;<br />
}</p>

<p>sub _init_color_object {<br />
    my ($self) = @_;<br />
    $self-&gt;color_obj<br />
      ( SDL::Video::map_RGB<br />
        ( $self-&gt;main-&gt;surface-&gt;format,<br />
          ((0xFF0000 &amp; $self-&gt;color)&gt;&gt;16),<br />
          ((0x00FF00 &amp; $self-&gt;color)&gt;&gt;8),<br />
          0x0000FF &amp; $self-&gt;color ));<br />
    return 1;<br />
}</p>

<p>sub _init_rect {<br />
    my ($self) = @_;<br />
    $self-&gt;rect_obj<br />
      ( SDL::Rect-&gt;new<br />
        ( 0, 0,<br />
          $self-&gt;camera-&gt;m2px($self-&gt;w),<br />
          $self-&gt;camera-&gt;m2px($self-&gt;h) ) );<br />
    return 1;<br />
}</p>

<p>sub _fill_rect {<br />
    my ($self) = @_;<br />
    SDL::Video::fill_rect<br />
        ( $self-&gt;surface(),<br />
          $self-&gt;rect_obj(),<br />
          $self-&gt;color_obj() );<br />
    return 1;<br />
}</p>

<p>after 'color' =&gt; sub {<br />
    my ($self, $color) = @_;<br />
    if ($color) {<br />
        $self-&gt;_init_color_object;<br />
        $self-&gt;_fill_rect;<br />
    }<br />
    return 1;<br />
};</p>

<p>after qw(w h) =&gt; sub {<br />
    my ($self, $newval) = @_;<br />
    if ($newval) {<br />
        $self-&gt;_init_surface;<br />
        $self-&gt;_init_rect;<br />
        $self-&gt;_fill_rect;<br />
    }<br />
    return 1;<br />
};</p>

<p>sub draw {<br />
    my ($self) = @_;<br />
    my $rect = SDL::Rect-&gt;new<br />
      ( $self-&gt;camera-&gt;translate_rect( $self-&gt;x, $self-&gt;y,<br />
                                       $self-&gt;w, $self-&gt;h ) );</p>

<p>    SDL::Video::blit_surface<br />
        ( $self-&gt;surface, $self-&gt;rect_obj,<br />
          $self-&gt;main-&gt;surface, $rect );</p>

<p>    return 1;<br />
}<br />
</PRE></p>

<p><P>Ok, now that we have the Model and the View classes, we can<br />
implement the observer pattern, so the view can be updated as the<br />
model changes.</P></p>

<p><P>One important aspect on how the MVC model works is that the<br />
controller should have just a limited control on the interaction<br />
between the model and the view, otherwise you'll get a very<br />
complicated code in the controller. Ideally you should have the same<br />
level of abstraction in the model as you have in the view, so you have<br />
componentization of your application.</P></p>

<p><P>That being said, we need to plan the communication pattern between<br />
the view and the model. It is important that they should be mostly<br />
unaware of each other, in the sense that the view doesn't need to know<br />
that it's a ball being modelled, but just that it has a point<br />
describing its position and a rect describing its measures - We can<br />
even keep only the rect for our current purposes.</P></p>

<p><P>That is our RectMoved event class and the Rect class which is used<br />
by it:</P></p>

<p><PRE><br />
package BouncingBall::Event::RectMoved;<br />
use Moose;</p>

<p>has old_rect =&gt; ( is =&gt; 'ro',<br />
                  isa =&gt; 'BouncingBall::Event::Rect',<br />
                  required =&gt; 0 );<br />
has new_rect =&gt; ( is =&gt; 'ro',<br />
                  isa =&gt; 'BouncingBall::Event::Rect',<br />
                  required =&gt; 1 );</p>

<p></PRE></p>

<p><P>The rect class is implemented here because SDL::Rect expects<br />
integers as its members, and we don't want to loose the precision.</P></p>

<p><PRE><br />
package BouncingBall::Event::Rect;<br />
use Moose;</p>

<p>has x =&gt; ( is =&gt; 'ro',<br />
           isa =&gt; 'Num',<br />
           required =&gt; 1 );<br />
has y =&gt; ( is =&gt; 'ro',<br />
           isa =&gt; 'Num',<br />
           required =&gt; 1 );<br />
has w =&gt; ( is =&gt; 'ro',<br />
           isa =&gt; 'Num',<br />
           required =&gt; 1 );<br />
has h =&gt; ( is =&gt; 'ro',<br />
           isa =&gt; 'Num',<br />
           required =&gt; 1 );<br />
</PRE></p>

<p><P>Now we need the role that implements the observable part, meaning<br />
that any class that wants to fire events for moving rects just need to<br />
compose that role and call the fire_rect_moved method.</P></p>

<p><PRE><br />
package BouncingBall::Event::RectMovingObservable;<br />
use Moose::Role;<br />
use MooseX::Types::Moose qw(ArrayRef);</p>

<p>use aliased 'BouncingBall::Event::RectMovingObserver';<br />
use aliased 'BouncingBall::Event::RectMoved';</p>

<p>has 'rect_moving_listeners' =&gt; ( traits =&gt; ['Array'],<br />
                                 is =&gt; 'ro',<br />
                                 isa =&gt; ArrayRef[RectMovingObserver],<br />
                                 default =&gt; sub { [] },<br />
                                 handles =&gt; { add_rect_moving_listener =&gt; 'push' } );</p>

<p>sub remove_rect_moving_listener {<br />
    my ($self, $object) = @_;<br />
    my $count = $self-&gt;rect_moving_listeners-&gt;count;<br />
    my $found;<br />
    for my $i (0..($count-1)) {<br />
        if ($self-&gt;rect_moving_listeners-&gt;[$i] == $object) {<br />
            $found = $i;<br />
            last;<br />
        }<br />
    }<br />
    if ($found) {<br />
        splice @{$self-&gt;rect_moving_listeners}, $found, 1, ();<br />
    }<br />
}</p>

<p>sub fire_rect_moved {<br />
    my ($self, $old_rect, $new_rect) = @_;<br />
    my %args = ( new_rect =&gt; $new_rect );<br />
    $args{old_rect} = $old_rect if $old_rect;<br />
    my $ev = RectMoved-&gt;new(\%args);<br />
    $_-&gt;rect_moved($ev) for @{$self-&gt;rect_moving_listeners};<br />
}<br />
</PRE></p>

<p><P>And the RectMovingObserver role:</P></p>

<p><PRE><br />
package BouncingBall::Event::RectMovingObserver;<br />
use Moose::Role;</p>

<p>requires 'rect_moved';<br />
</PRE></p>

<p><P>Now we need to make our Ball model class fire that event whenever<br />
its position or size attributes are changed. So we're goint to add the<br />
following modifiers to the attributes. At first we're not going to<br />
support the old_rect attribute of the event, so we're just sending the<br />
new_rect.</P></p>

<p><PRE><br />
with 'BouncingBall::Event::RectMovingObservable';</p>

<p>after qw(cen_v cen_h) =&gt; sub {<br />
    my ($self, $newval) = @_;<br />
    if ($newval) {<br />
        $self-&gt;fire_rect_moved( undef,<br />
                                Rect-&gt;new({ x =&gt; $self-&gt;pos_h,<br />
                                            y =&gt; $self-&gt;pos_v,<br />
                                            w =&gt; $self-&gt;width,<br />
                                            h =&gt; $self-&gt;height }) );<br />
    }<br />
}<br />
</PRE></p>

<p><P>And finally adding the observer code in the view class.</P></p>

<p><PRE><br />
with 'BouncingBall::Event::RectMovingObserver';</p>

<p>sub rect_moved {<br />
    my ($self, $ev) = @_;<br />
    $self-&gt;$_($ev-&gt;$_()) for grep { $self-&gt;$_() != $ev-&gt;$_() } qw(x y w h);<br />
}<br />
</PRE></p>

<p><H3>Everything's set! To the controller!</H3></p>

<p><P>Now we finally can have the controller code written. It should:</P></p>

<p><OL><br />
<LI>Initialize the models</LI><br />
<LI>Initialize the views</LI><br />
<LI>Connect them together</LI><br />
<LI>Orchestrate the time_lapse and the general rendering</LI><br />
</OL></p>

<p><P>So, in the end our controller looks like the following:</P></p>

<p><PRE><br />
package BouncingBall::Controller::InGame;<br />
use Moose;<br />
use MooseX::Types::Moose qw(ArrayRef);</p>

<p>use SDL::Events ':all';<br />
use aliased 'BouncingBall::Model::Ball';<br />
use aliased 'BouncingBall::Model::Wall';<br />
use aliased 'BouncingBall::View';<br />
use aliased 'BouncingBall::View::Plane';<br />
use aliased 'BouncingBall::View::FilledRect';<br />
use aliased 'BouncingBall::View::Camera';<br />
use aliased 'BouncingBall::View::MainSurface';<br />
use aliased 'BouncingBall::Event::Rect';</p>

<p>has 'ball' =&gt; ( is =&gt; 'rw',<br />
                isa =&gt; Ball,<br />
                default =&gt; sub { Ball-&gt;new() } );</p>

<p>has 'main_surface' =&gt; ( is =&gt; 'ro',<br />
                        isa =&gt; MainSurface,<br />
                        required =&gt; 1 );</p>

<p>has 'camera' =&gt; ( is =&gt; 'ro',<br />
                  isa =&gt; Camera );</p>

<p>has 'walls' =&gt; ( traits =&gt; ['Array'],<br />
                 is =&gt; 'rw',<br />
                 isa =&gt; ArrayRef[Wall] );<br />
has 'views' =&gt; ( traits =&gt; ['Array'],<br />
                 is =&gt; 'rw',<br />
                 isa =&gt; ArrayRef[View] );</p>

<p><br />
sub BUILD {<br />
    my $self = shift;</p>

<p>    my $background = Plane-&gt;new({ main =&gt; $self-&gt;main_surface,<br />
                                  color =&gt; 0xFFFFFF });</p>

<p>    my $camera = Camera-&gt;new({ pixels_w =&gt; $self-&gt;main_surface-&gt;width,<br />
                               pixels_h =&gt; $self-&gt;main_surface-&gt;height,<br />
                               pointing_x =&gt; $self-&gt;ball-&gt;cen_h,<br />
                               pointing_y =&gt; $self-&gt;ball-&gt;cen_v });</p>

<p>    my $ball_view = FilledRect-&gt;new({ color =&gt; 0x0000FF,<br />
                                      camera =&gt; $camera,<br />
                                      main =&gt; $self-&gt;main_surface,<br />
                                      x =&gt; $self-&gt;ball-&gt;pos_h,<br />
                                      y =&gt; $self-&gt;ball-&gt;pos_v,<br />
                                      w =&gt; $self-&gt;ball-&gt;width,<br />
                                      h =&gt; $self-&gt;ball-&gt;height });<br />
    $self-&gt;ball-&gt;add_rect_moving_listener($ball_view);</p>

<p>    $self-&gt;views([]);<br />
    push @{$self-&gt;views}, $background, $ball_view;</p>

<p>    $self-&gt;walls([]);</p>

<p>    # now we need to build four walls, to enclose our ball.<br />
    foreach my $rect ( Rect-&gt;new({ x =&gt; 0,<br />
                                   y =&gt; 0,<br />
                                   w =&gt; 20,<br />
                                   h =&gt; 1 }),<br />
                       Rect-&gt;new({ x =&gt; 0,<br />
                                   y =&gt; 0,<br />
                                   h =&gt; 20,<br />
                                   w =&gt; 1 }),<br />
                       Rect-&gt;new({ x =&gt; 20,<br />
                                   y =&gt; 0,<br />
                                   h =&gt; 20,<br />
                                   w =&gt; 1 }),<br />
                       Rect-&gt;new({ x =&gt; 0,<br />
                                   y =&gt; 20,<br />
                                   w =&gt; 21,<br />
                                   h =&gt; 1 }),<br />
                       Rect-&gt;new({ x =&gt; 10,<br />
                                   y =&gt; 0,<br />
                                   h =&gt; 10,<br />
                                   w =&gt; 1 })) {</p>

<p>        my $wall_model = Wall-&gt;new({ pos_v =&gt; $rect-&gt;y,<br />
                                     pos_h =&gt; $rect-&gt;x,<br />
                                     width =&gt; $rect-&gt;w,<br />
                                     height =&gt; $rect-&gt;h });</p>

<p>        push @{$self-&gt;walls}, $wall_model;</p>

<p>        my $wall_view = FilledRect-&gt;new({ color =&gt; 0xFF0000,<br />
                                          camera =&gt; $camera,<br />
                                          main =&gt; $self-&gt;main_surface,<br />
                                          x =&gt; $rect-&gt;x,<br />
                                          y =&gt; $rect-&gt;y,<br />
                                          w =&gt; $rect-&gt;w,<br />
                                          h =&gt; $rect-&gt;h });</p>

<p>        push @{$self-&gt;views}, $wall_view;</p>

<p>    }</p>

<p>}</p>

<p>sub handle_sdl_event {<br />
    my ($self, $sevent) = @_;</p>

<p>    my $ball = $self-&gt;ball;<br />
    my $type = $sevent-&gt;type;</p>

<p>    if ($type == SDL_KEYDOWN &amp;&amp;<br />
        $sevent-&gt;key_sym() == SDLK_LEFT) {<br />
        $ball-&gt;acc_h(-5);</p>

<p>    } elsif ($type == SDL_KEYUP &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_LEFT) {<br />
        $ball-&gt;acc_h(0);</p>

<p>    } elsif ($type == SDL_KEYDOWN &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_RIGHT) {<br />
        $ball-&gt;acc_h(5);</p>

<p>    } elsif ($type == SDL_KEYUP &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_RIGHT) {<br />
        $ball-&gt;acc_h(0);</p>

<p>    } elsif ($type == SDL_KEYDOWN &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_UP) {<br />
        $ball-&gt;acc_v(5);</p>

<p>    } elsif ($type == SDL_KEYUP &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_UP) {<br />
        $ball-&gt;acc_v(0);</p>

<p>    } elsif ($type == SDL_KEYDOWN &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_DOWN) {<br />
        $ball-&gt;acc_v(-5);</p>

<p>    } elsif ($type == SDL_KEYUP &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_DOWN) {<br />
        $ball-&gt;acc_v(0);</p>

<p>    } else {<br />
        return 0;<br />
    }<br />
    return 1;<br />
}</p>

<p>sub handle_frame {<br />
    my ($self, $oldtime, $now) = @_;</p>

<p>    my $frame_elapsed_time = ($now - $oldtime)/1000;</p>

<p>    my $ball = $self-&gt;ball;<br />
    my $collided = 0;<br />
    foreach my $wall (@{$self-&gt;walls}) {<br />
        if (my $coll = collide($ball, $wall, $frame_elapsed_time)) {<br />
            # need to place the ball in the result after the bounce given<br />
            # the time elapsed after the collision.<br />
            my $collision_remaining_time = $frame_elapsed_time - $coll-&gt;time;<br />
            my $movement_before_collision_h = $ball-&gt;vel_h * $coll-&gt;time;<br />
            my $movement_before_collision_v = $ball-&gt;vel_v * $coll-&gt;time;<br />
            my $movement_after_collision_h = $ball-&gt;vel_h * $collision_remaining_time;<br />
            my $movement_after_collision_v = $ball-&gt;vel_v * $collision_remaining_time;<br />
            if ($coll-&gt;axis eq 'x') {<br />
                $ball-&gt;cen_h(($ball-&gt;cen_h + $movement_before_collision_h) +<br />
                             ($movement_after_collision_h * -1));<br />
                $ball-&gt;cen_v($ball-&gt;cen_v +<br />
                             $movement_before_collision_v +<br />
                             $movement_after_collision_v);<br />
                $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
            } elsif ($coll-&gt;axis eq 'y') {<br />
                $ball-&gt;cen_v(($ball-&gt;cen_v + $movement_before_collision_v) +<br />
                             ($movement_after_collision_v * -1));<br />
                $ball-&gt;cen_h($ball-&gt;cen_h +<br />
                             $movement_before_collision_h +<br />
                             $movement_after_collision_h);<br />
                $ball-&gt;vel_v($ball-&gt;vel_v * -1);<br />
            } elsif (ref $coll-&gt;axis eq 'ARRAY') {<br />
                my ($xv, $yv) = @{$coll-&gt;bounce_vector};<br />
                $ball-&gt;cen_h(($ball-&gt;cen_h + $movement_before_collision_h) +<br />
                             ($xv * $collision_remaining_time));<br />
                $ball-&gt;vel_h($xv);<br />
                $ball-&gt;cen_v(($ball-&gt;cen_v + $movement_before_collision_v) +<br />
                             ($yv * $collision_remaining_time));<br />
                $ball-&gt;vel_v($yv);<br />
            } else {<br />
                warn 'BAD BALL!';<br />
                $ball-&gt;cen_h(($ball-&gt;cen_h + $movement_before_collision_h) +<br />
                             ($movement_after_collision_h * -1));<br />
                $ball-&gt;cen_v(($ball-&gt;cen_v + $movement_before_collision_v) +<br />
                             ($movement_after_collision_v * -1));<br />
                $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
                $ball-&gt;vel_v($ball-&gt;vel_v * -1);<br />
            }<br />
            $collided = 1;<br />
        }<br />
    }</p>

<p>    if (!$collided) {<br />
        $ball-&gt;time_lapse($oldtime, $now);<br />
    }</p>

<p>    foreach my $view (@{$self-&gt;views}) {<br />
        my $ret = $view-&gt;draw();<br />
    }</p>

<p>    SDL::Video::flip($self-&gt;main_surface-&gt;surface);</p>

<p>}</p>

<p>use Collision::2D ':all';<br />
sub collide {<br />
    my ($ball, $wall, $time) = @_;<br />
    my $rect = hash2rect({ x =&gt; $wall-&gt;pos_h, y =&gt; $wall-&gt;pos_v,<br />
                           h =&gt; $wall-&gt;height, w =&gt; $wall-&gt;width });<br />
    my $circ = hash2circle({ x =&gt; $ball-&gt;cen_h, y =&gt; $ball-&gt;cen_v,<br />
                             radius =&gt; $ball-&gt;radius,<br />
                             xv =&gt; $ball-&gt;vel_h,<br />
                             yv =&gt; $ball-&gt;vel_v });<br />
    return dynamic_collision($circ, $rect, interval =&gt; $time);<br />
}<br />
</PRE></p>

<p><P>And with all the reorganization, the main ball.pl code is now<br />
pretty simple:</P></p>

<p><PRE><br />
#!/usr/bin/perl</p>

<p>use 5.10.0;<br />
use strict;<br />
use warnings;</p>

<p>use SDL;<br />
use SDL::Event;<br />
use SDL::Events;</p>

<p>use lib 'lib';</p>

<p>use aliased 'BouncingBall::Controller::InGame';<br />
use aliased 'BouncingBall::View::MainSurface';</p>

<p>SDL::init( SDL_INIT_EVERYTHING );</p>

<p>my $fps = 60;</p>

<p>my $surf = MainSurface-&gt;new();</p>

<p>my $sevent = SDL::Event-&gt;new();<br />
my $time = SDL::get_ticks;</p>

<p>my $controller = InGame-&gt;new({ main_surface =&gt; $surf });</p>

<p>while (1) {<br />
    my $oldtime = $time;<br />
    my $now = SDL::get_ticks;</p>

<p>    while (SDL::Events::poll_event($sevent)) {<br />
        my $type = $sevent-&gt;type;<br />
        if ($type == SDL_QUIT) {<br />
            exit;<br />
        } elsif ($controller-&gt;handle_sdl_event($sevent)) {<br />
            # handled.<br />
        } else {<br />
            # unknown event.<br />
        }<br />
    }</p>

<p>    $controller-&gt;handle_frame($time, $now);</p>

<p>    $time = SDL::get_ticks;<br />
    SDL::delay(1000/$fps);<br />
}<br />
</PRE></p>

<p><H3>The case for the Camera!</H3></p>

<p><P>We started this post around the idea of making a camera, but we<br />
haven't done anything really interesting with it. So now I'm going to<br />
implement the really usefull part of all this thing we've done.</P></p>

<p><P>Currently the camera is being set as looking at the point the ball<br />
starts, but soon enough, the ball is going to get too close to the<br />
bottom border of the screen.</P></p>

<p><P>The idea is pretty simple, try to keep the ball inside a threshold<br />
margin by moving the camera when it gets too close of the border.</P></p>

<p><P>What makes this really simple is the fact that we just need to do<br />
two things:</P></p>

<p><OL><br />
  <LI>Add the camera as an observer of the ball.</LI><br />
  <LI>Implement the chasing logic in the rect_moved method</LI><br />
</OL></p>

<p><P>And that's all. Really. So here are all the code we need to make<br />
the camera chase the ball:</P></p>

<p><PRE><br />
# in the controller, we just need to add one line, after the camera<br />
# initialization.<br />
$self-&gt;ball-&gt;add_rect_moving_listener($camera);<br />
</PRE></p>

<p><P>And then we need to implement rect_moved on the camera:</P></p>

<p><PRE><br />
sub rect_moved {<br />
    my ($self, $ev) = @_;<br />
    # implement a loose following of the ball.  if the ball gets near<br />
    # the border of the screen, we follow it so it stays inside the<br />
    # desired area.</p>

<p>    my $lf_x = $self-&gt;pointing_x - ($self-&gt;width / 2);<br />
    my $br_lf_x = $lf_x + $self-&gt;width * 0.2;</p>

<p>    my $rt_x = $self-&gt;pointing_x + ($self-&gt;width / 2);<br />
    my $br_rt_x = $rt_x - $self-&gt;width * 0.2;</p>

<p>    my $up_y = $self-&gt;pointing_y + ($self-&gt;height / 2);<br />
    my $br_up_y = $up_y - $self-&gt;height * 0.2;</p>

<p>    my $dw_y = $self-&gt;pointing_y - ($self-&gt;height / 2);<br />
    my $br_dw_y = $dw_y + $self-&gt;height * 0.2;</p>

<p>    if ($ev-&gt;new_rect-&gt;x &lt; $br_lf_x) {<br />
        $self-&gt;pointing_x( $self-&gt;pointing_x - ($br_lf_x - $ev-&gt;new_rect-&gt;x))<br />
    } elsif ($ev-&gt;new_rect-&gt;x &gt; $br_rt_x) {<br />
        $self-&gt;pointing_x( $self-&gt;pointing_x + ($ev-&gt;new_rect-&gt;x - $br_rt_x));<br />
    }</p>

<p>    if ($ev-&gt;new_rect-&gt;y &lt; $br_dw_y) {<br />
        $self-&gt;pointing_y( $self-&gt;pointing_y - ($br_dw_y - $ev-&gt;new_rect-&gt;y))<br />
    } elsif ($ev-&gt;new_rect-&gt;y &gt; $br_up_y) {<br />
        $self-&gt;pointing_y( $self-&gt;pointing_y + ($ev-&gt;new_rect-&gt;y - $br_up_y));<br />
    }</p>

<p>    return 1;<br />
}<br />
</PRE></p>

<p><P>And that's all. That's the joy of a properly designed MVC<br />
architecture.</P></p>

<p><P>As usual, follows a small video of the game.</P></p>

<p><br />
<object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/BZWWfI0hTJc&amp;hl=pt_BR&amp;fs=1&amp;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/BZWWfI0hTJc&amp;hl=pt_BR&amp;fs=1&amp;" type="application/x-shockwave-flash" allowfullscreen="true" width="480" height="385"></embed></object></p>]]>
        
    </content>
</entry>

<entry>
    <title>Writing games in Perl - Part 3 - Collision detection</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/games-perl-3.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.161</id>

    <published>2010-03-21T02:03:50Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>Following posts 1 and 2 on the subject of writing games in Perl, now we are going to add colision. The idea is quite simple, we are going to add another square to the game, and when the ball hits...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sdl" label="sdl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="snippet" label="snippet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>Following<br />
posts <a href="http://daniel.ruoso.com/categoria/perl/games-perl-1">1</A><br />
and <a href="http://daniel.ruoso.com/categoria/perl/games-perl-2">2</A><br />
on the subject of writing games in Perl, now we are going to add<br />
colision.</P></p>

<p><P>The idea is quite simple, we are going to add another square to the<br />
game, and when the ball hits it, it will change direction. Following<br />
the way we were working, I'm going to add another object, called<br />
Wall.</P></p>

<p><P>The first thing is modelling our wall, which will be a rectangle,<br />
so it has the following attributes.</P></p>

<p><PRE><br />
package Wall;<br />
use Moose;<br />
use Util;<br />
use SDL::Rect;</p>

<p># Position - vertical and horizontal<br />
has pos_v =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0);<br />
has pos_h =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0.12);</p>

<p># Width and height<br />
has width =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0.005);<br />
has height =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0.4);<br />
</PRE></p>

<p><P>Unlike the ball, a wall doesn't move, so we don't need a time_lapse<br />
method, but we still have the get_rect and draw methods.</P></p>

<p><PRE><br />
sub get_rect {<br />
  my ($self, $height, $width) = @_;</p>

<p>  my $inverted_v = ($height - ($self-&gt;pos_v + $self-&gt;height));</p>

<p>  my $x = Util::m2px( $self-&gt;pos_h );<br />
  my $y = Util::m2px( $inverted_v );<br />
  my $h = Util::m2px( $self-&gt;height );<br />
  my $w = Util::m2px( $self-&gt;width );</p>

<p>  my $screen_w = Util::m2px( $width );<br />
  my $screen_h = Util::m2px( $height );</p>

<p>  if ($x  $screen_w) {<br />
    $w -= ($x + $w) - $screen_w;<br />
  }</p>

<p>  if ($y  $screen_h) {<br />
    $h -= ($y + $h) - $screen_h;<br />
  }</p>

<p>  return SDL::Rect-&gt;new( $x, $y, $w, $h );<br />
}</p>

<p>my $color;<br />
sub draw {<br />
  my ($self, $surface, $height, $width) = @_;<br />
  unless ($color) {<br />
    $color = SDL::Video::map_RGB<br />
      ( $surface-&gt;format(),<br />
        255, 0, 0 ); # red<br />
  }<br />
  SDL::Video::fill_rect<br />
      ( $surface,<br />
        $self-&gt;get_rect($height, $width),<br />
        $color );<br />
}<br />
</PRE></p>

<p><P>See<br />
the <a href="http://daniel.ruoso.com/categoria/perl/games-perl-1">first<br />
post</A> for more details on the get_rect and draw codes.</P></p>

<p><P>Now we need to add our wall to the game, that will mean a simple<br />
change in our main code, first we need to load the Wall module, then<br />
initialize the Wall just after initializing the ball, and finally<br />
calling the draw method just after calling the same method on<br />
ball.</P></p>

<p><PRE><br />
use Wall;<br />
</PRE></p>

<p><PRE><br />
my $wall = Wall-&gt;new;<br />
</PRE></p>

<p><PRE><br />
$wall-&gt;draw($app, $height, $width);<br />
</PRE></p>

<p><P>If you tried to run the code at this point, you'll notice you won't<br />
see any wall. That happens because the application is only updating<br />
the screen where the ball is passing. The Wall needs to be drawn a<br />
first time, and the screen needs to be updated at that position. This<br />
prevents us from re-updating the wall rect everytime, which is<br />
pointless, since the wall is static - that code goes right before the<br />
main loop.</P></p>

<p><PRE><br />
# let's draw the wall for the first time.<br />
$wall-&gt;draw($app, $height, $width);<br />
SDL::Video::update_rects<br />
  ( $app,<br />
    $wall-&gt;get_rect($height, $width) );<br />
</PRE></p>

<p><P>Now we need to check for a collision. This should happen in the<br />
place of the time_lapse call. Note that while I neglected math in the<br />
movement part, here it's more complicated because I need to react in a<br />
reasonable manner depending on how the collision happened. But as<br />
we're working in Perl and we have CPAN, I can just use Collision::2D<br />
(zpmorgan++ for working on this and pointing me in the correct<br />
direction)</P></p>

<p><P>If you don't have the Collision::2D module installed, just call</P></p>

<p><PRE><br />
# cpan Collision::2D<br />
</PRE></p>

<p><P>If you're not sure wether you have it or not, just try installing<br />
it anyway, it will suceed if the module is already installed.</P></p>

<p><PRE><br />
use Collision::2D ':all';<br />
sub collide {<br />
    my ($ball, $wall, $time) = @_;<br />
    my $rect = hash2rect({ x =&gt; $wall-&gt;pos_h, y =&gt; $wall-&gt;pos_v,<br />
                           h =&gt; $wall-&gt;height, w =&gt; $wall-&gt;width });<br />
    my $circ = hash2circle({ x =&gt; $ball-&gt;cen_h, y =&gt; $ball-&gt;cen_v,<br />
                             radius =&gt; $ball-&gt;radius,<br />
                             xv =&gt; $ball-&gt;vel_h,<br />
                             yv =&gt; $ball-&gt;vel_v });<br />
    return dynamic_collision($circ, $rect, interval =&gt; $time);<br />
}<br />
</PRE></p>

<p><P>I assumed an API that wasn't currently implemented in our Ball<br />
object, so I changed the ball so that pos_v, pos_h, width and height<br />
return the bounding dimensions for the ball I won't put the code in<br />
the post, but you can check at<br />
the <a href="http://github.com/ruoso/games-perl/">github repo</a>.</P></p>

<p><P>Okay, now it's time to check for collisions and act<br />
accordingly. Again, we'll assume an 100% efficient collision, so the<br />
code looks like:</P></p>

<p><PRE><br />
  my $frame_elapsed_time = ($now - $oldtime)/1000;<br />
  if (my $coll = Util::collide($ball, $wall, $frame_elapsed_time)) {<br />
      # need to place the ball in the result after the bounce given<br />
      # the time elapsed after the collision.<br />
      my $collision_remaining_time = $frame_elapsed_time - $coll-&gt;time;<br />
      my $movement_before_collision_h = $ball-&gt;vel_h * $coll-&gt;time;<br />
      my $movement_before_collision_v = $ball-&gt;vel_v * $coll-&gt;time;<br />
      my $movement_after_collision_h = $ball-&gt;vel_h * $collision_remaining_time;<br />
      my $movement_after_collision_v = $ball-&gt;vel_v * $collision_remaining_time;<br />
      if ($coll-&gt;axis eq 'x') {<br />
          $ball-&gt;cen_h(($ball-&gt;cen_h + $movement_before_collision_h) +<br />
                       ($movement_after_collision_h * -1));<br />
          $ball-&gt;cen_v($ball-&gt;cen_v +<br />
                       $movement_before_collision_v +<br />
                       $movement_after_collision_v);<br />
          $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
      } elsif ($coll-&gt;axis eq 'y') {<br />
          $ball-&gt;cen_v(($ball-&gt;cen_v + $movement_before_collision_v) +<br />
                       ($movement_after_collision_v * -1));<br />
          $ball-&gt;cen_h($ball-&gt;cen_h +<br />
                       $movement_before_collision_h +<br />
                       $movement_after_collision_h);<br />
          $ball-&gt;vel_v($ball-&gt;vel_v * -1);<br />
      } elsif (ref $coll-&gt;axis eq 'ARRAY') {<br />
          my ($xv, $yv) = @{$coll-&gt;bounce_vector};<br />
          $ball-&gt;cen_h(($ball-&gt;cen_h + $movement_before_collision_h) +<br />
                       ($xv * $collision_remaining_time));<br />
          $ball-&gt;vel_h($xv);<br />
          $ball-&gt;cen_v(($ball-&gt;cen_v + $movement_before_collision_v) +<br />
                       ($yv * $collision_remaining_time));<br />
          $ball-&gt;vel_v($yv);<br />
      } else {<br />
          warn 'BAD BALL!';<br />
          $ball-&gt;cen_h(($ball-&gt;cen_h + $movement_before_collision_h) +<br />
                       ($movement_after_collision_h * -1));<br />
          $ball-&gt;cen_v(($ball-&gt;cen_v + $movement_before_collision_v) +<br />
                       ($movement_after_collision_v * -1));<br />
          $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
          $ball-&gt;vel_v($ball-&gt;vel_v * -1);<br />
      }<br />
  } else {<br />
      $ball-&gt;time_lapse($oldtime, $now, $height, $width);<br />
  }<br />
</PRE></p>

<p><P>Okay, the above code was a bit complicated, let's brake it down...</p>

<p><PRE><br />
  my $frame_elapsed_time = ($now - $oldtime)/1000;<br />
</PRE></p>

<p><P>Collision::2D works with time in seconds, it calculates if the two<br />
objects would have collided during the duration of this frame.</P></p>

<p><PRE><br />
  if (my $coll = Util::collide($ball, $wall, $frame_elapsed_time)) {<br />
     ...<br />
  } else {<br />
      $ball-&gt;time_lapse($oldtime, $now, $height, $width);<br />
  }<br />
</PRE></p>

<p><P>Now we check if there was a collision. If not, we just proceed to<br />
the regular code that calculates the new position for the ball.</P></p>

<p><PRE><br />
      my $collision_remaining_time = $frame_elapsed_time - $coll-&gt;time;<br />
      my $movement_before_collision_h = $ball-&gt;vel_h * $coll-&gt;time;<br />
      my $movement_before_collision_v = $ball-&gt;vel_v * $coll-&gt;time;<br />
      my $movement_after_collision_h = $ball-&gt;vel_h * $collision_remaining_time;<br />
      my $movement_after_collision_v = $ball-&gt;vel_v * $collision_remaining_time;<br />
</PRE></p>

<p><P>In the case we have a collision, Collision::2D tells us when and<br />
how it happened. In order to implement the bouncing, I also calculate<br />
how far they would have been proceeded before and after the collision.</P></p>

<p><br />
<PRE><br />
      if ($coll-&gt;axis eq 'x') {<br />
          ...<br />
      } elsif ($coll-&gt;axis eq 'y') {<br />
          ...<br />
      } elsif (ref $coll-&gt;axis eq 'ARRAY') {<br />
          ...<br />
      } else {<br />
          ...<br />
      }<br />
</PRE></p>

<p><P>The method that describes how the collision happened is "axis". If<br />
it was a purely horizontal colision, it will return 'x', if it was<br />
purely vertical, it will return 'y', if it was mixed, it will return a<br />
vector that describes it. In the case of a bug, it will return undef.</P></p>

<p><PRE><br />
          $ball-&gt;cen_h(($ball-&gt;cen_h + $movement_before_collision_h) +<br />
                       ($movement_after_collision_h * -1));<br />
          $ball-&gt;cen_v($ball-&gt;cen_v +<br />
                       $movement_before_collision_v +<br />
                       $movement_after_collision_v);<br />
          $ball-&gt;vel_h($ball-&gt;vel_h * -1);<br />
</PRE></p>

<p><P>In the case of perfect horizontal or vertical collision (or bug),<br />
we reposition the ball by first calculating where it would be at the<br />
time of the collision and then bounce it away - depending on how the<br />
collision occurred.</P></p>

<p><PRE><br />
          my ($xv, $yv) = @{$coll-&gt;bounce_vector};<br />
          $ball-&gt;cen_h(($ball-&gt;cen_h + $movement_before_collision_h) +<br />
                       ($xv * $collision_remaining_time));<br />
          $ball-&gt;vel_h($xv);<br />
          $ball-&gt;cen_v(($ball-&gt;cen_v + $movement_before_collision_v) +<br />
                       ($yv * $collision_remaining_time));<br />
          $ball-&gt;vel_v($yv);<br />
</PRE></p>

<p><P>This last part of the code uses a cool feature for Collision::2D,<br />
which returns a bounce information for that collision, which we then<br />
use to figure out the correct position after the bounce.</p>

<p><P>And now we can run our code. I have made some other changes not<br />
explained here, because they are just settings that control the<br />
behavior. Remember to access<br />
the <a href="http://github.com/ruoso/games-perl/">github repo</a> for<br />
more details.</P></p>

<p><P>Now a small video of the game running.</P></p>

<p><object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/PcDe0dKOflA&amp;hl=pt_BR&amp;fs=1&amp;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/PcDe0dKOflA&amp;hl=pt_BR&amp;fs=1&amp;" type="application/x-shockwave-flash" allowfullscreen="true" width="480" height="385"></embed></object></p>]]>
        
    </content>
</entry>

<entry>
    <title>Introducing the Null CMS [Perl]</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/null-cms-1.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.162</id>

    <published>2010-03-15T15:02:10Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>I&apos;m working for some time in a concept on what I&apos;ve been calling Null CMS, which would be simply a content repository with metadata support and authorization. The interface would simply be a search and an edit screen. The data...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cms" label="cms" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>I'm working for some time in a concept on what I've been calling Null CMS, which would be simply a content repository with metadata support and authorization. The interface would simply be a search and an edit screen. The data would be stored in <a href="http://en.wikipedia.org/wiki/Plain_Old_Semantic_HTML">Plain Old Semantic HTML (POSH)</A>, tags and categorization would be made with HTML META tags, <a href="http://www.microformats.org">microformats</a> would also be used to allow structuring other types of data. Media files could be stored with an associated html file describing it.</P></p>

<p><P>In order to make it fast, I'd use KinoSearch to index all of that, including inexing known microformats and other patterns that could be defined in code. The other requisite for that is supporting UNIX-style permissions (ugo+rwx) so I could have three sets of indices - 1 for each user, 1 for each group and 1 for others.</P></p>

<p><P>In the end, this is going to be presented as a Catalyst Model, that will then be used to implement web sites in an easy and clean way - using a specialized cat front-end for sites is very straight forward, I had experience front-ending wordpress which, besides it's weird data modelling (and "weird" is putting it in a nice way), and it was pretty nice.</p>

<p><P>This could easily be solved with a XML database, such as Sedna, eXist or even bdbxml, but they require an extra level of control of the operating system that would make this project pointless (If I have this kind of control, I'd use Alfresco which already implements everything I need).</P></p>

<p><P>Conceptually, something as simple as storing everything in a tar file would solve it, but then we have concurrent access and it fails.</P></p>

<p><P>I was wondering about  KiokuDB, but I'd still need a storage for kinosearch indexes, maybe it's possible to create a store class for kinosearch that stores it in a relational database.</P></p>

<p><P>In summary, I need a solution that could be used in a regular cheap shared hosting (which probably means only MySQL).</P></p>

<p><P>The other alternative is using Amazon services, but that would make me too depedant on them - although it would probably be a minor problem, since it's all encapsulated in a model class...</P></p>

<p><P>I'd like to hear ideas on this topic... what do you think?</p>]]>
        
    </content>
</entry>

<entry>
    <title>Google AI Challenge in Perl</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/google-ai-challenge.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.163</id>

    <published>2010-02-14T00:18:29Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>I&apos;m usually not thrilled by competitions, but I must admit this one has taken me. I refer to the Google AI Challenge promoted by the University of Waterloo Computer Science Club. This is a simple bot competition where you play...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ai" label="ai" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="competition" label="competition" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>I'm usually not thrilled by competitions, but I must admit this one has taken me. I refer to the <A HREF="http://csclub.uwaterloo.ca/contest">Google AI Challenge</A> promoted by the University of Waterloo Computer Science Club. This is a simple bot competition where you play in a one-to-one tron game with another bot from the competition in one of a set of maps.</p>

<p>The deadline for bot submission is 26th february, but don't wait untill there. The example bots are nothing close to the competition bots... You can follow my status <a href="http://csclub.uwaterloo.ca/contest/profile.php?user_id=2601">here</a>.]]>
        
    </content>
</entry>

<entry>
    <title>Writing games in Perl - Part 2 - Controlling the Ball</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/games-perl-2.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.164</id>

    <published>2010-02-07T14:30:30Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>Following the first post on the subject of writing games in Perl, where we created a bouncing ball (I know, it is a rectangle, but I trust your imagination), this post is going to add something very important when dealing...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sdl" label="sdl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="snippet" label="snippet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>Following <a href="http://daniel.ruoso.com/categoria/perl/games-perl-1">the<br />
first post</A> on the subject of writing games in Perl, where we<br />
created a bouncing ball (I know, it is a rectangle, but I trust your<br />
imagination), this post is going to add something very important when<br />
dealing with games: input.</p>

<p><P><A href="http://silveiraneto.net">Silveira Neto</a> suggested that<br />
I should include more specific instructions on how to start the game<br />
(and maybe a video), so I recalled that I didn't mention that all the<br />
sources for this posts (including the text) is currently hosted at a<br />
<a href="http://github.com/ruoso/games-perl">github repository</a> (if<br />
you plan to contribute, please just ask me for commit permissions<br />
instead of forking the repo).</p>

<p><P>So if you want to run the codes posted here, you first need to:</p>

<p><PRE><br />
$ git clone http://github.com/ruoso/games-perl.git<br />
</PRE></p>

<p><P>You can check for updates by calling</p>

<p><PRE><br />
$ git pull origin master<br />
</PRE></p>

<p><P>from inside the games-perl directory. Each directory inside<br />
games-perl starts with the number of the post. The first post is<br />
inside the <TT>1-bouncing-ball</TT> directory and the second is in<br />
<TT>2-controlling</TT>. To run the the first code just get inside the<br />
first directory and call:</p>

<p><Pre><br />
$ perl ball.pl<br />
</Pre></p>

<p><P>The second example code is based on the first, so the script name<br />
is the same, so just get into the other directory and run the same<br />
line. If you get an error like:</p>

<p><PRE><br />
Can't locate SDL/Video.pm in @INC (@INC contains: /etc/perl<br />
/usr/local/lib/perl/5.10.0 /usr/local/share/perl/5.10.0 /usr/lib/perl5<br />
/usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10<br />
/usr/local/lib/site_perl .) at ball.pl line 8.<br />
</PRE></p>

<p><P>It means you probably don't have the newest SDL, take a look at<br />
the <a href="http://daniel.ruoso.com/categoria/perl/games-perl-1">first<br />
post</A> to see how to get the newest redesigned SDL.</p>

<h4>Controlling the Ball</h4>

<p><P>Enough for the introduction, let's get to the actual code. The<br />
first thing we need is understanding SDL Events. If you ever<br />
programmed GUI applications or even if you wrote some javascript you<br />
are aware of how an event framework looks like. SDL is no exception,<br />
you need to wait (or poll) for the events, and each event will contain<br />
the information you need to figure out what happened.</p>

<p><P>In our case, we want to apply additional acceleration to the ball<br />
whenever the arrow keys are pressed. But if we have an event-based<br />
system, the way to figure out which of those four keys is currently<br />
pressed is keeping a state mask and update it when you receive keydown<br />
and keyup events.</p>

<p><P>So what we're going to do is to manipulate the <TT>acc_h</TT><br />
and <TT>acc_v</TT> ball attributes depending on the keydown and keyup<br />
events. It might look complicated, but the only change we need is<br />
(this is inside ball.pl main loop):</p>

<p><PRE><br />
  while (SDL::Events::poll_event($event)) {<br />
    if ($event-&gt;type == SDL_QUIT) {<br />
      exit;</p>

<p>    } elsif ($type == SDL_KEYDOWN &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_LEFT) {<br />
      $ball-&gt;acc_h(-1);</p>

<p>    } elsif ($type == SDL_KEYUP &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_LEFT) {<br />
      $ball-&gt;acc_h(0);</p>

<p>    } elsif ($type == SDL_KEYDOWN &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_RIGHT) {<br />
      $ball-&gt;acc_h(1);</p>

<p>    } elsif ($type == SDL_KEYUP &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_RIGHT) {<br />
      $ball-&gt;acc_h(0);</p>

<p>    } elsif ($type == SDL_KEYDOWN &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_UP) {<br />
      $ball-&gt;acc_v(1);</p>

<p>    } elsif ($type == SDL_KEYUP &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_UP) {<br />
      $ball-&gt;acc_v(0);</p>

<p>    } elsif ($type == SDL_KEYDOWN &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_DOWN) {<br />
      $ball-&gt;acc_v(-1);</p>

<p>    } elsif ($type == SDL_KEYUP &amp;&amp;<br />
             $sevent-&gt;key_sym() == SDLK_DOWN) {<br />
      $ball-&gt;acc_v(0);</p>

<p>    }<br />
  }<br />
</PRE></p>

<p><P>So, this is it. Follows a small video of the game.<BR><BR></p>

<p><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/On8O7jJP_WI&amp;hl=pt_BR&amp;fs=1&amp;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/On8O7jJP_WI&amp;hl=pt_BR&amp;fs=1&amp;" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object></p>]]>
        
    </content>
</entry>

<entry>
    <title>Writing games in Perl - part 1 - Bouncing Ball</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/games-perl-1.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.165</id>

    <published>2010-02-01T16:54:20Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>I&apos;ve been saying I will write a lengthy description of my experiments with SDL in Perl for a while, today kthakore uploaded a SDL experimental version with all the code involved in this experiments. So I decided to start, but...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sdl" label="sdl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="snippet" label="snippet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>I've been saying I will write a lengthy description of my<br />
experiments with SDL in Perl for a while, today<br />
kthakore <a href="http://search.cpan.org/~kthakore/SDL-2.3_5/">uploaded<br />
a SDL experimental version</A> with all the code involved in this<br />
experiments. So I decided to start, but I decided to make it a serial<br />
post. I'm still unsure about how the format will look like for the<br />
rest of the posts, but I certainly would love any comment with ideas<br />
of where I should go next.</P></p>

<p><P>So at the first post, I'll try to make a very simple application:<br />
"bouncing ball". It is simply a ball bouncing in the screen, where the<br />
left and right cursors will accelerate them to each side.</p>

<h4>Starting the environment</h4>

<p>Well, at first you need version 2.3_5 or greater of the SDL
module <a href="http://search.cpan.org/~kthakore/SDL-2.3_5/">available
here</a>. Building the SDL perl binding will require the headers for
most of the sdl related libraries. If you're in a Debian machine (or
most debian-based distros) you can simply install the regular version
of the SDL perl bindings. You can also do:

<pre>
# apt-get build-dep libsdl-perl
</pre>

<p>This line requires you to have a deb-src line in your
/etc/apt/sources.list. Mine looks like:

<pre>
deb-src http://ftp.br.debian.org/debian lenny main
</pre>

<p>In the case you change your sources.list file, remember you need to
call apt-get update for it to get the new info.

<p><P>After that you can simply download SDL 2.3_5 from CPAN and follow<br />
the README instructions, which basically means (note that this version<br />
is experimental so you might notice some failing tests):</p>

<pre>
# perl Build.PL
# ./Build
# ./Build test
# ./Build install
</pre>

<p><P>You might setup a local::lib if you still want to run other<br />
applications that require the older and stable version of SDL (yes,<br />
there are a lot of API changes). I'm not a Windows user, but it has<br />
been reported that it works like charm when<br />
using <a href="http://www.strawberryperl.com">Strawberry Perl</a>.</p>

<p><P>If everything is fine, you should be able to get "2.35" when you<br />
do:</p>

<pre>
$ perl -MSDL -E 'say $SDL::VERSION'
</pre>

<p><P>You might always get into #sdl@irc.perl.org if you run into<br />
trouble.</p>

<h4>The way I write games</h4>

<p><P>Alright, before getting into the technicalities of how to write a<br />
game with SDL in Perl, let's think a bit on the mechanics of how a<br />
game works.</p>

<p>The first thing to realize is that a game needs to simulate some
universe, and that this universe needs to have some universal rules
like the physics you apply. For instance, it is very important that
you decide, from the beggining, if you're going to have gravity in
your game.

<p><P>The second thing to realize is that, even if we have the impression<br />
that the time is a continuum, time is actually a sequence of events,<br />
like the shutter of a camera in burst mode (okay, for the not<br />
interested in photography, think in stop motion). That basically<br />
means: in frame A the ball was at position 10,10 and in frame B it was<br />
at 20,30. There's no in-between, you don't have to worry about it. You<br />
might be wondering if a collision might be lost in that move, but the<br />
point is, if the machine can't evaluate enough frames per second as to<br />
avoid that, it probably wouldn't be able to evaluate a more<br />
ellaborated calculation of the tragetories to see if they would have<br />
collided.</p>

<p><P>This provides an important simplification on how to think your game<br />
model. In this first example I'm going to overlook the modelling for<br />
interaction with different objects, since we have just a bouncing<br />
ball.</p>

<p>One last thing before we go on. You might be tempted to use pixels
as your measuring unit, there's one important aspect to keep in
mind. A Pixel is an integer value, which means that you'll need to do
roundings for each frame. And if you need to store it as a integer
value, you're going to accumulate imprecision, which might lead to
weird effects, specially when the fps rate changes dramatically. My
suggestion is to stick with the good old international measuring
system and just use meters, a simple calculation can covert from/to
pixels.

<pre>
package Util;
use strict;
use warnings;
our $DPI = 96; # I think there's a sane way to fetch this value
sub m2px { int(((shift) * ($DPI / 0.0254)) + 0.5) }
sub px2m { (shift) / ($DPI / .0254) }
</pre>

<h4>Modelling the ball</h4>

<p><P>I think there probably isn't a better fit for Object Orientation<br />
than games, since you're actually dealing with simulated objects, and<br />
the most obvious choice is to use object orientation to work with<br />
it. So that's the attributes I can think right now to our object.</p>

<pre>
package Ball;
use Moose;

<p>use constant g =&gt; 1.5;<br />
use Util;<br />
use SDL::Rect;</p>

<p># how much space does it take<br />
has radius =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0.005);</p>

<p># Position - vertical and horizontal<br />
has pos_v =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0.1);<br />
has pos_h =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0.04);</p>

<p># Velocty - vertical and horizontal<br />
has vel_v =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0);<br />
has vel_h =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0);</p>

<p># Current acceleration - vertical and horizontal<br />
# gravity is added later<br />
has acc_v =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0);<br />
has acc_h =&gt; (is =&gt; 'rw', isa =&gt; 'Num', default =&gt; 0);<br />
</pre></p>

<p>With our virtual ball defined, we need to implement the simulation
of time. And again, we need to think that time is not a continuum, so
what we do is providing a "time_lapse" method that will recalculate
the attributes of our object according to the ammount of time past.

<pre>
sub time_lapse {
  my ($self, $old_time, $new_time, $height, $width) = @_;
  my $elapsed = ($new_time - $old_time)/1000; # convert to seconds...

<p>  # now simple mechanics...<br />
  $self-&gt;vel_h( $self-&gt;vel_h + $self-&gt;acc_h * $elapsed );<br />
  # and add gravity for vertical velocity.<br />
  $self-&gt;vel_v( $self-&gt;vel_v + ($self-&gt;acc_v - g) * $elapsed );</p>

<p>  # finally get the new position<br />
  $self-&gt;pos_v( $self-&gt;pos_v + $self-&gt;vel_v * $elapsed );<br />
  $self-&gt;pos_h( $self-&gt;pos_h + $self-&gt;vel_h * $elapsed );</p>

<p>  # this ball is supposed to bounce, so let's check $width and $height<br />
  # if we're out of bounds, we assume a 100% efficient bounce.<br />
  if ($self-&gt;pos_v pos_v($self-&gt;pos_v * -1);<br />
    $self-&gt;vel_v($self-&gt;vel_v * -1);<br />
  } elsif ($self-&gt;pos_v &gt; $height) {<br />
    $self-&gt;pos_v($height - ($self-&gt;pos_v - $height));<br />
    $self-&gt;vel_v($self-&gt;vel_v * -1);<br />
  }</p>

<p>  if ($self-&gt;pos_h pos_h($self-&gt;pos_h * -1);<br />
    $self-&gt;vel_h($self-&gt;vel_h * -1);<br />
  } elsif ($self-&gt;pos_h &gt; $width) {<br />
    $self-&gt;pos_h($width - ($self-&gt;pos_h - $width));<br />
    $self-&gt;vel_h($self-&gt;vel_h * -1);<br />
  }</p>

<p><br />
}<br />
</pre></p>

<h4>From the simulated universe to pixels</h4>

<p><P>You probably noticed that we haven't talked much about the game<br />
development per se, so let's start thinking about it</p>

<p>The first difference from the simulated universe and the actual
game is the coordinate system. In our universe the vertical position 0
is near the floor, but in the screen, the vertical position 0 is at
the top of the screen.

<p>The other difference, which I already mentioned, is that our
measures are in meters, and the screen is measured in pixels. The
SDL library provides an important class to interact with this issue,
the SDL::Rect.

<p><P>That way, we're going to have a method to return a rect - but we<br />
need to remember to only return a rect that is inside the expected<br />
bounds, otherwise SDL will throw an exception.</p>

<pre>
sub get_rect {
  my ($self, $height, $width) = @_;

<p>  my $inverted_v = $height - $self-&gt;pos_v;</p>

<p>  my $x = Util::m2px( $self-&gt;pos_h - $self-&gt;radius );<br />
  my $y = Util::m2px( $inverted_v - $self-&gt;radius );<br />
  my $h = Util::m2px( $self-&gt;radius * 2 );<br />
  my $w = Util::m2px( $self-&gt;radius * 2 );</p>

<p>  my $screen_w = Util::m2px( $width );<br />
  my $screen_h = Util::m2px( $height );</p>

<p>  if ($x  $screen_w) {<br />
    $w -= ($x + $w) - $screen_w;<br />
  }</p>

<p>  if ($y  $screen_h) {<br />
    $h -= ($y + $h) - $screen_h;<br />
  }</p>

<p>  return SDL::Rect-&gt;new( $x, $y, $w, $h );<br />
}<br />
</pre></p>

<h4>Painting</h4>

<p>The last part is actually drawing the ball, which involves painting
the ball in the correct place. In our first version, our ball will be
a square, since it's the most primitive drawing we have and I don't
want to get into that specifics.

<pre>
my $color;
sub draw {
  my ($self, $surface, $height, $width) = @_;
  unless ($color) {
    $color = SDL::Video::map_RGB
      ( $surface-&gt;format(),
        0, 0, 255 ); # blue
  }
  SDL::Video::fill_rect
      ( $surface,
        $self-&gt;get_rect($height, $width),
        $color );
}
</pre>

<p>Yeah, I know, it's an ugly ball, but it bounces... ;)

<h4>Putting the pieces together</h4>

<p><P>Now we just need the actual application to use our Ball. Note that<br />
the cycle is basically:</p>

<ul>
<li>Listen for events
<li>Evaluete the time_lapse
<li>Draw the background
<li>Draw the ball
<li>Update the parts of the screen that where changed
<li>Ask for a delay to keep the desired fps rate
</ul>

<p>Note that I could have asked for it to update the entire screen
instead of only the parts that were changed, but that particular
operation is actually the most expensive thing you can have in your
app, so we try to update as few parts of the screen as possible.

<pre>
#!/usr/bin/perl

<p>use 5.10.0;<br />
use strict;<br />
use warnings;</p>

<p>use SDL;<br />
use SDL::Video;<br />
use SDL::App;<br />
use SDL::Events;<br />
use SDL::Event;<br />
use SDL::Time;</p>

<p>use lib 'lib';<br />
use Util;<br />
use Ball;</p>

<p>my $ball = Ball-&gt;new;<br />
my $width = 0.2;<br />
my $height = 0.15;<br />
my $fps = 60;</p>

<p>my $app = SDL::App-&gt;new<br />
  ( -title =&gt; 'Bouncing Ball',<br />
    -width =&gt; Util::m2px($width),<br />
    -height =&gt; Util::m2px($height));</p>

<p>my $black = SDL::Video::map_RGB<br />
  ( $app-&gt;format(),<br />
    0, 0, 0 ); # black</p>

<p>my $event = SDL::Event-&gt;new();<br />
my $time = SDL::get_ticks;<br />
my $app_rect = SDL::Rect-&gt;new(0, 0, $app-&gt;w, $app-&gt;h);<br />
my $ball_rect = $ball-&gt;get_rect($height, $width);</p>

<p>while (1) {<br />
  my $oldtime = $time;<br />
  my $now = SDL::get_ticks;</p>

<p>  while (SDL::Events::poll_event($event)) {<br />
    exit if $event-&gt;type == SDL_QUIT;<br />
  }</p>

<p>  my $old_ball_rect = $ball_rect;</p>

<p>  $ball-&gt;time_lapse($oldtime, $now, $height, $width);</p>

<p>  $ball_rect = $ball-&gt;get_rect($height, $width);</p>

<p>  SDL::Video::fill_rect<br />
      ( $app,<br />
        $app_rect,<br />
        $black );</p>

<p>  $ball-&gt;draw($app, $height, $width);</p>

<p>  SDL::Video::update_rects<br />
      ( $app,<br />
        $old_ball_rect, $ball_rect );</p>

<p>  $time = SDL::get_ticks;<br />
  if (($time - $oldtime) &lt; (1000/$fps)) {<br />
    SDL::delay((1000/$fps) - ($time - $oldtime));<br />
  }<br />
}<br />
</pre></p>]]>
        
    </content>
</entry>

<entry>
    <title>My quest to SDL in Perl</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/sdl_perl_1.html.en" />
    <id>tag:daniel.ruoso.com,2010:/daniel_ruoso_in_english//6.166</id>

    <published>2010-01-08T13:17:46Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>I think this thing started when Silveira Neto posted his code snippet on Pygame animating the tile set he has been creating for a long time. I knew for a long time that Perl supported SDL and that Frozen Bubble...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sdl" label="sdl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="snippet" label="snippet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>I think this thing started when <a href="http://silveiraneto.net/2009/12/11/pygame-running-orcs/">Silveira Neto</a> posted his code snippet on Pygame animating the tile set he has been creating for a long time. I knew for a long time that Perl supported SDL and that Frozen Bubble is written in Perl, but I have never tried it myself.</p>

<p><P>Working with graphics wasn't new to me, back in the days I played with BASIC, I wrote a blackjack program with animated cards, some time later - already in Linux, I played a bit with vgalib. I've been also thinking for a while on the concept of how to evaluate the progress of time in a game environment.</p>

<p><P>If you join this with the fact that I now have a 1yo kid, it kinda urged me to writing something in SDL for him. The idea was quite simple, as he doesn't coordinate mouse and keyboard movement yet, the game would simply present random images and sounds as there was any event at all.</p>

<p><P>So I started by using a simple event loop for the SDL events, and a timer to evaluate the time lapse and draw the game. To my surprise, using the timer caused segfaults, because the timer callback runs in a different thread in SDL, but the binding didn't provide any support for it and all I got was kaboom.</p>

<p><P>I worked around this issue by using Event, a simple event library I already used some other places, to implement the timer. It worked like charm, as there was events in SDL, it was creating rects of random sizes and colors that would last for a random amount of time, fading to black.</p>

<p>Then I thought: Ok, now let's proceed to audio. To my surprise, the callbacks for procedural audio generation were simply missing - Frozen Bubble only plays pre-produced audio files - and my idea was to produce random audio (not noise, but sounds in random frequencies). This was the push I needed to get to the redesign branch in github and start porting the app to it.

<p><P>Lots of research later, with the help of kthakore++ and the tips from Nicholas++, we managed to have a working version of SDL based on threads and threads::shared. This was a very great moment. I must confess I always kept some envy from python people because of the - so I thought - better support for threads in Python. At some point in this path I found out that Python doesn't support threads at all, because they have a Global Interpreter Lock, which basically means that POE implements the same kind of scalability than Python (and it also explained why the people at ce.gov.br have so much trouble with zope scalability). So now not only we have a thread-enabled SDL binding, but it is *really* threaded, which means that the audio callback will really run at the same time as the timer callback , which will also run together with the event loop. And now I'm happy to know that Perl does have a better threading support than Python - yeah, I know envy is a bad thing, but... whatever...</p>

<p><P>After I finished <a href="http://github.com/ruoso/tecla">Tecla</a>, the app for my 1yo kid, I decided to play with Game::PerlInvaders, which I saw some time ago and I knew some things I could improve. The result is in the branch refact_ruoso at <a href="http://github.com/ruoso/Game-PerlInvaders/tree/refact_ruoso">github</a>.</p>

<p><P>I should make another post, with the details on how tecla and the rewrite of Game::PerlInvaders work, but that's it for now.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Analog ASCII Clock</title>
    <link rel="alternate" type="text/html" href="http://daniel.ruoso.com/categoria/perl/ascii-clock.html.en" />
    <id>tag:daniel.ruoso.com,2009:/daniel_ruoso_in_english//6.167</id>

    <published>2009-12-14T17:37:02Z</published>
    <updated>2010-07-01T19:42:23Z</updated>

    <summary>Today I started the day looking at this post that inspired me to write an ascii analog clock in Perl. Unlike the linked post, I didn&apos;t intend to golf, but rather writing a clean and readable code. Follows the code:...</summary>
    <author>
        <name>Daniel Ruoso</name>
        <uri>http://daniel.ruoso.com</uri>
    </author>
    
        <category term="Perl" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl5" label="perl5" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="snippet" label="snippet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://daniel.ruoso.com/">
        <![CDATA[<p><P>Today I started the day looking at <A HREF="http://www.perlmonks.org/?node_id=811919">this post</A> that inspired me to write an ascii analog clock in Perl.</p>

<p><P>Unlike the linked post, I didn't intend to golf, but rather writing a clean and readable code.</p>

<p><P>Follows the code:</p>

<p><PRE><br />
#!/usr/bin/perl</p>

<p># besides DateTime, the standard pragmas<br />
use 5.010;<br />
use strict;<br />
use warnings;<br />
use utf8;<br />
use DateTime;</p>

<p># initialize configuration variables<br />
my $width = 32;<br />
my $height = 32;<br />
my $mark_at = 15;<br />
my $length_m = 12;<br />
my $length_h = 8;<br />
my $length_s = 15;<br />
my $pi = 3.14159265;<br />
my $center_x = int(0.5 + ($width / 2));<br />
my $center_y = int(0.5 + ($height / 2));<br />
my $loop = 1;</p>

<p># clear the screen and position the cursor in the left top corner<br />
print "\x1b[0;0H\x1b[2J";</p>

<p># loop the rendering of the clock<br />
while ($loop &amp;&amp; sleep 1) {</p>

<p>  # create a matrix of the configured height and width with blanks<br />
  # I use two spaces because most console fonts have the height with<br />
  # twice the width<br />
 my $data = [map {[ map { '  ' } 1..$width ]} 1..$height];</p>

<p>  # get the date and time in the local time zone<br />
  my $now = DateTime-&gt;now(time_zone =&gt; 'local');<br />
  my $hour = $now-&gt;hour_12;<br />
  my $min = $now-&gt;minute;<br />
  my $sec = $now-&gt;second;</p>

<p>  # convert that to degrees for the hands of that clock<br />
  my $degree_m = ($min * 6) + 270;<br />
  my $degree_h = ($hour * 30) + 270;<br />
  my $degree_s = ($sec * 6) + 270;</p>

<p>  # see the place sub down there<br />
  # place the numbers 1 to 12 around the clock<br />
  place($data,($_ * 30) + 270,$mark_at,sprintf("%02d",$_)) for 1..12;</p>

<p>  # now the seconds hand<br />
  place($data,$degree_m, $_ , '&lt;&gt;') for 0..$length_m;<br />
  <br />
  # the hours hand<br />
  place($data,$degree_h, $_ , '::') for 0..$length_h;</p>

<p>  # the seconds hand<br />
  place($data,$degree_s, $_ , '..') for 0..$length_s;</p>

<p>  # mark the center o the clock<br />
  $data-&gt;[$center_y][$center_x] = 'OO';</p>

<p>  # position the cursor in the left top corner<br />
  print "\x1b[0;0H\n";<br />
  <br />
  # covert the matrix into a single string and print it<br />
  say join "\n", map { join '', @$_ } @$data;<br />
};</p>

<p># covert degrees and distance into X and Y coords using basic trigonometry<br />
sub vec2xy {<br />
  my ($deg, $len) = @_;<br />
  return $center_x + int(0.5 + ($len * cos($deg * ($pi/180)))),<br />
    $center_y + int(0.5 + ($len * sin($deg * ($pi/180))));<br />
}</p>

<p># place a string into some degree and distance<br />
sub place {<br />
  my ($data, $deg, $len, $txt) = @_;<br />
  my ($x,$y) = vec2xy($deg,$len);<br />
  $data-&gt;[$y][$x] = $txt;<br />
}<br />
</PRE></p>]]>
        
    </content>
</entry>

</feed>

