-
Notifications
You must be signed in to change notification settings - Fork 0
/
gameobjects.pas
212 lines (189 loc) · 9.59 KB
/
gameobjects.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
unit GameObjects;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Sprites,contnrs,allegro,boolUtils;
type
TObjectMode = (omAnim,omSprite);
{ TGameObject }
TGameObject = class
private
_CurrentAnim:integer; //actual value of current animation
_CurrentSprite:integer;//We keep current sprite number separately
procedure SetSprite(Value:Integer);
procedure SetAnim(Value:Integer); //sets value of animation and if it isn't nil reset it
public
Animations:TAnimatedSpriteList; //list of animations
Sprites:TSpriteList; //List of sprites
//as to not interfere if we want to switch
//GO from animation to static sprite
ObjectMode:TObjectMode; //Is this GO animated or is it just static
//object such as box? We don't need to
//animate static objects as it will make
//game needlessly slower.
x,y:Integer; //x/y positions of GO
property CurrentAnim:integer read _CurrentAnim write SetAnim; //property for current animation
property CurrentSprite:integer read _CurrentSprite write SetSprite; //property for current sprite
procedure MoveTo(_x,_y:Integer);virtual; //moves object to specific position
procedure MoveBy(_x,_y:Integer);virtual; //moves object by specified amount of pixels
function isColliding(GO:TGameObject):Boolean; //collision check with another GO
function isColliding(Sprite:TSprite):Boolean; //collision check with a Sprite.
//We don't need version with
//TAnimatedSprite as it is
//descendant of TSprite and
//checks exactly same way.
procedure Update();virtual; //Update function of TGameObject
procedure Draw(Bitmap:AL_BITMAPptr);virtual; //Rendering function of TGameObject
constructor Create(mode:TObjectMode); //constructor 1
constructor Create(DefaultAnimation:TAnimatedSprite); //constructor with default animation
constructor Create(DefaultSprite:TSprite); //constructor with default sprite
destructor Destroy; override; //destructor
end;
implementation
{ TGameObject }
procedure TGameObject.MoveTo(_x, _y: Integer);
begin
x:=_x;
y:=_y;
end;
procedure TGameObject.MoveBy(_x, _y: Integer);
begin
x:=x+_x;
y:=x+_y;
end;
function TGameObject.isColliding(GO: TGameObject): Boolean;
begin
Result:=false; //setting result just in case
case ObjectMode of
omAnim: begin
if (((Between(CurrentAnim,-1,Animations.Count)) and (Animations.Items[CurrentAnim]<>nil))) then //safety check so we won't get segfault
if GO.ObjectMode=omAnim then //checking if object mode of other game object is animation
begin
//setting result, checking other's GO "nilness" of animation
if ((Between(GO.CurrentAnim,-1,GO.Animations.Count))) and (Assigned(Pointer(GO.Animations.Items[GO.CurrentAnim]))) then
Result:=Animations.Items[CurrentAnim].IsColliding(GO.Animations.Items[GO.CurrentAnim]);
end else //if it's not omAnim, then it must be in sprite mode
begin
//setting result, checking other's GO "nilness" of sprite
Result:=((GO.Sprites.Items[GO.CurrentSprite]<>nil) and (Animations.Items[CurrentAnim].IsColliding(GO.Sprites.Items[GO.CurrentSprite])));
end;
end;
omSprite: begin
if Sprites.Items[CurrentSprite]<>nil then //safety check so we won't get segfault
if GO.ObjectMode=omAnim then //checking if object mode of other game object is animation
begin
//setting result, checking other's GO "nilness" of animation
Result:=((GO.Animations.Items[GO.CurrentAnim]<>nil) and (Sprites.Items[CurrentSprite].IsColliding(GO.Animations.Items[GO.CurrentAnim])));
end else //if it's not omAnim, then it must be in sprite mode
begin
//setting result, checking other's GO "nilness" of sprite
Result:=((GO.Sprites.Items[GO.CurrentSprite]<>nil) and (Sprites.Items[CurrentSprite].IsColliding(GO.Sprites.Items[GO.CurrentSprite])));
end;
end;
end;
end;
function TGameObject.isColliding(Sprite: TSprite): Boolean;
begin
Result:=false; //setting result, just in case
case ObjectMode of
omAnim: begin
if Animations.Items[CurrentAnim]<>nil then //safety check so we won't get segfault
//setting result
Result:=Animations.Items[CurrentAnim].IsColliding(Sprite);
end;
omSprite: begin
if Sprites.Items[CurrentSprite]<>nil then //safety check so we won't get segfault
//setting result
Result:=Sprites.Items[CurrentSprite].IsColliding(Sprite);
end;
end;
end;
procedure TGameObject.Update;
begin
case ObjectMode of //we update differently depending of whether it is animation
//or sprite, so there you go.
omAnim: begin
if Animations.Items[CurrentAnim]<>nil then //safety check so we won't get segfault
begin
//updating animation
Animations.Items[CurrentAnim].Update;
//locking animated sprite's position to game object's
Animations.Items[CurrentAnim].x:=x;
Animations.Items[CurrentAnim].y:=y;
end;
end;
omSprite: begin
if Sprites.Items[CurrentSprite]<>nil then //safety check so we won't get segfault
begin
//locking sprite's position to game object's
Sprites.Items[CurrentSprite].x:=x;
Sprites.Items[CurrentSprite].y:=y;
end;
end;
end;
end;
procedure TGameObject.Draw(Bitmap: AL_BITMAPptr);
begin
case ObjectMode of
omAnim: begin
if Animations.Items[CurrentAnim]<>nil then //safety check so we won't get segfault
begin
//when working with animations, we need to test if it needs updating of actual frame and then
//render it before we actually draw it to bitmap.
if Animations.Items[CurrentAnim].NeedUpdate then Animations.Items[CurrentAnim].UpdateFrame;
Animations.Items[CurrentAnim].Draw(Bitmap);
end;
end;
omSprite: begin
if Sprites.Items[CurrentSprite]<>nil then //safety check so we won't get segfault
//drawing sprite to requested bitmap (usually buffer one)
Sprites.Items[CurrentSprite].Draw(Bitmap);
end;
end;
end;
constructor TGameObject.Create(mode: TObjectMode);
begin
inherited Create;
ObjectMode:=mode;
//we don't need both lists if we are going to use only one type which is
//usually the case. If we need both, it is possible to create them
//after contruction (both will be freed when destroying class if applicable).
//todo: replace ifs with case of.
if mode=omAnim then Animations:=TAnimatedSpriteList.create;
if mode=omSprite then Sprites:=TSpriteList.create;
end;
constructor TGameObject.Create(DefaultAnimation: TAnimatedSprite);
begin
Create(omAnim); //executing standard constructor with omAnim object mode
Animations.Add(DefaultAnimation); //adding animation to the list
end;
constructor TGameObject.Create(DefaultSprite: TSprite);
begin
Create(omSprite); //executing standard constructor with omSprite object mode
Sprites.Add(DefaultSprite); //adding sprite to the list
end;
destructor TGameObject.Destroy;
begin
inherited Destroy;
Animations.Free; //free checks if it is nil, so it'll destroy them only if necessary.
Sprites.Free;
end;
procedure TGameObject.SetSprite(Value: Integer);
begin
_CurrentSprite:=Value; //setting actual sprite value
//clamping value so it won't go out of range
if _CurrentSprite<0 then _CurrentSprite:=0;
if _CurrentSprite>Animations.Count-1 then _CurrentSprite:=Animations.Count-1;
end;
procedure TGameObject.SetAnim(Value: Integer);
begin
_CurrentAnim:=Value; //setting actual animation value
//clamping value so it won't go out of range
if _CurrentAnim<0 then _CurrentAnim:=0;
if _CurrentAnim>Animations.Count-1 then _CurrentAnim:=Animations.Count-1;
//after some consideration I've decided to leave check for rare cases when programmer would bork his/her
//implementation and try to destroy item in Animations or just add uninitialized TAnimatedSprite.
//I need to make sure that game won't crash no matter what.
if Animations.Items[_CurrentAnim]<>nil then Animations.Items[_CurrentAnim].Reset; //resetting animation if it wasn't nil so it'll play from start.
end;
end.