00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 #include <math.h>
00021 #include "colors.hxx"
00022 #include "particle_factory.hxx"
00023 #include "controller.hxx"
00024 #include "rect_collider.hxx"
00025 #include "construo_error.hxx"
00026 
00027 Collider*
00028 RectCollider::duplicate() const
00029 {
00030   return new RectCollider(x1, y1, x2, y2);
00031 }
00032 
00033 RectCollider::RectCollider (lisp_object_t* cursor)
00034 {
00035   Vector2d pos1, pos2;
00036   
00037   LispReader reader(cursor);
00038   if (reader.read_vector("pos1", &pos1) == false
00039       || reader.read_vector("pos2", &pos2) == false)
00040     {
00041       throw ConstruoError("RectCollider entry incomplete");
00042     }
00043 
00044   x1 = pos1.x;
00045   y1 = pos1.y;
00046   x2 = pos2.x;
00047   y2 = pos2.y;
00048 }
00049 
00050 RectCollider::RectCollider (float x1_, float y1_, float x2_, float y2_)
00051   : x1 (x1_), y1 (y1_), x2 (x2_), y2 (y2_)
00052 {
00053 }
00054 
00055 bool
00056 RectCollider::is_at (const Vector2d& pos)
00057 {
00058   return (x1 <= pos.x && x2 > pos.x
00059           && y1 <= pos.y && y2 > pos.y);
00060 }
00061 
00062 Vector2d
00063 RectCollider::get_pos()
00064 {
00065   return Vector2d ((x1 + x2)/2.0f,
00066                    (y1 + y2)/2.0f); 
00067 }
00068 
00069 void
00070 RectCollider::set_pos(const Vector2d& pos)
00071 {
00072   Vector2d center = get_pos();
00073   x1 = x1 - center.x + pos.x;
00074   x2 = x2 - center.x + pos.x;
00075   y1 = y1 - center.y + pos.y;
00076   y2 = y2 - center.y + pos.y;
00077 }
00078 
00079 void
00080 RectCollider::bounce ()
00081 {
00082   ParticleFactory* particle_mgr = Controller::instance()->get_world()->get_particle_mgr();
00083 
00084   float damp = 0.8;
00085   for (ParticleFactory::ParticleIter i = particle_mgr->begin(); i != particle_mgr->end (); ++i)
00086     {
00087       Vector2d& pos = (*i)->pos;
00088       Vector2d& velocity = (*i)->velocity;
00089 
00090       if (pos.x > x1 && pos.x < x2
00091           && pos.y > y1 && pos.y < y2)
00092         {
00093           float left_dist  = pos.x - x1;
00094           float right_dist = x2 - pos.x;
00095 
00096           float top_dist    = pos.y - y1;
00097           float bottom_dist = y2 - pos.y;
00098 
00099           if (left_dist < right_dist
00100               && left_dist < top_dist 
00101               && left_dist < bottom_dist)
00102             {
00103               velocity.x = -fabs(velocity.x);
00104               pos.x = x1;
00105             }
00106           else if (right_dist < left_dist
00107                    && right_dist < top_dist 
00108                    && right_dist < bottom_dist)
00109             {
00110               velocity.x = fabs(velocity.x);
00111               pos.x = x2;
00112             }
00113           else if (top_dist < left_dist
00114                    && top_dist < right_dist
00115                    && top_dist < bottom_dist)
00116             {
00117               velocity.y = -fabs(velocity.y);
00118               pos.y = y1;
00119             }
00120           else
00121             {
00122               velocity.y = fabs(velocity.y);
00123               pos.y = y2;
00124             }
00125           velocity *= damp;
00126         }
00127     }
00128 }
00129 
00130 void
00131 RectCollider::draw (GraphicContext* gc)
00132 {
00133   
00134   gc->draw_fill_rect (x1, y1, x2, y2, Colors::rect_collider_bg);
00135   gc->draw_rect (x1, y1, x2, y2, Colors::rect_collider_fg);
00136 }
00137 
00138 void
00139 RectCollider::draw_highlight (GraphicContext* gc)
00140 {
00141   
00142   gc->draw_rect (x1, y1, x2, y2, Colors::selection_rect);
00143 }
00144 
00145 lisp_object_t*
00146 RectCollider::serialize()
00147 {
00148   LispWriter obj ("rect");
00149   obj.write_vector ("pos1", Vector2d(x1, y1));
00150   obj.write_vector ("pos2", Vector2d(x2, y2));
00151   return obj.create_lisp ();
00152 }
00153 
00154