Subversion Repositories spacemission

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 daniel-mar 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.