1 /****************************************************************************** 2 * Warmux is a convivial mass murder game. 3 * Copyright (C) 2001-2011 Warmux Team. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 18 ****************************************************************************** 19 * Abstract class used for physical object (object with a size, mass, 20 * etc.). This object can have differents state : ready, is moving, or ghost 21 * (is outside of the world). 22 * 23 * You can : make the object move (with collision test), change state, etc. 24 * If the object go outside of the world, it become a ghost. 25 *****************************************************************************/ 26 27 #ifndef PHYSICAL_OBJECT_H 28 #define PHYSICAL_OBJECT_H 29 30 #include "physics.h" 31 #include <WARMUX_point.h> 32 #include <WARMUX_rectangle.h> 33 34 // Alive state 35 typedef enum 36 { 37 ALIVE, 38 DEAD, 39 GHOST, 40 DROWNED 41 } alive_t; 42 43 // Forward declaration 44 class Action; 45 class Character; 46 47 #define PIXEL_PER_METER 40 48 static const Double METER_PER_PIXEL(1.0/PIXEL_PER_METER); 49 50 class PhysicalObj : public Physics 51 { 52 // collision management 53 bool m_collides_with_ground; 54 bool m_collides_with_characters; 55 bool m_collides_with_objects; 56 // Special meaning, SignalObjectCollision is called but trajectory continues 57 // until out of map 58 bool m_go_through_objects; 59 PhysicalObj *m_last_collided_object; 60 61 Point2i m_rebound_position; 62 63 // Rectangle used for collision tests 64 int m_test_left, m_test_right, m_test_top, m_test_bottom; 65 66 // Object size and position. 67 int m_width, m_height; 68 69 bool can_be_ghost; 70 71 protected: 72 PhysicalObj* m_overlapping_object; 73 uint m_minimum_overlapse_time; 74 bool m_ignore_movements; 75 bool m_is_character; 76 bool m_is_fire; 77 78 virtual void CheckOverlapping(); 79 80 std::string m_name; 81 std::string m_unique_id; 82 83 std::string m_rebound_sound; 84 85 alive_t m_alive; 86 int m_energy; 87 88 bool m_allow_negative_y; 89 StartMoving()90 void StartMoving() 91 { 92 m_last_collided_object = NULL; 93 Physics::StartMoving(); 94 } 95 96 public: 97 PhysicalObj(const std::string &name, const std::string &xml_config=""); 98 /* Note : The copy constructor is not implemented (and this is not a bug) 99 * because we can copy directly the pointer m_overlapping_object whereas this 100 * object does not own it. 101 * FIXME what happen if the object is deleted meanwhile ???*/ 102 virtual ~PhysicalObj(); 103 104 //-------- Set position and size ------- 105 CanBeGhost(bool state)106 void CanBeGhost(bool state) { can_be_ghost = state; } 107 108 // Set/Get position - notice how we don't introduce rounding of the other coordinate SetX(Double x)109 void SetX(Double x) { SetXY( Point2d(x, GetPhysY() * PIXEL_PER_METER) ); }; SetY(Double y)110 void SetY(Double y) { SetXY( Point2d(GetPhysX() * PIXEL_PER_METER, y) ); }; SetXY(const Point2i & position)111 void SetXY(const Point2i &position) { SetXY(Point2d(position.x, position.y)); }; 112 void SetXY(const Point2d &position); 113 // GetX/GetY use a hack assuming the coordinates are always positive! GetX()114 int GetX() const { return uround(GetPhysX() * PIXEL_PER_METER); }; GetY()115 int GetY() const { return uround(GetPhysY() * PIXEL_PER_METER); }; 116 // Get{X,Y} used to depend on Get{X,Y}Double, but this seems unnecessary Double roundtrips GetXDouble()117 Double GetXDouble() const { return GetX(); }; GetYDouble()118 Double GetYDouble() const { return GetY(); }; GetPosition()119 const Point2d GetPosition() const { return Point2d(GetXDouble(), GetYDouble()) ;}; 120 121 // Set/Get size 122 void SetSize(const Point2i &newSize); GetWidth()123 int GetWidth() const { return m_width; }; GetHeight()124 int GetHeight() const { return m_height; }; GetSize()125 Point2i GetSize() const { return Point2i(m_width, m_height); }; 126 127 // Set/Get test rectangles 128 void SetTestRect (uint left, uint right, uint top, uint bottom); 129 // Optimized intersection test 130 inline bool Intersect(const Rectanglei & position) const; GetTestRect()131 const Rectanglei GetTestRect() const 132 { 133 int width = m_width - m_test_right - m_test_left; 134 int height = m_height - m_test_bottom - m_test_top; 135 width = width ? width : 1; 136 height = height ? height : 1; 137 return Rectanglei(GetX() + m_test_left, GetY() + m_test_top, width, height); 138 } GetTestWidth()139 int GetTestWidth() const { return m_width -m_test_left -m_test_right; }; GetTestHeight()140 int GetTestHeight() const { return m_height -m_test_top -m_test_bottom; }; 141 142 //----------- Access to datas (read only) ---------- GetName()143 virtual const std::string &GetName() const { return m_name; } 144 GetUniqueId()145 const std::string &GetUniqueId() const { return m_unique_id; } SetUniqueId(const std::string & s)146 void SetUniqueId(const std::string& s) { m_unique_id = s; } 147 GetCenterX()148 int GetCenterX() const { return GetX() +m_test_left +GetTestWidth()/2; }; GetCenterY()149 int GetCenterY() const { return GetY() +m_test_top +GetTestHeight()/2; }; GetCenter()150 const Point2i GetCenter() const { return Point2i(GetCenterX(), GetCenterY()); }; GetRect()151 const Rectanglei GetRect() const { return Rectanglei( GetX(), GetY(), m_width, m_height); }; CollidesWithGround()152 bool CollidesWithGround() const { return m_collides_with_ground; } 153 // This is a hack CanBeBlasted()154 bool CanBeBlasted() const { return m_collides_with_ground && !m_go_through_objects; } IsCharacter()155 bool IsCharacter() const { return m_is_character; } 156 157 //----------- Physics related function ---------- 158 159 // Update position (and state) with current time 160 void UpdatePosition(); 161 162 // Move the character until he gets out of the ground 163 bool PutOutOfGround(); 164 165 // Where direction is the angle of the direction where the object is moved 166 // and max_distance is max distance allowed when putting out 167 bool PutOutOfGround(Double direction, Double max_distance=30); 168 169 // Collision management 170 void SetCollisionModel(bool collides_with_ground, 171 bool collides_with_characters, 172 bool collides_with_objects, 173 bool go_through_objects = false); 174 void SetOverlappingObject(PhysicalObj* obj, int timeout = 0); GetOverlappingObject()175 const PhysicalObj* GetOverlappingObject() const { return m_overlapping_object; }; IsOverlapping(const PhysicalObj * obj)176 virtual bool IsOverlapping(const PhysicalObj* obj) const { return m_overlapping_object == obj; }; 177 178 bool IsInVacuumXY(const Point2i &position, bool check_objects = true) const; 179 // Relative to current position 180 bool IsInVacuum(const Point2i &offset, bool check_objects = true) const { return IsInVacuumXY(GetPosition() + offset, check_objects); }; 181 PhysicalObj* CollidedObjectXY(const Point2i & position) const; 182 // Relative to current position 183 PhysicalObj* CollidedObject(const Point2i & offset = Point2i(0,0)) const { return CollidedObjectXY(GetPosition() + offset); }; 184 bool FootsInVacuumXY(const Point2i & position) const; FootsInVacuum()185 bool FootsInVacuum() const { return FootsInVacuumXY(GetPosition()); }; 186 187 bool IsInWater() const; 188 189 // The object is outside of the world 190 bool IsOutsideWorldXY(const Point2i& position) const; 191 // Relative to current position 192 bool IsOutsideWorld(const Point2i &offset = Point2i(0,0)) const { return IsOutsideWorldXY( GetPosition() + offset ); }; 193 194 // Refresh datas 195 virtual void Refresh() = 0; 196 197 // Draw the object 198 virtual void Draw() = 0; 199 200 // Damage handling 201 virtual void SetEnergyDelta(int delta, Character* dealer); 202 203 //-------- state ---- 204 void Init(); 205 void Ghost(); 206 void Drown(); 207 void GoOutOfWater(); // usefull for supertux. 208 IsImmobile()209 virtual bool IsImmobile() const { return IsSleeping() || m_ignore_movements ||(!IsMoving() && !FootsInVacuum())||(m_alive == GHOST); }; 210 IsGhost()211 bool IsGhost() const { return m_alive == GHOST; }; IsDrowned()212 bool IsDrowned() const { return m_alive == DROWNED; }; IsDead()213 bool IsDead() const { return IsGhost() || IsDrowned() || m_alive==DEAD; }; IsFire()214 bool IsFire() const { return m_is_fire; } 215 216 // Are the two object in contact ? (uses test rectangles) Overlapse(const PhysicalObj & b)217 bool Overlapse(const PhysicalObj &b) const { return GetTestRect().Intersect( b.GetTestRect() ); }; 218 219 // Do the point p touch the object ? Contain(const Point2i & p)220 bool Contain(const Point2i &p) const { return GetTestRect().Contains( p ); }; 221 222 bool PutRandomly(bool on_top_of_world, Double min_dst_with_characters, bool net_sync = true); 223 224 collision_t NotifyMove(Point2d oldPos, Point2d newPos); 225 226 protected: 227 virtual void SignalRebound(); SignalGroundCollision(const Point2d &,const Double &)228 virtual void SignalGroundCollision(const Point2d& /* my_speed_before */, const Double& /*contactAngle*/) { }; SignalObjectCollision(const Point2d &,PhysicalObj *,const Point2d &)229 virtual void SignalObjectCollision(const Point2d& /* my_speed_before */, 230 PhysicalObj * /* collided/ing object */, 231 const Point2d& /* object speed_before */) { }; SignalOutOfMap()232 virtual void SignalOutOfMap() { }; 233 234 private: 235 //Retrun the position of the point of contact of the obj on the ground 236 bool ContactPoint(int &x, int &y) const; 237 238 239 // The object fall directly to the ground (or become a ghost) 240 void DirectFall(); 241 242 // Directly after a rebound, if we are stuck in a wall, we stop moving 243 void CheckRebound(); 244 245 void Collide(collision_t collision, PhysicalObj* collided_obj, const Point2d& position); 246 247 void ContactPointAngleOnGround(const Point2d& oldPos, 248 Point2d& contactPos, 249 Double& contactAngle) const; 250 }; 251 252 #endif 253