-
Notifications
You must be signed in to change notification settings - Fork 0
/
fish_game.cpp
4277 lines (3317 loc) · 190 KB
/
fish_game.cpp
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <raylib.h>
#include <string>
#include <iostream>
#include <fstream>
#include <random>
#include <cmath>
#include "pthread.h"
#include <atomic>
#include <dirent.h>
using namespace std;
/*
credits: - “Additional sound effects from https://www.zapsplat.com“
- Music by: geoffharvey.
- Animations by: Terdpong.
*/
// ----- Static Declarations -----
// A thread friendly boolean indicator that all the data was loaded.
static std::atomic_bool images_loaded = ATOMIC_VAR_INIT(false);
static std::atomic_bool audio_loaded = ATOMIC_VAR_INIT(false);
static int data_progress = 0;
// ----- Basice Graphics classes -----
class Location
{
public:
int x;
int y;
public:
Location()
{
x = 0;
y = 0;
}
Location(int new_x, int new_y)
{
x = new_x;
y = new_y;
}
void set_location(Location location)
{
x = location.x;
y = location.y;
}
};
class Size
{
public:
int width;
int height;
public:
Size()
{
width = 0;
height = 0;
}
Size(int new_width, int new_height)
{
width = new_width;
height = new_height;
}
void set_size(Size size)
{
width = size.width;
height = size.height;
}
};
class Entity
{
/*
An entity in the world, with rectanngular frame.
*/
protected:
// The location of the entity on the screen. Reffering to center of the entity.
Location location;
// The size of the entity on the screen.
Size size;
// The scale of the entity.
float scale;
// The maximum scale of the entity.
float max_scale;
// The rotation of the entity.
float rotation;
public:
// Constructor.
Entity(Location new_location, Size new_size, float new_scale, float new_max_scale, int new_rotation)
{
// Set the location, size, scale and rotation of the entity.
location.set_location(new_location);
size.set_size(new_size);
scale = new_scale;
max_scale = new_max_scale;
rotation = new_rotation;
}
// Default constructor.
Entity()
{
location = Location(0, 0);
size = Size(0, 0);
scale = 0;
rotation = 0;
}
// Getters.
Location get_location() { return location; }
Size get_size() { return size; }
float get_scale() { return scale; }
int get_rotation() { return rotation; }
// Setters.
// Setters.
void set_scale(float new_scale)
{
if (new_scale > max_scale) { scale = max_scale; }
else { scale = new_scale; }
}
};
// ----- Structues -----
// An entity frame.
struct frame
{
int x_offset;
int y_offset;
int width;
int height;
};
// A description of a path.
struct fish_path
{
int speed_x;
int speed_y;
int is_moving_right;
int is_moving_top;
int current_frames_left;
};
// A fish_path stack.
struct paths_stack
{
// The initial location of the stack.
Location initial_location;
// An initial y coordinate.
int initial_y_coordinate;
// How many paths in the stack.
int length;
// An array of the paths.
fish_path* paths;
// If true the path repeats itself.
bool is_repeat;
// Flags for the initial location.
bool is_initial_location;
bool is_initial_y_coordinate;
bool is_randomize_x_coordinate;
bool is_left;
};
// Fish recipe.
struct fish_profile
{
// - Basic properties.
Image fish_image;
int* fish_image_frames_amount;
string fish_type;
frame collision_frame;
bool is_sting_proof;
bool is_facing_left_on_startup;
Size size;
float max_scaling;
float min_speed_x;
float max_speed_x;
float min_speed_y;
float max_speed_y;
int min_frames_per_path;
int max_frames_per_path;
float can_eat_ratio;
float cant_eat_ratio;
bool is_randomize_initial_scale;
// - Possible paths stacks
// The amount of paths stacks in the paths stacks array.
int paths_stacks_amount;
// An array of possible paths stacks.
paths_stack* paths_stacks;
// - Sounds.
Sound sound_eat;
Sound sound_sting;
// - Flags
// Indicates on the rarity of the fish. Try to avoid too large numbers. Do not use accuracy greater than 4 points after the decimal point.
float proportion;
};
// Declare the images struct.
struct images_refrences
{
int count = 16;
int my_fish_image_frames_amount;
Image my_fish_image;
const char* path_my_fish;
int fish1_image_frames_amount;
Image fish1_image;
const char* path_fish1;
int fish2_image_frames_amount;
Image fish2_image;
const char* path_fish2;
int fish3_image_frames_amount;
Image fish3_image;
const char* path_fish3;
int fish4_image_frames_amount;
Image fish4_image;
const char* path_fish4;
int fish5_image_frames_amount;
Image fish5_image;
const char* path_fish5;
int fish6_image_frames_amount;
Image fish6_image;
const char* path_fish6;
int fish7_image_frames_amount;
Image fish7_image;
const char* path_fish7;
int fish8_image_frames_amount;
Image fish8_image;
const char* path_fish8;
int fish9_image_frames_amount;
Image fish9_image;
const char* path_fish9;
int fish10_image_frames_amount;
Image fish10_image;
const char* path_fish10;
int fish11_image_frames_amount;
Image fish11_image;
const char* path_fish11;
int crab1_image_frames_amount;
Image crab1_image;
const char* path_crab1;
int crab2_image_frames_amount;
Image crab2_image;
const char* path_crab2;
int jeflly_fish1_image_frames_amount;
Image jelly_fish1_image;
const char* path_jelly_fish1;
int jeflly_fish2_image_frames_amount;
Image jelly_fish2_image;
const char* path_jelly_fish2;
};
// Declare the Audio struct.
struct audio_refrences
{
// Soundtrack equals 1, all the mini-sounds are altogether 1.
int count = 5;
Sound music_main_theme;
const char* path_music_main_theme;
Sound music_world1;
const char* path_music_world1;
Sound music_world2;
const char* path_music_world2;
Sound music_world3;
const char* path_music_world3;
Sound sound_eat;
const char* path_sound_eat;
Sound sound_eat_lower;
const char* path_sound_eat_lower;
Sound sound_sting1;
const char* path_sound_sting1;
Sound sound_sting1_lower;
const char* path_sound_sting1_lower;
};
// ----- Advanced Grahphics Classes -----
// Declare on cells before grid entity (Resolves the deadlock of Cell includes GridEntity and GridEntity includes Cell).
class Cell;
class GridEntity : public Entity
{
/*
An entity inside a grid.
*/
protected:
// The frame of the entity as a rectangle.
// Important: In the code, the location, size, scale and rotation of the entity might be changed outside the scope of the class,
// therefore rectangular_frame might not be up to date. Please call get_updated_rectangular_frame when using rectangular_frame.
// Important: The frame rectangle considers 0 rotation!
Rectangle rectangular_frame;
// The frame properties for collision detection.
// Important: the properites relates to the original dimensions of the gif file itself, not to the received size.
// Therfore, it is very important to call set_original_size() when the texture is initialized.
frame collision_frame;
// The maximum amount of cells the entity can be contained in. Note that if scale has no limit, might be inside all the cells of the grid.
int max_cells_within;
// The amount of cells currently within.
int current_amount_of_cells_within;
// Grid entities usually interact with each other (on collision for instance). Dynamic cast for "instance of" check, is inefficient and not recommended. Thefore, simply save the entity type as a string.
string entity_type;
public:
// The array of cells, as pointers, that the entity is currently within.
// cell_within is public due to the "referencing each other" conflic of Cell and GridEntity. The cells that the entity is within, directly manipulates cells_witihn from outside this class.
Cell** cells_within;
public:
// Constructor.
GridEntity(string new_entity_type, frame new_collision_frame, Location new_location, Size new_size, float new_scale, float new_max_scale, int new_rotation, int new_max_cells_within, Cell** new_cells_within) : Entity(new_location, new_size, new_scale, new_max_scale, new_rotation)
{
// The collision frame properties.
collision_frame = new_collision_frame;
// Save the maximum amount of cells might be within.
max_cells_within = new_max_cells_within;
// Create the cells array. Its length is exactly max_cells_within.
cells_within = new_cells_within;
// Not on the grid yet on initialization.
current_amount_of_cells_within = 0;
// The type of the entity as a string.
entity_type = new_entity_type;
}
// Defalut constructor.
GridEntity() : Entity()
{
max_cells_within = 0;
cells_within = NULL;
current_amount_of_cells_within = 0;
entity_type = "entity";
}
// The function receives the size of the texture and updates the collision frame size.
void set_original_size(Size original_size)
{
collision_frame.width = (int) (collision_frame.width * ((float) size.width / original_size.width));
collision_frame.x_offset = (int) (collision_frame.x_offset * ((float) size.width / original_size.width));
collision_frame.height = (int) (collision_frame.height * ((float) size.height / original_size.height));
collision_frame.y_offset = (int) (collision_frame.y_offset * ((float) size.height / original_size.height));
}
// The function returns the rectangular frame of the entity as a rectangle (NOT CONSIDERING ROTATION).
Rectangle get_updated_rectangular_frame()
{
// Calculate the frame considering the scale of the entity.
rectangular_frame = {location.x - ((sqrt(scale) * size.width) / 2), location.y - ((sqrt(scale) * size.height) / 2), sqrt(scale) * size.width, sqrt(scale) * size.height};
// Return the frame as rectangle.
return rectangular_frame;
}
// The function returns the collision frame rectangle.
Rectangle get_updated_collision_frame()
{
// Calculate the collision frame rectangle.
Rectangle collision_frame_rectangle = {location.x + (sqrt(scale) * collision_frame.x_offset) - ((sqrt(scale) * collision_frame.width) / 2), location.y + (sqrt(scale) * collision_frame.y_offset) - ((sqrt(scale) * collision_frame.height) / 2), sqrt(scale) * collision_frame.width, sqrt(scale) * collision_frame.height};
// Return the rectangle.
return collision_frame_rectangle;
}
// The function mirrors the collision frame on the y axis.
void flip_collision_frame_horizontal()
{
collision_frame.x_offset *= -1;
}
// The function returns the rectangular frame of the entity as a rectangle (NOT CONSIDERING ROTATION) Twice the size!
Rectangle get_updated_rectangular_frame_triple_size()
{
// Calculate the frame considering the scale of the entity.
Rectangle doubled_frame = {location.x - (float) (sqrt(scale) * size.width * 1.5), location.y - (float) (sqrt(scale) * size.height * 1.5), sqrt(scale) * size.width * 3, sqrt(scale) * size.height * 3};
// Return the frame as rectangle.
return doubled_frame;
}
// The function returns the rectangular frame of the entity as a rectangle (NOT CONSIDERING ROTATION) 0.8 the size!
Rectangle get_updated_rectangular_frame_lower_size()
{
// Calculate the frame considering the scale of the entity.
Rectangle doubled_frame = {location.x - (float) ((sqrt(scale) * size.width) * 0.8 / 2), location.y - (float) ((sqrt(scale) * size.height) * 0.8 / 2), (float) (sqrt(scale) * size.width * 0.8), (float) (sqrt(scale) * size.height * 0.8)};
// Return the frame as rectangle.
return doubled_frame;
}
// The function returns the array of cells that the entity is currently within.
Cell** get_cells_within() { return cells_within; }
// The function returns the amount of cells curretnly within.
int get_amount_of_cells_within() { return current_amount_of_cells_within; }
string get_entity_type() { return entity_type; }
// The function resets the array indicating the cells in which the entity is currently in.
void reset_cells_within() { current_amount_of_cells_within = 0;}
// The function is being called when a cell was added to cells_within.
void cell_within_was_added() { current_amount_of_cells_within++; }
// A GridEntity object might want to handle collision in its original class and not as an GridEntity.
virtual void handle_collision(GridEntity* colided_with_entity) {}
};
class Cell
{
/*
A cell of a grid.
*/
private:
// The maximum amount of enetities the current cell can contain.
int max_entities;
// The current amount of entities within the cell.
int entities_counter;
// All the entities within the current cell, as pointers.
GridEntity** entities;
public:
// Constructor.
Cell(int new_max_entities, GridEntity** new_entities)
{
// Set the maximum amount of entities the cell can contain.
max_entities = new_max_entities;
// Initialize the entities array with the size of max_entities.
entities = new_entities;
// Currently there are 0 entities in the cell.
entities_counter = 0;
}
// Default constructor.
Cell()
{
max_entities = 0;
entities = NULL;
entities_counter=0;
}
// Clears the current cell.
void reset()
{
entities_counter = 0;
}
// Add new entity to the cell.
void add_entity(GridEntity* new_entity)
{
// Add the entity to the cell.
entities[entities_counter] = new_entity;
entities_counter += 1;
// Add the cell to the entity.
new_entity -> cells_within[new_entity -> get_amount_of_cells_within()] = this;
new_entity -> cell_within_was_added();
}
// Remove received entity from the cell.
void remove_entity(GridEntity* entity_to_remove)
{
// Find the received entity in the entities array.
for (int i = 0; i < entities_counter; i++)
{
// Check if the current entity is the entity to remove.
if (entity_to_remove == entities[i])
{
// Overide the current entity with the entity at the end of the array.
entities[i] = entities[entities_counter - 1];
// Free the entity at the end of the array.
entities_counter -= 1;
// That's it.
break;
}
}
}
// The function returns the current amount of entities in the cell.
int get_entities_counter() { return entities_counter; }
// The function returns all the entities in the cell.
GridEntity** get_entities() { return entities; }
};
class Grid
{
/*
The grid reduces significantly the amount of collision checks in the world.
*/
private:
// The maximum amount of entities a cell can contain.
int cell_maximum_amount_of_entities;
// The amount of columns in the grid.
int columns_amount;
// The amount of rows in the grid.
int rows_amount;
// The width of the grid in pixels.
int width_pixels;
// The height of the grid in pixels.
int height_pixels;
// The width of each cell in pixels.
int cell_width_pixels;
// The height of each cell in pixels.
int cell_height_pixels;
// An 2d matrix with the cells of the grid, as pointers.
Cell*** cells;
public:
// Counstructor.
Grid(int new_columns_amount, int new_rows_amount, int new_cell_maximum_amount_of_entities, int new_width_pixels, int new_height_pixels)
{
// Set the amount of rows and columns.
columns_amount = new_columns_amount;
rows_amount = new_rows_amount;
// Set the width of the grid in pixels.
width_pixels = new_width_pixels;
height_pixels = new_height_pixels;
// Calculate and save the amount of pixels each cell covers.
cell_width_pixels = width_pixels / columns_amount;
cell_height_pixels = height_pixels / rows_amount;
// Save the maximum amount of entites a single cell can contain.
cell_maximum_amount_of_entities = new_cell_maximum_amount_of_entities;
// Declare the cells matrix.
cells = new Cell**[rows_amount];
for(int i = 0; i < rows_amount; i++)
cells[i] = new Cell*[columns_amount];
// Create the cells of the grid.
for (int row_index = 0; row_index < rows_amount; row_index++)
{
for (int column_index = 0; column_index < columns_amount; column_index++)
{
cells[row_index][column_index] = new Cell(cell_maximum_amount_of_entities, new GridEntity*[cell_maximum_amount_of_entities]);
}
}
}
// Default Constructor.
Grid()
{
cell_maximum_amount_of_entities = 0;
columns_amount = 0;
rows_amount = 0;
width_pixels = 0;
height_pixels = 0;
cell_width_pixels = 0;
cell_height_pixels = 0;
}
// Reset the grid.
void reset()
{
// Iterate over the cells in the grid.
for (int row_index = 0; row_index < rows_amount; row_index++)
for (int col_index = 0; col_index < columns_amount; col_index++)
cells[row_index][col_index] -> reset();
}
// The function receives an entity and refresh it location on the grid.
void refresh_entity(GridEntity* entity_to_refresh)
{
// Remove it from the grid.
remove_entity(entity_to_refresh);
// Add it to the grid.
add_entity(entity_to_refresh);
}
// The function receives an entity and adds it to the grid.
void add_entity(GridEntity* new_entity)
{
/*
The rectangles are not rotated.
This fact means that a rectangle is within a cell, if and only if the cell is between the y axis boundaries of the rectangle, as well as the x axis boundaries.
*/
// Get the location and size of the entity.
Location location = new_entity -> get_location();
Size size = new_entity -> get_size();
float scale = new_entity -> get_scale();
// Calculate the x boundaries.
int x_boundary_left = location.x - ((sqrt(scale) * size.width) / 2);
int x_boundary_right = x_boundary_left + (sqrt(scale) * size.width);
// Calculate the y boundaries.
int y_boundary_top = location.y - ((sqrt(scale) * size.height) / 2);
int y_boundary_bottom = y_boundary_top + (sqrt(scale) * size.height);
// Find the left and right columns indexes boundaries.
int left_column_index_boundary = (int) floor( (double) x_boundary_left / cell_width_pixels);
int right_column_index_boundary = (int) floor( (double) x_boundary_right / cell_width_pixels);
// Find the top and bottom rows indexes boundaries.
int top_row_index_boundary = (int) floor( (double) y_boundary_top / cell_height_pixels);
int bottom_row_index_boundary = (int) floor( (double) y_boundary_bottom / cell_height_pixels);
// Don't care if outside the grid.
if (top_row_index_boundary >= rows_amount) { top_row_index_boundary = rows_amount - 1; }
else if (top_row_index_boundary < 0) { top_row_index_boundary = 0; }
if (bottom_row_index_boundary < 0) { bottom_row_index_boundary = 0; }
else if (bottom_row_index_boundary >= rows_amount) { bottom_row_index_boundary = rows_amount - 1; }
if (left_column_index_boundary < 0) { left_column_index_boundary = 0; }
else if (left_column_index_boundary >= columns_amount) { left_column_index_boundary = columns_amount - 1; }
if (right_column_index_boundary >= columns_amount) { right_column_index_boundary = columns_amount - 1; }
else if (right_column_index_boundary < 0) { right_column_index_boundary = 0; }
// Add the entity to all the cells within those boundaries.
for (int row_index = top_row_index_boundary; row_index <= bottom_row_index_boundary; row_index++)
{
for(int col_index = left_column_index_boundary; col_index <= right_column_index_boundary; col_index++)
{
// Add the entity to the current cell (also adds the cell to the current entity).
cells[row_index][col_index] -> add_entity(new_entity);
}
}
}
// The function removes an entity from the grid.
void remove_entity(GridEntity* entity_to_remove)
{
// How many cells the entity is currently within.
int amount_of_cells_within = entity_to_remove -> get_amount_of_cells_within();
// Get the list of cells that the entity is currently within.
Cell** cells_within = entity_to_remove -> get_cells_within();
// Iterate over the cells within.
for (int i = 0; i < amount_of_cells_within; i++)
{
cells_within[i] -> remove_entity(entity_to_remove);
}
// Reset the cells within of the entity to remove.
entity_to_remove -> reset_cells_within();
}
// Getters.
// The function returns the amount of columns.
int get_columns_amount() { return columns_amount; }
// The function returns the amount of rows.
int get_rows_amount() { return rows_amount; }
// Getters.
int get_width_pixels() { return width_pixels; }
int get_height_pixels() { return height_pixels; }
int get_cell_width_pixels() { return cell_width_pixels; }
int get_cell_height_pixels() { return cell_height_pixels; }
// Returns the cells matrix.
Cell*** get_cells() { return cells; }
};
class MyGif: public GridEntity
{
/*
Load a gif to the screen.
Notes:
- The gif is loaded as a texture, and manipulated as a texture.
- The gif doesn't have to be on a grid, an almost identical MyGif class is spared due to unnecessary code overload. Simply the value of max_cells_within can be ignored and the array
cells_within should be nothing but a null pointer.
*/
protected:
// An optional attribute, if true on intialization, the gif originaly facing left. Indicates to flip it horizontaly to face right on startup.
bool is_facing_left_on_startup;
// If true, flips the gif horizontally.
bool is_flip_horizontal;
// If true, flips the gif vertically.
bool is_flip_vertical;
// When the gif is loaded, this variable contains the amount of frames this gif has.
int* frames_amount;
// Pointing on the current frame of the gif that is being displayed.
int current_frame = 0;
// The gif as image.
Image my_gif_image;
// The gif as texture.
Texture2D my_gif_texture;
// The tint of the gif.
Color tint;
public:
// Constructor.
MyGif(Image new_my_gif_image, int* new_frames_amount, frame new_collision_frame, string new_entity_type, Location new_location, Size new_size, float new_scale, float new_max_scale, int new_rotation, bool new_is_facing_left_on_startup, int new_max_cells_within, Cell** new_cells_within) : GridEntity(new_entity_type, new_collision_frame, new_location, new_size, new_scale, new_max_scale, new_rotation, new_max_cells_within, new_cells_within)
{
// Save the image of the gif.
my_gif_image = new_my_gif_image;
// Save the frames amount instance.
frames_amount = new_frames_amount;
// True if the gif faces left originaly.
is_facing_left_on_startup = new_is_facing_left_on_startup;
// Set the texture on initialization to face right.
if (is_facing_left_on_startup) { is_flip_horizontal = true; }
else { is_flip_horizontal = false; }
// Do not flip the texture verticaly on initialization.
is_flip_vertical = false;
// Create the texture instance.
my_gif_texture = LoadTextureFromImage(my_gif_image);
// Set the collision frame to match the current size.
set_original_size(Size(my_gif_texture.width, my_gif_texture.height));
// Set the tint to white.
tint = WHITE;
}
// Default Constructor.
MyGif() : GridEntity()
{
is_facing_left_on_startup = false;
is_flip_horizontal = false;
is_flip_vertical = false;
}
// Flipping manipulations
void flip_horizontal() {is_facing_left_on_startup ? is_flip_horizontal = false : is_flip_horizontal = true;}
void flip_vertical() {is_flip_vertical = true;}
void unflip_horizontal() {is_facing_left_on_startup ? is_flip_horizontal = true : is_flip_horizontal = false;}
void unflip_vertical() {is_flip_vertical = false;}
// Change the tint of the gif.
void update_tint(Color new_tint) { tint = new_tint; }
// The function Prepare the next frame of the gif.
void set_next_frame()
{
// Containing required data about the next frame.
int next_frame_data_offset;
// Point on the next frame.
current_frame++;
// Reset the current frame index if currently displaying the last frame of the gif.
if (current_frame >= *frames_amount) { current_frame = 0; }
// Get memory offset position for next frame data in image.data.
next_frame_data_offset = my_gif_image.width * my_gif_image.height * 4 * current_frame;
// Update GPU texture data with next frame image data.
UpdateTexture(my_gif_texture, ((unsigned char *) my_gif_image.data) + next_frame_data_offset);
}
// The function draws the last frame that was set with set_next_frame().
void draw_next_frame()
{
// -1 cause flip, 1 do not flips.
float flip_width = 1, flip_height = 1;
// Check if required flipping.
if (is_flip_horizontal) {flip_width = -1;}
if (is_flip_vertical) {flip_height = -1;}
// Crop the gif (we don't want to crop any gif, so just take its original frame).
Rectangle source = {0, 0, flip_width * my_gif_texture.width, flip_height * my_gif_texture.height};
// Where to draw the gif. The input location is where to put the center on the screen.
Rectangle destination = {(float) location.x, (float) location.y, (float) floor(sqrt(scale) * size.width), (float) floor(sqrt(scale) * size.height)};
// We want the gif to be rotated in relation to its center, and we want that the inputed location in the destination rectangle will be the center.
Vector2 center = {(sqrt(scale) * size.width) / 2, (sqrt(scale) * size.height) / 2};
// Draw the next frame of the gif properly.
DrawTexturePro(my_gif_texture, source, destination, center, rotation, tint);
}
// The function removes the gif from the screen.
void delete_gif()
{
// Remove the texture.
UnloadTexture(my_gif_texture);
}
// Returns the center location of the gif.
Location get_location() {return location;}
};
// ----- Game Classes -----
// Need to declare for the Fish class.
class FishNetwork;
class Fish : public MyGif
{
/*
Represents a fish.
*/
protected:
// How many frames elapsed in a second.
int fps;
// The type of the fish.
string fish_type;
// The speed of the fish on the x and y axes, pixels/frame;
float speed_x, speed_y;
// The location boundaries of the fish.
int left_boundary, right_boundary, top_boundary, bottom_boundary;
// Indicating if the fish is out of bounds.
bool is_fish_out_of_bounds;
// Indicates on the moving direction of the fish on the x axis.
bool is_moving_right;
// Indicating that the fish was eaten.
bool is_eaten;
// How much the fish grows after eating another fish.
float eat_grow_ratio;
// Can eat fish that are <can_eat_ratio> my size and greater.
float can_eat_ratio;
// Can't eat fish that are <cant_eat_ratio> and less my size.
float cant_eat_ratio;
// If true the fish can't get stinged.
bool is_sting_proof;
// How many frames left for the current stunt to over.
int current_stunt_frames_left;
// How much size decreases each frame from the current stunt.
float stunt_size_decrease_per_frame;
// The original speed of the fish (for when the speed is temporarly changed).
int original_speed_x;
int original_speed_y;
// Sounds.
Sound sound_eat;
Sound sound_sting;
public:
// Counstructor.
Fish(int new_fps, Image new_my_fish_image, int* new_frames_amount, frame new_collision_frame, string new_fish_type, bool new_is_sting_proof, Location new_location, Size new_size, float new_speed_x, float new_speed_y, int new_left_boundary, int new_right_boundary, int new_top_boundary, int new_bottom_boundary, float new_scale, float new_max_scale, float new_eat_grow_ratio, float new_can_eat_ratio, float new_cant_eat_ratio, float new_rotation, bool new_is_facing_left_on_startup, int new_max_cells_within, Cell** new_cells_within, Sound new_sound_eat, Sound new_sound_sting) : MyGif(new_my_fish_image, new_frames_amount, new_collision_frame, "Fish", new_location, new_size, new_scale, new_max_scale, new_rotation, new_is_facing_left_on_startup, new_max_cells_within, new_cells_within)
{
// How many frames are there per second.
fps = new_fps;
// Save the type of the fish.
fish_type = new_fish_type;
// Set the speed of the fish.
speed_x = new_speed_x;
speed_y = new_speed_y;
// Set the boundaries of the fish.
left_boundary = new_left_boundary;
right_boundary = new_right_boundary;
top_boundary = new_top_boundary;
bottom_boundary = new_bottom_boundary;
// Set false in initialization. Update accurate value on the first move call.
is_fish_out_of_bounds = false;
// Set the moving direction.
is_moving_right = (is_facing_left_on_startup) ? false: true;
// The fish is not eaten on startup.
is_eaten = false;
// The ratio of eating and growing.
eat_grow_ratio = new_eat_grow_ratio;
// The ratio of fish size can eat.
can_eat_ratio = new_can_eat_ratio;
// The ratio of fish size can't eat.
cant_eat_ratio = new_cant_eat_ratio;