- Added new physics engine-module with four new data types: Physics, Transform, Rigidbody and Collider. This library contains functions to apply physics calculations to a position vector calculating collisions automatically. - Fixed some writing mistakes of lighting module.pull/66/head
| @ -0,0 +1,144 @@ | |||||
| /******************************************************************************************* | |||||
| * | |||||
| * raylib [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) | |||||
| * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) | |||||
| * | |||||
| * Copyright (c) 2015 Ramon Santamaria (@raysan5) | |||||
| * | |||||
| ********************************************************************************************/ | |||||
| #include "raylib.h" | |||||
| #define OBJECT_SIZE 50 | |||||
| #define PLAYER_INDEX 0 | |||||
| int main() | |||||
| { | |||||
| // Initialization | |||||
| //-------------------------------------------------------------------------------------- | |||||
| int screenWidth = 800; | |||||
| int screenHeight = 450; | |||||
| InitWindow(screenWidth, screenHeight, "raylib [physics] example - basic rigidbody"); | |||||
| SetTargetFPS(60); // Enable v-sync | |||||
| 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); | |||||
| // Object initialization | |||||
| Transform player = (Transform){(Vector2){(screenWidth - OBJECT_SIZE) / 2, (screenHeight - OBJECT_SIZE) / 2}, 0.0f, (Vector2){OBJECT_SIZE, OBJECT_SIZE}}; | |||||
| AddCollider(PLAYER_INDEX, (Collider){true, RectangleCollider, (Rectangle){player.position.x, player.position.y, player.scale.x, player.scale.y}, 0}); | |||||
| AddRigidbody(PLAYER_INDEX, (Rigidbody){true, 1.0f, (Vector2){0, 0}, (Vector2){0, 0}, false, false, true, 0.5f, 1.0f}); | |||||
| // Floor initialization | |||||
| // NOTE: floor doesn't need a rigidbody because it's a static physic object, just a collider to collide with other dynamic colliders (with rigidbody) | |||||
| Transform floor = (Transform){(Vector2){0, screenHeight * 0.8f}, 0.0f, (Vector2){screenWidth, screenHeight * 0.2f}}; | |||||
| AddCollider(PLAYER_INDEX + 1, (Collider){true, RectangleCollider, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0}); | |||||
| // Object properties initialization | |||||
| float moveSpeed = 6.0f; | |||||
| float jumpForce = 4.5f; | |||||
| //-------------------------------------------------------------------------------------- | |||||
| // Main game loop | |||||
| while (!WindowShouldClose()) // Detect window close button or ESC key | |||||
| { | |||||
| // Update | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Update object physics | |||||
| // NOTE: all physics detections and reactions are calculated in ApplyPhysics() function (You will live happier :D) | |||||
| ApplyPhysics(PLAYER_INDEX, &player.position); | |||||
| // Check jump button input | |||||
| if(IsKeyDown(KEY_SPACE) && GetRigidbody(PLAYER_INDEX).isGrounded) | |||||
| { | |||||
| // Reset object Y velocity to avoid double jumping cases but keep the same X velocity that it already has | |||||
| SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){GetRigidbody(PLAYER_INDEX).velocity.x, 0}); | |||||
| // Add jumping force in Y axis | |||||
| AddRigidbodyForce(PLAYER_INDEX, (Vector2){0, jumpForce}); | |||||
| } | |||||
| // Check movement buttons input | |||||
| if(IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) | |||||
| { | |||||
| // Set rigidbody velocity in X based on moveSpeed value and apply the same Y velocity that it already has | |||||
| SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){moveSpeed, GetRigidbody(PLAYER_INDEX).velocity.y}); | |||||
| } | |||||
| else if(IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) | |||||
| { | |||||
| // Set rigidbody velocity in X based on moveSpeed negative value and apply the same Y velocity that it already has | |||||
| SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){-moveSpeed, GetRigidbody(PLAYER_INDEX).velocity.y}); | |||||
| } | |||||
| // Check debug mode toggle button input | |||||
| if(IsKeyPressed(KEY_P)) | |||||
| { | |||||
| // Update program physics value | |||||
| worldPhysics.debug = !worldPhysics.debug; | |||||
| // Update internal physics value | |||||
| SetPhysics(worldPhysics); | |||||
| } | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Draw | |||||
| //---------------------------------------------------------------------------------- | |||||
| BeginDrawing(); | |||||
| ClearBackground(RAYWHITE); | |||||
| // Draw information | |||||
| DrawText("Use LEFT / RIGHT to MOVE and SPACE to JUMP", (screenWidth - MeasureText("Use LEFT / RIGHT to MOVE and SPACE to JUMP", 20)) / 2, screenHeight * 0.20f, 20, LIGHTGRAY); | |||||
| 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) | |||||
| { | |||||
| // Draw every internal physics stored collider if it is active | |||||
| for(int i = 0; i < 2; i++) | |||||
| { | |||||
| if(GetCollider(i).enabled) | |||||
| { | |||||
| DrawRectangleLines(GetCollider(i).bounds.x, GetCollider(i).bounds.y, GetCollider(i).bounds.width, GetCollider(i).bounds.height, GREEN); | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| // Draw player | |||||
| 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); | |||||
| } | |||||
| EndDrawing(); | |||||
| //---------------------------------------------------------------------------------- | |||||
| } | |||||
| // De-Initialization | |||||
| //-------------------------------------------------------------------------------------- | |||||
| CloseWindow(); // Close window and OpenGL context | |||||
| //-------------------------------------------------------------------------------------- | |||||
| return 0; | |||||
| } | |||||
| @ -0,0 +1,272 @@ | |||||
| /********************************************************************************************** | |||||
| * | |||||
| * raylib physics engine module - Basic functions to apply physics to 2D objects | |||||
| * | |||||
| * Copyright (c) 2015 Victor Fisac and Ramon Santamaria | |||||
| * | |||||
| * 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 PHYSICS_STANDALONE // NOTE: To use the physics module as standalone lib, just uncomment this line | |||||
| #if defined(PHYSICS_STANDALONE) | |||||
| #include "physics.h" | |||||
| #else | |||||
| #include "raylib.h" | |||||
| #endif | |||||
| #include <math.h> | |||||
| #include <stdio.h> | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Defines and Macros | |||||
| //---------------------------------------------------------------------------------- | |||||
| #define MAX_ELEMENTS 1024 // Stored rigidbodies and colliders array length | |||||
| #define DECIMAL_FIX 0.01f // Decimal margin for collision checks (avoid rigidbodies shake) | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Types and Structures Definition | |||||
| //---------------------------------------------------------------------------------- | |||||
| // ... | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Global Variables Definition | |||||
| //---------------------------------------------------------------------------------- | |||||
| static Physics physics; | |||||
| static Collider colliders[MAX_ELEMENTS]; | |||||
| static Rigidbody rigidbodies[MAX_ELEMENTS]; | |||||
| static bool collisionChecker = false; | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Module Functions Definition | |||||
| //---------------------------------------------------------------------------------- | |||||
| void InitPhysics() | |||||
| { | |||||
| for (int i = 0; i < MAX_ELEMENTS; i++) | |||||
| { | |||||
| rigidbodies[i].enabled = false; | |||||
| rigidbodies[i].mass = 0.0f; | |||||
| rigidbodies[i].velocity = (Vector2){0, 0}; | |||||
| rigidbodies[i].acceleration = (Vector2){0, 0}; | |||||
| 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; | |||||
| } | |||||
| } | |||||
| void SetPhysics(Physics settings) | |||||
| { | |||||
| 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}; | |||||
| } | |||||
| void AddCollider(int index, Collider collider) | |||||
| { | |||||
| colliders[index] = collider; | |||||
| } | |||||
| void AddRigidbody(int index, Rigidbody rigidbody) | |||||
| { | |||||
| rigidbodies[index] = rigidbody; | |||||
| } | |||||
| void ApplyPhysics(int index, Vector2 *position) | |||||
| { | |||||
| if (rigidbodies[index].enabled) | |||||
| { | |||||
| // Apply gravity | |||||
| rigidbodies[index].velocity.y += rigidbodies[index].acceleration.y; | |||||
| rigidbodies[index].velocity.x += rigidbodies[index].acceleration.x; | |||||
| rigidbodies[index].velocity.y += physics.gravity.y; | |||||
| rigidbodies[index].velocity.x += physics.gravity.x; | |||||
| // Apply friction to velocity | |||||
| if (rigidbodies[index].isGrounded) | |||||
| { | |||||
| if (rigidbodies[index].velocity.x > DECIMAL_FIX) | |||||
| { | |||||
| rigidbodies[index].velocity.x -= rigidbodies[index].friction; | |||||
| } | |||||
| else if (rigidbodies[index].velocity.x < -DECIMAL_FIX) | |||||
| { | |||||
| rigidbodies[index].velocity.x += rigidbodies[index].friction; | |||||
| } | |||||
| else | |||||
| { | |||||
| rigidbodies[index].velocity.x = 0; | |||||
| } | |||||
| } | |||||
| if (rigidbodies[index].velocity.y > DECIMAL_FIX) | |||||
| { | |||||
| rigidbodies[index].velocity.y -= rigidbodies[index].friction; | |||||
| } | |||||
| else if (rigidbodies[index].velocity.y < -DECIMAL_FIX) | |||||
| { | |||||
| rigidbodies[index].velocity.y += rigidbodies[index].friction; | |||||
| } | |||||
| else | |||||
| { | |||||
| rigidbodies[index].velocity.y = 0; | |||||
| } | |||||
| // Apply friction to acceleration | |||||
| if (rigidbodies[index].isGrounded) | |||||
| { | |||||
| if (rigidbodies[index].acceleration.x > DECIMAL_FIX) | |||||
| { | |||||
| rigidbodies[index].acceleration.x -= rigidbodies[index].friction; | |||||
| } | |||||
| else if (rigidbodies[index].acceleration.x < -DECIMAL_FIX) | |||||
| { | |||||
| rigidbodies[index].acceleration.x += rigidbodies[index].friction; | |||||
| } | |||||
| else | |||||
| { | |||||
| rigidbodies[index].acceleration.x = 0; | |||||
| } | |||||
| } | |||||
| if (rigidbodies[index].acceleration.y > DECIMAL_FIX) | |||||
| { | |||||
| rigidbodies[index].acceleration.y -= rigidbodies[index].friction; | |||||
| } | |||||
| else if (rigidbodies[index].acceleration.y < -DECIMAL_FIX) | |||||
| { | |||||
| rigidbodies[index].acceleration.y += rigidbodies[index].friction; | |||||
| } | |||||
| else | |||||
| { | |||||
| rigidbodies[index].acceleration.y = 0; | |||||
| } | |||||
| // Update position vector | |||||
| position->x += rigidbodies[index].velocity.x; | |||||
| position->y -= rigidbodies[index].velocity.y; | |||||
| // Update collider bounds | |||||
| colliders[index].bounds.x = position->x; | |||||
| colliders[index].bounds.y = position->y; | |||||
| // Check collision with other colliders | |||||
| collisionChecker = false; | |||||
| rigidbodies[index].isContact = false; | |||||
| for (int j = 0; j < MAX_ELEMENTS; j++) | |||||
| { | |||||
| if (index != j) | |||||
| { | |||||
| if (colliders[index].enabled && colliders[j].enabled) | |||||
| { | |||||
| if (colliders[index].type == RectangleCollider) | |||||
| { | |||||
| if (colliders[j].type == RectangleCollider) | |||||
| { | |||||
| if (CheckCollisionRecs(colliders[index].bounds, colliders[j].bounds)) | |||||
| { | |||||
| collisionChecker = true; | |||||
| if ((colliders[index].bounds.y + colliders[index].bounds.height <= colliders[j].bounds.y) == false) | |||||
| { | |||||
| rigidbodies[index].isContact = true; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| if (CheckCollisionCircleRec((Vector2){colliders[j].bounds.x, colliders[j].bounds.y}, colliders[j].radius, colliders[index].bounds)) | |||||
| { | |||||
| collisionChecker = true; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| if (colliders[j].type == RectangleCollider) | |||||
| { | |||||
| if (CheckCollisionCircleRec((Vector2){colliders[index].bounds.x, colliders[index].bounds.y}, colliders[index].radius, colliders[j].bounds)) | |||||
| { | |||||
| collisionChecker = true; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| if (CheckCollisionCircles((Vector2){colliders[j].bounds.x, colliders[j].bounds.y}, colliders[j].radius, (Vector2){colliders[index].bounds.x, colliders[index].bounds.y}, colliders[index].radius)) | |||||
| { | |||||
| collisionChecker = true; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // Update grounded rigidbody state | |||||
| rigidbodies[index].isGrounded = collisionChecker; | |||||
| // Set grounded state if needed (fix overlap and set y velocity) | |||||
| if (collisionChecker && rigidbodies[index].velocity.y != 0) | |||||
| { | |||||
| position->y += rigidbodies[index].velocity.y; | |||||
| rigidbodies[index].velocity.y = -rigidbodies[index].velocity.y * rigidbodies[index].bounciness; | |||||
| } | |||||
| if (rigidbodies[index].isContact) | |||||
| { | |||||
| position->x -= rigidbodies[index].velocity.x; | |||||
| rigidbodies[index].velocity.x = rigidbodies[index].velocity.x; | |||||
| } | |||||
| } | |||||
| } | |||||
| void SetRigidbodyEnabled(int index, bool state) | |||||
| { | |||||
| rigidbodies[index].enabled = state; | |||||
| } | |||||
| void SetRigidbodyVelocity(int index, Vector2 velocity) | |||||
| { | |||||
| rigidbodies[index].velocity.x = velocity.x; | |||||
| rigidbodies[index].velocity.y = velocity.y; | |||||
| } | |||||
| void AddRigidbodyForce(int index, Vector2 force) | |||||
| { | |||||
| rigidbodies[index].acceleration.x = force.x * rigidbodies[index].mass; | |||||
| rigidbodies[index].acceleration.y = force.y * rigidbodies[index].mass; | |||||
| } | |||||
| void SetColliderEnabled(int index, bool state) | |||||
| { | |||||
| colliders[index].enabled = state; | |||||
| } | |||||
| Collider GetCollider(int index) | |||||
| { | |||||
| return colliders[index]; | |||||
| } | |||||
| Rigidbody GetRigidbody(int index) | |||||
| { | |||||
| return rigidbodies[index]; | |||||
| } | |||||
| @ -0,0 +1,99 @@ | |||||
| /********************************************************************************************** | |||||
| * | |||||
| * raylib physics engine module - Basic functions to apply physics to 2D objects | |||||
| * | |||||
| * Copyright (c) 2015 Victor Fisac and Ramon Santamaria | |||||
| * | |||||
| * 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 PHYSICS_H | |||||
| #define PHYSICS_H | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Defines and Macros | |||||
| //---------------------------------------------------------------------------------- | |||||
| // ... | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Types and Structures Definition | |||||
| //---------------------------------------------------------------------------------- | |||||
| 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; | |||||
| // Transform struct | |||||
| typedef struct Transform { | |||||
| Vector2 position; | |||||
| float rotation; | |||||
| Vector2 scale; | |||||
| } Transform; | |||||
| // Rigidbody struct | |||||
| typedef struct Rigidbody { | |||||
| bool enabled; | |||||
| float mass; | |||||
| Vector2 acceleration; | |||||
| Vector2 velocity; | |||||
| bool isGrounded; | |||||
| bool isContact; // Avoid freeze player when touching floor | |||||
| bool applyGravity; | |||||
| float friction; // 0.0f to 1.0f | |||||
| float bounciness; // 0.0f to 1.0f | |||||
| } Rigidbody; | |||||
| // Collider struct | |||||
| typedef struct Collider { | |||||
| bool enabled; | |||||
| ColliderType type; | |||||
| Rectangle bounds; // Just used for RectangleCollider type | |||||
| int radius; // Just used for CircleCollider type | |||||
| } Collider; | |||||
| #ifdef __cplusplus | |||||
| extern "C" { // Prevents name mangling of functions | |||||
| #endif | |||||
| //---------------------------------------------------------------------------------- | |||||
| // Module Functions Declaration | |||||
| //---------------------------------------------------------------------------------- | |||||
| void InitPhysics(); // Initialize all internal physics values | |||||
| void SetPhysics(Physics settings); // Set physics settings values using Physics data type to overwrite internal physics settings | |||||
| 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 | |||||
| void ApplyPhysics(int index, Vector2 *position); // Apply physics to internal rigidbody, physics calculations are applied to position pointer parameter | |||||
| void SetRigidbodyEnabled(int index, bool state); // Set enabled state to a defined rigidbody | |||||
| void SetRigidbodyVelocity(int index, Vector2 velocity); // Set velocity of rigidbody (without considering of mass value) | |||||
| void AddRigidbodyForce(int index, Vector2 force); // Set rigidbody force (considering mass value) | |||||
| void SetColliderEnabled(int index, bool state); // Set enabled state to a defined collider | |||||
| Rigidbody GetRigidbody(int index); // Returns the internal rigidbody data defined by index parameter | |||||
| Collider GetCollider(int index); // Returns the internal collider data defined by index parameter | |||||
| #ifdef __cplusplus | |||||
| } | |||||
| #endif | |||||
| #endif // PHYSICS_H | |||||