Subversion Repositories spacemission

Rev

Blame | Last modification | View Log | RSS feed

  1. unit DXMisc;
  2.  
  3. // Contains miscellaneous code
  4.  
  5. interface
  6.  
  7. uses classes, controls;
  8.  
  9. type
  10.    // This obtains the co-ords for the mouse relative to a control
  11.   TMousePos = class(Tobject)
  12.   private
  13.      { Private declarations }
  14.      // Data
  15.     fControl: TControl;
  16.  
  17.     fMouseX: integer;
  18.     fMouseY: integer;
  19.     fXDelta: integer;
  20.     fYDelta: integer;
  21.      // used to scale the mouse input
  22.     fSensitivity: Single;
  23.      // Options
  24.     fClipToControl: boolean;
  25.   protected
  26.      { Protected declarations }
  27.     procedure SetClipState(Value: boolean);
  28.   public
  29.      { Public declarations }
  30.     constructor Create(Control: TControl);
  31.     destructor Destroy; override;
  32.      // Sets the control to use
  33.     procedure SetControl(AControl: TControl);
  34.      // Grabs the latest mouse co-ords
  35.     procedure Update;
  36.      // Relative to the parent control
  37.     property MouseX: integer read fMouseX;
  38.     property MouseY: integer read fMouseY;
  39.     property XDelta: integer read fXDelta;
  40.     property YDelta: integer read fYDelta;
  41.      // The sensitivity of the mouse
  42.     property Sensitivity: Single read fSensitivity write fSensitivity;
  43.     property ClipToControl: Boolean read fClipToControl write SetClipState;
  44.  
  45.     property Control: TControl read fControl write SetControl;
  46.   published
  47.      { Published declarations }
  48.   end;
  49.  
  50.  // This is an example of how to cap the frame rate
  51.  // this has NOT been optimized and is just to hide the relatively
  52.  // mess code needed to properly calc the time delta for a frame
  53.  // and the time delta since the last render
  54.   TTiming = class(TObject)
  55.   protected
  56.     { Protected declarations }
  57.     // Used to implement frame capping
  58.     fGraphicsTimeDelta: longword;
  59.     LastTimeFrame: longword;
  60.     // the number of ms each frame has in its budget
  61.     FrameRateBudget: longword; // this is just for the graphics system
  62.     // see the properties section
  63.     fTimeDelta: longword;
  64.  
  65.     TimeFrame: longword;
  66.     fFrameRate: longword;
  67.     fFrameRateGoal: longword;
  68.  
  69.     fNoGraphics: boolean;
  70.     // sets up various timing stuff
  71.     procedure InitTiming(FrameRate: longword);
  72.   public
  73.     { Public declarations }
  74.     constructor Create(AFrameRateGoal: longword);
  75.     // Calculates the time delta from the last frame
  76.     procedure CalcNewTimeDelta;
  77.     // Checks if the designated time till the next render has passed
  78.     function TimeToRender: boolean;
  79.     // Prepares internal info for the next frame
  80.     procedure UpdateGraphicsTimeDelta;
  81.     procedure CalcFrameRate;
  82.  
  83.     property GraphicsTimeDelta: longword read fGraphicsTimeDelta;
  84.     // used to determine how much time has elapsed from the last frame in ms
  85.     property TimeDelta: longword read fTimeDelta;
  86.     // The timestamp for the current frame
  87.     property FrameStamp: longword read TimeFrame;
  88.     // The frame rate that is being achieved
  89.     property FrameRate: longword read fFrameRate;
  90.     // The goal frame rate for the frame skipping mechanism
  91.     // This also Limits the frame rate to this to
  92.     property FrameRateGoal: longword read fFrameRateGoal write InitTiming;
  93.  
  94.     // TimeTorender always returns false, used to disable graphics stuff
  95.     property NoGraphics: boolean read fNoGraphics write fNoGraphics;
  96.   end;
  97.  
  98.   TStateMachine = class;
  99.  
  100.   TState = class(TObject) // a state aware class
  101.   private
  102.     fStateIndex: integer;
  103.     fStateMachine: TStateMachine;
  104.   public
  105.     constructor Create; virtual;
  106.  
  107.     procedure Execute; virtual; abstract;
  108.     property StateIndex: integer read fStateIndex;
  109.     property StateMachine: TStateMachine read fStateMachine;
  110.   end;
  111.  
  112.   // This is a state machine which removes the need for large case statements when executing the current state
  113.   TStateMachine = class(TObject)
  114.   private
  115.      { Private declarations }
  116.   protected
  117.      { Protected declarations }
  118.      // Holds a list of the valid states
  119.     fStatesList: Tlist;
  120.      // the number of states
  121.     fStates: integer;
  122.      // The max number of allowed states
  123.     fMaxStates: integer;
  124.      // The current state
  125.     fCurrentState: TState;
  126. //     Function GetState(index :integer) : TState; virtual;
  127.   public
  128.      { Public declarations }
  129.     constructor Create;
  130.     destructor Destroy; override;
  131.     // This registers a state, if the state exists then it is updated
  132.     // Dont pass < 0 as the state constant
  133.     procedure AddState(State: TState); virtual;
  134.     // This removes a registerd state
  135.     procedure RemoveState(State: TState); virtual;
  136.     // This clears all the states
  137.     procedure ClearStates; virtual;
  138.  
  139.     // allows easy state changes
  140.     procedure ActivateNextState; virtual;
  141.     // The current state's id
  142.     property CurrentState: TState read fCurrentState write fCurrentState;
  143.  
  144.     // The Number of valid states
  145.     property States: integer read fStates;
  146.     property MaxStates: integer read fMaxStates write fMaxStates;
  147.     {
  148.     // Allows direct access to the states of an object
  149.     Property StateList[index :integer] : TState read GetState;
  150.     }
  151.     property StateList: Tlist read fStatesList;
  152.   end;
  153.  
  154. const
  155.  // This is the default strating number of states the TStateMachine will allocate
  156.   StartStates = 16; // This is also what it allocates when it tries to add a new state
  157.   MaxNumStates = 255; // this is the max number of states allowed. Why would you want more :)
  158.  
  159. // Scans a Component and the components owned by the Component for a Component of the class type 'Classtype'
  160. function FindComponentType(Aowner: TComponent; Classtype: TComponentClass): TComponent;
  161.  
  162. implementation
  163.  
  164. uses windows, Sysutils, mmsystem;
  165.  
  166. function FindComponentType(Aowner: TComponent; Classtype: TComponentClass): TComponent;
  167. var
  168.   index: integer;
  169. begin
  170.   if not assigned(AOwner) then
  171.   begin
  172.     result := nil;
  173.     exit;
  174.   end;
  175.   if AOwner is Classtype then
  176.   begin
  177.     result := AOwner;
  178.   end
  179.   else
  180.   begin
  181.   // For some reason, when in the designer AOwner.ComponentIndex = -1!
  182.   // thus this search algo would failed in designer mode
  183.     for index := 0 to AOwner.ComponentCount - 1 do
  184.     begin
  185.       if AOwner.Components[index] is Classtype then
  186.       begin
  187.         result := AOwner.Components[index];
  188.         exit;
  189.       end;
  190.     end;
  191.     result := nil;
  192.   end;
  193. end;
  194.  
  195. // -----------------------------------------------------------------------------
  196. // TTiming
  197. // -----------------------------------------------------------------------------
  198.  
  199. constructor TTiming.Create(AFrameRateGoal: longword);
  200. begin
  201.   inherited create;
  202.   FrameRateGoal := AFrameRateGoal;
  203.   InitTiming(FrameRateGoal);
  204. end; {TTiming}
  205.  
  206. procedure TTiming.InitTiming(FrameRate: longword);
  207. begin
  208.   fFrameRateGoal := FrameRate;
  209.   FrameRateBudget := 1000 div fFrameRateGoal;
  210.   fGraphicsTimeDelta := 0;
  211.   fTimeDelta := 0;
  212.   TimeFrame := timegettime;
  213.   LastTimeFrame := TimeFrame;
  214. end; {InitTiming}
  215.  
  216. procedure TTiming.CalcNewTimeDelta;
  217. var
  218.   NewTimeFrame: Longword;
  219. begin
  220. // update the time delta & time frame stamps
  221.   NewTimeFrame := TimeGetTime;
  222.   fTimeDelta := NewTimeFrame - TimeFrame;
  223.   TimeFrame := NewTimeFrame;
  224. end; {CalcNewTimeDelta}
  225.  
  226. procedure TTiming.UpdateGraphicsTimeDelta;
  227. begin
  228. // get how long it took to render the frame
  229.   LastTimeFrame := timegettime;
  230.   fGraphicsTimeDelta := 0;
  231. end;
  232.  
  233. procedure TTiming.CalcFrameRate;
  234. begin
  235.   if GraphicsTimeDelta <> 0 then
  236.     fFrameRate := 1000 div GraphicsTimeDelta
  237.   else
  238.     fFrameRate := 0;
  239. end; {CalcFrameRate}
  240.  
  241. function TTiming.TimeToRender: boolean;
  242. begin
  243. // Check to see if we can update the screen
  244.   fGraphicsTimeDelta := Timegettime - LastTimeFrame;
  245.   result := (GraphicsTimeDelta >= FrameRateBudget) and (not fNoGraphics);
  246. end; {TimeToRender}
  247.  
  248. // -----------------------------------------------------------------------------
  249. // TMousePos
  250. // -----------------------------------------------------------------------------
  251.  
  252. constructor TMousePos.Create(Control: TControl);
  253. begin
  254.   inherited Create;
  255.   if not assigned(Control) then
  256.     raise Exception.Create('Parent can''''t = nil');
  257.   fSensitivity := 1.0;
  258.   fClipToControl := true;
  259.   SetControl(Control);
  260. end; {Create}
  261.  
  262. destructor TMousePos.Destroy;
  263. begin
  264.   SetControl(nil);
  265.   inherited;
  266. end; {Destroy}
  267.  
  268. procedure TMousePos.SetControl(AControl: TControl);
  269. begin
  270.   assert(self <> nil);
  271.   if assigned(AControl) then
  272.   begin
  273.     fControl := AControl;
  274.   // This gets the intitial value
  275.     Update;
  276.   // This gets the correct mouse X,Y deltas
  277.     Update;
  278.   end
  279.   else
  280.   begin
  281.     fControl := nil;
  282.   end;
  283. end; {SetControl}
  284.  
  285. procedure TMousePos.SetClipState(Value: boolean);
  286. begin
  287.   if fClipToControl <> value then
  288.   begin
  289.     fClipToControl := Value;
  290.   // Re-obtain the co-ords with the correct option
  291.     Update;
  292.   end;
  293. end; {SetClipState}
  294.  
  295. procedure TMousePos.Update;
  296. var
  297.   pos: TPoint;
  298. begin
  299. // Get the latest mouse info
  300.   pos := mouse.CursorPos;
  301. // Convert them to relative to the Control
  302.   pos := fControl.ScreenToClient(pos);
  303.   if fClipToControl then
  304.   begin
  305.     if pos.x >= fControl.width then
  306.       pos.x := fControl.width - 1
  307.     else if pos.x < 0 then
  308.       pos.x := 0;
  309.     if pos.Y >= fControl.Height then
  310.       pos.Y := fControl.Height - 1
  311.     else if pos.Y < 0 then
  312.       pos.Y := 0;
  313.   end;
  314. // Update the mouse delta's
  315. // fmouse? = old mouse pos
  316. // pos.? = new mouse pos
  317.   fXDelta := pos.X - fMouseX;
  318.   fYDelta := pos.Y - fMouseY;
  319. // Scale the mouse co-ords
  320.   if fSensitivity - 1.0 > 0.00001 then
  321.   begin
  322.     fMouseX := fMouseX + Trunc(fXDelta * fSensitivity);
  323.     fMouseY := fMouseY + Trunc(fYDelta * fSensitivity);
  324.   end
  325.   else
  326.   begin
  327.     fMouseX := pos.X;
  328.     fMouseY := pos.Y;
  329.   end;
  330. end; {Update}
  331.  
  332. // -----------------------------------------------------------------------------
  333. // TStateMachine
  334. // -----------------------------------------------------------------------------
  335.  
  336. constructor TStateMachine.Create;
  337. begin
  338.   inherited;
  339.   fMaxStates := MaxNumStates;
  340.   fStatesList := Tlist.create;
  341. end; {Create}
  342.  
  343. destructor TStateMachine.Destroy;
  344. begin
  345.   ClearStates;
  346.   fStatesList.free;
  347.   inherited;
  348. end; {Destroy}
  349.  
  350. procedure TStateMachine.AddState(State: TState);
  351. begin
  352.   if (fStatesList.IndexOf(State) = -1) and
  353.     (fStates < MaxStates) then
  354.   begin
  355.     State.fStateIndex := fStatesList.add(State);
  356.     State.fStateMachine := self;
  357.     if fCurrentState = nil then
  358.       fCurrentState := state;
  359.     inc(fStates);
  360.   end;
  361. end; {AddState}
  362.  
  363. procedure TStateMachine.RemoveState(State: TState);
  364. var
  365.   index: integer;
  366. begin
  367.   index := fStatesList.IndexOf(State);
  368.   if (index <> -1) then
  369.   begin
  370.     if fCurrentState = state then
  371.       fCurrentState := nil;
  372.     fStatesList.Delete(index);
  373.     Dec(fStates);
  374.   end;
  375. end; {RemoveState}
  376.  
  377. procedure TStateMachine.ClearStates;
  378. var
  379.   state: Tstate;
  380. begin
  381.   while fStatesList.count <> 0 do
  382.   begin
  383.     state := fStatesList.Items[fStatesList.count - 1];
  384.     state.free;
  385.     fStatesList.Delete(fStatesList.count - 1);
  386.   end;
  387. end; {ClearStates}
  388.  
  389. procedure TStateMachine.ActivateNextState;
  390. var
  391.   index: integer;
  392. begin
  393.   if fStatesList.count = 0 then
  394.     exit;
  395.   if fCurrentState = nil then
  396.     fCurrentState := fStatesList[0];
  397.   index := fCurrentState.StateIndex;
  398.   inc(index);
  399.   if index >= fStatesList.count - 1 then
  400.     index := 0;
  401.   fCurrentState := Tstate(fStatesList[index]);
  402. end; {ActivateNextState}
  403.  
  404. constructor Tstate.Create;
  405. begin
  406.   inherited Create;
  407. end; {Create}
  408.  
  409. end.
  410.