diff --git a/examples/shapes_following_eyes.c b/examples/shapes_following_eyes.c new file mode 100644 index 0000000..39126eb --- /dev/null +++ b/examples/shapes_following_eyes.c @@ -0,0 +1,129 @@ +/******************************************************************************************* +* +* raylib [textures] example - Texture loading and drawing +* +* Example originally created with raylib 1.0, last time updated with raylib 1.0 +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include "math.h" + +void raylib_js_set_entry(void (*entry)(void)); + +Vector2 scleraLeftPosition; +Vector2 scleraRightPosition; +float scleraRadius; + +Vector2 irisLeftPosition; +Vector2 irisRightPosition; +float irisRadius; + +float angle; +float dx, dy, dxx, dyy; + +void GameFrame() { + // Update + //---------------------------------------------------------------------------------- + irisLeftPosition = GetMousePosition(); + irisRightPosition = GetMousePosition(); + + // Check not inside the left eye sclera + if (!CheckCollisionPointCircle(irisLeftPosition, scleraLeftPosition, scleraRadius - irisRadius)) + { + dx = irisLeftPosition.x - scleraLeftPosition.x; + dy = irisLeftPosition.y - scleraLeftPosition.y; + + angle = atan2f(dy, dx); + + dxx = (scleraRadius - irisRadius)*cosf(angle); + dyy = (scleraRadius - irisRadius)*sinf(angle); + + irisLeftPosition.x = scleraLeftPosition.x + dxx; + irisLeftPosition.y = scleraLeftPosition.y + dyy; + } + + // Check not inside the right eye sclera + if (!CheckCollisionPointCircle(irisRightPosition, scleraRightPosition, scleraRadius - irisRadius)) + { + dx = irisRightPosition.x - scleraRightPosition.x; + dy = irisRightPosition.y - scleraRightPosition.y; + + angle = atan2f(dy, dx); + + dxx = (scleraRadius - irisRadius)*cosf(angle); + dyy = (scleraRadius - irisRadius)*sinf(angle); + + irisRightPosition.x = scleraRightPosition.x + dxx; + irisRightPosition.y = scleraRightPosition.y + dyy; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawCircleV(scleraLeftPosition, scleraRadius, LIGHTGRAY); + DrawCircleV(irisLeftPosition, irisRadius, BROWN); + DrawCircleV(irisLeftPosition, 10, BLACK); + + DrawCircleV(scleraRightPosition, scleraRadius, LIGHTGRAY); + DrawCircleV(irisRightPosition, irisRadius, DARKGREEN); + DrawCircleV(irisRightPosition, 10, BLACK); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - following eyes"); + + scleraLeftPosition = CLITERAL(Vector2){ GetScreenWidth()/2.0f - 100.0f, GetScreenHeight()/2.0f }; + scleraRightPosition = CLITERAL(Vector2){ GetScreenWidth()/2.0f + 100.0f, GetScreenHeight()/2.0f }; + scleraRadius = 80; + + irisLeftPosition = CLITERAL(Vector2){ GetScreenWidth()/2.0f - 100.0f, GetScreenHeight()/2.0f }; + irisRightPosition = CLITERAL(Vector2){ GetScreenWidth()/2.0f + 100.0f, GetScreenHeight()/2.0f }; + irisRadius = 24; + + angle = 0.0f; + float dx = 0.0f; + dy = 0.0f; + dxx = 0.0f; + dyy = 0.0f; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + +#ifdef PLATFORM_WEB + raylib_js_set_entry(GameFrame); +#else + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + GameFrame(); + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- +#endif + return 0; +} diff --git a/index.html b/index.html index 960a2cd..1faa92e 100644 --- a/index.html +++ b/index.html @@ -69,7 +69,7 @@ const wasmPaths = { "tsoding": ["tsoding_ball", "tsoding_snake",], "core": ["core_basic_window", "core_basic_screen_manager", "core_input_keys", "core_input_mouse_wheel",], - "shapes": ["shapes_colors_palette"], + "shapes": ["shapes_colors_palette", "shapes_following_eyes"], "text": ["text_writing_anim"], "textures": ["textures_logo_raylib"], } diff --git a/nob.c b/nob.c index 15ef36d..5cb5fb1 100644 --- a/nob.c +++ b/nob.c @@ -48,6 +48,11 @@ Example examples[] = { .bin_path = "./build/text_writing_anim", .wasm_path = "./wasm/text_writing_anim.wasm", }, + { + .src_path = "./examples/shapes_following_eyes.c", + .bin_path = "./build/shapes_following_eyes", + .wasm_path = "./wasm/shapes_following_eyes.wasm", + }, }; bool build_native(void) @@ -60,6 +65,7 @@ bool build_native(void) nob_cmd_append(&cmd, "-L./lib/", "-lraylib", "-lm"); if (!nob_cmd_run_sync(cmd)) return 1; } + return 0; } bool build_wasm(void) @@ -81,6 +87,7 @@ bool build_wasm(void) nob_cmd_append(&cmd, "-DPLATFORM_WEB"); if (!nob_cmd_run_sync(cmd)) return 1; } + return 0; } int main(int argc, char **argv) diff --git a/raylib.js b/raylib.js index a6a0154..0c2db6a 100644 --- a/raylib.js +++ b/raylib.js @@ -344,6 +344,45 @@ class RaylibJs { this.ctx.fillText(text, posX, posY + fontSize); } + DrawFPS(x, y){ + // TODO: implement DrawFPS + } + + CheckCollisionCircles(center1_ptr, radius1, center2_ptr, radius2) { + const buffer = this.wasm.instance.exports.memory.buffer; + const [c1x, c1y] = new Float32Array(buffer, center1_ptr, 2); + const [c2x, c2y] = new Float32Array(buffer, center2_ptr, 2); + + var collision = false; + + var dx = c2x - c1x; // X distance between centers + var dy = c2y - c1y; // Y distance between centers + + var distance = Math.sqrt(dx*dx + dy*dy); // Distance between centers + + if (distance <= (radius1 + radius2)) collision = true; + + return collision; + } + + CheckCollisionPointCircle(point_ptr, center_ptr, radius) { + var collision = false; + collision = this.CheckCollisionCircles(point_ptr, 0, center_ptr, radius); + return collision; + } + + atan2f(x, y) { + return Math.atan2(x, y); + } + + cosf(x) { + return Math.cos(x); + } + + sinf(x) { + return Math.sin(x); + } + raylib_js_set_entry(entry) { this.entryFunction = this.wasm.instance.exports.__indirect_function_table.get(entry); } diff --git a/wasm/shapes_following_eyes.wasm b/wasm/shapes_following_eyes.wasm new file mode 100755 index 0000000..380298d Binary files /dev/null and b/wasm/shapes_following_eyes.wasm differ