1 | /* |
2 | Copyright (C) 2002-2005, Jason Katz-Brown <jasonkb@mit.edu> |
3 | Copyright 2010 Stefan Majewsky <majewsky@gmx.net> |
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | */ |
19 | |
20 | #ifndef KOLF_CANVASITEM_H |
21 | #define KOLF_CANVASITEM_H |
22 | |
23 | #include "config.h" |
24 | #include "vector.h" |
25 | #include "tagaro/spriteobjectitem.h" |
26 | |
27 | #include <QGraphicsRectItem> |
28 | #include <KDebug> |
29 | class b2Body; |
30 | class b2World; |
31 | |
32 | class Ball; |
33 | class KConfigGroup; |
34 | class KolfGame; |
35 | |
36 | namespace Kolf |
37 | { |
38 | class EllipseShape; |
39 | class Overlay; |
40 | class Shape; |
41 | } |
42 | |
43 | enum RttiCodes { Rtti_NoCollision = 1001, Rtti_DontPlaceOn = 1002, Rtti_Putter = 1004 }; |
44 | |
45 | class CanvasItem |
46 | { |
47 | public: |
48 | CanvasItem(b2World* world); |
49 | virtual ~CanvasItem(); |
50 | ///load your settings from the KConfigGroup, which represents a course. |
51 | virtual void load(KConfigGroup *) {} |
52 | ///save your settings. |
53 | virtual void save(KConfigGroup *cfg); |
54 | ///called for information when shot started |
55 | virtual void shotStarted() {} |
56 | ///called when the edit mode has been changed. |
57 | virtual void editModeChanged(bool editing); |
58 | ///Returns whether all items of this type of item (based on data()) that are "colliding" (ie, in the same spot) with ball should get collision() called. |
59 | virtual bool terrainCollisions() const { return false; } |
60 | ///Returns a Config that can be used to configure this item by the user. The default implementation returns one that says 'No configuration options'. |
61 | virtual Config *config(QWidget *parent) { return new DefaultConfig(parent); } |
62 | ///Returns other items that should be moveable (besides this one of course). |
63 | virtual QList<QGraphicsItem *> moveableItems() const { return QList<QGraphicsItem *>(); } |
64 | |
65 | void setId(int newId) { m_id = newId; } |
66 | int curId() const { return m_id; } |
67 | |
68 | ///Play a sound (e.g. playSound("wall") plays kdedir/share/apps/kolf/sounds/wall.wav). Optionally, specify \a vol to be between 0-1, for no sound to full volume, respectively. |
69 | void playSound(const QString &file, double vol = 1); |
70 | |
71 | ///Called on ball's collision. Return if terrain collidingItems should be processed. |
72 | virtual bool collision(Ball *ball) { Q_UNUSED(ball) return false; } |
73 | |
74 | ///Reimplement if you want extra items to have access to the game object. playSound() relies on having this. |
75 | virtual void setGame(KolfGame *game) { this->game = game; } |
76 | |
77 | QString name() const { return m_name; } |
78 | void setName(const QString &newname) { m_name = newname; } |
79 | virtual void setSize(const QSizeF&) {} |
80 | |
81 | virtual void moveBy(double dx, double dy); |
82 | |
83 | //The following is needed temporarily while CanvasItem is not a QGraphicsItem by itself. |
84 | void setPosition(const QPointF& pos) { const QPointF diff = pos - getPosition(); moveBy(diff.x(), diff.y()); } |
85 | virtual QPointF getPosition() const = 0; |
86 | |
87 | enum ZBehavior { FixedZValue = 0, IsStrut = 1, IsRaisedByStrut = 2 }; |
88 | ///This specifies how the object is Z-ordered. |
89 | ///\li FixedZValue: No special behavior. |
90 | ///\li IsStrut: This item is a vertical strut. It raises certain |
91 | /// items when they move on top of it. Its zValue is \a zValueStep. |
92 | ///\li IsRaisedByStrut: This item can be raised by struts underneath |
93 | /// it. \a zValueStep is the amount by which the zValue is raised |
94 | /// then. (i.e. \a zValue is relative to the strut) |
95 | //TODO: account for overlapping struts |
96 | void setZBehavior(ZBehavior behavior, qreal zValue); |
97 | ///Struts are normally found by collision detection. This method |
98 | ///configures a static strut for this item (on a semantic basis; |
99 | ///e.g. the RectangleItem is the static strut for its walls). |
100 | void setStaticStrut(CanvasItem* citem); |
101 | void updateZ(QGraphicsItem* self); |
102 | void moveItemsOnStrut(const QPointF& posDiff); |
103 | static bool mayCollide(CanvasItem* citem1, CanvasItem* citem2); |
104 | protected: |
105 | friend class Kolf::Overlay; //for delivery of Kolf::Overlay::stateChanged signal |
106 | ///pointer to main KolfGame |
107 | KolfGame *game; |
108 | private: |
109 | QString m_name; |
110 | int m_id; |
111 | CanvasItem::ZBehavior m_zBehavior; |
112 | qreal m_zValue; |
113 | CanvasItem* m_strut; |
114 | CanvasItem* m_staticStrut; |
115 | QList<CanvasItem*> m_struttedItems; |
116 | |
117 | //AFTER THIS LINE follows what I have inserted during the refactoring |
118 | public: |
119 | enum SimulationFlag |
120 | { |
121 | CollisionFlag = 1 << 0, |
122 | KinematicSimulationFlag = 1 << 1, |
123 | DynamicSimulationFlag = 1 << 2 |
124 | }; |
125 | enum SimulationType |
126 | { |
127 | ///The object is immovable. |
128 | NoSimulation = 0, |
129 | ///The object is immovable, but other objects can interact with it. |
130 | CollisionSimulation = CollisionFlag, |
131 | ///The object moves according to its kinematic state. |
132 | KinematicSimulation = CollisionSimulation | KinematicSimulationFlag, |
133 | ///This object collides with the shapes of other objects, and forces |
134 | ///can act on it. |
135 | DynamicSimulation = KinematicSimulation | DynamicSimulationFlag |
136 | }; |
137 | |
138 | b2World* world() const; |
139 | QList<Kolf::Shape*> shapes() const { return m_shapes; } |
140 | Kolf::Overlay* overlay(bool createIfNecessary = true); |
141 | ///@return items inside this CanvasItem which shall only be shown when |
142 | ///the user toggles additional info. Hide these items by default! |
143 | virtual QList<QGraphicsItem*> infoItems() const { return QList<QGraphicsItem*>(); } |
144 | |
145 | ///This is the velocity used by the physics engine: In each time step, |
146 | ///the position of this canvas item changes by the value of this property. |
147 | QPointF velocity() const; |
148 | void setVelocity(const QPointF& velocity); |
149 | protected: |
150 | void addShape(Kolf::Shape* shape); |
151 | ///Configure how this object will participate in physical simulation. |
152 | void setSimulationType(CanvasItem::SimulationType type); |
153 | |
154 | friend class ::KolfGame; //for the following two methods |
155 | ///The physics engine calls this method to prepare the object for the following simulation step. Subclass implementations have to call the base implementation just before returning. |
156 | virtual void startSimulation(); |
157 | ///The physics engine calls this method after calculating the next frame, to let the objects update their representation. Subclass implementations have to call the base implementation before anything else. |
158 | virtual void endSimulation(); |
159 | |
160 | ///Creates the optimal overlay for this object. The implementation does not have to propagate its properties to the overlay, as the overlay is updated just after it has been created. |
161 | ///@warning Do not actually call this function from subclass implementations. Use overlay() instead. |
162 | virtual Kolf::Overlay* createOverlay() { return 0; } //TODO: make this pure virtual when all CanvasItems are QGraphicsItems and implement createOverlay() (and then disallow createOverlay() == 0) |
163 | ///This function should be called whenever the value of an object's property changes. This will most prominently cause the overlay to be updated (if it exists). |
164 | void propagateUpdate(); |
165 | private: |
166 | friend class Kolf::Shape; //for access to m_body |
167 | b2Body* m_body; |
168 | |
169 | Kolf::Overlay* m_overlay; |
170 | QList<Kolf::Shape*> m_shapes; |
171 | CanvasItem::SimulationType m_simulationType; |
172 | }; |
173 | |
174 | //WARNING: pos() is at center (not at top-left edge of bounding rect!) |
175 | class EllipticalCanvasItem : public Tagaro::SpriteObjectItem, public CanvasItem |
176 | { |
177 | public: |
178 | EllipticalCanvasItem(bool withEllipse, const QString& spriteKey, QGraphicsItem* parent, b2World* world); |
179 | QGraphicsEllipseItem* ellipseItem() const { return m_ellipseItem; } |
180 | |
181 | virtual bool contains(const QPointF& point) const; |
182 | virtual QPainterPath shape() const; |
183 | |
184 | QRectF rect() const; |
185 | double width() const { return Tagaro::SpriteObjectItem::size().width(); } |
186 | double height() const { return Tagaro::SpriteObjectItem::size().height(); } |
187 | |
188 | virtual void setSize(const QSizeF& size); |
189 | void setSize(qreal width, qreal height) { setSize(QSizeF(width, height)); } |
190 | virtual void moveBy(double x, double y); |
191 | |
192 | void saveSize(KConfigGroup* group); |
193 | void loadSize(KConfigGroup* group); |
194 | |
195 | virtual QPointF getPosition() const { return QGraphicsItem::pos(); } |
196 | private: |
197 | QGraphicsEllipseItem* m_ellipseItem; |
198 | Kolf::EllipseShape* m_shape; |
199 | }; |
200 | |
201 | class ArrowItem : public QGraphicsPathItem |
202 | { |
203 | public: |
204 | ArrowItem(QGraphicsItem* parent); |
205 | |
206 | qreal angle() const; |
207 | void setAngle(qreal angle); |
208 | qreal length() const; |
209 | void setLength(qreal length); |
210 | bool isReversed() const; |
211 | void setReversed(bool reversed); |
212 | |
213 | Vector vector() const; |
214 | private: |
215 | void updatePath(); |
216 | qreal m_angle, m_length; |
217 | bool m_reversed; |
218 | }; |
219 | |
220 | #endif |
221 | |