Skip to content

Commit 99dac54

Browse files
committed
ADDED: Automation Events System, exposed to users
Added new API to record and play events Added examples illustrating functionality
1 parent 067dbe8 commit 99dac54

File tree

7 files changed

+1169
-348
lines changed

7 files changed

+1169
-348
lines changed
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
/*******************************************************************************************
2+
*
3+
* raylib [core] example - automation events
4+
*
5+
* Example originally created with raylib 5.0, last time updated with raylib 5.0
6+
*
7+
* Example based on 2d_camera_platformer example by arvyy (@arvyy)
8+
*
9+
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
10+
* BSD-like license that allows static linking with closed source software
11+
*
12+
* Copyright (c) 2023 Ramon Santamaria (@raysan5)
13+
*
14+
********************************************************************************************/
15+
16+
#include "raylib.h"
17+
#include "raymath.h"
18+
19+
#define GRAVITY 400
20+
#define PLAYER_JUMP_SPD 350.0f
21+
#define PLAYER_HOR_SPD 200.0f
22+
23+
#define MAX_ENVIRONMENT_ELEMENTS 5
24+
25+
typedef struct Player {
26+
Vector2 position;
27+
float speed;
28+
bool canJump;
29+
} Player;
30+
31+
typedef struct EnvElement {
32+
Rectangle rect;
33+
int blocking;
34+
Color color;
35+
} EnvElement;
36+
37+
38+
//------------------------------------------------------------------------------------
39+
// Program main entry point
40+
//------------------------------------------------------------------------------------
41+
int main(void)
42+
{
43+
// Initialization
44+
//--------------------------------------------------------------------------------------
45+
const int screenWidth = 800;
46+
const int screenHeight = 450;
47+
48+
InitWindow(screenWidth, screenHeight, "raylib [core] example - automation events");
49+
50+
// Define player
51+
Player player = { 0 };
52+
player.position = (Vector2){ 400, 280 };
53+
player.speed = 0;
54+
player.canJump = false;
55+
56+
// Define environment elements (platforms)
57+
EnvElement envElements[MAX_ENVIRONMENT_ELEMENTS] = {
58+
{{ 0, 0, 1000, 400 }, 0, LIGHTGRAY },
59+
{{ 0, 400, 1000, 200 }, 1, GRAY },
60+
{{ 300, 200, 400, 10 }, 1, GRAY },
61+
{{ 250, 300, 100, 10 }, 1, GRAY },
62+
{{ 650, 300, 100, 10 }, 1, GRAY }
63+
};
64+
65+
// Define camera
66+
Camera2D camera = { 0 };
67+
camera.target = player.position;
68+
camera.offset = (Vector2){ screenWidth/2.0f, screenHeight/2.0f };
69+
camera.rotation = 0.0f;
70+
camera.zoom = 1.0f;
71+
72+
// Automation events
73+
AutomationEventList aelist = LoadAutomationEventList(0); // Initialize list of automation events to record new events
74+
SetAutomationEventList(&aelist);
75+
bool eventRecording = false;
76+
bool eventPlaying = false;
77+
78+
int frameCounter = 0;
79+
int playFrameCounter = 0;
80+
int currentFrame = 0;
81+
82+
SetTargetFPS(60);
83+
//--------------------------------------------------------------------------------------
84+
85+
// Main game loop
86+
while (!WindowShouldClose())
87+
{
88+
// Update
89+
//----------------------------------------------------------------------------------
90+
float deltaTime = GetFrameTime();
91+
92+
// Dropped files logic
93+
//----------------------------------------------------------------------------------
94+
if (IsFileDropped())
95+
{
96+
FilePathList droppedFiles = LoadDroppedFiles();
97+
98+
// Supports loading .rgs style files (text or binary) and .png style palette images
99+
if (IsFileExtension(droppedFiles.paths[0], ".txt;.rae"))
100+
{
101+
UnloadAutomationEventList(&aelist);
102+
aelist = LoadAutomationEventList(droppedFiles.paths[0]);
103+
104+
eventRecording = false;
105+
106+
// Reset scene state to play
107+
eventPlaying = true;
108+
playFrameCounter = 0;
109+
110+
player.position = (Vector2){ 400, 280 };
111+
player.speed = 0;
112+
player.canJump = false;
113+
114+
camera.target = player.position;
115+
camera.offset = (Vector2){ screenWidth/2.0f, screenHeight/2.0f };
116+
camera.rotation = 0.0f;
117+
camera.zoom = 1.0f;
118+
}
119+
120+
UnloadDroppedFiles(droppedFiles); // Unload filepaths from memory
121+
}
122+
//----------------------------------------------------------------------------------
123+
124+
// Update player
125+
//----------------------------------------------------------------------------------
126+
if (IsKeyDown(KEY_LEFT)) player.position.x -= PLAYER_HOR_SPD*deltaTime;
127+
if (IsKeyDown(KEY_RIGHT)) player.position.x += PLAYER_HOR_SPD*deltaTime;
128+
if (IsKeyDown(KEY_SPACE) && player.canJump)
129+
{
130+
player.speed = -PLAYER_JUMP_SPD;
131+
player.canJump = false;
132+
}
133+
134+
int hitObstacle = 0;
135+
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
136+
{
137+
EnvElement *element = &envElements[i];
138+
Vector2 *p = &(player.position);
139+
if (element->blocking &&
140+
element->rect.x <= p->x &&
141+
element->rect.x + element->rect.width >= p->x &&
142+
element->rect.y >= p->y &&
143+
element->rect.y <= p->y + player.speed*deltaTime)
144+
{
145+
hitObstacle = 1;
146+
player.speed = 0.0f;
147+
p->y = element->rect.y;
148+
}
149+
}
150+
151+
if (!hitObstacle)
152+
{
153+
player.position.y += player.speed*deltaTime;
154+
player.speed += GRAVITY*deltaTime;
155+
player.canJump = false;
156+
}
157+
else player.canJump = true;
158+
159+
camera.zoom += ((float)GetMouseWheelMove()*0.05f);
160+
161+
if (camera.zoom > 3.0f) camera.zoom = 3.0f;
162+
else if (camera.zoom < 0.25f) camera.zoom = 0.25f;
163+
164+
if (IsKeyPressed(KEY_R))
165+
{
166+
camera.zoom = 1.0f;
167+
player.position = (Vector2){ 400, 280 };
168+
}
169+
//----------------------------------------------------------------------------------
170+
171+
// Update camera
172+
//----------------------------------------------------------------------------------
173+
camera.target = player.position;
174+
camera.offset = (Vector2){ screenWidth/2.0f, screenHeight/2.0f };
175+
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
176+
177+
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
178+
{
179+
EnvElement *element = &envElements[i];
180+
minX = fminf(element->rect.x, minX);
181+
maxX = fmaxf(element->rect.x + element->rect.width, maxX);
182+
minY = fminf(element->rect.y, minY);
183+
maxY = fmaxf(element->rect.y + element->rect.height, maxY);
184+
}
185+
186+
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, camera);
187+
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, camera);
188+
189+
if (max.x < screenWidth) camera.offset.x = screenWidth - (max.x - screenWidth/2);
190+
if (max.y < screenHeight) camera.offset.y = screenHeight - (max.y - screenHeight/2);
191+
if (min.x > 0) camera.offset.x = screenWidth/2 - min.x;
192+
if (min.y > 0) camera.offset.y = screenHeight/2 - min.y;
193+
//----------------------------------------------------------------------------------
194+
195+
// Toggle events recording
196+
if (IsKeyPressed(KEY_ONE))
197+
{
198+
if (!eventPlaying)
199+
{
200+
if (eventRecording)
201+
{
202+
StopAutomationEventRecording();
203+
eventRecording = false;
204+
205+
ExportAutomationEventList(aelist, "automation.rae");
206+
}
207+
else
208+
{
209+
StartAutomationEventRecording();
210+
eventRecording = true;
211+
}
212+
}
213+
}
214+
215+
if (eventPlaying)
216+
{
217+
if (playFrameCounter == aelist.events[currentFrame].frame)
218+
{
219+
PlayAutomationEvent(aelist.events[currentFrame]);
220+
currentFrame++;
221+
222+
if (currentFrame == aelist.count)
223+
{
224+
eventPlaying = false;
225+
currentFrame = 0;
226+
playFrameCounter = 0;
227+
}
228+
}
229+
230+
playFrameCounter++;
231+
}
232+
233+
if (eventRecording || eventPlaying) frameCounter++;
234+
else frameCounter = 0;
235+
//----------------------------------------------------------------------------------
236+
237+
// Draw
238+
//----------------------------------------------------------------------------------
239+
BeginDrawing();
240+
241+
ClearBackground(LIGHTGRAY);
242+
243+
BeginMode2D(camera);
244+
245+
// Draw environment elements
246+
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
247+
{
248+
DrawRectangleRec(envElements[i].rect, envElements[i].color);
249+
}
250+
251+
// Draw player rectangle
252+
DrawRectangleRec((Rectangle){ player.position.x - 20, player.position.y - 40, 40, 40 }, RED);
253+
254+
EndMode2D();
255+
256+
// Draw automation events recording indicator
257+
if (eventRecording)
258+
{
259+
if (((frameCounter/15)%2) == 1)
260+
{
261+
DrawCircle(GetScreenWidth() - 200, 20, 10, MAROON);
262+
DrawText(TextFormat("RECORDING EVENTS... [%i]", aelist.count), GetScreenWidth() - 180, 15, 10, RED);
263+
}
264+
}
265+
else if (eventPlaying)
266+
{
267+
if (((frameCounter/15)%2) == 1)
268+
{
269+
DrawTriangle((Vector2){ GetScreenWidth() - 200, 10 }, (Vector2){ GetScreenWidth() - 200, 30 }, (Vector2){ GetScreenWidth() - 200 + 20, 20 }, DARKGREEN);
270+
DrawText(TextFormat("PLAYING EVENTS... [%i]", currentFrame), GetScreenWidth() - 170, 15, 10, LIME);
271+
}
272+
}
273+
274+
DrawText("Controls:", 20, 20, 10, BLACK);
275+
DrawText("- Right/Left to move", 30, 40, 10, DARKGRAY);
276+
DrawText("- Space to jump", 30, 60, 10, DARKGRAY);
277+
DrawText("- Mouse Wheel to Zoom in-out, R to reset zoom", 30, 80, 10, DARKGRAY);
278+
279+
EndDrawing();
280+
//----------------------------------------------------------------------------------
281+
}
282+
283+
// De-Initialization
284+
//--------------------------------------------------------------------------------------
285+
CloseWindow(); // Close window and OpenGL context
286+
//--------------------------------------------------------------------------------------
287+
288+
return 0;
289+
}

0 commit comments

Comments
 (0)