iTickable.h
Engine/source/core/iTickable.h
Classes:
class
This interface allows you to let any object be ticked.
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#ifndef _ITICKABLE_H_ 25#define _ITICKABLE_H_ 26 27#include "core/util/tVector.h" 28 29/// This interface allows you to let any object be ticked. You use it like so: 30/// @code 31/// class FooClass : public SimObject, public virtual ITickable 32/// { 33/// // You still mark SimObject as Parent 34/// typdef SimObject Parent; 35/// private: 36/// ... 37/// 38/// protected: 39/// // These three methods are the interface for ITickable 40/// virtual void interpolateTick( F32 delta ); 41/// virtual void processTick(); 42/// virtual void advanceTime( F32 timeDelta ); 43/// 44/// public: 45/// ... 46/// }; 47/// @endcode 48/// Please note the three methods you must implement to use ITickable, but don't 49/// worry. If you forget, the compiler will tell you so. Also note that the 50/// typedef for Parent should NOT BE SET to ITickable, the compiler will <i>probably</i> 51/// also tell you if you forget that. Last, but assuridly not least is that you note 52/// the way that the inheretance is done: public <b>virtual</b> ITickable 53/// It is very important that you keep the virtual keyword in there, otherwise 54/// proper behavior is not guarenteed. You have been warned. 55/// 56/// The point of a tickable object is that the object gets ticks at a fixed rate 57/// which is one tick every 32ms. This means, also, that if an object doesn't get 58/// updated for 64ms, that the next update it will get two-ticks. Basically it 59/// comes down to this. You are assured to get one tick per 32ms of time passing 60/// provided that isProcessingTicks returns true when ITickable calls it. 61/// 62/// isProcessingTicks is a virtual method and you can (should you want to) 63/// override it and put some extended functionality to decide if you want to 64/// recieve tick-notification or not. 65/// 66/// The other half of this is that you get time-notification from advanceTime. 67/// advanceTime lets you know when time passes regardless of the return value 68/// of isProcessingTicks. The object WILL get the advanceTime call every single 69/// update. The argument passed to advanceTime is the time since the last call 70/// to advanceTime. Updates are not based on the 32ms tick time. Updates are 71/// dependant on framerate. So you may get 200 advanceTime calls in a second, or you 72/// may only get 20. There is no way of assuring consistant calls of advanceTime 73/// like there is with processTick. Both are useful for different things, and 74/// it is important to understand the differences between them. 75/// 76/// Interpolation is the last part of the ITickable interface. It is called 77/// every update, as long as isProcessingTicks evaluates to true on the object. 78/// This is used to interpolate between 32ms ticks. The argument passed to 79/// interpolateTick is the time since the last call to processTick. You can see 80/// in the code for ITickable::advanceTime that before a tick occurs it calls 81/// interpolateTick(0) on every object. This is to tell objects which do interpolate 82/// between ticks to reset their interpolation because they are about to get a 83/// new tick. 84/// 85/// This is an extremely powerful interface when used properly. An example of a class 86/// that properly uses this interface is GuiTickCtrl. The documentation for that 87/// class describes why it was created and why it was important that it use 88/// a consistant update frequency for its effects. 89/// @see GuiTickCtrl 90/// 91/// @todo Support processBefore/After and move the GameBase processing over to use ITickable 92class ITickable 93{ 94private: 95 static U32 smLastTick; ///< Time of the last tick that occurred 96 static U32 smLastTime; ///< Last time value at which advanceTime was called 97 static U32 smLastDelta; ///< Last delta value for advanceTime 98 99 static U32 smTickShift; ///< Shift value to control how often Ticks occur 100 static U32 smTickMs; ///< Number of milliseconds per tick, 32 in this case 101 static F32 smTickSec; ///< Fraction of a second per tick 102 static U32 smTickMask; 103 104 // This just makes life easy 105 typedef Vector<ITickable *>::iterator ProcessListIterator; 106 /// Returns a reference to the list of all ITickable objects. 107 static Vector<ITickable*>& getProcessList(); 108 109 bool mProcessTick; ///< Set to true if this object wants tick processing 110protected: 111 /// This method is called every frame and lets the control interpolate between 112 /// ticks so you can smooth things as long as isProcessingTicks returns true 113 /// when it is called on the object 114 virtual void interpolateTick( F32 delta ) = 0; 115 116 /// This method is called once every 32ms if isProcessingTicks returns true 117 /// when called on the object 118 virtual void processTick() = 0; 119 120 /// This method is called once every frame regardless of the return value of 121 /// isProcessingTicks and informs the object of the passage of time. 122 /// @param timeDelta Time increment in seconds. 123 virtual void advanceTime( F32 timeDelta ) = 0; 124 125public: 126 127 /// Constructor 128 /// This will add the object to the process list 129 ITickable(); 130 131 /// Destructor 132 /// Remove this object from the process list 133 virtual ~ITickable(); 134 135 /// Is this object wanting to receive tick notifications 136 /// @returns True if object wants tick notifications 137 bool isProcessingTicks() const { return mProcessTick; }; 138 139 /// Sets this object as either tick processing or not 140 /// @param tick True if this object should process ticks 141 virtual void setProcessTicks( bool tick = true ); 142 143 /// Initialise the ITickable system. 144 static void init( const U32 tickShift ); 145 146 /// Gets the Tick bit-shift. 147 static U32 getTickShift() { return smTickShift; } 148 /// Gets the Tick (ms) 149 static U32 getTickMs() { return smTickMs; } 150 /// Gets the Tick (seconds) 151 static F32 getTickSec() { return smTickSec; } 152 /// Gets the Tick mask. 153 static U32 getTickMask() { return smTickMask; } 154 155//------------------------------------------------------------------------------ 156 157 /// This is called in clientProcess to advance the time for all ITickable 158 /// objects. 159 /// @param timeDelta Time increment in milliseconds. 160 /// @returns True if any ticks were sent 161 /// @see clientProcess 162 static bool advanceTime( U32 timeDelta ); 163}; 164 165//------------------------------------------------------------------------------ 166 167inline void ITickable::setProcessTicks( bool tick /* = true */ ) 168{ 169 mProcessTick = tick; 170} 171 172#endif 173