File indexing completed on 2025-02-02 07:28:21
0001 /* 0002 Copyright (C) 2002-2005, Jason Katz-Brown <jasonkb@mit.edu> 0003 Copyright 2010 Stefan Majewsky <majewsky@gmx.net> 0004 0005 This program is free software; you can redistribute it and/or modify 0006 it under the terms of the GNU General Public License as published by 0007 the Free Software Foundation; either version 2 of the License, or 0008 (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 GNU General Public License for more details. 0014 0015 You should have received a copy of the GNU General Public License 0016 along with this program; if not, write to the Free Software 0017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0018 */ 0019 0020 #ifndef KOLF_CANVASITEM_H 0021 #define KOLF_CANVASITEM_H 0022 0023 #include <config.h> 0024 #include "vector.h" 0025 #include "tagaro/spriteobjectitem.h" 0026 0027 #include <QGraphicsRectItem> 0028 0029 class b2Body; 0030 class b2World; 0031 0032 class Ball; 0033 class KConfigGroup; 0034 class KolfGame; 0035 0036 namespace Kolf 0037 { 0038 class EllipseShape; 0039 class Overlay; 0040 class Shape; 0041 } 0042 0043 enum RttiCodes { Rtti_NoCollision = 1001, Rtti_DontPlaceOn = 1002, Rtti_Putter = 1004 }; 0044 0045 class CanvasItem 0046 { 0047 public: 0048 explicit CanvasItem(b2World* world); 0049 virtual ~CanvasItem(); 0050 ///load your settings from the KConfigGroup, which represents a course. 0051 virtual void load(KConfigGroup *) {} 0052 ///save your settings. 0053 virtual void save(KConfigGroup *cfg); 0054 ///called for information when shot started 0055 virtual void shotStarted() {} 0056 ///called when the edit mode has been changed. 0057 virtual void editModeChanged(bool editing); 0058 ///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. 0059 virtual bool terrainCollisions() const { return false; } 0060 ///Returns a Config that can be used to configure this item by the user. The default implementation returns one that says 'No configuration options'. 0061 virtual Config *config(QWidget *parent) { return new DefaultConfig(parent); } 0062 ///Returns other items that should be movable (besides this one of course). 0063 virtual QList<QGraphicsItem *> moveableItems() const { return QList<QGraphicsItem *>(); } 0064 0065 void setId(int newId) { m_id = newId; } 0066 int curId() const { return m_id; } 0067 0068 ///Called on ball's collision. Return if terrain collidingItems should be processed. 0069 virtual bool collision(Ball *ball) { Q_UNUSED(ball) return false; } 0070 0071 ///Reimplement if you want extra items to have access to the game object. 0072 virtual void setGame(KolfGame *game) { this->game = game; } 0073 0074 QString name() const { return m_name; } 0075 void setName(const QString &newname) { m_name = newname; } 0076 virtual void setSize(const QSizeF&) {} 0077 0078 virtual void moveBy(double dx, double dy); 0079 0080 //The following is needed temporarily while CanvasItem is not a QGraphicsItem by itself. 0081 void setPosition(const QPointF& pos) { const QPointF diff = pos - getPosition(); moveBy(diff.x(), diff.y()); } 0082 virtual QPointF getPosition() const = 0; 0083 0084 enum ZBehavior { FixedZValue = 0, IsStrut = 1, IsRaisedByStrut = 2 }; 0085 ///This specifies how the object is Z-ordered. 0086 ///\li FixedZValue: No special behavior. 0087 ///\li IsStrut: This item is a vertical strut. It raises certain 0088 /// items when they move on top of it. Its zValue is \a zValueStep. 0089 ///\li IsRaisedByStrut: This item can be raised by struts underneath 0090 /// it. \a zValueStep is the amount by which the zValue is raised 0091 /// then. (i.e. \a zValue is relative to the strut) 0092 //TODO: account for overlapping struts 0093 void setZBehavior(ZBehavior behavior, qreal zValue); 0094 ///Struts are normally found by collision detection. This method 0095 ///configures a static strut for this item (on a semantic basis; 0096 ///e.g. the RectangleItem is the static strut for its walls). 0097 void setStaticStrut(CanvasItem* citem); 0098 void updateZ(QGraphicsItem* self); 0099 void moveItemsOnStrut(const QPointF& posDiff); 0100 static bool mayCollide(CanvasItem* citem1, CanvasItem* citem2); 0101 protected: 0102 friend class Kolf::Overlay; //for delivery of Kolf::Overlay::stateChanged signal 0103 ///pointer to main KolfGame 0104 KolfGame *game; 0105 private: 0106 QString m_name; 0107 int m_id; 0108 CanvasItem::ZBehavior m_zBehavior; 0109 qreal m_zValue; 0110 CanvasItem* m_strut; 0111 CanvasItem* m_staticStrut; 0112 QList<CanvasItem*> m_struttedItems; 0113 0114 //AFTER THIS LINE follows what I have inserted during the refactoring 0115 public: 0116 enum SimulationFlag 0117 { 0118 CollisionFlag = 1 << 0, 0119 KinematicSimulationFlag = 1 << 1, 0120 DynamicSimulationFlag = 1 << 2 0121 }; 0122 enum SimulationType 0123 { 0124 ///The object is immovable. 0125 NoSimulation = 0, 0126 ///The object is immovable, but other objects can interact with it. 0127 CollisionSimulation = CollisionFlag, 0128 ///The object moves according to its kinematic state. 0129 KinematicSimulation = CollisionSimulation | KinematicSimulationFlag, 0130 ///This object collides with the shapes of other objects, and forces 0131 ///can act on it. 0132 DynamicSimulation = KinematicSimulation | DynamicSimulationFlag 0133 }; 0134 0135 b2World* world() const; 0136 QList<Kolf::Shape*> shapes() const { return m_shapes; } 0137 Kolf::Overlay* overlay(bool createIfNecessary = true); 0138 ///@return items inside this CanvasItem which shall only be shown when 0139 ///the user toggles additional info. Hide these items by default! 0140 virtual QList<QGraphicsItem*> infoItems() const { return QList<QGraphicsItem*>(); } 0141 0142 ///This is the velocity used by the physics engine: In each time step, 0143 ///the position of this canvas item changes by the value of this property. 0144 QPointF velocity() const; 0145 void setVelocity(const QPointF& velocity); 0146 protected: 0147 void addShape(Kolf::Shape* shape); 0148 ///Configure how this object will participate in physical simulation. 0149 void setSimulationType(CanvasItem::SimulationType type); 0150 0151 friend class ::KolfGame; //for the following two methods 0152 ///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. 0153 virtual void startSimulation(); 0154 ///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. 0155 virtual void endSimulation(); 0156 0157 ///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. 0158 ///@warning Do not actually call this function from subclass implementations. Use overlay() instead. 0159 virtual Kolf::Overlay* createOverlay() { return nullptr; } //TODO: make this pure virtual when all CanvasItems are QGraphicsItems and implement createOverlay() (and then disallow createOverlay() == 0) 0160 ///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). 0161 void propagateUpdate(); 0162 private: 0163 friend class Kolf::Shape; //for access to m_body 0164 b2Body* m_body; 0165 0166 Kolf::Overlay* m_overlay; 0167 QList<Kolf::Shape*> m_shapes; 0168 CanvasItem::SimulationType m_simulationType; 0169 }; 0170 0171 //WARNING: pos() is at center (not at top-left edge of bounding rect!) 0172 class EllipticalCanvasItem : public Tagaro::SpriteObjectItem, public CanvasItem 0173 { 0174 public: 0175 EllipticalCanvasItem(bool withEllipse, const QString& spriteKey, QGraphicsItem* parent, b2World* world); 0176 QGraphicsEllipseItem* ellipseItem() const { return m_ellipseItem; } 0177 0178 bool contains(const QPointF& point) const override; 0179 QPainterPath shape() const override; 0180 0181 QRectF rect() const; 0182 double width() const { return Tagaro::SpriteObjectItem::size().width(); } 0183 double height() const { return Tagaro::SpriteObjectItem::size().height(); } 0184 0185 void setSize(const QSizeF& size) override; 0186 void setSize(qreal width, qreal height) { setSize(QSizeF(width, height)); } 0187 void moveBy(double x, double y) override; 0188 0189 void saveSize(KConfigGroup* group); 0190 void loadSize(KConfigGroup* group); 0191 0192 QPointF getPosition() const override { return QGraphicsItem::pos(); } 0193 private: 0194 QGraphicsEllipseItem* m_ellipseItem; 0195 Kolf::EllipseShape* m_shape; 0196 }; 0197 0198 class ArrowItem : public QGraphicsPathItem 0199 { 0200 public: 0201 explicit ArrowItem(QGraphicsItem* parent); 0202 0203 qreal angle() const; 0204 void setAngle(qreal angle); 0205 qreal length() const; 0206 void setLength(qreal length); 0207 bool isReversed() const; 0208 void setReversed(bool reversed); 0209 0210 Vector vector() const; 0211 private: 0212 void updatePath(); 0213 qreal m_angle, m_length; 0214 bool m_reversed; 0215 }; 0216 0217 #endif