diff --git a/CHANGELOG b/CHANGELOG index 2af57c2c4..795a2ee53 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,11 +1,48 @@ changelog --------- -Current Release: raylib 1.3.0 (03 September 2015) +Current Release: raylib 1.4.0 (22 February 2016) NOTE: Only versions marked as 'Release' are available in installer, updates are only available as source. NOTE: Current Release includes all previous updates. +----------------------------------------------- +Release: raylib 1.4.0 (22 February 2016) +----------------------------------------------- +NOTE: + This version supposed another big improvement for raylib, inlcuding new modules and new features. + More than 30 new functions have been added to previous raylib version. + Around 8 new examples and +10 new game samples have been added. + +BIG changes: +[textures] IMAGE MANIPULATION: Functions to crop, resize, colorize, flip, dither and even draw image-to-image or text-to-image. +[text] SPRITEFONT SUPPORT: Added support for AngelCode fonts (.fnt) and TrueType fonts (.ttf). +[gestures] REDESIGN: Gestures system simplified and prepared to process generic touch events, including mouse events (multiplatform). +[physac] NEW MODULE: Basic 2D physics support, use colliders and rigidbodies; apply forces to physic objects. + +other changes: +[rlgl] Removed GLEW library dependency, now using GLAD +[rlgl] Implemented alternative to glGetTexImage() on OpenGL ES +[rlgl] Using depth data on batch drawing +[rlgl] Reviewed glReadPixels() function +[core][rlgl] Reviewed raycast system, now 3D picking works +[core] Android: Reviewed Android App cycle, paused if inactive +[shaders] Implemented Blinn-Phong lighting shading model +[textures] Implemented Floyd-Steinberg dithering - ImageDither() +[text] Added line-break support to DrawText() +[text] Added TrueType Fonts support (using stb_truetype) +[models] Implement function: CalculateBoundingBox(Mesh mesh) +[models] Added functions to check Ray collisions +[models] Improve map resolution control on LoadHeightmap() +[camera] Corrected small-glitch on zoom-in with mouse-wheel +[gestures] Implemented SetGesturesEnabled() to enable only some gestures +[gestures] Implemented GetElapsedTime() on Windows system +[gestures] Support mouse gestures for desktop platforms +[raymath] Complete review of the module and converted to header-only +[easings] Added new module for easing animations +[stb] Updated to latest headers versions +[*] Lots of tweaks around + ----------------------------------------------- Release: raylib 1.3.0 (01 September 2015) ----------------------------------------------- diff --git a/HELPME.md b/HELPME.md index 8a0ada189..b4f0219fc 100644 --- a/HELPME.md +++ b/HELPME.md @@ -32,6 +32,8 @@ contact * Webpage: [http://www.raylib.com](http://www.raylib.com) * Twitter: [http://www.twitter.com/raysan5](http://www.twitter.com/raysan5) * Facebook: [http://www.facebook.com/raylibgames](http://www.facebook.com/raylibgames) - + * Reddit: [https://www.reddit.com/r/raylib](https://www.reddit.com/r/raylib) + * Twitch: [http://www.twitch.tv/raysan5](http://www.twitch.tv/raysan5) + * Patreon: [https://www.patreon.com/raysan5](https://www.patreon.com/raysan5) -[raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San" +[raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San" diff --git a/README.md b/README.md index f9a5a0e23..5f6fea7f5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ about raylib is a simple and easy-to-use library to learn videogames programming. raylib is highly inspired by Borland BGI graphics lib and by XNA framework. -Allegro and SDL have also been analyzed for reference. NOTE for ADVENTURERS: raylib is a programming library to learn videogames programming; no fancy interface, no visual helpers, no auto-debugging... just coding in the most @@ -15,7 +14,7 @@ pure spartan-programmers way. Are you ready to learn? Jump to [code examples!](h history ------- -I've developed videogames for some years and last year I had to taught videogames development +I've developed videogames for some years and 4 years ago I started teaching videogames development to young people with artistic profile, most of them had never written a single line of code. I started with C language basis and, after searching for the most simple and easy-to-use library to teach @@ -102,25 +101,25 @@ Lots of code changes and lot of testing have concluded in this amazing new rayli notes on raylib 1.4 ------------------- -On February 2016, after 4 months of raylib 1.3 release, it comes raylib 1.4. +On February 2016, after 4 months of raylib 1.3 release, it comes raylib 1.4. For this new version, lots of parts of the library have been reviewed, lots of bugs have been solved and some interesting features have been added. -Lots of parts of the library have been reviewed to better accomodate to shaders systems and multiple new features have been added. +First big addition is a set of [Image manipulation functions](https://github.com/raysan5/raylib/blob/develop/src/raylib.h#L673) have been added to crop, resize, colorize, flip, dither and even draw image-to-image or text-to-image. Now a basic image processing can be done before converting the image to texture for usage. -SpriteFonts system has been improved, adding support for AngelCode fonts (.fnt) and TTF fonts (using stb_truetype). +SpriteFonts system has been improved, adding support for AngelCode fonts (.fnt) and TrueType Fonts (using [stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h) helper library). Now raylib can read standard .fnt font data and also generate at loading a SpriteFont from a TTF file. -Finally, raycast system for 3D picking is working, including some ray collision-detection functions. +New [physac](https://github.com/raysan5/raylib/blob/develop/src/physac.h) physics module for basic 2D physics support. Still in development but already functional. Module comes with some usage examples for basic jump and level interaction and also force-based physic movements. -A set of Image manipulation functions have been added to crop, resize, colorize, dither and even draw image-to-image or text-to-image. +[raymath](https://github.com/raysan5/raylib/blob/develop/src/raymath.h) module has been reviewed; some bugs have been solved and the module has been converted to a header-only file for easier portability, optionally, functions can also be used as inline. -Two new functions added for persistent data storage. +[gestures](https://github.com/raysan5/raylib/blob/develop/src/gestures.c) module has redesigned and simplified, now it can process touch events from any source, including mouse. This way, gestures system can be used on any platform providing an unified way to work with inputs and allowing the user to create multiplatform games with only one source code. -New [physac](https://github.com/raysan5/raylib/blob/develop/src/physac.h) physics module! +Raspberry Pi input system has been redesigned to better read raw inputs using generic Linux event handlers (keyboard:`stdin`, mouse:`/dev/input/mouse0`, gamepad:`/dev/input/js0`). Gamepad support has also been added (experimental). -Complete LUA scripting support to allow raylib usage from LUA and LUA scripts support within raylib. +Other important improvements are the functional raycast system for 3D picking, including some ray collision-detection functions, and the addition of two simple functions for persistent data storage. Now raylib user can save and load game data in a file (only some platforms supported). A simple [easings](https://github.com/raysan5/raylib/blob/develop/src/easings.h) module has also been added for values animation. -Up to 8 new examples have been added to show the new raylib features. +Up to 8 new code examples have been added to show the new raylib features and +10 complete game samples have been provided to learn how to create some classic games like Arkanoid, Asteroids, Missile Commander, Snake or Tetris. -Lots of code changes and lot of testing have concluded in this amazing new raylib 1.4. +Lots of code changes and lots of hours of hard work have concluded in this amazing new raylib 1.4. features -------- @@ -130,7 +129,7 @@ features * Hardware accelerated with OpenGL (1.1, 3.3 or ES2) * Unique OpenGL abstraction layer (usable as standalone module): [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.c) * Powerful fonts module with multiple SpriteFonts formats support (XNA bitmap fonts, AngelCode fonts, TTF) - * Outstanding texture formats support, including compressed formats + * Outstanding texture formats support, including compressed formats (DXT, ETC, PVRT, ASTC) * Basic 3d support for Shapes, Models, Billboards, Heightmaps and Cubicmaps * Powerful math module for Vector and Matrix operations: [raymath](https://github.com/raysan5/raylib/blob/master/src/raymath.c) * Audio loading and playing with streaming support (WAV and OGG) @@ -181,6 +180,9 @@ contact * Webpage: [http://www.raylib.com](http://www.raylib.com) * Twitter: [http://www.twitter.com/raysan5](http://www.twitter.com/raysan5) * Facebook: [http://www.facebook.com/raylibgames](http://www.facebook.com/raylibgames) + * Reddit: [https://www.reddit.com/r/raylib](https://www.reddit.com/r/raylib) + * Twitch: [http://www.twitch.tv/raysan5](http://www.twitch.tv/raysan5) + * Patreon: [https://www.patreon.com/raysan5](https://www.patreon.com/raysan5) If you are using raylib and you enjoy it, please, [let me know][raysan5]. diff --git a/ROADMAP.md b/ROADMAP.md index e0d0c825b..aaa1a256e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,28 +1,37 @@ roadmap ------- -Current version of raylib is quite complete and functional but there is still a lot of things I would like to improve. -Here it is a list of features I would like to add and functions to improve. +Current version of raylib is quite complete and functional but there is still a lot of things to add and improve. +Here it is a wish list of features I would like to add and functions to improve. -Around the source code there are multiple TODO points with pending revisions/bugs and here it is a list of desired features. +Note that around the raylib source code there are multiple TODO points with pending revisions/bugs. Check [GitHub Issues](https://github.com/raysan5/raylib/issues) for further details! -raylib v1.4 +raylib 1.5 - [DONE] TTF fonts support (using stb_truetype) - [DONE] Raycast system for 3D picking (including collisions detection) - [DONE] Floyd-Steinberg dithering on 16bit image format conversion - [DONE] Basic image manipulation functions (crop, resize, draw...) - [DONE] Storage load/save data functionality - [DONE] Physics module - [IN PROGRESS] LUA scripting support (wrapper to lua lib) - - Remove GLEW dependency (use another solution... glad?) - - Basic image procedural generation (spot, gradient, noise...) - - Basic GPU stats sytem (memory, draws, time...) - - -Check [GITHUB ISSUES][issues] for further details on implementation status for this features! + Redesign Shaders/Textures system, use Materials + Redesign physics module (physac) + Basic GPU stats sytem (memory, draws, time...) + Procedural image generation functions (spot, gradient, noise...) + Procedural mesh generation functions (cube, cone, sphere...) + Touch-based camera controls for Android + Skybox and Fog support + [IN PROGRESS] LUA scripting support (wrapper to lua lib) + +raylib 1.4 + + [DONE] TTF fonts support (using stb_truetype) + [DONE] Raycast system for 3D picking (including collisions detection) + [DONE] Floyd-Steinberg dithering on 16bit image format conversion + [DONE] Basic image manipulation functions (crop, resize, draw...) + [DONE] Storage load/save data functionality + [DONE] Add Physics module (physac) + [DONE] Remove GLEW dependency -> Replaced by GLAD + [DONE] Redesign Raspberry PI inputs system + [DONE] Redesign gestures module to be multiplatform + [DONE] Module raymath as header-only and functions inline + [DONE] Add Easings module (easings.h) Any feature missing? Do you have a request? [Let me know!][raysan5] -[raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San" +[raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San" [isssues]: https://github.com/raysan5/raylib/issues diff --git a/examples/core_3d_camera_first_person.c b/examples/core_3d_camera_first_person.c index 8a092275d..2b8dc7fce 100644 --- a/examples/core_3d_camera_first_person.c +++ b/examples/core_3d_camera_first_person.c @@ -22,7 +22,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person"); - // Define the camera to look into our 3d world + // Define the camera to look into our 3d world (position, target, up vector) Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; // Generates some random columns diff --git a/examples/core_3d_camera_free.c b/examples/core_3d_camera_free.c index df1b480c9..4b45373de 100644 --- a/examples/core_3d_camera_free.c +++ b/examples/core_3d_camera_free.c @@ -22,10 +22,10 @@ int main() // Define the camera to look into our 3d world Camera camera; - camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; - camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; - + camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; SetCameraMode(CAMERA_FREE); // Set a free camera mode diff --git a/examples/core_3d_camera_free.png b/examples/core_3d_camera_free.png index afb5a7c50..179206201 100644 Binary files a/examples/core_3d_camera_free.png and b/examples/core_3d_camera_free.png differ diff --git a/examples/core_3d_mode.c b/examples/core_3d_mode.c index 40415feac..7be5dd45a 100644 --- a/examples/core_3d_mode.c +++ b/examples/core_3d_mode.c @@ -22,9 +22,9 @@ int main() // Define the camera to look into our 3d world Camera camera; - camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; - camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; + camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; diff --git a/examples/core_3d_picking.c b/examples/core_3d_picking.c index 9a6cc1383..fdf770300 100644 --- a/examples/core_3d_picking.c +++ b/examples/core_3d_picking.c @@ -21,7 +21,10 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking"); // Define the camera to look into our 3d world - Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera; + camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; diff --git a/examples/core_3d_picking.png b/examples/core_3d_picking.png index 828c41a83..bb7660b0a 100644 Binary files a/examples/core_3d_picking.png and b/examples/core_3d_picking.png differ diff --git a/examples/core_gestures_detection.c b/examples/core_gestures_detection.c new file mode 100644 index 000000000..b69497c52 --- /dev/null +++ b/examples/core_gestures_detection.c @@ -0,0 +1,115 @@ +/******************************************************************************************* +* +* raylib [core] example - Gestures Detection +* +* This example has been created using raylib 1.4 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include + +#define MAX_GESTURE_STRINGS 20 + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - gestures detection"); + + Vector2 touchPosition = { 0, 0 }; + Rectangle touchArea = { 220, 10, screenWidth - 230, screenHeight - 20 }; + + int gesturesCount = 0; + char gestureStrings[MAX_GESTURE_STRINGS][32]; + + int currentGesture = GESTURE_NONE; + int lastGesture = GESTURE_NONE; + + //SetGesturesEnabled(0b0000000000001001); // Enable only some gestures to be detected + + SetTargetFPS(30); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + lastGesture = currentGesture; + touchPosition = GetTouchPosition(0); + + if (CheckCollisionPointRec(touchPosition, touchArea) && IsGestureDetected()) + { + currentGesture = GetGestureType(); + + if (currentGesture != lastGesture) + { + // Store gesture string + switch (currentGesture) + { + case GESTURE_TAP: strcpy(gestureStrings[gesturesCount], "GESTURE TAP"); break; + case GESTURE_DOUBLETAP: strcpy(gestureStrings[gesturesCount], "GESTURE DOUBLETAP"); break; + case GESTURE_HOLD: strcpy(gestureStrings[gesturesCount], "GESTURE HOLD"); break; + case GESTURE_DRAG: strcpy(gestureStrings[gesturesCount], "GESTURE DRAG"); break; + case GESTURE_SWIPE_RIGHT: strcpy(gestureStrings[gesturesCount], "GESTURE SWIPE RIGHT"); break; + case GESTURE_SWIPE_LEFT: strcpy(gestureStrings[gesturesCount], "GESTURE SWIPE LEFT"); break; + case GESTURE_SWIPE_UP: strcpy(gestureStrings[gesturesCount], "GESTURE SWIPE UP"); break; + case GESTURE_SWIPE_DOWN: strcpy(gestureStrings[gesturesCount], "GESTURE SWIPE DOWN"); break; + default: break; + } + + gesturesCount++; + + // Reset gestures strings + if (gesturesCount >= MAX_GESTURE_STRINGS) + { + for (int i = 0; i < MAX_GESTURE_STRINGS; i++) strcpy(gestureStrings[i], "\0"); + + gesturesCount = 0; + } + } + } + else currentGesture = GESTURE_NONE; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawRectangleRec(touchArea, GRAY); + DrawRectangle(225, 15, screenWidth - 240, screenHeight - 30, RAYWHITE); + + DrawText("GESTURES TEST AREA", screenWidth - 270, screenHeight - 40, 20, Fade(GRAY, 0.5f)); + + for (int i = 0; i < gesturesCount; i++) + { + if (i%2 == 0) DrawRectangle(10, 30 + 20*i, 200, 20, Fade(LIGHTGRAY, 0.5f)); + else DrawRectangle(10, 30 + 20*i, 200, 20, Fade(LIGHTGRAY, 0.3f)); + + if (i < gesturesCount - 1) DrawText(gestureStrings[i], 35, 36 + 20*i, 10, DARKGRAY); + else DrawText(gestureStrings[i], 35, 36 + 20*i, 10, MAROON); + } + + DrawRectangleLines(10, 29, 200, screenHeight - 50, GRAY); + DrawText("DETECTED GESTURES", 50, 15, 10, GRAY); + + if (currentGesture != GESTURE_NONE) DrawCircleV(touchPosition, 30, MAROON); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/examples/core_gestures_detection.png b/examples/core_gestures_detection.png new file mode 100644 index 000000000..d2bbb5d7c Binary files /dev/null and b/examples/core_gestures_detection.png differ diff --git a/examples/core_input_mouse.c b/examples/core_input_mouse.c index 358b5fd68..24d2dfcd4 100644 --- a/examples/core_input_mouse.c +++ b/examples/core_input_mouse.c @@ -21,6 +21,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - mouse input"); Vector2 ballPosition = { -100.0f, -100.0f }; + Color ballColor = DARKBLUE; SetTargetFPS(60); //--------------------------------------------------------------------------------------- @@ -30,10 +31,11 @@ int main() { // Update //---------------------------------------------------------------------------------- - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - ballPosition = GetMousePosition(); - } + ballPosition = GetMousePosition(); + + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) ballColor = MAROON; + else if (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) ballColor = LIME; + else if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) ballColor = DARKBLUE; //---------------------------------------------------------------------------------- // Draw @@ -42,9 +44,9 @@ int main() ClearBackground(RAYWHITE); - DrawCircleV(ballPosition, 40, GOLD); + DrawCircleV(ballPosition, 40, ballColor); - DrawText("mouse click to draw the ball", 10, 10, 20, DARKGRAY); + DrawText("move ball with mouse and click mouse button to change color", 10, 10, 20, DARKGRAY); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/core_storage_values.c b/examples/core_storage_values.c index 3190d0a08..43f0882fd 100644 --- a/examples/core_storage_values.c +++ b/examples/core_storage_values.c @@ -5,7 +5,7 @@ * This example has been created using raylib 1.4 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2015 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/examples/makefile b/examples/makefile index 04dc77561..2a9e88ba3 100644 --- a/examples/makefile +++ b/examples/makefile @@ -85,8 +85,8 @@ else # external libraries headers # GLFW3 INCLUDES += -I../external/glfw3/include -# GLEW - INCLUDES += -I../external/glew/include +# GLEW - Not required any more, replaced by GLAD + #INCLUDES += -I../external/glew/include # OpenAL Soft INCLUDES += -I../external/openal_soft/include endif @@ -102,8 +102,8 @@ else ifneq ($(PLATFORM_OS),OSX) # OpenAL Soft LFLAGS += -L../external/openal_soft/lib/$(LIBPATH) - # GLEW - LFLAGS += -L../external/glew/lib/$(LIBPATH) + # GLEW - Not required any more, replaced by GLAD + #LFLAGS += -L../external/glew/lib/$(LIBPATH) endif endif @@ -126,7 +126,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) else # libraries for Windows desktop compiling # NOTE: GLFW3 and OpenAL Soft libraries should be installed - LIBS = -lraylib -lglfw3 -lglew32 -lopengl32 -lopenal32 -lgdi32 + LIBS = -lraylib -lglfw3 -lopengl32 -lopenal32 -lgdi32 endif endif endif @@ -161,6 +161,8 @@ EXAMPLES = \ core_random_values \ core_color_select \ core_drop_files \ + core_storage_values \ + core_gestures_detection \ core_3d_mode \ core_3d_picking \ core_3d_camera_free \ @@ -177,10 +179,14 @@ EXAMPLES = \ textures_raw_data \ textures_formats_loading \ textures_particles_trail_blending \ + textures_image_processing \ + textures_image_drawing \ text_sprite_fonts \ + text_bmfont_ttf \ text_rbmf_fonts \ text_format_text \ text_font_select \ + text_writing_anim \ models_geometric_shapes \ models_box_collisions \ models_billboard \ @@ -195,8 +201,6 @@ EXAMPLES = \ audio_music_stream \ fix_dylib \ - #core_input_gamepad \ - # typing 'make' will invoke the first target entry in the file, # in this case, the 'default' target entry is raylib @@ -217,32 +221,44 @@ core_input_keys: core_input_keys.c core_input_mouse: core_input_mouse.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) -# compile [core] example - gamepad input -core_input_gamepad: core_input_gamepad.c -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) -else - @echo core_input_gamepad: Only supported on desktop platform -endif - # compile [core] example - mouse wheel core_mouse_wheel: core_mouse_wheel.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) +# compile [core] example - gamepad input +core_input_gamepad: core_input_gamepad.c +ifeq ($(PLATFORM), $(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_RPI)) + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) +else + @echo core_input_gamepad: Example not supported on PLATFORM_ANDROID or PLATFORM_WEB +endif + +# compile [core] example - generate random values +core_random_values: core_random_values.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile [core] example - color selection (collision detection) +core_color_select: core_color_select.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + # compile [core] example - drop files core_drop_files: core_drop_files.c ifeq ($(PLATFORM),PLATFORM_DESKTOP) $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) else - @echo core_drop_files: Only supported on desktop platform + @echo core_drop_files: Example not supported on PLATFORM_ANDROID or PLATFORM_WEB or PLATFORM_RPI endif - -# compile [core] example - generate random values -core_random_values: core_random_values.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) -# compile [core] example - color selection (collision detection) -core_color_select: core_color_select.c +# compile [core] example - storage values +core_storage_values: core_storage_values.c +ifeq ($(PLATFORM), $(filter $(PLATFORM),PLATFORM_DESKTOP PLATFORM_RPI)) + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) +else + @echo core_storage_values: Example not supported on PLATFORM_ANDROID or PLATFORM_WEB +endif + +# compile [core] example - gestures detection +core_gestures_detection: core_gestures_detection.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) # compile [core] example - 3d mode @@ -309,9 +325,21 @@ textures_formats_loading: textures_formats_loading.c textures_particles_trail_blending: textures_particles_trail_blending.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) +# compile [textures] example - texture image processing +textures_image_processing: textures_image_processing.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile [textures] example - texture image drawing +textures_image_drawing: textures_image_drawing.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + # compile [text] example - sprite fonts loading text_sprite_fonts: text_sprite_fonts.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile [text] example - bmfonts and ttf loading +text_bmfont_ttf: text_bmfont_ttf.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) # compile [text] example - raylib bitmap fonts (rBMF) text_rbmf_fonts: text_rbmf_fonts.c @@ -325,6 +353,10 @@ text_format_text: text_format_text.c text_font_select: text_font_select.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) +# compile [text] example - text writing animation +text_writing_anim: text_writing_anim.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + # compile [models] example - basic geometric 3d shapes models_geometric_shapes: models_geometric_shapes.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) diff --git a/examples/models_billboard.png b/examples/models_billboard.png index f1ed92399..dad1e55b7 100644 Binary files a/examples/models_billboard.png and b/examples/models_billboard.png differ diff --git a/examples/models_heightmap.c b/examples/models_heightmap.c index ac578c614..f1da33019 100644 --- a/examples/models_heightmap.c +++ b/examples/models_heightmap.c @@ -21,13 +21,13 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing"); // Define our custom camera to look into our 3d world - Camera camera = {{ 24.0f, 18.0f, 24.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 18.0f, 16.0f, 18.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; - Image image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM) - Texture2D texture = LoadTextureFromImage(image); // Convert image to texture (VRAM) - Model map = LoadHeightmap(image, 32); // Load heightmap model - SetModelTexture(&map, texture); // Bind texture to model - Vector3 mapPosition = { -16.0f, 0.0f, -16.0f }; // Set model position (depends on model scaling!) + Image image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM) + Texture2D texture = LoadTextureFromImage(image); // Convert image to texture (VRAM) + Model map = LoadHeightmap(image, (Vector3){ 16, 8, 16 }); // Load heightmap model with defined size + SetModelTexture(&map, texture); // Bind texture to model + Vector3 mapPosition = { -8.0f, 0.0f, -8.0f }; // Set model position (depends on model scaling!) UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM @@ -54,7 +54,9 @@ int main() Begin3dMode(camera); // NOTE: Model is scaled to 1/4 of its original size (128x128 units) - DrawModel(map, mapPosition, 1/4.0f, RED); + DrawModel(map, mapPosition, 1.0f, RED); + + DrawGrid(20, 1.0f); End3dMode(); diff --git a/examples/models_heightmap.png b/examples/models_heightmap.png index 9ed04586e..6dcf01f05 100644 Binary files a/examples/models_heightmap.png and b/examples/models_heightmap.png differ diff --git a/examples/physics_basic_rigidbody.c b/examples/physics_basic_rigidbody.c index b82fe638c..6c354eb73 100644 --- a/examples/physics_basic_rigidbody.c +++ b/examples/physics_basic_rigidbody.c @@ -2,20 +2,10 @@ * * raylib [physac] physics example - Basic rigidbody * -* Welcome to raylib! -* -* To test examples, just press F6 and execute raylib_compile_execute script -* Note that compiled executable is placed in the same folder as .c file -* -* You can find all basic examples on C:\raylib\raylib\examples folder or -* raylib official webpage: www.raylib.com -* -* Enjoy using raylib. :) -* -* This example has been created using raylib 1.3 (www.raylib.com) +* This example has been created using raylib 1.4 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* Copyright (c) 2016 Victor Fisac and Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -33,13 +23,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [physics] example - basic rigidbody"); - InitPhysics(); // Initialize internal physics values (max rigidbodies/colliders available: 1024) - - // Physics initialization - Physics worldPhysics = { true, false, (Vector2){ 0, -9.81f } }; - - // Set internal physics settings - SetPhysics(worldPhysics); + InitPhysics(3); // Initialize physics system with maximum physic objects // Object initialization Transform player = (Transform){(Vector2){(screenWidth - OBJECT_SIZE) / 2, (screenHeight - OBJECT_SIZE) / 2}, 0.0f, (Vector2){OBJECT_SIZE, OBJECT_SIZE}}; @@ -55,6 +39,8 @@ int main() float moveSpeed = 6.0f; float jumpForce = 5.0f; + bool physicsDebug = false; + SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -91,14 +77,7 @@ int main() } // Check debug mode toggle button input - if(IsKeyPressed(KEY_P)) - { - // Update program physics value - worldPhysics.debug = !worldPhysics.debug; - - // Update internal physics value - SetPhysics(worldPhysics); - } + if (IsKeyPressed(KEY_P)) physicsDebug = !physicsDebug; //---------------------------------------------------------------------------------- // Draw @@ -112,7 +91,7 @@ int main() DrawText("Use P to switch DEBUG MODE", (screenWidth - MeasureText("Use P to switch DEBUG MODE", 20)) / 2, screenHeight * 0.3f, 20, LIGHTGRAY); // Check if debug mode is enabled - if (worldPhysics.debug) + if (physicsDebug) { // Draw every internal physics stored collider if it is active for (int i = 0; i < 2; i++) @@ -122,14 +101,11 @@ int main() DrawRectangleLines(GetCollider(i).bounds.x, GetCollider(i).bounds.y, GetCollider(i).bounds.width, GetCollider(i).bounds.height, GREEN); } } - } else { - // Draw player + // Draw player and floor DrawRectangleRec((Rectangle){player.position.x, player.position.y, player.scale.x, player.scale.y}, GRAY); - - // Draw floor DrawRectangleRec((Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, BLACK); } @@ -138,7 +114,9 @@ int main() } // De-Initialization - //-------------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------------- + UnloadPhysics(); // Unload physic objects + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/physics_rigidbody_force.c b/examples/physics_rigidbody_force.c index 3ac560c51..74a88a970 100644 --- a/examples/physics_rigidbody_force.c +++ b/examples/physics_rigidbody_force.c @@ -2,10 +2,10 @@ * * raylib [physac] physics example - Rigidbody forces * -* This example has been created using raylib 1.3 (www.raylib.com) +* This example has been created using raylib 1.4 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2016 Victor Fisac and Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -26,15 +26,9 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [physics] example - rigidbodies forces"); - InitPhysics(); // Initialize internal physics values (max rigidbodies/colliders available: 1024) + InitPhysics(MAX_OBJECTS + 1); // Initialize physics system with maximum physic objects - // Physics initialization - Physics worldPhysics = {true, false, (Vector2){0, -9.81f}}; - - // Set internal physics settings - SetPhysics(worldPhysics); - - // Objects initialization + // Physic Objects initialization Transform objects[MAX_OBJECTS]; for (int i = 0; i < MAX_OBJECTS; i++) @@ -49,6 +43,8 @@ int main() Transform floor = (Transform){(Vector2){0, screenHeight * 0.8f}, 0.0f, (Vector2){screenWidth, screenHeight * 0.2f}}; AddCollider(MAX_OBJECTS, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0}); + bool physicsDebug = false; + SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -72,14 +68,7 @@ int main() } // Check debug mode toggle button input - if (IsKeyPressed(KEY_P)) - { - // Update program physics value - worldPhysics.debug = !worldPhysics.debug; - - // Update internal physics value - SetPhysics(worldPhysics); - } + if (IsKeyPressed(KEY_P)) physicsDebug = !physicsDebug; //---------------------------------------------------------------------------------- // Draw @@ -89,10 +78,10 @@ int main() ClearBackground(RAYWHITE); // Check if debug mode is enabled - if (worldPhysics.debug) + if (physicsDebug) { // Draw every internal physics stored collider if it is active (floor included) - for (int i = 0; i < MAX_OBJECTS + 1; i++) + for (int i = 0; i < MAX_OBJECTS; i++) { if (GetCollider(i).enabled) { @@ -136,7 +125,9 @@ int main() } // De-Initialization - //-------------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------------- + UnloadPhysics(); // Unload physic objects + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/resources/cat.png b/examples/resources/cat.png new file mode 100644 index 000000000..d023aa218 Binary files /dev/null and b/examples/resources/cat.png differ diff --git a/examples/resources/fonts/bmfont.fnt b/examples/resources/fonts/bmfont.fnt new file mode 100644 index 000000000..372c2c886 --- /dev/null +++ b/examples/resources/fonts/bmfont.fnt @@ -0,0 +1,99 @@ +info face="Arial Black" size=-32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=2,2 outline=0 +common lineHeight=45 base=35 scaleW=512 scaleH=256 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4 +page id=0 file="bmfont.png" +chars count=95 +char id=32 x=423 y=141 width=3 height=45 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=15 +char id=33 x=323 y=141 width=9 height=45 xoffset=1 yoffset=0 xadvance=11 page=0 chnl=15 +char id=34 x=123 y=141 width=16 height=45 xoffset=0 yoffset=0 xadvance=16 page=0 chnl=15 +char id=35 x=221 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=36 x=244 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=37 x=70 y=0 width=30 height=45 xoffset=1 yoffset=0 xadvance=32 page=0 chnl=15 +char id=38 x=390 y=0 width=25 height=45 xoffset=2 yoffset=0 xadvance=28 page=0 chnl=15 +char id=39 x=378 y=141 width=8 height=45 xoffset=1 yoffset=0 xadvance=9 page=0 chnl=15 +char id=40 x=222 y=141 width=11 height=45 xoffset=1 yoffset=0 xadvance=12 page=0 chnl=15 +char id=41 x=499 y=94 width=11 height=45 xoffset=1 yoffset=0 xadvance=12 page=0 chnl=15 +char id=42 x=497 y=47 width=13 height=45 xoffset=2 yoffset=0 xadvance=18 page=0 chnl=15 +char id=43 x=394 y=94 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=44 x=367 y=141 width=9 height=45 xoffset=1 yoffset=0 xadvance=11 page=0 chnl=15 +char id=45 x=261 y=141 width=11 height=45 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=15 +char id=46 x=356 y=141 width=9 height=45 xoffset=1 yoffset=0 xadvance=11 page=0 chnl=15 +char id=47 x=248 y=141 width=11 height=45 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=15 +char id=48 x=382 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=49 x=496 y=0 width=14 height=45 xoffset=2 yoffset=0 xadvance=21 page=0 chnl=15 +char id=50 x=134 y=94 width=20 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=51 x=359 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=52 x=313 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=53 x=336 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=54 x=178 y=94 width=20 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=55 x=478 y=94 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=56 x=290 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=57 x=90 y=94 width=20 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=58 x=345 y=141 width=9 height=45 xoffset=1 yoffset=0 xadvance=11 page=0 chnl=15 +char id=59 x=334 y=141 width=9 height=45 xoffset=1 yoffset=0 xadvance=11 page=0 chnl=15 +char id=60 x=0 y=141 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=61 x=21 y=141 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=62 x=310 y=94 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=63 x=352 y=94 width=19 height=45 xoffset=1 yoffset=0 xadvance=20 page=0 chnl=15 +char id=64 x=279 y=0 width=26 height=45 xoffset=-1 yoffset=0 xadvance=24 page=0 chnl=15 +char id=65 x=193 y=0 width=27 height=45 xoffset=-1 yoffset=0 xadvance=25 page=0 chnl=15 +char id=66 x=150 y=47 width=22 height=45 xoffset=2 yoffset=0 xadvance=25 page=0 chnl=15 +char id=67 x=444 y=0 width=24 height=45 xoffset=1 yoffset=0 xadvance=25 page=0 chnl=15 +char id=68 x=174 y=47 width=22 height=45 xoffset=2 yoffset=0 xadvance=25 page=0 chnl=15 +char id=69 x=156 y=94 width=20 height=45 xoffset=2 yoffset=0 xadvance=23 page=0 chnl=15 +char id=70 x=63 y=141 width=18 height=45 xoffset=2 yoffset=0 xadvance=21 page=0 chnl=15 +char id=71 x=417 y=0 width=25 height=45 xoffset=1 yoffset=0 xadvance=27 page=0 chnl=15 +char id=72 x=125 y=47 width=23 height=45 xoffset=2 yoffset=0 xadvance=27 page=0 chnl=15 +char id=73 x=388 y=141 width=8 height=45 xoffset=2 yoffset=0 xadvance=12 page=0 chnl=15 +char id=74 x=200 y=94 width=20 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=75 x=251 y=0 width=26 height=45 xoffset=2 yoffset=0 xadvance=27 page=0 chnl=15 +char id=76 x=373 y=94 width=19 height=45 xoffset=2 yoffset=0 xadvance=21 page=0 chnl=15 +char id=77 x=134 y=0 width=28 height=45 xoffset=1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=78 x=100 y=47 width=23 height=45 xoffset=2 yoffset=0 xadvance=27 page=0 chnl=15 +char id=79 x=363 y=0 width=25 height=45 xoffset=1 yoffset=0 xadvance=27 page=0 chnl=15 +char id=80 x=112 y=94 width=20 height=45 xoffset=2 yoffset=0 xadvance=23 page=0 chnl=15 +char id=81 x=335 y=0 width=26 height=45 xoffset=1 yoffset=0 xadvance=27 page=0 chnl=15 +char id=82 x=470 y=0 width=24 height=45 xoffset=2 yoffset=0 xadvance=25 page=0 chnl=15 +char id=83 x=75 y=47 width=23 height=45 xoffset=0 yoffset=0 xadvance=23 page=0 chnl=15 +char id=84 x=50 y=47 width=23 height=45 xoffset=0 yoffset=0 xadvance=23 page=0 chnl=15 +char id=85 x=25 y=47 width=23 height=45 xoffset=2 yoffset=0 xadvance=27 page=0 chnl=15 +char id=86 x=307 y=0 width=26 height=45 xoffset=0 yoffset=0 xadvance=25 page=0 chnl=15 +char id=87 x=0 y=0 width=34 height=45 xoffset=-1 yoffset=0 xadvance=32 page=0 chnl=15 +char id=88 x=222 y=0 width=27 height=45 xoffset=-1 yoffset=0 xadvance=25 page=0 chnl=15 +char id=89 x=164 y=0 width=27 height=45 xoffset=-1 yoffset=0 xadvance=25 page=0 chnl=15 +char id=90 x=0 y=47 width=23 height=45 xoffset=0 yoffset=0 xadvance=23 page=0 chnl=15 +char id=91 x=274 y=141 width=11 height=45 xoffset=1 yoffset=0 xadvance=12 page=0 chnl=15 +char id=92 x=300 y=141 width=10 height=45 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=15 +char id=93 x=287 y=141 width=11 height=45 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=15 +char id=94 x=457 y=94 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=95 x=103 y=141 width=18 height=45 xoffset=-1 yoffset=0 xadvance=16 page=0 chnl=15 +char id=96 x=312 y=141 width=9 height=45 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=15 +char id=97 x=474 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=98 x=68 y=94 width=20 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=99 x=267 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=100 x=46 y=94 width=20 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=101 x=198 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=102 x=141 y=141 width=15 height=45 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=15 +char id=103 x=222 y=94 width=20 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=104 x=415 y=94 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=105 x=398 y=141 width=7 height=45 xoffset=2 yoffset=0 xadvance=11 page=0 chnl=15 +char id=106 x=235 y=141 width=11 height=45 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=15 +char id=107 x=405 y=47 width=21 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=108 x=407 y=141 width=7 height=45 xoffset=2 yoffset=0 xadvance=11 page=0 chnl=15 +char id=109 x=102 y=0 width=30 height=45 xoffset=1 yoffset=0 xadvance=32 page=0 chnl=15 +char id=110 x=331 y=94 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=111 x=428 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=112 x=266 y=94 width=20 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=113 x=288 y=94 width=20 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=114 x=158 y=141 width=15 height=45 xoffset=1 yoffset=0 xadvance=14 page=0 chnl=15 +char id=115 x=244 y=94 width=20 height=45 xoffset=0 yoffset=0 xadvance=20 page=0 chnl=15 +char id=116 x=175 y=141 width=14 height=45 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=15 +char id=117 x=436 y=94 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 +char id=118 x=451 y=47 width=21 height=45 xoffset=0 yoffset=0 xadvance=20 page=0 chnl=15 +char id=119 x=36 y=0 width=32 height=45 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=120 x=0 y=94 width=21 height=45 xoffset=0 yoffset=0 xadvance=21 page=0 chnl=15 +char id=121 x=23 y=94 width=21 height=45 xoffset=0 yoffset=0 xadvance=20 page=0 chnl=15 +char id=122 x=83 y=141 width=18 height=45 xoffset=0 yoffset=0 xadvance=18 page=0 chnl=15 +char id=123 x=191 y=141 width=14 height=45 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=15 +char id=124 x=416 y=141 width=5 height=45 xoffset=2 yoffset=0 xadvance=9 page=0 chnl=15 +char id=125 x=207 y=141 width=13 height=45 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=15 +char id=126 x=42 y=141 width=19 height=45 xoffset=1 yoffset=0 xadvance=21 page=0 chnl=15 diff --git a/examples/resources/fonts/bmfont.png b/examples/resources/fonts/bmfont.png new file mode 100644 index 000000000..9d621594a Binary files /dev/null and b/examples/resources/fonts/bmfont.png differ diff --git a/examples/resources/fonts/pixantiqua.ttf b/examples/resources/fonts/pixantiqua.ttf new file mode 100644 index 000000000..e012875da Binary files /dev/null and b/examples/resources/fonts/pixantiqua.ttf differ diff --git a/examples/resources/parrots.png b/examples/resources/parrots.png new file mode 100644 index 000000000..d6ec60ba3 Binary files /dev/null and b/examples/resources/parrots.png differ diff --git a/examples/resources/shaders/phong.vs b/examples/resources/shaders/phong.vs index ee6d34bfa..52cc22279 100644 --- a/examples/resources/shaders/phong.vs +++ b/examples/resources/shaders/phong.vs @@ -7,7 +7,9 @@ in vec3 vertexNormal; // Projection and model data uniform mat4 mvpMatrix; + uniform mat4 modelMatrix; +//uniform mat4 viewMatrix; // Not used // Attributes to fragment shader out vec2 fragTexCoord; diff --git a/examples/resources/shaders/shapes_base.vs b/examples/resources/shaders/shapes_base.vs index 1fd686beb..ad272dc17 100644 --- a/examples/resources/shaders/shapes_base.vs +++ b/examples/resources/shaders/shapes_base.vs @@ -1,4 +1,4 @@ -#version 110 +#version 330 attribute vec3 vertexPosition; attribute vec2 vertexTexCoord; diff --git a/examples/resources/shaders/shapes_grayscale.fs b/examples/resources/shaders/shapes_grayscale.fs index 23ba91539..0698e1bf1 100644 --- a/examples/resources/shaders/shapes_grayscale.fs +++ b/examples/resources/shaders/shapes_grayscale.fs @@ -1,4 +1,4 @@ -#version 110 +#version 330 uniform sampler2D texture0; varying vec2 fragTexCoord; diff --git a/examples/shaders_basic_lighting.c b/examples/shaders_basic_lighting.c index ba779b94f..84bd1af42 100644 --- a/examples/shaders_basic_lighting.c +++ b/examples/shaders_basic_lighting.c @@ -14,6 +14,17 @@ #define SHININESS_SPEED 1.0f #define LIGHT_SPEED 0.25f +// Light type +typedef struct Light { + Vector3 position; + Vector3 direction; + float intensity; + float specIntensity; + Color diffuse; + Color ambient; + Color specular; +} Light; + int main() { // Initialization @@ -48,6 +59,10 @@ int main() int cameraLoc = GetShaderLocation(shader, "cameraPos"); int lightLoc = GetShaderLocation(shader, "lightPos"); + // Model and View matrix locations (required for lighting) + int modelLoc = GetShaderLocation(shader, "modelMatrix"); + //int viewLoc = GetShaderLocation(shader, "viewMatrix"); // Not used + // Light and material definitions Light light; Material matBlinn; @@ -62,9 +77,9 @@ int main() light.specIntensity = 1.0f; // Material initialization - matBlinn.diffuse = WHITE; - matBlinn.ambient = (Color){ 50, 50, 50, 255 }; - matBlinn.specular = WHITE; + matBlinn.colDiffuse = WHITE; + matBlinn.colAmbient = (Color){ 50, 50, 50, 255 }; + matBlinn.colSpecular = WHITE; matBlinn.glossiness = 50.0f; // Setup camera @@ -82,6 +97,10 @@ int main() //---------------------------------------------------------------------------------- UpdateCamera(&camera); // Update camera position + // NOTE: Model transform can be set in model.transform or directly with params at draw... WATCH OUT! + SetShaderValueMatrix(shader, modelLoc, model.transform); // Send model matrix to shader + //SetShaderValueMatrix(shader, viewLoc, GetCameraMatrix(camera)); // Not used + // Glossiness input control if(IsKeyDown(KEY_UP)) matBlinn.glossiness += SHININESS_SPEED; else if(IsKeyDown(KEY_DOWN)) @@ -110,8 +129,8 @@ int main() SetShaderValue(shader, lSpecIntensityLoc, &light.specIntensity, 1); // Send material values to shader - SetShaderValue(shader, mAmbientLoc, ColorToFloat(matBlinn.ambient), 3); - SetShaderValue(shader, mSpecularLoc, ColorToFloat(matBlinn.specular), 3); + SetShaderValue(shader, mAmbientLoc, ColorToFloat(matBlinn.colAmbient), 3); + SetShaderValue(shader, mSpecularLoc, ColorToFloat(matBlinn.colSpecular), 3); SetShaderValue(shader, mGlossLoc, &matBlinn.glossiness, 1); // Send camera and light transform values to shader @@ -127,7 +146,7 @@ int main() Begin3dMode(camera); - DrawModel(model, position, 4.0f, matBlinn.diffuse); + DrawModel(model, position, 4.0f, matBlinn.colDiffuse); DrawSphere(light.position, 0.5f, GOLD); DrawGrid(20, 1.0f); diff --git a/examples/shapes_logo_raylib_anim.c b/examples/shapes_logo_raylib_anim.c index b1bdc3a8c..c6d3796e6 100644 --- a/examples/shapes_logo_raylib_anim.c +++ b/examples/shapes_logo_raylib_anim.c @@ -2,7 +2,7 @@ * * raylib [shapes] example - raylib logo animation * -* This example has been created using raylib 1.1 (www.raylib.com) +* This example has been created using raylib 1.4 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * * Copyright (c) 2014 Ramon Santamaria (@raysan5) @@ -32,8 +32,6 @@ int main() int bottomSideRecWidth = 16; int rightSideRecHeight = 16; - char raylib[8] = " \0"; // raylib text array, max 8 letters - int state = 0; // Tracking animation states (State Machine) float alpha = 1.0f; // Useful for fading @@ -79,24 +77,13 @@ int main() framesCounter = 0; } - switch (lettersCount) - { - case 1: raylib[0] = 'r'; break; - case 2: raylib[1] = 'a'; break; - case 3: raylib[2] = 'y'; break; - case 4: raylib[3] = 'l'; break; - case 5: raylib[4] = 'i'; break; - case 6: raylib[5] = 'b'; break; - default: break; - } - if (lettersCount >= 10) // When all letters have appeared, just fade out everything { - alpha -= 0.02; + alpha -= 0.02f; - if (alpha <= 0) + if (alpha <= 0.0f) { - alpha = 0; + alpha = 0.0f; state = 4; } } @@ -114,12 +101,7 @@ int main() bottomSideRecWidth = 16; rightSideRecHeight = 16; - for (int i = 0; i < 7; i++) raylib[i] = ' '; - - raylib[7] = '\0'; // Last character is end-of-line - - alpha = 1.0; - + alpha = 1.0f; state = 0; // Return to State 0 } } @@ -158,7 +140,7 @@ int main() DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); - DrawText(raylib, screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha)); + DrawText(SubText("raylib", 0, lettersCount), screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha)); } else if (state == 4) { diff --git a/examples/text_bmfont_ttf.c b/examples/text_bmfont_ttf.c new file mode 100644 index 000000000..caece548d --- /dev/null +++ b/examples/text_bmfont_ttf.c @@ -0,0 +1,68 @@ +/******************************************************************************************* +* +* raylib [text] example - BMFont and TTF SpriteFonts loading +* +* This example has been created using raylib 1.4 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [text] example - bmfont and ttf sprite fonts loading"); + + const char msgBm[64] = "THIS IS AN AngelCode SPRITE FONT"; + const char msgTtf[64] = "THIS SPRITE FONT has been GENERATED from a TTF"; + + // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) + SpriteFont fontBm = LoadSpriteFont("resources/fonts/bmfont.fnt"); // BMFont (AngelCode) + SpriteFont fontTtf = LoadSpriteFont("resources/fonts/pixantiqua.ttf"); // TTF font + + Vector2 fontPosition; + + fontPosition.x = screenWidth/2 - MeasureTextEx(fontBm, msgBm, fontBm.size, 0).x/2; + fontPosition.y = screenHeight/2 - fontBm.size/2 - 80; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // TODO: Update variables here... + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawTextEx(fontBm, msgBm, fontPosition, fontBm.size, 0, MAROON); + DrawTextEx(fontTtf, msgTtf, (Vector2){ 75.0f, 240.0f }, fontTtf.size*0.8f, 2, LIME); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadSpriteFont(fontBm); // AngelCode SpriteFont unloading + UnloadSpriteFont(fontTtf); // TTF SpriteFont unloading + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/text_bmfont_ttf.png b/examples/text_bmfont_ttf.png new file mode 100644 index 000000000..8305d36b8 Binary files /dev/null and b/examples/text_bmfont_ttf.png differ diff --git a/examples/text_writing_anim.c b/examples/text_writing_anim.c new file mode 100644 index 000000000..5f19b4682 --- /dev/null +++ b/examples/text_writing_anim.c @@ -0,0 +1,60 @@ +/******************************************************************************************* +* +* raylib [text] example - Text Writing Animation +* +* This example has been created using raylib 1.4 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [text] example - text writing anim"); + + const char message[128] = "This sample illustrates a text writing\nanimation effect! Check it out! ;)"; + + int framesCounter = 0; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + framesCounter++; + + if (IsKeyPressed(KEY_ENTER)) framesCounter = 0; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText(SubText(message, 0, framesCounter/10), 210, 160, 20, MAROON); + + DrawText("PRESS [ENTER] to RESTART!", 240, 280, 20, LIGHTGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/text_writing_anim.png b/examples/text_writing_anim.png new file mode 100644 index 000000000..d6752dd88 Binary files /dev/null and b/examples/text_writing_anim.png differ diff --git a/examples/textures_formats_loading.png b/examples/textures_formats_loading.png index 4cdb2f13b..6778080f4 100644 Binary files a/examples/textures_formats_loading.png and b/examples/textures_formats_loading.png differ diff --git a/examples/textures_image_drawing.c b/examples/textures_image_drawing.c new file mode 100644 index 000000000..1c6a1fb95 --- /dev/null +++ b/examples/textures_image_drawing.c @@ -0,0 +1,78 @@ +/******************************************************************************************* +* +* raylib [textures] example - Image loading and drawing on it +* +* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM) +* +* This example has been created using raylib 1.4 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [textures] example - image drawing"); + + // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) + + Image cat = LoadImage("resources/cat.png"); // Load image in CPU memory (RAM) + ImageCrop(&cat, (Rectangle){ 100, 10, 280, 380 }); // Crop an image piece + ImageFlipHorizontal(&cat); // Flip cropped image horizontally + ImageResize(&cat, 150, 200); // Resize flipped-cropped image + + Image parrots = LoadImage("resources/parrots.png"); // Load image in CPU memory (RAM) + + // Draw one image over the other with a scaling of 1.5f + ImageDraw(&parrots, cat, (Rectangle){ 0, 0, cat.width, cat.height }, (Rectangle){ 30, 40, cat.width*1.5f, cat.height*1.5f }); + ImageCrop(&parrots, (Rectangle){ 0, 50, parrots.width, parrots.height - 100 }); // Crop resulting image + + UnloadImage(cat); // Unload image from RAM + + Texture2D texture = LoadTextureFromImage(parrots); // Image converted to texture, uploaded to GPU memory (VRAM) + UnloadImage(parrots); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM + + SetTargetFPS(60); + //--------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawTexture(texture, screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2 - 40, WHITE); + DrawRectangleLines(screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2 - 40, texture.width, texture.height, DARKGRAY); + + DrawText("We are drawing only one texture from various images composed!", 240, 350, 10, DARKGRAY); + DrawText("Source images have been cropped, scaled, flipped and copied one over the other.", 190, 370, 10, DARKGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTexture(texture); // Texture unloading + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/textures_image_drawing.png b/examples/textures_image_drawing.png new file mode 100644 index 000000000..acfee069a Binary files /dev/null and b/examples/textures_image_drawing.png differ diff --git a/examples/textures_image_processing.c b/examples/textures_image_processing.c new file mode 100644 index 000000000..58b746e01 --- /dev/null +++ b/examples/textures_image_processing.c @@ -0,0 +1,154 @@ +/******************************************************************************************* +* +* raylib [textures] example - Image processing +* +* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM) +* +* This example has been created using raylib 1.4 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include // Required for: free() + +#define NUM_PROCESSES 8 + +typedef enum { + NONE = 0, + COLOR_GRAYSCALE, + COLOR_TINT, + COLOR_INVERT, + COLOR_CONTRAST, + COLOR_BRIGHTNESS, + FLIP_VERTICAL, + FLIP_HORIZONTAL +} ImageProcess; + +static const char *processText[] = { + "NO PROCESSING", + "COLOR GRAYSCALE", + "COLOR TINT", + "COLOR INVERT", + "COLOR CONTRAST", + "COLOR BRIGHTNESS", + "FLIP VERTICAL", + "FLIP HORIZONTAL" +}; + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [textures] example - image processing"); + + // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) + + Image image = LoadImage("resources/parrots.png"); // Loaded in CPU memory (RAM) + ImageFormat(&image, UNCOMPRESSED_R8G8B8A8); // Format image to RGBA 32bit (required for texture update) + Texture2D texture = LoadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM) + + int currentProcess = NONE; + bool textureReload = false; + + Rectangle selectRecs[NUM_PROCESSES]; + + for (int i = 0; i < NUM_PROCESSES; i++) selectRecs[i] = (Rectangle){ 40, 50 + 32*i, 150, 30 }; + + SetTargetFPS(60); + //--------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + if (IsKeyPressed(KEY_DOWN)) + { + currentProcess++; + if (currentProcess > 7) currentProcess = 0; + textureReload = true; + } + else if (IsKeyPressed(KEY_UP)) + { + currentProcess--; + if (currentProcess < 0) currentProcess = 7; + textureReload = true; + } + + if (textureReload) + { + UnloadImage(image); // Unload current image data + image = LoadImage("resources/parrots.png"); // Re-load image data + + // NOTE: Image processing is a costly CPU process to be done every frame, + // If image processing is required in a frame-basis, it should be done + // with a texture and by shaders + switch (currentProcess) + { + case COLOR_GRAYSCALE: ImageColorGrayscale(&image); break; + case COLOR_TINT: ImageColorTint(&image, GREEN); break; + case COLOR_INVERT: ImageColorInvert(&image); break; + case COLOR_CONTRAST: ImageColorContrast(&image, -40); break; + case COLOR_BRIGHTNESS: ImageColorBrightness(&image, -80); break; + case FLIP_VERTICAL: ImageFlipVertical(&image); break; + case FLIP_HORIZONTAL: ImageFlipHorizontal(&image); break; + default: break; + } + + Color *pixels = GetImageData(image); // Get pixel data from image (RGBA 32bit) + UpdateTexture(texture, pixels); // Update texture with new image data + free(pixels); // Unload pixels data from RAM + + textureReload = false; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("IMAGE PROCESSING:", 40, 30, 10, DARKGRAY); + + // Draw rectangles + for (int i = 0; i < NUM_PROCESSES; i++) + { + if (i == currentProcess) + { + DrawRectangleRec(selectRecs[i], SKYBLUE); + DrawRectangleLines(selectRecs[i].x, selectRecs[i].y, selectRecs[i].width, selectRecs[i].height, BLUE); + DrawText(processText[i], selectRecs[i].x + selectRecs[i].width/2 - MeasureText(processText[i], 10)/2, selectRecs[i].y + 11, 10, DARKBLUE); + } + else + { + DrawRectangleRec(selectRecs[i], LIGHTGRAY); + DrawRectangleLines(selectRecs[i].x, selectRecs[i].y, selectRecs[i].width, selectRecs[i].height, GRAY); + DrawText(processText[i], selectRecs[i].x + selectRecs[i].width/2 - MeasureText(processText[i], 10)/2, selectRecs[i].y + 11, 10, DARKGRAY); + } + } + + DrawTexture(texture, screenWidth - texture.width - 60, screenHeight/2 - texture.height/2, WHITE); + DrawRectangleLines(screenWidth - texture.width - 60, screenHeight/2 - texture.height/2, texture.width, texture.height, BLACK); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTexture(texture); // Unload texture from VRAM + UnloadImage(image); // Unload image from RAM + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/textures_image_processing.png b/examples/textures_image_processing.png new file mode 100644 index 000000000..c15e19f9a Binary files /dev/null and b/examples/textures_image_processing.png differ diff --git a/examples/textures_srcrec_dstrec.c b/examples/textures_srcrec_dstrec.c index 589174213..6d824ce61 100644 --- a/examples/textures_srcrec_dstrec.c +++ b/examples/textures_srcrec_dstrec.c @@ -55,6 +55,10 @@ int main() ClearBackground(RAYWHITE); // NOTE: Using DrawTexturePro() we can easily rotate and scale the part of the texture we draw + // sourceRec defines the part of the texture we use for drawing + // destRec defines the rectangle where our texture part will fit (scaling it to fit) + // origin defines the point of the texture used as reference for rotation and scaling + // rotation defines the texture rotation (using origin as rotation point) DrawTexturePro(guybrush, sourceRec, destRec, origin, rotation, WHITE); DrawLine(destRec.x, 0, destRec.x, screenHeight, GRAY); diff --git a/games/arkanoid.c b/games/arkanoid.c new file mode 100644 index 000000000..f10f93833 --- /dev/null +++ b/games/arkanoid.c @@ -0,0 +1,349 @@ +/******************************************************************************************* +* +* raylib - sample game: arkanoid +* +* Sample game Marc Palau and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include +#include +#include +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- + +#define PLAYER_MAX_LIFE 5 +#define LINES_OF_BRICKS 5 +#define BRICKS_PER_LINE 20 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum GameScreen { LOGO, TITLE, GAMEPLAY, ENDING } GameScreen; + +typedef struct Player { + Vector2 position; + Vector2 size; + int life; +} Player; + +typedef struct Ball { + Vector2 position; + Vector2 speed; + int radius; + bool active; +} Ball; + +typedef struct Brick { + Vector2 position; + bool active; +} Brick; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter; +static bool gameOver; +static bool pause; + +static Player player; +static Ball ball; +static Brick brick[LINES_OF_BRICKS][BRICKS_PER_LINE]; +static Vector2 brickSize; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +// Additional module functions +static void UpdateBall(void); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: arkanoid"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +void InitGame(void) +{ + brickSize = (Vector2){ GetScreenWidth()/BRICKS_PER_LINE, 40 }; + + // Initialize player + player.position = (Vector2){ screenWidth/2, screenHeight*7/8 }; + player.size = (Vector2){ screenWidth/10, 20 }; + player.life = PLAYER_MAX_LIFE; + + // Initialize ball + ball.position = (Vector2){ screenWidth/2, screenHeight*7/8 - 30 }; + ball.speed = (Vector2){ 0, 0 }; + ball.radius = 7; + ball.active = false; + + // Initialize bricks + int initialDownPosition = 50; + + for (int i = 0; i < LINES_OF_BRICKS; i++) + { + for (int j = 0; j < BRICKS_PER_LINE; j++) + { + brick[i][j].position = (Vector2){ j*brickSize.x + brickSize.x/2, i*brickSize.y + initialDownPosition }; + brick[i][j].active = true; + } + } +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + // Player movement + if (IsKeyDown(KEY_LEFT)) player.position.x -= 5; + if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2; + if (IsKeyDown(KEY_RIGHT)) player.position.x += 5; + if ((player.position.x + player.size.x/2) >= screenWidth) player.position.x = screenWidth - player.size.x/2; + + // Launch ball + if (!ball.active) + { + if (IsKeyPressed(KEY_SPACE)) + { + ball.active = true; + ball.speed = (Vector2){ 0, -5 }; + } + } + + UpdateBall(); + + // Game over logic + if (player.life <= 0) gameOver = true; + else + { + gameOver = true; + + for (int i = 0; i < LINES_OF_BRICKS; i++) + { + for (int j = 0; j < BRICKS_PER_LINE; j++) + { + if (brick[i][j].active) gameOver = false; + } + } + } + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } + + +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + // Draw player bar + DrawRectangle(player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y, BLACK); + + // Draw player lives + for (int i = 0; i < player.life; i++) DrawRectangle(20 + 40*i, screenHeight - 30, 35, 10, LIGHTGRAY); + + // Draw ball + DrawCircleV(ball.position, ball.radius, MAROON); + + // Draw bricks + for (int i = 0; i < LINES_OF_BRICKS; i++) + { + for (int j = 0; j < BRICKS_PER_LINE; j++) + { + if (brick[i][j].active) + { + if ((i + j) % 2 == 0) DrawRectangle(brick[i][j].position.x - brickSize.x/2, brick[i][j].position.y - brickSize.y/2, brickSize.x, brickSize.y, GRAY); + else DrawRectangle(brick[i][j].position.x - brickSize.x/2, brick[i][j].position.y - brickSize.y/2, brickSize.x, brickSize.y, DARKGRAY); + } + } + } + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} + +//-------------------------------------------------------------------------------------- +// Additional module functions +//-------------------------------------------------------------------------------------- +static void UpdateBall() +{ + // Update position + if (ball.active) + { + ball.position.x += ball.speed.x; + ball.position.y += ball.speed.y; + } + else + { + ball.position = (Vector2){ player.position.x, screenHeight*7/8 - 30 }; + } + + // Bounce in x + if (((ball.position.x + ball.radius) >= screenWidth) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1; + + // Bounce in y + if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1; + + // Ball reaches bottom of the screen + if ((ball.position.y + ball.radius) >= screenHeight) + { + ball.speed = (Vector2){ 0, 0 }; + ball.active = false; + + player.life--; + } + + // Collision logic: ball vs player + if (CheckCollisionCircleRec(ball.position, ball.radius, + (Rectangle){ player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y})) + { + if (ball.speed.y > 0) + { + ball.speed.y *= -1; + ball.speed.x = (ball.position.x - player.position.x)/(player.size.x/2)*5; + } + } + + // Collision logic: ball vs bricks + for (int i = 0; i < LINES_OF_BRICKS; i++) + { + for (int j = 0; j < BRICKS_PER_LINE; j++) + { + if (brick[i][j].active) + { + // Hit below + if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brickSize.y/2)) && + ((ball.position.y - ball.radius) > (brick[i][j].position.y + brickSize.y/2 + ball.speed.y)) && + ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y < 0)) + { + brick[i][j].active = false; + ball.speed.y *= -1; + } + // Hit above + else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brickSize.y/2)) && + ((ball.position.y + ball.radius) < (brick[i][j].position.y - brickSize.y/2 + ball.speed.y)) && + ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y > 0)) + { + brick[i][j].active = false; + ball.speed.y *= -1; + } + // Hit left + else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brickSize.x/2)) && + ((ball.position.x + ball.radius) < (brick[i][j].position.x - brickSize.x/2 + ball.speed.x)) && + ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x > 0)) + { + brick[i][j].active = false; + ball.speed.x *= -1; + } + // Hit right + else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brickSize.x/2)) && + ((ball.position.x - ball.radius) > (brick[i][j].position.x + brickSize.x/2 + ball.speed.x)) && + ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x < 0)) + { + brick[i][j].active = false; + ball.speed.x *= -1; + } + } + } + } +} \ No newline at end of file diff --git a/games/asteroids.c b/games/asteroids.c new file mode 100644 index 000000000..53ebbd8e3 --- /dev/null +++ b/games/asteroids.c @@ -0,0 +1,579 @@ +/******************************************************************************************* +* +* raylib - sample game: asteroids +* +* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define PLAYER_BASE_SIZE 20.0f +#define PLAYER_SPEED 6.0f +#define PLAYER_MAX_SHOOTS 10 + +#define METEORS_SPEED 2 +#define MAX_BIG_METEORS 4 +#define MAX_MEDIUM_METEORS 8 +#define MAX_SMALL_METEORS 16 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +typedef struct Player { + Vector2 position; + Vector2 speed; + float acceleration; + float rotation; + Vector3 collider; + Color color; +} Player; + +typedef struct Shoot { + Vector2 position; + Vector2 speed; + float radius; + float rotation; + int lifeSpawn; + bool active; + Color color; +} Shoot; + +typedef struct Meteor { + Vector2 position; + Vector2 speed; + float radius; + bool active; + Color color; +} Meteor; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter; +static bool gameOver; +static bool pause; +static bool victory; + +// NOTE: Defined triangle is isosceles with common angles of 70 degrees. +static float shipHeight; + +static Player player; +static Shoot shoot[PLAYER_MAX_SHOOTS]; +static Meteor bigMeteor[MAX_BIG_METEORS]; +static Meteor mediumMeteor[MAX_MEDIUM_METEORS]; +static Meteor smallMeteor[MAX_SMALL_METEORS]; + +static int countMediumMeteors; +static int countSmallMeteors; +static int meteorsDestroyed; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +static void InitShoot(Shoot shoot); +static void DrawSpaceship(Vector2 position, float rotation, Color color); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: asteroids"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +void InitGame(void) +{ + int posx, posy; + int velx, vely; + bool correctRange = false; + victory = false; + pause = false; + + shipHeight = (PLAYER_BASE_SIZE/2)/tanf(20*DEG2RAD); + + // Initialization player + player.position = (Vector2){screenWidth/2, screenHeight/2 - shipHeight/2}; + player.speed = (Vector2){0, 0}; + player.acceleration = 0; + player.rotation = 0; + player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12}; + player.color = LIGHTGRAY; + + meteorsDestroyed = 0; + + // Initialization shoot + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + shoot[i].position = (Vector2){0, 0}; + shoot[i].speed = (Vector2){0, 0}; + shoot[i].radius = 2; + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + shoot[i].color = WHITE; + } + + for (int i = 0; i < MAX_BIG_METEORS; i++) + { + posx = GetRandomValue(0, screenWidth); + + while(!correctRange) + { + if (posx > screenWidth/2 - 150 && posx < screenWidth/2 + 150) posx = GetRandomValue(0, screenWidth); + else correctRange = true; + } + + correctRange = false; + + posy = GetRandomValue(0, screenHeight); + + while(!correctRange) + { + if (posy > screenHeight/2 - 150 && posy < screenHeight/2 + 150) posy = GetRandomValue(0, screenHeight); + else correctRange = true; + } + + bigMeteor[i].position = (Vector2){posx, posy}; + + correctRange = false; + velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + + while(!correctRange) + { + if (velx == 0 && vely == 0) + { + velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + } + else correctRange = true; + } + + bigMeteor[i].speed = (Vector2){velx, vely}; + bigMeteor[i].radius = 40; + bigMeteor[i].active = true; + bigMeteor[i].color = BLUE; + } + + for (int i = 0; i < MAX_MEDIUM_METEORS; i++) + { + mediumMeteor[i].position = (Vector2){-100, -100}; + mediumMeteor[i].speed = (Vector2){0,0}; + mediumMeteor[i].radius = 20; + mediumMeteor[i].active = false; + mediumMeteor[i].color = BLUE; + } + + for (int i = 0; i < MAX_SMALL_METEORS; i++) + { + smallMeteor[i].position = (Vector2){-100, -100}; + smallMeteor[i].speed = (Vector2){0,0}; + smallMeteor[i].radius = 10; + smallMeteor[i].active = false; + smallMeteor[i].color = BLUE; + } + + countMediumMeteors = 0; + countSmallMeteors = 0; +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + // Player logic + + // Rotation + if (IsKeyDown(KEY_LEFT)) player.rotation -= 5; + if (IsKeyDown(KEY_RIGHT)) player.rotation += 5; + + // Speed + player.speed.x = sin(player.rotation*DEG2RAD)*PLAYER_SPEED; + player.speed.y = cos(player.rotation*DEG2RAD)*PLAYER_SPEED; + + // Controller + if (IsKeyDown(KEY_UP)) + { + if (player.acceleration < 1) player.acceleration += 0.04f; + } + else + { + if (player.acceleration > 0) player.acceleration -= 0.02f; + else if (player.acceleration < 0) player.acceleration = 0; + } + if (IsKeyDown(KEY_DOWN)) + { + if (player.acceleration > 0) player.acceleration -= 0.04f; + else if (player.acceleration < 0) player.acceleration = 0; + } + + // Movement + player.position.x += (player.speed.x*player.acceleration); + player.position.y -= (player.speed.y*player.acceleration); + + // Wall behaviour for player + if (player.position.x > screenWidth + shipHeight) player.position.x = -(shipHeight); + else if (player.position.x < -(shipHeight)) player.position.x = screenWidth + shipHeight; + if (player.position.y > (screenHeight + shipHeight)) player.position.y = -(shipHeight); + else if (player.position.y < -(shipHeight)) player.position.y = screenHeight + shipHeight; + + // Activation of shoot + if (IsKeyPressed(KEY_SPACE)) + { + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if (!shoot[i].active) + { + shoot[i].position = (Vector2){ player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight) }; + shoot[i].active = true; + shoot[i].speed.x = 1.5*sin(player.rotation*DEG2RAD)*PLAYER_SPEED; + shoot[i].speed.y = 1.5*cos(player.rotation*DEG2RAD)*PLAYER_SPEED; + shoot[i].rotation = player.rotation; + break; + } + } + } + + // Shoot life timer + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if (shoot[i].active) shoot[i].lifeSpawn++; + } + + // Shot logic + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if (shoot[i].active) + { + // Movement + shoot[i].position.x += shoot[i].speed.x; + shoot[i].position.y -= shoot[i].speed.y; + + // Wall behaviour for shoot + if (shoot[i].position.x > screenWidth + shoot[i].radius) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + } + else if (shoot[i].position.x < 0 - shoot[i].radius) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + } + if (shoot[i].position.y > screenHeight + shoot[i].radius) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + } + else if (shoot[i].position.y < 0 - shoot[i].radius) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + } + + // Life of shoot + if (shoot[i].lifeSpawn >= 60) + { + shoot[i].position = (Vector2){0, 0}; + shoot[i].speed = (Vector2){0, 0}; + shoot[i].lifeSpawn = 0; + shoot[i].active = false; + } + } + } + + // Collision Player to meteors + player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12}; + + for (int a = 0; a < MAX_BIG_METEORS; a++) + { + if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, bigMeteor[a].position, bigMeteor[a].radius) && bigMeteor[a].active) gameOver = true; + } + + for (int a = 0; a < MAX_MEDIUM_METEORS; a++) + { + if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, mediumMeteor[a].position, mediumMeteor[a].radius) && mediumMeteor[a].active) gameOver = true; + } + + for (int a = 0; a < MAX_SMALL_METEORS; a++) + { + if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, smallMeteor[a].position, smallMeteor[a].radius) && smallMeteor[a].active) gameOver = true; + } + + // Meteor logic + for (int i = 0; i < MAX_BIG_METEORS; i++) + { + if (bigMeteor[i].active) + { + // movement + bigMeteor[i].position.x += bigMeteor[i].speed.x; + bigMeteor[i].position.y += bigMeteor[i].speed.y; + + // wall behaviour + if (bigMeteor[i].position.x > screenWidth + bigMeteor[i].radius) bigMeteor[i].position.x = -(bigMeteor[i].radius); + else if (bigMeteor[i].position.x < 0 - bigMeteor[i].radius) bigMeteor[i].position.x = screenWidth + bigMeteor[i].radius; + if (bigMeteor[i].position.y > screenHeight + bigMeteor[i].radius) bigMeteor[i].position.y = -(bigMeteor[i].radius); + else if (bigMeteor[i].position.y < 0 - bigMeteor[i].radius) bigMeteor[i].position.y = screenHeight + bigMeteor[i].radius; + } + } + + for (int i = 0; i < MAX_MEDIUM_METEORS; i++) + { + if (mediumMeteor[i].active) + { + // movement + mediumMeteor[i].position.x += mediumMeteor[i].speed.x; + mediumMeteor[i].position.y += mediumMeteor[i].speed.y; + + // wall behaviour + if (mediumMeteor[i].position.x > screenWidth + mediumMeteor[i].radius) mediumMeteor[i].position.x = -(mediumMeteor[i].radius); + else if (mediumMeteor[i].position.x < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.x = screenWidth + mediumMeteor[i].radius; + if (mediumMeteor[i].position.y > screenHeight + mediumMeteor[i].radius) mediumMeteor[i].position.y = -(mediumMeteor[i].radius); + else if (mediumMeteor[i].position.y < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.y = screenHeight + mediumMeteor[i].radius; + } + } + + for (int i = 0; i < MAX_SMALL_METEORS; i++) + { + if (smallMeteor[i].active) + { + // movement + smallMeteor[i].position.x += smallMeteor[i].speed.x; + smallMeteor[i].position.y += smallMeteor[i].speed.y; + + // wall behaviour + if (smallMeteor[i].position.x > screenWidth + smallMeteor[i].radius) smallMeteor[i].position.x = -(smallMeteor[i].radius); + else if (smallMeteor[i].position.x < 0 - smallMeteor[i].radius) smallMeteor[i].position.x = screenWidth + smallMeteor[i].radius; + if (smallMeteor[i].position.y > screenHeight + smallMeteor[i].radius) smallMeteor[i].position.y = -(smallMeteor[i].radius); + else if (smallMeteor[i].position.y < 0 - smallMeteor[i].radius) smallMeteor[i].position.y = screenHeight + smallMeteor[i].radius; + } + } + + // Collision behaviour + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if ((shoot[i].active)) + { + for (int a = 0; a < MAX_BIG_METEORS; a++) + { + if (bigMeteor[a].active && CheckCollisionCircles(shoot[i].position, shoot[i].radius, bigMeteor[a].position, bigMeteor[a].radius)) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + bigMeteor[a].active = false; + meteorsDestroyed++; + for (int j = 0; j < 2; j ++) + { + if (countMediumMeteors%2 == 0) + { + mediumMeteor[countMediumMeteors].position = (Vector2){bigMeteor[a].position.x, bigMeteor[a].position.y}; + mediumMeteor[countMediumMeteors].speed = (Vector2){cos(shoot[i].rotation*DEG2RAD)*METEORS_SPEED*-1, sin(shoot[i].rotation*DEG2RAD)*METEORS_SPEED*-1}; + } + else + { + mediumMeteor[countMediumMeteors].position = (Vector2){bigMeteor[a].position.x, bigMeteor[a].position.y}; + mediumMeteor[countMediumMeteors].speed = (Vector2){cos(shoot[i].rotation*DEG2RAD)*METEORS_SPEED, sin(shoot[i].rotation*DEG2RAD)*METEORS_SPEED}; + } + + mediumMeteor[countMediumMeteors].active = true; + countMediumMeteors ++; + } + //bigMeteor[a].position = (Vector2){-100, -100}; + bigMeteor[a].color = RED; + a = MAX_BIG_METEORS; + } + } + } + if ((shoot[i].active)) + { + for (int b = 0; b < MAX_MEDIUM_METEORS; b++) + { + if (mediumMeteor[b].active && CheckCollisionCircles(shoot[i].position, shoot[i].radius, mediumMeteor[b].position, mediumMeteor[b].radius)) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + mediumMeteor[b].active = false; + meteorsDestroyed++; + for (int j = 0; j < 2; j ++) + { + if (countSmallMeteors%2 == 0) + { + smallMeteor[countSmallMeteors].position = (Vector2){mediumMeteor[b].position.x, mediumMeteor[b].position.y}; + smallMeteor[countSmallMeteors].speed = (Vector2){cos(shoot[i].rotation*DEG2RAD)*METEORS_SPEED*-1, sin(shoot[i].rotation*DEG2RAD)*METEORS_SPEED*-1}; + } + else + { + smallMeteor[countSmallMeteors].position = (Vector2){mediumMeteor[b].position.x, mediumMeteor[b].position.y}; + smallMeteor[countSmallMeteors].speed = (Vector2){cos(shoot[i].rotation*DEG2RAD)*METEORS_SPEED, sin(shoot[i].rotation*DEG2RAD)*METEORS_SPEED}; + } + + smallMeteor[countSmallMeteors].active = true; + countSmallMeteors ++; + } + //mediumMeteor[b].position = (Vector2){-100, -100}; + mediumMeteor[b].color = GREEN; + b = MAX_MEDIUM_METEORS; + } + } + } + if ((shoot[i].active)) + { + for (int c = 0; c < MAX_SMALL_METEORS; c++) + { + if (smallMeteor[c].active && CheckCollisionCircles(shoot[i].position, shoot[i].radius, smallMeteor[c].position, smallMeteor[c].radius)) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + smallMeteor[c].active = false; + meteorsDestroyed++; + smallMeteor[c].color = YELLOW; + // smallMeteor[c].position = (Vector2){-100, -100}; + c = MAX_SMALL_METEORS; + } + } + } + } + } + + if (meteorsDestroyed == MAX_BIG_METEORS + MAX_MEDIUM_METEORS + MAX_SMALL_METEORS) victory = true; + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + // Draw spaceship + Vector2 v1 = { player.position.x + sinf(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cosf(player.rotation*DEG2RAD)*(shipHeight) }; + Vector2 v2 = { player.position.x - cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y - sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) }; + Vector2 v3 = { player.position.x + cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y + sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) }; + DrawTriangle(v1, v2, v3, MAROON); + + // Draw meteors + for (int i = 0; i < MAX_BIG_METEORS; i++) + { + if (bigMeteor[i].active) DrawCircleV(bigMeteor[i].position, bigMeteor[i].radius, DARKGRAY); + else DrawCircleV(bigMeteor[i].position, bigMeteor[i].radius, Fade(LIGHTGRAY, 0.3f)); + } + + for (int i = 0; i < MAX_MEDIUM_METEORS; i++) + { + if (mediumMeteor[i].active) DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, GRAY); + else DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, Fade(LIGHTGRAY, 0.3f)); + } + + for (int i = 0; i < MAX_SMALL_METEORS; i++) + { + if (smallMeteor[i].active) DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, GRAY); + else DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, Fade(LIGHTGRAY, 0.3f)); + } + + // Draw shoot + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if (shoot[i].active) DrawCircleV(shoot[i].position, shoot[i].radius, BLACK); + } + + if (victory) DrawText("VICTORY", screenWidth/2 - MeasureText("VICTORY", 20)/2, screenHeight/2, 20, LIGHTGRAY); + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} \ No newline at end of file diff --git a/games/asteroids_survival.c b/games/asteroids_survival.c new file mode 100644 index 000000000..aa21112d7 --- /dev/null +++ b/games/asteroids_survival.c @@ -0,0 +1,383 @@ +/******************************************************************************************* +* +* raylib - sample game: asteroids survival +* +* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define PLAYER_BASE_SIZE 20.0f +#define PLAYER_SPEED 6.0f +#define PLAYER_MAX_SHOOTS 10 + +#define METEORS_SPEED 2 +#define MAX_MEDIUM_METEORS 8 +#define MAX_SMALL_METEORS 16 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +typedef struct Player { + Vector2 position; + Vector2 speed; + float acceleration; + float rotation; + Vector3 collider; + Color color; +} Player; + +typedef struct Meteor { + Vector2 position; + Vector2 speed; + float radius; + bool active; + Color color; +} Meteor; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter; +static bool gameOver; +static bool pause; + +// NOTE: Defined triangle is isosceles with common angles of 70 degrees. +static float shipHeight; + +static Player player; +static Meteor mediumMeteor[MAX_MEDIUM_METEORS]; +static Meteor smallMeteor[MAX_SMALL_METEORS]; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: asteroids survival"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +void InitGame(void) +{ + int posx, posy; + int velx, vely; + bool correctRange = false; + + pause = false; + + framesCounter = 0; + + shipHeight = (PLAYER_BASE_SIZE/2)/tanf(20*DEG2RAD); + + // Initialization player + player.position = (Vector2){screenWidth/2, screenHeight/2 - shipHeight/2}; + player.speed = (Vector2){0, 0}; + player.acceleration = 0; + player.rotation = 0; + player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12}; + player.color = LIGHTGRAY; + + for (int i = 0; i < MAX_MEDIUM_METEORS; i++) + { + posx = GetRandomValue(0, screenWidth); + + while(!correctRange) + { + if (posx > screenWidth/2 - 150 && posx < screenWidth/2 + 150) posx = GetRandomValue(0, screenWidth); + else correctRange = true; + } + + correctRange = false; + + posy = GetRandomValue(0, screenHeight); + + while(!correctRange) + { + if (posy > screenHeight/2 - 150 && posy < screenHeight/2 + 150) posy = GetRandomValue(0, screenHeight); + else correctRange = true; + } + + correctRange = false; + velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + + while(!correctRange) + { + if (velx == 0 && vely == 0) + { + velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + } + else correctRange = true; + } + mediumMeteor[i].position = (Vector2){posx, posy}; + mediumMeteor[i].speed = (Vector2){velx, vely}; + mediumMeteor[i].radius = 20; + mediumMeteor[i].active = true; + mediumMeteor[i].color = GREEN; + } + + for (int i = 0; i < MAX_SMALL_METEORS; i++) + { + posx = GetRandomValue(0, screenWidth); + + while(!correctRange) + { + if (posx > screenWidth/2 - 150 && posx < screenWidth/2 + 150) posx = GetRandomValue(0, screenWidth); + else correctRange = true; + } + + correctRange = false; + + posy = GetRandomValue(0, screenHeight); + + while(!correctRange) + { + if (posy > screenHeight/2 - 150 && posy < screenHeight/2 + 150) posy = GetRandomValue(0, screenHeight); + else correctRange = true; + } + + correctRange = false; + velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + + while(!correctRange) + { + if (velx == 0 && vely == 0) + { + velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED); + } + else correctRange = true; + } + smallMeteor[i].position = (Vector2){posx, posy}; + smallMeteor[i].speed = (Vector2){velx, vely}; + smallMeteor[i].radius = 10; + smallMeteor[i].active = true; + smallMeteor[i].color = YELLOW; + } +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + framesCounter++; + + // Player logic + + // Rotation + if (IsKeyDown(KEY_LEFT)) player.rotation -= 5; + if (IsKeyDown(KEY_RIGHT)) player.rotation += 5; + + // Speed + player.speed.x = sin(player.rotation*DEG2RAD)*PLAYER_SPEED; + player.speed.y = cos(player.rotation*DEG2RAD)*PLAYER_SPEED; + + // Controller + if (IsKeyDown(KEY_UP)) + { + if (player.acceleration < 1) player.acceleration += 0.04f; + } + else + { + if (player.acceleration > 0) player.acceleration -= 0.02f; + else if (player.acceleration < 0) player.acceleration = 0; + } + if (IsKeyDown(KEY_DOWN)) + { + if (player.acceleration > 0) player.acceleration -= 0.04f; + else if (player.acceleration < 0) player.acceleration = 0; + } + + // Movement + player.position.x += (player.speed.x*player.acceleration); + player.position.y -= (player.speed.y*player.acceleration); + + // Wall behaviour for player + if (player.position.x > screenWidth + shipHeight) player.position.x = -(shipHeight); + else if (player.position.x < -(shipHeight)) player.position.x = screenWidth + shipHeight; + if (player.position.y > (screenHeight + shipHeight)) player.position.y = -(shipHeight); + else if (player.position.y < -(shipHeight)) player.position.y = screenHeight + shipHeight; + + // Collision Player to meteors + player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12}; + + for (int a = 0; a < MAX_MEDIUM_METEORS; a++) + { + if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, mediumMeteor[a].position, mediumMeteor[a].radius) && mediumMeteor[a].active) gameOver = true; + } + + for (int a = 0; a < MAX_SMALL_METEORS; a++) + { + if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, smallMeteor[a].position, smallMeteor[a].radius) && smallMeteor[a].active) gameOver = true; + } + + // Meteor logic + + for (int i = 0; i < MAX_MEDIUM_METEORS; i++) + { + if (mediumMeteor[i].active) + { + // movement + mediumMeteor[i].position.x += mediumMeteor[i].speed.x; + mediumMeteor[i].position.y += mediumMeteor[i].speed.y; + + // wall behaviour + if (mediumMeteor[i].position.x > screenWidth + mediumMeteor[i].radius) mediumMeteor[i].position.x = -(mediumMeteor[i].radius); + else if (mediumMeteor[i].position.x < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.x = screenWidth + mediumMeteor[i].radius; + if (mediumMeteor[i].position.y > screenHeight + mediumMeteor[i].radius) mediumMeteor[i].position.y = -(mediumMeteor[i].radius); + else if (mediumMeteor[i].position.y < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.y = screenHeight + mediumMeteor[i].radius; + } + } + + for (int i = 0; i < MAX_SMALL_METEORS; i++) + { + if (smallMeteor[i].active) + { + // movement + smallMeteor[i].position.x += smallMeteor[i].speed.x; + smallMeteor[i].position.y += smallMeteor[i].speed.y; + + // wall behaviour + if (smallMeteor[i].position.x > screenWidth + smallMeteor[i].radius) smallMeteor[i].position.x = -(smallMeteor[i].radius); + else if (smallMeteor[i].position.x < 0 - smallMeteor[i].radius) smallMeteor[i].position.x = screenWidth + smallMeteor[i].radius; + if (smallMeteor[i].position.y > screenHeight + smallMeteor[i].radius) smallMeteor[i].position.y = -(smallMeteor[i].radius); + else if (smallMeteor[i].position.y < 0 - smallMeteor[i].radius) smallMeteor[i].position.y = screenHeight + smallMeteor[i].radius; + } + } + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + // Draw spaceship + Vector2 v1 = { player.position.x + sinf(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cosf(player.rotation*DEG2RAD)*(shipHeight) }; + Vector2 v2 = { player.position.x - cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y - sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) }; + Vector2 v3 = { player.position.x + cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y + sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) }; + DrawTriangle(v1, v2, v3, MAROON); + + // Draw meteor + for (int i = 0;i < MAX_MEDIUM_METEORS; i++) + { + if (mediumMeteor[i].active) DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, GRAY); + else DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, Fade(LIGHTGRAY, 0.3f)); + } + + for (int i = 0;i < MAX_SMALL_METEORS; i++) + { + if (smallMeteor[i].active) DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, DARKGRAY); + else DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, Fade(LIGHTGRAY, 0.3f)); + } + + DrawText(FormatText("TIME: %.02f", (float)framesCounter/60), 10, 10, 20, BLACK); + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} \ No newline at end of file diff --git a/games/drturtle/04_drturtle_gui.c b/games/drturtle/04_drturtle_gui.c index 0e648b5db..bbfd3492a 100644 --- a/games/drturtle/04_drturtle_gui.c +++ b/games/drturtle/04_drturtle_gui.c @@ -338,7 +338,7 @@ int main() DrawTexture(title, screenWidth/2 - title.width/2, screenHeight/2 - title.height/2 - 80, WHITE); // Draw blinking text - if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER", (Vector2){ screenWidth/2 - 150, 480 }, GetFontBaseSize(font), 0, WHITE); + if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER", (Vector2){ screenWidth/2 - 150, 480 }, font.size, 0, WHITE); } break; case GAMEPLAY: @@ -388,8 +388,8 @@ int main() DrawRectangle(20, 20, foodBar, 40, ORANGE); DrawRectangleLines(20, 20, 400, 40, BLACK); - DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ screenWidth - 300, 20 }, GetFontBaseSize(font), -2, ORANGE); - DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 550, 20 }, GetFontBaseSize(font), -2, ORANGE); + DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ screenWidth - 300, 20 }, font.size, -2, ORANGE); + DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 550, 20 }, font.size, -2, ORANGE); if (gameraMode) { @@ -403,15 +403,15 @@ int main() // Draw a transparent black rectangle that covers all screen DrawRectangle(0, 0, screenWidth, screenHeight, Fade(BLACK, 0.4f)); - DrawTextEx(font, "GAME OVER", (Vector2){ 300, 160 }, GetFontBaseSize(font)*3, -2, MAROON); + DrawTextEx(font, "GAME OVER", (Vector2){ 300, 160 }, font.size*3, -2, MAROON); - DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ 680, 350 }, GetFontBaseSize(font), -2, GOLD); - DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 290, 350 }, GetFontBaseSize(font), -2, GOLD); - DrawTextEx(font, FormatText("HISCORE: %04i", hiscore), (Vector2){ 665, 400 }, GetFontBaseSize(font), -2, ORANGE); - DrawTextEx(font, FormatText("HIDISTANCE: %04i", (int)hidistance), (Vector2){ 270, 400 }, GetFontBaseSize(font), -2, ORANGE); + DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ 680, 350 }, font.size, -2, GOLD); + DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 290, 350 }, font.size, -2, GOLD); + DrawTextEx(font, FormatText("HISCORE: %04i", hiscore), (Vector2){ 665, 400 }, font.size, -2, ORANGE); + DrawTextEx(font, FormatText("HIDISTANCE: %04i", (int)hidistance), (Vector2){ 270, 400 }, font.size, -2, ORANGE); // Draw blinking text - if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER to REPLAY", (Vector2){ screenWidth/2 - 250, 520 }, GetFontBaseSize(font), -2, LIGHTGRAY); + if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER to REPLAY", (Vector2){ screenWidth/2 - 250, 520 }, font.size, -2, LIGHTGRAY); } break; default: break; diff --git a/games/drturtle/05_drturtle_audio.c b/games/drturtle/05_drturtle_audio.c index 7e8cac70f..4a36d015c 100644 --- a/games/drturtle/05_drturtle_audio.c +++ b/games/drturtle/05_drturtle_audio.c @@ -351,7 +351,7 @@ int main() DrawTexture(title, screenWidth/2 - title.width/2, screenHeight/2 - title.height/2 - 80, WHITE); // Draw blinking text - if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER", (Vector2){ screenWidth/2 - 150, 480 }, GetFontBaseSize(font), 0, WHITE); + if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER", (Vector2){ screenWidth/2 - 150, 480 }, font.size, 0, WHITE); } break; case GAMEPLAY: @@ -401,8 +401,8 @@ int main() DrawRectangle(20, 20, foodBar, 40, ORANGE); DrawRectangleLines(20, 20, 400, 40, BLACK); - DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ screenWidth - 300, 20 }, GetFontBaseSize(font), -2, ORANGE); - DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 550, 20 }, GetFontBaseSize(font), -2, ORANGE); + DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ screenWidth - 300, 20 }, font.size, -2, ORANGE); + DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 550, 20 }, font.size, -2, ORANGE); if (gameraMode) { @@ -416,15 +416,15 @@ int main() // Draw a transparent black rectangle that covers all screen DrawRectangle(0, 0, screenWidth, screenHeight, Fade(BLACK, 0.4f)); - DrawTextEx(font, "GAME OVER", (Vector2){ 300, 160 }, GetFontBaseSize(font)*3, -2, MAROON); + DrawTextEx(font, "GAME OVER", (Vector2){ 300, 160 }, font.size*3, -2, MAROON); - DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ 680, 350 }, GetFontBaseSize(font), -2, GOLD); - DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 290, 350 }, GetFontBaseSize(font), -2, GOLD); - DrawTextEx(font, FormatText("HISCORE: %04i", hiscore), (Vector2){ 665, 400 }, GetFontBaseSize(font), -2, ORANGE); - DrawTextEx(font, FormatText("HIDISTANCE: %04i", (int)hidistance), (Vector2){ 270, 400 }, GetFontBaseSize(font), -2, ORANGE); + DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ 680, 350 }, font.size, -2, GOLD); + DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 290, 350 }, font.size, -2, GOLD); + DrawTextEx(font, FormatText("HISCORE: %04i", hiscore), (Vector2){ 665, 400 }, font.size, -2, ORANGE); + DrawTextEx(font, FormatText("HIDISTANCE: %04i", (int)hidistance), (Vector2){ 270, 400 }, font.size, -2, ORANGE); // Draw blinking text - if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER to REPLAY", (Vector2){ screenWidth/2 - 250, 520 }, GetFontBaseSize(font), -2, LIGHTGRAY); + if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER to REPLAY", (Vector2){ screenWidth/2 - 250, 520 }, font.size, -2, LIGHTGRAY); } break; default: break; diff --git a/games/drturtle/06_drturtle_final.c b/games/drturtle/06_drturtle_final.c index a3475de47..128b23a56 100644 --- a/games/drturtle/06_drturtle_final.c +++ b/games/drturtle/06_drturtle_final.c @@ -21,6 +21,8 @@ #include "raylib.h" +#include // Used for sinf() + #define MAX_ENEMIES 10 typedef enum { TITLE, GAMEPLAY, ENDING } GameScreen; @@ -128,7 +130,7 @@ int main() framesCounter++; // Sea color tint effect - blue = 210 + 25 * sin(timeCounter); + blue = 210 + 25 * sinf(timeCounter); timeCounter += 0.01; // Game screens management @@ -374,7 +376,7 @@ int main() DrawTexture(title, screenWidth/2 - title.width/2, screenHeight/2 - title.height/2 - 80, WHITE); // Draw blinking text - if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER", (Vector2){ screenWidth/2 - 150, 480 }, GetFontBaseSize(font), 0, WHITE); + if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER", (Vector2){ screenWidth/2 - 150, 480 }, font.size, 0, WHITE); } break; case GAMEPLAY: @@ -424,8 +426,8 @@ int main() DrawRectangle(20, 20, foodBar, 40, ORANGE); DrawRectangleLines(20, 20, 400, 40, BLACK); - DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ screenWidth - 300, 20 }, GetFontBaseSize(font), -2, ORANGE); - DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 550, 20 }, GetFontBaseSize(font), -2, ORANGE); + DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ screenWidth - 300, 20 }, font.size, -2, ORANGE); + DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 550, 20 }, font.size, -2, ORANGE); if (gameraMode) { @@ -439,15 +441,15 @@ int main() // Draw a transparent black rectangle that covers all screen DrawRectangle(0, 0, screenWidth, screenHeight, Fade(BLACK, 0.4f)); - DrawTextEx(font, "GAME OVER", (Vector2){ 300, 160 }, GetFontBaseSize(font)*3, -2, MAROON); + DrawTextEx(font, "GAME OVER", (Vector2){ 300, 160 }, font.size*3, -2, MAROON); - DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ 680, 350 }, GetFontBaseSize(font), -2, GOLD); - DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 290, 350 }, GetFontBaseSize(font), -2, GOLD); - DrawTextEx(font, FormatText("HISCORE: %04i", hiscore), (Vector2){ 665, 400 }, GetFontBaseSize(font), -2, ORANGE); - DrawTextEx(font, FormatText("HIDISTANCE: %04i", (int)hidistance), (Vector2){ 270, 400 }, GetFontBaseSize(font), -2, ORANGE); + DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ 680, 350 }, font.size, -2, GOLD); + DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 290, 350 }, font.size, -2, GOLD); + DrawTextEx(font, FormatText("HISCORE: %04i", hiscore), (Vector2){ 665, 400 }, font.size, -2, ORANGE); + DrawTextEx(font, FormatText("HIDISTANCE: %04i", (int)hidistance), (Vector2){ 270, 400 }, font.size, -2, ORANGE); // Draw blinking text - if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER to REPLAY", (Vector2){ screenWidth/2 - 250, 520 }, GetFontBaseSize(font), -2, LIGHTGRAY); + if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER to REPLAY", (Vector2){ screenWidth/2 - 250, 520 }, font.size, -2, LIGHTGRAY); } break; default: break; diff --git a/games/drturtle/drturtle_final_web.c b/games/drturtle/drturtle_final_web.c new file mode 100644 index 000000000..25f4074be --- /dev/null +++ b/games/drturtle/drturtle_final_web.c @@ -0,0 +1,541 @@ +/******************************************************************************************* +* +* raylib game - Dr. Turtle & Mr. Gamera +* +* Welcome to raylib! +* +* To test examples, just press F6 and execute raylib_compile_execute script +* Note that compiled executable is placed in the same folder as .c file +* +* You can find all basic examples on C:\raylib\raylib\examples folder or +* raylib official webpage: www.raylib.com +* +* Enjoy using raylib. :) +* +* This game has been created using raylib 1.1 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +********************************************************************************************/ + +#include "raylib.h" +#include // Used for sinf() + +#if defined(PLATFORM_WEB) + #include +#endif + +#define MAX_ENEMIES 10 + +typedef enum { TITLE = 0, GAMEPLAY, ENDING } GameScreen; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +const int screenWidth = 1280; +const int screenHeight = 720; + +Texture2D sky; +Texture2D mountains; +Texture2D sea; +Texture2D title; +Texture2D turtle; +Texture2D gamera; +Texture2D shark; +Texture2D orca; +Texture2D swhale; +Texture2D fish; +Texture2D gframe; + +SpriteFont font; + +Sound eat; +Sound die; +Sound growl; + +// Define scrolling variables +int backScrolling = 0; +int seaScrolling = 0; + +// Define current screen +GameScreen currentScreen = 0; + +// Define player variables +int playerRail = 1; +Rectangle playerBounds; +bool gameraMode = false; + +// Define enemies variables +Rectangle enemyBounds[MAX_ENEMIES]; +int enemyRail[MAX_ENEMIES]; +int enemyType[MAX_ENEMIES]; +bool enemyActive[MAX_ENEMIES]; +float enemySpeed = 10; + +// Define additional game variables +int score = 0; +float distance = 0.0f; +int hiscore = 0; +float hidistance = 0.0f; +int foodBar = 0; +int framesCounter = 0; + +unsigned char blue = 200; +float timeCounter = 0; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +void UpdateDrawFrame(void); // Update and Draw one frame + +//---------------------------------------------------------------------------------- +// Main Enry Point +//---------------------------------------------------------------------------------- +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + + // Init window + InitWindow(screenWidth, screenHeight, "Dr. Turtle & Mr. GAMERA"); + + // Initialize audio device + InitAudioDevice(); + + // Load game resources: textures + sky = LoadTexture("resources/sky.png"); + mountains = LoadTexture("resources/mountains.png"); + sea = LoadTexture("resources/sea.png"); + title = LoadTexture("resources/title.png"); + turtle = LoadTexture("resources/turtle.png"); + gamera = LoadTexture("resources/gamera.png"); + shark = LoadTexture("resources/shark.png"); + orca = LoadTexture("resources/orca.png"); + swhale = LoadTexture("resources/swhale.png"); + fish = LoadTexture("resources/fish.png"); + gframe = LoadTexture("resources/gframe.png"); + + // Load game resources: fonts + font = LoadSpriteFont("resources/komika.png"); + + // Load game resources: sounds + eat = LoadSound("resources/eat.wav"); + die = LoadSound("resources/die.wav"); + growl = LoadSound("resources/gamera.wav"); + + // Start playing streaming music + PlayMusicStream("resources/speeding.ogg"); + + playerBounds = (Rectangle){ 30 + 14, playerRail*120 + 90 + 14, 100, 100 }; + + // Init enemies variables + for (int i = 0; i < MAX_ENEMIES; i++) + { + // Define enemy type (all same probability) + //enemyType[i] = GetRandomValue(0, 3); + + // Probability system for enemies type + int enemyProb = GetRandomValue(0, 100); + + if (enemyProb < 30) enemyType[i] = 0; + else if (enemyProb < 60) enemyType[i] = 1; + else if (enemyProb < 90) enemyType[i] = 2; + else enemyType[i] = 3; + + // define enemy rail + enemyRail[i] = GetRandomValue(0, 4); + + // Make sure not two consecutive enemies in the same row + if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); + + enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; + enemyActive[i] = false; + } + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + UpdateDrawFrame(); + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + + // Unload textures + UnloadTexture(sky); + UnloadTexture(mountains); + UnloadTexture(sea); + UnloadTexture(gframe); + UnloadTexture(title); + UnloadTexture(turtle); + UnloadTexture(shark); + UnloadTexture(orca); + UnloadTexture(swhale); + UnloadTexture(fish); + UnloadTexture(gamera); + + // Unload font texture + UnloadSpriteFont(font); + + // Unload sounds + UnloadSound(eat); + UnloadSound(die); + UnloadSound(growl); + + StopMusicStream(); // Stop music + CloseAudioDevice(); // Close audio device + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + UpdateMusicStream(); + + framesCounter++; + + // Sea color tint effect + blue = 210 + 25 * sinf(timeCounter); + timeCounter += 0.01; + + // Game screens management + switch (currentScreen) + { + case TITLE: + { + // Sea scrolling + seaScrolling -= 2; + if (seaScrolling <= -screenWidth) seaScrolling = 0; + + // Press enter to change to gameplay screen + if (IsKeyPressed(KEY_ENTER)) + { + currentScreen = GAMEPLAY; + framesCounter = 0; + } + + } break; + case GAMEPLAY: + { + // Background scrolling logic + backScrolling--; + if (backScrolling <= -screenWidth) backScrolling = 0; + + // Sea scrolling logic + seaScrolling -= (enemySpeed - 2); + if (seaScrolling <= -screenWidth) seaScrolling = 0; + + // Player movement logic + if (IsKeyPressed(KEY_DOWN)) playerRail++; + else if (IsKeyPressed(KEY_UP)) playerRail--; + + // Check player not out of rails + if (playerRail > 4) playerRail = 4; + else if (playerRail < 0) playerRail = 0; + + // Update player bounds + playerBounds = (Rectangle){ 30 + 14, playerRail*120 + 90 + 14, 100, 100 }; + + // Enemies activation logic (every 40 frames) + if (framesCounter > 40) + { + for (int i = 0; i < MAX_ENEMIES; i++) + { + if (enemyActive[i] == false) + { + enemyActive[i] = true; + i = MAX_ENEMIES; + } + } + + framesCounter = 0; + } + + // Enemies logic + for (int i = 0; i < MAX_ENEMIES; i++) + { + if (enemyActive[i]) + { + enemyBounds[i].x -= enemySpeed; + } + + // Check enemies out of screen + if (enemyBounds[i].x <= 0 - 128) + { + enemyActive[i] = false; + enemyType[i] = GetRandomValue(0, 3); + enemyRail[i] = GetRandomValue(0, 4); + + // Make sure not two consecutive enemies in the same row + if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); + + enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; + } + } + + if (!gameraMode) enemySpeed += 0.005; + + // Check collision player vs enemies + for (int i = 0; i < MAX_ENEMIES; i++) + { + if (enemyActive[i]) + { + if (CheckCollisionRecs(playerBounds, enemyBounds[i])) + { + if (enemyType[i] < 3) // Bad enemies + { + if (gameraMode) + { + if (enemyType[i] == 0) score += 50; + else if (enemyType[i] == 1) score += 150; + else if (enemyType[i] == 2) score += 300; + + foodBar += 15; + + enemyActive[i] = false; + + // After enemy deactivation, reset enemy parameters to be reused + enemyType[i] = GetRandomValue(0, 3); + enemyRail[i] = GetRandomValue(0, 4); + + // Make sure not two consecutive enemies in the same row + if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); + + enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; + + PlaySound(eat); + } + else + { + // Player die logic + PlaySound(die); + + currentScreen = ENDING; + framesCounter = 0; + + // Save hiscore and hidistance for next game + if (score > hiscore) hiscore = score; + if (distance > hidistance) hidistance = distance; + } + } + else // Sweet fish + { + enemyActive[i] = false; + enemyType[i] = GetRandomValue(0, 3); + enemyRail[i] = GetRandomValue(0, 4); + + // Make sure not two consecutive enemies in the same row + if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); + + enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; + + if (!gameraMode) foodBar += 80; + else foodBar += 25; + + score += 10; + + if (foodBar == 400) + { + gameraMode = true; + + PlaySound(growl); + } + + PlaySound(eat); + } + } + } + } + + // Gamera mode logic + if (gameraMode) + { + foodBar--; + + if (foodBar <= 0) + { + gameraMode = false; + enemySpeed -= 2; + if (enemySpeed < 10) enemySpeed = 10; + } + } + + // Update distance counter + distance += 0.5f; + + } break; + case ENDING: + { + // Press enter to play again + if (IsKeyPressed(KEY_ENTER)) + { + currentScreen = GAMEPLAY; + + // Reset player + playerRail = 1; + playerBounds = (Rectangle){ 30 + 14, playerRail*120 + 90 + 14, 100, 100 }; + gameraMode = false; + + // Reset enemies data + for (int i = 0; i < MAX_ENEMIES; i++) + { + int enemyProb = GetRandomValue(0, 100); + + if (enemyProb < 30) enemyType[i] = 0; + else if (enemyProb < 60) enemyType[i] = 1; + else if (enemyProb < 90) enemyType[i] = 2; + else enemyType[i] = 3; + + //enemyType[i] = GetRandomValue(0, 3); + enemyRail[i] = GetRandomValue(0, 4); + + // Make sure not two consecutive enemies in the same row + if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); + + enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; + enemyActive[i] = false; + } + + enemySpeed = 10; + + // Reset game variables + score = 0; + distance = 0.0; + foodBar = 0; + framesCounter = 0; + } + + } break; + default: break; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // Draw background (common to all screens) + DrawTexture(sky, 0, 0, WHITE); + + DrawTexture(mountains, backScrolling, 0, WHITE); + DrawTexture(mountains, screenWidth + backScrolling, 0, WHITE); + + if (!gameraMode) + { + DrawTexture(sea, seaScrolling, 0, (Color){ 16, 189, blue, 255}); + DrawTexture(sea, screenWidth + seaScrolling, 0, (Color){ 16, 189, blue, 255}); + } + else + { + DrawTexture(sea, seaScrolling, 0, (Color){ 255, 113, 66, 255}); + DrawTexture(sea, screenWidth + seaScrolling, 0, (Color){ 255, 113, 66, 255}); + } + + switch (currentScreen) + { + case TITLE: + { + // Draw title + DrawTexture(title, screenWidth/2 - title.width/2, screenHeight/2 - title.height/2 - 80, WHITE); + + // Draw blinking text + if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER", (Vector2){ screenWidth/2 - 150, 480 }, font.size, 1, WHITE); + + } break; + case GAMEPLAY: + { + // Draw water lines + for (int i = 0; i < 5; i++) DrawRectangle(0, i*120 + 120, screenWidth, 110, Fade(SKYBLUE, 0.1f)); + + // Draw player + if (!gameraMode) DrawTexture(turtle, playerBounds.x - 14, playerBounds.y - 14, WHITE); + else DrawTexture(gamera, playerBounds.x - 64, playerBounds.y - 64, WHITE); + + // Draw player bounding box + //if (!gameraMode) DrawRectangleRec(playerBounds, Fade(GREEN, 0.4f)); + //else DrawRectangleRec(playerBounds, Fade(ORANGE, 0.4f)); + + // Draw enemies + for (int i = 0; i < MAX_ENEMIES; i++) + { + if (enemyActive[i]) + { + // Draw enemies + switch(enemyType[i]) + { + case 0: DrawTexture(shark, enemyBounds[i].x - 14, enemyBounds[i].y - 14, WHITE); break; + case 1: DrawTexture(orca, enemyBounds[i].x - 14, enemyBounds[i].y - 14, WHITE); break; + case 2: DrawTexture(swhale, enemyBounds[i].x - 14, enemyBounds[i].y - 14, WHITE); break; + case 3: DrawTexture(fish, enemyBounds[i].x - 14, enemyBounds[i].y - 14, WHITE); break; + default: break; + } + + // Draw enemies bounding boxes + /* + switch(enemyType[i]) + { + case 0: DrawRectangleRec(enemyBounds[i], Fade(RED, 0.5f)); break; + case 1: DrawRectangleRec(enemyBounds[i], Fade(RED, 0.5f)); break; + case 2: DrawRectangleRec(enemyBounds[i], Fade(RED, 0.5f)); break; + case 3: DrawRectangleRec(enemyBounds[i], Fade(GREEN, 0.5f)); break; + default: break; + } + */ + } + } + + // Draw gameplay interface + DrawRectangle(20, 20, 400, 40, Fade(GRAY, 0.4f)); + DrawRectangle(20, 20, foodBar, 40, ORANGE); + DrawRectangleLines(20, 20, 400, 40, BLACK); + + DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ screenWidth - 300, 20 }, font.size, -2, ORANGE); + DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 550, 20 }, font.size, -2, ORANGE); + + if (gameraMode) + { + DrawText("GAMERA MODE", 60, 22, 40, GRAY); + DrawTexture(gframe, 0, 0, Fade(WHITE, 0.5f)); + } + + } break; + case ENDING: + { + // Draw a transparent black rectangle that covers all screen + DrawRectangle(0, 0, screenWidth, screenHeight, Fade(BLACK, 0.4f)); + + DrawTextEx(font, "GAME OVER", (Vector2){ 300, 160 }, font.size*3, -2, MAROON); + + DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ 680, 350 }, font.size, -2, GOLD); + DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 290, 350 }, font.size, -2, GOLD); + DrawTextEx(font, FormatText("HISCORE: %04i", hiscore), (Vector2){ 665, 400 }, font.size, -2, ORANGE); + DrawTextEx(font, FormatText("HIDISTANCE: %04i", (int)hidistance), (Vector2){ 270, 400 }, font.size, -2, ORANGE); + + // Draw blinking text + if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER to REPLAY", (Vector2){ screenWidth/2 - 250, 520 }, font.size, -2, LIGHTGRAY); + + } break; + default: break; + } + + EndDrawing(); + //---------------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/games/drturtle/makefile b/games/drturtle/makefile new file mode 100644 index 000000000..f9efd3e85 --- /dev/null +++ b/games/drturtle/makefile @@ -0,0 +1,186 @@ +#************************************************************************************************** +# +# raylib - makefile to compile Dr.Turtle game +# +# Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +# +# This software is provided "as-is", without any express or implied warranty. In no event +# will the authors be held liable for any damages arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, including commercial +# applications, and to alter it and redistribute it freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not claim that you +# wrote the original software. If you use this software in a product, an acknowledgment +# in the product documentation would be appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be misrepresented +# as being the original software. +# +# 3. This notice may not be removed or altered from any source distribution. +# +#************************************************************************************************** + +# define raylib platform if not defined (by default, compile for RPI) +# Other possible platform: PLATFORM_DESKTOP +PLATFORM ?= PLATFORM_DESKTOP + +# determine PLATFORM_OS in case PLATFORM_DESKTOP selected +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + ifeq ($(OS),Windows_NT) + PLATFORM_OS=WINDOWS + LIBPATH=win32 + else + UNAMEOS:=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + LIBPATH=linux + else + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS=OSX + LIBPATH=osx + endif + endif + endif +endif + +# define compiler: gcc for C program, define as g++ for C++ +ifeq ($(PLATFORM),PLATFORM_WEB) + # define emscripten compiler + CC = emcc +else +ifeq ($(PLATFORM_OS),OSX) + # define llvm compiler for mac + CC = clang +else + # define default gcc compiler + CC = gcc +endif +endif + +# define compiler flags: +# -O2 defines optimization level +# -Wall turns on most, but not all, compiler warnings +# -std=c99 use standard C from 1999 revision +ifeq ($(PLATFORM),PLATFORM_RPI) + CFLAGS = -O2 -Wall -std=gnu99 -fgnu89-inline +else + CFLAGS = -O2 -Wall -std=c99 +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources -s ALLOW_MEMORY_GROWTH=1 --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 --preload-file resources + #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing + #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) +endif + +# define any directories containing required header files +ifeq ($(PLATFORM),PLATFORM_RPI) + INCLUDES = -I. -I../../src -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads +else + INCLUDES = -I. -I../../src +# external libraries headers +# GLFW3 + INCLUDES += -I../../external/glfw3/include +# GLEW + INCLUDES += -I../../external/glew/include +# OpenAL Soft + INCLUDES += -I../../external/openal_soft/include +endif + +# define library paths containing required libs +ifeq ($(PLATFORM),PLATFORM_RPI) + LFLAGS = -L. -L../../src -L/opt/vc/lib +else + LFLAGS = -L. -L../../src + # external libraries to link with + # GLFW3 + LFLAGS += -L../../external/glfw3/lib/$(LIBPATH) + ifneq ($(PLATFORM_OS),OSX) + # OpenAL Soft + LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) + # GLEW + LFLAGS += -L../../external/glew/lib/$(LIBPATH) + endif +endif + +# define any libraries to link into executable +# if you want to link libraries (libname.so or libname.a), use the -lname +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),LINUX) + # libraries for Debian GNU/Linux desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -lGLEW -lGL -lopenal + endif + ifeq ($(PLATFORM_OS),OSX) + # libraries for OS X 10.9 desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -framework OpenGL -framework OpenAl -framework Cocoa + else + # libraries for Windows desktop compiling + # NOTE: GLFW3 and OpenAL Soft libraries should be installed + LIBS = -lraylib -lglfw3 -lglew32 -lopengl32 -lopenal32 -lgdi32 + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + # libraries for Raspberry Pi compiling + # NOTE: OpenAL Soft library should be installed (libopenal1 package) + LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + LIBS = ../../src/libraylib.bc +endif + +# define additional parameters and flags for windows +ifeq ($(PLATFORM_OS),WINDOWS) + # resources file contains windows exe icon + # -Wl,--subsystem,windows hides the console window + WINFLAGS = ../../src/resources -Wl,--subsystem,windows +endif + +ifeq ($(PLATFORM),PLATFORM_WEB) + EXT = .html +endif + +# define all screen object files required +SCREENS = \ + +# typing 'make' will invoke the first target entry in the file, +# in this case, the 'default' target entry is advance_game +default: drturtle + +# compile template - advance_game +drturtle: drturtle_final_web.c $(SCREENS) + $(CC) -o $@$(EXT) $< $(SCREENS) $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# clean everything +clean: +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),OSX) + find . -type f -perm +ugo+x -delete + rm -f *.o + else + ifeq ($(PLATFORM_OS),LINUX) + find . -type f -executable -delete + rm -f *.o + else + del *.o *.exe + endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + find . -type f -executable -delete + rm -f *.o +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + del *.o *.html *.js +endif + @echo Cleaning done + +# instead of defining every module one by one, we can define a pattern +# this pattern below will automatically compile every module defined on $(OBJS) +#%.exe : %.c +# $(CC) -o $@ $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) diff --git a/games/floppy.c b/games/floppy.c new file mode 100644 index 000000000..f48ea2352 --- /dev/null +++ b/games/floppy.c @@ -0,0 +1,246 @@ +/******************************************************************************************* +* +* raylib - sample game: floppy +* +* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define MAX_TUBES 100 +#define FLOPPY_RADIUS 24 +#define TUBES_WIDTH 80 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct Floppy { + Vector2 position; + int radius; + Color color; +} Floppy; + +typedef struct Tubes { + Rectangle rec; + Color color; + bool active; +} Tubes; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter; +static bool gameOver; +static bool pause; +static int score; +static int hiScore = 0; + +static Floppy floppy; +static Tubes tubes[MAX_TUBES*2]; +static Vector2 tubesPos[MAX_TUBES]; +static int tubesSpeedX; +static bool superfx; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: floppy"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +void InitGame(void) +{ + floppy.radius = FLOPPY_RADIUS; + floppy.position = (Vector2){80, screenHeight/2 - floppy.radius}; + tubesSpeedX = 2; + + for (int i = 0; i < MAX_TUBES; i++) + { + tubesPos[i].x = 400 + 280*i; + tubesPos[i].y = -GetRandomValue(0, 120); + } + + for (int i = 0; i < MAX_TUBES*2; i += 2) + { + tubes[i].rec.x = tubesPos[i/2].x; + tubes[i].rec.y = tubesPos[i/2].y; + tubes[i].rec.width = TUBES_WIDTH; + tubes[i].rec.height = 255; + + tubes[i+1].rec.x = tubesPos[i/2].x; + tubes[i+1].rec.y = 600 + tubesPos[i/2].y - 255; + tubes[i+1].rec.width = TUBES_WIDTH; + tubes[i+1].rec.height = 255; + + tubes[i/2].active = true; + } + + score = 0; + + gameOver = false; + superfx = false; + pause = false; +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + for (int i = 0; i < MAX_TUBES; i++) tubesPos[i].x -= tubesSpeedX; + + for (int i = 0; i < MAX_TUBES*2; i += 2) + { + tubes[i].rec.x = tubesPos[i/2].x; + tubes[i+1].rec.x = tubesPos[i/2].x; + } + + if (IsKeyDown(KEY_SPACE) && !gameOver) floppy.position.y -= 3; + else floppy.position.y += 1; + + // Check Collisions + for (int i = 0; i < MAX_TUBES*2; i++) + { + if (CheckCollisionCircleRec(floppy.position, floppy.radius, tubes[i].rec)) + { + gameOver = true; + pause = false; + } + else if ((tubesPos[i/2].x < floppy.position.x) && tubes[i/2].active && !gameOver) + { + score += 100; + tubes[i/2].active = false; + + superfx = true; + + if (score > hiScore) hiScore = score; + } + } + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + DrawCircle(floppy.position.x, floppy.position.y, floppy.radius, DARKGRAY); + + // Draw tubes + for (int i = 0; i < MAX_TUBES; i++) + { + DrawRectangle(tubes[i*2].rec.x, tubes[i*2].rec.y, tubes[i*2].rec.width, tubes[i*2].rec.height, GRAY); + DrawRectangle(tubes[i*2 + 1].rec.x, tubes[i*2 + 1].rec.y, tubes[i*2 + 1].rec.width, tubes[i*2 + 1].rec.height, GRAY); + } + + // Draw flashing fx (one frame only) + if (superfx) + { + DrawRectangle(0, 0, screenWidth, screenHeight, WHITE); + superfx = false; + } + + DrawText(FormatText("%04i", score), 20, 20, 40, GRAY); + DrawText(FormatText("HI-SCORE: %04i", hiScore), 20, 70, 20, LIGHTGRAY); + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} \ No newline at end of file diff --git a/games/floppy/floppy.c b/games/floppy/floppy.c deleted file mode 100644 index 0c0cb5f2e..000000000 --- a/games/floppy/floppy.c +++ /dev/null @@ -1,213 +0,0 @@ -/******************************************************************************************* -* -* raylib game - Floppy Bird -* -* This game has been created using raylib 1.1 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) -* -********************************************************************************************/ - -#include "raylib.h" - -#define MAX_TUBES 100 - -int main() -{ - // Initialization - //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "Floppy Bird"); - - InitAudioDevice(); // Initialize audio device - - Sound coin = LoadSound("resources/coin.wav"); - Sound jump = LoadSound("resources/jump.wav"); - - Texture2D background = LoadTexture("resources/background.png"); - Texture2D tubes = LoadTexture("resources/tubes.png"); - Texture2D floppy = LoadTexture("resources/floppy.png"); - - Vector2 floppyPos = { 80, screenHeight/2 - floppy.height/2 }; - - Vector2 tubesPos[MAX_TUBES]; - int tubesSpeedX = 2; - - for (int i = 0; i < MAX_TUBES; i++) - { - tubesPos[i].x = 400 + 280*i; - tubesPos[i].y = -GetRandomValue(0, 120); - } - - Rectangle tubesRecs[MAX_TUBES*2]; - bool tubesActive[MAX_TUBES]; - - for (int i = 0; i < MAX_TUBES*2; i += 2) - { - tubesRecs[i].x = tubesPos[i/2].x; - tubesRecs[i].y = tubesPos[i/2].y; - tubesRecs[i].width = tubes.width; - tubesRecs[i].height = 255; - - tubesRecs[i+1].x = tubesPos[i/2].x; - tubesRecs[i+1].y = 600 + tubesPos[i/2].y - 255; - tubesRecs[i+1].width = tubes.width; - tubesRecs[i+1].height = 255; - - tubesActive[i/2] = true; - } - - int backScroll = 0; - - int score = 0; - int hiscore = 0; - - bool gameover = false; - bool superfx = false; - - SetTargetFPS(60); - //--------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - - // Background scroll logic - backScroll--; - if (backScroll <= -800) backScroll = 0; - - // Player movement logic - if (!gameover) - { - if (IsKeyDown(KEY_SPACE)) floppyPos.y -= 3; - else floppyPos.y += 1; - - if (IsKeyPressed(KEY_SPACE)) PlaySound(jump); - } - - // Tubes moving logic - for (int i = 0; i < MAX_TUBES; i++) tubesPos[i].x -= tubesSpeedX; - - for (int i = 0; i < MAX_TUBES*2; i += 2) - { - tubesRecs[i].x = tubesPos[i/2].x; - tubesRecs[i+1].x = tubesPos[i/2].x; - } - - // Check collisions player-tubes - for (int i = 0; i < MAX_TUBES*2; i++) - { - if (CheckCollisionCircleRec((Vector2){ floppyPos.x + floppy.width/2, floppyPos.y + floppy.height/2 }, floppy.width/2, tubesRecs[i])) - { - gameover = true; - } - else if ((tubesPos[i/2].x < floppyPos.x) && tubesActive[i/2] && !gameover) - { - score += 100; - tubesActive[i/2] = false; - PlaySound(coin); - - superfx = true; - - if (score > hiscore) hiscore = score; - } - } - - // Gameover logic for reset - if (gameover && IsKeyPressed(KEY_ENTER)) - { - for (int i = 0; i < MAX_TUBES; i++) - { - tubesPos[i].x = 400 + 280*i; - tubesPos[i].y = -GetRandomValue(0, 120); - } - - for (int i = 0; i < MAX_TUBES*2; i += 2) - { - tubesRecs[i].x = tubesPos[i/2].x; - tubesRecs[i].y = tubesPos[i/2].y; - - tubesRecs[i+1].x = tubesPos[i/2].x; - tubesRecs[i+1].y = 600 + tubesPos[i/2].y - 255; - - tubesActive[i/2] = true; - } - - floppyPos.x = 80; - floppyPos.y = screenHeight/2 - floppy.height/2; - - gameover = false; - score = 0; - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - // Draw scrolling background - DrawTexture(background, backScroll, 0, WHITE); - DrawTexture(background, screenWidth + backScroll, 0, WHITE); - - // Draw moving tubes - for (int i = 0; i < MAX_TUBES; i++) - { - if (tubesPos[i].x <= 800) DrawTextureEx(tubes, tubesPos[i], 0, 1.0, WHITE); - - // Draw collision recs - //DrawRectangleLines(tubesRecs[i*2].x, tubesRecs[i*2].y, tubesRecs[i*2].width, tubesRecs[i*2].height, RED); - //DrawRectangleLines(tubesRecs[i*2 + 1].x, tubesRecs[i*2 + 1].y, tubesRecs[i*2 + 1].width, tubesRecs[i*2 + 1].height, RED); - } - - // Draw scores - DrawText(FormatText("%04i", score), 20, 20, 40, PINK); - DrawText(FormatText("HI-SCORE: %04i", hiscore), 20, 70, 20, VIOLET); - - // Draw player or game over messages - if (!gameover) - { - DrawTextureEx(floppy, floppyPos, 0, 1.0, WHITE); - - // Draw collision circle - //DrawCircleLines(floppyPos.x + floppy.width/2, floppyPos.y + floppy.height/2, floppy.width/2, RED); - } - else - { - DrawText("GAME OVER", 100, 180, 100, MAROON); - DrawText("PRESS ENTER to RETRY!", 280, 280, 20, RED); - } - - // Draw screen light flash when passing through a tube - if (superfx) - { - DrawRectangle(0, 0, screenWidth, screenHeight, GOLD); - superfx = false; - } - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - UnloadTexture(background); // Texture unloading - UnloadTexture(tubes); // Texture unloading - UnloadTexture(floppy); // Texture unloading - - UnloadSound(coin); // Unload sound data - UnloadSound(jump); // Unload sound data - - CloseAudioDevice(); // Close audio device - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} \ No newline at end of file diff --git a/games/floppy/resources/background.png b/games/floppy/resources/background.png deleted file mode 100644 index eab9d8650..000000000 Binary files a/games/floppy/resources/background.png and /dev/null differ diff --git a/games/floppy/resources/coin.wav b/games/floppy/resources/coin.wav deleted file mode 100644 index d3b6e93cd..000000000 Binary files a/games/floppy/resources/coin.wav and /dev/null differ diff --git a/games/floppy/resources/floppy.png b/games/floppy/resources/floppy.png deleted file mode 100644 index 7c8510868..000000000 Binary files a/games/floppy/resources/floppy.png and /dev/null differ diff --git a/games/floppy/resources/jump.wav b/games/floppy/resources/jump.wav deleted file mode 100644 index 1f68d3363..000000000 Binary files a/games/floppy/resources/jump.wav and /dev/null differ diff --git a/games/floppy/resources/tubes.png b/games/floppy/resources/tubes.png deleted file mode 100644 index a3ca8e7e5..000000000 Binary files a/games/floppy/resources/tubes.png and /dev/null differ diff --git a/games/gold_fever.c b/games/gold_fever.c new file mode 100644 index 000000000..5a4350272 --- /dev/null +++ b/games/gold_fever.c @@ -0,0 +1,288 @@ +/******************************************************************************************* +* +* raylib - sample game: gold fever +* +* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct Player { + Vector2 position; + Vector2 speed; + int radius; +} Player; + +typedef struct Enemy { + Vector2 position; + Vector2 speed; + int radius; + int radiusBounds; + bool moveRight; // RAY: o__O +} Enemy; + +typedef struct Points { + Vector2 position; + int radius; + int value; + bool active; +} Points; + +typedef struct Home { + Rectangle rec; + bool active; + bool save; + Color color; +} Home; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter; +static bool gameOver; +static bool pause; +static int score; +static int hiScore = 0; + +static Player player; +static Enemy enemy; +static Points points; +static Home home; +static bool follow; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + + InitWindow(screenWidth, screenHeight, "sample game: gold fever"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +void InitGame(void) +{ + pause = false; + score = 0; + + player.position = (Vector2){50, 50}; + player.radius = 20; + player.speed = (Vector2){5, 5}; + + enemy.position = (Vector2){screenWidth - 50, screenHeight/2}; + enemy.radius = 20; + enemy.radiusBounds = 150; + enemy.speed = (Vector2){3, 3}; + enemy.moveRight = true; + follow = false; + + points.radius = 10; + points.position = (Vector2){GetRandomValue(points.radius, screenWidth - points.radius), GetRandomValue(points.radius, screenHeight - points.radius)}; + points.value = 100; + points.active = true; + + home.rec.width = 50; + home.rec.height = 50; + home.rec.x = GetRandomValue(0, screenWidth - home.rec.width); + home.rec.y = GetRandomValue(0, screenHeight - home.rec.height); + home.active = false; + home.save = false; +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + //Control player + if (IsKeyDown(KEY_RIGHT)) player.position.x += player.speed.x; + if (IsKeyDown(KEY_LEFT)) player.position.x -= player.speed.x; + if (IsKeyDown(KEY_UP)) player.position.y -= player.speed.y; + if (IsKeyDown(KEY_DOWN)) player.position.y += player.speed.y; + + //wall behaviour player + if (player.position.x - player.radius <= 0) player.position.x = player.radius; + if (player.position.x + player.radius >= screenWidth) player.position.x = screenWidth - player.radius; + if (player.position.y - player.radius <= 0) player.position.y = player.radius; + if (player.position.y + player.radius >= screenHeight) player.position.y = screenHeight - player.radius; + + //IA Enemy + if ( (follow || CheckCollisionCircles(player.position, player.radius, enemy.position, enemy.radiusBounds)) && !home.save) + { + if (player.position.x > enemy.position.x) enemy.position.x += enemy.speed.x; + if (player.position.x < enemy.position.x) enemy.position.x -= enemy.speed.x; + + if (player.position.y > enemy.position.y) enemy.position.y += enemy.speed.y; + if (player.position.y < enemy.position.y) enemy.position.y -= enemy.speed.y; + } + else + { + if (enemy.moveRight) enemy.position.x += enemy.speed.x; + else enemy.position.x -= enemy.speed.x; + } + + //wall behaviour enemy + if (enemy.position.x - enemy.radius <= 0) enemy.moveRight = true; + if (enemy.position.x + enemy.radius >= screenWidth) enemy.moveRight = false; + + if (enemy.position.x - enemy.radius <= 0) enemy.position.x = enemy.radius; + if (enemy.position.x + enemy.radius >= screenWidth) enemy.position.x = screenWidth - enemy.radius; + if (enemy.position.y - enemy.radius <= 0) enemy.position.y = enemy.radius; + if (enemy.position.y + enemy.radius >= screenHeight) enemy.position.y = screenHeight - enemy.radius; + + //Collisions + if (CheckCollisionCircles(player.position, player.radius, points.position, points.radius) && points.active) + { + follow = true; + points.active = false; + home.active = true; + } + + if (CheckCollisionCircles(player.position, player.radius, enemy.position, enemy.radius) && !home.save) + { + gameOver = true; + + if (hiScore < score) hiScore = score; + } + + if (CheckCollisionCircleRec(player.position, player.radius, home.rec)) + { + follow = false; + + if (!points.active) + { + score += points.value; + points.active = true; + enemy.speed.x += 0.5; + enemy.speed.y += 0.5; + points.position = (Vector2){GetRandomValue(points.radius, screenWidth - points.radius), GetRandomValue(points.radius, screenHeight - points.radius)}; + } + + home.save = true; + } + else home.save = false; + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + if (follow) + { + DrawRectangle(0, 0, screenWidth, screenHeight, RED); + DrawRectangle(10, 10, screenWidth - 20, screenHeight - 20, RAYWHITE); + } + + DrawRectangleLines(home.rec.x, home.rec.y, home.rec.width, home.rec.height, BLUE); + + DrawCircleLines(enemy.position.x, enemy.position.y, enemy.radiusBounds, RED); + DrawCircleV(enemy.position, enemy.radius, MAROON); + + DrawCircleV(player.position, player.radius, GRAY); + if (points.active) DrawCircleV(points.position, points.radius, GOLD); + + DrawText(FormatText("SCORE: %04i", score), 20, 15, 20, GRAY); + DrawText(FormatText("HI-SCORE: %04i", hiScore), 300, 15, 20, GRAY); + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} \ No newline at end of file diff --git a/games/gorilas.c b/games/gorilas.c new file mode 100644 index 000000000..86fd3f5b4 --- /dev/null +++ b/games/gorilas.c @@ -0,0 +1,571 @@ +/******************************************************************************************* +* +* raylib - sample game: gorilas +* +* Sample game Marc Palau and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include +#include +#include +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define MAX_BUILDINGS 15 +#define MAX_EXPLOSIONS 200 +#define MAX_PLAYERS 2 + +#define BUILDING_RELATIVE_ERROR 30 // Building size random range % +#define BUILDING_MIN_RELATIVE_HEIGHT 20 // Minimum height in % of the screenHeight +#define BUILDING_MAX_RELATIVE_HEIGHT 60 // Maximum height in % of the screenHeight +#define BUILDING_MIN_GRAYSCALE_COLOR 120 // Minimum gray color for the buildings +#define BUILDING_MAX_GRAYSCALE_COLOR 200 // Maximum gray color for the buildings + +#define MIN_PLAYER_POSITION 5 // Minimum x position % +#define MAX_PLAYER_POSITION 20 // Maximum x position % + +#define GRAVITY 9.81f +#define DELTA_FPS 60 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct Player { + Vector2 position; + Vector2 size; + + Vector2 aimingPoint; + int aimingAngle; + int aimingPower; + + Vector2 previousPoint; + int previousAngle; + int previousPower; + + Vector2 impactPoint; + + bool isLeftTeam; // This player belongs to the left or to the right team + bool isPlayer; // If is a player or an AI + bool isAlive; +} Player; + +typedef struct Building { + Rectangle rectangle; + Color color; +} Building; + +typedef struct Explosion { + Vector2 position; + int radius; + bool active; +} Explosion; + +typedef struct Ball { + Vector2 position; + Vector2 speed; + int radius; + bool active; +} Ball; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static bool gameOver = false; +static bool pause = false; + +static Player player[MAX_PLAYERS]; +static Building building[MAX_BUILDINGS]; +static Explosion explosion[MAX_EXPLOSIONS]; +static Ball ball; + +static int playerTurn = 0; +static bool ballOnAir = false; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +// Additional module functions +static void InitBuildings(void); +static void InitPlayers(void); +static bool UpdatePlayer(int playerTurn); +static bool UpdateBall(int playerTurn); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: gorilas"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +void InitGame(void) +{ + // Init shoot + ball.radius = 10; + ballOnAir = false; + ball.active = false; + + InitBuildings(); + InitPlayers(); + + // Init explosions + for (int i = 0; i < MAX_EXPLOSIONS; i++) + { + explosion[i].position = (Vector2){ 0.0f, 0.0f }; + explosion[i].radius = 30; + explosion[i].active = false; + } +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + if (!ballOnAir) ballOnAir = UpdatePlayer(playerTurn); // If we are aiming + else + { + if (UpdateBall(playerTurn)) // If collision + { + // Game over logic + bool leftTeamAlive = false; + bool rightTeamAlive = false; + + for (int i = 0; i < MAX_PLAYERS; i++) + { + if (player[i].isAlive) + { + if (player[i].isLeftTeam) leftTeamAlive = true; + if (!player[i].isLeftTeam) rightTeamAlive = true; + } + } + + if (leftTeamAlive && rightTeamAlive) + { + ballOnAir = false; + ball.active = false; + + playerTurn++; + + if (playerTurn == MAX_PLAYERS) playerTurn = 0; + } + else + { + gameOver = true; + + // if (leftTeamAlive) left team wins + // if (rightTeamAlive) right team wins + } + } + } + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + // Draw buildings + for (int i = 0; i < MAX_BUILDINGS; i++) DrawRectangleRec(building[i].rectangle, building[i].color); + + // Draw explosions + for (int i = 0; i < MAX_EXPLOSIONS; i++) + { + if (explosion[i].active) DrawCircle(explosion[i].position.x, explosion[i].position.y, explosion[i].radius, RAYWHITE); + } + + // Draw players + for (int i = 0; i < MAX_PLAYERS; i++) + { + if (player[i].isAlive) + { + if (player[i].isLeftTeam) DrawRectangle(player[i].position.x - player[i].size.x/2, player[i].position.y - player[i].size.y/2, + player[i].size.x, player[i].size.y, BLUE); + else DrawRectangle(player[i].position.x - player[i].size.x/2, player[i].position.y - player[i].size.y/2, + player[i].size.x, player[i].size.y, RED); + } + } + + // Draw ball + if (ball.active) DrawCircle(ball.position.x, ball.position.y, ball.radius, MAROON); + + // Draw the angle and the power of the aim, and the previous ones + if (!ballOnAir) + { + // Draw shot information + /* + if (player[playerTurn].isLeftTeam) + { + DrawText(FormatText("Previous Point %i, %i", (int)player[playerTurn].previousPoint.x, (int)player[playerTurn].previousPoint.y), 20, 20, 20, DARKBLUE); + DrawText(FormatText("Previous Angle %i", player[playerTurn].previousAngle), 20, 50, 20, DARKBLUE); + DrawText(FormatText("Previous Power %i", player[playerTurn].previousPower), 20, 80, 20, DARKBLUE); + DrawText(FormatText("Aiming Point %i, %i", (int)player[playerTurn].aimingPoint.x, (int)player[playerTurn].aimingPoint.y), 20, 110, 20, DARKBLUE); + DrawText(FormatText("Aiming Angle %i", player[playerTurn].aimingAngle), 20, 140, 20, DARKBLUE); + DrawText(FormatText("Aiming Power %i", player[playerTurn].aimingPower), 20, 170, 20, DARKBLUE); + } + else + { + DrawText(FormatText("Previous Point %i, %i", (int)player[playerTurn].previousPoint.x, (int)player[playerTurn].previousPoint.y), screenWidth*3/4, 20, 20, DARKBLUE); + DrawText(FormatText("Previous Angle %i", player[playerTurn].previousAngle), screenWidth*3/4, 50, 20, DARKBLUE); + DrawText(FormatText("Previous Power %i", player[playerTurn].previousPower), screenWidth*3/4, 80, 20, DARKBLUE); + DrawText(FormatText("Aiming Point %i, %i", (int)player[playerTurn].aimingPoint.x, (int)player[playerTurn].aimingPoint.y), screenWidth*3/4, 110, 20, DARKBLUE); + DrawText(FormatText("Aiming Angle %i", player[playerTurn].aimingAngle), screenWidth*3/4, 140, 20, DARKBLUE); + DrawText(FormatText("Aiming Power %i", player[playerTurn].aimingPower), screenWidth*3/4, 170, 20, DARKBLUE); + } + */ + + // Draw aim + if (player[playerTurn].isLeftTeam) + { + // Previous aiming + DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 }, + (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 }, + player[playerTurn].previousPoint, GRAY); + + // Actual aiming + DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 }, + (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 }, + player[playerTurn].aimingPoint, DARKBLUE); + } + else + { + // Previous aiming + DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 }, + (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 }, + player[playerTurn].previousPoint, GRAY); + + // Actual aiming + DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 }, + (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 }, + player[playerTurn].aimingPoint, MAROON); + } + } + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} + +//-------------------------------------------------------------------------------------- +// Additional module functions +//-------------------------------------------------------------------------------------- +static void InitBuildings(void) +{ + // Horizontal generation + int currentWidth = 0; + + // We make sure the absolute error randomly generated for each building, has as a minimum value the screenWidth. + // This way all the screen will be filled with buildings. Each building will have a different, random width. + + float relativeWidth = 100/(100 - BUILDING_RELATIVE_ERROR); + float buildingWidthMean = (screenWidth*relativeWidth/MAX_BUILDINGS) + 1; // We add one to make sure we will cover the whole screen. + + // Vertical generation + int currentHeighth = 0; + int grayLevel; + + // Creation + for (int i = 0; i < MAX_BUILDINGS; i++) + { + // Horizontal + building[i].rectangle.x = currentWidth; + building[i].rectangle.width = GetRandomValue(buildingWidthMean*(100 - BUILDING_RELATIVE_ERROR/2)/100 + 1, buildingWidthMean*(100 + BUILDING_RELATIVE_ERROR)/100); + + currentWidth += building[i].rectangle.width; + + // Vertical + currentHeighth = GetRandomValue(BUILDING_MIN_RELATIVE_HEIGHT, BUILDING_MAX_RELATIVE_HEIGHT); + building[i].rectangle.y = screenHeight - (screenHeight*currentHeighth/100); + building[i].rectangle.height = screenHeight*currentHeighth/100 + 1; + + // Color + grayLevel = GetRandomValue(BUILDING_MIN_GRAYSCALE_COLOR, BUILDING_MAX_GRAYSCALE_COLOR); + building[i].color = (Color){ grayLevel, grayLevel, grayLevel, 255 }; + } +} + +static void InitPlayers(void) +{ + for (int i = 0; i < MAX_PLAYERS; i++) + { + player[i].isAlive = true; + + // Decide the team of this player + if (i % 2 == 0) player[i].isLeftTeam = true; + else player[i].isLeftTeam = false; + + // Now there is no AI + player[i].isPlayer = true; + + // Set size, by default by now + player[i].size = (Vector2){ 40, 40 }; + + // Set position + if (player[i].isLeftTeam) player[i].position.x = GetRandomValue(screenWidth*MIN_PLAYER_POSITION/100, screenWidth*MAX_PLAYER_POSITION/100); + else player[i].position.x = screenWidth - GetRandomValue(screenWidth*MIN_PLAYER_POSITION/100, screenWidth*MAX_PLAYER_POSITION/100); + + for (int j = 0; j < MAX_BUILDINGS; j++) + { + if (building[j].rectangle.x > player[i].position.x) + { + // Set the player in the center of the building + player[i].position.x = building[j-1].rectangle.x + building[j-1].rectangle.width/2; + // Set the player at the top of the building + player[i].position.y = building[j-1].rectangle.y - player[i].size.y/2; + break; + } + } + + // Set statistics to 0 + player[i].aimingPoint = player[i].position; + player[i].previousAngle = 0; + player[i].previousPower = 0; + player[i].previousPoint = player[i].position; + player[i].aimingAngle = 0; + player[i].aimingPower = 0; + + player[i].impactPoint = (Vector2){ -100, -100 }; + } +} + +static bool UpdatePlayer(int playerTurn) +{ + // If we are aiming at the firing quadrant, we calculate the angle + if (GetMousePosition().y <= player[playerTurn].position.y) + { + // Left team + if (player[playerTurn].isLeftTeam && GetMousePosition().x >= player[playerTurn].position.x) + { + // Distance (calculating the fire power) + player[playerTurn].aimingPower = sqrt(pow(player[playerTurn].position.x - GetMousePosition().x, 2) + pow(player[playerTurn].position.y - GetMousePosition().y, 2)); + // Calculates the angle via arcsin + player[playerTurn].aimingAngle = asin((player[playerTurn].position.y - GetMousePosition().y)/player[playerTurn].aimingPower)*RAD2DEG; + // Point of the screen we are aiming at + player[playerTurn].aimingPoint = GetMousePosition(); + + // Ball fired + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + player[playerTurn].previousPoint = player[playerTurn].aimingPoint; + player[playerTurn].previousPower = player[playerTurn].aimingPower; + player[playerTurn].previousAngle = player[playerTurn].aimingAngle; + ball.position = player[playerTurn].position; + + return true; + } + } + // Right team + else if (!player[playerTurn].isLeftTeam && GetMousePosition().x <= player[playerTurn].position.x) + { + // Distance (calculating the fire power) + player[playerTurn].aimingPower = sqrt(pow(player[playerTurn].position.x - GetMousePosition().x, 2) + pow(player[playerTurn].position.y - GetMousePosition().y, 2)); + // Calculates the angle via arcsin + player[playerTurn].aimingAngle = asin((player[playerTurn].position.y - GetMousePosition().y)/player[playerTurn].aimingPower)*RAD2DEG; + // Point of the screen we are aiming at + player[playerTurn].aimingPoint = GetMousePosition(); + + // Ball fired + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + player[playerTurn].previousPoint = player[playerTurn].aimingPoint; + player[playerTurn].previousPower = player[playerTurn].aimingPower; + player[playerTurn].previousAngle = player[playerTurn].aimingAngle; + ball.position = player[playerTurn].position; + + return true; + } + } + else + { + player[playerTurn].aimingPoint = player[playerTurn].position; + player[playerTurn].aimingPower = 0; + player[playerTurn].aimingAngle = 0; + } + } + else + { + player[playerTurn].aimingPoint = player[playerTurn].position; + player[playerTurn].aimingPower = 0; + player[playerTurn].aimingAngle = 0; + } + + return false; +} + +static bool UpdateBall(int playerTurn) +{ + static int explosionNumber = 0; + + // Activate ball + if (!ball.active) + { + if (player[playerTurn].isLeftTeam) + { + ball.speed.x = cos(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS; + ball.speed.y = -sin(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS; + ball.active = true; + } + else + { + ball.speed.x = -cos(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS; + ball.speed.y = -sin(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS; + ball.active = true; + } + } + + ball.position.x += ball.speed.x; + ball.position.y += ball.speed.y; + ball.speed.y += GRAVITY/DELTA_FPS; + + // Collision + if (ball.position.x + ball.radius < 0) return true; + else if (ball.position.x - ball.radius > screenWidth) return true; + else + { + // Player collision + for (int i = 0; i < MAX_PLAYERS; i++) + { + if (CheckCollisionCircleRec(ball.position, ball.radius, (Rectangle){ player[i].position.x - player[i].size.x/2, player[i].position.y - player[i].size.y/2, + player[i].size.x, player[i].size.y })) + { + // We can't hit ourselves + if (i == playerTurn) return false; + else + { + // We set the impact point + player[playerTurn].impactPoint.x = ball.position.x; + player[playerTurn].impactPoint.y = ball.position.y + ball.radius; + + // We destroy the player + player[i].isAlive = false; + return true; + } + } + } + + // Building collision + // NOTE: We only check building collision if we are not inside an explosion + for (int i = 0; i < MAX_BUILDINGS; i++) + { + if (CheckCollisionCircles(ball.position, ball.radius, explosion[i].position, explosion[i].radius - ball.radius)) + { + return false; + } + } + + for (int i = 0; i < MAX_BUILDINGS; i++) + { + if (CheckCollisionCircleRec(ball.position, ball.radius, building[i].rectangle)) + { + // We set the impact point + player[playerTurn].impactPoint.x = ball.position.x; + player[playerTurn].impactPoint.y = ball.position.y + ball.radius; + + // We create an explosion + explosion[explosionNumber].position = player[playerTurn].impactPoint; + explosion[explosionNumber].active = true; + explosionNumber++; + + return true; + } + } + } + + return false; +} \ No newline at end of file diff --git a/games/just_do/makefile b/games/just_do/makefile index 4c36b154f..5cca9df5b 100644 --- a/games/just_do/makefile +++ b/games/just_do/makefile @@ -72,7 +72,7 @@ else CFLAGS = -O2 -Wall -std=c99 endif ifeq ($(PLATFORM),PLATFORM_WEB) - CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --shell-file ../../templates/web_shell/shell.html #-s ASSERTIONS=1 --preload-file resources #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) diff --git a/games/light_my_ritual/light_my_ritual.c b/games/light_my_ritual/light_my_ritual.c new file mode 100644 index 000000000..0f1dc47ee --- /dev/null +++ b/games/light_my_ritual/light_my_ritual.c @@ -0,0 +1,271 @@ +/******************************************************************************************* +* +* GLOBAL GAME JAM 2016 - LIGHT MY RITUAL! +* +* Preparing a ritual session is not that easy. +* You must light all the candles before the astral alignment finishes... +* but dark creatures move in the shadows to put out all your lights! +* Be fast! Be smart! Light my ritual! +* +* This game has been created using raylib (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +********************************************************************************************/ + +#include "raylib.h" +#include "screens/screens.h" // NOTE: Defines global variable: currentScreen + +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- +const int screenWidth = 1280; +const int screenHeight = 720; + +// Required variables to manage screen transitions (fade-in, fade-out) +float transAlpha = 0; +bool onTransition = false; +bool transFadeOut = false; +int transFromScreen = -1; +int transToScreen = -1; + +//---------------------------------------------------------------------------------- +// Local Functions Declaration +//---------------------------------------------------------------------------------- +void TransitionToScreen(int screen); +void ChangeToScreen(int screen); // No transition effect +void UpdateTransition(void); +void DrawTransition(void); + +void UpdateDrawFrame(void); // Update and Draw one frame + +//---------------------------------------------------------------------------------- +// Main entry point +//---------------------------------------------------------------------------------- +int main(void) +{ + // Initialization + //--------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "GGJ16 - LIGHT MY RITUAL!"); + + // Global data loading (assets that must be available in all screens, i.e. fonts) + InitAudioDevice(); + + Image image = LoadImage("resources/lights_map.png"); // Load image in CPU memory (RAM) + + lightsMap = GetImageData(image); // Get image pixels data as an array of Color + lightsMapWidth = image.width; + lightsMapHeight = image.height; + + UnloadImage(image); // Unload image from CPU memory (RAM) + + //PlayMusicStream("resources/audio/come_play_with_me.ogg"); + + font = LoadSpriteFont("resources/font_arcadian.png"); + //doors = LoadTexture("resources/textures/doors.png"); + //sndDoor = LoadSound("resources/audio/door.ogg"); + + // Setup and Init first screen + currentScreen = LOGO_RL; + //InitTitleScreen(); + //InitGameplayScreen(); + rlInitLogoScreen(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + UpdateDrawFrame(); + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + switch (currentScreen) + { + case LOGO_RL: rlUnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + default: break; + } + + // Unload all global loaded data (i.e. fonts) here! + UnloadSpriteFont(font); + //UnloadSound(sndDoor); + + free(lightsMap); + + CloseAudioDevice(); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +void TransitionToScreen(int screen) +{ + onTransition = true; + transFromScreen = currentScreen; + transToScreen = screen; +} + +void ChangeToScreen(int screen) +{ + switch (currentScreen) + { + case LOGO_RL: rlUnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + default: break; + } + + switch (screen) + { + case LOGO_RL: rlInitLogoScreen(); break; + case TITLE: InitTitleScreen(); break; + case GAMEPLAY: InitGameplayScreen(); break; + default: break; + } + + currentScreen = screen; +} + +void UpdateTransition(void) +{ + if (!transFadeOut) + { + transAlpha += 0.05f; + + if (transAlpha >= 1.0) + { + transAlpha = 1.0; + + switch (transFromScreen) + { + case LOGO_RL: rlUnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + default: break; + } + + switch (transToScreen) + { + case LOGO_RL: + { + rlInitLogoScreen(); + currentScreen = LOGO_RL; + } break; + case TITLE: + { + InitTitleScreen(); + currentScreen = TITLE; + } break; + case GAMEPLAY: + { + InitGameplayScreen(); + currentScreen = GAMEPLAY; + } break; + default: break; + } + + transFadeOut = true; + } + } + else // Transition fade out logic + { + transAlpha -= 0.05f; + + if (transAlpha <= 0) + { + transAlpha = 0; + transFadeOut = false; + onTransition = false; + transFromScreen = -1; + transToScreen = -1; + } + } +} + +void DrawTransition(void) +{ + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, transAlpha)); +} + +// Update and draw game frame +void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + if (!onTransition) + { + switch(currentScreen) + { + case LOGO_RL: + { + rlUpdateLogoScreen(); + + if (rlFinishLogoScreen()) TransitionToScreen(TITLE); + + } break; + case TITLE: + { + UpdateTitleScreen(); + + if (FinishTitleScreen() == 1) TransitionToScreen(GAMEPLAY); + + } break; + case GAMEPLAY: + { + UpdateGameplayScreen(); + + if (FinishGameplayScreen() == 1) ChangeToScreen(LOGO_RL); + else if (FinishGameplayScreen() == 2) TransitionToScreen(TITLE); + + } break; + default: break; + } + } + else + { + // Update transition (fade-in, fade-out) + UpdateTransition(); + } + + UpdateMusicStream(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + switch(currentScreen) + { + case LOGO_RL: rlDrawLogoScreen(); break; + case TITLE: DrawTitleScreen(); break; + case GAMEPLAY: DrawGameplayScreen(); break; + default: break; + } + + if (onTransition) DrawTransition(); + + //DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} + diff --git a/games/light_my_ritual/makefile b/games/light_my_ritual/makefile new file mode 100644 index 000000000..84d7e994d --- /dev/null +++ b/games/light_my_ritual/makefile @@ -0,0 +1,203 @@ +#************************************************************************************************** +# +# raylib - Advance Game +# +# makefile to compile advance game for desktop platforms, Raspberry Pi and HTML5 (emscripten) +# +# Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +# +# This software is provided "as-is", without any express or implied warranty. In no event +# will the authors be held liable for any damages arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, including commercial +# applications, and to alter it and redistribute it freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not claim that you +# wrote the original software. If you use this software in a product, an acknowledgment +# in the product documentation would be appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be misrepresented +# as being the original software. +# +# 3. This notice may not be removed or altered from any source distribution. +# +#************************************************************************************************** + +# define raylib platform if not defined (by default, compile for RPI) +# Other possible platform: PLATFORM_DESKTOP +PLATFORM ?= PLATFORM_DESKTOP + +# determine PLATFORM_OS in case PLATFORM_DESKTOP selected +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + ifeq ($(OS),Windows_NT) + PLATFORM_OS=WINDOWS + LIBPATH=win32 + else + UNAMEOS:=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + LIBPATH=linux + else + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS=OSX + LIBPATH=osx + endif + endif + endif +endif + +# define compiler: gcc for C program, define as g++ for C++ +ifeq ($(PLATFORM),PLATFORM_WEB) + # define emscripten compiler + CC = emcc +else +ifeq ($(PLATFORM_OS),OSX) + # define llvm compiler for mac + CC = clang +else + # define default gcc compiler + CC = gcc +endif +endif + +# define compiler flags: +# -O2 defines optimization level +# -Wall turns on most, but not all, compiler warnings +# -std=c99 use standard C from 1999 revision +ifeq ($(PLATFORM),PLATFORM_RPI) + CFLAGS = -O2 -Wall -std=gnu99 -fgnu89-inline +else + CFLAGS = -O2 -Wall -std=c99 +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources -s ALLOW_MEMORY_GROWTH=1 --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 --preload-file resources + #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing + #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) +endif + +# define any directories containing required header files +ifeq ($(PLATFORM),PLATFORM_RPI) + INCLUDES = -I. -I../../src -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads +else + INCLUDES = -I. -I../../src +# external libraries headers +# GLFW3 + INCLUDES += -I../../external/glfw3/include +# GLEW + INCLUDES += -I../../external/glew/include +# OpenAL Soft + INCLUDES += -I../../external/openal_soft/include +endif + +# define library paths containing required libs +ifeq ($(PLATFORM),PLATFORM_RPI) + LFLAGS = -L. -L../../src -L/opt/vc/lib +else + LFLAGS = -L. -L../../src + # external libraries to link with + # GLFW3 + LFLAGS += -L../../external/glfw3/lib/$(LIBPATH) + ifneq ($(PLATFORM_OS),OSX) + # OpenAL Soft + LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) + # GLEW + LFLAGS += -L../../external/glew/lib/$(LIBPATH) + endif +endif + +# define any libraries to link into executable +# if you want to link libraries (libname.so or libname.a), use the -lname +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),LINUX) + # libraries for Debian GNU/Linux desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -lGLEW -lGL -lopenal + endif + ifeq ($(PLATFORM_OS),OSX) + # libraries for OS X 10.9 desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -framework OpenGL -framework OpenAl -framework Cocoa + else + # libraries for Windows desktop compiling + # NOTE: GLFW3 and OpenAL Soft libraries should be installed + LIBS = -lraylib -lglfw3 -lglew32 -lopengl32 -lopenal32 -lgdi32 + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + # libraries for Raspberry Pi compiling + # NOTE: OpenAL Soft library should be installed (libopenal1 package) + LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + LIBS = ../../src/libraylib.bc +endif + +# define additional parameters and flags for windows +ifeq ($(PLATFORM_OS),WINDOWS) + # resources file contains windows exe icon + # -Wl,--subsystem,windows hides the console window + WINFLAGS = ../../src/resources -Wl,--subsystem,windows +endif + +ifeq ($(PLATFORM),PLATFORM_WEB) + EXT = .html +endif + +# define all screen object files required +SCREENS = \ + screens/screen_logo_raylib.o \ + screens/screen_title.o \ + screens/screen_gameplay.o \ + +# typing 'make' will invoke the first target entry in the file, +# in this case, the 'default' target entry is advance_game +default: light_my_ritual + +# compile template - advance_game +light_my_ritual: light_my_ritual.c $(SCREENS) + $(CC) -o $@$(EXT) $< $(SCREENS) $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile screen LOGO raylib +screens/screen_logo_raylib.o: screens/screen_logo_raylib.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen TITLE +screens/screen_title.o: screens/screen_title.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen ENDING +screens/screen_gameplay.o: screens/screen_gameplay.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# clean everything +clean: +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),OSX) + find . -type f -perm +ugo+x -delete + rm -f *.o + else + ifeq ($(PLATFORM_OS),LINUX) + find . -type f -executable -delete + rm -f *.o + else + del *.o *.exe + endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + find . -type f -executable -delete + rm -f *.o +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + del *.o *.html *.js +endif + @echo Cleaning done + +# instead of defining every module one by one, we can define a pattern +# this pattern below will automatically compile every module defined on $(OBJS) +#%.exe : %.c +# $(CC) -o $@ $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) diff --git a/games/light_my_ritual/resources/audio/ambient.ogg b/games/light_my_ritual/resources/audio/ambient.ogg new file mode 100644 index 000000000..5828c5161 Binary files /dev/null and b/games/light_my_ritual/resources/audio/ambient.ogg differ diff --git a/games/light_my_ritual/resources/audio/light_off.wav b/games/light_my_ritual/resources/audio/light_off.wav new file mode 100644 index 000000000..d2203e721 Binary files /dev/null and b/games/light_my_ritual/resources/audio/light_off.wav differ diff --git a/games/light_my_ritual/resources/audio/light_on.wav b/games/light_my_ritual/resources/audio/light_on.wav new file mode 100644 index 000000000..38b7ca58d Binary files /dev/null and b/games/light_my_ritual/resources/audio/light_on.wav differ diff --git a/games/light_my_ritual/resources/audio/ritual.ogg b/games/light_my_ritual/resources/audio/ritual.ogg new file mode 100644 index 000000000..4674ff7b6 Binary files /dev/null and b/games/light_my_ritual/resources/audio/ritual.ogg differ diff --git a/games/light_my_ritual/resources/audio/start.wav b/games/light_my_ritual/resources/audio/start.wav new file mode 100644 index 000000000..66ce7ac16 Binary files /dev/null and b/games/light_my_ritual/resources/audio/start.wav differ diff --git a/games/light_my_ritual/resources/font_arcadian.png b/games/light_my_ritual/resources/font_arcadian.png new file mode 100644 index 000000000..5c3df51ac Binary files /dev/null and b/games/light_my_ritual/resources/font_arcadian.png differ diff --git a/games/light_my_ritual/resources/lights_map.png b/games/light_my_ritual/resources/lights_map.png new file mode 100644 index 000000000..362094cd8 Binary files /dev/null and b/games/light_my_ritual/resources/lights_map.png differ diff --git a/games/light_my_ritual/resources/textures/back_title.png b/games/light_my_ritual/resources/textures/back_title.png new file mode 100644 index 000000000..549212478 Binary files /dev/null and b/games/light_my_ritual/resources/textures/back_title.png differ diff --git a/games/light_my_ritual/resources/textures/background.png b/games/light_my_ritual/resources/textures/background.png new file mode 100644 index 000000000..367bdd30c Binary files /dev/null and b/games/light_my_ritual/resources/textures/background.png differ diff --git a/games/light_my_ritual/resources/textures/book.png b/games/light_my_ritual/resources/textures/book.png new file mode 100644 index 000000000..c0bfbdb37 Binary files /dev/null and b/games/light_my_ritual/resources/textures/book.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_i_off.png b/games/light_my_ritual/resources/textures/circle_level_i_off.png new file mode 100644 index 000000000..7961af7d4 Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_i_off.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_i_on.png b/games/light_my_ritual/resources/textures/circle_level_i_on.png new file mode 100644 index 000000000..1f2177349 Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_i_on.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_ii_off.png b/games/light_my_ritual/resources/textures/circle_level_ii_off.png new file mode 100644 index 000000000..642adc3be Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_ii_off.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_ii_on.png b/games/light_my_ritual/resources/textures/circle_level_ii_on.png new file mode 100644 index 000000000..93b71b3a5 Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_ii_on.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_iii_off.png b/games/light_my_ritual/resources/textures/circle_level_iii_off.png new file mode 100644 index 000000000..daf50be95 Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_iii_off.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_iii_on.png b/games/light_my_ritual/resources/textures/circle_level_iii_on.png new file mode 100644 index 000000000..e2256e95c Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_iii_on.png differ diff --git a/games/light_my_ritual/resources/textures/enemy.png b/games/light_my_ritual/resources/textures/enemy.png new file mode 100644 index 000000000..dc0a911d2 Binary files /dev/null and b/games/light_my_ritual/resources/textures/enemy.png differ diff --git a/games/light_my_ritual/resources/textures/foreground_level_i.png b/games/light_my_ritual/resources/textures/foreground_level_i.png new file mode 100644 index 000000000..32b96740d Binary files /dev/null and b/games/light_my_ritual/resources/textures/foreground_level_i.png differ diff --git a/games/light_my_ritual/resources/textures/foreground_level_ii.png b/games/light_my_ritual/resources/textures/foreground_level_ii.png new file mode 100644 index 000000000..44f26003a Binary files /dev/null and b/games/light_my_ritual/resources/textures/foreground_level_ii.png differ diff --git a/games/light_my_ritual/resources/textures/foreground_level_iii.png b/games/light_my_ritual/resources/textures/foreground_level_iii.png new file mode 100644 index 000000000..0fc039d72 Binary files /dev/null and b/games/light_my_ritual/resources/textures/foreground_level_iii.png differ diff --git a/games/light_my_ritual/resources/textures/light.png b/games/light_my_ritual/resources/textures/light.png new file mode 100644 index 000000000..5d08326f8 Binary files /dev/null and b/games/light_my_ritual/resources/textures/light.png differ diff --git a/games/light_my_ritual/resources/textures/light_glow.png b/games/light_my_ritual/resources/textures/light_glow.png new file mode 100644 index 000000000..d31356c6d Binary files /dev/null and b/games/light_my_ritual/resources/textures/light_glow.png differ diff --git a/games/light_my_ritual/resources/textures/light_ray.png b/games/light_my_ritual/resources/textures/light_ray.png new file mode 100644 index 000000000..f9f877fa4 Binary files /dev/null and b/games/light_my_ritual/resources/textures/light_ray.png differ diff --git a/games/light_my_ritual/resources/textures/msg_ritual.png b/games/light_my_ritual/resources/textures/msg_ritual.png new file mode 100644 index 000000000..73f14d484 Binary files /dev/null and b/games/light_my_ritual/resources/textures/msg_ritual.png differ diff --git a/games/light_my_ritual/resources/textures/player.png b/games/light_my_ritual/resources/textures/player.png new file mode 100644 index 000000000..d6849478c Binary files /dev/null and b/games/light_my_ritual/resources/textures/player.png differ diff --git a/games/light_my_ritual/resources/textures/time_over.png b/games/light_my_ritual/resources/textures/time_over.png new file mode 100644 index 000000000..9f7935bea Binary files /dev/null and b/games/light_my_ritual/resources/textures/time_over.png differ diff --git a/games/light_my_ritual/resources/textures/title.png b/games/light_my_ritual/resources/textures/title.png new file mode 100644 index 000000000..55eb593dd Binary files /dev/null and b/games/light_my_ritual/resources/textures/title.png differ diff --git a/games/light_my_ritual/screens/screen_gameplay.c b/games/light_my_ritual/screens/screen_gameplay.c new file mode 100644 index 000000000..b91d25459 --- /dev/null +++ b/games/light_my_ritual/screens/screen_gameplay.c @@ -0,0 +1,842 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +#include + +#define MAX_LIGHTS_I 8 +#define MAX_LIGHTS_II 12 +#define MAX_LIGHTS_III 20 + +#define MAX_ENEMIES 8 + +#define MAX_PLAYER_ENERGY 40.0f +#define ENERGY_REFILL_RATIO 0.2f + +#define GAMEPAD_SENSITIVITY 4.0f // More sensitivity, more speed :P + +#define LIGHT_ANIM_FRAMES 7 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct Player { + Vector2 position; + Vector2 speed; + int radius; + Color color; + float lightEnergy; +} Player; + +typedef struct Enemy { + Vector2 position; + Vector2 targetPos; // light target position + int targetNum; // light target number + float speed; // scalar value + int radius; + int active; + int awakeFramesDelay; + int framesCounter; + Color color; +} Enemy; + +typedef struct Light { + Vector2 position; + int radius; + int requiredEnergy; + bool active; + Color color; + + int framesCounter; + int currentFrame; + Rectangle frameRec; +} Light; + +typedef enum { LEVEL_I, LEVEL_II, LEVEL_III, LEVEL_FINISHED } LightedLevel; + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +//static Texture2D background; + +static bool pause; + +static Player player; + +static Light lightsI[MAX_LIGHTS_I]; +static Light lightsII[MAX_LIGHTS_II]; +static Light lightsIII[MAX_LIGHTS_III]; + +static Enemy enemies[MAX_ENEMIES]; + +static int ritualLevel; +static int previousLightedLevel; +static int currentLightedLevel; + +static Vector2 lighterPosition; + +static int maxLightEnergy; +static int currentLightEnergy; + +static float ritualTime; +static bool startRitual; +static float alphaRitual; + +static bool timeOver; +static int nextStarsAlignment; + +static Texture2D background; +static Texture2D foregroundI; +static Texture2D foregroundII; +static Texture2D foregroundIII; +static Texture2D texPlayer; +static Texture2D texEnemy; +static Texture2D texLight; +static Texture2D lightGlow; +static Texture2D lightRay; +static Texture2D book; +static Texture2D texRitual; +static Texture2D texTimeOver; +static Texture2D circleIoff, circleIIoff, circleIIIoff; +static Texture2D circleIon, circleIIon, circleIIIon; + +static Rectangle lightOff, lightOn; + +static Sound fxLightOn, fxLightOff; + +// Debug variables +static bool enemiesStopped; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static bool ColorEqual(Color col1, Color col2); // Check if two colors are equal +static Vector2 Vector2Subtract(Vector2 v1, Vector2 v2); +static void Vector2Normalize(Vector2 *v); +static void EnemyReset(Enemy *enemy); + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitGameplayScreen(void) +{ + framesCounter = 0; + finishScreen = 0; + pause = false; + + // Textures loading + background = LoadTexture("resources/textures/background.png"); + foregroundI = LoadTexture("resources/textures/foreground_level_i.png"); + foregroundII = LoadTexture("resources/textures/foreground_level_ii.png"); + foregroundIII = LoadTexture("resources/textures/foreground_level_iii.png"); + texPlayer = LoadTexture("resources/textures/player.png"); + texEnemy = LoadTexture("resources/textures/enemy.png"); + texLight = LoadTexture("resources/textures/light.png"); + lightGlow = LoadTexture("resources/textures/light_glow.png"); + lightRay = LoadTexture("resources/textures/light_ray.png"); + book = LoadTexture("resources/textures/book.png"); + texRitual = LoadTexture("resources/textures/msg_ritual.png"); + texTimeOver = LoadTexture("resources/textures/time_over.png"); + + circleIoff = LoadTexture("resources/textures/circle_level_i_off.png"); + circleIIoff = LoadTexture("resources/textures/circle_level_ii_off.png"); + circleIIIoff = LoadTexture("resources/textures/circle_level_iii_off.png"); + circleIon = LoadTexture("resources/textures/circle_level_i_on.png"); + circleIIon = LoadTexture("resources/textures/circle_level_ii_on.png"); + circleIIIon = LoadTexture("resources/textures/circle_level_iii_on.png"); + + lightOff = (Rectangle){ 0, 0, 64, 64 }; + lightOn = (Rectangle){ 64, 0, 64, 64 }; + + fxLightOn = LoadSound("resources/audio/light_on.wav"); + fxLightOff = LoadSound("resources/audio/light_off.wav"); + + // Initialize player + player.position = (Vector2){ GetScreenWidth()/2, GetScreenHeight()/2 - 40 }; + player.radius = 20; + player.speed = (Vector2){5, 5}; + player.color = WHITE; + + // Initialize lights positions based on lights map image data + int kI = 0, kII = 0, kIII = 0; + for (int y = 0; y < lightsMapHeight; y++) + { + for (int x = 0; x < lightsMapWidth; x++) + { + if (ColorEqual(lightsMap[y*lightsMapWidth + x], (Color){ 255, 0, 0, 255 })) + { + // Store light position I + lightsI[kI].position.x = (float)x*10; + lightsI[kI].position.y = (float)y*10; + kI++; + + //printf("Light %02i position: %i, %i\n", kI, (int)lightsI[kI - 1].position.x, (int)lightsI[kI - 1].position.y); + } + else if (ColorEqual(lightsMap[y*lightsMapWidth + x], (Color){ 0, 255, 0, 255 })) + { + // Store light position II + lightsII[kII].position.x = (float)x*10; + lightsII[kII].position.y = (float)y*10; + kII++; + } + else if (ColorEqual(lightsMap[y*lightsMapWidth + x], (Color){ 0, 0, 255, 255 })) + { + // Store light position III + lightsIII[kIII].position.x = (float)x*10; + lightsIII[kIII].position.y = (float)y*10; + kIII++; + } + } + } + + // Initialize lights I + for (int i = 0; i < MAX_LIGHTS_I; i++) + { + lightsI[i].radius = 12; + lightsI[i].requiredEnergy = GetRandomValue(3, 9); + lightsI[i].active = false; + lightsI[i].color = GOLD; + + lightsI[i].framesCounter = 0; + lightsI[i].currentFrame = 0; + lightsI[i].frameRec = (Rectangle){ 0, 0, 64, 64 }; + } + + // Initialize lights II + for (int i = 0; i < MAX_LIGHTS_II; i++) + { + lightsII[i].radius = 8; + lightsII[i].requiredEnergy = GetRandomValue(3, 8); + lightsII[i].active = false; + lightsII[i].color = GOLD; + + lightsII[i].framesCounter = 0; + lightsII[i].currentFrame = 0; + lightsII[i].frameRec = (Rectangle){ 0, 0, 64, 64 }; + } + + // Initialize lights III + for (int i = 0; i < MAX_LIGHTS_III; i++) + { + lightsIII[i].radius = 8; + lightsIII[i].requiredEnergy = GetRandomValue(4, 10); + lightsIII[i].active = false; + lightsIII[i].color = GOLD; + + lightsIII[i].framesCounter = 0; + lightsIII[i].currentFrame = 0; + lightsIII[i].frameRec = (Rectangle){ 0, 0, 64, 64 }; + } + + // Initialize ritual level + ritualLevel = 0; + currentLightedLevel = LEVEL_I; + lighterPosition = (Vector2){ GetScreenWidth()/2, GetScreenHeight()/2 }; + + // Initialize enemies + for (int i = 0; i < MAX_ENEMIES; i++) EnemyReset(&enemies[i]); + + // Initialize max light energy (depends on lights randomness) + maxLightEnergy = 0; + + for (int i = 0; i < MAX_LIGHTS_I; i++) maxLightEnergy += lightsI[i].requiredEnergy; + for (int i = 0; i < MAX_LIGHTS_II; i++) maxLightEnergy += lightsII[i].requiredEnergy; + for (int i = 0; i < MAX_LIGHTS_III; i++) maxLightEnergy += lightsIII[i].requiredEnergy; + + //printf("Max light energy: %i\n", maxLightEnergy); + + // Initialize ritual variables + ritualTime = 0.0f; + startRitual = false;; + alphaRitual = 0.0f; + + timeOver = false; + nextStarsAlignment = GetRandomValue(500, 1000); + + enemiesStopped = false; + + PlayMusicStream("resources/audio/ritual.ogg"); +} + +// Gameplay Screen Update logic +void UpdateGameplayScreen(void) +{ + if (IsKeyPressed('P')) pause = !pause; + + if (!pause && (currentLightedLevel != LEVEL_FINISHED) && !timeOver) + { + framesCounter++; // Time starts counting to awake enemies + + // Player movement logic + if (IsKeyDown(KEY_RIGHT)) player.position.x += player.speed.x; + else if (IsKeyDown(KEY_LEFT)) player.position.x -= player.speed.x; + + if (IsKeyDown(KEY_UP)) player.position.y -= player.speed.y; + else if (IsKeyDown(KEY_DOWN)) player.position.y += player.speed.y; + + // Debug key to stop enemies + if (IsKeyPressed(KEY_S)) enemiesStopped = !enemiesStopped; + + /* + if (IsGamepadAvailable(GAMEPAD_PLAYER1)) + { + Vector2 movement = GetGamepadMovement(GAMEPAD_PLAYER1); + + player.position.x += movement.x*GAMEPAD_SENSITIVITY; + player.position.y += movement.y*GAMEPAD_SENSITIVITY; + } + */ + + // Player light energy filling logic + if (CheckCollisionCircles(player.position, player.radius, lighterPosition, 50)) + { + player.lightEnergy += ENERGY_REFILL_RATIO; + player.color = (Color){ 255, 255, 100, 255 }; + } + else player.color = WHITE; + + if (player.lightEnergy > MAX_PLAYER_ENERGY) player.lightEnergy = MAX_PLAYER_ENERGY; + + // Player vs lights collision detection (depends on lighted level) + if (currentLightedLevel == LEVEL_I) + { + for (int i = 0; i < MAX_LIGHTS_I; i++) + { + // Check player vs lightI collision + if (CheckCollisionCircles(player.position, player.radius, lightsI[i].position, lightsI[i].radius)) + { + if (!lightsI[i].active && (player.lightEnergy >= lightsI[i].requiredEnergy)) + { + lightsI[i].active = true; + lightsI[i].currentFrame = 1; + player.lightEnergy -= lightsI[i].requiredEnergy; + + PlaySound(fxLightOn); + } + } + } + } + else if (currentLightedLevel == LEVEL_II) + { + for (int i = 0; i < MAX_LIGHTS_II; i++) + { + if (CheckCollisionCircles(player.position, player.radius, lightsII[i].position, lightsII[i].radius)) + { + if (!lightsII[i].active && (player.lightEnergy >= lightsII[i].requiredEnergy)) + { + lightsII[i].active = true; + player.lightEnergy -= lightsII[i].requiredEnergy; + + PlaySound(fxLightOn); + } + } + } + } + else if (currentLightedLevel == LEVEL_III) + { + for (int i = 0; i < MAX_LIGHTS_III; i++) + { + if (CheckCollisionCircles(player.position, player.radius, lightsIII[i].position, lightsIII[i].radius)) + { + if (!lightsIII[i].active && (player.lightEnergy >= lightsIII[i].requiredEnergy)) + { + lightsIII[i].active = true; + player.lightEnergy -= lightsIII[i].requiredEnergy; + + PlaySound(fxLightOn); + } + } + } + } + + // Lights animation (it doesn't depend on currentLightedLevel) + for (int i = 0; i < MAX_LIGHTS_I; i++) + { + // Light animation + if (lightsI[i].active) + { + lightsI[i].framesCounter++; + + if (lightsI[i].framesCounter > 10) + { + lightsI[i].currentFrame++; + + if (lightsI[i].currentFrame > LIGHT_ANIM_FRAMES - 1) lightsI[i].currentFrame = 1; + + lightsI[i].framesCounter = 0; + } + } + + lightsI[i].frameRec.x = lightsI[i].currentFrame*texLight.width/LIGHT_ANIM_FRAMES; + } + + for (int i = 0; i < MAX_LIGHTS_II; i++) + { + // Light animation + if (lightsII[i].active) + { + lightsII[i].framesCounter++; + + if (lightsII[i].framesCounter > 10) + { + lightsII[i].currentFrame++; + + if (lightsII[i].currentFrame > LIGHT_ANIM_FRAMES - 1) lightsII[i].currentFrame = 1; + + lightsII[i].framesCounter = 0; + } + } + + lightsII[i].frameRec.x = lightsII[i].currentFrame*texLight.width/LIGHT_ANIM_FRAMES; + } + + for (int i = 0; i < MAX_LIGHTS_III; i++) + { + // Light animation + if (lightsIII[i].active) + { + lightsIII[i].framesCounter++; + + if (lightsIII[i].framesCounter > 10) + { + lightsIII[i].currentFrame++; + + if (lightsIII[i].currentFrame > LIGHT_ANIM_FRAMES - 1) lightsIII[i].currentFrame = 1; + + lightsIII[i].framesCounter = 0; + } + } + + lightsIII[i].frameRec.x = lightsIII[i].currentFrame*texLight.width/LIGHT_ANIM_FRAMES; + } + + // Enemies logic + if (!enemiesStopped) + { + for (int i = 0; i < MAX_ENEMIES; i++) + { + if (!enemies[i].active) enemies[i].framesCounter++; + + if (enemies[i].framesCounter > enemies[i].awakeFramesDelay) enemies[i].active = true; + + if (enemies[i].active) + { + // Move to the target + Vector2 dir = Vector2Subtract(enemies[i].targetPos, enemies[i].position); + Vector2Normalize(&dir); + + enemies[i].position.x += dir.x*enemies[i].speed; + enemies[i].position.y += dir.y*enemies[i].speed; + + if (currentLightedLevel == LEVEL_I) + { + if (CheckCollisionCircles(enemies[i].position, enemies[i].radius, enemies[i].targetPos, lightsI[enemies[i].targetNum].radius)) + { + lightsI[enemies[i].targetNum].active = false; + lightsI[enemies[i].targetNum].framesCounter = 0; + lightsI[enemies[i].targetNum].currentFrame = 0; + lightsI[enemies[i].targetNum].frameRec = (Rectangle){ 0, 0, 64, 64 }; + + EnemyReset(&enemies[i]); + + PlaySound(fxLightOff); + } + } + else if (currentLightedLevel == LEVEL_II) + { + if (CheckCollisionCircles(enemies[i].position, enemies[i].radius, enemies[i].targetPos, lightsII[enemies[i].targetNum].radius)) + { + lightsII[enemies[i].targetNum].active = false; + lightsII[enemies[i].targetNum].framesCounter = 0; + lightsII[enemies[i].targetNum].currentFrame = 0; + lightsII[enemies[i].targetNum].frameRec = (Rectangle){ 0, 0, 64, 64 }; + + EnemyReset(&enemies[i]); + + PlaySound(fxLightOff); + } + } + else if (currentLightedLevel == LEVEL_III) + { + if (CheckCollisionCircles(enemies[i].position, enemies[i].radius, enemies[i].targetPos, lightsIII[enemies[i].targetNum].radius)) + { + lightsIII[enemies[i].targetNum].active = false; + lightsIII[enemies[i].targetNum].framesCounter = 0; + lightsIII[enemies[i].targetNum].currentFrame = 0; + lightsIII[enemies[i].targetNum].frameRec = (Rectangle){ 0, 0, 64, 64 }; + + EnemyReset(&enemies[i]); + + PlaySound(fxLightOff); + } + } + } + } + } + + // Check current light energy (for right bar) + currentLightEnergy = 0; + + for (int i = 0; i < MAX_LIGHTS_I; i++) if (lightsI[i].active) currentLightEnergy += lightsI[i].requiredEnergy; + for (int i = 0; i < MAX_LIGHTS_II; i++) if (lightsII[i].active) currentLightEnergy += lightsII[i].requiredEnergy; + for (int i = 0; i < MAX_LIGHTS_III; i++) if (lightsIII[i].active) currentLightEnergy += lightsIII[i].requiredEnergy; + + // Check current lighted level + // Check ending conditions: all lights off, ritual level reached + previousLightedLevel = currentLightedLevel; + + currentLightedLevel = LEVEL_I; + + bool lightedLevel = true; + for (int i = 0; i < MAX_LIGHTS_I; i++) if (!lightsI[i].active) lightedLevel = false; + if (lightedLevel) currentLightedLevel = LEVEL_II; + + for (int i = 0; i < MAX_LIGHTS_II; i++) if (!lightsII[i].active) lightedLevel = false; + if (lightedLevel) currentLightedLevel = LEVEL_III; + + for (int i = 0; i < MAX_LIGHTS_III; i++) if (!lightsIII[i].active) lightedLevel = false; + if (lightedLevel) + { + currentLightedLevel = LEVEL_FINISHED; + + for (int i = 0; i < MAX_ENEMIES; i++) enemies[i].active = false; + } + + if (currentLightedLevel != previousLightedLevel) for (int i = 0; i < MAX_ENEMIES; i++) EnemyReset(&enemies[i]); + + ritualTime = (float)framesCounter/60; + + // Check game over condition (time run out) + if ((99.0f - ritualTime) <= 0.0f) + { + ritualTime = 99.0f; + timeOver = true; + } + } + + if (startRitual) + { + alphaRitual += 0.02f; + + SetMusicVolume(1.0f - alphaRitual); + + if (alphaRitual > 1.0f) finishScreen = 1; + } +} + +// Gameplay Screen Draw logic +void DrawGameplayScreen(void) +{ + DrawTexture(background, 0, 0, WHITE); + + // DrawText("STARS ARE ALIGNED! NO TIME TO LOOSE! LIGHT MY RITUAL!", + + // Draw foreground and circles + if ((currentLightedLevel == LEVEL_FINISHED) || (currentLightedLevel == LEVEL_III)) DrawTexture(foregroundIII, 0, 0, WHITE); + else if (currentLightedLevel == LEVEL_II) DrawTexture(foregroundII, 0, 0, WHITE); + else if (currentLightedLevel == LEVEL_I) DrawTexture(foregroundI, 0, 0, WHITE); + + // Draw lighted circles (depends on current lighted level) + switch (currentLightedLevel) + { + case LEVEL_FINISHED: + { + DrawTexture(circleIIIon, GetScreenWidth()/2 - circleIIIon.width/2, GetScreenHeight()/2 - circleIIIon.height/2, WHITE); + DrawTexture(circleIIon, GetScreenWidth()/2 - circleIIon.width/2, GetScreenHeight()/2 - circleIIon.height/2, WHITE); + DrawTexture(circleIon, GetScreenWidth()/2 - circleIon.width/2, GetScreenHeight()/2 - circleIon.height/2, WHITE); + } break; + case LEVEL_III: + { + DrawTexture(circleIIIoff, GetScreenWidth()/2 - circleIIIoff.width/2, GetScreenHeight()/2 - circleIIIoff.height/2, WHITE); + DrawTexture(circleIIon, GetScreenWidth()/2 - circleIIon.width/2, GetScreenHeight()/2 - circleIIon.height/2, WHITE); + DrawTexture(circleIon, GetScreenWidth()/2 - circleIon.width/2, GetScreenHeight()/2 - circleIon.height/2, WHITE); + } break; + case LEVEL_II: + { + DrawTexture(circleIIoff, GetScreenWidth()/2 - circleIIoff.width/2, GetScreenHeight()/2 - circleIIoff.height/2, WHITE); + DrawTexture(circleIon, GetScreenWidth()/2 - circleIon.width/2, GetScreenHeight()/2 - circleIon.height/2, WHITE); + } break; + case LEVEL_I: + { + DrawTexture(circleIoff, GetScreenWidth()/2 - circleIoff.width/2, GetScreenHeight()/2 - circleIoff.height/2, WHITE); + } break; + default: break; + } + + // Draw lights (depends on current lighted level) + switch (currentLightedLevel) + { + case LEVEL_FINISHED: + case LEVEL_III: + { + for (int i = 0; i < MAX_LIGHTS_III; i++) + { + //if (lightsIII[i].active) DrawCircleV(lightsIII[i].position, lightsIII[i].radius, GOLD); + //else DrawCircleLines(lightsIII[i].position.x, lightsIII[i].position.y, lightsIII[i].radius, GRAY); + + if (lightsIII[i].active) + { + DrawTextureRec(texLight, lightsIII[i].frameRec, (Vector2){ lightsIII[i].position.x - 32, lightsIII[i].position.y - 32 }, WHITE); + DrawTexture(lightGlow, lightsIII[i].position.x - lightGlow.width/2, lightsIII[i].position.y - lightGlow.height/2, Fade(WHITE, 0.3f)); + DrawText(FormatText("%02i", lightsIII[i].requiredEnergy), lightsIII[i].position.x - 10, lightsIII[i].position.y + 14, 20, GRAY); + } + else + { + DrawTextureRec(texLight, lightsIII[i].frameRec, (Vector2){ lightsIII[i].position.x - 32, lightsIII[i].position.y - 32 }, WHITE); + DrawText(FormatText("%02i", lightsIII[i].requiredEnergy), lightsIII[i].position.x - 10, lightsIII[i].position.y + 14, 20, YELLOW); + } + } + } + case LEVEL_II: + { + for (int i = 0; i < MAX_LIGHTS_II; i++) + { + //if (lightsII[i].active) DrawCircleV(lightsII[i].position, lightsII[i].radius, GOLD); + //else DrawCircleLines(lightsI[i].position.x, lightsI[i].position.y, lightsI[i].radius, GRAY); + + if (lightsII[i].active) + { + DrawTextureRec(texLight, lightsII[i].frameRec, (Vector2){ lightsII[i].position.x - 32, lightsII[i].position.y - 32 }, WHITE); + DrawTexture(lightGlow, lightsII[i].position.x - lightGlow.width/2, lightsII[i].position.y - lightGlow.height/2, Fade(WHITE, 0.3f)); + DrawText(FormatText("%02i", lightsII[i].requiredEnergy), lightsII[i].position.x - 10, lightsII[i].position.y + 14, 20, GRAY); + } + else + { + DrawTextureRec(texLight, lightsII[i].frameRec, (Vector2){ lightsII[i].position.x - 32, lightsII[i].position.y - 32 }, WHITE); + DrawText(FormatText("%02i", lightsII[i].requiredEnergy), lightsII[i].position.x - 10, lightsII[i].position.y + 14, 20, YELLOW); + } + } + } + case LEVEL_I: + { + for (int i = 0; i < MAX_LIGHTS_I; i++) + { + //if (lightsI[i].active) DrawCircleV(lightsI[i].position, lightsI[i].radius, GOLD); + //else DrawCircleLines(lightsI[i].position.x, lightsI[i].position.y, lightsI[i].radius, GRAY); + + if (lightsI[i].active) + { + DrawTextureRec(texLight, lightsI[i].frameRec, (Vector2){ lightsI[i].position.x - 32, lightsI[i].position.y - 32 }, WHITE); + DrawTexture(lightGlow, lightsI[i].position.x - lightGlow.width/2, lightsI[i].position.y - lightGlow.height/2, Fade(WHITE, 0.3f)); + DrawText(FormatText("%02i", lightsI[i].requiredEnergy), lightsI[i].position.x - 10, lightsI[i].position.y + 14, 20, GRAY); + } + else + { + DrawTextureRec(texLight, lightsI[i].frameRec, (Vector2){ lightsI[i].position.x - 32, lightsI[i].position.y - 32 }, WHITE); + DrawText(FormatText("%02i", lightsI[i].requiredEnergy), lightsI[i].position.x - 10, lightsI[i].position.y + 14, 20, YELLOW); + } + } + } + default: break; + } + + // Draw main lighter + DrawTexture(book, GetScreenWidth()/2 - book.width/2, GetScreenHeight()/2, WHITE); + DrawTexture(lightRay, GetScreenWidth()/2 - lightRay.width/2, 0, Fade(WHITE, 0.5f)); + + // Draw player + //DrawCircleV(player.position, player.radius, player.color); + DrawTexture(texPlayer, player.position.x - 32, player.position.y - 32, player.color); + + if (currentLightedLevel != LEVEL_FINISHED) + { + // Draw enemies (depends on current lighted level) + for (int i = 0; i < MAX_ENEMIES; i++) + { + if (enemies[i].active) + { + //DrawCircleV(enemies[i].position, enemies[i].radius, enemies[i].color); + DrawTextureRec(texEnemy, (Rectangle){ 0, 0, 64, 64 }, (Vector2){ enemies[i].position.x - 32, enemies[i].position.y - 32 }, WHITE); + } + } + + // Draw time left for ritual + DrawTextEx(font, FormatText("%02.2f", (99.0f - ritualTime)), (Vector2){ 560, 20 }, font.size, 0, WHITE); + + // Draw light energy bar + DrawRectangle(20, 30, 400, 20, GRAY); + DrawRectangle(20, 30, (400*player.lightEnergy)/MAX_PLAYER_ENERGY, 20, GOLD); + DrawRectangleLines(20, 30, 400, 20, LIGHTGRAY); + DrawText(FormatText("%03.0f", player.lightEnergy), 430, 30, 20, WHITE); + + // Draw level lighted bar (for completion) + DrawRectangle(GetScreenWidth() - 40, 30, 20, 660, GRAY); + DrawRectangle(GetScreenWidth() - 40, 30 + 660 - 660*currentLightEnergy/maxLightEnergy, 20, 660*currentLightEnergy/maxLightEnergy, YELLOW); + DrawRectangleLines(GetScreenWidth() - 40, 30, 20, 660, LIGHTGRAY); + + // Show message: "You run out of light!!!" if player.lightEnergy <= 0 + if (player.lightEnergy < 2) + { + if ((framesCounter/20)%2) DrawTextEx(font, "YOU'RE RUNNING OUT OF LIGHT!", (Vector2){ 20, 60 }, font.size/2, 0, WHITE); + } + } + else if (!timeOver) // LEVEL_FINISHED + { + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, 0.4f)); + + // Wait some time before jumping to ending: raylib + DrawTexture(texRitual, GetScreenWidth()/2 - texRitual.width/2, 100, WHITE); + DrawTextEx(font, FormatText("BEST LIGHTING TIME: %02.2f", ritualTime), (Vector2){ 320, 340 }, 50, 0, WHITE); + DrawTextEx(font, "PRESS ENTER to START the RITUAL", (Vector2){ 160, 480 }, 60, 0, WHITE); + + if (IsKeyPressed(KEY_ENTER)) startRitual = true; + } + + if (timeOver) + { + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, 0.4f)); + + DrawTexture(texTimeOver, GetScreenWidth()/2 - texTimeOver.width/2, 140, WHITE); + DrawTextEx(font, FormatText("NEXT STARS ALIGNMENT IN %i YEARS", nextStarsAlignment), (Vector2){ 200, 360 }, 50, 0, WHITE); + DrawTextEx(font, "PRESS ENTER to GO HOME...", (Vector2){ 260, 480 }, 60, 0, WHITE); + + if (IsKeyPressed(KEY_ENTER)) finishScreen = 2; + } + + if (startRitual) DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(RAYWHITE, alphaRitual)); + + if (pause) DrawTextEx(font, "RITUAL PAUSED", (Vector2){ GetScreenWidth()/2 - MeasureText("RITUAL PAUSED", 40)/2, 110 }, 50, 0, WHITE); +} + +// Gameplay Screen Unload logic +void UnloadGameplayScreen(void) +{ + // Unload GAMEPLAY screen variables here! + UnloadTexture(background); + UnloadTexture(foregroundI); + UnloadTexture(foregroundII); + UnloadTexture(foregroundIII); + UnloadTexture(texPlayer); + UnloadTexture(texEnemy); + UnloadTexture(texLight); + UnloadTexture(lightGlow); + UnloadTexture(lightRay); + UnloadTexture(book); + UnloadTexture(texRitual); + UnloadTexture(texTimeOver); + + // Unload circles + UnloadTexture(circleIoff); + UnloadTexture(circleIIoff); + UnloadTexture(circleIIIoff); + UnloadTexture(circleIon); + UnloadTexture(circleIIon); + UnloadTexture(circleIIIon); + + // Unload sounds + UnloadSound(fxLightOn); + UnloadSound(fxLightOff); +} + +// Gameplay Screen should finish? +int FinishGameplayScreen(void) +{ + return finishScreen; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Check two colors if equal +static bool ColorEqual(Color col1, Color col2) +{ + return ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a)); +} + +// Substract two vectors +static Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) +{ + Vector2 result; + + result.x = v1.x - v2.x; + result.y = v1.y - v2.y; + + return result; +} + +// Normalize provided vector +static void Vector2Normalize(Vector2 *v) +{ + float length, ilength; + + length = sqrt(v->x*v->x + v->y*v->y); + + if (length == 0) length = 1.0f; + + ilength = 1.0f/length; + + v->x *= ilength; + v->y *= ilength; +} + +// Reset enemy parameters +// NOTE: Depends on currentLightedLevel +static void EnemyReset(Enemy *enemy) +{ + enemy->active = false; + enemy->framesCounter = 0; + enemy->color = RED; + enemy->radius = 10; + + int side = GetRandomValue(0, 1); + + if (side) enemy->position = (Vector2){ GetRandomValue(50, 150), GetRandomValue(50, GetScreenHeight() - 50) }; + else enemy->position = (Vector2){ GetRandomValue(GetScreenWidth() - 150, GetScreenWidth() - 50), GetRandomValue(50, GetScreenHeight() - 50) }; + + // TODO: Choose only active lights + // TODO: if currentLightedLevel has no active lights, choose light from a lower level! + + if (currentLightedLevel == LEVEL_I) + { + enemy->targetNum = GetRandomValue(0, MAX_LIGHTS_I - 1); // LEVEL_I + enemy->targetPos = lightsI[enemy->targetNum].position; + enemy->speed = (float)GetRandomValue(15, 20)/10.0f; + enemy->awakeFramesDelay = GetRandomValue(90, 400); + } + else if (currentLightedLevel == LEVEL_II) + { + enemy->targetNum = GetRandomValue(0, MAX_LIGHTS_II - 1); // LEVEL_II + enemy->targetPos = lightsII[enemy->targetNum].position; + enemy->speed = (float)GetRandomValue(10, 20)/10.0f; + enemy->awakeFramesDelay = GetRandomValue(240, 800); + } + else if (currentLightedLevel == LEVEL_III) + { + enemy->targetNum = GetRandomValue(0, MAX_LIGHTS_III - 1); // LEVEL_III + enemy->targetPos = lightsIII[enemy->targetNum].position; + enemy->speed = (float)GetRandomValue(8, 18)/10.0f; + enemy->awakeFramesDelay = GetRandomValue(180, 1200); + } +} \ No newline at end of file diff --git a/games/light_my_ritual/screens/screen_logo_raylib.c b/games/light_my_ritual/screens/screen_logo_raylib.c new file mode 100644 index 000000000..40157b105 --- /dev/null +++ b/games/light_my_ritual/screens/screen_logo_raylib.c @@ -0,0 +1,214 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Logo Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +#define LOGO_RECS_SIDE 16 + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Logo screen global variables +static int framesCounter; +static int finishScreen; + +static int logoPositionX; +static int logoPositionY; + +static int lettersCount; + +static int topSideRecWidth; +static int leftSideRecHeight; + +static int bottomSideRecWidth; +static int rightSideRecHeight; + +static char raylib[8]; // raylib text array, max 8 letters +static int state; // Tracking animation states (State Machine) +static float alpha = 1.0f; // Useful for fading + +//---------------------------------------------------------------------------------- +// Logo Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Logo Screen Initialization logic +void rlInitLogoScreen(void) +{ + // Initialize LOGO screen variables here! + finishScreen = 0; + framesCounter = 0; + lettersCount = 0; + + logoPositionX = GetScreenWidth()/2 - 128; + logoPositionY = GetScreenHeight()/2 - 128; + + topSideRecWidth = LOGO_RECS_SIDE; + leftSideRecHeight = LOGO_RECS_SIDE; + bottomSideRecWidth = LOGO_RECS_SIDE; + rightSideRecHeight = LOGO_RECS_SIDE; + + for (int i = 0; i < 8; i++) raylib[i] = '\0'; + + state = 0; + alpha = 1.0f; + + PlayMusicStream("resources/audio/ambient.ogg"); + SetMusicVolume(1.0f); +} + +// Logo Screen Update logic +void rlUpdateLogoScreen(void) +{ + // Update LOGO screen variables here! + if (state == 0) // State 0: Small box blinking + { + framesCounter++; + + if (framesCounter == 80) + { + state = 1; + framesCounter = 0; // Reset counter... will be used later... + } + } + else if (state == 1) // State 1: Top and left bars growing + { + topSideRecWidth += 8; + leftSideRecHeight += 8; + + if (topSideRecWidth == 256) state = 2; + } + else if (state == 2) // State 2: Bottom and right bars growing + { + bottomSideRecWidth += 8; + rightSideRecHeight += 8; + + if (bottomSideRecWidth == 256) state = 3; + } + else if (state == 3) // State 3: Letters appearing (one by one) + { + framesCounter++; + + if (framesCounter/10) // Every 12 frames, one more letter! + { + lettersCount++; + framesCounter = 0; + } + + switch (lettersCount) + { + case 1: raylib[0] = 'r'; break; + case 2: raylib[1] = 'a'; break; + case 3: raylib[2] = 'y'; break; + case 4: raylib[3] = 'l'; break; + case 5: raylib[4] = 'i'; break; + case 6: raylib[5] = 'b'; break; + default: break; + } + + // When all letters have appeared... + if (lettersCount >= 10) + { + state = 4; + framesCounter = 0; + } + } + else if (state == 4) + { + framesCounter++; + + if (framesCounter > 100) + { + alpha -= 0.02f; + + if (alpha <= 0.0f) + { + alpha = 0.0f; + finishScreen = 1; + } + } + } +} + +// Logo Screen Draw logic +void rlDrawLogoScreen(void) +{ + if (state == 0) + { + if ((framesCounter/10)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK); + } + else if (state == 1) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); + DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); + } + else if (state == 2) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); + DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); + + DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK); + } + else if (state == 3) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); + + DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); + + DrawRectangle(GetScreenWidth()/2 - 112, GetScreenHeight()/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); + + DrawText(raylib, GetScreenWidth()/2 - 44, GetScreenHeight()/2 + 48, 50, Fade(BLACK, alpha)); + } + else if (state == 4) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); + + DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); + + DrawRectangle(GetScreenWidth()/2 - 112, GetScreenHeight()/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); + + DrawText(raylib, GetScreenWidth()/2 - 44, GetScreenHeight()/2 + 48, 50, Fade(BLACK, alpha)); + + if (framesCounter > 20) DrawText("powered by", logoPositionX, logoPositionY - 27, 20, Fade(DARKGRAY, alpha)); + } +} + +// Logo Screen Unload logic +void rlUnloadLogoScreen(void) +{ + // TODO: Unload LOGO screen variables here! +} + +// Logo Screen should finish? +int rlFinishLogoScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/light_my_ritual/screens/screen_title.c b/games/light_my_ritual/screens/screen_title.c new file mode 100644 index 000000000..c1ecaf122 --- /dev/null +++ b/games/light_my_ritual/screens/screen_title.c @@ -0,0 +1,105 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Title Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Title screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; +static Texture2D title; +static float titleAlpha = 0.0f; + +static Sound fxStart; + +//---------------------------------------------------------------------------------- +// Title Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Title Screen Initialization logic +void InitTitleScreen(void) +{ + // Initialize TITLE screen variables here! + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/back_title.png"); + title = LoadTexture("resources/textures/title.png"); + + fxStart = LoadSound("resources/audio/start.wav"); +} + +// Title Screen Update logic +void UpdateTitleScreen(void) +{ + // Update TITLE screen variables here! + framesCounter++; + + titleAlpha += 0.005f; + + if (titleAlpha >= 1.0f) titleAlpha = 1.0f; + + // Press enter to change to ATTIC screen + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + PlaySound(fxStart); + finishScreen = 1; + } +} + +// Title Screen Draw logic +void DrawTitleScreen(void) +{ + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 26, 26, 26, 255 }); + + DrawTexture(background, GetScreenWidth()/2 - background.width/2, 0, WHITE); + DrawTexture(title, GetScreenWidth()/2 - title.width/2, 30, Fade(WHITE, titleAlpha)); + + DrawText("(c) Developed by Ramon Santamaria (@raysan5)", 20, GetScreenHeight() - 40, 20, LIGHTGRAY); + + if ((framesCounter > 180) && ((framesCounter/40)%2)) DrawTextEx(font, "PRESS ENTER to START LIGHTING", (Vector2){ 230, 450 }, font.size, -2, WHITE); +} + +// Title Screen Unload logic +void UnloadTitleScreen(void) +{ + // Unload TITLE screen variables here! + UnloadTexture(background); + UnloadTexture(title); + + UnloadSound(fxStart); +} + +// Title Screen should finish? +int FinishTitleScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/light_my_ritual/screens/screens.h b/games/light_my_ritual/screens/screens.h new file mode 100644 index 000000000..8fee52744 --- /dev/null +++ b/games/light_my_ritual/screens/screens.h @@ -0,0 +1,78 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Screens Functions Declarations (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef SCREENS_H +#define SCREENS_H + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum GameScreen { LOGO_RL = 0, TITLE, GAMEPLAY } GameScreen; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +GameScreen currentScreen; +SpriteFont font; + +Color *lightsMap; +int lightsMapWidth, lightsMapHeight; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// raylib Logo Screen Functions Declaration +//---------------------------------------------------------------------------------- +void rlInitLogoScreen(void); +void rlUpdateLogoScreen(void); +void rlDrawLogoScreen(void); +void rlUnloadLogoScreen(void); +int rlFinishLogoScreen(void); + +//---------------------------------------------------------------------------------- +// Title Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitTitleScreen(void); +void UpdateTitleScreen(void); +void DrawTitleScreen(void); +void UnloadTitleScreen(void); +int FinishTitleScreen(void); + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitGameplayScreen(void); +void UpdateGameplayScreen(void); +void DrawGameplayScreen(void); +void UnloadGameplayScreen(void); +int FinishGameplayScreen(void); + +#ifdef __cplusplus +} +#endif + +#endif // SCREENS_H \ No newline at end of file diff --git a/games/makefile b/games/makefile new file mode 100644 index 000000000..2d992896e --- /dev/null +++ b/games/makefile @@ -0,0 +1,254 @@ +#************************************************************************************************** +# +# raylib makefile for desktop platforms, Raspberry Pi and HTML5 (emscripten) +# +# Copyright (c) 2015 Ramon Santamaria (@raysan5) +# +# This software is provided "as-is", without any express or implied warranty. In no event +# will the authors be held liable for any damages arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, including commercial +# applications, and to alter it and redistribute it freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not claim that you +# wrote the original software. If you use this software in a product, an acknowledgment +# in the product documentation would be appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be misrepresented +# as being the original software. +# +# 3. This notice may not be removed or altered from any source distribution. +# +#************************************************************************************************** + +# define raylib platform to compile for +# possible platforms: PLATFORM_DESKTOP PLATFORM_RPI PLATFORM_WEB +# WARNING: To compile to HTML5, code must be redesigned to use emscripten.h and emscripten_set_main_loop() +PLATFORM ?= PLATFORM_DESKTOP + +# determine PLATFORM_OS in case PLATFORM_DESKTOP selected +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + ifeq ($(OS),Windows_NT) + PLATFORM_OS=WINDOWS + LIBPATH=win32 + else + UNAMEOS:=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + LIBPATH=linux + else + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS=OSX + LIBPATH=osx + endif + endif + endif +endif + +# define compiler: gcc for C program, define as g++ for C++ +ifeq ($(PLATFORM),PLATFORM_WEB) + # define emscripten compiler + CC = emcc +else +ifeq ($(PLATFORM_OS),OSX) + # define llvm compiler for mac + CC = clang +else + # define default gcc compiler + CC = gcc +endif +endif + +# define compiler flags: +# -O2 defines optimization level +# -Wall turns on most, but not all, compiler warnings +# -std=c99 use standard C from 1999 revision +ifeq ($(PLATFORM),PLATFORM_RPI) + CFLAGS = -O2 -Wall -std=gnu99 -fgnu89-inline +else + CFLAGS = -O2 -Wall -std=c99 +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 # to check for memory allocation errors (-O1 disables it) + #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing + #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) +endif + +#CFLAGSEXTRA = -Wextra -Wmissing-prototypes -Wstrict-prototypes + +# define any directories containing required header files +ifeq ($(PLATFORM),PLATFORM_RPI) + INCLUDES = -I. -I../src -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads +else + INCLUDES = -I. -I../src +# external libraries headers +# GLFW3 + INCLUDES += -I../external/glfw3/include +# GLEW - Not required any more, replaced by GLAD + #INCLUDES += -I../external/glew/include +# OpenAL Soft + INCLUDES += -I../external/openal_soft/include +endif + +# define library paths containing required libs +ifeq ($(PLATFORM),PLATFORM_RPI) + LFLAGS = -L. -L../src -L/opt/vc/lib +else + LFLAGS = -L. -L../src +# external libraries to link with + # GLFW3 + LFLAGS += -L../external/glfw3/lib/$(LIBPATH) + ifneq ($(PLATFORM_OS),OSX) + # OpenAL Soft + LFLAGS += -L../external/openal_soft/lib/$(LIBPATH) + # GLEW: Not used, replaced by GLAD + #LFLAGS += -L../../external/glew/lib/$(LIBPATH) + endif +endif + +# define any libraries to link into executable +# if you want to link libraries (libname.so or libname.a), use the -lname +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),LINUX) + # libraries for Debian GNU/Linux desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw3 -lGLEW -lGL -lopenal -lm -pthread + # on XWindow could require also below libraries, just uncomment + #LIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + else + ifeq ($(PLATFORM_OS),OSX) + # libraries for OS X 10.9 desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -framework OpenGL -framework OpenAl -framework Cocoa + else + # libraries for Windows desktop compiling + # NOTE: GLFW3 and OpenAL Soft libraries should be installed + LIBS = -lraylib -lglfw3 -lopengl32 -lopenal32 -lgdi32 + endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + # libraries for Raspberry Pi compiling + # NOTE: OpenAL Soft library should be installed (libopenal1 package) + LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + # NOTE: Set the correct path to libraylib.bc + LIBS = ../src/libraylib.bc +endif + +# define additional parameters and flags for windows +ifeq ($(PLATFORM_OS),WINDOWS) + # resources file contains windows exe icon + # -Wl,--subsystem,windows hides the console window + WINFLAGS = ../src/resources -Wl,--subsystem,windows +endif + +ifeq ($(PLATFORM),PLATFORM_WEB) + EXT = .html +endif + +# define all object files required +SAMPLES = \ + arkanoid \ + asteroids \ + asteroids_survival \ + floppy \ + gold_fever \ + gorilas \ + missile_commander \ + pang \ + snake \ + space_invaders \ + tetris \ + fix_dylib \ + + +# typing 'make' will invoke the first target entry in the file, +# in this case, the 'default' target entry is raylib +default: samples + +# compile all game samples +samples: $(SAMPLES) + +# compile game sample - arkanoid +arkanoid: arkanoid.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - steroids +asteroids: asteroids.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - asteroids_survival +asteroids_survival: asteroids_survival.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - floppy +floppy: floppy.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - gold_fever +gold_fever: gold_fever.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - gorilas +gorilas: gorilas.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - missile_commander +missile_commander: missile_commander.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - pang +pang: pang.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - snake +snake: snake.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - space_invaders +space_invaders: space_invaders.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile game sample - tetris +tetris: tetris.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# fix dylib install path name for each executable (MAC) +fix_dylib: +ifeq ($(PLATFORM_OS),OSX) + find . -type f -perm +ugo+x -print0 | xargs -t -0 -R 1 -I file install_name_tool -change libglfw.3.0.dylib ../external/glfw3/lib/osx/libglfw.3.0.dylib file +endif + +# clean everything +clean: +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),OSX) + find . -type f -perm +ugo+x -delete + rm -f *.o + else + ifeq ($(PLATFORM_OS),LINUX) + find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -f + else + del *.o *.exe + endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + find . -type f -executable -delete + rm -f *.o +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + del *.o *.html *.js +endif + @echo Cleaning done + +# instead of defining every module one by one, we can define a pattern +# this pattern below will automatically compile every module defined on $(OBJS) +#%.exe : %.c +# $(CC) -o $@ $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) diff --git a/games/missile_commander.c b/games/missile_commander.c new file mode 100644 index 000000000..6317c41a7 --- /dev/null +++ b/games/missile_commander.c @@ -0,0 +1,539 @@ +/******************************************************************************************* +* +* raylib - sample game: missile commander +* +* Sample game Marc Palau and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include +#include +#include +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define MAX_MISSILES 100 +#define MAX_INTERCEPTORS 30 +#define MAX_EXPLOSIONS 100 +#define LAUNCHERS_AMOUNT 3 // Not a variable, should not be changed +#define BUILDINGS_AMOUNT 6 // Not a variable, should not be changed + +#define LAUNCHER_SIZE 80 +#define BUILDING_SIZE 60 +#define EXPLOSION_RADIUS 40 + +#define MISSILE_SPEED 1 +#define MISSILE_LAUNCH_FRAMES 80 +#define INTERCEPTOR_SPEED 10 +#define EXPLOSION_INCREASE_TIME 90 // In frames +#define EXPLOSION_TOTAL_TIME 210 // In frames + +#define EXPLOSION_COLOR (Color){ 125, 125, 125, 125 } + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct Missile { + Vector2 origin; + Vector2 position; + Vector2 objective; + Vector2 speed; + + bool active; +} Missile; + +typedef struct Interceptor { + Vector2 origin; + Vector2 position; + Vector2 objective; + Vector2 speed; + + bool active; +} Interceptor; + +typedef struct Explosion { + Vector2 position; + float radiusMultiplier; + int frame; + bool active; +} Explosion; + +typedef struct Launcher { + Vector2 position; + bool active; +} Launcher; + +typedef struct Building { + Vector2 position; + bool active; +} Building; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter = 0; +static bool gameOver = false; +static bool pause = false; +static int score = 0; + +static Missile missile[MAX_MISSILES]; +static Interceptor interceptor[MAX_INTERCEPTORS]; +static Explosion explosion[MAX_EXPLOSIONS]; +static Launcher launcher[LAUNCHERS_AMOUNT]; +static Building building[BUILDINGS_AMOUNT]; +static int explosionIndex = 0; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +// Additional module functions +static void UpdateOutgoingFire(); +static void UpdateIncomingFire(); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: missile commander"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//-------------------------------------------------------------------------------------- +// Game Module Functions Definition +//-------------------------------------------------------------------------------------- + +// Initialize game variables +void InitGame(void) +{ + // Initialize missiles + for (int i = 0; i < MAX_MISSILES; i++) + { + missile[i].origin = (Vector2){ 0, 0 }; + missile[i].speed = (Vector2){ 0, 0 }; + missile[i].position = (Vector2){ 0, 0 }; + + missile[i].active = false; + } + + // Initialize interceptors + for (int i = 0; i < MAX_INTERCEPTORS; i++) + { + interceptor[i].origin = (Vector2){ 0, 0 }; + interceptor[i].speed = (Vector2){ 0, 0 }; + interceptor[i].position = (Vector2){ 0, 0 }; + + interceptor[i].active = false; + } + + // Initialize explosions + for (int i = 0; i < MAX_EXPLOSIONS; i++) + { + explosion[i].position = (Vector2){ 0, 0 }; + explosion[i].frame = 0; + explosion[i].active = false; + } + + // Initialize buildings and launchers + int sparcing = screenWidth/(LAUNCHERS_AMOUNT + BUILDINGS_AMOUNT + 1); + + // Buildings and launchers placing + launcher[0].position = (Vector2){ 1*sparcing, screenHeight - LAUNCHER_SIZE/2 }; + building[0].position = (Vector2){ 2*sparcing, screenHeight - BUILDING_SIZE/2 }; + building[1].position = (Vector2){ 3*sparcing, screenHeight - BUILDING_SIZE/2 }; + building[2].position = (Vector2){ 4*sparcing, screenHeight - BUILDING_SIZE/2 }; + launcher[1].position = (Vector2){ 5*sparcing, screenHeight - LAUNCHER_SIZE/2 }; + building[3].position = (Vector2){ 6*sparcing, screenHeight - BUILDING_SIZE/2 }; + building[4].position = (Vector2){ 7*sparcing, screenHeight - BUILDING_SIZE/2 }; + building[5].position = (Vector2){ 8*sparcing, screenHeight - BUILDING_SIZE/2 }; + launcher[2].position = (Vector2){ 9*sparcing, screenHeight - LAUNCHER_SIZE/2 }; + + // Buildings and launchers activation + for (int i = 0; i < LAUNCHERS_AMOUNT; i++) launcher[i].active = true; + for (int i = 0; i < BUILDINGS_AMOUNT; i++) building[i].active = true; + + // Initialize game variables + score = 0; +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + framesCounter++; + + static + float distance; + + // Interceptors update + for (int i = 0; i < MAX_INTERCEPTORS; i++) + { + if (interceptor[i].active) + { + // Update position + interceptor[i].position.x += interceptor[i].speed.x; + interceptor[i].position.y += interceptor[i].speed.y; + + // Distance to objective + distance = sqrt( pow(interceptor[i].position.x - interceptor[i].objective.x, 2) + + pow(interceptor[i].position.y - interceptor[i].objective.y, 2)); + + if (distance < INTERCEPTOR_SPEED) + { + // Interceptor dissapears + interceptor[i].active = false; + + // Explosion + explosion[explosionIndex].position = interceptor[i].position; + explosion[explosionIndex].active = true; + explosion[explosionIndex].frame = 0; + explosionIndex++; + if (explosionIndex == MAX_EXPLOSIONS) explosionIndex = 0; + + break; + } + } + } + + // Missiles update + for (int i = 0; i < MAX_MISSILES; i++) + { + if (missile[i].active) + { + // Update position + missile[i].position.x += missile[i].speed.x; + missile[i].position.y += missile[i].speed.y; + + // Collision and missile out of bounds + if (missile[i].position.y > screenHeight) missile[i].active = false; + else + { + // CHeck collision with launchers + for (int j = 0; j < LAUNCHERS_AMOUNT; j++) + { + if (launcher[j].active) + { + if (CheckCollisionPointRec(missile[i].position, (Rectangle){ launcher[j].position.x - LAUNCHER_SIZE/2, launcher[j].position.y - LAUNCHER_SIZE/2, + LAUNCHER_SIZE, LAUNCHER_SIZE })) + { + // Missile dissapears + missile[i].active = false; + + // Explosion and destroy building + launcher[j].active = false; + + explosion[explosionIndex].position = missile[i].position; + explosion[explosionIndex].active = true; + explosion[explosionIndex].frame = 0; + explosionIndex++; + if (explosionIndex == MAX_EXPLOSIONS) explosionIndex = 0; + + break; + } + } + } + + // CHeck collision with buildings + for (int j = 0; j < BUILDINGS_AMOUNT; j++) + { + if (building[j].active) + { + if (CheckCollisionPointRec(missile[i].position, (Rectangle){ building[j].position.x - BUILDING_SIZE/2, building[j].position.y - BUILDING_SIZE/2, + BUILDING_SIZE, BUILDING_SIZE })) + { + // Missile dissapears + missile[i].active = false; + + // Explosion and destroy building + building[j].active = false; + + explosion[explosionIndex].position = missile[i].position; + explosion[explosionIndex].active = true; + explosion[explosionIndex].frame = 0; + explosionIndex++; + if (explosionIndex == MAX_EXPLOSIONS) explosionIndex = 0; + + break; + } + } + } + + // CHeck collision with explosions + for (int j = 0; j < MAX_EXPLOSIONS; j++) + { + if (explosion[j].active) + { + if (CheckCollisionPointCircle(missile[i].position, explosion[j].position, EXPLOSION_RADIUS*explosion[j].radiusMultiplier)) + { + // Missile dissapears and we earn 100 points + missile[i].active = false; + score += 100; + + explosion[explosionIndex].position = missile[i].position; + explosion[explosionIndex].active = true; + explosion[explosionIndex].frame = 0; + explosionIndex++; + if (explosionIndex == MAX_EXPLOSIONS) explosionIndex = 0; + + break; + } + } + } + } + } + } + + // Explosions update + for (int i = 0; i < MAX_EXPLOSIONS; i++) + { + if (explosion[i].active) + { + explosion[i].frame++; + + if (explosion[i].frame <= EXPLOSION_INCREASE_TIME) explosion[i].radiusMultiplier = explosion[i].frame/(float)EXPLOSION_INCREASE_TIME; + else if (explosion[i].frame <= EXPLOSION_TOTAL_TIME) explosion[i].radiusMultiplier = 1 - (explosion[i].frame - (float)EXPLOSION_INCREASE_TIME)/(float)EXPLOSION_TOTAL_TIME; + else + { + explosion[i].frame = 0; + explosion[i].active = false; + } + } + } + + // Fire logic + UpdateOutgoingFire(); + UpdateIncomingFire(); + + // Game over logic + int checker = 0; + + for (int i = 0; i < LAUNCHERS_AMOUNT; i++) + { + if (!launcher[i].active) checker++; + if (checker == LAUNCHERS_AMOUNT) gameOver = true; + } + + checker = 0; + for (int i = 0; i < BUILDINGS_AMOUNT; i++) + { + if (!building[i].active) checker++; + if (checker == BUILDINGS_AMOUNT) gameOver = true; + } + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + // Draw missiles + for (int i = 0; i < MAX_MISSILES; i++) + { + if (missile[i].active) + { + DrawLine(missile[i].origin.x, missile[i].origin.y, missile[i].position.x, missile[i].position.y, RED); + + if (framesCounter % 16 < 8) DrawCircle(missile[i].position.x, missile[i].position.y, 3, YELLOW); + } + } + + // Draw interceptors + for (int i = 0; i < MAX_INTERCEPTORS; i++) + { + if (interceptor[i].active) + { + DrawLine(interceptor[i].origin.x, interceptor[i].origin.y, interceptor[i].position.x, interceptor[i].position.y, GREEN); + + if (framesCounter % 16 < 8) DrawCircle(interceptor[i].position.x, interceptor[i].position.y, 3, BLUE); + } + } + + // Draw explosions + for (int i = 0; i < MAX_EXPLOSIONS; i++) + { + if (explosion[i].active) DrawCircle(explosion[i].position.x, explosion[i].position.y, EXPLOSION_RADIUS*explosion[i].radiusMultiplier, EXPLOSION_COLOR); + } + + // Draw buildings and launchers + for (int i = 0; i < LAUNCHERS_AMOUNT; i++) + { + if (launcher[i].active) DrawRectangle(launcher[i].position.x - LAUNCHER_SIZE/2, launcher[i].position.y - LAUNCHER_SIZE/2, LAUNCHER_SIZE, LAUNCHER_SIZE, GRAY); + } + + for (int i = 0; i < BUILDINGS_AMOUNT; i++) + { + if (building[i].active) DrawRectangle(building[i].position.x - BUILDING_SIZE/2, building[i].position.y - BUILDING_SIZE/2, BUILDING_SIZE, BUILDING_SIZE, LIGHTGRAY); + } + + // Draw score + DrawText(FormatText("SCORE %4i", score), 20, 20, 40, LIGHTGRAY); + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} + +//-------------------------------------------------------------------------------------- +// Additional module functions +//-------------------------------------------------------------------------------------- +static void UpdateOutgoingFire() +{ + static int interceptorNumber = 0; + int launcherShooting = 0; + + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) launcherShooting = 1; + if (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) launcherShooting = 2; + if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) launcherShooting = 3; + + if (launcherShooting > 0 && launcher[launcherShooting - 1].active) + { + float module; + float sideX; + float sideY; + + // Activate the interceptor + interceptor[interceptorNumber].active = true; + + // Assign start position + interceptor[interceptorNumber].origin = launcher[launcherShooting - 1].position; + interceptor[interceptorNumber].position = interceptor[interceptorNumber].origin; + interceptor[interceptorNumber].objective = GetMousePosition(); + + // Calculate speed + module = sqrt( pow(interceptor[interceptorNumber].objective.x - interceptor[interceptorNumber].origin.x, 2) + + pow(interceptor[interceptorNumber].objective.y - interceptor[interceptorNumber].origin.y, 2)); + + sideX = (interceptor[interceptorNumber].objective.x - interceptor[interceptorNumber].origin.x)*INTERCEPTOR_SPEED/module; + sideY = (interceptor[interceptorNumber].objective.y - interceptor[interceptorNumber].origin.y)*INTERCEPTOR_SPEED/module; + + interceptor[interceptorNumber].speed = (Vector2){ sideX, sideY }; + + // Update + interceptorNumber++; + if (interceptorNumber == MAX_INTERCEPTORS) interceptorNumber = 0; + } +} + +static void UpdateIncomingFire() +{ + static int missileIndex = 0; + + // Launch missile + if (framesCounter % MISSILE_LAUNCH_FRAMES == 0) + { + float module; + float sideX; + float sideY; + + // Activate the missile + missile[missileIndex].active = true; + + // Assign start position + missile[missileIndex].origin = (Vector2){ GetRandomValue(20, screenWidth - 20), -10 }; + missile[missileIndex].position = missile[missileIndex].origin; + missile[missileIndex].objective = (Vector2){ GetRandomValue(20, screenWidth - 20), screenHeight + 10 }; + + // Calculate speed + module = sqrt( pow(missile[missileIndex].objective.x - missile[missileIndex].origin.x, 2) + + pow(missile[missileIndex].objective.y - missile[missileIndex].origin.y, 2)); + + sideX = (missile[missileIndex].objective.x - missile[missileIndex].origin.x)*MISSILE_SPEED/module; + sideY = (missile[missileIndex].objective.y - missile[missileIndex].origin.y)*MISSILE_SPEED/module; + + missile[missileIndex].speed = (Vector2){ sideX, sideY }; + + // Update + missileIndex++; + if (missileIndex == MAX_MISSILES) missileIndex = 0; + } +} \ No newline at end of file diff --git a/games/pang.c b/games/pang.c new file mode 100644 index 000000000..fe1c3005e --- /dev/null +++ b/games/pang.c @@ -0,0 +1,630 @@ +/******************************************************************************************* +* +* raylib - sample game: pang +* +* Sample game developed by Ian Eito and Albert Martos and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define PLAYER_BASE_SIZE 20.0f +#define PLAYER_SPEED 5.0f +#define PLAYER_MAX_SHOOTS 1 + +#define MAX_BIG_BALLS 2 +#define BALLS_SPEED 2.0f + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +typedef struct Player { + Vector2 position; + Vector2 speed; + Vector3 collider; + float rotation; +} Player; + +typedef struct Shoot { + Vector2 position; + Vector2 speed; + float radius; + float rotation; + int lifeSpawn; + bool active; +} Shoot; + +typedef struct Ball { + Vector2 position; + Vector2 speed; + float radius; + int points; + bool active; +} Ball; + +typedef struct Points { + Vector2 position; + int value; + float alpha; +} Points; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter; +static bool gameOver; +static bool pause; +static int score; + +static Player player; +static Shoot shoot[PLAYER_MAX_SHOOTS]; +static Ball bigBalls[MAX_BIG_BALLS]; +static Ball mediumBalls[MAX_BIG_BALLS*2]; +static Ball smallBalls[MAX_BIG_BALLS*4]; +static Points points[5]; + +// NOTE: Defined triangle is isosceles with common angles of 70 degrees. +static float shipHeight; +static float gravity; + +static int countmediumBallss; +static int countsmallBallss; +static int meteorsDestroyed; +static Vector2 linePosition; + +static bool victory; +static bool lose; +static bool awake; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + InitWindow(screenWidth, screenHeight, "sample game: pang"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +static void InitGame(void) +{ + int posx, posy; + int velx = 0; + int vely = 0; + + framesCounter = 0; + gameOver = false; + pause = false; + score = 0; + + victory = false; + lose = false; + awake = true; + gravity = 0.25f; + + linePosition = (Vector2){ 0.0f , 0.0f }; + shipHeight = (PLAYER_BASE_SIZE/2)/tanf(20*DEG2RAD); + + // Initialization player + player.position = (Vector2){ screenWidth/2, screenHeight }; + player.speed = (Vector2){ PLAYER_SPEED, PLAYER_SPEED }; + player.rotation = 0; + player.collider = (Vector3){ player.position.x, player.position.y - shipHeight/2.0f, 12.0f }; + + meteorsDestroyed = 0; + + // Initialize shoots + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + shoot[i].position = (Vector2){ 0, 0 }; + shoot[i].speed = (Vector2){ 0, 0 }; + shoot[i].radius = 2; + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + } + + // Initialize big meteors + for (int i = 0; i < MAX_BIG_BALLS; i++) + { + bigBalls[i].radius = 40.0f; + posx = GetRandomValue(0 + bigBalls[i].radius, screenWidth - bigBalls[i].radius); + posy = GetRandomValue(0 + bigBalls[i].radius, screenHeight/2); + + bigBalls[i].position = (Vector2){ posx, posy }; + + while ((velx == 0) || (vely == 0)) + { + velx = GetRandomValue(-BALLS_SPEED, BALLS_SPEED); + vely = GetRandomValue(-BALLS_SPEED, BALLS_SPEED); + } + + bigBalls[i].speed = (Vector2){ velx, vely }; + bigBalls[i].points = 200; + bigBalls[i].active = true; + } + + // Initialize medium meteors + for (int i = 0; i < MAX_BIG_BALLS*2; i++) + { + mediumBalls[i].position = (Vector2){-100, -100}; + mediumBalls[i].speed = (Vector2){0,0}; + mediumBalls[i].radius = 20.0f; + mediumBalls[i].points = 100; + mediumBalls[i].active = false; + } + + // Initialize small meteors + for (int i = 0; i < MAX_BIG_BALLS*4; i++) + { + smallBalls[i].position = (Vector2){ -100, -100 }; + smallBalls[i].speed = (Vector2){ 0, 0 }; + smallBalls[i].radius = 10.0f; + smallBalls[i].points = 50; + smallBalls[i].active = false; + } + + // Initialize animated points + for (int i = 0; i < 5; i++) + { + points[i].position = (Vector2){ 0, 0 }; + points[i].value = 0; + points[i].alpha = 0.0f; + } + + countmediumBallss = 0; + countsmallBallss = 0; +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver && !victory) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + // Player logic + if (IsKeyDown(KEY_LEFT)) player.position.x -= player.speed.x; + if (IsKeyDown(KEY_RIGHT)) player.position.x += player.speed.x; + + // Player vs wall collision logic + if (player.position.x + PLAYER_BASE_SIZE/2 > screenWidth) player.position.x = screenWidth - PLAYER_BASE_SIZE/2; + else if (player.position.x - PLAYER_BASE_SIZE/2 < 0) player.position.x = 0 + PLAYER_BASE_SIZE/2; + + // Player shot logic + if (IsKeyPressed(KEY_SPACE)) + { + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if (!shoot[i].active) + { + shoot[i].position = (Vector2){ player.position.x, player.position.y - shipHeight }; + shoot[i].speed.y = PLAYER_SPEED; + shoot[i].active = true; + + linePosition = (Vector2){ player.position.x, player.position.y}; + + break; + } + } + } + + // Shoot life timer + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if (shoot[i].active) shoot[i].lifeSpawn++; + } + + // Shot logic + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if (shoot[i].active) + { + shoot[i].position.y -= shoot[i].speed.y; + + // Shot vs walls collision logic + if ((shoot[i].position.x > screenWidth + shoot[i].radius) || (shoot[i].position.x < 0 - shoot[i].radius) || + (shoot[i].position.y > screenHeight + shoot[i].radius) || (shoot[i].position.y < 0 - shoot[i].radius)) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + } + + // Player shot life spawn + if (shoot[i].lifeSpawn >= 120) + { + shoot[i].position = (Vector2){ 0.0f, 0.0f }; + shoot[i].speed = (Vector2){ 0.0f, 0.0f }; + shoot[i].lifeSpawn = 0; + shoot[i].active = false; + } + } + } + + // Player vs meteors collision logic + player.collider = (Vector3){player.position.x, player.position.y - shipHeight/2, 12}; + + for (int i = 0; i < MAX_BIG_BALLS; i++) + { + if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, bigBalls[i].position, bigBalls[i].radius) && bigBalls[i].active) + { + gameOver = true; + } + } + + for (int i = 0; i < MAX_BIG_BALLS*2; i++) + { + if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, mediumBalls[i].position, mediumBalls[i].radius) && mediumBalls[i].active) + { + gameOver = true; + } + } + + for (int i = 0; i < MAX_BIG_BALLS*4; i++) + { + if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, smallBalls[i].position, smallBalls[i].radius) && smallBalls[i].active) + { + gameOver = true; + } + } + + // Meteors logic (big) + for (int i = 0; i < MAX_BIG_BALLS; i++) + { + if (bigBalls[i].active) + { + // Meteor movement logic + bigBalls[i].position.x += bigBalls[i].speed.x; + bigBalls[i].position.y += bigBalls[i].speed.y; + + // Meteor vs wall collision logic + if (((bigBalls[i].position.x + bigBalls[i].radius) >= screenWidth) || ((bigBalls[i].position.x - bigBalls[i].radius) <= 0)) bigBalls[i].speed.x *= -1; + if ((bigBalls[i].position.y - bigBalls[i].radius) <= 0) bigBalls[i].speed.y *= -1.5; + + if ((bigBalls[i].position.y + bigBalls[i].radius) >= screenHeight) + { + bigBalls[i].speed.y *= -1; + bigBalls[i].position.y = screenHeight - bigBalls[i].radius; + } + + bigBalls[i].speed.y += gravity; + } + } + + // Meteors logic (medium) + for (int i = 0; i < MAX_BIG_BALLS*2; i++) + { + if (mediumBalls[i].active) + { + // Meteor movement logic + mediumBalls[i].position.x += mediumBalls[i].speed.x; + mediumBalls[i].position.y += mediumBalls[i].speed.y; + + // Meteor vs wall collision logic + if (mediumBalls[i].position.x + mediumBalls[i].radius >= screenWidth || mediumBalls[i].position.x - mediumBalls[i].radius <= 0) mediumBalls[i].speed.x *= -1; + if (mediumBalls[i].position.y - mediumBalls[i].radius <= 0) mediumBalls[i].speed.y *= -1; + if (mediumBalls[i].position.y + mediumBalls[i].radius >= screenHeight) + { + mediumBalls[i].speed.y *= -1; + mediumBalls[i].position.y = screenHeight - mediumBalls[i].radius; + } + + mediumBalls[i].speed.y += gravity + 0.12f; + } + } + + // Meteors logic (small) + for (int i = 0; i < MAX_BIG_BALLS*4; i++) + { + if (smallBalls[i].active) + { + // Meteor movement logic + smallBalls[i].position.x += smallBalls[i].speed.x; + smallBalls[i].position.y += smallBalls[i].speed.y; + + // Meteor vs wall collision logic + if (smallBalls[i].position.x + smallBalls[i].radius >= screenWidth || smallBalls[i].position.x - smallBalls[i].radius <= 0) smallBalls[i].speed.x *= -1; + if (smallBalls[i].position.y - smallBalls[i].radius <= 0) smallBalls[i].speed.y *= -1; + if (smallBalls[i].position.y + smallBalls[i].radius >= screenHeight) + { + smallBalls[i].speed.y *= -1; + smallBalls[i].position.y = screenHeight - smallBalls[i].radius; + } + + smallBalls[i].speed.y += gravity + 0.25f; + } + } + + // Player-shot vs meteors logic + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if ((shoot[i].active)) + { + for (int a = 0; a < MAX_BIG_BALLS; a++) + { + if (bigBalls[a].active && (bigBalls[a].position.x - bigBalls[a].radius <= linePosition.x && bigBalls[a].position.x + bigBalls[a].radius >= linePosition.x) + && (bigBalls[a].position.y + bigBalls[a].radius >= shoot[i].position.y)) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + bigBalls[a].active = false; + meteorsDestroyed++; + score += bigBalls[a].points; + + for (int z = 0; z < 5; z++) + { + if (points[z].alpha == 0.0f) + { + points[z].position = bigBalls[a].position; + points[z].value = bigBalls[a].points; + points[z].alpha = 1.0f; + z = 5; + } + } + + for (int j = 0; j < 2; j ++) + { + if ((countmediumBallss%2) == 0) + { + mediumBalls[countmediumBallss].position = (Vector2){bigBalls[a].position.x, bigBalls[a].position.y}; + mediumBalls[countmediumBallss].speed = (Vector2){ -1*BALLS_SPEED, BALLS_SPEED }; + } + else + { + mediumBalls[countmediumBallss].position = (Vector2){bigBalls[a].position.x, bigBalls[a].position.y}; + mediumBalls[countmediumBallss].speed = (Vector2){ BALLS_SPEED, BALLS_SPEED }; + } + + mediumBalls[countmediumBallss].active = true; + countmediumBallss ++; + } + + a = MAX_BIG_BALLS; + } + } + } + + if ((shoot[i].active)) + { + for (int b = 0; b < MAX_BIG_BALLS*2; b++) + { + if (mediumBalls[b].active && (mediumBalls[b].position.x - mediumBalls[b].radius <= linePosition.x && mediumBalls[b].position.x + mediumBalls[b].radius >= linePosition.x) + && (mediumBalls[b].position.y + mediumBalls[b].radius >= shoot[i].position.y)) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + mediumBalls[b].active = false; + meteorsDestroyed++; + score += mediumBalls[b].points; + + for (int z = 0; z < 5; z++) + { + if (points[z].alpha == 0.0f) + { + points[z].position = mediumBalls[b].position; + points[z].value = mediumBalls[b].points; + points[z].alpha = 1.0f; + z = 5; + } + } + + for (int j = 0; j < 2; j ++) + { + if (countsmallBallss%2 == 0) + { + smallBalls[countsmallBallss].position = (Vector2){mediumBalls[b].position.x, mediumBalls[b].position.y}; + smallBalls[countsmallBallss].speed = (Vector2){ BALLS_SPEED*-1, BALLS_SPEED*-1}; + } + else + { + smallBalls[countsmallBallss].position = (Vector2){mediumBalls[b].position.x, mediumBalls[b].position.y}; + smallBalls[countsmallBallss].speed = (Vector2){ BALLS_SPEED, BALLS_SPEED*-1}; + } + + smallBalls[countsmallBallss].active = true; + countsmallBallss ++; + } + + b = MAX_BIG_BALLS*2; + } + } + } + + if ((shoot[i].active)) + { + for (int c = 0; c < MAX_BIG_BALLS*4; c++) + { + if (smallBalls[c].active && (smallBalls[c].position.x - smallBalls[c].radius <= linePosition.x && smallBalls[c].position.x + smallBalls[c].radius >= linePosition.x) + && (smallBalls[c].position.y + smallBalls[c].radius >= shoot[i].position.y)) + { + shoot[i].active = false; + shoot[i].lifeSpawn = 0; + smallBalls[c].active = false; + meteorsDestroyed++; + score += smallBalls[c].points; + + for (int z = 0; z < 5; z++) + { + if (points[z].alpha == 0.0f) + { + points[z].position = smallBalls[c].position; + points[z].value = smallBalls[c].points; + points[z].alpha = 1.0f; + z = 5; + } + } + + c = MAX_BIG_BALLS*4; + } + } + } + } + + if (meteorsDestroyed == (MAX_BIG_BALLS + MAX_BIG_BALLS*2 + MAX_BIG_BALLS*4)) victory = true; + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } + + // Points move-up and fade logic + for (int z = 0; z < 5; z++) + { + if (points[z].alpha > 0.0f) + { + points[z].position.y -= 2; + points[z].alpha -= 0.02f; + } + + if (points[z].alpha < 0.0f) points[z].alpha = 0.0f; + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + // Draw player + Vector2 v1 = { player.position.x + sinf(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cosf(player.rotation*DEG2RAD)*(shipHeight) }; + Vector2 v2 = { player.position.x - cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y - sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) }; + Vector2 v3 = { player.position.x + cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y + sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) }; + DrawTriangle(v1, v2, v3, MAROON); + + // Draw meteors (big) + for (int i = 0;i < MAX_BIG_BALLS; i++) + { + if (bigBalls[i].active) DrawCircleV(bigBalls[i].position, bigBalls[i].radius, DARKGRAY); + else DrawCircleV(bigBalls[i].position, bigBalls[i].radius, Fade(LIGHTGRAY, 0.3f)); + } + + // Draw meteors (medium) + for (int i = 0;i < MAX_BIG_BALLS*2; i++) + { + if (mediumBalls[i].active) DrawCircleV(mediumBalls[i].position, mediumBalls[i].radius, GRAY); + else DrawCircleV(mediumBalls[i].position, mediumBalls[i].radius, Fade(LIGHTGRAY, 0.3f)); + } + + // Draw meteors (small) + for (int i = 0;i < MAX_BIG_BALLS*4; i++) + { + if (smallBalls[i].active) DrawCircleV(smallBalls[i].position, smallBalls[i].radius, GRAY); + else DrawCircleV(smallBalls[i].position, smallBalls[i].radius, Fade(LIGHTGRAY, 0.3f)); + } + + // Draw shoot + for (int i = 0; i < PLAYER_MAX_SHOOTS; i++) + { + if (shoot[i].active) DrawLine(linePosition.x, linePosition.y, shoot[i].position.x, shoot[i].position.y, RED); + } + + // Draw score points + for (int z = 0; z < 5; z++) + { + if (points[z].alpha > 0.0f) + { + DrawText(FormatText("+%02i", points[z].value), points[z].position.x, points[z].position.y, 20, Fade(BLUE, points[z].alpha)); + } + } + + // Draw score (UI) + DrawText(FormatText("SCORE: %i", score), 10, 10, 20, LIGHTGRAY); + + if (victory) + { + DrawText("YOU WIN!", screenWidth/2 - MeasureText("YOU WIN!", 60)/2, 100, 60, LIGHTGRAY); + DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, LIGHTGRAY); + } + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, LIGHTGRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, LIGHTGRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} \ No newline at end of file diff --git a/games/raylib_demo/makefile b/games/raylib_demo/makefile index 3e2fe6147..a4435bb0b 100644 --- a/games/raylib_demo/makefile +++ b/games/raylib_demo/makefile @@ -2,7 +2,7 @@ # # raylib - Basic Game # -# makefile to compile basic game +# makefile to compile advance game for desktop platforms, Raspberry Pi and HTML5 (emscripten) # # Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) # @@ -23,31 +23,57 @@ # #************************************************************************************************** -# define raylib platform (by default, compile for RPI) -# Other possible platform: PLATFORM_DESKTOP, PLATFORM_WEB, PLATFORM_RPI -PLATFORM ?= PLATFORM_WEB +# define raylib platform to compile for +# possible platforms: PLATFORM_DESKTOP PLATFORM_RPI PLATFORM_WEB +# WARNING: To compile to HTML5, code must be redesigned to use emscripten.h and emscripten_set_main_loop() +PLATFORM ?= PLATFORM_DESKTOP + +# determine PLATFORM_OS in case PLATFORM_DESKTOP selected +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + ifeq ($(OS),Windows_NT) + PLATFORM_OS=WINDOWS + LIBPATH=win32 + else + UNAMEOS:=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + LIBPATH=linux + else + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS=OSX + LIBPATH=osx + endif + endif + endif +endif # define compiler: gcc for C program, define as g++ for C++ ifeq ($(PLATFORM),PLATFORM_WEB) # define emscripten compiler CC = emcc +else +ifeq ($(PLATFORM_OS),OSX) + # define llvm compiler for mac + CC = clang else # define default gcc compiler CC = gcc endif +endif # define compiler flags: # -O2 defines optimization level # -Wall turns on most, but not all, compiler warnings # -std=c99 use standard C from 1999 revision ifeq ($(PLATFORM),PLATFORM_RPI) - CFLAGS = -O1 -Wall -std=gnu99 -fgnu89-inline + CFLAGS = -O2 -Wall -std=gnu99 -fgnu89-inline else - CFLAGS = -O1 -Wall -std=c99 + CFLAGS = -O2 -Wall -std=c99 endif - ifeq ($(PLATFORM),PLATFORM_WEB) - CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 -s ASSERTIONS=1 --preload-file resources + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 # to check for memory allocation errors (-O1 disables it) #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) endif @@ -59,33 +85,66 @@ ifeq ($(PLATFORM),PLATFORM_RPI) INCLUDES = -I. -I../../src -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads else INCLUDES = -I. -I../../src +# external libraries headers +# GLFW3 + INCLUDES += -I../../external/glfw3/include +# GLEW - Not required any more, replaced by GLAD + #INCLUDES += -I../external/glew/include +# OpenAL Soft + INCLUDES += -I../../external/openal_soft/include endif # define library paths containing required libs -ifeq ($(PLATFORM),PLATFORM_WEB) - LFLAGS = -L. -else +ifeq ($(PLATFORM),PLATFORM_RPI) LFLAGS = -L. -L../../src -L/opt/vc/lib +else + LFLAGS = -L. -L../../src -LC:/raylib/raylib/src + # external libraries to link with + # GLFW3 + LFLAGS += -L../../external/glfw3/lib/$(LIBPATH) + ifneq ($(PLATFORM_OS),OSX) + # OpenAL Soft + LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) + # GLEW: Not used, replaced by GLAD + #LFLAGS += -L../../external/glew/lib/$(LIBPATH) + endif endif # define any libraries to link into executable # if you want to link libraries (libname.so or libname.a), use the -lname +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),LINUX) + # libraries for Debian GNU/Linux desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw3 -lGLEW -lGL -lopenal -lm -pthread + # on XWindow could require also below libraries, just uncomment + #LIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + else + ifeq ($(PLATFORM_OS),OSX) + # libraries for OS X 10.9 desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -framework OpenGL -framework OpenAl -framework Cocoa + else + # libraries for Windows desktop compiling + # NOTE: GLFW3 and OpenAL Soft libraries should be installed + LIBS = -lraylib -lglfw3 -lopengl32 -lopenal32 -lgdi32 + endif + endif +endif ifeq ($(PLATFORM),PLATFORM_RPI) # libraries for Raspberry Pi compiling # NOTE: OpenAL Soft library should be installed (libopenal1 package) LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal -else - # libraries for Windows desktop compiling - # NOTE: GLFW3 and OpenAL Soft libraries should be installed - LIBS = -lraylib -lglfw3 -lglew32 -lopengl32 -lopenal32 -lgdi32 endif - ifeq ($(PLATFORM),PLATFORM_WEB) + # NOTE: Set the correct path to libraylib.bc LIBS = ../../src/libraylib.bc endif # define additional parameters and flags for windows -ifeq ($(PLATFORM),PLATFORM_DESKTOP) +ifeq ($(PLATFORM_OS),WINDOWS) # resources file contains windows exe icon # -Wl,--subsystem,windows hides the console window WINFLAGS = ../../src/resources -Wl,--subsystem,windows @@ -99,21 +158,30 @@ endif # in this case, the 'default' target entry is qidv_raylib default: raylib_demo -# compile qidv_raylib +# compile raylib demo raylib_demo: raylib_demo.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) # clean everything clean: -ifeq ($(PLATFORM),PLATFORM_RPI) - rm -f *.o -# find . -executable -delete -else -ifeq ($(PLATFORM),PLATFORM_WEB) - del *.html *.js -else - del *.o *.exe +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),OSX) + find . -type f -perm +ugo+x -delete + rm -f *.o + else + ifeq ($(PLATFORM_OS),LINUX) + find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -f + else + del *.o *.exe + endif + endif endif +ifeq ($(PLATFORM),PLATFORM_RPI) + find . -type f -executable -delete + rm -f *.o +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + del *.o *.html *.js endif @echo Cleaning done diff --git a/games/raylib_demo/raylib_demo.c b/games/raylib_demo/raylib_demo.c index 5bbccbe80..7f6f291a3 100644 --- a/games/raylib_demo/raylib_demo.c +++ b/games/raylib_demo/raylib_demo.c @@ -1,10 +1,8 @@ /******************************************************************************************* * -* raylib - Talk: QIDV raylib (Learn Videogames Programming) +* raylib - Features demo 01 (Learn Videogames Programming) * -* Aprende a Programar Videojuegos con raylib -* -* This talk has been created using raylib v1.2 (www.raylib.com) +* This show has been created using raylib v1.4 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * * Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) @@ -703,11 +701,11 @@ void UpdateDrawOneFrame(void) { DrawText("This module give you functions to:", 48, 200, 10, GetColor(0x5c5a5aff)); - DrawTextEx(fontRomulus, "Open-Close Window", (Vector2){ 48, 230 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x5c5a5aff)); - DrawTextEx(fontRomulus, "Manage Drawing Area", (Vector2){ 48, 260 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x5c5a5aff)); - DrawTextEx(fontRomulus, "Manage Inputs", (Vector2){ 48, 290 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x5c5a5aff)); - DrawTextEx(fontRomulus, "Manage Timming", (Vector2){ 48, 320 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x5c5a5aff)); - DrawTextEx(fontRomulus, "Auxiliar Functions", (Vector2){ 48, 350 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x5c5a5aff)); + DrawTextEx(fontRomulus, "Open-Close Window", (Vector2){ 48, 230 }, fontRomulus.size*2, 4, GetColor(0x5c5a5aff)); + DrawTextEx(fontRomulus, "Manage Drawing Area", (Vector2){ 48, 260 }, fontRomulus.size*2, 4, GetColor(0x5c5a5aff)); + DrawTextEx(fontRomulus, "Manage Inputs", (Vector2){ 48, 290 }, fontRomulus.size*2, 4, GetColor(0x5c5a5aff)); + DrawTextEx(fontRomulus, "Manage Timming", (Vector2){ 48, 320 }, fontRomulus.size*2, 4, GetColor(0x5c5a5aff)); + DrawTextEx(fontRomulus, "Auxiliar Functions", (Vector2){ 48, 350 }, fontRomulus.size*2, 4, GetColor(0x5c5a5aff)); switch (coreWindow) { @@ -733,16 +731,16 @@ void UpdateDrawOneFrame(void) if (framesCounter > 140) { - DrawTextEx(fontMecha, "MOVE ME", (Vector2){ ballPosition.x - 26, ballPosition.y - 20 }, GetFontBaseSize(fontMecha), 2, BLACK); - DrawTextEx(fontMecha, "[ W A S D ]", (Vector2){ ballPosition.x - 36, ballPosition.y }, GetFontBaseSize(fontMecha), 2, BLACK); + DrawTextEx(fontMecha, "MOVE ME", (Vector2){ ballPosition.x - 26, ballPosition.y - 20 }, fontMecha.size, 2, BLACK); + DrawTextEx(fontMecha, "[ W A S D ]", (Vector2){ ballPosition.x - 36, ballPosition.y }, fontMecha.size, 2, BLACK); } } break; case SHAPES: { DrawText("This module give you functions to:", 48, 200, 10, GetColor(0xcd5757ff)); - DrawTextEx(fontRomulus, "Draw Basic Shapes", (Vector2){ 48, 230 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0xcd5757ff)); - DrawTextEx(fontRomulus, "Basic Collision Detection", (Vector2){ 48, 260 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0xcd5757ff)); + DrawTextEx(fontRomulus, "Draw Basic Shapes", (Vector2){ 48, 230 }, fontRomulus.size*2, 4, GetColor(0xcd5757ff)); + DrawTextEx(fontRomulus, "Basic Collision Detection", (Vector2){ 48, 260 }, fontRomulus.size*2, 4, GetColor(0xcd5757ff)); DrawCircle(screenWidth/4, 120 + 240, 35, DARKBLUE); DrawCircleGradient(screenWidth/4, 220 + 240, 60, GREEN, SKYBLUE); @@ -763,8 +761,8 @@ void UpdateDrawOneFrame(void) { DrawText("This module give you functions to:", 48, 200, 10, GetColor(0x60815aff)); - DrawTextEx(fontRomulus, "Load Images and Textures", (Vector2){ 48, 230 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x60815aff)); - DrawTextEx(fontRomulus, "Draw Textures", (Vector2){ 48, 260 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x60815aff)); + DrawTextEx(fontRomulus, "Load Images and Textures", (Vector2){ 48, 230 }, fontRomulus.size*2, 4, GetColor(0x60815aff)); + DrawTextEx(fontRomulus, "Draw Textures", (Vector2){ 48, 260 }, fontRomulus.size*2, 4, GetColor(0x60815aff)); DrawRectangle(138, 348, 260, 260, GRAY); DrawTexturePro(lena, (Rectangle){ 0, 0, lena.width, lena.height }, (Rectangle){ 140 + 128, 350 + 128, lena.width/2*scaleFactor, lena.height/2*scaleFactor }, (Vector2){ lena.width/4*scaleFactor, lena.height/4*scaleFactor }, 0.0f, WHITE); @@ -780,21 +778,21 @@ void UpdateDrawOneFrame(void) { DrawText("This module give you functions to:", 48, 200, 10, GetColor(0x377764ff)); - DrawTextEx(fontRomulus, "Load SpriteFonts", (Vector2){ 48, 230 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x377764ff)); - DrawTextEx(fontRomulus, "Draw Text", (Vector2){ 48, 260 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x377764ff)); - DrawTextEx(fontRomulus, "Text Formatting", (Vector2){ 48, 290 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x377764ff)); + DrawTextEx(fontRomulus, "Load SpriteFonts", (Vector2){ 48, 230 }, fontRomulus.size*2, 4, GetColor(0x377764ff)); + DrawTextEx(fontRomulus, "Draw Text", (Vector2){ 48, 260 }, fontRomulus.size*2, 4, GetColor(0x377764ff)); + DrawTextEx(fontRomulus, "Text Formatting", (Vector2){ 48, 290 }, fontRomulus.size*2, 4, GetColor(0x377764ff)); DrawTexture(texAlagard, 60, 360, WHITE); - DrawTextEx(fontMechaC, msg1, (Vector2){ 540 + 168, 210 }, GetFontBaseSize(fontMechaC), -3, WHITE); - DrawTextEx(fontAlagardC, msg2, (Vector2){ 460 + 140, 260 }, GetFontBaseSize(fontAlagardC), -2, WHITE); - DrawTextEx(fontJupiterC, msg3, (Vector2){ 640 + 70, 300 }, GetFontBaseSize(fontJupiterC), 2, WHITE); + DrawTextEx(fontMechaC, msg1, (Vector2){ 540 + 168, 210 }, fontMechaC.size, -3, WHITE); + DrawTextEx(fontAlagardC, msg2, (Vector2){ 460 + 140, 260 }, fontAlagardC.size, -2, WHITE); + DrawTextEx(fontJupiterC, msg3, (Vector2){ 640 + 70, 300 }, fontJupiterC.size, 2, WHITE); - DrawTextEx(fontAlagard, "It also includes some...", (Vector2){ 650 + 70, 400 }, GetFontBaseSize(fontAlagard)*2, 2, MAROON); - DrawTextEx(fontPixelplay, "...free fonts in rBMF format...", (Vector2){ 705 - 26, 450 }, GetFontBaseSize(fontPixelplay)*2, 4, ORANGE); - DrawTextEx(fontMecha, "...to be used even in...", (Vector2){ 700 + 40, 500 }, GetFontBaseSize(fontMecha)*2, 4, DARKGREEN); - DrawTextEx(fontSetback, "...comercial projects...", (Vector2){ 710, 550 }, GetFontBaseSize(fontSetback)*2, 4, DARKBLUE); - DrawTextEx(fontRomulus, "...completely for free!", (Vector2){ 710 + 17, 600 }, GetFontBaseSize(fontRomulus)*2, 3, DARKPURPLE); + DrawTextEx(fontAlagard, "It also includes some...", (Vector2){ 650 + 70, 400 }, fontAlagard.size*2, 2, MAROON); + DrawTextEx(fontPixelplay, "...free fonts in rBMF format...", (Vector2){ 705 - 26, 450 }, fontPixelplay.size*2, 4, ORANGE); + DrawTextEx(fontMecha, "...to be used even in...", (Vector2){ 700 + 40, 500 }, fontMecha.size*2, 4, DARKGREEN); + DrawTextEx(fontSetback, "...comercial projects...", (Vector2){ 710, 550 }, fontSetback.size*2, 4, DARKBLUE); + DrawTextEx(fontRomulus, "...completely for free!", (Vector2){ 710 + 17, 600 }, fontRomulus.size*2, 3, DARKPURPLE); DrawText("This is a custom font spritesheet, raylib can load it automatically!", 228, 360 + 295, 10, GRAY); @@ -803,9 +801,9 @@ void UpdateDrawOneFrame(void) { DrawText("This module give you functions to:", 48, 200, 10, GetColor(0x417794ff)); - DrawTextEx(fontRomulus, "Draw Geometric Models", (Vector2){ 48, 230 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x417794ff)); - DrawTextEx(fontRomulus, "Load 3D Models", (Vector2){ 48, 260 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x417794ff)); - DrawTextEx(fontRomulus, "Draw 3D Models", (Vector2){ 48, 290 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x417794ff)); + DrawTextEx(fontRomulus, "Draw Geometric Models", (Vector2){ 48, 230 }, fontRomulus.size*2, 4, GetColor(0x417794ff)); + DrawTextEx(fontRomulus, "Load 3D Models", (Vector2){ 48, 260 }, fontRomulus.size*2, 4, GetColor(0x417794ff)); + DrawTextEx(fontRomulus, "Draw 3D Models", (Vector2){ 48, 290 }, fontRomulus.size*2, 4, GetColor(0x417794ff)); Begin3dMode(camera); @@ -823,7 +821,7 @@ void UpdateDrawOneFrame(void) DrawCylinder((Vector3){1, 0, -4}, 0, 1.5, 3, 8, GOLD); DrawCylinderWires((Vector3){1, 0, -4}, 0, 1.5, 3, 8, PINK); - DrawModelEx(cat, (Vector3){ 8.0f, 0.0f, 2.0f }, (Vector3){ 0.0f, 0.5f*framesCounter, 0.0f }, (Vector3){ 0.1f, 0.1f, 0.1f }, WHITE); + DrawModelEx(cat, (Vector3){ 8.0f, 0.0f, 2.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, 0.5f*framesCounter, (Vector3){ 0.1f, 0.1f, 0.1f }, WHITE); DrawGizmo((Vector3){ 8.0f, 0.0f, 2.0f }); DrawGrid(10.0, 1.0); // Draw a grid @@ -837,8 +835,8 @@ void UpdateDrawOneFrame(void) { DrawText("This module give you functions to:", 48, 200, 10, GetColor(0x8c7539ff)); - DrawTextEx(fontRomulus, "Load and Play Sounds", (Vector2){ 48, 230 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x8c7539ff)); - DrawTextEx(fontRomulus, "Play Music (streaming)", (Vector2){ 48, 260 }, GetFontBaseSize(fontRomulus)*2, 4, GetColor(0x8c7539ff)); + DrawTextEx(fontRomulus, "Load and Play Sounds", (Vector2){ 48, 230 }, fontRomulus.size*2, 4, GetColor(0x8c7539ff)); + DrawTextEx(fontRomulus, "Play Music (streaming)", (Vector2){ 48, 260 }, fontRomulus.size*2, 4, GetColor(0x8c7539ff)); DrawText("PRESS SPACE to START PLAYING MUSIC", 135, 350, 20, GRAY); DrawRectangle(150, 390, 400, 12, LIGHTGRAY); @@ -891,7 +889,7 @@ void UpdateDrawOneFrame(void) case ENDING: { // Draw ENDING screen - DrawTextEx(fontAlagard, "LEARN VIDEOGAMES PROGRAMMING", (Vector2){ screenWidth/2 - MeasureTextEx(fontAlagard, "LEARN VIDEOGAMES PROGRAMMING", GetFontBaseSize(fontAlagard)*4, 4).x/2, 80 }, GetFontBaseSize(fontAlagard)*4, 4, MAROON); + DrawTextEx(fontAlagard, "LEARN VIDEOGAMES PROGRAMMING", (Vector2){ screenWidth/2 - MeasureTextEx(fontAlagard, "LEARN VIDEOGAMES PROGRAMMING", fontAlagard.size*4, 4).x/2, 80 }, fontAlagard.size*4, 4, MAROON); DrawTexture(raylibLogoA, logoPositionX, logoPositionY - 40, WHITE); diff --git a/games/skully_escape/makefile b/games/skully_escape/makefile new file mode 100644 index 000000000..d47760d3a --- /dev/null +++ b/games/skully_escape/makefile @@ -0,0 +1,254 @@ +#************************************************************************************************** +# +# raylib - Advance Game +# +# makefile to compile advance game +# +# Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +# +# This software is provided "as-is", without any express or implied warranty. In no event +# will the authors be held liable for any damages arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, including commercial +# applications, and to alter it and redistribute it freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not claim that you +# wrote the original software. If you use this software in a product, an acknowledgment +# in the product documentation would be appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be misrepresented +# as being the original software. +# +# 3. This notice may not be removed or altered from any source distribution. +# +#************************************************************************************************** + +# define raylib platform if not defined (by default, compile for RPI) +# Other possible platform: PLATFORM_DESKTOP +PLATFORM ?= PLATFORM_DESKTOP + +# determine PLATFORM_OS in case PLATFORM_DESKTOP selected +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + ifeq ($(OS),Windows_NT) + PLATFORM_OS=WINDOWS + LIBPATH=win32 + else + UNAMEOS:=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + LIBPATH=linux + else + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS=OSX + LIBPATH=osx + endif + endif + endif +endif + +# define compiler: gcc for C program, define as g++ for C++ +ifeq ($(PLATFORM),PLATFORM_WEB) + # define emscripten compiler + CC = emcc +else +ifeq ($(PLATFORM_OS),OSX) + # define llvm compiler for mac + CC = clang +else + # define default gcc compiler + CC = gcc +endif +endif + +# define compiler flags: +# -O2 defines optimization level +# -Wall turns on most, but not all, compiler warnings +# -std=c99 use standard C from 1999 revision +ifeq ($(PLATFORM),PLATFORM_RPI) + CFLAGS = -O2 -Wall -std=gnu99 -fgnu89-inline +else + CFLAGS = -O2 -Wall -std=c99 +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources -s ALLOW_MEMORY_GROWTH=1 --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 --preload-file resources + #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing + #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) +endif + +# define any directories containing required header files +ifeq ($(PLATFORM),PLATFORM_RPI) + INCLUDES = -I. -I../../src -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads +else + INCLUDES = -I. -I../../src +# external libraries headers +# GLFW3 + INCLUDES += -I../../external/glfw3/include +# GLEW + INCLUDES += -I../../external/glew/include +# OpenAL Soft + INCLUDES += -I../../external/openal_soft/include +endif + +# define library paths containing required libs +ifeq ($(PLATFORM),PLATFORM_RPI) + LFLAGS = -L. -L../../src -L/opt/vc/lib +else + LFLAGS = -L. -L../../src -L../../../src + # external libraries to link with + # GLFW3 + LFLAGS += -L../../external/glfw3/lib/$(LIBPATH) + ifneq ($(PLATFORM_OS),OSX) + # OpenAL Soft + LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) + # GLEW + LFLAGS += -L../../external/glew/lib/$(LIBPATH) + endif +endif + +# define any libraries to link into executable +# if you want to link libraries (libname.so or libname.a), use the -lname +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),LINUX) + # libraries for Debian GNU/Linux desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -lGLEW -lGL -lopenal + endif + ifeq ($(PLATFORM_OS),OSX) + # libraries for OS X 10.9 desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -framework OpenGL -framework OpenAl -framework Cocoa + else + # libraries for Windows desktop compiling + # NOTE: GLFW3 and OpenAL Soft libraries should be installed + LIBS = -lraylib -lglfw3 -lglew32 -lopengl32 -lopenal32 -lgdi32 + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + # libraries for Raspberry Pi compiling + # NOTE: OpenAL Soft library should be installed (libopenal1 package) + LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + LIBS = ../../src/libraylib.bc +endif + +# define additional parameters and flags for windows +ifeq ($(PLATFORM_OS),WINDOWS) + # resources file contains windows exe icon + # -Wl,--subsystem,windows hides the console window + WINFLAGS = ../../src/resources + #-Wl,--subsystem,windows +endif + +ifeq ($(PLATFORM),PLATFORM_WEB) + EXT = .html +endif + +# define all screen object files required +SCREENS = \ + screens/screen_logo.o \ + screens/screen_logo_raylib.o \ + screens/screen_title.o \ + screens/screen_attic.o \ + screens/screen_aisle01.o \ + screens/screen_aisle02.o \ + screens/screen_armory.o \ + screens/screen_livingroom.o \ + screens/screen_kitchen.o \ + screens/screen_bathroom.o \ + screens/screen_ending.o \ + player.o \ + monster.o \ + +# typing 'make' will invoke the first target entry in the file, +# in this case, the 'default' target entry is advance_game +default: skully_escape + +# compile template - advance_game +skully_escape: skully_escape.c $(SCREENS) + $(CC) -o $@$(EXT) $< $(SCREENS) $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile screen LOGO +screens/screen_logo.o: screens/screen_logo.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen LOGO raylib +screens/screen_logo_raylib.o: screens/screen_logo_raylib.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen TITLE +screens/screen_title.o: screens/screen_title.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen ATTIC +screens/screen_attic.o: screens/screen_attic.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen AISLE01 +screens/screen_aisle01.o: screens/screen_aisle01.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen AISLE02 +screens/screen_aisle02.o: screens/screen_aisle02.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen BATHROOM +screens/screen_bathroom.o: screens/screen_bathroom.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen LIVINGROOM +screens/screen_livingroom.o: screens/screen_livingroom.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen KITCHEN +screens/screen_kitchen.o: screens/screen_kitchen.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen ARMORY +screens/screen_armory.o: screens/screen_armory.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen ENDING +screens/screen_ending.o: screens/screen_ending.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen LOGO +player.o: player.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen LOGO +monster.o: monster.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# clean everything +clean: +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),OSX) + find . -type f -perm +ugo+x -delete + rm -f *.o + else + ifeq ($(PLATFORM_OS),LINUX) + find . -type f -executable -delete + rm -f *.o + else + del *.o *.exe + endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + find . -type f -executable -delete + rm -f *.o +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + del *.o *.html *.js +endif + @echo Cleaning done + +# instead of defining every module one by one, we can define a pattern +# this pattern below will automatically compile every module defined on $(OBJS) +#%.exe : %.c +# $(CC) -o $@ $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) diff --git a/games/skully_escape/monster.c b/games/skully_escape/monster.c new file mode 100644 index 000000000..643d0a731 --- /dev/null +++ b/games/skully_escape/monster.c @@ -0,0 +1,54 @@ +/*********************************************************************************** +* +* KING GAME JAM - GRAY TEAM +* +* +* +* +* This game has been created using raylib (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +************************************************************************************/ + +#include "raylib.h" +#include "monster.h" + +void UpdateMonster(Monster *monster) +{ + if (!monster->active) + { + if (CheckCollisionPointRec(GetMousePosition(), monster->bounds)) monster->selected = true; + else monster->selected = false; + } + else if (monster->spooky) + { + monster->framesCounter++; + monster->currentSeq = 0; + + if (monster->framesCounter > 7) + { + monster->currentFrame++; + monster->framesCounter = 0; + + if (monster->currentFrame > monster->numFrames - 1) monster->currentFrame = 1; + } + } + + monster->frameRec.x = monster->currentFrame*monster->texture.width/monster->numFrames; + monster->frameRec.y = monster->currentSeq*monster->texture.height; +} + +void DrawMonster(Monster monster, int scroll) +{ + Vector2 scrollPos = { monster.position.x - scroll, monster.position.y }; + + if (monster.selected) DrawTextureRec(monster.texture, monster.frameRec, scrollPos, RED); + else DrawTextureRec(monster.texture, monster.frameRec, scrollPos, WHITE); +} + +void UnloadMonster(Monster monster) +{ + UnloadTexture(monster.texture); +} \ No newline at end of file diff --git a/games/skully_escape/monster.h b/games/skully_escape/monster.h new file mode 100644 index 000000000..e7e018564 --- /dev/null +++ b/games/skully_escape/monster.h @@ -0,0 +1,73 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Screens Functions Declarations (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef MONSTER_H +#define MONSTER_H + +#define MONSTER_ANIM_FRAMES 7 +#define MONSTER_ANIM_SEQ 2 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//--------------------------------------------------------------------------------- +typedef struct Monster { + Vector2 position; + Texture2D texture; + Rectangle bounds; + Rectangle frameRec; + Color color; + int framesCounter; + int currentFrame; + int currentSeq; + int numFrames; + bool active; + bool selected; + bool spooky; +} Monster; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- + + + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Monster Functions Declaration +//---------------------------------------------------------------------------------- + +void UpdateMonster(Monster *monster); +void DrawMonster(Monster monster, int scroll); +void UnloadMonster(Monster monster); + + +#ifdef __cplusplus +} +#endif + +#endif // SCREENS_H \ No newline at end of file diff --git a/games/skully_escape/player.c b/games/skully_escape/player.c new file mode 100644 index 000000000..11006f65d --- /dev/null +++ b/games/skully_escape/player.c @@ -0,0 +1,281 @@ +/*********************************************************************************** +* +* KING GAME JAM - GRAY TEAM +* +* +* +* +* This game has been created using raylib (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +************************************************************************************/ + +#include "raylib.h" +#include "player.h" + +#define PLAYER_ANIM_FRAMES 4 +#define PLAYER_ANIM_SEQ 6 + +//---------------------------------------------------------------------------------- +// Module Variables Definition +//---------------------------------------------------------------------------------- + +// Player mouse moving variables +static bool movingAnim; +static int moveDirection; +static int nextMovePoint; + +// Mouse pointer variables +static Vector2 pointerPosition; +static bool pointerAnim; +static float pointerAlpha; + +static int framesCounter; +static bool outControl = false; + +static int animTimer = 0; + +static Texture2D texLife; + +static void DrawLifes(void); + +// player initialitaction definition +void InitPlayer(void) +{ + // NOTE: Some player variables are only initialized once + player.texture = LoadTexture("resources/textures/skully.png"); + player.position = (Vector2){ 350, 400 }; + player.numLifes = 4; + + ResetPlayer(); + + framesCounter = 0; + + texLife = LoadTexture("resources/textures/skully_icon.png"); +} + +// player update definition +void UpdatePlayer(void) +{ + if (!outControl) + { + if ((IsKeyDown(KEY_LEFT)) || (IsKeyDown(KEY_RIGHT))) + { + moveDirection = -1; + movingAnim = false; + } + + if ((IsKeyDown(KEY_RIGHT)) || (moveDirection == 0)) + { + player.currentSeq = WALK_RIGHT; + framesCounter++; + + if (framesCounter > 15) + { + player.currentFrame++; + framesCounter = 0; + + if (player.currentFrame > PLAYER_ANIM_FRAMES - 1) player.currentFrame = 0; + } + + player.position.x += 4; + } + else if ((IsKeyDown(KEY_LEFT)) || (moveDirection == 1)) + { + player.currentSeq = WALK_LEFT; + framesCounter++; + + if (framesCounter > 15) + { + player.currentFrame++; + framesCounter = 0; + + if (player.currentFrame > PLAYER_ANIM_FRAMES - 1) player.currentFrame = 0; + } + + player.position.x -= 4; + } + else player.currentFrame = 0; + } + else + { + framesCounter++; + animTimer++; + + if (framesCounter > 10) + { + player.currentFrame++; + framesCounter = 0; + + if (player.currentFrame > PLAYER_ANIM_FRAMES - 1) player.currentFrame = 0; + + // We can adjust animation playing time depending on sequence + switch (player.currentSeq) + { + case SCARE_RIGHT: + { + if (animTimer > 180) + { + animTimer = 0; + outControl = false; + player.currentSeq = WALK_LEFT; + } + } break; + case SCARE_LEFT: + { + if (animTimer > 240) + { + animTimer = 0; + outControl = false; + player.currentSeq = WALK_RIGHT; + } + } break; + case SEARCH: + case FIND_KEY: + { + if (animTimer > 240) + { + animTimer = 0; + outControl = false; + player.currentSeq = WALK_RIGHT; + } + } break; + } + } + } + + if (player.position.x < 30) player.position.x = 30; + else if (player.position.x > (GetScreenWidth() - 200)) player.position.x = GetScreenWidth() - 200; + + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + pointerPosition = GetMousePosition(); + pointerAnim = true; + pointerAlpha = 1.0f; + + nextMovePoint = (int)pointerPosition.x; + movingAnim = true; + } + + if (movingAnim) + { + if (nextMovePoint > (player.position.x + (player.frameRec.width/2) + 5)) moveDirection = 0; // Move Left + else if (nextMovePoint < (player.position.x + (player.frameRec.width/2) - 5)) moveDirection = 1; // Move Right + else + { + moveDirection = -1; + movingAnim = 0; + } + } + + player.frameRec.x = player.currentFrame*player.texture.width/PLAYER_ANIM_FRAMES; + player.frameRec.y = (player.currentSeq - 1)*player.texture.height/PLAYER_ANIM_SEQ; + + // Update player bounds + player.bounds = (Rectangle){ player.position.x + 50, player.position.y - 60, 100, 300 }; + + // Mouse pointer alpha animation + if (pointerAnim) + { + pointerAlpha -= 0.1f; + + if (pointerAlpha <= 0.0f) + { + pointerAlpha = 0.0f; + pointerAnim = false; + } + } +} +// +void DrawPlayer(void) +{ + DrawTextureRec(player.texture, player.frameRec, player.position, WHITE); + + // Draw mouse pointer on click + if (pointerAnim) DrawCircleV(pointerPosition, 20, Fade(RED, pointerAlpha)); + + DrawLifes(); +} + +void UnloadPlayer(void) +{ + UnloadTexture(player.texture); + UnloadTexture(texLife); +} + +void ResetPlayer(void) +{ + // Reset player variables + player.frameRec = (Rectangle){ 0, 0, player.texture.width/PLAYER_ANIM_FRAMES, player.texture.height/PLAYER_ANIM_SEQ }; + player.currentFrame = 0; + player.currentSeq = WALK_RIGHT; + + player.key = false; + player.dead = false; + + // Reset player position + if (player.position.x < 400) player.position.x = GetScreenWidth() - 350; + if (player.position.x > (GetScreenWidth() - 400)) player.position.x = 350; + + // Reset moving variables + movingAnim = false; + moveDirection = -1; + nextMovePoint = 0; + framesCounter = 0; + outControl = false; + animTimer = 0; + + // Reset pointer + pointerAlpha = 0.0f; + pointerAnim = false; +} + +void ScarePlayer(void) +{ + player.currentFrame = 0; + + if (moveDirection == 0) player.currentSeq = SCARE_RIGHT; + else if (moveDirection == 1) player.currentSeq = SCARE_LEFT; + else player.currentSeq = SCARE_RIGHT; + + player.numLifes--; + + if (player.numLifes <= 0) player.dead = true; + + outControl = true; +} + +void SearchKeyPlayer(void) +{ + moveDirection = -1; + movingAnim = 0; + + player.currentFrame = 0; + player.currentSeq = SEARCH; + + outControl = true; +} + +void FindKeyPlayer(void) +{ + player.currentFrame = 0; + player.currentSeq = FIND_KEY; + player.key = true; + + outControl = true; +} + +static void DrawLifes(void) +{ + if (player.numLifes != 0) + { + Vector2 position = { 20, GetScreenHeight() - texLife.height - 20 }; + + for(int i = 0; i < player.numLifes; i++) + { + DrawTexture(texLife, position.x + i*texLife.width, position.y, Fade(RAYWHITE, 0.7f)); + } + } +} \ No newline at end of file diff --git a/games/skully_escape/player.h b/games/skully_escape/player.h new file mode 100644 index 000000000..7d59bdde8 --- /dev/null +++ b/games/skully_escape/player.h @@ -0,0 +1,51 @@ +#ifndef PLAYER_H +#define PLAYER_H + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum { NONE, WALK_RIGHT, WALK_LEFT, SCARE_RIGHT, SCARE_LEFT, SEARCH, FIND_KEY } PlayerSequence; + +typedef struct Player { + Vector2 position; + Rectangle bounds; + Texture2D texture; + Color color; + + // Animation variables + Rectangle frameRec; + int currentFrame; + int currentSeq; + + bool key; + int numLifes; + bool dead; +} Player; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +Player player; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Logo Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitPlayer(void); +void UpdatePlayer(void); +void DrawPlayer(void); +void UnloadPlayer(void); +void ResetPlayer(void); + +void ScarePlayer(void); +void SearchKeyPlayer(void); +void FindKeyPlayer(void); + +#ifdef __cplusplus +} +#endif + +#endif // SCREENS_H \ No newline at end of file diff --git a/games/skully_escape/resources/audio/come_play_with_me.ogg b/games/skully_escape/resources/audio/come_play_with_me.ogg new file mode 100644 index 000000000..425498b81 Binary files /dev/null and b/games/skully_escape/resources/audio/come_play_with_me.ogg differ diff --git a/games/skully_escape/resources/audio/door.ogg b/games/skully_escape/resources/audio/door.ogg new file mode 100644 index 000000000..a1d1cd1b3 Binary files /dev/null and b/games/skully_escape/resources/audio/door.ogg differ diff --git a/games/skully_escape/resources/audio/scream.ogg b/games/skully_escape/resources/audio/scream.ogg new file mode 100644 index 000000000..415240279 Binary files /dev/null and b/games/skully_escape/resources/audio/scream.ogg differ diff --git a/games/skully_escape/resources/textures/alagard.png b/games/skully_escape/resources/textures/alagard.png new file mode 100644 index 000000000..c5cc54dc8 Binary files /dev/null and b/games/skully_escape/resources/textures/alagard.png differ diff --git a/games/skully_escape/resources/textures/background_aisle01.png b/games/skully_escape/resources/textures/background_aisle01.png new file mode 100644 index 000000000..482056f8d Binary files /dev/null and b/games/skully_escape/resources/textures/background_aisle01.png differ diff --git a/games/skully_escape/resources/textures/background_aisle02.png b/games/skully_escape/resources/textures/background_aisle02.png new file mode 100644 index 000000000..fced627f3 Binary files /dev/null and b/games/skully_escape/resources/textures/background_aisle02.png differ diff --git a/games/skully_escape/resources/textures/background_armory.png b/games/skully_escape/resources/textures/background_armory.png new file mode 100644 index 000000000..1a93807f9 Binary files /dev/null and b/games/skully_escape/resources/textures/background_armory.png differ diff --git a/games/skully_escape/resources/textures/background_attic.png b/games/skully_escape/resources/textures/background_attic.png new file mode 100644 index 000000000..446e09a77 Binary files /dev/null and b/games/skully_escape/resources/textures/background_attic.png differ diff --git a/games/skully_escape/resources/textures/background_bathroom.png b/games/skully_escape/resources/textures/background_bathroom.png new file mode 100644 index 000000000..55061d1f1 Binary files /dev/null and b/games/skully_escape/resources/textures/background_bathroom.png differ diff --git a/games/skully_escape/resources/textures/background_kitchen.png b/games/skully_escape/resources/textures/background_kitchen.png new file mode 100644 index 000000000..5c74c74e1 Binary files /dev/null and b/games/skully_escape/resources/textures/background_kitchen.png differ diff --git a/games/skully_escape/resources/textures/background_livingroom.png b/games/skully_escape/resources/textures/background_livingroom.png new file mode 100644 index 000000000..f91a11f95 Binary files /dev/null and b/games/skully_escape/resources/textures/background_livingroom.png differ diff --git a/games/skully_escape/resources/textures/doors.png b/games/skully_escape/resources/textures/doors.png new file mode 100644 index 000000000..f5a75d058 Binary files /dev/null and b/games/skully_escape/resources/textures/doors.png differ diff --git a/games/skully_escape/resources/textures/monster_arc.png b/games/skully_escape/resources/textures/monster_arc.png new file mode 100644 index 000000000..ae3e346d9 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_arc.png differ diff --git a/games/skully_escape/resources/textures/monster_blazon01.png b/games/skully_escape/resources/textures/monster_blazon01.png new file mode 100644 index 000000000..2d2a409cb Binary files /dev/null and b/games/skully_escape/resources/textures/monster_blazon01.png differ diff --git a/games/skully_escape/resources/textures/monster_blazon02.png b/games/skully_escape/resources/textures/monster_blazon02.png new file mode 100644 index 000000000..8cea93618 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_blazon02.png differ diff --git a/games/skully_escape/resources/textures/monster_blazon03.png b/games/skully_escape/resources/textures/monster_blazon03.png new file mode 100644 index 000000000..cc4665a1b Binary files /dev/null and b/games/skully_escape/resources/textures/monster_blazon03.png differ diff --git a/games/skully_escape/resources/textures/monster_candle.png b/games/skully_escape/resources/textures/monster_candle.png new file mode 100644 index 000000000..9feef00d9 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_candle.png differ diff --git a/games/skully_escape/resources/textures/monster_chair_left.png b/games/skully_escape/resources/textures/monster_chair_left.png new file mode 100644 index 000000000..b3ac070f3 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_chair_left.png differ diff --git a/games/skully_escape/resources/textures/monster_chair_right.png b/games/skully_escape/resources/textures/monster_chair_right.png new file mode 100644 index 000000000..d29cc0211 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_chair_right.png differ diff --git a/games/skully_escape/resources/textures/monster_closet.png b/games/skully_escape/resources/textures/monster_closet.png new file mode 100644 index 000000000..7c0c8f27f Binary files /dev/null and b/games/skully_escape/resources/textures/monster_closet.png differ diff --git a/games/skully_escape/resources/textures/monster_lamp_left.png b/games/skully_escape/resources/textures/monster_lamp_left.png new file mode 100644 index 000000000..3b31b77f5 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_lamp_left.png differ diff --git a/games/skully_escape/resources/textures/monster_lamp_right.png b/games/skully_escape/resources/textures/monster_lamp_right.png new file mode 100644 index 000000000..26491866b Binary files /dev/null and b/games/skully_escape/resources/textures/monster_lamp_right.png differ diff --git a/games/skully_escape/resources/textures/monster_mirror.png b/games/skully_escape/resources/textures/monster_mirror.png new file mode 100644 index 000000000..2e9943091 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_mirror.png differ diff --git a/games/skully_escape/resources/textures/monster_phone.png b/games/skully_escape/resources/textures/monster_phone.png new file mode 100644 index 000000000..a4862ef76 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_phone.png differ diff --git a/games/skully_escape/resources/textures/monster_picture.png b/games/skully_escape/resources/textures/monster_picture.png new file mode 100644 index 000000000..29549895b Binary files /dev/null and b/games/skully_escape/resources/textures/monster_picture.png differ diff --git a/games/skully_escape/resources/textures/monster_window.png b/games/skully_escape/resources/textures/monster_window.png new file mode 100644 index 000000000..47d70a793 Binary files /dev/null and b/games/skully_escape/resources/textures/monster_window.png differ diff --git a/games/skully_escape/resources/textures/skully.png b/games/skully_escape/resources/textures/skully.png new file mode 100644 index 000000000..9ce6cd583 Binary files /dev/null and b/games/skully_escape/resources/textures/skully.png differ diff --git a/games/skully_escape/resources/textures/skully_icon.png b/games/skully_escape/resources/textures/skully_icon.png new file mode 100644 index 000000000..91a0bc2aa Binary files /dev/null and b/games/skully_escape/resources/textures/skully_icon.png differ diff --git a/games/skully_escape/resources/textures/skully_logo.png b/games/skully_escape/resources/textures/skully_logo.png new file mode 100644 index 000000000..93e8bfe2b Binary files /dev/null and b/games/skully_escape/resources/textures/skully_logo.png differ diff --git a/games/skully_escape/resources/textures/title.png b/games/skully_escape/resources/textures/title.png new file mode 100644 index 000000000..20e08c887 Binary files /dev/null and b/games/skully_escape/resources/textures/title.png differ diff --git a/games/skully_escape/screens/screen_aisle01.c b/games/skully_escape/screens/screen_aisle01.c new file mode 100644 index 000000000..17d250588 --- /dev/null +++ b/games/skully_escape/screens/screen_aisle01.c @@ -0,0 +1,409 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" +#include "../player.h" +#include "../monster.h" + +#include + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; + +// Declare doors +static Door doorRight; +static Door doorCenter; +static Door doorLeft; + +// Decalre monsters +static Monster lamp; +static Monster picture; + +static bool monsterHover = false; +static int monsterCheck = -1; // Identify checking monster + +static const char message[256] = "WHO IS THERE???\nANYBODY IN THE ROOM???"; +static int msgPosX = 100; + +static int msgState = 0; // 0-writting, 1-wait, 2-choose +static int lettersCounter = 0; +static char msgBuffer[256] = { '\0' }; +static int msgCounter = 0; + +static bool searching = false; + +static int scroll = 0; + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitAisle01Screen(void) +{ + ResetPlayer(); + + // Reset Screen variables + monsterHover = false; + monsterCheck = -1; + msgState = 0; + msgCounter = 0; + lettersCounter = 0; + for (int i = 0; i < 256; i++) msgBuffer[i] = '\0'; + + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/background_aisle01.png"); + + scroll = player.position.x - 200; + + // Initialize doors + doorLeft.position = (Vector2) { -30, 135 }; + doorLeft.facing = 0; + doorLeft.locked = true; + doorLeft.frameRec =(Rectangle) {((doors.width/3)*doorLeft.facing), doors.height/2, doors.width/3, doors.height/2}; + doorLeft.bound = (Rectangle) { doorLeft.position.x, doorLeft.position.y, doors.width/3, doors.height/2}; + doorLeft.selected = false; + + doorCenter.position = (Vector2) { 1115, 104 }; + doorCenter.facing = 1; + doorCenter.locked = true; + doorCenter.frameRec =(Rectangle) {((doors.width/3)*doorCenter.facing), doors.height/2, doors.width/3, doors.height/2}; + doorCenter.bound = (Rectangle) { doorCenter.position.x, doorCenter.position.y, doors.width/3, doors.height/2}; + doorCenter.selected = false; + + doorRight.position = (Vector2) { 1710, 140 }; + doorRight.facing = 2; + doorRight.locked = true; + doorRight.frameRec =(Rectangle) {((doors.width/3)*doorRight.facing), doors.height/2, doors.width/3, doors.height/2}; + doorRight.bound = (Rectangle) { doorRight.position.x, doorRight.position.y, doors.width/3, doors.height/2}; + + // Monster init: lamp + lamp.position = (Vector2){ 187, 256 }; + lamp.texture = LoadTexture("resources/textures/monster_lamp_left.png"); + lamp.currentFrame = 0; + lamp.framesCounter = 0; + lamp.numFrames = 4; + lamp.bounds = (Rectangle){ lamp.position.x + 20, lamp.position.y, 90, 380 }; + lamp.frameRec = (Rectangle) { 0, 0, lamp.texture.width/lamp.numFrames, lamp.texture.height }; + lamp.selected = false; + lamp.active = false; + lamp.spooky = true; + + // Monster init: arc + picture.position = (Vector2){ 637, 178 }; + picture.texture = LoadTexture("resources/textures/monster_picture.png"); + picture.currentFrame = 0; + picture.framesCounter = 0; + picture.numFrames = 4; + picture.bounds = (Rectangle){ picture.position.x + 44, picture.position.y, 174, 256 }; + picture.frameRec = (Rectangle) { 0, 0, picture.texture.width/picture.numFrames, picture.texture.height }; + picture.selected = false; + picture.active = false; + picture.spooky = false; +} + +// Gameplay Screen Update logic +void UpdateAisle01Screen(void) +{ + // Update doors bounds + doorLeft.bound.x = doorLeft.position.x - scroll; + doorCenter.bound.x = doorCenter.position.x - scroll; + doorRight.bound.x = doorRight.position.x - scroll; + + if (player.key) + { + // Door: left + if ((CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || + (CheckCollisionRecs(player.bounds, doorLeft.bound))) doorLeft.selected = true; + else doorLeft.selected = false; + + if ((doorLeft.selected) && (CheckCollisionRecs(player.bounds, doorLeft.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorLeft.locked) + { + doorLeft.frameRec.y = 0; + doorLeft.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 1; + } + } + + // Door: center + if ((CheckCollisionPointRec(GetMousePosition(), doorCenter.bound)) || + (CheckCollisionRecs(player.bounds, doorCenter.bound))) doorCenter.selected = true; + else doorCenter.selected = false; + + if ((doorCenter.selected) && (CheckCollisionRecs(player.bounds, doorCenter.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorCenter.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorCenter.locked) + { + doorCenter.frameRec.y = 0; + doorCenter.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 2; + } + } + + // Door: right + if ((CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || + (CheckCollisionRecs(player.bounds, doorRight.bound))) doorRight.selected = true; + else doorRight.selected = false; + + if ((doorRight.selected) && (CheckCollisionRecs(player.bounds, doorRight.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorRight.locked) + { + doorRight.frameRec.y = 0; + doorRight.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 3; + } + } + } + + if (msgState > 2) + { + UpdatePlayer(); + + // Monsters logic + UpdateMonster(&lamp); + UpdateMonster(&picture); + } + + // Update monster bounds + lamp.bounds.x = lamp.position.x + 20 - scroll; + picture.bounds.x = picture.position.x + 44 - scroll; + + // Check player hover monsters to interact + if (((CheckCollisionRecs(player.bounds, lamp.bounds)) && !lamp.active) || + ((CheckCollisionRecs(player.bounds, picture.bounds)) && !picture.active)) monsterHover = true; + else monsterHover = false; + + // Monters logic: lamp + if ((CheckCollisionRecs(player.bounds, lamp.bounds)) && !lamp.active) + { + lamp.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), lamp.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 1; + } + } + else lamp.selected = false; + + // Monters logic: picture + if ((CheckCollisionRecs(player.bounds, picture.bounds)) && !picture.active) + { + picture.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), picture.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 2; + } + } + else picture.selected = false; + + if (searching) + { + framesCounter++; + + if (framesCounter > 180) + { + if (monsterCheck == 1) + { + if (lamp.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + lamp.active = true; + lamp.selected = false; + } + else if (monsterCheck == 2) + { + if (picture.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + picture.active = true; + picture.selected = false; + } + + searching = false; + framesCounter = 0; + } + } + + // Text animation + framesCounter++; + + if ((framesCounter%2) == 0) lettersCounter++; + + if (msgState == 0) + { + if (lettersCounter <= (int)strlen(message)) strncpy(msgBuffer, message, lettersCounter); + else + { + for (int i = 0; i < (int)strlen(msgBuffer); i++) msgBuffer[i] = '\0'; + + lettersCounter = 0; + msgState = 1; + } + + if (IsKeyPressed(KEY_ENTER)) msgState = 1; + } + else if (msgState == 1) + { + msgCounter++; + + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + msgState = 2; + msgCounter = 0; + } + } + else if (msgState == 2) + { + msgCounter++; + + if (msgCounter > 180) msgState = 3; + } + else msgCounter++; + + if (player.position.x > 200) + { + scroll = player.position.x - 200; + + if (scroll > 620) scroll = 620; + } +} + +// Gameplay Screen Draw logic +void DrawAisle01Screen(void) +{ + DrawTexture(background, -scroll, 0, WHITE); + + // Draw monsters + DrawMonster(lamp, scroll); + DrawMonster(picture, scroll); + + // Draw door + Vector2 doorScrollPos = { doorCenter.position.x - scroll, doorCenter.position.y }; + if (doorCenter.selected) DrawTextureRec(doors, doorCenter.frameRec, doorScrollPos, GREEN); + else DrawTextureRec(doors, doorCenter.frameRec, doorScrollPos, WHITE); + + doorScrollPos = (Vector2){ doorLeft.position.x - scroll, doorLeft.position.y }; + if (doorLeft.selected) DrawTextureRec(doors, doorLeft.frameRec, doorScrollPos, GREEN); + else DrawTextureRec(doors, doorLeft.frameRec, doorScrollPos, WHITE); + + doorScrollPos = (Vector2){ doorRight.position.x - scroll, doorRight.position.y }; + if (doorRight.selected) DrawTextureRec(doors, doorRight.frameRec, doorScrollPos, GREEN); + else DrawTextureRec(doors, doorRight.frameRec, doorScrollPos, WHITE); + + // Draw messsages + if (msgState < 2) DrawRectangle(0, 40, GetScreenWidth(), 200, Fade(LIGHTGRAY, 0.5f)); + else if (msgState == 2) DrawRectangle(0, 80, GetScreenWidth(), 100, Fade(LIGHTGRAY, 0.5f)); + + if (msgState == 0) + { + DrawTextEx(font, msgBuffer, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + } + else if (msgState == 1) + { + DrawTextEx(font, message, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + + if ((msgCounter/30)%2) DrawText("PRESS ENTER or CLICK", GetScreenWidth() - 280, 200, 20, BLACK); + } + else if (msgState == 2) + { + if ((msgCounter/30)%2) + { + DrawTextEx(font, "CHOOSE WISELY!", (Vector2){ 300, 95 }, font.size*2, 2, WHITE); + + DrawRectangleRec(lamp.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(picture.bounds, Fade(RED, 0.6f)); + } + } + else + { + if ((monsterHover) && ((msgCounter/30)%2)) + { + DrawRectangle(0, 0, GetScreenWidth(), 50, Fade(LIGHTGRAY, 0.5f)); + DrawText("PRESS SPACE or CLICK to INTERACT", 420, 15, 20, BLACK); + } + } + + DrawPlayer(); // NOTE: Also draws mouse pointer! +} + +// Gameplay Screen Unload logic +void UnloadAisle01Screen(void) +{ + // TODO: Unload GAMEPLAY screen variables here! + UnloadTexture(background); + + UnloadMonster(lamp); + UnloadMonster(picture); +} + +// Gameplay Screen should finish? +int FinishAisle01Screen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_aisle02.c b/games/skully_escape/screens/screen_aisle02.c new file mode 100644 index 000000000..6186a1fc3 --- /dev/null +++ b/games/skully_escape/screens/screen_aisle02.c @@ -0,0 +1,444 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" +#include "../player.h" +#include "../monster.h" + +#include + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; + +// Declare doors +static Door doorLeft; + +// Decalre monsters +static Monster lamp; +static Monster chair; +static Monster picture; +static Monster arc; + +static bool monsterHover = false; +static int monsterCheck = -1; // Identify checking monster + +static const char message[256] = "HAS LEGS BUT CAN NOT WALK...\nSEARCH FOR IT TO OPEN THE DOOR!"; +static int msgPosX = 100; + +static int msgState = 0; // 0-writting, 1-wait, 2-choose +static int lettersCounter = 0; +static char msgBuffer[256] = { '\0' }; +static int msgCounter = 0; + +static bool searching = false; + +static int scroll = 0; + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitAisle02Screen(void) +{ + ResetPlayer(); + + // Reset Screen variables + monsterHover = false; + monsterCheck = -1; + msgState = 0; + msgCounter = 0; + lettersCounter = 0; + for (int i = 0; i < 256; i++) msgBuffer[i] = '\0'; + + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/background_aisle02.png"); + + scroll = player.position.x - 200; + + // Initialize doors + doorLeft.position = (Vector2) { -10, 136 }; + doorLeft.facing = 0; + doorLeft.locked = true; + doorLeft.frameRec =(Rectangle) {((doors.width/3)*doorLeft.facing), doors.height/2, doors.width/3, doors.height/2}; + doorLeft.bound = (Rectangle) { doorLeft.position.x, doorLeft.position.y, doors.width/3, doors.height/2}; + doorLeft.selected = false; + + // Monster init: lamp + lamp.position = (Vector2){ 1520, 300 }; + lamp.texture = LoadTexture("resources/textures/monster_lamp_right.png"); + lamp.currentFrame = 0; + lamp.framesCounter = 0; + lamp.numFrames = 4; + lamp.bounds = (Rectangle){ lamp.position.x + 200, lamp.position.y, 90, 380 }; + lamp.frameRec = (Rectangle) { 0, 0, lamp.texture.width/lamp.numFrames, lamp.texture.height }; + lamp.selected = false; + lamp.active = false; + lamp.spooky = true; + + // Monster init: chair + chair.position = (Vector2){ 1400, 404 }; + chair.texture = LoadTexture("resources/textures/monster_chair_right.png"); + chair.currentFrame = 0; + chair.framesCounter = 0; + chair.numFrames = 4; + chair.bounds = (Rectangle){ chair.position.x + 50, chair.position.y + 30, 120, 190 }; + chair.frameRec = (Rectangle) { 0, 0, chair.texture.width/chair.numFrames, chair.texture.height }; + chair.selected = false; + chair.active = false; + chair.spooky = false; + + // Monster init: picture + picture.position = (Vector2){ 837, 162 }; + picture.texture = LoadTexture("resources/textures/monster_picture.png"); + picture.currentFrame = 0; + picture.framesCounter = 0; + picture.numFrames = 4; + picture.bounds = (Rectangle){ picture.position.x + 44, picture.position.y, 174, 264 }; + picture.frameRec = (Rectangle) { 0, 0, picture.texture.width/picture.numFrames, picture.texture.height }; + picture.selected = false; + picture.active = false; + picture.spooky = true; + + // Monster init: arc + arc.position = (Vector2){ 388, 423 }; + arc.texture = LoadTexture("resources/textures/monster_arc.png"); + arc.currentFrame = 0; + arc.framesCounter = 0; + arc.numFrames = 4; + arc.bounds = (Rectangle){ arc.position.x + 44, arc.position.y + 70, 220, 120 }; + arc.frameRec = (Rectangle) { 0, 0, arc.texture.width/arc.numFrames, arc.texture.height }; + arc.selected = false; + arc.active = false; + arc.spooky = true; +} + +// Gameplay Screen Update logic +void UpdateAisle02Screen(void) +{ + // Update doors bounds + doorLeft.bound.x = doorLeft.position.x - scroll; + + if (player.key) + { + // Door: left + if ((CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || + (CheckCollisionRecs(player.bounds, doorLeft.bound))) doorLeft.selected = true; + else doorLeft.selected = false; + + if ((doorLeft.selected) && (CheckCollisionRecs(player.bounds, doorLeft.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorLeft.locked) + { + doorLeft.frameRec.y = 0; + doorLeft.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 1; + } + } + } + + if (msgState > 2) + { + UpdatePlayer(); + + // Monsters logic + UpdateMonster(&lamp); + UpdateMonster(&chair); + UpdateMonster(&picture); + UpdateMonster(&arc); + } + + // Update monster bounds + lamp.bounds.x = lamp.position.x + 200 - scroll; + chair.bounds.x = chair.position.x + 50 - scroll; + picture.bounds.x = picture.position.x + 44 - scroll; + arc.bounds.x = arc.position.x + 44 - scroll; + + // Check player hover monsters to interact + if (((CheckCollisionRecs(player.bounds, lamp.bounds)) && !lamp.active) || + ((CheckCollisionRecs(player.bounds, chair.bounds)) && !chair.active) || + ((CheckCollisionRecs(player.bounds, picture.bounds)) && !picture.active) || + ((CheckCollisionRecs(player.bounds, arc.bounds)) && !arc.active)) monsterHover = true; + else monsterHover = false; + + + // Monters logic: lamp + if ((CheckCollisionRecs(player.bounds, lamp.bounds)) && !lamp.active) + { + lamp.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), lamp.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 1; + } + } + else lamp.selected = false; + + // Monters logic: chair + if ((CheckCollisionRecs(player.bounds, chair.bounds)) && !chair.active) + { + chair.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), chair.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 2; + } + } + else chair.selected = false; + + // Monters logic: picture + if ((CheckCollisionRecs(player.bounds, picture.bounds)) && !picture.active) + { + picture.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), picture.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 3; + } + } + else picture.selected = false; + + // Monters logic: arc + if ((CheckCollisionRecs(player.bounds, arc.bounds)) && !arc.active) + { + arc.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), arc.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 4; + } + } + else arc.selected = false; + + if (searching) + { + framesCounter++; + + if (framesCounter > 180) + { + if (monsterCheck == 1) + { + if (lamp.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + lamp.active = true; + lamp.selected = false; + } + else if (monsterCheck == 2) + { + if (chair.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + chair.active = true; + chair.selected = false; + } + else if (monsterCheck == 3) + { + if (picture.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + picture.active = true; + picture.selected = false; + } + else if (monsterCheck == 4) + { + if (arc.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + arc.active = true; + arc.selected = false; + } + + searching = false; + framesCounter = 0; + } + } + + // Text animation + framesCounter++; + + if ((framesCounter%2) == 0) lettersCounter++; + + if (msgState == 0) + { + if (lettersCounter <= (int)strlen(message)) strncpy(msgBuffer, message, lettersCounter); + else + { + for (int i = 0; i < (int)strlen(msgBuffer); i++) msgBuffer[i] = '\0'; + + lettersCounter = 0; + msgState = 1; + } + + if (IsKeyPressed(KEY_ENTER)) msgState = 1; + } + else if (msgState == 1) + { + msgCounter++; + + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + msgState = 2; + msgCounter = 0; + } + } + else if (msgState == 2) + { + msgCounter++; + + if (msgCounter > 180) msgState = 3; + } + else msgCounter++; + + if (player.position.x > 200) + { + scroll = player.position.x - 200; + + if (scroll > 620) scroll = 620; + } +} + +// Gameplay Screen Draw logic +void DrawAisle02Screen(void) +{ + DrawTexture(background, -scroll, 0, WHITE); + + // Draw monsters + DrawMonster(lamp, scroll); + DrawMonster(arc, scroll); + DrawMonster(picture, scroll); + DrawMonster(chair, scroll); + + // Draw door + Vector2 doorScrollPos = { doorLeft.position.x - scroll, doorLeft.position.y }; + + if (doorLeft.selected) DrawTextureRec(doors, doorLeft.frameRec, doorScrollPos, GREEN); + else DrawTextureRec(doors, doorLeft.frameRec, doorScrollPos, WHITE); + + // Draw messsages + if (msgState < 2) DrawRectangle(0, 40, GetScreenWidth(), 200, Fade(LIGHTGRAY, 0.5f)); + else if (msgState == 2) DrawRectangle(0, 80, GetScreenWidth(), 100, Fade(LIGHTGRAY, 0.5f)); + + if (msgState == 0) + { + DrawTextEx(font, msgBuffer, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + } + else if (msgState == 1) + { + DrawTextEx(font, message, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + + if ((msgCounter/30)%2) DrawText("PRESS ENTER or CLICK", GetScreenWidth() - 280, 200, 20, BLACK); + } + else if (msgState == 2) + { + if ((msgCounter/30)%2) + { + DrawTextEx(font, "CHOOSE WISELY!", (Vector2){ 300, 95 }, font.size*2, 2, WHITE); + + DrawRectangleRec(lamp.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(arc.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(chair.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(picture.bounds, Fade(RED, 0.6f)); + } + } + else + { + if ((monsterHover) && ((msgCounter/30)%2)) + { + DrawRectangle(0, 0, GetScreenWidth(), 50, Fade(LIGHTGRAY, 0.5f)); + DrawText("PRESS SPACE or CLICK to INTERACT", 420, 15, 20, BLACK); + } + } + + DrawPlayer(); // NOTE: Also draws mouse pointer! +} + +// Gameplay Screen Unload logic +void UnloadAisle02Screen(void) +{ + // TODO: Unload GAMEPLAY screen variables here! + UnloadTexture(background); + + UnloadMonster(lamp); + UnloadMonster(chair); + UnloadMonster(picture); + UnloadMonster(arc); +} + +// Gameplay Screen should finish? +int FinishAisle02Screen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_armory.c b/games/skully_escape/screens/screen_armory.c new file mode 100644 index 000000000..622299f0e --- /dev/null +++ b/games/skully_escape/screens/screen_armory.c @@ -0,0 +1,404 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" +#include "../player.h" +#include "../monster.h" + +#include + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; + +// Declare doors +static Door doorLeft; +static Door doorRight; + +// Decalre monsters +static Monster blazon01; +static Monster blazon02; +static Monster blazon03; + +static bool monsterHover = false; +static int monsterCheck = -1; // Identify checking monster + +static const char message[256] = "NO MORE TIPS...\nFOLLOW YOUR INSTINCT!"; +static int msgPosX = 100; + +static int msgState = 0; // 0-writting, 1-wait, 2-choose +static int lettersCounter = 0; +static char msgBuffer[256] = { '\0' }; +static int msgCounter = 0; + +static bool searching = false; + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitArmoryScreen(void) +{ + ResetPlayer(); + + // Reset Screen variables + monsterHover = false; + monsterCheck = -1; + msgState = 0; + msgCounter = 0; + lettersCounter = 0; + for (int i = 0; i < 256; i++) msgBuffer[i] = '\0'; + + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/background_armory.png"); + + // Initialize doors + doorLeft.position = (Vector2) { -50, 145 }; + doorLeft.facing = 0; + doorLeft.locked = true; + doorLeft.frameRec =(Rectangle) {((doors.width/3)*doorLeft.facing), doors.height/2, doors.width/3, doors.height/2}; + doorLeft.bound = (Rectangle) { doorLeft.position.x, doorLeft.position.y, doors.width/3, doors.height/2}; + doorLeft.selected = false; + + doorRight.position = (Vector2) { 1074, 140 }; + doorRight.facing = 2; + doorRight.locked = true; + doorRight.frameRec =(Rectangle) {((doors.width/3)*doorRight.facing), doors.height/2, doors.width/3, doors.height/2}; + doorRight.bound = (Rectangle) { doorRight.position.x, doorRight.position.y, doors.width/3, doors.height/2}; + doorRight.selected = false; + + // Monster init: blazon01 + blazon01.position = (Vector2){ 300, 260 }; + blazon01.texture = LoadTexture("resources/textures/monster_blazon01.png"); + blazon01.currentFrame = 0; + blazon01.framesCounter = 0; + blazon01.numFrames = 4; + blazon01.bounds = (Rectangle){ blazon01.position.x, blazon01.position.y + 20, 160, 230 }; + blazon01.frameRec = (Rectangle) { 0, 0, blazon01.texture.width/blazon01.numFrames, blazon01.texture.height }; + blazon01.selected = false; + blazon01.active = false; + blazon01.spooky = true; + + // Monster init: blazon02 + blazon02.position = (Vector2){ 550, 260 }; + blazon02.texture = LoadTexture("resources/textures/monster_blazon02.png"); + blazon02.currentFrame = 0; + blazon02.framesCounter = 0; + blazon02.numFrames = 4; + blazon02.bounds = (Rectangle){ blazon02.position.x, blazon02.position.y + 20, 160, 230 }; + blazon02.frameRec = (Rectangle) { 0, 0, blazon02.texture.width/blazon02.numFrames, blazon02.texture.height }; + blazon02.selected = false; + blazon02.active = false; + blazon02.spooky = true; + + // Monster init: blazon03 + blazon03.position = (Vector2){ 800, 260 }; + blazon03.texture = LoadTexture("resources/textures/monster_blazon03.png"); + blazon03.currentFrame = 0; + blazon03.framesCounter = 0; + blazon03.numFrames = 4; + blazon03.bounds = (Rectangle){ blazon03.position.x, blazon03.position.y + 20, 160, 230 }; + blazon03.frameRec = (Rectangle) { 0, 0, blazon03.texture.width/blazon03.numFrames, blazon03.texture.height }; + blazon03.selected = false; + blazon03.active = false; + blazon03.spooky = false; +} + +// Gameplay Screen Update logic +void UpdateArmoryScreen(void) +{ + if (player.key) + { + // Door: left + if ((CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || + (CheckCollisionRecs(player.bounds, doorLeft.bound))) doorLeft.selected = true; + else doorLeft.selected = false; + + if ((doorLeft.selected) && (CheckCollisionRecs(player.bounds, doorLeft.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorLeft.locked) + { + doorLeft.frameRec.y = 0; + doorLeft.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 1; + } + } + + // Door: right + if ((CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || + (CheckCollisionRecs(player.bounds, doorRight.bound))) doorRight.selected = true; + else doorRight.selected = false; + + if ((doorRight.selected) && (CheckCollisionRecs(player.bounds, doorRight.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorRight.locked) + { + doorRight.frameRec.y = 0; + doorRight.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 2; + } + } + } + + if (msgState > 2) + { + UpdatePlayer(); + + // Monsters logic + UpdateMonster(&blazon01); + UpdateMonster(&blazon02); + UpdateMonster(&blazon03); + } + + // Check player hover monsters to interact + if (((CheckCollisionRecs(player.bounds, blazon01.bounds)) && !blazon01.active) || + ((CheckCollisionRecs(player.bounds, blazon02.bounds)) && !blazon02.active) || + ((CheckCollisionRecs(player.bounds, blazon03.bounds)) && !blazon03.active)) monsterHover = true; + else monsterHover = false; + + // Monters logic: blazon01 + if ((CheckCollisionRecs(player.bounds, blazon01.bounds)) && !blazon01.active) + { + blazon01.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), blazon01.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 1; + } + } + else blazon01.selected = false; + + // Monters logic: blazon02 + if ((CheckCollisionRecs(player.bounds, blazon02.bounds)) && !blazon02.active) + { + blazon02.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), blazon02.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 2; + } + } + else blazon02.selected = false; + + // Monters logic: blazon03 + if ((CheckCollisionRecs(player.bounds, blazon03.bounds)) && !blazon03.active) + { + blazon03.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), blazon03.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 3; + } + } + else blazon03.selected = false; + + if (searching) + { + framesCounter++; + + if (framesCounter > 180) + { + if (monsterCheck == 1) + { + if (blazon01.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + blazon01.active = true; + blazon01.selected = false; + } + else if (monsterCheck == 2) + { + if (blazon02.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + blazon02.active = true; + blazon02.selected = false; + } + else if (monsterCheck == 3) + { + if (blazon03.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + blazon03.active = true; + blazon03.selected = false; + } + + searching = false; + framesCounter = 0; + } + } + + // Text animation + framesCounter++; + + if ((framesCounter%2) == 0) lettersCounter++; + + if (msgState == 0) + { + if (lettersCounter <= (int)strlen(message)) strncpy(msgBuffer, message, lettersCounter); + else + { + for (int i = 0; i < (int)strlen(msgBuffer); i++) msgBuffer[i] = '\0'; + + lettersCounter = 0; + msgState = 1; + } + + if (IsKeyPressed(KEY_ENTER)) msgState = 1; + } + else if (msgState == 1) + { + msgCounter++; + + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + msgState = 2; + msgCounter = 0; + } + } + else if (msgState == 2) + { + msgCounter++; + + if (msgCounter > 180) msgState = 3; + } + else msgCounter++; +} + +// Gameplay Screen Draw logic +void DrawArmoryScreen(void) +{ + DrawTexture(background, 0, 0, WHITE); + + // Draw monsters + DrawMonster(blazon01, 0); + DrawMonster(blazon02, 0); + DrawMonster(blazon03, 0); + + // Draw door + if (doorLeft.selected) DrawTextureRec(doors, doorLeft.frameRec, doorLeft.position, GREEN); + else DrawTextureRec(doors, doorLeft.frameRec, doorLeft.position, WHITE); + + if (doorRight.selected) DrawTextureRec(doors, doorRight.frameRec, doorRight.position, GREEN); + else DrawTextureRec(doors, doorRight.frameRec, doorRight.position, WHITE); + + // Draw messsages + if (msgState < 2) DrawRectangle(0, 40, GetScreenWidth(), 200, Fade(LIGHTGRAY, 0.5f)); + else if (msgState == 2) DrawRectangle(0, 80, GetScreenWidth(), 100, Fade(LIGHTGRAY, 0.5f)); + + if (msgState == 0) + { + DrawTextEx(font, msgBuffer, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + } + else if (msgState == 1) + { + DrawTextEx(font, message, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + + if ((msgCounter/30)%2) DrawText("PRESS ENTER or CLICK", GetScreenWidth() - 280, 200, 20, BLACK); + } + else if (msgState == 2) + { + if ((msgCounter/30)%2) + { + DrawTextEx(font, "CHOOSE WISELY!", (Vector2){ 300, 95 }, font.size*2, 2, WHITE); + + DrawRectangleRec(blazon01.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(blazon02.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(blazon03.bounds, Fade(RED, 0.6f)); + } + } + else + { + if ((monsterHover) && ((msgCounter/30)%2)) + { + DrawRectangle(0, 0, GetScreenWidth(), 50, Fade(LIGHTGRAY, 0.5f)); + DrawText("PRESS SPACE or CLICK to INTERACT", 420, 15, 20, BLACK); + } + } + + DrawPlayer(); // NOTE: Also draws mouse pointer! +} + +// Gameplay Screen Unload logic +void UnloadArmoryScreen(void) +{ + // TODO: Unload GAMEPLAY screen variables here! + UnloadTexture(background); + + UnloadMonster(blazon01); + UnloadMonster(blazon02); + UnloadMonster(blazon03); +} + +// Gameplay Screen should finish? +int FinishArmoryScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_attic.c b/games/skully_escape/screens/screen_attic.c new file mode 100644 index 000000000..a8bc0a6b8 --- /dev/null +++ b/games/skully_escape/screens/screen_attic.c @@ -0,0 +1,332 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" +#include "../player.h" +#include "../monster.h" + +#include + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; + +// Declare doors +static Door doorRight; + +// Decalre monsters +static Monster lamp; +static Monster arc; + +static bool monsterHover; +static int monsterCheck; // Identify checking monster + +static const char message[256] = "YOUR PARENTS ARE GONE! TIME TO ESCAPE!\nTHE DOOR IS LOCKED... TURN ON THE LIGHTS! ;)"; +static int msgPosX = 100; + +static int msgState = 0; // 0-writting, 1-wait, 2-choose +static int lettersCounter = 0; +static char msgBuffer[256] = { '\0' }; +static int msgCounter = 0; + +static bool searching = false; + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitAtticScreen(void) +{ + ResetPlayer(); + + // Reset Screen variables + monsterHover = false; + monsterCheck = -1; + msgState = 0; + msgCounter = 0; + lettersCounter = 0; + for (int i = 0; i < 256; i++) msgBuffer[i] = '\0'; + + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/background_attic.png"); + + // Initialize doors + doorRight.position = (Vector2) { 1074, 140 }; + doorRight.facing = 2; + doorRight.locked = true; + doorRight.frameRec =(Rectangle) {((doors.width/3)*doorRight.facing), doors.height/2, doors.width/3, doors.height/2}; + doorRight.bound = (Rectangle) { doorRight.position.x, doorRight.position.y, doors.width/3, doors.height/2}; + doorRight.selected = false; + + // Monster init: lamp + lamp.position = (Vector2){ 50, 316 }; + lamp.texture = LoadTexture("resources/textures/monster_lamp_left.png"); + lamp.currentFrame = 0; + lamp.framesCounter = 0; + lamp.numFrames = 4; + lamp.bounds = (Rectangle){ lamp.position.x + 20, lamp.position.y, 90, 380 }; + lamp.frameRec = (Rectangle) { 0, 0, lamp.texture.width/lamp.numFrames, lamp.texture.height }; + lamp.selected = false; + lamp.active = false; + lamp.spooky = false; + + // Monster init: arc + arc.position = (Vector2){ 760, 430 }; + arc.texture = LoadTexture("resources/textures/monster_arc.png"); + arc.currentFrame = 0; + arc.framesCounter = 0; + arc.numFrames = 4; + arc.bounds = (Rectangle){ arc.position.x + 44, arc.position.y + 70, 220, 120 }; + arc.frameRec = (Rectangle) { 0, 0, arc.texture.width/arc.numFrames, arc.texture.height }; + arc.selected = false; + arc.active = false; + arc.spooky = true; +} + +// Gameplay Screen Update logic +void UpdateAtticScreen(void) +{ + if (player.key) + { + // Door: right + if ((CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || + (CheckCollisionRecs(player.bounds, doorRight.bound))) doorRight.selected = true; + else doorRight.selected = false; + + if ((doorRight.selected) && (CheckCollisionRecs(player.bounds, doorRight.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorRight.locked) + { + doorRight.frameRec.y = 0; + doorRight.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 1; + } + } + } + + if (msgState > 2) + { + UpdatePlayer(); + + // Monsters logic + UpdateMonster(&lamp); + UpdateMonster(&arc); + } + + // Check player hover monsters to interact + if (((CheckCollisionRecs(player.bounds, lamp.bounds)) && !lamp.active) || + ((CheckCollisionRecs(player.bounds, arc.bounds)) && !arc.active)) monsterHover = true; + else monsterHover = false; + + // Monters logic: lamp + if ((CheckCollisionRecs(player.bounds, lamp.bounds)) && !lamp.active) + { + lamp.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), lamp.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 1; + } + } + else lamp.selected = false; + + // Monters logic: arc + if ((CheckCollisionRecs(player.bounds, arc.bounds)) && !arc.active) + { + arc.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), arc.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 2; + } + } + else arc.selected = false; + + if (searching) + { + framesCounter++; + + if (framesCounter > 180) + { + if (monsterCheck == 1) + { + if (lamp.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + lamp.active = true; + lamp.selected = false; + } + else if (monsterCheck == 2) + { + if (arc.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + arc.active = true; + arc.selected = false; + } + + searching = false; + framesCounter = 0; + } + } + + // Text animation + framesCounter++; + + if ((framesCounter%2) == 0) lettersCounter++; + + if (msgState == 0) + { + if (lettersCounter <= (int)strlen(message)) strncpy(msgBuffer, message, lettersCounter); + else + { + for (int i = 0; i < (int)strlen(msgBuffer); i++) msgBuffer[i] = '\0'; + + lettersCounter = 0; + msgState = 1; + } + + if (IsKeyPressed(KEY_ENTER)) msgState = 1; + } + else if (msgState == 1) + { + msgCounter++; + + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + msgState = 2; + msgCounter = 0; + } + } + else if (msgState == 2) + { + msgCounter++; + + if (msgCounter > 180) msgState = 3; + } + else msgCounter++; + + if (IsKeyPressed('M')) + { + finishScreen = 1; + } +} + +// Gameplay Screen Draw logic +void DrawAtticScreen(void) +{ + DrawTexture(background, 0, 0, WHITE); + + // Draw monsters + DrawMonster(lamp, 0); + DrawMonster(arc, 0); + + // Draw door + if (doorRight.selected) DrawTextureRec(doors, doorRight.frameRec, doorRight.position, GREEN); + else DrawTextureRec(doors, doorRight.frameRec, doorRight.position, WHITE); + + // Draw messsages + if (msgState < 2) DrawRectangle(0, 40, GetScreenWidth(), 200, Fade(LIGHTGRAY, 0.5f)); + else if (msgState == 2) DrawRectangle(0, 80, GetScreenWidth(), 100, Fade(LIGHTGRAY, 0.5f)); + + if (msgState == 0) + { + DrawTextEx(font, msgBuffer, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + } + else if (msgState == 1) + { + DrawTextEx(font, message, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + + if ((msgCounter/30)%2) DrawText("PRESS ENTER or CLICK", GetScreenWidth() - 280, 200, 20, BLACK); + } + else if (msgState == 2) + { + if ((msgCounter/30)%2) + { + DrawTextEx(font, "CHOOSE WISELY!", (Vector2){ 300, 95 }, font.size*2, 2, WHITE); + + DrawRectangleRec(lamp.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(arc.bounds, Fade(RED, 0.6f)); + } + } + else + { + if ((monsterHover) && ((msgCounter/30)%2)) + { + DrawRectangle(0, 0, GetScreenWidth(), 50, Fade(LIGHTGRAY, 0.5f)); + DrawText("PRESS SPACE or CLICK to INTERACT", 420, 15, 20, BLACK); + } + } + + DrawPlayer(); // NOTE: Also draws mouse pointer! +} + +// Gameplay Screen Unload logic +void UnloadAtticScreen(void) +{ + // TODO: Unload GAMEPLAY screen variables here! + UnloadTexture(background); + + UnloadMonster(lamp); + UnloadMonster(arc); +} + +// Gameplay Screen should finish? +int FinishAtticScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_bathroom.c b/games/skully_escape/screens/screen_bathroom.c new file mode 100644 index 000000000..176967a7b --- /dev/null +++ b/games/skully_escape/screens/screen_bathroom.c @@ -0,0 +1,383 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" +#include "../player.h" +#include "../monster.h" + +#include + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; + +// Declare doors +static Door doorRight; + +// Decalre monst +static Monster lamp; +static Monster chair; +static Monster mirror; + +static bool monsterHover = false; +static int monsterCheck = -1; // Identify checking monster + +static const char message[256] = "TRICK OR TREAT! WHO IS THE MOST BEAUTIFUL\nSKELETON IN THE WORLD?"; +static int msgPosX = 100; + +static int msgState = 0; // 0-writting, 1-wait, 2-choose +static int lettersCounter = 0; +static char msgBuffer[256] = { '\0' }; +static int msgCounter = 0; + +static bool searching = false; + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitBathroomScreen(void) +{ + ResetPlayer(); + + // Reset Screen variables + monsterHover = false; + monsterCheck = -1; + msgState = 0; + msgCounter = 0; + lettersCounter = 0; + for (int i = 0; i < 256; i++) msgBuffer[i] = '\0'; + + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/background_bathroom.png"); + + // Reset Screen variables + monsterHover = false; + monsterCheck = -1; + msgState = 0; + msgCounter = 0; + lettersCounter = 0; + for (int i = 0; i < 256; i++) msgBuffer[i] = '\0'; + + // Initialize doors + doorRight.position = (Vector2) { 1070, 135 }; + doorRight.facing = 2; + doorRight.locked = true; + doorRight.frameRec =(Rectangle) {((doors.width/3)*doorRight.facing), doors.height/2, doors.width/3, doors.height/2}; + doorRight.bound = (Rectangle) { doorRight.position.x, doorRight.position.y, doors.width/3, doors.height/2}; + doorRight.selected = false; + + // Monster init: lamp + lamp.position = (Vector2){ 35, 334 }; + lamp.texture = LoadTexture("resources/textures/monster_lamp_left.png"); + lamp.currentFrame = 0; + lamp.framesCounter = 0; + lamp.numFrames = 4; + lamp.bounds = (Rectangle){ lamp.position.x + 20, lamp.position.y + 0, 90, 380}; + lamp.frameRec = (Rectangle) { 0, 0, lamp.texture.width/lamp.numFrames, lamp.texture.height }; + lamp.selected = false; + lamp.active = false; + lamp.spooky = true; + + // Monster init: mirror + mirror.position = (Vector2){ 300, 200 }; + mirror.texture = LoadTexture("resources/textures/monster_mirror.png"); + mirror.currentFrame = 0; + mirror.framesCounter = 0; + mirror.numFrames = 4; + mirror.bounds = (Rectangle){ mirror.position.x + 40, mirror.position.y + 20, 190, 200 }; + mirror.frameRec = (Rectangle) { 0, 0, mirror.texture.width/mirror.numFrames, mirror.texture.height }; + mirror.selected = false; + mirror.active = false; + mirror.spooky = false; + + // Monster init: chair + chair.position = (Vector2){ 760, 430 }; + chair.texture = LoadTexture("resources/textures/monster_chair_right.png"); + chair.currentFrame = 0; + chair.framesCounter = 0; + chair.numFrames = 4; + chair.bounds = (Rectangle){ chair.position.x + 30, chair.position.y + 30, 120, 190 }; + chair.frameRec = (Rectangle) { 0, 0, chair.texture.width/chair.numFrames, chair.texture.height }; + chair.selected = false; + chair.active = false; + chair.spooky = true; +} + +// Gameplay Screen Update logic +void UpdateBathroomScreen(void) +{ + if (player.key) + { + // Door: right + if ((CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || + (CheckCollisionRecs(player.bounds, doorRight.bound))) doorRight.selected = true; + else doorRight.selected = false; + + if ((doorRight.selected) && (CheckCollisionRecs(player.bounds, doorRight.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorRight.locked) + { + doorRight.frameRec.y = 0; + doorRight.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 1; + } + } + } + + if (msgState > 2) + { + UpdatePlayer(); + + // Monsters logic + UpdateMonster(&lamp); + UpdateMonster(&mirror); + UpdateMonster(&chair); + } + + // Check player hover monsters to interact + if (((CheckCollisionRecs(player.bounds, lamp.bounds)) && !lamp.active) || + ((CheckCollisionRecs(player.bounds, mirror.bounds)) && !mirror.active) || + ((CheckCollisionRecs(player.bounds, chair.bounds)) && !chair.active)) monsterHover = true; + else monsterHover = false; + + + // Monters logic: lamp + if ((CheckCollisionRecs(player.bounds, lamp.bounds)) && !lamp.active) + { + lamp.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), lamp.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 1; + } + } + else lamp.selected = false; + + // Monters logic: mirror + if ((CheckCollisionRecs(player.bounds, mirror.bounds)) && !mirror.active) + { + mirror.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), mirror.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 2; + } + } + else mirror.selected = false; + + // Monters logic: chair + if ((CheckCollisionRecs(player.bounds, chair.bounds)) && !chair.active) + { + chair.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), chair.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 3; + } + } + else chair.selected = false; + + if (searching) + { + framesCounter++; + + if (framesCounter > 180) + { + if (monsterCheck == 1) + { + if (lamp.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + lamp.active = true; + lamp.selected = false; + } + else if (monsterCheck == 2) + { + if (mirror.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + mirror.active = true; + mirror.selected = false; + } + else if (monsterCheck == 3) + { + if (chair.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + chair.active = true; + chair.selected = false; + } + + searching = false; + framesCounter = 0; + } + } + + // Text animation + framesCounter++; + + if ((framesCounter%2) == 0) lettersCounter++; + + if (msgState == 0) + { + if (lettersCounter <= (int)strlen(message)) strncpy(msgBuffer, message, lettersCounter); + else + { + for (int i = 0; i < (int)strlen(msgBuffer); i++) msgBuffer[i] = '\0'; + + lettersCounter = 0; + msgState = 1; + } + + if (IsKeyPressed(KEY_ENTER)) msgState = 1; + } + else if (msgState == 1) + { + msgCounter++; + + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + msgState = 2; + msgCounter = 0; + } + } + else if (msgState == 2) + { + msgCounter++; + + if (msgCounter > 180) msgState = 3; + } + else msgCounter++; +} + +// Gameplay Screen Draw logic +void DrawBathroomScreen(void) +{ + DrawTexture(background, 0, 0, WHITE); + + // Draw monsters + DrawMonster(lamp, 0); + DrawMonster(mirror, 0); + DrawMonster(chair, 0); + + // Draw door + if (doorRight.selected) DrawTextureRec(doors, doorRight.frameRec, doorRight.position, GREEN); + else DrawTextureRec(doors, doorRight.frameRec, doorRight.position, WHITE); + + // Draw messsages + if (msgState < 2) DrawRectangle(0, 40, GetScreenWidth(), 200, Fade(LIGHTGRAY, 0.5f)); + else if (msgState == 2) DrawRectangle(0, 80, GetScreenWidth(), 100, Fade(LIGHTGRAY, 0.5f)); + + if (msgState == 0) + { + DrawTextEx(font, msgBuffer, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + } + else if (msgState == 1) + { + DrawTextEx(font, message, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + + if ((msgCounter/30)%2) DrawText("PRESS ENTER or CLICK", GetScreenWidth() - 280, 200, 20, BLACK); + } + else if (msgState == 2) + { + if ((msgCounter/30)%2) + { + DrawTextEx(font, "CHOOSE WISELY!", (Vector2){ 300, 95 }, font.size*2, 2, WHITE); + + DrawRectangleRec(lamp.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(mirror.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(chair.bounds, Fade(RED, 0.6f)); + } + } + else + { + if ((monsterHover) && ((msgCounter/30)%2)) + { + DrawRectangle(0, 0, GetScreenWidth(), 50, Fade(LIGHTGRAY, 0.5f)); + DrawText("PRESS SPACE or CLICK to INTERACT", 420, 15, 20, BLACK); + } + } + + DrawPlayer(); // NOTE: Also draws mouse pointer! +} + +// Gameplay Screen Unload logic +void UnloadBathroomScreen(void) +{ + // TODO: Unload GAMEPLAY screen variables here! + UnloadTexture(background); + + UnloadMonster(lamp); + UnloadMonster(chair); + UnloadMonster(mirror); +} + +// Gameplay Screen should finish? +int FinishBathroomScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_ending.c b/games/skully_escape/screens/screen_ending.c new file mode 100644 index 000000000..120d9071f --- /dev/null +++ b/games/skully_escape/screens/screen_ending.c @@ -0,0 +1,90 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Ending Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Ending screen global variables +static int framesCounter; +static int finishScreen; + +static float alpha = 0.0f; + +//---------------------------------------------------------------------------------- +// Ending Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Ending Screen Initialization logic +void InitEndingScreen(void) +{ + // TODO: Initialize ENDING screen variables here! + framesCounter = 0; + finishScreen = 0; + alpha = 0.0f; +} + +// Ending Screen Update logic +void UpdateEndingScreen(void) +{ + // TODO: Update ENDING screen variables here! + framesCounter++; + + alpha += 0.005f; + + if (alpha >= 1.0f) alpha = 1.0f; + + // Press enter to change to ATTIC screen + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + finishScreen = 1; + } +} + +// Ending Screen Draw logic +void DrawEndingScreen(void) +{ + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), DARKGRAY); + + DrawTextEx(font, "CONGRATULATIONS!", (Vector2){ 50, 160 }, font.size*3, 2, Fade(WHITE, alpha)); + DrawTextEx(font, "SKULLY ESCAPED!", (Vector2){ 100, 300 }, font.size*3, 2, Fade(WHITE, alpha)); + + if ((framesCounter > 180) && ((framesCounter/40)%2)) DrawText("PRESS ENTER or CLICK", 380, 545, 40, BLACK); +} + +// Ending Screen Unload logic +void UnloadEndingScreen(void) +{ + // TODO: Unload ENDING screen variables here! +} + +// Ending Screen should finish? +int FinishEndingScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_kitchen.c b/games/skully_escape/screens/screen_kitchen.c new file mode 100644 index 000000000..a6b8924d0 --- /dev/null +++ b/games/skully_escape/screens/screen_kitchen.c @@ -0,0 +1,403 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" +#include "../player.h" +#include "../monster.h" + +#include + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; + +// Declare doors +static Door doorLeft; +static Door doorRight; + +// Decalre monsters +static Monster closet; +static Monster chair; +static Monster window; + +static bool monsterHover = false; +static int monsterCheck = -1; // Identify checking monster + +static const char message[256] = "QUITE BORING AROUND...\nANY BETTER ENTERTAINING?"; +static int msgPosX = 100; + +static int msgState = 0; // 0-writting, 1-wait, 2-choose +static int lettersCounter = 0; +static char msgBuffer[256] = { '\0' }; +static int msgCounter = 0; + +static bool searching = false; + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitKitchenScreen(void) +{ + ResetPlayer(); + + // Reset Screen variables + monsterHover = false; + monsterCheck = -1; + msgState = 0; + msgCounter = 0; + lettersCounter = 0; + for (int i = 0; i < 256; i++) msgBuffer[i] = '\0'; + + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/background_kitchen.png"); + + // Initialize doors + doorLeft.position = (Vector2) { -45, 136 }; + doorLeft.facing = 0; + doorLeft.locked = true; + doorLeft.frameRec =(Rectangle) {((doors.width/3)*doorLeft.facing), doors.height/2, doors.width/3, doors.height/2}; + doorLeft.bound = (Rectangle) { doorLeft.position.x, doorLeft.position.y, doors.width/3, doors.height/2}; + doorLeft.selected = false; + + doorRight.position = (Vector2) { 1090, 148 }; + doorRight.facing = 2; + doorRight.locked = true; + doorRight.frameRec =(Rectangle) {((doors.width/3)*doorRight.facing), doors.height/2, doors.width/3, doors.height/2}; + doorRight.bound = (Rectangle) { doorRight.position.x, doorRight.position.y, doors.width/3, doors.height/2}; + doorRight.selected = false; + + // Monster init: lamp + closet.position = (Vector2){ 280, 260 }; + closet.texture = LoadTexture("resources/textures/monster_closet.png"); + closet.currentFrame = 0; + closet.framesCounter = 0; + closet.numFrames = 4; + closet.bounds = (Rectangle){ closet.position.x + 100, closet.position.y+25, 272,348 }; + closet.frameRec = (Rectangle) { 0, 0, closet.texture.width/closet.numFrames, closet.texture.height }; + closet.selected = false; + closet.active = false; + closet.spooky = true; + + // Monster init: chair + chair.position = (Vector2){ 230, 410 }; + chair.texture = LoadTexture("resources/textures/monster_chair_left.png"); + chair.currentFrame = 0; + chair.framesCounter = 0; + chair.numFrames = 4; + chair.bounds = (Rectangle){ chair.position.x + 30, chair.position.y + 60, 100, 160 }; + chair.frameRec = (Rectangle) { 0, 0, chair.texture.width/chair.numFrames, chair.texture.height }; + chair.selected = false; + chair.active = false; + chair.spooky = true; + + // Monster init: window + window.position = (Vector2){ 715, 88 }; + window.texture = LoadTexture("resources/textures/monster_window.png"); + window.currentFrame = 0; + window.framesCounter = 0; + window.numFrames = 4; + window.bounds = (Rectangle){ window.position.x + 100, window.position.y + 10, 200, 370 }; + window.frameRec = (Rectangle) { 0, 0, window.texture.width/window.numFrames, window.texture.height }; + window.selected = false; + window.active = false; + window.spooky = false; +} + +// Gameplay Screen Update logic +void UpdateKitchenScreen(void) +{ + if (player.key) + { + // Door: left + if ((CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || + (CheckCollisionRecs(player.bounds, doorLeft.bound))) doorLeft.selected = true; + else doorLeft.selected = false; + + if ((doorLeft.selected) && (CheckCollisionRecs(player.bounds, doorLeft.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorLeft.locked) + { + doorLeft.frameRec.y = 0; + doorLeft.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 1; + } + } + + // Door: right + if ((CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || + (CheckCollisionRecs(player.bounds, doorRight.bound))) doorRight.selected = true; + else doorRight.selected = false; + + if ((doorRight.selected) && (CheckCollisionRecs(player.bounds, doorRight.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorRight.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorRight.locked) + { + doorRight.frameRec.y = 0; + doorRight.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 2; + } + } + } + + if (msgState > 2) + { + UpdatePlayer(); + + // Monsters logic + UpdateMonster(&closet); + UpdateMonster(&chair); + UpdateMonster(&window); + } + + // Check player hover monsters to interact + if (((CheckCollisionRecs(player.bounds, closet.bounds)) && !closet.active) || + ((CheckCollisionRecs(player.bounds, window.bounds)) && !window.active)) monsterHover = true; + else monsterHover = false; + + // Monters logic: closet + if ((CheckCollisionRecs(player.bounds, closet.bounds)) && !closet.active) + { + closet.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), closet.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 1; + } + } + else closet.selected = false; + + // Monters logic: chair + if ((CheckCollisionRecs(player.bounds, chair.bounds)) && !chair.active) + { + chair.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), chair.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 2; + } + } + else chair.selected = false; + + // Monters logic: window + if ((CheckCollisionRecs(player.bounds, window.bounds)) && !window.active) + { + window.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), window.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 3; + } + } + else window.selected = false; + + if (searching) + { + framesCounter++; + + if (framesCounter > 180) + { + if (monsterCheck == 1) + { + if (closet.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + closet.active = true; + closet.selected = false; + } + else if (monsterCheck == 2) + { + if (chair.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + chair.active = true; + chair.selected = false; + } + else if (monsterCheck == 3) + { + if (window.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + window.active = true; + window.selected = false; + } + + searching = false; + framesCounter = 0; + } + } + + // Text animation + framesCounter++; + + if ((framesCounter%2) == 0) lettersCounter++; + + if (msgState == 0) + { + if (lettersCounter <= (int)strlen(message)) strncpy(msgBuffer, message, lettersCounter); + else + { + for (int i = 0; i < (int)strlen(msgBuffer); i++) msgBuffer[i] = '\0'; + + lettersCounter = 0; + msgState = 1; + } + + if (IsKeyPressed(KEY_ENTER)) msgState = 1; + } + else if (msgState == 1) + { + msgCounter++; + + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + msgState = 2; + msgCounter = 0; + } + } + else if (msgState == 2) + { + msgCounter++; + + if (msgCounter > 180) msgState = 3; + } + else msgCounter++; +} + +// Gameplay Screen Draw logic +void DrawKitchenScreen(void) +{ + DrawTexture(background, 0, 0, WHITE); + + // Draw monsters + DrawMonster(closet, 0); + DrawMonster(chair, 0); + DrawMonster(window, 0); + + // Draw door + if (doorRight.selected) DrawTextureRec(doors, doorRight.frameRec, doorRight.position, GREEN); + else DrawTextureRec(doors, doorRight.frameRec, doorRight.position, WHITE); + + if (doorLeft.selected) DrawTextureRec(doors, doorLeft.frameRec, doorLeft.position, GREEN); + else DrawTextureRec(doors, doorLeft.frameRec, doorLeft.position, WHITE); + + // Draw messsages + if (msgState < 2) DrawRectangle(0, 40, GetScreenWidth(), 200, Fade(LIGHTGRAY, 0.5f)); + else if (msgState == 2) DrawRectangle(0, 80, GetScreenWidth(), 100, Fade(LIGHTGRAY, 0.5f)); + + if (msgState == 0) + { + DrawTextEx(font, msgBuffer, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + } + else if (msgState == 1) + { + DrawTextEx(font, message, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + + if ((msgCounter/30)%2) DrawText("PRESS ENTER or CLICK", GetScreenWidth() - 280, 200, 20, BLACK); + } + else if (msgState == 2) + { + if ((msgCounter/30)%2) + { + DrawTextEx(font, "CHOOSE WISELY!", (Vector2){ 300, 95 }, font.size*2, 2, WHITE); + + DrawRectangleRec(closet.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(window.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(chair.bounds, Fade(RED, 0.6f)); + } + } + else + { + if ((monsterHover) && ((msgCounter/30)%2)) + { + DrawRectangle(0, 0, GetScreenWidth(), 50, Fade(LIGHTGRAY, 0.5f)); + DrawText("PRESS SPACE or CLICK to INTERACT", 420, 15, 20, BLACK); + } + } + + DrawPlayer(); // NOTE: Also draws mouse pointer! +} + +// Gameplay Screen Unload logic +void UnloadKitchenScreen(void) +{ + // TODO: Unload GAMEPLAY screen variables here! + UnloadTexture(background); + + UnloadMonster(closet); + UnloadMonster(chair); + UnloadMonster(window); +} + +// Gameplay Screen should finish? +int FinishKitchenScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_livingroom.c b/games/skully_escape/screens/screen_livingroom.c new file mode 100644 index 000000000..b2b09d9a8 --- /dev/null +++ b/games/skully_escape/screens/screen_livingroom.c @@ -0,0 +1,403 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" +#include "../player.h" +#include "../monster.h" + +#include + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; + +// Declare doors +static Door doorCenter; +static Door doorLeft; + +// Decalre monsters +static Monster candle; +static Monster picture; +static Monster phone; + +static bool monsterHover = false; +static int monsterCheck = -1; // Identify checking monster + +static const char message[256] = "WHEN WIND BLOWS, IT KNOWS THE DIRECTION\nLET IT GUIDE YOU!"; +static int msgPosX = 100; + +static int msgState = 0; // 0-writting, 1-wait, 2-choose +static int lettersCounter = 0; +static char msgBuffer[256] = { '\0' }; +static int msgCounter = 0; + +static bool searching = false; + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitLivingroomScreen(void) +{ + ResetPlayer(); + + // Reset Screen variables + monsterHover = false; + monsterCheck = -1; + msgState = 0; + msgCounter = 0; + lettersCounter = 0; + for (int i = 0; i < 256; i++) msgBuffer[i] = '\0'; + + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/background_livingroom.png"); + + // Initialize doors + doorLeft.position = (Vector2) { -45, 140}; + doorLeft.facing = 0; + doorLeft.locked = true; + doorLeft.frameRec =(Rectangle) {((doors.width/3)*doorLeft.facing), doors.height/2, doors.width/3, doors.height/2}; + doorLeft.bound = (Rectangle) { doorLeft.position.x, doorLeft.position.y, doors.width/3, doors.height/2}; + doorLeft.selected = false; + + doorCenter.position = (Vector2) { 830, 108 }; + doorCenter.facing = 1; + doorCenter.locked = true; + doorCenter.frameRec =(Rectangle) {((doors.width/3)*doorCenter.facing), doors.height/2, doors.width/3, doors.height/2}; + doorCenter.bound = (Rectangle) { doorCenter.position.x, doorCenter.position.y, doors.width/3, doors.height/2}; + doorCenter.selected = false; + + // Monster init: lamp + candle.position = (Vector2){ 154, 256 }; + candle.texture = LoadTexture("resources/textures/monster_candle.png"); + candle.currentFrame = 0; + candle.framesCounter = 0; + candle.numFrames = 4; + candle.bounds = (Rectangle){ candle.position.x + 90, candle.position.y + 30, 185, 340 }; + candle.frameRec = (Rectangle) { 0, 0, candle.texture.width/candle.numFrames, candle.texture.height }; + candle.selected = false; + candle.active = false; + candle.spooky = false; + + // Monster init: arc + picture.position = (Vector2){ 504, 164 }; + picture.texture = LoadTexture("resources/textures/monster_picture.png"); + picture.currentFrame = 0; + picture.framesCounter = 0; + picture.numFrames = 4; + picture.bounds = (Rectangle){ picture.position.x + 44, picture.position.y, 174, 264 }; + picture.frameRec = (Rectangle) { 0, 0, picture.texture.width/picture.numFrames, picture.texture.height }; + picture.selected = false; + picture.active = false; + picture.spooky = true; + + // Monster init: phone + phone.position = (Vector2){ 1054, 404 }; + phone.texture = LoadTexture("resources/textures/monster_phone.png"); + phone.currentFrame = 0; + phone.framesCounter = 0; + phone.numFrames = 4; + phone.bounds = (Rectangle){ phone.position.x + 64, phone.position.y +120, 100, 160 }; + phone.frameRec = (Rectangle) { 0, 0, phone.texture.width/phone.numFrames, phone.texture.height }; + phone.selected = false; + phone.active = false; + phone.spooky = true; +} + +// Gameplay Screen Update logic +void UpdateLivingroomScreen(void) +{ + if (player.key) + { + // Door: left + if ((CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || + (CheckCollisionRecs(player.bounds, doorLeft.bound))) doorLeft.selected = true; + else doorLeft.selected = false; + + if ((doorLeft.selected) && (CheckCollisionRecs(player.bounds, doorLeft.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorLeft.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorLeft.locked) + { + doorLeft.frameRec.y = 0; + doorLeft.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 1; + } + } + + // Door: center + if ((CheckCollisionPointRec(GetMousePosition(), doorCenter.bound)) || + (CheckCollisionRecs(player.bounds, doorCenter.bound))) doorCenter.selected = true; + else doorCenter.selected = false; + + if ((doorCenter.selected) && (CheckCollisionRecs(player.bounds, doorCenter.bound))) + { + if (((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && CheckCollisionPointRec(GetMousePosition(), doorCenter.bound)) || (IsKeyPressed(KEY_SPACE))) + { + if (doorCenter.locked) + { + doorCenter.frameRec.y = 0; + doorCenter.locked = false; + PlaySound(sndDoor); + } + else finishScreen = 2; + } + } + } + + if (msgState > 2) + { + UpdatePlayer(); + + // Monsters logic + UpdateMonster(&candle); + UpdateMonster(&picture); + UpdateMonster(&phone); + } + + // Check player hover monsters to interact + if (((CheckCollisionRecs(player.bounds, candle.bounds)) && !candle.active) || + ((CheckCollisionRecs(player.bounds, picture.bounds)) && !picture.active) || + ((CheckCollisionRecs(player.bounds, phone.bounds)) && !phone.active)) monsterHover = true; + else monsterHover = false; + + // Monters logic: candle + if ((CheckCollisionRecs(player.bounds, candle.bounds)) && !candle.active) + { + candle.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), candle.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 1; + } + } + else candle.selected = false; + + // Monters logic: picture + if ((CheckCollisionRecs(player.bounds, picture.bounds)) && !picture.active) + { + picture.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), picture.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 2; + } + } + else picture.selected = false; + + // Monters logic: phone + if ((CheckCollisionRecs(player.bounds, phone.bounds)) && !phone.active) + { + phone.selected = true; + + if ((IsKeyPressed(KEY_SPACE)) || + ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) && (CheckCollisionPointRec(GetMousePosition(), phone.bounds)))) + { + SearchKeyPlayer(); + searching = true; + framesCounter = 0; + + monsterCheck = 3; + } + } + else phone.selected = false; + + if (searching) + { + framesCounter++; + + if (framesCounter > 180) + { + if (monsterCheck == 1) + { + if (candle.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + candle.active = true; + candle.selected = false; + } + else if (monsterCheck == 2) + { + if (picture.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + picture.active = true; + picture.selected = false; + } + else if (monsterCheck == 3) + { + if (phone.spooky) + { + ScarePlayer(); + PlaySound(sndScream); + } + else FindKeyPlayer(); + + phone.active = true; + phone.selected = false; + } + + searching = false; + framesCounter = 0; + } + } + + // Text animation + framesCounter++; + + if ((framesCounter%2) == 0) lettersCounter++; + + if (msgState == 0) + { + if (lettersCounter <= (int)strlen(message)) strncpy(msgBuffer, message, lettersCounter); + else + { + for (int i = 0; i < (int)strlen(msgBuffer); i++) msgBuffer[i] = '\0'; + + lettersCounter = 0; + msgState = 1; + } + + if (IsKeyPressed(KEY_ENTER)) msgState = 1; + } + else if (msgState == 1) + { + msgCounter++; + + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + msgState = 2; + msgCounter = 0; + } + } + else if (msgState == 2) + { + msgCounter++; + + if (msgCounter > 180) msgState = 3; + } + else msgCounter++; +} + +// Gameplay Screen Draw logic +void DrawLivingroomScreen(void) +{ + DrawTexture(background, 0, 0, WHITE); + + // Draw monsters + DrawMonster(picture, 0); + DrawMonster(candle, 0); + DrawMonster(phone, 0); + + // Draw door + if (doorCenter.selected) DrawTextureRec(doors, doorCenter.frameRec, doorCenter.position, GREEN); + else DrawTextureRec(doors, doorCenter.frameRec, doorCenter.position, WHITE); + if (doorLeft.selected) DrawTextureRec(doors, doorLeft.frameRec, doorLeft.position, GREEN); + else DrawTextureRec(doors, doorLeft.frameRec, doorLeft.position, WHITE); + + // Draw messsages + if (msgState < 2) DrawRectangle(0, 40, GetScreenWidth(), 200, Fade(LIGHTGRAY, 0.5f)); + else if (msgState == 2) DrawRectangle(0, 80, GetScreenWidth(), 100, Fade(LIGHTGRAY, 0.5f)); + + if (msgState == 0) + { + DrawTextEx(font, msgBuffer, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + } + else if (msgState == 1) + { + DrawTextEx(font, message, (Vector2){ msgPosX, 80 }, font.size, 2, WHITE); + + if ((msgCounter/30)%2) DrawText("PRESS ENTER or CLICK", GetScreenWidth() - 280, 200, 20, BLACK); + } + else if (msgState == 2) + { + if ((msgCounter/30)%2) + { + DrawTextEx(font, "CHOOSE WISELY!", (Vector2){ 300, 95 }, font.size*2, 2, WHITE); + + DrawRectangleRec(candle.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(phone.bounds, Fade(RED, 0.6f)); + DrawRectangleRec(picture.bounds, Fade(RED, 0.6f)); + } + } + else + { + if ((monsterHover) && ((msgCounter/30)%2)) + { + DrawRectangle(0, 0, GetScreenWidth(), 50, Fade(LIGHTGRAY, 0.5f)); + DrawText("PRESS SPACE or CLICK to INTERACT", 420, 15, 20, BLACK); + } + } + + DrawPlayer(); // NOTE: Also draws mouse pointer! +} + +// Gameplay Screen Unload logic +void UnloadLivingroomScreen(void) +{ + // TODO: Unload GAMEPLAY screen variables here! + UnloadTexture(background); + + UnloadMonster(candle); + UnloadMonster(picture); + UnloadMonster(phone); +} + +// Gameplay Screen should finish? +int FinishLivingroomScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_logo.c b/games/skully_escape/screens/screen_logo.c new file mode 100644 index 000000000..f07f5f544 --- /dev/null +++ b/games/skully_escape/screens/screen_logo.c @@ -0,0 +1,108 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Logo Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Logo screen global variables +static int framesCounter = 0; +static int finishScreen; + +static Texture2D logo; +static float logoAlpha = 0; + +static int state = 0; + +//---------------------------------------------------------------------------------- +// Logo Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Logo Screen Initialization logic +void InitLogoScreen(void) +{ + // Initialize LOGO screen variables here! + finishScreen = 0; + + logo = LoadTexture("resources/textures/skully_logo.png"); +} + +// Logo Screen Update logic +void UpdateLogoScreen(void) +{ + // Update LOGO screen variables here! + if (state == 0) + { + logoAlpha += 0.04f; + + if (logoAlpha >= 1.0f) state = 1; + } + else if (state == 1) + { + framesCounter++; + + if (framesCounter > 180) state = 2; + } + else if (state == 2) + { + logoAlpha -= 0.04f; + + if (logoAlpha <= 0.0f) + { + framesCounter = 0; + state = 3; + } + } + else if (state == 3) + { + finishScreen = 1; + } +} + +// Logo Screen Draw logic +void DrawLogoScreen(void) +{ + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), RAYWHITE); + + DrawTexture(logo, GetScreenWidth()/2 - logo.width/2, 130, Fade(WHITE, logoAlpha)); + + DrawText("GRAY TEAM", 340, 450, 100, Fade(DARKGRAY, logoAlpha)); +} + +// Logo Screen Unload logic +void UnloadLogoScreen(void) +{ + // Unload LOGO screen variables here! + UnloadTexture(logo); +} + +// Logo Screen should finish? +int FinishLogoScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_logo_raylib.c b/games/skully_escape/screens/screen_logo_raylib.c new file mode 100644 index 000000000..e5efe8435 --- /dev/null +++ b/games/skully_escape/screens/screen_logo_raylib.c @@ -0,0 +1,201 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Logo Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +#define LOGO_RECS_SIDE 16 + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Logo screen global variables +static int framesCounter = 0; +static int finishScreen; + +static int logoPositionX; +static int logoPositionY; + +static int lettersCount = 0; + +static int topSideRecWidth = LOGO_RECS_SIDE; +static int leftSideRecHeight = LOGO_RECS_SIDE; + +static int bottomSideRecWidth = LOGO_RECS_SIDE; +static int rightSideRecHeight = LOGO_RECS_SIDE; + +static char raylib[8]; // raylib text array, max 8 letters +static int state = 0; // Tracking animation states (State Machine) +static float alpha = 1.0f; // Useful for fading + +//---------------------------------------------------------------------------------- +// Logo Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Logo Screen Initialization logic +void rlInitLogoScreen(void) +{ + // TODO: Initialize LOGO screen variables here! + finishScreen = 0; + + logoPositionX = GetScreenWidth()/2 - 128; + logoPositionY = GetScreenHeight()/2 - 128; + + for (int i = 0; i < 8; i++) raylib[i] = '\0'; +} + +// Logo Screen Update logic +void rlUpdateLogoScreen(void) +{ + // Update LOGO screen variables here! + if (state == 0) // State 0: Small box blinking + { + framesCounter++; + + if (framesCounter == 80) + { + state = 1; + framesCounter = 0; // Reset counter... will be used later... + } + } + else if (state == 1) // State 1: Top and left bars growing + { + topSideRecWidth += 8; + leftSideRecHeight += 8; + + if (topSideRecWidth == 256) state = 2; + } + else if (state == 2) // State 2: Bottom and right bars growing + { + bottomSideRecWidth += 8; + rightSideRecHeight += 8; + + if (bottomSideRecWidth == 256) state = 3; + } + else if (state == 3) // State 3: Letters appearing (one by one) + { + framesCounter++; + + if (framesCounter/10) // Every 12 frames, one more letter! + { + lettersCount++; + framesCounter = 0; + } + + switch (lettersCount) + { + case 1: raylib[0] = 'r'; break; + case 2: raylib[1] = 'a'; break; + case 3: raylib[2] = 'y'; break; + case 4: raylib[3] = 'l'; break; + case 5: raylib[4] = 'i'; break; + case 6: raylib[5] = 'b'; break; + default: break; + } + + // When all letters have appeared... + if (lettersCount >= 10) + { + state = 4; + framesCounter = 0; + } + } + else if (state == 4) + { + framesCounter++; + + if (framesCounter > 100) + { + alpha -= 0.02f; + + if (alpha <= 0.0f) + { + alpha = 0.0f; + finishScreen = 1; + } + } + } +} + +// Logo Screen Draw logic +void rlDrawLogoScreen(void) +{ + if (state == 0) + { + if ((framesCounter/10)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK); + } + else if (state == 1) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); + DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); + } + else if (state == 2) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); + DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); + + DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK); + } + else if (state == 3) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); + + DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); + + DrawRectangle(GetScreenWidth()/2 - 112, GetScreenHeight()/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); + + DrawText(raylib, GetScreenWidth()/2 - 44, GetScreenHeight()/2 + 48, 50, Fade(BLACK, alpha)); + } + else if (state == 4) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); + + DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); + + DrawRectangle(GetScreenWidth()/2 - 112, GetScreenHeight()/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); + + DrawText(raylib, GetScreenWidth()/2 - 44, GetScreenHeight()/2 + 48, 50, Fade(BLACK, alpha)); + + if (framesCounter > 20) DrawText("powered by", logoPositionX, logoPositionY - 27, 20, Fade(DARKGRAY, alpha)); + } +} + +// Logo Screen Unload logic +void rlUnloadLogoScreen(void) +{ + // TODO: Unload LOGO screen variables here! +} + +// Logo Screen should finish? +int rlFinishLogoScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screen_title.c b/games/skully_escape/screens/screen_title.c new file mode 100644 index 000000000..837b5112e --- /dev/null +++ b/games/skully_escape/screens/screen_title.c @@ -0,0 +1,92 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Title Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Title screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D title; +static float titleAlpha = 0.0f; + +//---------------------------------------------------------------------------------- +// Title Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Title Screen Initialization logic +void InitTitleScreen(void) +{ + // Initialize TITLE screen variables here! + framesCounter = 0; + finishScreen = 0; + + title = LoadTexture("resources/textures/title.png"); +} + +// Title Screen Update logic +void UpdateTitleScreen(void) +{ + // Update TITLE screen variables here! + framesCounter++; + + titleAlpha += 0.005f; + + if (titleAlpha >= 1.0f) titleAlpha = 1.0f; + + // Press enter to change to ATTIC screen + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + finishScreen = 1; + } +} + +// Title Screen Draw logic +void DrawTitleScreen(void) +{ + //DrawText("TITLE SCREEN", 100, 100, 140, Fade(BLACK, titleAlpha)); + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), DARKGRAY); + DrawTexture(title, GetScreenWidth()/2 - title.width/2, 20, Fade(WHITE, titleAlpha)); + + if ((framesCounter > 180) && ((framesCounter/40)%2)) DrawText("PRESS ENTER to START", 380, 545, 40, BLACK); +} + +// Title Screen Unload logic +void UnloadTitleScreen(void) +{ + // Unload TITLE screen variables here! + UnloadTexture(title); +} + +// Title Screen should finish? +int FinishTitleScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/skully_escape/screens/screens.h b/games/skully_escape/screens/screens.h new file mode 100644 index 000000000..790df9ff8 --- /dev/null +++ b/games/skully_escape/screens/screens.h @@ -0,0 +1,164 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Screens Functions Declarations (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef SCREENS_H +#define SCREENS_H + +#define PLAYER_ANIM_FRAMES 7 +#define PLAYER_ANIM_SEQ 2 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum GameScreen { LOGO = 0, LOGO_RL, TITLE, ATTIC, AISLE01, AISLE02, BATHROOM, LIVINGROOM, KITCHEN, ARMORY, ENDING } GameScreen; + +typedef struct Door { + Vector2 position; + int facing; + bool locked; + bool selected; + Rectangle frameRec; + Rectangle bound; +} Door; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +GameScreen currentScreen; +SpriteFont font; + +Texture2D doors; +Sound sndDoor; +Sound sndScream; + + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Logo Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitLogoScreen(void); +void UpdateLogoScreen(void); +void DrawLogoScreen(void); +void UnloadLogoScreen(void); +int FinishLogoScreen(void); + +//---------------------------------------------------------------------------------- +// raylib Logo Screen Functions Declaration +//---------------------------------------------------------------------------------- +void rlInitLogoScreen(void); +void rlUpdateLogoScreen(void); +void rlDrawLogoScreen(void); +void rlUnloadLogoScreen(void); +int rlFinishLogoScreen(void); + +//---------------------------------------------------------------------------------- +// Title Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitTitleScreen(void); +void UpdateTitleScreen(void); +void DrawTitleScreen(void); +void UnloadTitleScreen(void); +int FinishTitleScreen(void); + +//---------------------------------------------------------------------------------- +// Attic Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitAtticScreen(void); +void UpdateAtticScreen(void); +void DrawAtticScreen(void); +void UnloadAtticScreen(void); +int FinishAtticScreen(void); + +//---------------------------------------------------------------------------------- +// Aisle01 Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitAisle01Screen(void); +void UpdateAisle01Screen(void); +void DrawAisle01Screen(void); +void UnloadAisle01Screen(void); +int FinishAisle01Screen(void); + +//---------------------------------------------------------------------------------- +// Aisle02 Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitAisle02Screen(void); +void UpdateAisle02Screen(void); +void DrawAisle02Screen(void); +void UnloadAisle02Screen(void); +int FinishAisle02Screen(void); + +//---------------------------------------------------------------------------------- +// Bathroom Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitBathroomScreen(void); +void UpdateBathroomScreen(void); +void DrawBathroomScreen(void); +void UnloadBathroomScreen(void); +int FinishBathroomScreen(void); + +//---------------------------------------------------------------------------------- +// Livingroom Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitLivingroomScreen(void); +void UpdateLivingroomScreen(void); +void DrawLivingroomScreen(void); +void UnloadLivingroomScreen(void); +int FinishLivingroomScreen(void); + +//---------------------------------------------------------------------------------- +// Kitchen Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitKitchenScreen(void); +void UpdateKitchenScreen(void); +void DrawKitchenScreen(void); +void UnloadKitchenScreen(void); +int FinishKitchenScreen(void); + +//---------------------------------------------------------------------------------- +// Armory Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitArmoryScreen(void); +void UpdateArmoryScreen(void); +void DrawArmoryScreen(void); +void UnloadArmoryScreen(void); +int FinishArmoryScreen(void); + +//---------------------------------------------------------------------------------- +// Ending Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitEndingScreen(void); +void UpdateEndingScreen(void); +void DrawEndingScreen(void); +void UnloadEndingScreen(void); +int FinishEndingScreen(void); + +#ifdef __cplusplus +} +#endif + +#endif // SCREENS_H \ No newline at end of file diff --git a/games/skully_escape/skully_escape.c b/games/skully_escape/skully_escape.c new file mode 100644 index 000000000..22cc04e4d --- /dev/null +++ b/games/skully_escape/skully_escape.c @@ -0,0 +1,403 @@ +/******************************************************************************************* +* +* SKULLY ESCAPE [KING GAME JAM 2015] +* +* This game has been created using raylib (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +********************************************************************************************/ + +#include "raylib.h" +#include "screens/screens.h" // NOTE: Defines global variable: currentScreen + +#include "player.h" + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- +const int screenWidth = 1280; +const int screenHeight = 720; + +// Required variables to manage screen transitions (fade-in, fade-out) +float transAlpha = 0; +bool onTransition = false; +bool transFadeOut = false; +int transFromScreen = -1; +int transToScreen = -1; + +static int framesCounter = 0; + +//---------------------------------------------------------------------------------- +// Local Functions Declaration +//---------------------------------------------------------------------------------- +void TransitionToScreen(int screen); +void ChangeToScreen(int screen); // No transition effect +void UpdateTransition(void); +void DrawTransition(void); + +void UpdateDrawFrame(void); // Update and Draw one frame + +//---------------------------------------------------------------------------------- +// Main entry point +//---------------------------------------------------------------------------------- +int main(void) +{ + // Initialization + //--------------------------------------------------------- + const char windowTitle[30] = "SKULLY ESCAPE [KING GAMEJAM]"; + + InitWindow(screenWidth, screenHeight, windowTitle); + + // Global data loading (assets that must be available in all screens, i.e. fonts) + InitAudioDevice(); + + PlayMusicStream("resources/audio/come_play_with_me.ogg"); + + font = LoadSpriteFont("resources/textures/alagard.png"); + doors = LoadTexture("resources/textures/doors.png"); + sndDoor = LoadSound("resources/audio/door.ogg"); + sndScream = LoadSound("resources/audio/scream.ogg"); + + InitPlayer(); + + // Setup and Init first screen + currentScreen = LOGO; + InitLogoScreen(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + UpdateDrawFrame(); + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + + // Unload all global loaded data (i.e. fonts) here! + UnloadPlayer(); + UnloadSpriteFont(font); + UnloadTexture(doors); + UnloadSound(sndDoor); + UnloadSound(sndScream); + + CloseAudioDevice(); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +void TransitionToScreen(int screen) +{ + onTransition = true; + transFromScreen = currentScreen; + transToScreen = screen; +} + +void ChangeToScreen(int screen) +{ + switch (currentScreen) + { + case LOGO: UnloadLogoScreen(); break; + case LOGO_RL: rlUnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case ATTIC: UnloadAtticScreen(); break; + case AISLE01: UnloadAisle01Screen();break; + case AISLE02: UnloadAisle02Screen();break; + case ARMORY: UnloadArmoryScreen();break; + case LIVINGROOM: UnloadLivingroomScreen();break; + case KITCHEN: UnloadKitchenScreen(); break; + case BATHROOM: UnloadBathroomScreen(); break; + case ENDING: UnloadEndingScreen(); break; + default: break; + } + + switch (screen) + { + case LOGO: InitLogoScreen(); break; + case LOGO_RL: rlInitLogoScreen(); break; + case TITLE: InitTitleScreen(); break; + case ATTIC: InitAtticScreen(); break; + case AISLE01: InitAisle01Screen();break; + case AISLE02: InitAisle02Screen();break; + case ARMORY: InitArmoryScreen();break; + case LIVINGROOM: InitLivingroomScreen();break; + case KITCHEN: InitKitchenScreen(); break; + case BATHROOM: InitBathroomScreen(); break; + case ENDING: InitEndingScreen(); break; + default: break; + } + + currentScreen = screen; +} + +void UpdateTransition(void) +{ + if (!transFadeOut) + { + transAlpha += 0.05f; + + if (transAlpha >= 1.0) + { + transAlpha = 1.0; + + switch (transFromScreen) + { + case LOGO: UnloadLogoScreen(); break; + case LOGO_RL: rlUnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case ATTIC: UnloadAtticScreen(); break; + case AISLE01: UnloadAisle01Screen();break; + case AISLE02: UnloadAisle02Screen();break; + case ARMORY: UnloadArmoryScreen();break; + case LIVINGROOM: UnloadLivingroomScreen();break; + case KITCHEN: UnloadKitchenScreen(); break; + case BATHROOM: UnloadBathroomScreen(); break; + case ENDING: UnloadEndingScreen(); break; + default: break; + } + + switch (transToScreen) + { + case LOGO: + { + InitLogoScreen(); + currentScreen = LOGO; + } break; + case LOGO_RL: + { + rlInitLogoScreen(); + currentScreen = LOGO_RL; + } break; + case TITLE: + { + InitTitleScreen(); + currentScreen = TITLE; + } break; + case ATTIC: + { + InitAtticScreen(); + currentScreen = ATTIC; + } break; + case AISLE01: + { + InitAisle01Screen(); + currentScreen = AISLE01; + } break; + case AISLE02: + { + InitAisle02Screen(); + currentScreen = AISLE02; + } break; + case BATHROOM: + { + InitBathroomScreen(); + currentScreen = BATHROOM; + } break; + case LIVINGROOM: + { + InitLivingroomScreen(); + currentScreen = LIVINGROOM; + } break; + case KITCHEN: + { + InitKitchenScreen(); + currentScreen = KITCHEN; + } break; + case ARMORY: + { + InitArmoryScreen(); + currentScreen = ARMORY; + } break; + case ENDING: + { + InitEndingScreen(); + currentScreen = ENDING; + } break; + default: break; + } + + transFadeOut = true; + } + } + else // Transition fade out logic + { + transAlpha -= 0.05f; + + if (transAlpha <= 0) + { + transAlpha = 0; + transFadeOut = false; + onTransition = false; + transFromScreen = -1; + transToScreen = -1; + } + } +} + +void DrawTransition(void) +{ + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, transAlpha)); +} + +// Update and draw game frame +void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + if (!onTransition) + { + if (player.dead) + { + framesCounter++; + + if (framesCounter > 80) + { + framesCounter = 0; + player.dead = false; + player.numLifes = 4; + + TransitionToScreen(TITLE); + } + } + + switch(currentScreen) + { + case LOGO: + { + UpdateLogoScreen(); + + if (FinishLogoScreen()) ChangeToScreen(LOGO_RL); + + } break; + case LOGO_RL: + { + rlUpdateLogoScreen(); + + if (rlFinishLogoScreen()) TransitionToScreen(TITLE); + + } break; + case TITLE: + { + UpdateTitleScreen(); + + if (FinishTitleScreen() == 1) TransitionToScreen(ATTIC); + + } break; + case ATTIC: + { + UpdateAtticScreen(); + + if (FinishAtticScreen() == 1) TransitionToScreen(AISLE01); + + } break; + case AISLE01: + { + UpdateAisle01Screen(); + + if (FinishAisle01Screen() == 1) TransitionToScreen(BATHROOM); + else if(FinishAisle01Screen() == 2) TransitionToScreen(KITCHEN); + else if(FinishAisle01Screen() == 3) TransitionToScreen(LIVINGROOM); + + } break; + case BATHROOM: + { + UpdateBathroomScreen(); + + if (FinishBathroomScreen() == 1) TransitionToScreen(AISLE01); + + } break; + case LIVINGROOM: + { + UpdateLivingroomScreen(); + + if (FinishLivingroomScreen() == 1) TransitionToScreen(AISLE01); + else if(FinishLivingroomScreen() == 2)TransitionToScreen(AISLE02); + + } break; + case AISLE02: + { + UpdateAisle02Screen(); + + if (FinishAisle02Screen() == 1) TransitionToScreen(KITCHEN); + + } break; + case KITCHEN: + { + UpdateKitchenScreen(); + + if (FinishKitchenScreen() == 1) TransitionToScreen(ARMORY); + else if(FinishKitchenScreen() == 2)TransitionToScreen(AISLE02); + + } break; + case ARMORY: + { + UpdateArmoryScreen(); + + if(FinishArmoryScreen() == 1) TransitionToScreen(ENDING); + else if(FinishArmoryScreen() == 2) TransitionToScreen(KITCHEN); + + } break; + case ENDING: + { + UpdateEndingScreen(); + + if (FinishEndingScreen()) TransitionToScreen(TITLE); + + } break; + default: break; + } + } + else + { + // Update transition (fade-in, fade-out) + UpdateTransition(); + } + + UpdateMusicStream(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + switch(currentScreen) + { + case LOGO: DrawLogoScreen(); break; + case LOGO_RL: rlDrawLogoScreen(); break; + case TITLE: DrawTitleScreen(); break; + case ATTIC: DrawAtticScreen(); break; + case AISLE01: DrawAisle01Screen();break; + case AISLE02: DrawAisle02Screen();break; + case BATHROOM: DrawBathroomScreen();break; + case LIVINGROOM: DrawLivingroomScreen();break; + case KITCHEN: DrawKitchenScreen();break; + case ARMORY: DrawArmoryScreen();break; + case ENDING: DrawEndingScreen(); break; + default: break; + } + + if (onTransition) DrawTransition(); + + //DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} + diff --git a/games/snake.c b/games/snake.c new file mode 100644 index 000000000..ac2f61323 --- /dev/null +++ b/games/snake.c @@ -0,0 +1,293 @@ +/******************************************************************************************* +* +* raylib - sample game: snake +* +* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define SNAKE_LENGTH 256 +#define SQUARE_SIZE 31 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct Snake { + Vector2 position; + Vector2 size; + Vector2 speed; + Color color; +} Snake; + +typedef struct Food { + Vector2 position; + Vector2 size; + bool active; + Color color; +} Food; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter; +static bool gameOver; +static bool pause; + +static Food fruit; +static Snake snake[SNAKE_LENGTH]; +static Vector2 snakePosition[SNAKE_LENGTH]; +static bool allowMove; +static Vector2 offset; +static int counterTail; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: snake"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +void InitGame(void) +{ + framesCounter = 0; + gameOver = false; + pause = false; + + counterTail = 1; + allowMove = false; + + offset.x = screenWidth%SQUARE_SIZE; + offset.y = screenHeight%SQUARE_SIZE; + + for (int i = 0; i < SNAKE_LENGTH; i++) + { + snake[i].position = (Vector2){ offset.x/2, offset.y/2 }; + snake[i].size = (Vector2){ SQUARE_SIZE, SQUARE_SIZE }; + snake[i].speed = (Vector2){ SQUARE_SIZE, 0 }; + + if (i == 0) snake[i].color = DARKBLUE; + else snake[i].color = BLUE; + } + + for (int i = 0; i < SNAKE_LENGTH; i++) + { + snakePosition[i] = (Vector2){ 0.0f, 0.0f }; + } + + fruit.size = (Vector2){ SQUARE_SIZE, SQUARE_SIZE }; + fruit.color = SKYBLUE; + fruit.active = false; +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + // control + if (IsKeyPressed(KEY_RIGHT) && (snake[0].speed.x == 0) && allowMove) + { + snake[0].speed = (Vector2){ SQUARE_SIZE, 0 }; + allowMove = false; + } + if (IsKeyPressed(KEY_LEFT) && (snake[0].speed.x == 0) && allowMove) + { + snake[0].speed = (Vector2){ -SQUARE_SIZE, 0 }; + allowMove = false; + } + if (IsKeyPressed(KEY_UP) && (snake[0].speed.y == 0) && allowMove) + { + snake[0].speed = (Vector2){ 0, -SQUARE_SIZE }; + allowMove = false; + } + if (IsKeyPressed(KEY_DOWN) && (snake[0].speed.y == 0) && allowMove) + { + snake[0].speed = (Vector2){ 0, SQUARE_SIZE }; + allowMove = false; + } + + // movement + for (int i = 0; i < counterTail; i++) snakePosition[i] = snake[i].position; + + if ((framesCounter%5) == 0) + { + for (int i = 0; i < counterTail; i++) + { + if (i == 0) + { + snake[0].position.x += snake[0].speed.x; + snake[0].position.y += snake[0].speed.y; + allowMove = true; + } + else snake[i].position = snakePosition[i-1]; + } + } + + // wall behaviour + if (((snake[0].position.x) > (screenWidth - offset.x)) || + ((snake[0].position.y) > (screenHeight - offset.y)) || + (snake[0].position.x < 0) || (snake[0].position.y < 0)) + { + gameOver = true; + } + + // collision with yourself + for (int i = 1; i < counterTail; i++) + { + if ((snake[0].position.x == snake[i].position.x) && (snake[0].position.y == snake[i].position.y)) gameOver = true; + } + + // TODO: review logic: fruit.position calculation + if (!fruit.active) + { + fruit.active = true; + fruit.position = (Vector2){ GetRandomValue(0, (screenWidth/SQUARE_SIZE) - 1)*SQUARE_SIZE + offset.x/2, GetRandomValue(0, (screenHeight/SQUARE_SIZE) - 1)*SQUARE_SIZE + offset.y/2 }; + + for (int i = 0; i < counterTail; i++) + { + while ((fruit.position.x == snake[i].position.x) && (fruit.position.y == snake[i].position.y)) + { + fruit.position = (Vector2){ GetRandomValue(0, (screenWidth/SQUARE_SIZE) - 1)*SQUARE_SIZE, GetRandomValue(0, (screenHeight/SQUARE_SIZE) - 1)*SQUARE_SIZE }; + i = 0; + } + } + } + + // collision + if (CheckCollisionRecs((Rectangle){(int)snake[0].position.x, (int)snake[0].position.y, (int)snake[0].size.x, (int)snake[0].size.y}, + (Rectangle){(int)fruit.position.x, (int)fruit.position.y, (int)fruit.size.x, (int)fruit.size.y})) + { + snake[counterTail].position = snakePosition[counterTail - 1]; + counterTail += 1; + fruit.active = false; + } + + framesCounter++; + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + // Draw grid lines + for (int i = 0; i < screenWidth/SQUARE_SIZE + 1; i++) + { + DrawLineV((Vector2){SQUARE_SIZE*i + offset.x/2, offset.y/2}, (Vector2){SQUARE_SIZE*i + offset.x/2, screenHeight - offset.y/2}, LIGHTGRAY); + } + + for (int i = 0; i < screenHeight/SQUARE_SIZE + 1; i++) + { + DrawLineV((Vector2){offset.x/2, SQUARE_SIZE*i + offset.y/2}, (Vector2){screenWidth - offset.x/2, SQUARE_SIZE*i + offset.y/2}, LIGHTGRAY); + } + + // Draw snake + for (int i = 0; i < counterTail; i++) DrawRectangleV(snake[i].position, snake[i].size, snake[i].color); + + // Draw fruit to pick + DrawRectangleV(fruit.position, fruit.size, fruit.color); + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} \ No newline at end of file diff --git a/games/space_invaders.c b/games/space_invaders.c new file mode 100644 index 000000000..c2dd0c61e --- /dev/null +++ b/games/space_invaders.c @@ -0,0 +1,406 @@ +/******************************************************************************************* +* +* raylib - sample game: space invaders +* +* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define NUM_SHOOTS 50 +#define NUM_MAX_ENEMIES 50 +#define FIRST_WAVE 10 +#define SECOND_WAVE 20 +#define THIRD_WAVE 50 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum { FIRST = 0, SECOND, THIRD } EnemyWave; + +typedef struct Player{ + Rectangle rec; + Vector2 speed; + Color color; +} Player; + +typedef struct Enemy{ + Rectangle rec; + Vector2 speed; + bool active; + Color color; +} Enemy; + +typedef struct Shoot{ + Rectangle rec; + Vector2 speed; + bool active; + Color color; +} Shoot; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static int framesCounter; +static bool gameOver; +static bool pause; +static int score; +static bool victory; + +static Player player; +static Enemy enemy[NUM_MAX_ENEMIES]; +static Shoot shoot[NUM_SHOOTS]; +static EnemyWave wave; + +static int shootRate; +static float alpha; + +static int activeEnemies; +static int enemiesKill; +static bool smooth; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: space invaders"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Initialize game variables +void InitGame(void) +{ + // Initialize game variables + shootRate = 0; + pause = false; + gameOver = false; + victory = false; + smooth = false; + wave = FIRST; + activeEnemies = FIRST_WAVE; + enemiesKill = 0; + score = 0; + alpha = 0; + + // Initialize player + player.rec.x = 20; + player.rec.y = 50; + player.rec.width = 20; + player.rec.height = 20; + player.speed.x = 5; + player.speed.y = 5; + player.color = BLACK; + + // Initialize enemies + for (int i = 0; i < NUM_MAX_ENEMIES; i++) + { + enemy[i].rec.width = 10; + enemy[i].rec.height = 10; + enemy[i].rec.x = GetRandomValue(screenWidth, screenWidth + 1000); + enemy[i].rec.y = GetRandomValue(0, screenHeight - enemy[i].rec.height); + enemy[i].speed.x = 5; + enemy[i].speed.y = 5; + enemy[i].active = true; + enemy[i].color = GRAY; + } + + // Initialize shoots + for (int i = 0; i < NUM_SHOOTS; i++) + { + shoot[i].rec.x = player.rec.x; + shoot[i].rec.y = player.rec.y + player.rec.height/4; + shoot[i].rec.width = 10; + shoot[i].rec.height = 5; + shoot[i].speed.x = 7; + shoot[i].speed.y = 0; + shoot[i].active = false; + shoot[i].color = MAROON; + } +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + switch (wave) + { + case FIRST: + { + if (!smooth) + { + alpha += 0.02f; + + if (alpha >= 1.0f) smooth = true; + } + + if (smooth) alpha -= 0.02f; + + if (enemiesKill == activeEnemies) + { + enemiesKill = 0; + + for (int i = 0; i < activeEnemies; i++) + { + if (!enemy[i].active) enemy[i].active = true; + } + + activeEnemies = SECOND_WAVE; + wave = SECOND; + smooth = false; + alpha = 0.0f; + } + } break; + case SECOND: + { + if (!smooth) + { + alpha += 0.02f; + + if (alpha >= 1.0f) smooth = true; + } + + if (smooth) alpha -= 0.02f; + + if (enemiesKill == activeEnemies) + { + enemiesKill = 0; + + for (int i = 0; i < activeEnemies; i++) + { + if (!enemy[i].active) enemy[i].active = true; + } + + activeEnemies = THIRD_WAVE; + wave = THIRD; + smooth = false; + alpha = 0.0f; + } + } break; + case THIRD: + { + if (!smooth) + { + alpha += 0.02f; + + if (alpha >= 1.0f) smooth = true; + } + + if (smooth) alpha -= 0.02f; + + if (enemiesKill == activeEnemies) victory = true; + + } break; + default: break; + } + + // Player movement + if (IsKeyDown(KEY_RIGHT)) player.rec.x += player.speed.x; + if (IsKeyDown(KEY_LEFT)) player.rec.x -= player.speed.x; + if (IsKeyDown(KEY_UP)) player.rec.y -= player.speed.y; + if (IsKeyDown(KEY_DOWN)) player.rec.y += player.speed.y; + + // Player collision with enemy + for (int i = 0; i < activeEnemies; i++) + { + if (CheckCollisionRecs(player.rec, enemy[i].rec)) gameOver = true; + } + + // Enemy behaviour + for (int i = 0; i < activeEnemies; i++) + { + if (enemy[i].active) + { + enemy[i].rec.x -= enemy[i].speed.x; + + if (enemy[i].rec.x < 0) + { + enemy[i].rec.x = GetRandomValue(screenWidth, screenWidth + 1000); + enemy[i].rec.y = GetRandomValue(0, screenHeight - enemy[i].rec.height); + } + } + } + + // Wall behaviour + if (player.rec.x <= 0) player.rec.x = 0; + if (player.rec.x + player.rec.width >= screenWidth) player.rec.x = screenWidth - player.rec.width; + if (player.rec.y <= 0) player.rec.y = 0; + if (player.rec.y + player.rec.height >= screenHeight) player.rec.y = screenHeight - player.rec.height; + + //Shoot initialization + if (IsKeyDown(KEY_SPACE)) + { + shootRate += 5; + + for (int i = 0; i < NUM_SHOOTS; i++) + { + if (!shoot[i].active && shootRate%20 == 0) + { + shoot[i].rec.x = player.rec.x; + shoot[i].rec.y = player.rec.y + player.rec.height/4; + shoot[i].active = true; + break; + } + } + } + + // Shoot logic + for (int i = 0; i < NUM_SHOOTS; i++) + { + if (shoot[i].active) + { + // Movement + shoot[i].rec.x += shoot[i].speed.x; + + // Collision with enemy + for (int j = 0; j < activeEnemies; j++) + { + if (enemy[j].active) + { + if (CheckCollisionRecs(shoot[i].rec, enemy[j].rec)) + { + shoot[i].active = false; + enemy[j].rec.x = GetRandomValue(screenWidth, screenWidth + 1000); + enemy[j].rec.y = GetRandomValue(0, screenHeight - enemy[j].rec.height); + shootRate = 0; + enemiesKill++; + score += 100; + } + + if (shoot[i].rec.x + shoot[i].rec.width >= screenWidth) + { + shoot[i].active = false; + shootRate = 0; + } + } + } + } + } + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + DrawRectangleRec(player.rec, player.color); + + if (wave == FIRST) DrawText("FIRST WAVE", screenWidth/2 - MeasureText("FIRST WAVE", 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha)); + else if (wave == SECOND) DrawText("SECOND WAVE", screenWidth/2 - MeasureText("SECOND WAVE", 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha)); + else if (wave == THIRD) DrawText("THIRD WAVE", screenWidth/2 - MeasureText("THIRD WAVE", 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha)); + + for (int i = 0; i < activeEnemies; i++) + { + if (enemy[i].active) DrawRectangleRec(enemy[i].rec, enemy[i].color); + } + + for (int i = 0; i < NUM_SHOOTS; i++) + { + if (shoot[i].active) DrawRectangleRec(shoot[i].rec, shoot[i].color); + } + + DrawText(FormatText("%04i", score), 20, 20, 40, GRAY); + + if (victory) DrawText("YOU WIN", screenWidth/2 - MeasureText("YOU WIN", 40)/2, screenHeight/2 - 40, 40, BLACK); + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} \ No newline at end of file diff --git a/games/tetris.c b/games/tetris.c new file mode 100644 index 000000000..62400201f --- /dev/null +++ b/games/tetris.c @@ -0,0 +1,836 @@ +/******************************************************************************************* +* +* raylib - sample game: tetris +* +* Sample game Marc Palau and Ramon Santamaria +* +* This game has been created using raylib v1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include +#include +#include +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Some Defines +//---------------------------------------------------------------------------------- +#define SQUARE_SIZE 20 + +#define GRID_HORIZONTAL_SIZE 12 +#define GRID_VERTICAL_SIZE 20 + +#define LATERAL_SPEED 10 +#define TURNING_SPEED 12 +#define FAST_FALL_AWAIT_COUNTER 30 + +#define FADING_TIME 33 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum GridSquare { EMPTY, MOVING, FULL, BLOCK, FADING } GridSquare; + +//------------------------------------------------------------------------------------ +// Global Variables Declaration +//------------------------------------------------------------------------------------ +static int screenWidth = 800; +static int screenHeight = 450; + +static bool gameOver = false; +static bool pause = false; + +// Matrices +static GridSquare grid [GRID_HORIZONTAL_SIZE][GRID_VERTICAL_SIZE]; +static GridSquare piece [4][4]; +static GridSquare incomingPiece [4][4]; + +// Theese variables keep track of the active piece position +static int piecePositionX = 0; +static int piecePositionY = 0; + +// Game parameters +static Color fadingColor; +//static int fallingSpeed; // In frames + +static bool beginPlay = true; // This var is only true at the begining of the game, used for the first matrix creations +static bool pieceActive = false; +static bool detection = false; +static bool lineToDelete = false; + +// Statistics +static int level = 1; +static int lines = 0; + +// Counters +static int gravityMovementCounter = 0; +static int lateralMovementCounter = 0; +static int turnMovementCounter = 0; +static int fastFallMovementCounter = 0; + +static int fadeLineCounter = 0; + +// Based on level +static int gravitySpeed = 30; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static void InitGame(void); // Initialize game +static void UpdateGame(void); // Update game (one frame) +static void DrawGame(void); // Draw game (one frame) +static void UnloadGame(void); // Unload game +static void UpdateDrawFrame(void); // Update and Draw (one frame) + +// Additional module functions +static bool Createpiece(); +static void GetRandompiece(); +static void ResolveFallingMovement(); +static bool ResolveLateralMovement(); +static bool ResolveTurnMovement(); +static void CheckDetection(); +static void CheckCompletition(); +static void DeleteCompleteLines(); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "sample game: tetris"); + + InitGame(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateGame(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + DrawGame(); + //---------------------------------------------------------------------------------- + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadGame(); // Unload loaded data (textures, sounds, models...) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//-------------------------------------------------------------------------------------- +// Game Module Functions Definition +//-------------------------------------------------------------------------------------- + +// Initialize game variables +void InitGame(void) +{ + // Initialize game statistics + level = 1; + lines = 0; + + fadingColor = GRAY; + + piecePositionX = 0; + piecePositionY = 0; + + pause = false; + + beginPlay = true; + pieceActive = false; + detection = false; + lineToDelete = false; + + // Counters + gravityMovementCounter = 0; + lateralMovementCounter = 0; + turnMovementCounter = 0; + fastFallMovementCounter = 0; + + fadeLineCounter = 0; + gravitySpeed = 30; + + // Initialize grid matrices + for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++) + { + for (int j = 0; j < GRID_VERTICAL_SIZE; j++) + { + if ((j == GRID_VERTICAL_SIZE - 1) || (i == 0) || (i == GRID_HORIZONTAL_SIZE - 1)) grid[i][j] = BLOCK; + else grid[i][j] = EMPTY; + } + } + + // Initialize incoming piece matrices + for (int i = 0; i < 4; i++) + { + for (int j = 0; j< 4; j++) + { + incomingPiece[i][j] = EMPTY; + } + } +} + +// Update game (one frame) +void UpdateGame(void) +{ + if (!gameOver) + { + if (IsKeyPressed('P')) pause = !pause; + + if (!pause) + { + if (!lineToDelete) + { + if (!pieceActive) + { + // Get another piece + pieceActive = Createpiece(); + + // We leave a little time before starting the fast falling down + fastFallMovementCounter = 0; + } + else // Piece falling + { + // Counters update + fastFallMovementCounter++; + gravityMovementCounter++; + lateralMovementCounter++; + turnMovementCounter++; + + // We make sure to move if we've pressed the key this frame + if (IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_RIGHT)) lateralMovementCounter = LATERAL_SPEED; + if (IsKeyPressed(KEY_UP)) turnMovementCounter = TURNING_SPEED; + + // Fall down + if (IsKeyDown(KEY_DOWN) && (fastFallMovementCounter >= FAST_FALL_AWAIT_COUNTER)) + { + // We make sure the piece is going to fall this frame + gravityMovementCounter += gravitySpeed; + } + + if (gravityMovementCounter >= gravitySpeed) + { + // Basic falling movement + CheckDetection(&detection); + + // Check if the piece has collided with another piece or with the boundings + ResolveFallingMovement(&detection, &pieceActive); + + // Check if we fullfilled a line and if so, erase the line and pull down the the lines above + CheckCompletition(&lineToDelete); + + gravityMovementCounter = 0; + } + + // Move laterally at player's will + if (lateralMovementCounter >= LATERAL_SPEED) + { + // Update the lateral movement and if success, reset the lateral counter + if (!ResolveLateralMovement()) lateralMovementCounter = 0; + } + + // Turn the piece at player's will + if (turnMovementCounter >= TURNING_SPEED) + { + // Update the turning movement and reset the turning counter + if (ResolveTurnMovement()) turnMovementCounter = 0; + } + } + + // Game over logic + for (int j = 0; j < 2; j++) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == FULL) + { + gameOver = true; + } + } + } + } + else + { + // Animation when deleting lines + fadeLineCounter++; + + if (fadeLineCounter%8 < 4) fadingColor = MAROON; + else fadingColor = GRAY; + + if (fadeLineCounter >= FADING_TIME) + { + DeleteCompleteLines(); + fadeLineCounter = 0; + lineToDelete = false; + + lines++; + } + } + } + } + else + { + if (IsKeyPressed(KEY_ENTER)) + { + InitGame(); + gameOver = false; + } + } +} + +// Draw game (one frame) +void DrawGame(void) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (!gameOver) + { + // Draw gameplay area + Vector2 offset; + offset.x = screenWidth/2 - (GRID_HORIZONTAL_SIZE*SQUARE_SIZE/2) - 50; + offset.y = screenHeight/2 - ((GRID_VERTICAL_SIZE - 1)*SQUARE_SIZE/2) + SQUARE_SIZE*2; + + offset.y -= 50; // NOTE: Harcoded position! + + int controller = offset.x; + + for (int j = 0; j < GRID_VERTICAL_SIZE; j++) + { + for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++) + { + // Draw each square of the grid + if (grid[i][j] == EMPTY) + { + DrawLine(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, LIGHTGRAY ); + DrawLine(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, LIGHTGRAY ); + DrawLine(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, LIGHTGRAY ); + DrawLine(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, LIGHTGRAY ); + offset.x += SQUARE_SIZE; + } + else if (grid[i][j] == FULL) + { + DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, GRAY); + offset.x += SQUARE_SIZE; + } + else if (grid[i][j] == MOVING) + { + DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, DARKGRAY); + offset.x += SQUARE_SIZE; + } + else if (grid[i][j] == BLOCK) + { + DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, LIGHTGRAY); + offset.x += SQUARE_SIZE; + } + else if (grid[i][j] == FADING) + { + DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, fadingColor); + offset.x += SQUARE_SIZE; + } + } + + offset.x = controller; + offset.y += SQUARE_SIZE; + } + + // Draw incoming piece (hardcoded) + offset.x = 500; + offset.y = 45; + + int controler = offset.x; + + for (int j = 0; j < 4; j++) + { + for (int i = 0; i < 4; i++) + { + if (incomingPiece[i][j] == EMPTY) + { + DrawLine(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, LIGHTGRAY ); + DrawLine(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, LIGHTGRAY ); + DrawLine(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, LIGHTGRAY ); + DrawLine(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, LIGHTGRAY ); + offset.x += SQUARE_SIZE; + } + else if (incomingPiece[i][j] == MOVING) + { + DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, GRAY); + offset.x += SQUARE_SIZE; + } + } + + offset.x = controler; + offset.y += SQUARE_SIZE; + } + + DrawText("INCOMING:", offset.x, offset.y - 100, 10, GRAY); + DrawText(FormatText("LINES: %04i", lines), offset.x, offset.y + 20, 10, GRAY); + + if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY); + } + else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); + + EndDrawing(); +} + +// Unload game variables +void UnloadGame(void) +{ + // TODO: Unload all dynamic loaded data (textures, sounds, models...) +} + +// Update and Draw (one frame) +void UpdateDrawFrame(void) +{ + UpdateGame(); + DrawGame(); +} + +//-------------------------------------------------------------------------------------- +// Additional module functions +//-------------------------------------------------------------------------------------- +static bool Createpiece() +{ + piecePositionX = (int)((GRID_HORIZONTAL_SIZE - 4)/2); + piecePositionY = 0; + + // If the game is starting and you are going to create the first piece, we create an extra one + if (beginPlay) + { + GetRandompiece(); + beginPlay = false; + } + + // We assign the incoming piece to the actual piece + for (int i = 0; i < 4; i++) + { + for (int j = 0; j< 4; j++) + { + piece[i][j] = incomingPiece[i][j]; + } + } + + // We assign a random piece to the incoming one + GetRandompiece(); + + // Assign the piece to the grid + for (int i = piecePositionX; i < piecePositionX + 4; i++) + { + for (int j = 0; j < 4; j++) + { + if (piece[i - (int)piecePositionX][j] == MOVING) grid[i][j] = MOVING; + } + } + + return true; +} + +static void GetRandompiece() +{ + srand(time(NULL)); + int random = rand() % 7; + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + incomingPiece[i][j] = EMPTY; + } + } + + switch(random) + { + case 0: { incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; } break; //Cube + case 1: { incomingPiece[1][0] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; } break; //L + case 2: { incomingPiece[1][2] = MOVING; incomingPiece[2][0] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[2][2] = MOVING; } break; //L inversa + case 3: { incomingPiece[0][1] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[3][1] = MOVING; } break; //Recta + case 4: { incomingPiece[1][0] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][1] = MOVING; } break; //Creu tallada + case 5: { incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[2][2] = MOVING; incomingPiece[3][2] = MOVING; } break; //S + case 6: { incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[3][1] = MOVING; } break; //S inversa + } +} + +static void ResolveFallingMovement(bool *detection, bool *pieceActive) +{ + // If we finished moving this piece, we stop it + if (*detection) + { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { + grid[i][j] = FULL; + *detection = false; + *pieceActive = false; + } + } + } + } + // We move down the piece + else + { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { + grid[i][j+1] = MOVING; + grid[i][j] = EMPTY; + } + } + } + piecePositionY++; + } +} + +static bool ResolveLateralMovement() +{ + bool collision = false; + + // Move left + if (IsKeyDown(KEY_LEFT)) + { + // Check if is possible to move to left + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { + // Check if we are touching the left wall or we have a full square at the left + if ((i-1 == 0) || (grid[i-1][j] == FULL)) collision = true; + } + } + } + // If able, move left + if (!collision) + { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) // We check the matrix from left to right + { + // Move everything to the left + if (grid[i][j] == MOVING) + { + grid[i-1][j] = MOVING; + grid[i][j] = EMPTY; + } + } + } + + piecePositionX--; + } + } + + // Move right + else if (IsKeyDown(KEY_RIGHT)) + { + // Check if is possible to move to right + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { + // Check if we are touching the right wall or we have a full square at the right + if ((i+1 == GRID_HORIZONTAL_SIZE - 1) || (grid[i+1][j] == FULL)) + { + collision = true; + + } + } + } + } + // If able move right + if (!collision) + { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = GRID_HORIZONTAL_SIZE - 1; i >= 1; i--) // We check the matrix from right to left + { + // Move everything to the right + if (grid[i][j] == MOVING) + { + grid[i+1][j] = MOVING; + grid[i][j] = EMPTY; + } + } + } + + piecePositionX++; + } + } + + return collision; +} + +static bool ResolveTurnMovement() +{ + // Input for turning the piece + if (IsKeyDown(KEY_UP)) + { + int aux; + bool checker = false; + + // Check all turning possibilities + if ((grid[piecePositionX + 3][piecePositionY] == MOVING) && + (grid[piecePositionX][piecePositionY] != EMPTY) && + (grid[piecePositionX][piecePositionY] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX + 3][piecePositionY + 3] == MOVING) && + (grid[piecePositionX + 3][piecePositionY] != EMPTY) && + (grid[piecePositionX + 3][piecePositionY] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX][piecePositionY + 3] == MOVING) && + (grid[piecePositionX + 3][piecePositionY + 3] != EMPTY) && + (grid[piecePositionX + 3][piecePositionY + 3] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX][piecePositionY] == MOVING) && + (grid[piecePositionX][piecePositionY + 3] != EMPTY) && + (grid[piecePositionX][piecePositionY + 3] != MOVING)) + { + checker = true; + } + + + if ((grid[piecePositionX + 1][piecePositionY] == MOVING) && + (grid[piecePositionX][piecePositionY + 2] != EMPTY) && + (grid[piecePositionX][piecePositionY + 2] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX + 3][piecePositionY + 1] == MOVING) && + (grid[piecePositionX + 1][piecePositionY] != EMPTY) && + (grid[piecePositionX + 1][piecePositionY] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX + 2][piecePositionY + 3] == MOVING) && + (grid[piecePositionX + 3][piecePositionY + 1] != EMPTY) && + (grid[piecePositionX + 3][piecePositionY + 1] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX][piecePositionY + 2] == MOVING) && + (grid[piecePositionX + 2][piecePositionY + 3] != EMPTY) && + (grid[piecePositionX + 2][piecePositionY + 3] != MOVING)) + { + checker = true; + } + + + if ((grid[piecePositionX + 2][piecePositionY] == MOVING) && + (grid[piecePositionX][piecePositionY + 1] != EMPTY) && + (grid[piecePositionX][piecePositionY + 1] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX + 3][piecePositionY + 2] == MOVING) && + (grid[piecePositionX + 2][piecePositionY] != EMPTY) && + (grid[piecePositionX + 2][piecePositionY] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX + 1][piecePositionY + 3] == MOVING) && + (grid[piecePositionX + 3][piecePositionY + 2] != EMPTY) && + (grid[piecePositionX + 3][piecePositionY + 2] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX][piecePositionY + 1] == MOVING) && + (grid[piecePositionX + 1][piecePositionY + 3] != EMPTY) && + (grid[piecePositionX + 1][piecePositionY + 3] != MOVING)) + { + checker = true; + } + + if ((grid[piecePositionX + 1][piecePositionY + 1] == MOVING) && + (grid[piecePositionX + 1][piecePositionY + 2] != EMPTY) && + (grid[piecePositionX + 1][piecePositionY + 2] != MOVING)) + { + checker = true; + } + + if ((grid[piecePositionX + 2][piecePositionY + 1] == MOVING) && + (grid[piecePositionX + 1][piecePositionY + 1] != EMPTY) && + (grid[piecePositionX + 1][piecePositionY + 1] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX + 2][piecePositionY + 2] == MOVING) && + (grid[piecePositionX + 2][piecePositionY + 1] != EMPTY) && + (grid[piecePositionX + 2][piecePositionY + 1] != MOVING)) + { + checker = true; + } + if ((grid[piecePositionX + 1][piecePositionY + 2] == MOVING) && + (grid[piecePositionX + 2][piecePositionY + 2] != EMPTY) && + (grid[piecePositionX + 2][piecePositionY + 2] != MOVING)) + { + checker = true; + } + + if (!checker) + { + aux = piece[0][0]; + piece[0][0] = piece[3][0]; + piece[3][0] = piece[3][3]; + piece[3][3] = piece[0][3]; + piece[0][3] = aux; + + aux = piece[1][0]; + piece[1][0] = piece[3][1]; + piece[3][1] = piece[2][3]; + piece[2][3] = piece[0][2]; + piece[0][2] = aux; + + aux = piece[2][0]; + piece[2][0] = piece[3][2]; + piece[3][2] = piece[1][3]; + piece[1][3] = piece[0][1]; + piece[0][1] = aux; + + aux = piece[1][1]; + piece[1][1] = piece[2][1]; + piece[2][1] = piece[2][2]; + piece[2][2] = piece[1][2]; + piece[1][2] = aux; + } + + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { + grid[i][j] = EMPTY; + } + } + } + + for (int i = piecePositionX; i < piecePositionX + 4; i++) + { + for (int j = piecePositionY; j < piecePositionY + 4; j++) + { + if (piece[i - piecePositionX][j - piecePositionY] == MOVING) + { + grid[i][j] = MOVING; + } + } + } + return true; + } + + return false; +} + +static void CheckDetection(bool *detection) +{ + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if ((grid[i][j] == MOVING) && ((grid[i][j+1] == FULL) || (grid[i][j+1] == BLOCK))) *detection = true; + } + } +} + +static void CheckCompletition(bool *lineToDelete) +{ + int calculator; + + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + calculator = 0; + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + // Count each square of the line + if (grid[i][j] == FULL) + { + calculator++; + } + + // Check if we completed the whole line + if (calculator == GRID_HORIZONTAL_SIZE - 2) + { + *lineToDelete = true; + calculator = 0; + // points++; + + // Mark the completed line + for (int z = 1; z < GRID_HORIZONTAL_SIZE - 1; z++) + { + grid[z][j] = FADING; + } + } + } + } +} + +static void DeleteCompleteLines() +{ + // erase the completed line + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + while (grid[1][j] == FADING) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + grid[i][j] = EMPTY; + } + for (int j2 = j-1; j2 >= 0; j2--) + { + for (int i2 = 1; i2 < GRID_HORIZONTAL_SIZE - 1; i2++) + { + if (grid[i2][j2] == FULL) + { + grid[i2][j2+1] = FULL; + grid[i2][j2] = EMPTY; + } + else if (grid[i2][j2] == FADING) + { + grid[i2][j2+1] = FADING; + grid[i2][j2] = EMPTY; + } + } + } + } + } +} \ No newline at end of file diff --git a/logo/tshirt/raylib_tshirt_back.svg b/logo/tshirt/raylib_tshirt_back.svg new file mode 100644 index 000000000..05c587ece --- /dev/null +++ b/logo/tshirt/raylib_tshirt_back.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/logo/tshirt/raylib_tshirt_female.png b/logo/tshirt/raylib_tshirt_female.png new file mode 100644 index 000000000..e693a2623 Binary files /dev/null and b/logo/tshirt/raylib_tshirt_female.png differ diff --git a/logo/tshirt/raylib_tshirt_front.svg b/logo/tshirt/raylib_tshirt_front.svg new file mode 100644 index 000000000..7d1414f88 --- /dev/null +++ b/logo/tshirt/raylib_tshirt_front.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/logo/tshirt/raylib_tshirt_male.png b/logo/tshirt/raylib_tshirt_male.png new file mode 100644 index 000000000..2de06ed75 Binary files /dev/null and b/logo/tshirt/raylib_tshirt_male.png differ diff --git a/src/audio.c b/src/audio.c index 6313c9dc5..260f67783 100644 --- a/src/audio.c +++ b/src/audio.c @@ -166,15 +166,8 @@ void CloseAudioDevice(void) // Load sound to memory Sound LoadSound(char *fileName) { - Sound sound; - Wave wave; - - // Init some default values for wave... - wave.data = NULL; - wave.dataSize = 0; - wave.sampleRate = 0; - wave.bitsPerSample = 0; - wave.channels = 0; + Sound sound = { 0 }; + Wave wave = { 0 }; // NOTE: The entire file is loaded to memory to play it all at once (no-streaming) @@ -236,7 +229,7 @@ Sound LoadSound(char *fileName) // Load sound from wave data Sound LoadSoundFromWave(Wave wave) { - Sound sound; + Sound sound = { 0 }; if (wave.data != NULL) { @@ -287,10 +280,10 @@ Sound LoadSoundFromWave(Wave wave) } // Load sound to memory from rRES file (raylib Resource) +// TODO: Maybe rresName could be directly a char array with all the data? Sound LoadSoundFromRES(const char *rresName, int resId) { - // NOTE: rresName could be directly a char array with all the data!!! --> TODO - Sound sound; + Sound sound = { 0 }; #if defined(AUDIO_STANDALONE) TraceLog(WARNING, "Sound loading from rRES resource file not supported on standalone mode"); @@ -791,7 +784,7 @@ static Wave LoadWAV(const char *fileName) WaveFormat waveFormat; WaveData waveData; - Wave wave; + Wave wave = { 0 }; FILE *wavFile; wavFile = fopen(fileName, "rb"); diff --git a/src/camera.c b/src/camera.c index 4768b1766..517e4a2bb 100644 --- a/src/camera.c +++ b/src/camera.c @@ -2,7 +2,7 @@ * * raylib Camera System - Camera Modes Setup and Control Functions * -* Copyright (c) 2015 Marc Palau and Ramon Santamaria +* Copyright (c) 2015 Marc Palau and Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -36,44 +36,44 @@ // Defines and Macros //---------------------------------------------------------------------------------- // CAMERA_GENERIC -#define CAMERA_SCROLL_SENSITIVITY 1.5 +#define CAMERA_SCROLL_SENSITIVITY 1.5f // FREE_CAMERA -#define FREE_CAMERA_MOUSE_SENSITIVITY 0.01 -#define FREE_CAMERA_DISTANCE_MIN_CLAMP 0.3 -#define FREE_CAMERA_DISTANCE_MAX_CLAMP 120 -#define FREE_CAMERA_MIN_CLAMP 85 -#define FREE_CAMERA_MAX_CLAMP -85 -#define FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY 0.05 -#define FREE_CAMERA_PANNING_DIVIDER 5.1 +#define FREE_CAMERA_MOUSE_SENSITIVITY 0.01f +#define FREE_CAMERA_DISTANCE_MIN_CLAMP 0.3f +#define FREE_CAMERA_DISTANCE_MAX_CLAMP 120.0f +#define FREE_CAMERA_MIN_CLAMP 85.0f +#define FREE_CAMERA_MAX_CLAMP -85.0f +#define FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY 0.05f +#define FREE_CAMERA_PANNING_DIVIDER 5.1f // ORBITAL_CAMERA -#define ORBITAL_CAMERA_SPEED 0.01 +#define ORBITAL_CAMERA_SPEED 0.01f // FIRST_PERSON -//#define FIRST_PERSON_MOUSE_SENSITIVITY 0.003 -#define FIRST_PERSON_FOCUS_DISTANCE 25 -#define FIRST_PERSON_MIN_CLAMP 85 -#define FIRST_PERSON_MAX_CLAMP -85 +//#define FIRST_PERSON_MOUSE_SENSITIVITY 0.003f +#define FIRST_PERSON_FOCUS_DISTANCE 25.0f +#define FIRST_PERSON_MIN_CLAMP 85.0f +#define FIRST_PERSON_MAX_CLAMP -85.0f -#define FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0 -#define FIRST_PERSON_STEP_DIVIDER 30.0 -#define FIRST_PERSON_WAVING_DIVIDER 200.0 +#define FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0f +#define FIRST_PERSON_STEP_DIVIDER 30.0f +#define FIRST_PERSON_WAVING_DIVIDER 200.0f -#define FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION 0.85 +#define FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION 0.85f // THIRD_PERSON -//#define THIRD_PERSON_MOUSE_SENSITIVITY 0.003 -#define THIRD_PERSON_DISTANCE_CLAMP 1.2 -#define THIRD_PERSON_MIN_CLAMP 5 -#define THIRD_PERSON_MAX_CLAMP -85 -#define THIRD_PERSON_OFFSET (Vector3){ 0.4, 0, 0 } +//#define THIRD_PERSON_MOUSE_SENSITIVITY 0.003f +#define THIRD_PERSON_DISTANCE_CLAMP 1.2f +#define THIRD_PERSON_MIN_CLAMP 5.0f +#define THIRD_PERSON_MAX_CLAMP -85.0f +#define THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f } // PLAYER (used by camera) -#define PLAYER_WIDTH 0.4 -#define PLAYER_HEIGHT 0.9 -#define PLAYER_DEPTH 0.4 -#define PLAYER_MOVEMENT_DIVIDER 20.0 +#define PLAYER_WIDTH 0.4f +#define PLAYER_HEIGHT 0.9f +#define PLAYER_DEPTH 0.4f +#define PLAYER_MOVEMENT_DIVIDER 20.0f //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -84,11 +84,11 @@ typedef enum { MOVE_FRONT = 0, MOVE_LEFT, MOVE_BACK, MOVE_RIGHT, MOVE_UP, MOVE_D //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static Camera internalCamera = {{2, 0, 2}, {0, 0, 0}, {0, 1, 0}}; -static Vector2 cameraAngle = { 0, 0 }; +static Camera internalCamera = {{ 2.0f, 0.0f, 2.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; +static Vector2 cameraAngle = { 0.0f, 0.0f }; static float cameraTargetDistance = 5.0f; -static Vector2 cameraMousePosition = { 0, 0 }; -static Vector2 cameraMouseVariation = { 0, 0 }; +static Vector2 cameraMousePosition = { 0.0f, 0.0f }; +static Vector2 cameraMouseVariation = { 0.0f, 0.0f }; static float mouseSensitivity = 0.003f; static int cameraMoveControl[6] = { 'W', 'A', 'S', 'D', 'E', 'Q' }; static int cameraMoveCounter = 0; @@ -107,7 +107,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition); #if defined(CAMERA_STANDALONE) // NOTE: Camera controls depend on some raylib input functions // TODO: Set your own input functions (used in ProcessCamera()) -static Vector2 GetMousePosition() { return (Vector2){ 0, 0}; } +static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } static void SetMousePosition(Vector2 pos) {} static int IsMouseButtonDown(int button) { return 0;} static int GetMouseWheelMove() { return 0; } @@ -129,33 +129,33 @@ void SetCameraMode(int mode) if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_FREE)) { cameraMode = CAMERA_THIRD_PERSON; - cameraTargetDistance = 5; - cameraAngle.y = -40 * DEG2RAD; + cameraTargetDistance = 5.0f; + cameraAngle.y = -40*DEG2RAD; ProcessCamera(&internalCamera, &internalCamera.position); } else if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_ORBITAL)) { cameraMode = CAMERA_THIRD_PERSON; - cameraTargetDistance = 5; - cameraAngle.y = -40 * DEG2RAD; + cameraTargetDistance = 5.0f; + cameraAngle.y = -40*DEG2RAD; ProcessCamera(&internalCamera, &internalCamera.position); } else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_FREE)) { - cameraTargetDistance = 10; - cameraAngle.x = 45 * DEG2RAD; - cameraAngle.y = -40 * DEG2RAD; - internalCamera.target = (Vector3){ 0, 0, 0 }; + cameraTargetDistance = 10.0f; + cameraAngle.x = 45*DEG2RAD; + cameraAngle.y = -40*DEG2RAD; + internalCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; ProcessCamera(&internalCamera, &internalCamera.position); ShowCursor(); } else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_ORBITAL)) { - cameraTargetDistance = 10; - cameraAngle.x = 225 * DEG2RAD; - cameraAngle.y = -40 * DEG2RAD; - internalCamera.target = (Vector3){ 0, 0, 0}; + cameraTargetDistance = 10.0f; + cameraAngle.x = 225*DEG2RAD; + cameraAngle.y = -40*DEG2RAD; + internalCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; ProcessCamera(&internalCamera, &internalCamera.position); } @@ -165,7 +165,7 @@ void SetCameraMode(int mode) // Update camera (player position is ignored) void UpdateCamera(Camera *camera) { - Vector3 position = { 0, 0, 0 }; + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Process internal camera and player position (if required) if (cameraMode != CAMERA_CUSTOM) ProcessCamera(&internalCamera, &position); @@ -244,7 +244,7 @@ void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, // Set camera mouse sensitivity (1st person and 3rd person cameras) void SetCameraMouseSensitivity(float sensitivity) { - mouseSensitivity = (sensitivity/10000.0); + mouseSensitivity = (sensitivity/10000.0f); } //---------------------------------------------------------------------------------- @@ -375,13 +375,13 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) } // Focus to center - // TODO: Move this function out of the module? - if (IsKeyDown('Z')) camera->target = (Vector3){ 0, 0, 0 }; + // TODO: Move this function out of this module? + if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera position update camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; + if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; @@ -398,12 +398,12 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) if (cameraTargetDistance < THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = THIRD_PERSON_DISTANCE_CLAMP; // Focus to center - if (IsKeyDown('Z')) camera->target = (Vector3){ 0, 0, 0 }; + if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera position update camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; + if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; @@ -412,7 +412,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) case CAMERA_FIRST_PERSON: case CAMERA_THIRD_PERSON: { - int isMoving = 0; + bool isMoving = false; // Keyboard inputs if (IsKeyDown(cameraMoveControl[MOVE_FRONT])) @@ -422,7 +422,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) if (!cameraUseGravity) camera->position.y += sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER; - isMoving = 1; + isMoving = true; } else if (IsKeyDown(cameraMoveControl[MOVE_BACK])) { @@ -431,7 +431,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) if (!cameraUseGravity) camera->position.y -= sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER; - isMoving = 1; + isMoving = true; } if (IsKeyDown(cameraMoveControl[MOVE_LEFT])) @@ -439,23 +439,23 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) playerPosition->x -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; playerPosition->z += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - isMoving = 1; + isMoving = true; } else if (IsKeyDown(cameraMoveControl[MOVE_RIGHT])) { playerPosition->x += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; playerPosition->z -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - isMoving = 1; + isMoving = true; } if (IsKeyDown(cameraMoveControl[MOVE_UP])) { - if (!cameraUseGravity) playerPosition->y += 1/PLAYER_MOVEMENT_DIVIDER; + if (!cameraUseGravity) playerPosition->y += 1.0f/PLAYER_MOVEMENT_DIVIDER; } else if (IsKeyDown(cameraMoveControl[MOVE_DOWN])) { - if (!cameraUseGravity) playerPosition->y -= 1/PLAYER_MOVEMENT_DIVIDER; + if (!cameraUseGravity) playerPosition->y -= 1.0f/PLAYER_MOVEMENT_DIVIDER; } if (cameraMode == CAMERA_THIRD_PERSON) @@ -482,7 +482,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition) // Camera position update camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; + if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; diff --git a/src/camera.h b/src/camera.h index ed85320a4..9ad09c6fc 100644 --- a/src/camera.h +++ b/src/camera.h @@ -28,8 +28,8 @@ #define PI 3.14159265358979323846 #endif -#define DEG2RAD (PI / 180.0f) -#define RAD2DEG (180.0f / PI) +#define DEG2RAD (PI/180.0f) +#define RAD2DEG (180.0f/PI) //---------------------------------------------------------------------------------- // Defines and Macros diff --git a/src/core.c b/src/core.c index 9b068300c..dbcfa6bc1 100644 --- a/src/core.c +++ b/src/core.c @@ -53,8 +53,7 @@ #include // String function definitions, memset() #include // Macros for reporting and retrieving error conditions through error codes -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - +#if defined(PLATFORM_DESKTOP) #define GLAD_EXTENSIONS_LOADER #if defined(GLEW_EXTENSIONS_LOADER) #define GLEW_STATIC @@ -62,14 +61,16 @@ #elif defined(GLAD_EXTENSIONS_LOADER) #include "glad.h" // GLAD library: Manage OpenGL headers and extensions #endif +#endif +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 - #include // GLFW3 library: Windows, OpenGL context and Input management + #include // GLFW3 library: Windows, OpenGL context and Input management #ifdef __linux - #define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting - #define GLFW_EXPOSE_NATIVE_GLX // native functions like glfwGetX11Window - #include // which are required for hiding mouse + #define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting + #define GLFW_EXPOSE_NATIVE_GLX // native functions like glfwGetX11Window + #include // which are required for hiding mouse #endif //#include // OpenGL functions (GLFW3 already includes gl.h) //#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version! @@ -101,11 +102,6 @@ #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions #include "EGL/eglext.h" // Khronos EGL library - Extensions #include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library - - #define DEFAULT_KEYBOARD_DEV "/dev/input/event0" // Not used, keyboard inputs are read raw from stdin - #define DEFAULT_MOUSE_DEV "/dev/input/event1" - //#define DEFAULT_MOUSE_DEV "/dev/input/mouse0" - #define DEFAULT_GAMEPAD_DEV "/dev/input/js0" #endif #if defined(PLATFORM_WEB) @@ -116,6 +112,22 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- +#define STORAGE_FILENAME "storage.data" + +#if defined(PLATFORM_RPI) + // Old device inputs system + #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input + #define DEFAULT_MOUSE_DEV "/dev/input/mouse0" + #define DEFAULT_GAMEPAD_DEV "/dev/input/js0" + + // New device input events (evdev) (must be detected) + //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN" + //#define DEFAULT_MOUSE_DEV "/dev/input/eventN" + //#define DEFAULT_GAMEPAD_DEV "/dev/input/eventN" + + #define MOUSE_SENSITIVITY 0.8f + #define MAX_GAMEPAD_BUTTONS 11 +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -140,24 +152,24 @@ static int currentButtonState[128] = { 1 }; // Required to check if button p #elif defined(PLATFORM_RPI) static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device) -// Input variables (mouse/keyboard) +// Keyboard input variables +// NOTE: For keyboard we will use the standard input (but reconfigured...) +static struct termios defaultKeyboardSettings; // Used to store default keyboard settings +static int defaultKeyboardMode; // Used to store default keyboard mode + +// Mouse input variables static int mouseStream = -1; // Mouse device file descriptor static bool mouseReady = false; // Flag to know if mouse is ready pthread_t mouseThreadId; // Mouse reading thread id -// NOTE: For keyboard we will use the standard input (but reconfigured...) -static int defaultKeyboardMode; // Used to store default keyboard mode -static struct termios defaultKeyboardSettings; // Used to staore default keyboard settings - -static int keyboardMode = 0; // Keyboard mode: 1 (KEYCODES), 2 (ASCII) - -// This array maps Unix keycodes to ASCII equivalent and to GLFW3 equivalent for special function keys (>256) -const short UnixKeycodeToASCII[128] = { 256, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 259, 9, 81, 87, 69, 82, 84, 89, 85, 73, 79, 80, 91, 93, 257, 341, 65, 83, 68, - 70, 71, 72, 74, 75, 76, 59, 39, 96, 340, 92, 90, 88, 67, 86, 66, 78, 77, 44, 46, 47, 344, -1, 342, 32, -1, 290, 291, 292, 293, 294, 295, 296, - 297, 298, 299, -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 257, 345, 47, -1, - 346, -1, -1, 265, -1, 263, 262, -1, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - +// Gamepad input variables static int gamepadStream = -1; // Gamepad device file descriptor +static bool gamepadReady = false; // Flag to know if gamepad is ready +pthread_t gamepadThreadId; // Gamepad reading thread id + +int gamepadButtons[MAX_GAMEPAD_BUTTONS]; +int gamepadAxisX = 0; +int gamepadAxisY = 0; #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -180,7 +192,7 @@ static bool fullscreen = false; // Fullscreen mode (useful only for static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) -static Vector2 touchPosition; // Touch position on screen +static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen #endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) @@ -208,7 +220,9 @@ static int exitKey = KEY_ESCAPE; // Default exit key (ESC) static int lastKeyPressed = -1; // Register last key pressed static bool cursorHidden; // Track if cursor is hidden +#endif +#if defined(PLATFORM_DESKTOP) static char **dropFilesPath; // Store dropped files paths as strings static int dropFilesCount = 0; // Count stored strings #endif @@ -242,17 +256,20 @@ static void LogoAnimation(void); // Plays raylib logo app static void SetupFramebufferSize(int displayWidth, int displayHeight); #if defined(PLATFORM_RPI) +static void InitKeyboard(void); // Init raw keyboard system (standard input reading) +static void ProcessKeyboard(void); // Process keyboard events +static void RestoreKeyboard(void); // Restore keyboard system static void InitMouse(void); // Mouse initialization (including mouse thread) static void *MouseThread(void *arg); // Mouse reading thread -static void InitKeyboard(void); // Init raw keyboard system (standard input reading) -static void RestoreKeyboard(void); // Restore keyboard system static void InitGamepad(void); // Init raw gamepad input +static void *GamepadThread(void *arg); // Mouse reading thread #endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value) static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area @@ -320,6 +337,10 @@ void InitWindow(int width, int height, const char *title) emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenInputCallback); emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback); emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback); + + // TODO: Add gamepad support (not provided by GLFW3 on emscripten) + //emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenInputCallback); + //emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenInputCallback); #endif mousePosition.x = (float)screenWidth/2.0f; @@ -355,7 +376,7 @@ void InitWindow(int width, int height, struct android_app *state) if (orientation == ACONFIGURATION_ORIENTATION_PORT) TraceLog(INFO, "PORTRAIT window orientation"); else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TraceLog(INFO, "LANDSCAPE window orientation"); - // TODO: Review, it doesn't work... + // TODO: Automatic orientation doesn't seem to work if (width <= height) { AConfiguration_setOrientation(app->config, ACONFIGURATION_ORIENTATION_PORT); @@ -463,6 +484,7 @@ bool IsWindowMinimized(void) } // Fullscreen toggle +// TODO: When destroying window context is lost and resources too, take care! void ToggleFullscreen(void) { #if defined(PLATFORM_DESKTOP) @@ -590,7 +612,7 @@ void Begin3dMode(Camera camera) // Setup perspective projection float aspect = (float)screenWidth/(float)screenHeight; - double top = 0.1f*tan(45.0f*PI/360.0f); + double top = 0.1*tan(45.0*PI/360.0); double right = top*aspect; // NOTE: zNear and zFar values are important when computing depth buffer values @@ -629,7 +651,7 @@ void SetTargetFPS(int fps) // Returns current FPS float GetFPS(void) { - return (float)(1/frameTime); + return (float)(1.0/frameTime); } // Returns time in seconds for one frame @@ -754,7 +776,7 @@ void ShowLogo(void) showLogo = true; } -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) +#if defined(PLATFORM_DESKTOP) // Check if a file have been dropped into window bool IsFileDropped(void) { @@ -790,10 +812,10 @@ void StorageSaveValue(int position, int value) FILE *storageFile = NULL; // Try open existing file to append data - storageFile = fopen("storage.data", "rb+"); + storageFile = fopen(STORAGE_FILENAME, "rb+"); // If file doesn't exist, create a new storage data file - if (!storageFile) storageFile = fopen("storage.data", "wb"); + if (!storageFile) storageFile = fopen(STORAGE_FILENAME, "wb"); if (!storageFile) TraceLog(WARNING, "Storage data file could not be created"); else @@ -821,7 +843,7 @@ int StorageLoadValue(int position) int value = 0; // Try open existing file to append data - FILE *storageFile = fopen("storage.data", "rb"); + FILE *storageFile = fopen(STORAGE_FILENAME, "rb"); if (!storageFile) TraceLog(WARNING, "Storage data file could not be found"); else @@ -888,8 +910,8 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) MatrixInvert(&matProjView); // Calculate far and near points - Quaternion near = { deviceCoords.x, deviceCoords.y, 0, 1}; - Quaternion far = { deviceCoords.x, deviceCoords.y, 1, 1}; + Quaternion near = { deviceCoords.x, deviceCoords.y, 0.0f, 1.0f}; + Quaternion far = { deviceCoords.x, deviceCoords.y, 1.0f, 1.0f}; // Multiply points by unproject matrix QuaternionTransform(&near, matProjView); @@ -938,6 +960,12 @@ Vector2 WorldToScreen(Vector3 position, Camera camera) return screenPosition; } +// Get transform matrix for camera +Matrix GetCameraMatrix(Camera camera) +{ + return MatrixLookAt(camera.position, camera.target, camera.up); +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //---------------------------------------------------------------------------------- @@ -1091,23 +1119,44 @@ void ShowCursor() cursorHidden = false; } +// Disable mouse cursor +void DisableCursor() +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); +#endif + cursorHidden = true; +} + +// Enable mouse cursor +void EnableCursor() +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +#endif + cursorHidden = false; +} + // Check if mouse cursor is hidden bool IsCursorHidden() { return cursorHidden; } -#endif -// TODO: Enable gamepad usage on Rapsberry Pi -// NOTE: emscripten not implemented -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) +// NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) + // Detect if a gamepad is available bool IsGamepadAvailable(int gamepad) { - int result = glfwJoystickPresent(gamepad); + bool result = false; + +#if defined(PLATFORM_RPI) + if (gamepadReady && (gamepad == 0)) result = true; +#else + if (glfwJoystickPresent(gamepad) == 1) result = true; +#endif - if (result == 1) return true; - else return false; + return result; } // Return axis movement vector for a gamepad @@ -1116,10 +1165,15 @@ Vector2 GetGamepadMovement(int gamepad) Vector2 vec = { 0, 0 }; const float *axes; - int axisCount; - + int axisCount = 0; + +#if defined(PLATFORM_RPI) + // TODO: Get gamepad axis information + // Use gamepadAxisX, gamepadAxisY +#else axes = glfwGetJoystickAxes(gamepad, &axisCount); - +#endif + if (axisCount >= 2) { vec.x = axes[0]; // Left joystick X @@ -1152,16 +1206,23 @@ bool IsGamepadButtonPressed(int gamepad, int button) // Detect if a gamepad button is being pressed bool IsGamepadButtonDown(int gamepad, int button) { + bool result = false; + +#if defined(PLATFORM_RPI) + // Get gamepad buttons information + if ((gamepad == 0) && (gamepadButtons[button] == 1)) result = true; + else result = false; +#else const unsigned char *buttons; int buttonsCount; - + buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); - if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) - { - return true; - } - else return false; + if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) result = true; + else result = false; +#endif + + return result; } // Detect if a gamepad button has NOT been pressed once @@ -1184,41 +1245,59 @@ bool IsGamepadButtonReleased(int gamepad, int button) // Detect if a mouse button is NOT being pressed bool IsGamepadButtonUp(int gamepad, int button) { + bool result = false; + +#if defined(PLATFORM_RPI) + // Get gamepad buttons information + if ((gamepad == 0) && (gamepadButtons[button] == 0)) result = true; + else result = false; +#else const unsigned char *buttons; int buttonsCount; buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); - if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE)) - { - return true; - } - else return false; -} + if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE)) result = true; + else result = false; #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) + return result; +} +#endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) + // Returns touch position X int GetTouchX(void) { - return (int)touchPosition.x; +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) + return (int)touchPosition[0].x; +#else // PLATFORM_DESKTOP, PLATFORM_RPI + return GetMouseX(); +#endif } // Returns touch position Y int GetTouchY(void) { - return (int)touchPosition.y; +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) + return (int)touchPosition[0].y; +#else // PLATFORM_DESKTOP, PLATFORM_RPI + return GetMouseY(); +#endif } // Returns touch position XY -// TODO: touch position should be scaled depending on display size and render size -Vector2 GetTouchPosition(void) +// TODO: Touch position should be scaled depending on display size and render size +Vector2 GetTouchPosition(int index) { - Vector2 position = touchPosition; + Vector2 position = { -1.0f, -1.0f }; + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) + if (index < MAX_TOUCH_POINTS) position = touchPosition[index]; + else TraceLog(WARNING, "Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS); if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) { - // TODO: Seems to work ok but... review! + // TODO: Review touch position scaling for screenSize vs displaySize position.x = position.x*((float)screenWidth/(float)(displayWidth - renderOffsetX)) - renderOffsetX/2; position.y = position.y*((float)screenHeight/(float)(displayHeight - renderOffsetY)) - renderOffsetY/2; } @@ -1227,10 +1306,14 @@ Vector2 GetTouchPosition(void) position.x = position.x*((float)renderWidth/(float)displayWidth) - renderOffsetX/2; position.y = position.y*((float)renderHeight/(float)displayHeight) - renderOffsetY/2; } +#else // PLATFORM_DESKTOP, PLATFORM_RPI + if (index == 0) position = GetMousePosition(); +#endif return position; } +#if defined(PLATFORM_ANDROID) // Detect if a button has been pressed once bool IsButtonPressed(int button) { @@ -1333,10 +1416,24 @@ static void InitDisplay(int width, int height) if (fullscreen) { // At this point we need to manage render size vs screen size - // NOTE: This function uses and modifies global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView + // NOTE: This function uses and modifies global module variables: + // screenWidth/screenHeight - renderWidth/renderHeight - downscaleView SetupFramebufferSize(displayWidth, displayHeight); + + // TODO: SetupFramebufferSize() does not consider properly display video modes. + // It setups a renderWidth/renderHeight with black bars that could not match a valid video mode, + // and so, framebuffer is not scaled properly to some monitors. + + int count; + const GLFWvidmode *modes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count); + + for (int i = 0; i < count; i++) + { + // TODO: Check modes[i]->width; + // TODO: Check modes[i]->height; + } - window = glfwCreateWindow(renderWidth, renderHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); + window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); } else { @@ -1345,10 +1442,8 @@ static void InitDisplay(int width, int height) #if defined(PLATFORM_DESKTOP) // Center window on screen - const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - - int windowPosX = mode->width/2 - screenWidth/2; - int windowPosY = mode->height/2 - screenHeight/2; + int windowPosX = displayWidth/2 - screenWidth/2; + int windowPosY = displayHeight/2 - screenHeight/2; if (windowPosX < 0) windowPosX = 0; if (windowPosY < 0) windowPosY = 0; @@ -1379,6 +1474,7 @@ static void InitDisplay(int width, int height) glfwSetCursorEnterCallback(window, CursorEnterCallback); glfwSetKeyCallback(window, KeyCallback); glfwSetMouseButtonCallback(window, MouseButtonCallback); + glfwSetCursorPosCallback(window, MouseCursorPosCallback); // Track mouse position changes glfwSetCharCallback(window, CharCallback); glfwSetScrollCallback(window, ScrollCallback); glfwSetWindowIconifyCallback(window, WindowIconifyCallback); @@ -1388,6 +1484,7 @@ static void InitDisplay(int width, int height) glfwMakeContextCurrent(window); +#if defined(PLATFORM_DESKTOP) // Extensions initialization for OpenGL 3.3 if (rlGetVersion() == OPENGL_33) { @@ -1419,6 +1516,7 @@ static void InitDisplay(int width, int height) //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object #endif } +#endif // Enables GPU v-sync, so frames are not limited to screen refresh rate (60Hz -> 60 FPS) // If not set, swap interval uses GPU v-sync configuration @@ -1622,8 +1720,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i #endif else currentKeyState[key] = action; - // HACK for GuiTextBox, to deteck back key - // TODO: Review... + // TODO: Review (and remove) this HACK for GuiTextBox, to deteck back key if ((key == 259) && (action == GLFW_PRESS)) lastKeyPressed = 3; } @@ -1631,6 +1728,59 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { currentMouseState[button] = action; + +#define ENABLE_MOUSE_GESTURES +#if defined(ENABLE_MOUSE_GESTURES) + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent; + + // Register touch actions + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN; + else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_UP; + + // NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback() + + // Assign a pointer ID + gestureEvent.pointerId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = GetMousePosition(); + + // Normalize gestureEvent.position[0] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +// GLFW3 Cursor Position Callback, runs on mouse move +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) +{ +#define ENABLE_MOUSE_GESTURES +#if defined(ENABLE_MOUSE_GESTURES) + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent; + + gestureEvent.touchAction = TOUCH_MOVE; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = (Vector2){ (float)x, (float)y }; + + // Normalize gestureEvent.position[0] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif } // GLFW3 Char Key Callback, runs on key pressed (get char value) @@ -1831,8 +1981,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) if (type == AINPUT_EVENT_TYPE_MOTION) { - touchPosition.x = AMotionEvent_getX(event, 0); - touchPosition.y = AMotionEvent_getY(event, 0); + // Get first touch position + touchPosition[0].x = AMotionEvent_getX(event, 0); + touchPosition[0].y = AMotionEvent_getY(event, 0); + + // Get second touch position + touchPosition[1].x = AMotionEvent_getX(event, 1); + touchPosition[1].y = AMotionEvent_getY(event, 1); } else if (type == AINPUT_EVENT_TYPE_KEY) { @@ -1876,11 +2031,22 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) // Register touch points count gestureEvent.pointCount = AMotionEvent_getPointerCount(event); + // Register touch points id + gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0); + gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1); + // Register touch points position // NOTE: Only two points registered gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) }; gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) }; + // Normalize gestureEvent.position[x] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + gestureEvent.position[1].x /= (float)GetScreenWidth(); + gestureEvent.position[1].y /= (float)GetScreenHeight(); + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); @@ -1948,7 +2114,7 @@ static bool GetKeyStatus(int key) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetKey(window, key); #elif defined(PLATFORM_ANDROID) - // TODO: Check virtual keyboard (?) + // TODO: Check for virtual keyboard return false; #elif defined(PLATFORM_RPI) // NOTE: Keys states are filled in PollInputEvents() @@ -1963,10 +2129,10 @@ static bool GetMouseButtonStatus(int button) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetMouseButton(window, button); #elif defined(PLATFORM_ANDROID) - // TODO: Check virtual keyboard (?) + // TODO: Check for virtual keyboard return false; #elif defined(PLATFORM_RPI) - // NOTE: mouse buttons array is filled on PollInputEvents() + // NOTE: Mouse buttons states are filled in PollInputEvents() return currentMouseState[button]; #endif } @@ -1974,11 +2140,9 @@ static bool GetMouseButtonStatus(int button) // Poll (store) all input events static void PollInputEvents(void) { -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) - - // TODO: Remove this requirement... + // NOTE: Gestures update must be called every frame to reset gestures correctly + // because ProcessGestureEvent() is just called on an event, not every frame UpdateGestures(); -#endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -1990,8 +2154,7 @@ static void PollInputEvents(void) mousePosition.x = (float)mouseX; mousePosition.y = (float)mouseY; - // Keyboard polling - // Automatically managed by GLFW3 through callback + // Keyboard input polling (automatically managed by GLFW3 through callback) lastKeyPressed = -1; // Register previous keys states @@ -2030,199 +2193,14 @@ static void PollInputEvents(void) // NOTE: Keyboard reading could be done using input_event(s) reading or just read from stdin, // we use method 2 (stdin) but maybe in a future we should change to method 1... + ProcessKeyboard(); - // Keyboard input polling (fill keys[256] array with status) - int numKeysBuffer = 0; // Keys available on buffer - char keysBuffer[32]; // Max keys to be read at a time + // NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread() - // Reset pressed keys array - for (int i = 0; i < 512; i++) currentKeyState[i] = 0; - - // Read availables keycodes from stdin - numKeysBuffer = read(STDIN_FILENO, keysBuffer, 32); // POSIX system call - - // Fill array with pressed keys - for (int i = 0; i < numKeysBuffer; i++) - { - //TraceLog(INFO, "Bytes on keysBuffer: %i", numKeysBuffer); - - int key = keysBuffer[i]; - - if (keyboardMode == 2) // scancodes - { - // NOTE: If (key == 0x1b), depending on next key, it could be a special keymap code! - // Up -> 1b 5b 41 / Left -> 1b 5b 44 / Right -> 1b 5b 43 / Down -> 1b 5b 42 - if (key == 0x1b) - { - if (keysBuffer[i+1] == 0x5b) // Special function key - { - switch (keysBuffer[i+2]) - { - case 0x41: currentKeyState[265] = 1; break; - case 0x42: currentKeyState[264] = 1; break; - case 0x43: currentKeyState[262] = 1; break; - case 0x44: currentKeyState[263] = 1; break; - default: break; - } - - i += 2; // Jump to next key - - // NOTE: Other special function keys (F1, F2...) are not contempled for this keyboardMode... - // ...or they are just not directly keymapped (CTRL, ALT, SHIFT) - } - } - else if (key == 0x0a) currentKeyState[257] = 1; // raylib KEY_ENTER (don't mix with KEY_*) - else if (key == 0x7f) currentKeyState[259] = 1; - else - { - TraceLog(DEBUG, "Pressed key (ASCII): 0x%02x", key); - - currentKeyState[key] = 1; - } - - // Detect ESC to stop program - if ((key == 0x1b) && (numKeysBuffer == 1)) windowShouldClose = true; - } - else if (keyboardMode == 1) // keycodes (K_MEDIUMRAW mode) - { - TraceLog(DEBUG, "Pressed key (keycode): 0x%02x", key); - - // NOTE: Each key is 7-bits (high bit in the byte is 0 for down, 1 for up) - - // TODO: Review (or rewrite) this code... not clear... replace by events! - - int asciiKey = -1; - - // Convert keycode to some recognized key (ASCII or GLFW3 equivalent) - if (key < 128) asciiKey = (int)UnixKeycodeToASCII[key]; - - // Record equivalent key state - if ((asciiKey >= 0) && (asciiKey < 512)) currentKeyState[asciiKey] = 1; - - // In case of letter, we also activate lower case version - if ((asciiKey >= 65) && (asciiKey <=90)) currentKeyState[asciiKey + 32] = 1; - - // Detect KEY_ESC to stop program - if (key == 0x01) windowShouldClose = true; - } - - - // Same fucnionality as GLFW3 KeyCallback() - /* - if (asciiKey == exitKey) windowShouldClose = true; - else if (key == GLFW_KEY_F12 && action == GLFW_PRESS) - { - TakeScreenshot(); - } - */ - } - - // TODO: Gamepad support (use events, easy!) -/* - struct js_event gamepadEvent; - - read(gamepadStream, &gamepadEvent, sizeof(struct js_event)); - - if (gamepadEvent.type == JS_EVENT_BUTTON) - { - switch (gamepadEvent.number) - { - case 0: // 1st Axis X - case 1: // 1st Axis Y - case 2: // 2st Axis X - case 3: // 2st Axis Y - case 4: - { - if (gamepadEvent.value == 1) // Button pressed, 0 release - - } break; - // Buttons is similar, variable for every joystick - } - } - else if (gamepadEvent.type == JS_EVENT_AXIS) - { - switch (gamepadEvent.number) - { - case 0: // 1st Axis X - case 1: // 1st Axis Y - case 2: // 2st Axis X - case 3: // 2st Axis Y - // Buttons is similar, variable for every joystick - } - } -*/ #endif } #if defined(PLATFORM_RPI) -// Mouse initialization (including mouse thread) -static void InitMouse(void) -{ - // NOTE: We can use /dev/input/mice to read from all available mice - if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0) - { - TraceLog(WARNING, "Mouse device could not be opened, no mouse available"); - } - else - { - mouseReady = true; - - int error = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL); - - if (error != 0) TraceLog(WARNING, "Error creating mouse input event thread"); - else TraceLog(INFO, "Mouse device initialized successfully"); - } -} - -// Mouse reading thread -// NOTE: We need a separate thread to avoid loosing mouse events, -// if too much time passes between reads, queue gets full and new events override older ones... -static void *MouseThread(void *arg) -{ - struct input_event mouseEvent; - - while(1) - { - // NOTE: read() will return -1 if the events queue is empty - read(mouseStream, &mouseEvent, sizeof(struct input_event)); - - // Check event types - if (mouseEvent.type == EV_REL) // Relative motion event - { - if (mouseEvent.code == REL_X) - { - mousePosition.x += (float)mouseEvent.value; - - // Screen limits X check - if (mousePosition.x < 0) mousePosition.x = 0; - if (mousePosition.x > screenWidth) mousePosition.x = screenWidth; - } - - if (mouseEvent.code == REL_Y) - { - mousePosition.y += (float)mouseEvent.value; - - // Screen limits Y check - if (mousePosition.y < 0) mousePosition.y = 0; - if (mousePosition.y > screenHeight) mousePosition.y = screenHeight; - } - - if (mouseEvent.code == REL_WHEEL) - { - // mouseEvent.value give 1 or -1 (direction) - } - } - else if (mouseEvent.type == EV_KEY) // Mouse button event - { - if (mouseEvent.code == BTN_LEFT) currentMouseState[0] = mouseEvent.value; - if (mouseEvent.code == BTN_RIGHT) currentMouseState[1] = mouseEvent.value; - if (mouseEvent.code == BTN_MIDDLE) currentMouseState[2] = mouseEvent.value; - } - } - - return NULL; -} - // Initialize Keyboard system (using standard input) static void InitKeyboard(void) { @@ -2247,15 +2225,13 @@ static void InitKeyboard(void) // Set new keyboard settings (change occurs immediately) tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings); - // NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE, we change that! + // NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE, we change that! -> WHY??? // Save old keyboard mode to restore it at the end if (ioctl(STDIN_FILENO, KDGKBMODE, &defaultKeyboardMode) < 0) { // NOTE: It could mean we are using a remote keyboard through ssh! TraceLog(WARNING, "Could not change keyboard mode (SSH keyboard?)"); - - keyboardMode = 2; // ASCII } else { @@ -2264,15 +2240,111 @@ static void InitKeyboard(void) // - keycodes (K_MEDIUMRAW) // - ASCII chars (K_XLATE) // - UNICODE chars (K_UNICODE) - ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW); - - keyboardMode = 1; // keycodes + ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE); } // Register keyboard restore when program finishes atexit(RestoreKeyboard); } +// Process keyboard inputs +// TODO: Most probably input reading and processing should be in a separate thread +static void ProcessKeyboard(void) +{ + #define MAX_KEYBUFFER_SIZE 32 // Max size in bytes to read + + // Keyboard input polling (fill keys[256] array with status) + int bufferByteCount = 0; // Bytes available on the buffer + char keysBuffer[MAX_KEYBUFFER_SIZE]; // Max keys to be read at a time + + // Reset pressed keys array + for (int i = 0; i < 512; i++) currentKeyState[i] = 0; + + // Read availables keycodes from stdin + bufferByteCount = read(STDIN_FILENO, keysBuffer, MAX_KEYBUFFER_SIZE); // POSIX system call + + // Fill all read bytes (looking for keys) + for (int i = 0; i < bufferByteCount; i++) + { + TraceLog(DEBUG, "Bytes on keysBuffer: %i", bufferByteCount); + + //printf("Key(s) bytes: "); + //for (int i = 0; i < bufferByteCount; i++) printf("0x%02x ", keysBuffer[i]); + //printf("\n"); + + // NOTE: If (key == 0x1b), depending on next key, it could be a special keymap code! + // Up -> 1b 5b 41 / Left -> 1b 5b 44 / Right -> 1b 5b 43 / Down -> 1b 5b 42 + if (keysBuffer[i] == 0x1b) + { + // Detect ESC to stop program + if (bufferByteCount == 1) currentKeyState[256] = 1; // raylib key: KEY_ESCAPE + else + { + if (keysBuffer[i + 1] == 0x5b) // Special function key + { + if ((keysBuffer[i + 2] == 0x5b) || (keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32)) + { + // Process special function keys (F1 - F12) + switch (keysBuffer[i + 3]) + { + case 0x41: currentKeyState[290] = 1; break; // raylib KEY_F1 + case 0x42: currentKeyState[291] = 1; break; // raylib KEY_F2 + case 0x43: currentKeyState[292] = 1; break; // raylib KEY_F3 + case 0x44: currentKeyState[293] = 1; break; // raylib KEY_F4 + case 0x45: currentKeyState[294] = 1; break; // raylib KEY_F5 + case 0x37: currentKeyState[295] = 1; break; // raylib KEY_F6 + case 0x38: currentKeyState[296] = 1; break; // raylib KEY_F7 + case 0x39: currentKeyState[297] = 1; break; // raylib KEY_F8 + case 0x30: currentKeyState[298] = 1; break; // raylib KEY_F9 + case 0x31: currentKeyState[299] = 1; break; // raylib KEY_F10 + case 0x33: currentKeyState[300] = 1; break; // raylib KEY_F11 + case 0x34: currentKeyState[301] = 1; break; // raylib KEY_F12 + default: break; + } + + if (keysBuffer[i + 2] == 0x5b) i += 4; + else if ((keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32)) i += 5; + } + else + { + switch (keysBuffer[i + 2]) + { + case 0x41: currentKeyState[265] = 1; break; // raylib KEY_UP + case 0x42: currentKeyState[264] = 1; break; // raylib KEY_DOWN + case 0x43: currentKeyState[262] = 1; break; // raylib KEY_RIGHT + case 0x44: currentKeyState[263] = 1; break; // raylib KEY_LEFT + default: break; + } + + i += 3; // Jump to next key + } + + // NOTE: Some keys are not directly keymapped (CTRL, ALT, SHIFT) + } + } + } + else if (keysBuffer[i] == 0x0a) currentKeyState[257] = 1; // raylib KEY_ENTER (don't mix with KEY_*) + else if (keysBuffer[i] == 0x7f) currentKeyState[259] = 1; // raylib KEY_BACKSPACE + else + { + TraceLog(DEBUG, "Pressed key (ASCII): 0x%02x", keysBuffer[i]); + + // Translate lowercase a-z letters to A-Z + if ((keysBuffer[i] >= 97) && (keysBuffer[i] <= 122)) + { + currentKeyState[(int)keysBuffer[i] - 32] = 1; + } + else currentKeyState[(int)keysBuffer[i]] = 1; + } + } + + // Check exit key (same functionality as GLFW3 KeyCallback()) + if (currentKeyState[exitKey] == 1) windowShouldClose = true; + + // Check screen capture key + if (currentKeyState[301] == 1) TakeScreenshot(); // raylib key: KEY_F12 (GLFW_KEY_F12) +} + // Restore default keyboard input static void RestoreKeyboard(void) { @@ -2283,12 +2355,161 @@ static void RestoreKeyboard(void) ioctl(STDIN_FILENO, KDSKBMODE, defaultKeyboardMode); } +// Mouse initialization (including mouse thread) +static void InitMouse(void) +{ + // NOTE: We can use /dev/input/mice to read from all available mice + if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0) + { + TraceLog(WARNING, "Mouse device could not be opened, no mouse available"); + } + else + { + mouseReady = true; + + int error = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL); + + if (error != 0) TraceLog(WARNING, "Error creating mouse input event thread"); + else TraceLog(INFO, "Mouse device initialized successfully"); + } +} + +// Mouse reading thread +// NOTE: We need a separate thread to avoid loosing mouse events, +// if too much time passes between reads, queue gets full and new events override older ones... +static void *MouseThread(void *arg) +{ + const unsigned char XSIGN = 1<<4, YSIGN = 1<<5; + + typedef struct { + char buttons; + char dx, dy; + } MouseEvent; + + MouseEvent mouse; + + int mouseRelX = 0; + int mouseRelY = 0; + + while(1) + { + if (read(mouseStream, &mouse, sizeof(MouseEvent)) == (int)sizeof(MouseEvent)) + { + if ((mouse.buttons & 0x08) == 0) break; // This bit should always be set + + // Check Left button pressed + if ((mouse.buttons & 0x01) > 0) currentMouseState[0] = 1; + else currentMouseState[0] = 0; + + // Check Right button pressed + if ((mouse.buttons & 0x02) > 0) currentMouseState[1] = 1; + else currentMouseState[1] = 0; + + // Check Middle button pressed + if ((mouse.buttons & 0x04) > 0) currentMouseState[2] = 1; + else currentMouseState[2] = 0; + + mouseRelX = (int)mouse.dx; + mouseRelY = (int)mouse.dy; + + if ((mouse.buttons & XSIGN) > 0) mouseRelX = -1*(255 - mouseRelX); + if ((mouse.buttons & YSIGN) > 0) mouseRelY = -1*(255 - mouseRelY); + + // NOTE: Mouse movement is normalized to not be screen resolution dependant + // We suppose 2*255 (max relative movement) is equivalent to screenWidth (max pixels width) + // Result after normalization is multiplied by MOUSE_SENSITIVITY factor + + mousePosition.x += (float)mouseRelX*((float)screenWidth/(2*255))*MOUSE_SENSITIVITY; + mousePosition.y -= (float)mouseRelY*((float)screenHeight/(2*255))*MOUSE_SENSITIVITY; + + if (mousePosition.x < 0) mousePosition.x = 0; + if (mousePosition.y < 0) mousePosition.y = 0; + + if (mousePosition.x > screenWidth) mousePosition.x = screenWidth; + if (mousePosition.y > screenHeight) mousePosition.y = screenHeight; + } + //else read(mouseStream, &mouse, 1); // Try to sync up again + } + + return NULL; +} + // Init gamepad system static void InitGamepad(void) { - // TODO: Gamepad support - if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available"); - else TraceLog(INFO, "Gamepad device initialized successfully"); + if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) + { + TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available"); + } + else + { + gamepadReady = true; + + int error = pthread_create(&gamepadThreadId, NULL, &GamepadThread, NULL); + + if (error != 0) TraceLog(WARNING, "Error creating gamepad input event thread"); + else TraceLog(INFO, "Gamepad device initialized successfully"); + } +} + +// Process Gamepad (/dev/input/js0) +static void *GamepadThread(void *arg) +{ + #define JS_EVENT_BUTTON 0x01 // Button pressed/released + #define JS_EVENT_AXIS 0x02 // Joystick axis moved + #define JS_EVENT_INIT 0x80 // Initial state of device + + struct js_event { + unsigned int time; // event timestamp in milliseconds + short value; // event value + unsigned char type; // event type + unsigned char number; // event axis/button number + }; + + // These values are sensible on Logitech Dual Action Rumble and Xbox360 controller + const int joystickAxisX = 0; + const int joystickAxisY = 1; + + // Read gamepad event + struct js_event gamepadEvent; + + while (1) + { + if (read(gamepadStream, &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) + { + gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events + + // Process gamepad events by type + if (gamepadEvent.type == JS_EVENT_BUTTON) + { + TraceLog(DEBUG, "Gamepad button: %i, value: %i", gamepadEvent.number, gamepadEvent.value); + + if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS) + { + // 1 - button pressed, 0 - button released + gamepadButtons[gamepadEvent.number] = (int)gamepadEvent.value; + } + } + else if (gamepadEvent.type == JS_EVENT_AXIS) + { + TraceLog(DEBUG, "Gamepad axis: %i, value: %i", gamepadEvent.number, gamepadEvent.value); + + if (gamepadEvent.number == joystickAxisX) gamepadAxisX = (int)gamepadEvent.value; + if (gamepadEvent.number == joystickAxisY) gamepadAxisY = (int)gamepadEvent.value; + /* + switch (gamepadEvent.number) + { + case 0: // 1st Axis X + case 1: // 1st Axis Y + case 2: // 2st Axis X + case 3: // 2st Axis Y + } + */ + } + } + } + + return NULL; } #endif @@ -2306,6 +2527,10 @@ static void SwapBuffers(void) // NOTE: Global variables renderWidth/renderHeight can be modified static void SetupFramebufferSize(int displayWidth, int displayHeight) { + // TODO: SetupFramebufferSize() does not consider properly display video modes. + // It setups a renderWidth/renderHeight with black bars that could not match a valid video mode, + // and so, framebuffer is not scaled properly to some monitors. + // Calculate renderWidth and renderHeight, we have the display size (input params) and the desired screen size (global var) if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) { @@ -2436,6 +2661,10 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent // Register touch points count gestureEvent.pointCount = touchEvent->numTouches; + // Register touch points id + gestureEvent.pointerId[0] = touchEvent->touches[0].identifier; + gestureEvent.pointerId[1] = touchEvent->touches[1].identifier; + // Register touch points position // NOTE: Only two points registered // TODO: Touch data should be scaled accordingly! @@ -2444,8 +2673,16 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY }; gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY }; - touchPosition = gestureEvent.position[0]; + touchPosition[0] = gestureEvent.position[0]; + touchPosition[1] = gestureEvent.position[1]; + // Normalize gestureEvent.position[x] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + gestureEvent.position[1].x /= (float)GetScreenWidth(); + gestureEvent.position[1].y /= (float)GetScreenHeight(); + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); // Process obtained gestures data @@ -2469,7 +2706,6 @@ static void LogoAnimation(void) int bottomSideRecWidth = 16; int rightSideRecHeight = 16; - char raylib[8] = " "; // raylib text array, max 8 letters int state = 0; // Tracking animation states (State Machine) float alpha = 1.0f; // Useful for fading @@ -2511,17 +2747,6 @@ static void LogoAnimation(void) framesCounter = 0; } - switch (lettersCount) - { - case 1: raylib[0] = 'r'; break; - case 2: raylib[1] = 'a'; break; - case 3: raylib[2] = 'y'; break; - case 4: raylib[3] = 'l'; break; - case 5: raylib[4] = 'i'; break; - case 6: raylib[5] = 'b'; break; - default: break; - } - if (lettersCount >= 10) // When all letters have appeared, just fade out everything { alpha -= 0.02f; @@ -2568,7 +2793,7 @@ static void LogoAnimation(void) DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); - DrawText(raylib, screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha)); + DrawText(SubText("raylib", 0, lettersCount), screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha)); } EndDrawing(); diff --git a/src/gestures.c b/src/gestures.c index ea744555a..e615c06d6 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -1,8 +1,10 @@ /********************************************************************************************** * -* raylib Gestures System - Gestures Detection and Usage Functions (Android and HTML5) +* raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse) * -* Copyright (c) 2015 Marc Palau and Ramon Santamaria +* Initial design by Marc Palau +* Redesigned by Albert Martos and Ian Eito +* Reviewed by Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -29,9 +31,7 @@ #include "raylib.h" // Required for typedef(s): Vector2, Gestures #endif -#include // malloc(), free() -#include // printf(), fprintf() -#include // Used for ... +#include // Used for: atan2(), sqrt() #include // Defines int32_t, int64_t #if defined(_WIN32) @@ -39,72 +39,73 @@ int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); #elif defined(__linux) + #include // Declares storage size of ‘now’ #include // Used for clock functions #endif //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 20 -#define TAP_TIMEOUT 300 -//#define MAX_TOUCH_POINTS 4 +#define FORCE_TO_SWIPE 0.0005f // Measured in normalized pixels / time +#define MINIMUM_DRAG 0.015f // Measured in normalized pixels [0..1] +#define MINIMUM_PINCH 0.005f // Measured in normalized pixels [0..1] +#define TAP_TIMEOUT 300 // Time in milliseconds +#define PINCH_TIMEOUT 300 // Time in milliseconds +#define DOUBLETAP_RANGE 0.03f //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -typedef enum { - TYPE_MOTIONLESS, - TYPE_DRAG, - TYPE_DUAL_INPUT -} GestureType; +// ... //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static GestureType gestureType = TYPE_MOTIONLESS; -static double eventTime = 0; -//static int32_t touchId; // Not used... -// Tap gesture variables -static Vector2 initialTapPosition = { 0, 0 }; +// Touch gesture variables +static Vector2 touchDownPosition = { 0.0f, 0.0f }; +static Vector2 touchDownPosition2 = { 0.0f, 0.0f }; +static Vector2 touchDownDragPosition = { 0.0f, 0.0f }; +static Vector2 touchUpPosition = { 0.0f, 0.0f }; +static Vector2 moveDownPosition = { 0.0f, 0.0f }; +static Vector2 moveDownPosition2 = { 0.0f, 0.0f }; +static int numTap = 0; -// Double Tap gesture variables -static bool doubleTapping = false; -static bool untap = false; // Check if recently done a tap +static int pointCount = 0; +static int touchId = -1; + +static double eventTime = 0.0; +static double swipeTime = 0.0; + +// Hold gesture variables +static int numHold = 0; +static float timeHold = 0.0f; // Drag gesture variables -static Vector2 initialDragPosition = { 0, 0 }; -static Vector2 endDragPosition = { 0, 0 }; -static Vector2 lastDragPosition = { 0, 0 }; -static Vector2 dragVector = { 0, 0 }; - -static float magnitude = 0; // Distance traveled dragging -static float angle = 0; // Angle direction of the drag -static float intensity = 0; // How fast we did the drag (pixels per frame) -static int draggingTimeCounter = 0; // Time that have passed while dragging +static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position) +static float dragAngle = 0.0f; // DRAG angle (relative to x-axis) +static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) (normalized [0..1]) +static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) +static bool startMoving = false; // SWIPE used to define when start measuring swipeTime // Pinch gesture variables -static Vector2 firstInitialPinchPosition = { 0, 0 }; -static Vector2 secondInitialPinchPosition = { 0, 0 }; -static Vector2 firstEndPinchPosition = { 0, 0 }; -static Vector2 secondEndPinchPosition = { 0, 0 }; -static float pinchDelta = 0; // Pinch delta displacement +static Vector2 pinchVector = { 0.0f , 0.0f }; // PINCH vector (between first and second touch points) +static float pinchAngle = 0.0f; // PINCH angle (relative to x-axis) +static float pinchDistance = 0.0f; // PINCH displacement distance (normalized [0..1]) // Detected gestures static int previousGesture = GESTURE_NONE; static int currentGesture = GESTURE_NONE; // Enabled gestures flags, all gestures enabled by default -static unsigned int enabledGestures = 0b0000011111111111; +static unsigned int enabledGestures = 0b0000001111111111; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static void InitPinchGesture(Vector2 posA, Vector2 posB); -static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, float magnitude); -static float VectorDistance(Vector2 v1, Vector2 v2); -static float VectorDotProduct(Vector2 v1, Vector2 v2); -static double GetCurrentTime(); +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); +static float Vector2Distance(Vector2 v1, Vector2 v2); +static double GetCurrentTime(void); //---------------------------------------------------------------------------------- // Module Functions Definition @@ -113,179 +114,185 @@ static double GetCurrentTime(); // Process gesture event and translate it into gestures void ProcessGestureEvent(GestureEvent event) { - // Resets - dragVector = (Vector2){ 0, 0 }; - pinchDelta = 0; - + // Reset required variables previousGesture = currentGesture; - switch (gestureType) - { - case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events + pointCount = event.pointCount; // Required on UpdateGestures() + + if (pointCount < 2) + { + touchId = event.pointerId[0]; + + if (event.touchAction == TOUCH_DOWN) { - if (event.touchAction == TOUCH_DOWN) + numTap++; // Tap counter + + // Detect GESTURE_DOUBLE_TAP + if ((currentGesture == GESTURE_NONE) && (numTap >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) { - if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); - else + currentGesture = GESTURE_DOUBLETAP; + numTap = 0; + } + else // Detect GESTURE_TAP + { + numTap = 1; + currentGesture = GESTURE_TAP; + } + + touchDownPosition = event.position[0]; + touchDownDragPosition = event.position[0]; + + touchUpPosition = touchDownPosition; + eventTime = GetCurrentTime(); + + dragVector = (Vector2){ 0.0f, 0.0f }; + } + else if (event.touchAction == TOUCH_UP) + { + if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0]; + + // NOTE: dragIntensity dependend on the resolution of the screen + dragDistance = Vector2Distance(touchDownPosition, touchUpPosition); + dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime)); + + startMoving = false; + + // Detect GESTURE_SWIPE + if ((dragIntensity > FORCE_TO_SWIPE) && (touchId == 0)) // RAY: why check (touchId == 0)??? + { + // NOTE: Angle should be inverted in Y + dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition); + + if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right + else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up + else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left + else if ((dragAngle > 210) && (dragAngle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down + else currentGesture = GESTURE_NONE; + } + else + { + dragDistance = 0.0f; + dragIntensity = 0.0f; + dragAngle = 0.0f; + + currentGesture = GESTURE_NONE; + } + + touchDownDragPosition = (Vector2){ 0.0f, 0.0f }; + } + else if (event.touchAction == TOUCH_MOVE) + { + if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime(); + + if (!startMoving) + { + swipeTime = GetCurrentTime(); + startMoving = true; + } + + moveDownPosition = event.position[0]; + + if (currentGesture == GESTURE_HOLD) + { + if (numHold == 1) touchDownPosition = event.position[0]; + + numHold = 2; + + // Detect GESTURE_DRAG + if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG) { - // Set the press position - initialTapPosition = event.position[0]; - - // If too much time have passed, we reset the double tap - if (GetCurrentTime() - eventTime > TAP_TIMEOUT) untap = false; - - // If we are in time, we detect the double tap - if (untap) doubleTapping = true; - - // Update our event time eventTime = GetCurrentTime(); - - // Set hold - if (doubleTapping) currentGesture = GESTURE_DOUBLETAP; - else currentGesture = GESTURE_TAP; + currentGesture = GESTURE_DRAG; } } - else if (event.touchAction == TOUCH_UP) - { - currentGesture = GESTURE_NONE; - - // Detect that we are tapping instead of holding - if (GetCurrentTime() - eventTime < TAP_TIMEOUT) - { - if (doubleTapping) untap = false; - else untap = true; - } - - // Tap finished - doubleTapping = false; - - // Update our event time - eventTime = GetCurrentTime(); - } - // Begin dragging - else if (event.touchAction == TOUCH_MOVE) - { - if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); - else - { - // Set the drag starting position - initialDragPosition = initialTapPosition; - endDragPosition = initialDragPosition; - - // Initialize drag - draggingTimeCounter = 0; - gestureType = TYPE_DRAG; - currentGesture = GESTURE_NONE; - } - } - } break; - case TYPE_DRAG: // Detect DRAG and SWIPE events + + dragVector.x = moveDownPosition.x - touchDownDragPosition.x; + dragVector.y = moveDownPosition.y - touchDownDragPosition.y; + } + } + else // Two touch points + { + if (event.touchAction == TOUCH_DOWN) { - // end of the drag - if (event.touchAction == TOUCH_UP) - { - // Return Swipe if we have enough sensitivity - if (intensity > FORCE_TO_SWIPE) - { - if (angle < 30 || angle > 330) currentGesture = GESTURE_SWIPE_RIGHT; // Right - else if (angle > 60 && angle < 120) currentGesture = GESTURE_SWIPE_UP; // Up - else if (angle > 150 && angle < 210) currentGesture = GESTURE_SWIPE_LEFT; // Left - else if (angle > 240 && angle < 300) currentGesture = GESTURE_SWIPE_DOWN; // Down - } - - magnitude = 0; - angle = 0; - intensity = 0; - - gestureType = TYPE_MOTIONLESS; - } - // Update while we are dragging - else if (event.touchAction == TOUCH_MOVE) - { - if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); - else - { - lastDragPosition = endDragPosition; - endDragPosition = event.position[0]; - - //endDragPosition.x = AMotionEvent_getX(event, 0); - //endDragPosition.y = AMotionEvent_getY(event, 0); - - // Calculate attributes - dragVector = (Vector2){ endDragPosition.x - lastDragPosition.x, endDragPosition.y - lastDragPosition.y }; - magnitude = sqrt(pow(endDragPosition.x - initialDragPosition.x, 2) + pow(endDragPosition.y - initialDragPosition.y, 2)); - angle = CalculateAngle(initialDragPosition, endDragPosition, magnitude); - intensity = magnitude / (float)draggingTimeCounter; - - // Check if drag movement is less than minimum to keep it as hold state or switch to drag state - if(magnitude > FORCE_TO_SWIPE) - { - currentGesture = GESTURE_DRAG; - draggingTimeCounter++; - } - else currentGesture = GESTURE_HOLD; - } - } - } break; - case TYPE_DUAL_INPUT: + touchDownPosition = event.position[0]; + touchDownPosition2 = event.position[1]; + + //pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2); + + pinchVector.x = touchDownPosition2.x - touchDownPosition.x; + pinchVector.y = touchDownPosition2.y - touchDownPosition.y; + + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + } + else if (event.touchAction == TOUCH_MOVE) { - if (event.touchAction == TOUCH_UP) + pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2); + + touchDownPosition = moveDownPosition; + touchDownPosition2 = moveDownPosition2; + + moveDownPosition = event.position[0]; + moveDownPosition2 = event.position[1]; + + pinchVector.x = moveDownPosition2.x - moveDownPosition.x; + pinchVector.y = moveDownPosition2.y - moveDownPosition.y; + + if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH)) { - if (event.pointCount == 1) - { - // Set the drag starting position - initialTapPosition = event.position[0]; - } - gestureType = TYPE_MOTIONLESS; + if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN; + else currentGesture = GESTURE_PINCH_OUT; } - else if (event.touchAction == TOUCH_MOVE) + else { - // Adapt the ending position of the inputs - firstEndPinchPosition = event.position[0]; - secondEndPinchPosition = event.position[1]; - - // If there is no more than two inputs - if (event.pointCount == 2) - { - // Calculate distances - float initialDistance = VectorDistance(firstInitialPinchPosition, secondInitialPinchPosition); - float endDistance = VectorDistance(firstEndPinchPosition, secondEndPinchPosition); - - // Calculate Vectors - Vector2 firstTouchVector = { firstEndPinchPosition.x - firstInitialPinchPosition.x, firstEndPinchPosition.y - firstInitialPinchPosition.y }; - Vector2 secondTouchVector = { secondEndPinchPosition.x - secondInitialPinchPosition.x, secondEndPinchPosition.y - secondInitialPinchPosition.y }; - - // Detect the pinch gesture - if (VectorDotProduct(firstTouchVector, secondTouchVector) < -0.5) pinchDelta = initialDistance - endDistance; - else pinchDelta = 0; - - // Pinch gesture resolution - if (pinchDelta != 0) - { - if (pinchDelta > 0) currentGesture = GESTURE_PINCH_IN; - else currentGesture = GESTURE_PINCH_OUT; - } - } - else - { - // Set the drag starting position - initialTapPosition = event.position[0]; - - gestureType = TYPE_MOTIONLESS; - } - - // Readapt the initial position of the inputs - firstInitialPinchPosition = firstEndPinchPosition; - secondInitialPinchPosition = secondEndPinchPosition; + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); } - } break; + + // NOTE: Angle should be inverted in Y + pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2); + } + else if (event.touchAction == TOUCH_UP) + { + pinchDistance = 0.0f; + pinchAngle = 0.0f; + pinchVector = (Vector2){ 0.0f, 0.0f }; + + currentGesture = GESTURE_NONE; + } + } +} + +// Update gestures detected (must be called every frame) +void UpdateGestures(void) +{ + // NOTE: Gestures are processed through system callbacks on touch events + + // Detect GESTURE_HOLD + if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && (pointCount < 2)) + { + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + } + + if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2)) + { + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + numHold = 1; + } + + // Detect GESTURE_NONE + if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN)) + { + currentGesture = GESTURE_NONE; } } // Check if a gesture have been detected bool IsGestureDetected(void) { - if (currentGesture != GESTURE_NONE) return true; + if ((enabledGestures & currentGesture) != GESTURE_NONE) return true; else return false; } @@ -296,124 +303,86 @@ int GetGestureType(void) return (enabledGestures & currentGesture); } -void SetGesturesEnabled(unsigned int gestureFlags) +// Get number of touch points +int GetTouchPointsCount(void) { - enabledGestures = enabledGestures | gestureFlags; + // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called + + return pointCount; } -// Get drag intensity (pixels per frame) -float GetGestureDragIntensity(void) +// Enable only desired getures to be detected +void SetGesturesEnabled(unsigned int gestureFlags) { - return intensity; + enabledGestures = gestureFlags; +} + +// Hold time measured in ms +float GetGestureHoldDuration(void) +{ + // NOTE: time is calculated on current gesture HOLD + + float time = 0.0f; + + if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold; + + return time; +} + +// Get drag vector (between initial touch point to current) +Vector2 GetGestureDragVector(void) +{ + // NOTE: drag vector is calculated on one touch points TOUCH_MOVE + + return dragVector; } // Get drag angle // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGestureDragAngle(void) { - return angle; + // NOTE: drag angle is calculated on one touch points TOUCH_UP + + return dragAngle; } -// Get drag vector (between initial and final position) -Vector2 GetGestureDragVector(void) +// Get distance between two pinch points +Vector2 GetGesturePinchVector(void) { - return dragVector; -} - -// Hold time measured in frames -int GetGestureHoldDuration(void) -{ - return 0; -} - -// Get magnitude between two pinch points -float GetGesturePinchDelta(void) -{ - return pinchDelta; + // NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index) + // NOTE: pinch distance is calculated on two touch points TOUCH_MOVE + + return pinchVector; } // Get angle beween two pinch points // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGesturePinchAngle(void) { - return 0; -} - -// Update gestures detected (must be called every frame) -void UpdateGestures(void) -{ - // NOTE: Gestures are processed through system callbacks on touch events + // NOTE: pinch angle is calculated on two touch points TOUCH_MOVE - // When screen is touched, in first frame GESTURE_TAP is called but in next frame touch event callback is not called (if touch position doesn't change), - // so we need to store previous frame gesture type manually in this update function to switch to HOLD if current gesture is - // GESTURE_TAP two frames in a row. Due to current gesture is set to HOLD, current gesture doesn't need to be reset to NONE every frame. - // It will be reset when UP is called. - if(currentGesture == GESTURE_TAP) previousGesture = currentGesture; - - if(previousGesture == GESTURE_TAP && currentGesture == GESTURE_TAP) currentGesture = GESTURE_HOLD; + return pinchAngle; } //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- -static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, float magnitude) +// Returns angle from two-points vector with X-axis +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition) { float angle; - - // Calculate arcsinus of the movement - angle = asin((finalPosition.y - initialPosition.y)/magnitude); + + angle = atan2(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x); angle *= RAD2DEG; - // Calculate angle depending on the sector - if ((finalPosition.x - initialPosition.x) >= 0) - { - // Sector 4 - if ((finalPosition.y - initialPosition.y) >= 0) - { - angle *= -1; - angle += 360; - } - // Sector 1 - else angle *= -1; - } - else - { - // Sector 3 - if ((finalPosition.y - initialPosition.y) >= 0) angle += 180; - // Sector 2 - else - { - angle *= -1; - angle = 180 - angle; - } - } - + if (angle < 0) angle += 360.0f; + return angle; } -static void InitPinchGesture(Vector2 posA, Vector2 posB) -{ - initialDragPosition = (Vector2){ 0, 0 }; - endDragPosition = (Vector2){ 0, 0 }; - lastDragPosition = (Vector2){ 0, 0 }; - - // Initialize positions - firstInitialPinchPosition = posA; - secondInitialPinchPosition = posB; - - firstEndPinchPosition = firstInitialPinchPosition; - secondEndPinchPosition = secondInitialPinchPosition; - - // Resets - magnitude = 0; - angle = 0; - intensity = 0; - - gestureType = TYPE_DUAL_INPUT; -} - -static float VectorDistance(Vector2 v1, Vector2 v2) +// Calculate distance between two Vector2 +static float Vector2Distance(Vector2 v1, Vector2 v2) { float result; @@ -425,22 +394,8 @@ static float VectorDistance(Vector2 v1, Vector2 v2) return result; } -static float VectorDotProduct(Vector2 v1, Vector2 v2) -{ - float result; - - float v1Module = sqrt(v1.x*v1.x + v1.y*v1.y); - float v2Module = sqrt(v2.x*v2.x + v2.y*v2.y); - - Vector2 v1Normalized = { v1.x / v1Module, v1.y / v1Module }; - Vector2 v2Normalized = { v2.x / v2Module, v2.y / v2Module }; - - result = v1Normalized.x*v2Normalized.x + v1Normalized.y*v2Normalized.y; - - return result; -} - -static double GetCurrentTime() +// Time measure returned are milliseconds +static double GetCurrentTime(void) { double time = 0; @@ -450,16 +405,16 @@ static double GetCurrentTime() QueryPerformanceFrequency(&clockFrequency); QueryPerformanceCounter(¤tTime); - time = (double)currentTime/clockFrequency*1000.0f; // time in miliseconds + time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds #endif #if defined(__linux) // NOTE: Only for Linux-based systems struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time provided in nanoseconds + uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds - time = ((double)nowTime/1000000.0); // time in miliseconds + time = ((double)nowTime/1000000.0); // Time in miliseconds #endif return time; diff --git a/src/gestures.h b/src/gestures.h index b5cf2767c..5468eb545 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -90,19 +90,20 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- +void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) bool IsGestureDetected(void); // Check if a gesture have been detected int GetGestureType(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures +int GetTouchPointsCount(void); // Get touch points count -float GetGestureDragIntensity(void); // Get gesture drag intensity -float GetGestureDragAngle(void); // Get gesture drag angle +float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector -int GetGestureHoldDuration(void); // Get gesture hold time in frames -float GetGesturePinchDelta(void); // Get gesture pinch delta +float GetGestureDragAngle(void); // Get gesture drag angle +Vector2 GetGesturePinchVector(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle + #ifdef __cplusplus } #endif diff --git a/src/libraylib.bc b/src/libraylib.bc new file mode 100644 index 000000000..21039250f Binary files /dev/null and b/src/libraylib.bc differ diff --git a/src/makefile b/src/makefile index 70fbca7cc..cab2ced06 100644 --- a/src/makefile +++ b/src/makefile @@ -91,7 +91,13 @@ else endif # define all object files required -OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o camera.o gestures.o stb_vorbis.o +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + OBJS = core.o rlgl.o glad.o shapes.o text.o textures.o models.o audio.o utils.o camera.o gestures.o stb_vorbis.o +else + #GLAD only required on desktop platform + OBJS = core.o rlgl.o shapes.o text.o textures.o models.o audio.o stb_vorbis.o utils.o camera.o gestures.o +endif + # typing 'make' will invoke the first target entry in the file, # in this case, the 'default' target entry is raylib @@ -114,9 +120,9 @@ core.o: core.c rlgl.o: rlgl.c $(CC) -c rlgl.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(GRAPHICS) -# compile raymath module -raymath.o: raymath.c - $(CC) -c raymath.c $(CFLAGS) $(INCLUDES) +# compile glad module +glad.o: glad.c + $(CC) -c glad.c $(CFLAGS) $(INCLUDES) # compile shapes module shapes.o: shapes.c diff --git a/src/models.c b/src/models.c index 80d9a13a5..8a36c2799 100644 --- a/src/models.c +++ b/src/models.c @@ -55,7 +55,6 @@ extern unsigned int whiteTexture; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static float GetHeightValue(Color pixel); static Mesh LoadOBJ(const char *fileName); //---------------------------------------------------------------------------------- @@ -557,7 +556,7 @@ void DrawGizmo(Vector3 position) // Load a 3d model (from file) Model LoadModel(const char *fileName) { - Model model; + Model model = { 0 }; Mesh mesh = { 0 }; // NOTE: Initialize default data for model in case loading fails, maybe a cube? @@ -608,17 +607,19 @@ Model LoadModelEx(Mesh data) } // Load a heightmap image as a 3d model -Model LoadHeightmap(Image heightmap, float maxHeight) +// NOTE: model map size is defined in generic units +Model LoadHeightmap(Image heightmap, Vector3 size) { + #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3) + Mesh mesh; int mapX = heightmap.width; int mapZ = heightmap.height; - Color *heightmapPixels = GetImageData(heightmap); + Color *pixels = GetImageData(heightmap); // NOTE: One vertex per pixel - // TODO: Consider resolution when generating model data? int numTriangles = (mapX-1)*(mapZ-1)*2; // One quad every four pixels mesh.vertexCount = numTriangles*3; @@ -634,7 +635,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight) int trisCounter = 0; - float scaleFactor = maxHeight/255; // TODO: Review scaleFactor calculation + Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ }; for(int z = 0; z < mapZ-1; z++) { @@ -644,17 +645,17 @@ Model LoadHeightmap(Image heightmap, float maxHeight) //---------------------------------------------------------- // one triangle - 3 vertex - mesh.vertices[vCounter] = x; - mesh.vertices[vCounter + 1] = GetHeightValue(heightmapPixels[x + z*mapX])*scaleFactor; - mesh.vertices[vCounter + 2] = z; + mesh.vertices[vCounter] = (float)x*scaleFactor.x; + mesh.vertices[vCounter + 1] = (float)GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y; + mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z; - mesh.vertices[vCounter + 3] = x; - mesh.vertices[vCounter + 4] = GetHeightValue(heightmapPixels[x + (z+1)*mapX])*scaleFactor; - mesh.vertices[vCounter + 5] = z+1; + mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x; + mesh.vertices[vCounter + 4] = (float)GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y; + mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z; - mesh.vertices[vCounter + 6] = x+1; - mesh.vertices[vCounter + 7] = GetHeightValue(heightmapPixels[(x+1) + z*mapX])*scaleFactor; - mesh.vertices[vCounter + 8] = z; + mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x; + mesh.vertices[vCounter + 7] = (float)GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y; + mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z; // another triangle - 3 vertex mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6]; @@ -665,21 +666,21 @@ Model LoadHeightmap(Image heightmap, float maxHeight) mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4]; mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5]; - mesh.vertices[vCounter + 15] = x+1; - mesh.vertices[vCounter + 16] = GetHeightValue(heightmapPixels[(x+1) + (z+1)*mapX])*scaleFactor; - mesh.vertices[vCounter + 17] = z+1; + mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x; + mesh.vertices[vCounter + 16] = (float)GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y; + mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z; vCounter += 18; // 6 vertex, 18 floats // Fill texcoords array with data //-------------------------------------------------------------- - mesh.texcoords[tcCounter] = (float)x / (mapX-1); - mesh.texcoords[tcCounter + 1] = (float)z / (mapZ-1); + mesh.texcoords[tcCounter] = (float)x/(mapX - 1); + mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1); - mesh.texcoords[tcCounter + 2] = (float)x / (mapX-1); - mesh.texcoords[tcCounter + 3] = (float)(z+1) / (mapZ-1); + mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1); + mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1); - mesh.texcoords[tcCounter + 4] = (float)(x+1) / (mapX-1); - mesh.texcoords[tcCounter + 5] = (float)z / (mapZ-1); + mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1); + mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1); mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4]; mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5]; @@ -687,13 +688,12 @@ Model LoadHeightmap(Image heightmap, float maxHeight) mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2]; mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3]; - mesh.texcoords[tcCounter + 10] = (float)(x+1) / (mapX-1); - mesh.texcoords[tcCounter + 11] = (float)(z+1) / (mapZ-1); + mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1); + mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1); tcCounter += 12; // 6 texcoords, 12 floats // Fill normals array with data //-------------------------------------------------------------- - // NOTE: Current Model implementation doe not use normals! for (int i = 0; i < 18; i += 3) { mesh.normals[nCounter + i] = 0.0f; @@ -704,12 +704,11 @@ Model LoadHeightmap(Image heightmap, float maxHeight) // TODO: Calculate normals in an efficient way nCounter += 18; // 6 vertex, 18 floats - trisCounter += 2; } } - free(heightmapPixels); + free(pixels); // Fill color data // NOTE: Not used any more... just one plain color defined at DrawModel() @@ -1149,14 +1148,14 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint) Vector3 vScale = { scale, scale, scale }; Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; - DrawModelEx(model, position, 0.0f, rotationAxis, vScale, tint); + DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint); } // Draw a model with extended parameters -void DrawModelEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint) +void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) { // NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel() - rlglDrawModel(model, position, rotationAngle, rotationAxis, scale, tint, false); + rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, false); } // Draw a model wires (with texture if set) @@ -1165,14 +1164,14 @@ void DrawModelWires(Model model, Vector3 position, float scale, Color color) Vector3 vScale = { scale, scale, scale }; Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; - rlglDrawModel(model, position, 0.0f, rotationAxis, vScale, color, true); + rlglDrawModel(model, position, rotationAxis, 0.0f, vScale, color, true); } // Draw a model wires (with texture if set) with extended parameters -void DrawModelWiresEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint) +void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) { // NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel() - rlglDrawModel(model, position, rotationAngle, rotationAxis, scale, tint, true); + rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, true); } // Draw a billboard @@ -1275,6 +1274,20 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec rlDisableTexture(); } +// Draw a bounding box with wires +void DrawBoundingBox(BoundingBox box) +{ + Vector3 size; + + size.x = fabsf(box.max.x - box.min.x); + size.y = fabsf(box.max.y - box.min.y); + size.z = fabsf(box.max.z - box.min.z); + + Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f }; + + DrawCubeWires(center, size.x, size.y, size.z, GREEN); +} + // Detect collision between two spheres bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB) { @@ -1401,10 +1414,8 @@ bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox) return collision; } -// TODO: Useful function to check collision area? -//BoundingBox GetCollisionArea(BoundingBox box1, BoundingBox box2) - // Calculate mesh bounding box limits +// NOTE: minVertex and maxVertex should be transformed by model transform matrix (position, scale, rotate) BoundingBox CalculateBoundingBox(Mesh mesh) { // Get min and max vertex to construct bounds (AABB) @@ -1413,15 +1424,10 @@ BoundingBox CalculateBoundingBox(Mesh mesh) for (int i = 1; i < mesh.vertexCount; i++) { - // TODO: Compare min and max with previous vertex - //minVertex = Vector3.Min(minVertex, mesh.vertices[i]); - //maxVertex = Vector3.Max(maxVertex, mesh.vertices[i]); + minVertex = VectorMin(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); + maxVertex = VectorMax(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); } - - // NOTE: For OBB, transform mesh by model transform matrix - //minVertex = VectorTransform(meshMin, mesh.transform); - //maxVertex = VectorTransform(meshMax, mesh.transform); - + // Create the bounding box BoundingBox box; box.min = minVertex; @@ -1681,12 +1687,6 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p // Module specific Functions Definition //---------------------------------------------------------------------------------- -// Get current vertex y altitude (proportional to pixel colors in grayscale) -static float GetHeightValue(Color pixel) -{ - return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3); -} - // Load OBJ mesh data static Mesh LoadOBJ(const char *fileName) { diff --git a/src/physac.c b/src/physac.c index 891f01234..4c50dd41b 100644 --- a/src/physac.c +++ b/src/physac.c @@ -30,13 +30,12 @@ #endif #include -#include +#include // Required for: malloc(), free() //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define MAX_ELEMENTS 1024 // Stored rigidbodies and colliders array length -#define DECIMAL_FIX 0.26f // Decimal margin for collision checks (avoid rigidbodies shake) +#define DECIMAL_FIX 0.26f // Decimal margin for collision checks (avoid rigidbodies shake) //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -46,10 +45,13 @@ //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static Physics physics; -static Collider colliders[MAX_ELEMENTS]; -static Rigidbody rigidbodies[MAX_ELEMENTS]; -static bool collisionChecker = false; +static Collider *colliders; // Colliders array, dynamically allocated at runtime +static Rigidbody *rigidbodies; // Rigitbody array, dynamically allocated at runtime +static bool collisionChecker; + +static int maxElements; // Max physic elements to compute +static bool enabled; // Physics enabled? (true by default) +static Vector2 gravity; // Gravity value used for physic calculations //---------------------------------------------------------------------------------- // Module specific Functions Declarations @@ -61,30 +63,39 @@ static void Vector2Normalize(Vector2 *vector); //---------------------------------------------------------------------------------- // Module Functions Definitions //---------------------------------------------------------------------------------- -void InitPhysics(void) -{ - for (int i = 0; i < MAX_ELEMENTS; i++) +void InitPhysics(int maxPhysicElements) +{ + maxElements = maxPhysicElements; + + colliders = (Collider *)malloc(maxElements*sizeof(Collider)); + rigidbodies = (Rigidbody *)malloc(maxElements*sizeof(Rigidbody)); + + for (int i = 0; i < maxElements; i++) { + colliders[i].enabled = false; + colliders[i].bounds = (Rectangle){ 0, 0, 0, 0 }; + colliders[i].radius = 0; + rigidbodies[i].enabled = false; rigidbodies[i].mass = 0.0f; - rigidbodies[i].velocity = (Vector2){0, 0}; - rigidbodies[i].acceleration = (Vector2){0, 0}; + rigidbodies[i].velocity = (Vector2){ 0.0f, 0.0f }; + rigidbodies[i].acceleration = (Vector2){ 0.0f, 0.0f }; rigidbodies[i].isGrounded = false; rigidbodies[i].isContact = false; rigidbodies[i].friction = 0.0f; - - colliders[i].enabled = false; - colliders[i].bounds = (Rectangle){0, 0, 0, 0}; - colliders[i].radius = 0; } + + collisionChecker = false; + enabled = true; + + // NOTE: To get better results, gravity needs to be 1:10 from original parameter + gravity = (Vector2){ 0.0f, -9.81f/10.0f }; // By default, standard gravity } -void SetPhysics(Physics settings) +void UnloadPhysics() { - physics = settings; - - // To get good results, gravity needs to be 1:10 from original parameter - physics.gravity = (Vector2){physics.gravity.x / 10, physics.gravity.y / 10}; + free(colliders); + free(rigidbodies); } void AddCollider(int index, Collider collider) @@ -159,8 +170,8 @@ void ApplyPhysics(int index, Vector2 *position) } // Apply gravity - rigidbodies[index].velocity.y += physics.gravity.y; - rigidbodies[index].velocity.x += physics.gravity.x; + rigidbodies[index].velocity.y += gravity.y; + rigidbodies[index].velocity.x += gravity.x; // Apply acceleration rigidbodies[index].velocity.y += rigidbodies[index].acceleration.y; @@ -177,7 +188,7 @@ void ApplyPhysics(int index, Vector2 *position) // Check collision with other colliders collisionChecker = false; rigidbodies[index].isContact = false; - for (int j = 0; j < MAX_ELEMENTS; j++) + for (int j = 0; j < maxElements; j++) { if (index != j) { @@ -269,7 +280,7 @@ void AddRigidbodyForce(int index, Vector2 force) void AddForceAtPosition(Vector2 position, float intensity, float radius) { - for(int i = 0; i < MAX_ELEMENTS; i++) + for(int i = 0; i < maxElements; i++) { if(rigidbodies[i].enabled) { diff --git a/src/physac.h b/src/physac.h index 12209987e..9e1b0b88b 100644 --- a/src/physac.h +++ b/src/physac.h @@ -35,13 +35,6 @@ // Collider types typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType; -// Physics struct -typedef struct Physics { - bool enabled; - bool debug; // Should be used by programmer for testing purposes - Vector2 gravity; -} Physics; - // Transform struct typedef struct Transform { Vector2 position; @@ -77,8 +70,8 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declarations //---------------------------------------------------------------------------------- -void InitPhysics(void); // Initialize all internal physics values -void SetPhysics(Physics settings); // Set physics settings values using Physics data type to overwrite internal physics settings +void InitPhysics(int maxPhysicElements); // Initialize all internal physics values +void UnloadPhysics(); // Unload physic elements arrays void AddRigidbody(int index, Rigidbody rigidbody); // Initialize a new rigidbody with parameters to internal index slot void AddCollider(int index, Collider collider); // Initialize a new Collider with parameters to internal index slot diff --git a/src/raygui.c b/src/raygui.c index 2c68c96f7..60df21217 100644 --- a/src/raygui.c +++ b/src/raygui.c @@ -2,7 +2,8 @@ * * raygui - raylib IMGUI system (Immedite Mode GUI) * -* Copyright (c) 2015 Kevin Gato, Daniel Nicolás, Sergio Martinez and Ramon Santamaria +* Initial design by Kevin Gato and Daniel Nicolás +* Reviewed by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -856,10 +857,6 @@ char *GuiTextBox(Rectangle bounds, char *text) return text; } -// TODO: GuiBox? -// TODO: GuiWindow? -// TODO: GuiPanel? - // Save current GUI style into a text file void SaveGuiStyle(const char *fileName) { @@ -873,12 +870,14 @@ void SaveGuiStyle(const char *fileName) // Load GUI style from a text file void LoadGuiStyle(const char *fileName) { + #define MAX_STYLE_PROPERTIES 128 + typedef struct { char id[64]; int value; } StyleProperty; - StyleProperty *styleProp = (StyleProperty *)malloc(128*sizeof(StyleProperty));; + StyleProperty *styleProp = (StyleProperty *)malloc(MAX_STYLE_PROPERTIES*sizeof(StyleProperty));; int counter = 0; FILE *styleFile = fopen(fileName, "rt"); diff --git a/src/raylib.h b/src/raylib.h index bebf4bc56..c598ec303 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -7,10 +7,10 @@ * Features: * Library written in plain C code (C99) * Uses C# PascalCase/camelCase notation -* Hardware accelerated with OpenGL (1.1, 3.3+ or ES2) +* Hardware accelerated with OpenGL (1.1, 3.3 or ES2) * Unique OpenGL abstraction layer [rlgl] -* Powerful fonts module with SpriteFonts support -* Multiple textures support, including DDS and mipmaps generation +* Powerful fonts module with SpriteFonts support (including AngelCode fonts and TTF) +* Multiple textures support, including compressed formats and mipmaps generation * Basic 3d support for Shapes, Models, Heightmaps and Billboards * Powerful math module for Vector and Matrix operations [raymath] * Audio loading and playing with streaming support (WAV and OGG) @@ -18,20 +18,21 @@ * * Used external libs: * GLFW3 (www.glfw.org) for window/context management and input -* GLEW for OpenGL extensions loading (3.3+ and ES2) +* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) * stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) * stb_image_write (Sean Barret) for image writting (PNG) * stb_vorbis (Sean Barret) for ogg audio loading +* stb_truetype (Sean Barret) for ttf fonts loading * OpenAL Soft for audio device/context management * tinfl for data decompression (DEFLATE algorithm) * * Some design decisions: -* 32bit Colors - All defined color are always RGBA -* SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures +* 32bit Colors - All defined color are always RGBA (struct Color is 4 byte) * One custom default font is loaded automatically when InitWindow() -* If using OpenGL 3.3+ or ES2, one default shader is loaded automatically (internally defined) +* If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads +* If using OpenGL 3.3 or ES2, two default shaders are loaded automatically (internally defined) * -* -- LICENSE (raylib v1.2, September 2014) -- +* -- LICENSE -- * * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: @@ -80,8 +81,8 @@ #define PI 3.14159265358979323846 #endif -#define DEG2RAD (PI / 180.0f) -#define RAD2DEG (180.0f / PI) +#define DEG2RAD (PI/180.0f) +#define RAD2DEG (180.0f/PI) // raylib Config Flags #define FLAG_FULLSCREEN_MODE 1 @@ -110,6 +111,8 @@ #define KEY_F8 297 #define KEY_F9 298 #define KEY_F10 299 +#define KEY_F11 300 +#define KEY_F12 301 #define KEY_LEFT_SHIFT 340 #define KEY_LEFT_CONTROL 341 #define KEY_LEFT_ALT 342 @@ -117,7 +120,7 @@ #define KEY_RIGHT_CONTROL 345 #define KEY_RIGHT_ALT 346 -// Keyboard Alhpa Numeric Keys +// Keyboard Alpha Numeric Keys #define KEY_ZERO 48 #define KEY_ONE 49 #define KEY_TWO 50 @@ -165,6 +168,9 @@ #define MOUSE_MIDDLE_BUTTON 2 #endif +// Touch points registered +#define MAX_TOUCH_POINTS 2 + // Gamepad Number #define GAMEPAD_PLAYER1 0 #define GAMEPAD_PLAYER2 1 @@ -347,9 +353,6 @@ typedef struct Shader { // Uniforms int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - - int modelLoc; // Model transformation matrix uniform location point (vertex shader) - int viewLoc; // View transformation matrix uniform location point (vertex shader) int tintColorLoc; // Color uniform location point (fragment shader) int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader) @@ -357,12 +360,31 @@ typedef struct Shader { int mapSpecularLoc; // Specular map texture uniform location point (fragment shader) } Shader; +// Material type +// TODO: Redesign material-shaders-textures system +typedef struct Material { + //Shader shader; + + //Texture2D texDiffuse; // Diffuse texture + //Texture2D texNormal; // Normal texture + //Texture2D texSpecular; // Specular texture + + Color colDiffuse; + Color colAmbient; + Color colSpecular; + + float glossiness; + float normalDepth; +} Material; + // 3d Model type +// TODO: Replace shader/testure by material typedef struct Model { Mesh mesh; Matrix transform; Texture2D texture; // Only for OpenGL 1.1, on newer versions this should be in the shader Shader shader; + //Material material; } Model; // Ray type (useful for raycast) @@ -386,26 +408,6 @@ typedef struct Wave { short channels; } Wave; -// Light type -typedef struct Light { - Vector3 position; - Vector3 direction; - float intensity; - float specIntensity; - Color diffuse; - Color ambient; - Color specular; -} Light; - -// Material type -typedef struct Material { - Color diffuse; - Color ambient; - Color specular; - float glossiness; - float normalDepth; -} Material; - // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { @@ -435,28 +437,29 @@ typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; // Gestures type // NOTE: It could be used as flags to enable only some gestures typedef enum { - GESTURE_NONE = 1, - GESTURE_TAP = 2, - GESTURE_DOUBLETAP = 4, - GESTURE_HOLD = 8, - GESTURE_DRAG = 16, - GESTURE_SWIPE_RIGHT = 32, - GESTURE_SWIPE_LEFT = 64, - GESTURE_SWIPE_UP = 128, - GESTURE_SWIPE_DOWN = 256, - GESTURE_PINCH_IN = 512, - GESTURE_PINCH_OUT = 1024 + GESTURE_NONE = 0, + GESTURE_TAP = 1, + GESTURE_DOUBLETAP = 2, + GESTURE_HOLD = 4, + GESTURE_DRAG = 8, + GESTURE_SWIPE_RIGHT = 16, + GESTURE_SWIPE_LEFT = 32, + GESTURE_SWIPE_UP = 64, + GESTURE_SWIPE_DOWN = 128, + GESTURE_PINCH_IN = 256, + GESTURE_PINCH_OUT = 512 } Gestures; +// Touch action (fingers or mouse) typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; // Gesture events -// NOTE: MAX_TOUCH_POINTS fixed to 4 +// NOTE: MAX_TOUCH_POINTS fixed to 2 typedef struct { int touchAction; int pointCount; - int pointerId[4]; - Vector2 position[4]; + int pointerId[MAX_TOUCH_POINTS]; + Vector2 position[MAX_TOUCH_POINTS]; } GestureEvent; // Camera system modes @@ -465,13 +468,6 @@ typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERS // Collider types typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType; -// Physics struct -typedef struct Physics { - bool enabled; - bool debug; // Should be used by programmer for testing purposes - Vector2 gravity; -} Physics; - // Transform struct typedef struct Transform { Vector2 position; @@ -534,11 +530,12 @@ void BeginDrawing(void); // Setup drawing can void BeginDrawingEx(int blendMode, Shader shader, Matrix transform); // Setup drawing canvas with extended parameters void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering) -void Begin3dMode(Camera cam); // Initializes 3D mode for drawing (Camera setup) +void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup) void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position Vector2 WorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position +Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) void SetTargetFPS(int fps); // Set target FPS (maximum) float GetFPS(void); // Returns current FPS @@ -585,10 +582,10 @@ int GetMouseWheelMove(void); // Returns mouse wheel m void ShowCursor(void); // Shows cursor void HideCursor(void); // Hides cursor +void EnableCursor(void); // Enables cursor +void DisableCursor(void); // Disables cursor bool IsCursorHidden(void); // Returns true if cursor is not visible -#endif -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available Vector2 GetGamepadMovement(int gamepad); // Return axis movement vector for a gamepad bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once @@ -597,30 +594,31 @@ bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad b bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) -int GetTouchX(void); // Returns touch position X (relative to screen size) -int GetTouchY(void); // Returns touch position Y (relative to screen size) -Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size) +int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size) +int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) +Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) + +#if defined(PLATFORM_ANDROID) bool IsButtonPressed(int button); // Detect if an android physic button has been pressed bool IsButtonDown(int button); // Detect if an android physic button is being pressed bool IsButtonReleased(int button); // Detect if an android physic button has been released +#endif //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ +void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) bool IsGestureDetected(void); // Check if a gesture have been detected int GetGestureType(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures +int GetTouchPointsCount(void); // Get touch points count -float GetGestureDragIntensity(void); // Get gesture drag intensity -float GetGestureDragAngle(void); // Get gesture drag angle +float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector -int GetGestureHoldDuration(void); // Get gesture hold time in frames -float GetGesturePinchDelta(void); // Get gesture pinch delta +float GetGestureDragAngle(void); // Get gesture drag angle +Vector2 GetGesturePinchVector(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle -#endif //------------------------------------------------------------------------------------ // Camera System Functions (Module: camera) @@ -699,7 +697,7 @@ void ImageFlipVertical(Image *image); void ImageFlipHorizontal(Image *image); // Flip image horizontally void ImageColorTint(Image *image, Color color); // Modify image color: tint void ImageColorInvert(Image *image); // Modify image color: invert -void ImageColorGrayscale(Image *image); // Modify bimage color: grayscale +void ImageColorGrayscale(Image *image); // Modify image color: grayscale void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture @@ -754,19 +752,21 @@ void DrawGizmo(Vector3 position); Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) Model LoadModelEx(Mesh data); // Load a 3d model (from vertex data) //Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource) -Model LoadHeightmap(Image heightmap, float maxHeight); // Load a heightmap image as a 3d model +Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) void UnloadModel(Model model); // Unload 3d model from memory void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) -void DrawModelEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint); // Draw a model with extended parameters +void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set) -void DrawModelWiresEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +void DrawBoundingBox(BoundingBox box); // Draw bounding box (wires) void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec +BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, Vector3 maxBBox2); // Detect collision between two boxes bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere @@ -775,7 +775,6 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox); // Detect collision between ray and box Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap // NOTE: Return the normal vector of the impacted surface - //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 @@ -792,6 +791,7 @@ bool IsPosproShaderEnabled(void); // Check if int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) +void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) void SetShaderMapDiffuse(Shader *shader, Texture2D texture); // Default diffuse shader map texture assignment void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture); // Normal map texture shader assignment void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture); // Specular map texture shader assignment @@ -800,10 +800,10 @@ void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textur void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) //---------------------------------------------------------------------------------- -// Physics System Functions (engine-module: physics) +// Physics System Functions (engine-module: physac) //---------------------------------------------------------------------------------- -void InitPhysics(void); // Initialize all internal physics values -void SetPhysics(Physics settings); // Set physics settings values using Physics data type to overwrite internal physics settings +void InitPhysics(int maxPhysicElements); // Initialize all internal physics values +void UnloadPhysics(); // Unload physic elements arrays void AddRigidbody(int index, Rigidbody rigidbody); // Initialize a new rigidbody with parameters to internal index slot void AddCollider(int index, Collider collider); // Initialize a new Collider with parameters to internal index slot diff --git a/src/raymath.h b/src/raymath.h index f54485042..35cee39f8 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -126,6 +126,8 @@ RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount); // Calculate lin RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal); // Calculate reflected vector to normal RMDEF void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Vector3 by a given Matrix RMDEF Vector3 VectorZero(void); // Return a Vector3 init to zero +RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2); // Return min value for each pair of components +RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2); // Return max value for each pair of components //------------------------------------------------------------------------------------ // Functions Declaration to work with Matrix @@ -139,7 +141,7 @@ RMDEF Matrix MatrixIdentity(void); // Returns identit RMDEF Matrix MatrixAdd(Matrix left, Matrix right); // Add two matrices RMDEF Matrix MatrixSubstract(Matrix left, Matrix right); // Substract two matrices (left - right) RMDEF Matrix MatrixTranslate(float x, float y, float z); // Returns translation matrix -RMDEF Matrix MatrixRotate(float angle, Vector3 axis); // Returns rotation matrix for an angle around an specified axis (angle in radians) +RMDEF Matrix MatrixRotate(Vector3 axis, float angle); // Returns rotation matrix for an angle around an specified axis (angle in radians) RMDEF Matrix MatrixRotateX(float angle); // Returns x-rotation matrix (angle in radians) RMDEF Matrix MatrixRotateY(float angle); // Returns y-rotation matrix (angle in radians) RMDEF Matrix MatrixRotateZ(float angle); // Returns z-rotation matrix (angle in radians) @@ -160,8 +162,8 @@ RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2); // Calcula RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float slerp); // Calculates spherical linear interpolation between two quaternions RMDEF Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion for a given rotation matrix RMDEF Matrix QuaternionToMatrix(Quaternion q); // Returns a matrix for a given quaternion -RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis); // Returns rotation quaternion for an angle and axis -RMDEF void QuaternionToAxisAngle(Quaternion q, float *outAngle, Vector3 *outAxis); // Returns the rotation angle and axis for a given quaternion +RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle); // Returns rotation quaternion for an angle and axis +RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle); // Returns the rotation angle and axis for a given quaternion RMDEF void QuaternionTransform(Quaternion *q, Matrix mat); // Transform a quaternion given a transformation matrix #ifdef __cplusplus @@ -361,6 +363,30 @@ RMDEF Vector3 VectorZero(void) return zero; } +// Return min value for each pair of components +RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2) +{ + Vector3 result; + + result.x = fminf(vec1.x, vec2.x); + result.y = fminf(vec1.y, vec2.y); + result.z = fminf(vec1.z, vec2.z); + + return result; +} + +// Return max value for each pair of components +RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2) +{ + Vector3 result; + + result.x = fmaxf(vec1.x, vec2.x); + result.y = fmaxf(vec1.y, vec2.y); + result.z = fmaxf(vec1.z, vec2.z); + + return result; +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Matrix math //---------------------------------------------------------------------------------- @@ -561,7 +587,7 @@ RMDEF Matrix MatrixTranslate(float x, float y, float z) // Create rotation matrix from axis and angle // NOTE: Angle should be provided in radians -RMDEF Matrix MatrixRotate(float angle, Vector3 axis) +RMDEF Matrix MatrixRotate(Vector3 axis, float angle) { Matrix result; @@ -579,9 +605,9 @@ RMDEF Matrix MatrixRotate(float angle, Vector3 axis) z *= length; } - float s = sinf(angle); - float c = cosf(angle); - float t = 1.0f - c; + float sinres = sinf(angle); + float cosres = cosf(angle); + float t = 1.0f - cosres; // Cache some matrix values (speed optimization) float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; @@ -589,9 +615,9 @@ RMDEF Matrix MatrixRotate(float angle, Vector3 axis) float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; // Construct the elements of the rotation matrix - float b00 = x*x*t + c, b01 = y*x*t + z*s, b02 = z*x*t - y*s; - float b10 = x*y*t - z*s, b11 = y*y*t + c, b12 = z*y*t + x*s; - float b20 = x*z*t + y*s, b21 = y*z*t - x*s, b22 = z*z*t + c; + float b00 = x*x*t + cosres, b01 = y*x*t + z*sinres, b02 = z*x*t - y*sinres; + float b10 = x*y*t - z*sinres, b11 = y*y*t + cosres, b12 = z*y*t + x*sinres; + float b20 = x*z*t + y*sinres, b21 = y*z*t - x*sinres, b22 = z*z*t + cosres; // Perform rotation-specific matrix multiplication result.m0 = a00*b00 + a10*b01 + a20*b02; @@ -662,8 +688,8 @@ RMDEF Matrix MatrixRotateX(float angle) { Matrix result = MatrixIdentity(); - float cosres = (float)cos(angle); - float sinres = (float)sin(angle); + float cosres = cosf(angle); + float sinres = sinf(angle); result.m5 = cosres; result.m6 = -sinres; @@ -694,8 +720,8 @@ RMDEF Matrix MatrixRotateZ(float angle) { Matrix result = MatrixIdentity(); - float cosres = (float)cos(angle); - float sinres = (float)sin(angle); + float cosres = cosf(angle); + float sinres = sinf(angle); result.m0 = cosres; result.m1 = -sinres; @@ -920,8 +946,8 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) } else { - float ratioA = sin((1 - amount)*halfTheta)/sinHalfTheta; - float ratioB = sin(amount*halfTheta)/sinHalfTheta; + float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta; + float ratioB = sinf(amount*halfTheta)/sinHalfTheta; result.x = (q1.x*ratioA + q2.x*ratioB); result.y = (q1.y*ratioA + q2.y*ratioB); @@ -1034,7 +1060,7 @@ RMDEF Matrix QuaternionToMatrix(Quaternion q) // Returns rotation quaternion for an angle and axis // NOTE: angle must be provided in radians -RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis) +RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle) { Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; @@ -1043,11 +1069,14 @@ RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis) angle *= 0.5f; VectorNormalize(&axis); + + float sinres = sinf(angle); + float cosres = cosf(angle); - result.x = axis.x*(float)sin(angle); - result.y = axis.y*(float)sin(angle); - result.z = axis.z*(float)sin(angle); - result.w = (float)cos(angle); + result.x = axis.x*sinres; + result.y = axis.y*sinres; + result.z = axis.z*sinres; + result.w = cosres; QuaternionNormalize(&result); @@ -1055,7 +1084,7 @@ RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis) } // Returns the rotation angle and axis for a given quaternion -RMDEF void QuaternionToAxisAngle(Quaternion q, float *outAngle, Vector3 *outAxis) +RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle) { if (fabs(q.w) > 1.0f) QuaternionNormalize(&q); diff --git a/src/resources b/src/resources index b41637ff9..6fc578e07 100644 Binary files a/src/resources and b/src/resources differ diff --git a/src/rlgl.c b/src/rlgl.c index ec909385f..8ea7d0f29 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -171,7 +171,7 @@ typedef struct { typedef struct { GLuint textureId; int vertexCount; - // TODO: DrawState state -> Blending mode, shader + // TODO: Store draw state -> blending mode, shader } DrawCall; // pixel type (same as Color type) @@ -411,7 +411,7 @@ void rlRotatef(float angleDeg, float x, float y, float z) Vector3 axis = (Vector3){ x, y, z }; VectorNormalize(&axis); - matRotation = MatrixRotate(angleDeg*DEG2RAD, axis); + matRotation = MatrixRotate(axis, angleDeg*DEG2RAD); MatrixTranspose(&matRotation); @@ -981,7 +981,7 @@ void rlglInit(void) else TraceLog(WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported"); if (npotSupported) TraceLog(INFO, "[EXTENSION] NPOT textures extension detected, full NPOT textures supported"); - else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, NPOT textures support is limited (no-mipmaps, no-repeat)"); + else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)"); #endif if (texCompDXTSupported) TraceLog(INFO, "[EXTENSION] DXT compressed textures supported"); @@ -1406,13 +1406,13 @@ void rlglDrawPostpro(void) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glBindFramebuffer(GL_FRAMEBUFFER, 0); - rlglDrawModel(postproQuad, (Vector3){0,0,0}, 0.0f, (Vector3){0,0,0}, (Vector3){1.0f, 1.0f, 1.0f}, (Color){ 255, 255, 255, 255 }, false); + rlglDrawModel(postproQuad, (Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.0f, (Vector3){1.0f, 1.0f, 1.0f}, (Color){ 255, 255, 255, 255 }, false); #endif } // Draw a 3d model // NOTE: Model transform can come within model struct -void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires) +void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires) { #if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) // NOTE: glPolygonMode() not available on OpenGL ES @@ -1461,10 +1461,10 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r // Calculate transformation matrix from function parameters // Get transform matrix (rotation -> scale -> translation) - Matrix matRotation = MatrixRotate(rotationAngle*DEG2RAD, rotationAxis); + Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); - Matrix matTransform = MatrixMultiply(MatrixMultiply(matRotation, matScale), matTranslation); + Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); // Combine model internal transformation matrix (model.transform) with matrix generated by function parameters (matTransform) Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates @@ -1475,11 +1475,7 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r // Calculate model-view-projection matrix (MVP) Matrix matMVP = MatrixMultiply(matModelView, matProjection); // Transform to screen-space coordinates - // NOTE: Drawing in OpenGL 3.3+, matrices are passed to shader - // TODO: Reduce number of matrices passed to shaders, use only matMVP - glUniformMatrix4fv(model.shader.modelLoc, 1, false, MatrixToFloat(matModel)); - glUniformMatrix4fv(model.shader.viewLoc, 1, false, MatrixToFloat(matView)); - + // Send combined model-view-projection matrix to shader glUniformMatrix4fv(model.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); // Apply color tinting to model @@ -1615,7 +1611,6 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height) } // Get world coordinates from screen coordinates -// TODO: It doesn't work! It drives me crazy! // NOTE: Using global variables: screenWidth, screenHeight Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view) { @@ -1900,7 +1895,7 @@ void rlglGenerateMipmaps(Texture2D texture) int mipmapCount = GenerateMipmaps(data, texture.width, texture.height); // TODO: Adjust mipmap size depending on texture format! - int size = texture.width*texture.height*4; + int size = texture.width*texture.height*4; // RGBA 32bit only int offset = size; int mipWidth = texture.width/2; @@ -2201,9 +2196,6 @@ Shader LoadShader(char *vsFileName, char *fsFileName) // Get handles to GLSL uniform locations (vertex shader) shader.mvpLoc = glGetUniformLocation(shader.id, "mvpMatrix"); - - shader.modelLoc = glGetUniformLocation(shader.id, "modelMatrix"); - shader.viewLoc = glGetUniformLocation(shader.id, "viewMatrix"); // Get handles to GLSL uniform locations (fragment shader) shader.tintColorLoc = glGetUniformLocation(shader.id, "fragTintColor"); @@ -2503,6 +2495,18 @@ void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size) #endif } +// Set shader uniform value (matrix 4x4) +void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glUseProgram(shader.id); + + glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat)); + + glUseProgram(0); +#endif +} + // Default diffuse shader map texture assignment void SetShaderMapDiffuse(Shader *shader, Texture2D texture) { @@ -2741,9 +2745,6 @@ static Shader LoadDefaultShader(void) // Get handles to GLSL uniform locations (vertex shader) shader.mvpLoc = glGetUniformLocation(shader.id, "mvpMatrix"); - - shader.modelLoc = glGetUniformLocation(shader.id, "modelMatrix"); - shader.viewLoc = glGetUniformLocation(shader.id, "viewMatrix"); // Get handles to GLSL uniform locations (fragment shader) shader.tintColorLoc = -1; @@ -2822,9 +2823,6 @@ static Shader LoadSimpleShader(void) // Get handles to GLSL uniform locations (vertex shader) shader.mvpLoc = glGetUniformLocation(shader.id, "mvpMatrix"); - - shader.modelLoc = glGetUniformLocation(shader.id, "modelMatrix"); - shader.viewLoc = glGetUniformLocation(shader.id, "viewMatrix"); // Get handles to GLSL uniform locations (fragment shader) shader.tintColorLoc = glGetUniformLocation(shader.id, "fragTintColor"); diff --git a/src/rlgl.h b/src/rlgl.h index 76cae9877..9e0aaaaa6 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -167,9 +167,6 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; // Uniforms int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - - int modelLoc; // Model transformation matrix uniform location point (vertex shader) - int viewLoc; // View transformation matrix uniform location point (vertex shader) int tintColorLoc; // Color uniform location point (fragment shader) int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader) @@ -265,7 +262,7 @@ void rlglInitPostpro(void); // Initialize postprocessing sys void rlglDrawPostpro(void); // Draw with postprocessing shader Model rlglLoadModel(Mesh mesh); // Upload vertex data into GPU and provided VAO/VBO ids -void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires); +void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires); Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates diff --git a/src/shapes.c b/src/shapes.c index a47615368..65e3621b6 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -397,8 +397,8 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) int recCenterX = rec.x + rec.width/2; int recCenterY = rec.y + rec.height/2; - float dx = abs(center.x - recCenterX); - float dy = abs(center.y - recCenterY); + float dx = fabs(center.x - recCenterX); + float dy = fabs(center.y - recCenterY); if (dx > (rec.width/2 + radius)) { return false; } if (dy > (rec.height/2 + radius)) { return false; } @@ -412,6 +412,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) } // Get collision rectangle for two rectangles collision +// TODO: Depending on rec1 and rec2 order, it fails -> Review! Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) { Rectangle retRec = { 0, 0, 0, 0 }; diff --git a/src/text.c b/src/text.c index 3755932d0..e4c7bbf3e 100644 --- a/src/text.c +++ b/src/text.c @@ -346,7 +346,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int f for(int i = 0; i < length; i++) { - // TODO: Right now we are supposing characters follow a continous order and start at FONT_FIRST_CHAR, + // TODO: Right now we are supposing characters that follow a continous order and start at FONT_FIRST_CHAR, // this sytem can be improved to support any characters order and init value... // An intermediate table could be created to link char values with predefined char position index in chars rectangle array diff --git a/src/textures.c b/src/textures.c index f03d2d9ad..36819daf4 100644 --- a/src/textures.c +++ b/src/textures.c @@ -712,7 +712,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) { oldpixel = pixels[y*image->width + x]; - // TODO: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) + // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) newpixel.r = oldpixel.r>>(8 - rBpp); // R bits newpixel.g = oldpixel.g>>(8 - gBpp); // G bits newpixel.b = oldpixel.b>>(8 - bBpp); // B bits @@ -769,7 +769,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) } // Convert image to POT (power-of-two) -// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5) +// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) void ImageToPOT(Image *image, Color fillColor) { Color *pixels = GetImageData(*image); // Get pixels data @@ -784,7 +784,7 @@ void ImageToPOT(Image *image, Color fillColor) Color *pixelsPOT = NULL; // Generate POT array from NPOT data - pixelsPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color)); + pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color)); for (int j = 0; j < potHeight; j++) { @@ -896,7 +896,9 @@ void ImageCrop(Image *image, Rectangle crop) } // Resize and image to new size -// NOTE: Uses stb default scaling filter +// NOTE: Uses stb default scaling filters (both bicubic): +// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +// STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL (high-quality Catmull-Rom) void ImageResize(Image *image, int newWidth, int newHeight) { // Get data as Color pixels array to work with it diff --git a/src_android/jni/Android.mk b/src_android/jni/Android.mk index f9c20e661..200737604 100644 --- a/src_android/jni/Android.mk +++ b/src_android/jni/Android.mk @@ -39,7 +39,6 @@ LOCAL_MODULE := raylib LOCAL_SRC_FILES :=\ ../../src/core.c \ ../../src/rlgl.c \ - ../../src/raymath.c \ ../../src/textures.c \ ../../src/text.c \ ../../src/shapes.c \ diff --git a/templates/advance_game/makefile b/templates/advance_game/makefile index b6dfc5342..e19eb746a 100644 --- a/templates/advance_game/makefile +++ b/templates/advance_game/makefile @@ -72,7 +72,8 @@ else CFLAGS = -O2 -Wall -std=c99 endif ifeq ($(PLATFORM),PLATFORM_WEB) - CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 -s ASSERTIONS=1 --preload-file resources + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 # to check for memory allocation errors (-O1 disables it) #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) endif @@ -87,8 +88,8 @@ else # external libraries headers # GLFW3 INCLUDES += -I../../external/glfw3/include -# GLEW - INCLUDES += -I../../external/glew/include +# GLEW - Not required any more, replaced by GLAD + #INCLUDES += -I../external/glew/include # OpenAL Soft INCLUDES += -I../../external/openal_soft/include endif @@ -100,12 +101,12 @@ else LFLAGS = -L. -L../../src -LC:/raylib/raylib/src # external libraries to link with # GLFW3 - LFLAGS += -L../../external/glfw3/lib/$(LIBPATH) + LFLAGS += -L../../external/glfw3/lib/$(LIBPATH) ifneq ($(PLATFORM_OS),OSX) # OpenAL Soft LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) - # GLEW - LFLAGS += -L../../external/glew/lib/$(LIBPATH) + # GLEW: Not used, replaced by GLAD + #LFLAGS += -L../../external/glew/lib/$(LIBPATH) endif endif @@ -128,7 +129,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) else # libraries for Windows desktop compiling # NOTE: GLFW3 and OpenAL Soft libraries should be installed - LIBS = -lraylib -lglfw3 -lglew32 -lopengl32 -lopenal32 -lgdi32 + LIBS = -lraylib -lglfw3 -lopengl32 -lopenal32 -lgdi32 endif endif endif @@ -138,8 +139,8 @@ ifeq ($(PLATFORM),PLATFORM_RPI) LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal endif ifeq ($(PLATFORM),PLATFORM_WEB) - # just adjust the correct path to libraylib.bc - LIBS = C:/raylib/raylib/src/libraylib.bc + # NOTE: Set the correct path to libraylib.bc + LIBS = ../../src/libraylib.bc endif # define additional parameters and flags for windows diff --git a/templates/android_project/jni/include/raylib.h b/templates/android_project/jni/include/raylib.h index 72211b59e..c4d4392dd 100644 --- a/templates/android_project/jni/include/raylib.h +++ b/templates/android_project/jni/include/raylib.h @@ -7,10 +7,10 @@ * Features: * Library written in plain C code (C99) * Uses C# PascalCase/camelCase notation -* Hardware accelerated with OpenGL (1.1, 3.3+ or ES2) +* Hardware accelerated with OpenGL (1.1, 3.3 or ES2) * Unique OpenGL abstraction layer [rlgl] -* Powerful fonts module with SpriteFonts support -* Multiple textures support, including DDS and mipmaps generation +* Powerful fonts module with SpriteFonts support (including AngelCode fonts and TTF) +* Multiple textures support, including compressed formats and mipmaps generation * Basic 3d support for Shapes, Models, Heightmaps and Billboards * Powerful math module for Vector and Matrix operations [raymath] * Audio loading and playing with streaming support (WAV and OGG) @@ -18,20 +18,21 @@ * * Used external libs: * GLFW3 (www.glfw.org) for window/context management and input -* GLEW for OpenGL extensions loading (3.3+ and ES2) +* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) * stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) * stb_image_write (Sean Barret) for image writting (PNG) * stb_vorbis (Sean Barret) for ogg audio loading +* stb_truetype (Sean Barret) for ttf fonts loading * OpenAL Soft for audio device/context management * tinfl for data decompression (DEFLATE algorithm) * * Some design decisions: -* 32bit Colors - All defined color are always RGBA -* SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures +* 32bit Colors - All defined color are always RGBA (struct Color is 4 byte) * One custom default font is loaded automatically when InitWindow() -* If using OpenGL 3.3+ or ES2, one default shader is loaded automatically (internally defined) +* If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads +* If using OpenGL 3.3 or ES2, two default shaders are loaded automatically (internally defined) * -* -- LICENSE (raylib v1.2, September 2014) -- +* -- LICENSE -- * * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: @@ -80,8 +81,8 @@ #define PI 3.14159265358979323846 #endif -#define DEG2RAD (PI / 180.0f) -#define RAD2DEG (180.0f / PI) +#define DEG2RAD (PI/180.0f) +#define RAD2DEG (180.0f/PI) // raylib Config Flags #define FLAG_FULLSCREEN_MODE 1 @@ -110,6 +111,8 @@ #define KEY_F8 297 #define KEY_F9 298 #define KEY_F10 299 +#define KEY_F11 300 +#define KEY_F12 301 #define KEY_LEFT_SHIFT 340 #define KEY_LEFT_CONTROL 341 #define KEY_LEFT_ALT 342 @@ -117,7 +120,7 @@ #define KEY_RIGHT_CONTROL 345 #define KEY_RIGHT_ALT 346 -// Keyboard Alhpa Numeric Keys +// Keyboard Alpha Numeric Keys #define KEY_ZERO 48 #define KEY_ONE 49 #define KEY_TWO 50 @@ -165,6 +168,9 @@ #define MOUSE_MIDDLE_BUTTON 2 #endif +// Touch points registered +#define MAX_TOUCH_POINTS 2 + // Gamepad Number #define GAMEPAD_PLAYER1 0 #define GAMEPAD_PLAYER2 1 @@ -308,17 +314,27 @@ typedef struct Camera { Vector3 up; } Camera; +// Bounding box type +typedef struct BoundingBox { + Vector3 min; + Vector3 max; +} BoundingBox; + // Vertex data definning a mesh -// NOTE: If using OpenGL 1.1, data loaded in CPU; if OpenGL 3.3+ data loaded in GPU (vaoId) -typedef struct VertexData { - int vertexCount; - float *vertices; // 3 components per vertex - float *texcoords; // 2 components per vertex - float *normals; // 3 components per vertex - unsigned char *colors; // 4 components per vertex - unsigned int vaoId; - unsigned int vboId[4]; -} VertexData; +typedef struct Mesh { + int vertexCount; // num vertices + float *vertices; // vertex position (XYZ - 3 components per vertex) + float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) + float *texcoords2; // vertex second texture coordinates (useful for lightmaps) + float *normals; // vertex normals (XYZ - 3 components per vertex) + float *tangents; // vertex tangents (XYZ - 3 components per vertex) + unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) + + BoundingBox bounds; // mesh limits defined by min and max points + + unsigned int vaoId; // OpenGL Vertex Array Object id + unsigned int vboId[6]; // OpenGL Vertex Buffer Objects id (6 types of vertex data) +} Mesh; // Shader type (generic shader) typedef struct Shader { @@ -336,10 +352,7 @@ typedef struct Shader { int colorLoc; // Color attibute location point (vertex shader) // Uniforms - int projectionLoc; // Projection matrix uniform location point (vertex shader) - int modelviewLoc; // ModelView matrix uniform location point (vertex shader) - int modelLoc; // Model transformation matrix uniform location point (vertex shader) - int viewLoc; // View transformation matrix uniform location point (vertex shader) + int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) int tintColorLoc; // Color uniform location point (fragment shader) int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader) @@ -347,12 +360,31 @@ typedef struct Shader { int mapSpecularLoc; // Specular map texture uniform location point (fragment shader) } Shader; +// Material type +// TODO: Redesign material-shaders-textures system +typedef struct Material { + //Shader shader; + + //Texture2D texDiffuse; // Diffuse texture + //Texture2D texNormal; // Normal texture + //Texture2D texSpecular; // Specular texture + + Color colDiffuse; + Color colAmbient; + Color colSpecular; + + float glossiness; + float normalDepth; +} Material; + // 3d Model type +// TODO: Replace shader/testure by material typedef struct Model { - VertexData mesh; + Mesh mesh; Matrix transform; Texture2D texture; // Only for OpenGL 1.1, on newer versions this should be in the shader Shader shader; + //Material material; } Model; // Ray type (useful for raycast) @@ -376,26 +408,6 @@ typedef struct Wave { short channels; } Wave; -// Light type -typedef struct Light { - float position[3]; - float rotation[3]; - float intensity[1]; - float ambientColor[3]; - float diffuseColor[3]; - float specularColor[3]; - float specularIntensity[1]; -} Light; - -// Material type -typedef struct Material { - float ambientColor[3]; - float diffuseColor[3]; - float specularColor[3]; - float glossiness[1]; - float normalDepth[1]; -} Material; - // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { @@ -425,42 +437,36 @@ typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; // Gestures type // NOTE: It could be used as flags to enable only some gestures typedef enum { - GESTURE_NONE = 1, - GESTURE_TAP = 2, - GESTURE_DOUBLETAP = 4, - GESTURE_HOLD = 8, - GESTURE_DRAG = 16, - GESTURE_SWIPE_RIGHT = 32, - GESTURE_SWIPE_LEFT = 64, - GESTURE_SWIPE_UP = 128, - GESTURE_SWIPE_DOWN = 256, - GESTURE_PINCH_IN = 512, - GESTURE_PINCH_OUT = 1024 + GESTURE_NONE = 0, + GESTURE_TAP = 1, + GESTURE_DOUBLETAP = 2, + GESTURE_HOLD = 4, + GESTURE_DRAG = 8, + GESTURE_SWIPE_RIGHT = 16, + GESTURE_SWIPE_LEFT = 32, + GESTURE_SWIPE_UP = 64, + GESTURE_SWIPE_DOWN = 128, + GESTURE_PINCH_IN = 256, + GESTURE_PINCH_OUT = 512 } Gestures; +// Touch action (fingers or mouse) typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; // Gesture events -// NOTE: MAX_TOUCH_POINTS fixed to 4 +// NOTE: MAX_TOUCH_POINTS fixed to 2 typedef struct { int touchAction; int pointCount; - int pointerId[4]; - Vector2 position[4]; + int pointerId[MAX_TOUCH_POINTS]; + Vector2 position[MAX_TOUCH_POINTS]; } GestureEvent; // Camera system modes typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; // Collider types -typedef enum { RectangleCollider, CircleCollider } ColliderType; - -// Physics struct -typedef struct Physics { - bool enabled; - bool debug; // Should be used by programmer for testing purposes - Vector2 gravity; -} Physics; +typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType; // Transform struct typedef struct Transform { @@ -486,8 +492,8 @@ typedef struct Rigidbody { typedef struct Collider { bool enabled; ColliderType type; - Rectangle bounds; // Just used for RectangleCollider type - int radius; // Just used for CircleCollider type + Rectangle bounds; // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE + int radius; // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE } Collider; #ifdef __cplusplus @@ -524,10 +530,12 @@ void BeginDrawing(void); // Setup drawing can void BeginDrawingEx(int blendMode, Shader shader, Matrix transform); // Setup drawing canvas with extended parameters void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering) -void Begin3dMode(Camera cam); // Initializes 3D mode for drawing (Camera setup) +void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup) void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode -Ray GetMouseRay(Vector2 mousePosition, Camera camera); // TODO: Returns a ray trace from mouse position +Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position +Vector2 WorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position +Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) void SetTargetFPS(int fps); // Set target FPS (maximum) float GetFPS(void); // Returns current FPS @@ -535,6 +543,9 @@ float GetFrameTime(void); // Returns time in s Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value int GetHexValue(Color color); // Returns hexadecimal value for a Color +float *ColorToFloat(Color color); // Converts Color to float array and normalizes +float *VectorToFloat(Vector3 vec); // Converts Vector3 to float array +float *MatrixToFloat(Matrix mat); // Converts Matrix to float array int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f @@ -571,10 +582,10 @@ int GetMouseWheelMove(void); // Returns mouse wheel m void ShowCursor(void); // Shows cursor void HideCursor(void); // Hides cursor +void EnableCursor(void); // Enables cursor +void DisableCursor(void); // Disables cursor bool IsCursorHidden(void); // Returns true if cursor is not visible -#endif -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available Vector2 GetGamepadMovement(int gamepad); // Return axis movement vector for a gamepad bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once @@ -583,30 +594,31 @@ bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad b bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) -int GetTouchX(void); // Returns touch position X (relative to screen size) -int GetTouchY(void); // Returns touch position Y (relative to screen size) -Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size) +int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size) +int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) +Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) + +#if defined(PLATFORM_ANDROID) bool IsButtonPressed(int button); // Detect if an android physic button has been pressed bool IsButtonDown(int button); // Detect if an android physic button is being pressed bool IsButtonReleased(int button); // Detect if an android physic button has been released +#endif //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ +void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) bool IsGestureDetected(void); // Check if a gesture have been detected int GetGestureType(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures +int GetTouchPointsCount(void); // Get touch points count -float GetGestureDragIntensity(void); // Get gesture drag intensity -float GetGestureDragAngle(void); // Get gesture drag angle +float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector -int GetGestureHoldDuration(void); // Get gesture hold time in frames -float GetGesturePinchDelta(void); // Get gesture pinch delta +float GetGestureDragAngle(void); // Get gesture drag angle +Vector2 GetGesturePinchVector(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle -#endif //------------------------------------------------------------------------------------ // Camera System Functions (Module: camera) @@ -738,27 +750,31 @@ void DrawGizmo(Vector3 position); // Model 3d Loading and Drawing Functions (Module: models) //------------------------------------------------------------------------------------ Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) -Model LoadModelEx(VertexData data); // Load a 3d model (from vertex data) +Model LoadModelEx(Mesh data); // Load a 3d model (from vertex data) //Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource) -Model LoadHeightmap(Image heightmap, float maxHeight); // Load a heightmap image as a 3d model +Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) void UnloadModel(Model model); // Unload 3d model from memory void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) -void DrawModelEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint); // Draw a model with extended parameters +void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set) -void DrawModelWiresEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +void DrawBoundingBox(BoundingBox box); // Draw bounding box (wires) void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec +BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, Vector3 maxBBox2); // Detect collision between two boxes bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere +bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere +bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere with extended parameters and collision point detection +bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox); // Detect collision between ray and box Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap // NOTE: Return the normal vector of the impacted surface - //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 @@ -775,6 +791,7 @@ bool IsPosproShaderEnabled(void); // Check if int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) +void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) void SetShaderMapDiffuse(Shader *shader, Texture2D texture); // Default diffuse shader map texture assignment void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture); // Normal map texture shader assignment void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture); // Specular map texture shader assignment @@ -783,30 +800,10 @@ void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textur void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) //---------------------------------------------------------------------------------- -// Lighting System Functions (engine-module: lighting) -// NOTE: light and material structs uses float pointers instead of vectors to be compatible with SetShaderValue() +// Physics System Functions (engine-module: physac) //---------------------------------------------------------------------------------- -// Lights functions -void SetLightPosition(Light *light, Vector3 position); // Set light position converting position vector to float pointer -void SetLightRotation(Light *light, Vector3 rotation); // Set light rotation converting rotation vector to float pointer -void SetLightIntensity(Light *light, float intensity); // Set light intensity value -void SetLightAmbientColor(Light *light, Vector3 color); // Set light ambient color value (it will be multiplied by material ambient color) -void SetLightDiffuseColor(Light *light, Vector3 color); // Set light diffuse color (light color) -void SetLightSpecularColor(Light *light, Vector3 color); // Set light specular color (it will be multiplied by material specular color) -void SetLightSpecIntensity(Light *light, float specIntensity); // Set light specular intensity (specular color scalar multiplier) - -// Materials functions -void SetMaterialAmbientColor(Material *material, Vector3 color); // Set material ambient color value (it will be multiplied by light ambient color) -void SetMaterialDiffuseColor(Material *material, Vector3 color); // Set material diffuse color (material color, should use DrawModel() tint parameter) -void SetMaterialSpecularColor(Material *material, Vector3 color); // Set material specular color (it will be multiplied by light specular color) -void SetMaterialGlossiness(Material *material, float glossiness); // Set material glossiness value (recommended values: 0 - 100) -void SetMaterialNormalDepth(Material *material, float depth); // Set normal map depth (B component from RGB type map scalar multiplier) - -//---------------------------------------------------------------------------------- -// Physics System Functions (engine-module: physics) -//---------------------------------------------------------------------------------- -void InitPhysics(void); // Initialize all internal physics values -void SetPhysics(Physics settings); // Set physics settings values using Physics data type to overwrite internal physics settings +void InitPhysics(int maxPhysicElements); // Initialize all internal physics values +void UnloadPhysics(); // Unload physic elements arrays void AddRigidbody(int index, Rigidbody rigidbody); // Initialize a new rigidbody with parameters to internal index slot void AddCollider(int index, Collider collider); // Initialize a new Collider with parameters to internal index slot diff --git a/templates/android_project/jni/libs/libraylib.a b/templates/android_project/jni/libs/libraylib.a index 14e10ab79..2cda58431 100644 Binary files a/templates/android_project/jni/libs/libraylib.a and b/templates/android_project/jni/libs/libraylib.a differ diff --git a/templates/basic_game/makefile b/templates/basic_game/makefile index 9a52c4eb6..057320403 100644 --- a/templates/basic_game/makefile +++ b/templates/basic_game/makefile @@ -72,7 +72,8 @@ else CFLAGS = -O2 -Wall -std=c99 endif ifeq ($(PLATFORM),PLATFORM_WEB) - CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 -s ASSERTIONS=1 --preload-file resources + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 # to check for memory allocation errors (-O1 disables it) #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) endif @@ -104,8 +105,8 @@ else ifneq ($(PLATFORM_OS),OSX) # OpenAL Soft LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) - # GLEW - LFLAGS += -L../../external/glew/lib/$(LIBPATH) + # GLEW: Not used, replaced by GLAD + #LFLAGS += -L../../external/glew/lib/$(LIBPATH) endif endif @@ -138,8 +139,8 @@ ifeq ($(PLATFORM),PLATFORM_RPI) LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal endif ifeq ($(PLATFORM),PLATFORM_WEB) - # just adjust the correct path to libraylib.bc - LIBS = C:/raylib/raylib/src/libraylib.bc + # NOTE: Set the correct path to libraylib.bc + LIBS = ../../src/libraylib.bc endif # define additional parameters and flags for windows diff --git a/templates/simple_game/makefile b/templates/simple_game/makefile index 30216e5dd..41fef740a 100644 --- a/templates/simple_game/makefile +++ b/templates/simple_game/makefile @@ -72,7 +72,8 @@ else CFLAGS = -O2 -Wall -std=c99 endif ifeq ($(PLATFORM),PLATFORM_WEB) - CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 -s ASSERTIONS=1 --preload-file resources + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 # to check for memory allocation errors (-O1 disables it) #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) endif @@ -104,8 +105,8 @@ else ifneq ($(PLATFORM_OS),OSX) # OpenAL Soft LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) - # GLEW - LFLAGS += -L../../external/glew/lib/$(LIBPATH) + # GLEW: Not used, replaced by GLAD + #LFLAGS += -L../../external/glew/lib/$(LIBPATH) endif endif @@ -138,8 +139,8 @@ ifeq ($(PLATFORM),PLATFORM_RPI) LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal endif ifeq ($(PLATFORM),PLATFORM_WEB) - # just adjust the correct path to libraylib.bc - LIBS = C:/raylib/raylib/src/libraylib.bc + # NOTE: Set the correct path to libraylib.bc + LIBS = ../../src/libraylib.bc endif # define additional parameters and flags for windows diff --git a/templates/standard_game/makefile b/templates/standard_game/makefile index ec847b0e4..90f0e6f2f 100644 --- a/templates/standard_game/makefile +++ b/templates/standard_game/makefile @@ -72,7 +72,8 @@ else CFLAGS = -O2 -Wall -std=c99 endif ifeq ($(PLATFORM),PLATFORM_WEB) - CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 -s ASSERTIONS=1 --preload-file resources + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources --shell-file ../../templates/web_shell/shell.html + #-s ASSERTIONS=1 # to check for memory allocation errors (-O1 disables it) #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) endif @@ -104,8 +105,8 @@ else ifneq ($(PLATFORM_OS),OSX) # OpenAL Soft LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) - # GLEW - LFLAGS += -L../../external/glew/lib/$(LIBPATH) + # GLEW: Not used, replaced by GLAD + #LFLAGS += -L../../external/glew/lib/$(LIBPATH) endif endif @@ -138,8 +139,8 @@ ifeq ($(PLATFORM),PLATFORM_RPI) LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal endif ifeq ($(PLATFORM),PLATFORM_WEB) - # just adjust the correct path to libraylib.bc - LIBS = C:/raylib/raylib/src/libraylib.bc + # NOTE: Set the correct path to libraylib.bc + LIBS = ../../src/libraylib.bc endif # define additional parameters and flags for windows diff --git a/templates/web_shell/shell.html b/templates/web_shell/shell.html new file mode 100644 index 000000000..c154ee7e4 --- /dev/null +++ b/templates/web_shell/shell.html @@ -0,0 +1,239 @@ + + + + + + + raylib HTML5 GAME + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
Downloading...
+ + + + + +
+ +
+
+ +
+ +
+ + + + + {{{ SCRIPT }}} + + \ No newline at end of file