1 //  Construo - A wire-frame construction gamee
2 //  Copyright (C) 2002 Ingo Ruhnke <grumbel@gmx.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 #include <math.h>
18 #include "colors.hpp"
19 #include "particle_factory.hpp"
20 #include "controller.hpp"
21 #include "rect_collider.hpp"
22 #include "construo_error.hpp"
23 
24 Collider*
duplicate() const25 RectCollider::duplicate() const
26 {
27   return new RectCollider(x1, y1, x2, y2);
28 }
29 
RectCollider(lisp_object_t * cursor)30 RectCollider::RectCollider (lisp_object_t* cursor)
31 {
32   Vector2d pos1, pos2;
33 
34   LispReader reader(cursor);
35   if (reader.read_vector("pos1", &pos1) == false
36       || reader.read_vector("pos2", &pos2) == false)
37     {
38       throw ConstruoError("RectCollider entry incomplete");
39     }
40 
41   x1 = pos1.x;
42   y1 = pos1.y;
43   x2 = pos2.x;
44   y2 = pos2.y;
45 }
46 
RectCollider(float x1_,float y1_,float x2_,float y2_)47 RectCollider::RectCollider (float x1_, float y1_, float x2_, float y2_)
48   : x1 (Math::min(x1_, x2_)),
49     y1 (Math::min(y1_, y2_)),
50     x2 (Math::max(x1_, x2_)),
51     y2 (Math::max(y1_, y2_))
52 {
53 }
54 
55 bool
is_at(const Vector2d & pos)56 RectCollider::is_at (const Vector2d& pos)
57 {
58   return (x1 <= pos.x && x2 > pos.x
59           && y1 <= pos.y && y2 > pos.y);
60 }
61 
62 Vector2d
get_pos()63 RectCollider::get_pos()
64 {
65   return Vector2d ((x1 + x2)/2.0f,
66                    (y1 + y2)/2.0f);
67 }
68 
69 void
set_pos(const Vector2d & pos)70 RectCollider::set_pos(const Vector2d& pos)
71 {
72   Vector2d center = get_pos();
73   x1 = x1 - center.x + pos.x;
74   x2 = x2 - center.x + pos.x;
75   y1 = y1 - center.y + pos.y;
76   y2 = y2 - center.y + pos.y;
77 }
78 
79 void
bounce()80 RectCollider::bounce ()
81 {
82   ParticleFactory* particle_mgr = Controller::instance()->get_world()->get_particle_mgr();
83 
84   float damp = 0.8;
85   for (ParticleFactory::ParticleIter i = particle_mgr->begin(); i != particle_mgr->end (); ++i)
86     {
87       Vector2d& pos = (*i)->pos;
88       Vector2d& velocity = (*i)->velocity;
89 
90       if (pos.x > x1 && pos.x < x2
91           && pos.y > y1 && pos.y < y2)
92         {
93           float left_dist  = pos.x - x1;
94           float right_dist = x2 - pos.x;
95 
96           float top_dist    = pos.y - y1;
97           float bottom_dist = y2 - pos.y;
98 
99           if (left_dist < right_dist
100               && left_dist < top_dist
101               && left_dist < bottom_dist)
102             {
103               velocity.x = -fabs(velocity.x);
104               pos.x = x1;
105             }
106           else if (right_dist < left_dist
107                    && right_dist < top_dist
108                    && right_dist < bottom_dist)
109             {
110               velocity.x = fabs(velocity.x);
111               pos.x = x2;
112             }
113           else if (top_dist < left_dist
114                    && top_dist < right_dist
115                    && top_dist < bottom_dist)
116             {
117               velocity.y = -fabs(velocity.y);
118               pos.y = y1;
119             }
120           else
121             {
122               velocity.y = fabs(velocity.y);
123               pos.y = y2;
124             }
125           velocity *= damp;
126         }
127     }
128 }
129 
130 void
draw(GraphicContext * gc)131 RectCollider::draw (GraphicContext* gc)
132 {
133   //std::cout << "Drawing collider" << std::endl;
134   gc->draw_fill_rect (x1, y1, x2, y2, Colors::rect_collider_bg);
135   gc->draw_rect (x1, y1, x2, y2, Colors::rect_collider_fg);
136 }
137 
138 void
draw_highlight(GraphicContext * gc)139 RectCollider::draw_highlight (GraphicContext* gc)
140 {
141   //gc->draw_fill_rect (x1, y1, x2, y2, Colors::rect_collider_bg);
142   gc->draw_rect (x1, y1, x2, y2, Colors::selection_rect);
143 }
144 
145 BoundingBox
get_bounding_box() const146 RectCollider::get_bounding_box() const
147 {
148   return BoundingBox(x1, y1, x2, y2);
149 }
150 
151 lisp_object_t*
serialize()152 RectCollider::serialize()
153 {
154   LispWriter obj ("rect");
155   obj.write_vector ("pos1", Vector2d(x1, y1));
156   obj.write_vector ("pos2", Vector2d(x2, y2));
157   return obj.create_lisp ();
158 }
159 
160 /* EOF */
161