big refactor
This commit is contained in:
@@ -1,3 +1,2 @@
|
||||
bin/
|
||||
.vscode/
|
||||
.DS_STORE/
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "macOS",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/include",
|
||||
"${workspaceFolder}/external/engine",
|
||||
"${workspaceFolder}/external/raygui",
|
||||
"${workspaceFolder}/external/rini",
|
||||
"/opt/homebrew/Cellar/raylib/5.5/include"
|
||||
],
|
||||
"cStandard": "c99",
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/include",
|
||||
"${workspaceFolder}/external/engine",
|
||||
"${workspaceFolder}/external/raygui",
|
||||
"${workspaceFolder}/external/rini",
|
||||
"C:/raylib/include"
|
||||
],
|
||||
"cStandard": "c99",
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
@@ -1,5 +1,32 @@
|
||||
COMPILER = gcc
|
||||
C_FLAGS = -std=c99 -g -Wall -Werror -Wpedantic -Wshadow -Wstrict-prototypes -Wno-unknown-pragmas
|
||||
|
||||
C_FLAG_STD_C99 = -std=c99 # Use the C99 language standard
|
||||
C_FLAG_DEBUG_INFO = -g # Include debug information
|
||||
# C_FLAG_HEADERS = -H # Prints paths of all headers
|
||||
C_FLAG_ALL_WARNINGS = -Wall # Enable most common warning
|
||||
C_FLAG_PEDANTIC = -Wpedantic # Enforce ISO C standard strictly
|
||||
C_FLAG_SHADOW = -Wshadow # Warn if a local variable shadows another
|
||||
C_FLAG_STRICT_PROTOS = -Wstrict-prototypes # Warn if function declarations are missing parameter types
|
||||
C_FLAG_NO_UNKNOWN_PRAGMAS = -Wno-unknown-pragmas # Suppress warnings about unknown pragmas
|
||||
C_FLAGS = \
|
||||
$(C_FLAG_STD_C99) \
|
||||
$(C_FLAG_DEBUG_INFO) \
|
||||
$(C_FLAG_HEADERS) \
|
||||
$(C_FLAG_ALL_WARNINGS) \
|
||||
$(C_FLAG_PEDANTIC) \
|
||||
$(C_FLAG_SHADOW) \
|
||||
$(C_FLAG_STRICT_PROTOS) \
|
||||
$(C_FLAG_NO_UNKNOWN_PRAGMAS)
|
||||
|
||||
INCLUDE_FLAGS = -Iinclude
|
||||
|
||||
EXTERNAL_ENGINE = -Iexternal/engine
|
||||
EXTERNAL_RAYGUI = -Iexternal/raygui
|
||||
EXTERNAL_RINI = -Iexternal/rini
|
||||
EXTERNAL_FLAGS = \
|
||||
$(EXTERNAL_ENGINE) \
|
||||
$(EXTERNAL_RINI) \
|
||||
$(EXTERNAL_RAYGUI)
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
SRC = src\main.c
|
||||
@@ -14,7 +41,7 @@ endif
|
||||
$(shell mkdir -p bin/osx bin/win)
|
||||
|
||||
build: $(SRC)
|
||||
$(COMPILER) $(SRC) -o $(TARGET) $(C_FLAGS) $(RAYLIB_FLAGS)
|
||||
$(COMPILER) $(SRC) -o $(TARGET) $(C_FLAGS) $(INCLUDE_FLAGS) $(EXTERNAL_FLAGS) $(RAYLIB_FLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
startScreen = 0 ; LOGO = 0, MENU = 1, GAMEPLAY = 2
|
||||
|
||||
display_title = The Last Hive
|
||||
display_width = 1280 ; in Pixel
|
||||
display_height = 720 ; in Pixel
|
||||
|
||||
showFPS = 1 ; OFF = 0, ON = 1
|
||||
|
||||
font_path = assets/SproutLandsUI/fonts/pixelFont-7-8x14-sproutLands.fnt
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include "input.h"
|
||||
#include <raymath.h>
|
||||
|
||||
Camera2D CreateCamera(int screenWidth, int screenHeight, Vector2 playerPosition, float initZoom){
|
||||
return (Camera2D){
|
||||
Vendored
+67
@@ -0,0 +1,67 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#define RINI_IMPLEMENTATION
|
||||
#define RINI_VALUE_DELIMITER '='
|
||||
|
||||
#include <rini.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
char *path;
|
||||
rini_config rini;
|
||||
} Config;
|
||||
|
||||
void InitConfig(Config *config, const char* path) {
|
||||
config->rini = rini_load_config(path);
|
||||
if (config->rini.count == 0) {
|
||||
printf("Warning: Loaded config has no entries. Path: %s\n", config->path);
|
||||
}
|
||||
}
|
||||
|
||||
int GetConfigInt(Config *config, const char *key) {
|
||||
return rini_get_config_value_fallback(config->rini, key, 0);
|
||||
}
|
||||
|
||||
int GetConfigIntOrDefault(Config *config, const char *key, int default_value) {
|
||||
return rini_get_config_value_fallback(config->rini, key, default_value);
|
||||
}
|
||||
|
||||
const char* GetConfigString(Config *config, const char *key) {
|
||||
return rini_get_config_value_text(config->rini, key);
|
||||
}
|
||||
|
||||
const char* GetConfigStringOrDefault(Config *config, const char *key, const char *default_value) {
|
||||
return rini_get_config_value_text_fallback(config->rini, key, default_value);
|
||||
}
|
||||
|
||||
const char* GetConfigDescription(Config *config, const char *key) {
|
||||
return rini_get_config_value_description(config->rini, key);
|
||||
}
|
||||
|
||||
int SetConfigInt(Config *config, const char *key, int value, const char *desc) {
|
||||
return rini_set_config_value(&config->rini, key, value, desc);
|
||||
}
|
||||
|
||||
int SetConfigString(Config *config, const char *key, const char *text, const char *desc) {
|
||||
return rini_set_config_value_text(&config->rini, key, text, desc);
|
||||
}
|
||||
|
||||
int SetConfigDescription(Config *config, const char *key, const char *desc) {
|
||||
return rini_set_config_value_description(&config->rini, key, desc);
|
||||
}
|
||||
|
||||
int AddCommentLine(Config *config, const char *comment) {
|
||||
return rini_set_config_comment_line(&config->rini, comment);
|
||||
}
|
||||
|
||||
void SaveConfig(Config *config) {
|
||||
rini_save_config(config->rini, config->path);
|
||||
}
|
||||
|
||||
void CleanUpConfig(Config *config) {
|
||||
rini_unload_config(&config->rini);
|
||||
}
|
||||
|
||||
#endif // CONFIG_H
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
const char* name;
|
||||
const char* title;
|
||||
} Display;
|
||||
|
||||
#endif // DISPLAY_H
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
#define GUI_H
|
||||
|
||||
#define RAYGUI_IMPLEMENTATION
|
||||
#include "../../include/raygui.h"
|
||||
#include <raygui.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef INPUT_H
|
||||
#define INPUT_H
|
||||
|
||||
#include <raymath.h>
|
||||
|
||||
typedef struct {
|
||||
Vector2 screenPosition;
|
||||
Vector2 worldPosition;
|
||||
+14
-6
@@ -1,30 +1,38 @@
|
||||
#ifndef PHYSICS_H
|
||||
#define PHYSICS_H
|
||||
|
||||
typedef struct {
|
||||
#include <raymath.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 direction;
|
||||
Vector2 velocity;
|
||||
float speed;
|
||||
} Physics;
|
||||
|
||||
void UpdatePhysicsDirection(Vector2 *direction, Vector2 vector){
|
||||
void UpdatePhysicsDirection(Vector2 *direction, Vector2 vector)
|
||||
{
|
||||
*direction = Vector2Normalize(vector);
|
||||
}
|
||||
|
||||
void UpdatePhysicsVelocity(Vector2 *velocity, Vector2 *direction, float *speed){
|
||||
void UpdatePhysicsVelocity(Vector2 *velocity, Vector2 *direction, float *speed)
|
||||
{
|
||||
*velocity = Vector2Scale(*direction, *speed * GetFrameTime());
|
||||
}
|
||||
|
||||
void UpdatePhysicsPosition(Vector2 *position, Vector2 *velocity) {
|
||||
void UpdatePhysicsPosition(Vector2 *position, Vector2 *velocity)
|
||||
{
|
||||
*position = Vector2Add(*position, *velocity);
|
||||
}
|
||||
|
||||
void UpdatePhysicsSpeed(float *speed, float *newSpeed){
|
||||
void UpdatePhysicsSpeed(float *speed, float *newSpeed)
|
||||
{
|
||||
*speed = *newSpeed;
|
||||
}
|
||||
|
||||
void UpdatePhysics(Physics *physics, Vector2 direction){
|
||||
void UpdatePhysics(Physics *physics, Vector2 direction)
|
||||
{
|
||||
UpdatePhysicsDirection(&physics->direction, direction);
|
||||
UpdatePhysicsVelocity(&physics->velocity, &physics->direction, &physics->speed);
|
||||
UpdatePhysicsPosition(&physics->position, &physics->velocity);
|
||||
+29
-21
@@ -1,46 +1,54 @@
|
||||
#ifndef SPRITE_H
|
||||
#define SPRITE_H
|
||||
|
||||
typedef struct {
|
||||
Texture2D texture;
|
||||
Rectangle sourceRec;
|
||||
Rectangle destRec;
|
||||
Vector2 frameSize;
|
||||
Vector2 origin;
|
||||
float rotation;
|
||||
#include <raymath.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Texture2D texture;
|
||||
Rectangle sourceRec;
|
||||
Rectangle destRec;
|
||||
Vector2 frameSize;
|
||||
Vector2 origin;
|
||||
float rotation;
|
||||
Color color;
|
||||
} Sprite;
|
||||
|
||||
void UpdateSpriteSourceRec(Sprite *sprite, const Vector2 *vector){
|
||||
void UpdateSpriteSourceRec(Sprite *sprite, const Vector2 *vector)
|
||||
{
|
||||
sprite->sourceRec.x = vector->x;
|
||||
sprite->sourceRec.y = vector->y;
|
||||
}
|
||||
|
||||
void UpdateSpriteDestRec(Sprite *sprite, const Vector2 *vector){
|
||||
void UpdateSpriteDestRec(Sprite *sprite, const Vector2 *vector)
|
||||
{
|
||||
sprite->destRec.x = vector->x;
|
||||
sprite->destRec.y = vector->y;
|
||||
}
|
||||
|
||||
void UpdateSpriteRotation(Sprite *sprite, Vector2 *vector){
|
||||
if(Vector2Length(*vector) <= 0.0f){
|
||||
void UpdateSpriteRotation(Sprite *sprite, Vector2 *vector)
|
||||
{
|
||||
if (Vector2Length(*vector) <= 0.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float targetRotation = (float)atan2(vector->y, vector->x) * (180.0f / PI) + 90.0f;
|
||||
sprite->rotation = Lerp(sprite->rotation, targetRotation, 0.1f);
|
||||
sprite->rotation = Lerp(sprite->rotation, targetRotation, 0.1f);
|
||||
}
|
||||
|
||||
void RenderSprite(const Sprite *sprite){
|
||||
void RenderSprite(const Sprite *sprite)
|
||||
{
|
||||
DrawTexturePro(
|
||||
sprite->texture,
|
||||
sprite->sourceRec,
|
||||
sprite->destRec,
|
||||
sprite->origin,
|
||||
sprite->rotation,
|
||||
sprite->color
|
||||
);
|
||||
sprite->texture,
|
||||
sprite->sourceRec,
|
||||
sprite->destRec,
|
||||
sprite->origin,
|
||||
sprite->rotation,
|
||||
sprite->color);
|
||||
}
|
||||
|
||||
void PrintSprite(const Sprite *sprite) {
|
||||
void PrintSprite(const Sprite *sprite)
|
||||
{
|
||||
printf("Sprite:\n");
|
||||
printf(" Sprite.texture: id = %d\n", sprite->texture.id);
|
||||
printf(" Sprite.sourceRec: x = %f, y = %f, width = %f, height = %f\n", sprite->sourceRec.x, sprite->sourceRec.y, sprite->sourceRec.width, sprite->sourceRec.height);
|
||||
Vendored
+842
@@ -0,0 +1,842 @@
|
||||
/**********************************************************************************************
|
||||
*
|
||||
* rini v1.0 - A simple and easy-to-use config init files reader and writer
|
||||
*
|
||||
* DESCRIPTION:
|
||||
* Load and save config init properties
|
||||
*
|
||||
* FEATURES:
|
||||
* - Config files reading and writing
|
||||
* - Supported value types: int, string
|
||||
* - Support comment lines and empty lines
|
||||
* - Support custom line comment delimiter
|
||||
* - Support custom value delimiters
|
||||
* - Support value description comments
|
||||
* - Support custom description custom delimiter
|
||||
* - Support multi-word text values w/o quote delimiters
|
||||
* - Minimal C standard lib dependency (optional)
|
||||
* - Customizable maximum config values capacity
|
||||
*
|
||||
* LIMITATIONS:
|
||||
* - Config [sections] not supported
|
||||
* - Saving config file requires complete rewrite
|
||||
*
|
||||
* POSSIBLE IMPROVEMENTS:
|
||||
* - Support config [sections]
|
||||
* - Support disabled entries recognition
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define RINI_IMPLEMENTATION
|
||||
* Generates the implementation of the library into the included file.
|
||||
* If not defined, the library is in header only mode and can be included in other headers
|
||||
* or source files without problems. But only ONE file should hold the implementation.
|
||||
*
|
||||
* #define RINI_MAX_LINE_SIZE
|
||||
* Defines the maximum size of line buffer to read from file.
|
||||
* Default value: 512 bytes (considering [key + text + desc] is 256 max size by default)
|
||||
*
|
||||
* #define RINI_MAX_KEY_SIZE
|
||||
* Defines the maximum size of value key
|
||||
* Default value: 64 bytes
|
||||
*
|
||||
* #define RINI_MAX_TEXT_SIZE
|
||||
* Defines the maximum size of value text
|
||||
* Default value: 128 bytes
|
||||
*
|
||||
* #define RINI_MAX_DESC_SIZE
|
||||
* Defines the maximum size of value description
|
||||
* Default value: 128 bytes
|
||||
*
|
||||
* #define RINI_MAX_VALUE_CAPACITY
|
||||
* Defines the maximum number of values supported
|
||||
* Default value: 128 entries support
|
||||
*
|
||||
* #define RINI_LINE_COMMENT_DELIMITER
|
||||
* Define character used to comment lines, placed at beginning of line
|
||||
* Most .ini files use semicolon ';' but '#' is also used
|
||||
* Default value: '#'
|
||||
*
|
||||
* #define RINI_LINE_SECTION_DELIMITER
|
||||
* Defines section lines start character
|
||||
* Sections loading is not supported, lines are just skipped for now
|
||||
* Default value: '['
|
||||
*
|
||||
* #define RINI_VALUE_DELIMITER
|
||||
* Defines a key value delimiter, in case it is defined.
|
||||
* Most .ini files use '=' as value delimiter but ':' is also used or just whitespace
|
||||
* Default value: ' '
|
||||
*
|
||||
* #define RINI_VALUE_QUOTATION_MARKS
|
||||
* Defines quotation marks to be used around text values
|
||||
* Text values are determined checking text with atoi(), only for integer values,
|
||||
* in case of float values they are always considered as text
|
||||
* Default value: '\"'
|
||||
*
|
||||
* #define RINI_DESCRIPTION_DELIMITER
|
||||
* Defines a property line-end comment delimiter
|
||||
* This implementation allows adding inline comments after the value.
|
||||
* Default value: '#'
|
||||
*
|
||||
* DEPENDENCIES: C standard library:
|
||||
* - stdio.h: fopen(), feof(), fgets(), fclose(), fprintf()
|
||||
* - stdlib.h: malloc(), calloc(), free()
|
||||
* - string.h: memset(), memcpy(), strcmp(), strlen()
|
||||
*
|
||||
* VERSIONS HISTORY:
|
||||
* 2.0 (26-Jan-2023) ADDED: Support custom comment lines (as config entries)
|
||||
* ADDED: Use of quotation-marks and marks customization
|
||||
* ADDED: rini_set_config_comment_line()
|
||||
* ADDED: rini_get_config_value_fallback(), with fallback return value
|
||||
* ADDED: rini_get_config_text_fallback(), with fallback return value
|
||||
* REMOVED: Config header requirement, use comments entries
|
||||
* REVIEWED: Some configuration default values, capacities
|
||||
* REVIEWED: rini_save_config(), removed parameter
|
||||
* REVIEWED: rini_save_config_from_memory(), removed parameter
|
||||
*
|
||||
* 1.0 (18-May-2023) First release, basic read/write functionality
|
||||
*
|
||||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2023-2025 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.
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#ifndef RINI_H
|
||||
#define RINI_H
|
||||
|
||||
#define RINI_VERSION "1.0"
|
||||
|
||||
// Function specifiers in case library is build/used as a shared library (Windows)
|
||||
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
|
||||
#if defined(_WIN32)
|
||||
#if defined(BUILD_LIBTYPE_SHARED)
|
||||
#define RINIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
|
||||
#elif defined(USE_LIBTYPE_SHARED)
|
||||
#define RINIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Function specifiers definition
|
||||
#ifndef RINIAPI
|
||||
#define RINIAPI // Functions defined as 'extern' by default (implicit specifiers)
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
// Allow custom memory allocators
|
||||
#ifndef RINI_MALLOC
|
||||
#define RINI_MALLOC(sz) malloc(sz)
|
||||
#endif
|
||||
#ifndef RINI_CALLOC
|
||||
#define RINI_CALLOC(n,sz) calloc(n,sz)
|
||||
#endif
|
||||
#ifndef RINI_FREE
|
||||
#define RINI_FREE(p) free(p)
|
||||
#endif
|
||||
|
||||
// Simple log system to avoid printf() calls if required
|
||||
// NOTE: Avoiding those calls, also avoids const strings memory usage
|
||||
#define RINI_SUPPORT_LOG_INFO
|
||||
#if defined(RINI_SUPPORT_LOG_INFO)
|
||||
#define RINI_LOG(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define RINI_LOG(...)
|
||||
#endif
|
||||
|
||||
#if !defined(RINI_MAX_LINE_SIZE)
|
||||
#define RINI_MAX_LINE_SIZE 512
|
||||
#endif
|
||||
|
||||
#if !defined(RINI_MAX_KEY_SIZE)
|
||||
#define RINI_MAX_KEY_SIZE 64
|
||||
#endif
|
||||
|
||||
#if !defined(RINI_MAX_TEXT_SIZE)
|
||||
#define RINI_MAX_TEXT_SIZE 128
|
||||
#endif
|
||||
|
||||
#if !defined(RINI_MAX_DESC_SIZE)
|
||||
#define RINI_MAX_DESC_SIZE 128
|
||||
#endif
|
||||
|
||||
#if !defined(RINI_MAX_VALUE_CAPACITY)
|
||||
#define RINI_MAX_VALUE_CAPACITY 128
|
||||
#endif
|
||||
|
||||
// Line comment delimiter (starting string)
|
||||
#if !defined(RINI_LINE_COMMENT_DELIMITER)
|
||||
#define RINI_LINE_COMMENT_DELIMITER '#'
|
||||
#endif
|
||||
|
||||
// Line section delimiter -NOT USED-
|
||||
#if !defined(RINI_LINE_SECTION_DELIMITER)
|
||||
#define RINI_LINE_SECTION_DELIMITER '['
|
||||
#endif
|
||||
|
||||
// Value delimiter, separator between key and value
|
||||
#if !defined(RINI_VALUE_DELIMITER)
|
||||
#define RINI_VALUE_DELIMITER ' '
|
||||
#endif
|
||||
|
||||
// Use quotation marks for text values
|
||||
// NOTE: Integer values do not use quotation-marks
|
||||
#define RINI_USE_TEXT_QUOTATION_MARKS 1
|
||||
// Text value quoation marks
|
||||
#if !defined(RINI_VALUE_QUOTATION_MARKS)
|
||||
#define RINI_VALUE_QUOTATION_MARKS '\"'
|
||||
#endif
|
||||
|
||||
// Description delimiter, separator between value and description
|
||||
#if !defined(RINI_DESCRIPTION_DELIMITER)
|
||||
#define RINI_DESCRIPTION_DELIMITER '#'
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// Config value entry
|
||||
typedef struct {
|
||||
char key[RINI_MAX_KEY_SIZE]; // Config value key identifier
|
||||
char text[RINI_MAX_TEXT_SIZE]; // Config value text
|
||||
char desc[RINI_MAX_DESC_SIZE]; // Config value description
|
||||
} rini_config_value;
|
||||
|
||||
// Config data
|
||||
typedef struct {
|
||||
rini_config_value *values; // Config values array
|
||||
unsigned int count; // Config values count
|
||||
unsigned int capacity; // Config values capacity
|
||||
} rini_config;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" { // Prevents name mangling of functions
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Functions declaration
|
||||
//------------------------------------------------------------------------------------
|
||||
RINIAPI rini_config rini_load_config(const char *file_name); // Load config from file (*.ini) or create a new config object (pass NULL)
|
||||
RINIAPI rini_config rini_load_config_from_memory(const char *text); // Load config from text buffer
|
||||
RINIAPI void rini_save_config(rini_config config, const char *file_name); // Save config to file, with custom header
|
||||
RINIAPI char *rini_save_config_to_memory(rini_config config); // Save config to text buffer ('\0' EOL)
|
||||
RINIAPI void rini_unload_config(rini_config *config); // Unload config data from memory
|
||||
|
||||
RINIAPI int rini_get_config_value(rini_config config, const char *key); // Get config value int for provided key, returns 0 if not found
|
||||
RINIAPI const char *rini_get_config_value_text(rini_config config, const char *key); // Get config value text for provided key
|
||||
RINIAPI const char *rini_get_config_value_description(rini_config config, const char *key); // Get config value description for provided key
|
||||
|
||||
RINIAPI int rini_get_config_value_fallback(rini_config config, const char *key, int fallback); // Get config value for provided key with default value fallback if not found or not valid
|
||||
RINIAPI const char *rini_get_config_value_text_fallback(rini_config config, const char *key, const char *fallback); // Get config value text for provided key with fallback if not found or not valid
|
||||
|
||||
RINIAPI int rini_set_config_comment_line(rini_config *config, const char *comment); // Set config comment line
|
||||
|
||||
// Set config value int/text and description for existing key or create a new entry
|
||||
// NOTE: When setting a text value, if id does not exist, a new entry is automatically created
|
||||
RINIAPI int rini_set_config_value(rini_config *config, const char *key, int value, const char *desc);
|
||||
RINIAPI int rini_set_config_value_text(rini_config *config, const char *key, const char *text, const char *desc);
|
||||
|
||||
// Set config value description for existing key
|
||||
// WARNING: Key must exist to add description, if a description exists, it is updated
|
||||
RINIAPI int rini_set_config_value_description(rini_config *config, const char *key, const char *desc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RINI_H
|
||||
|
||||
/***********************************************************************************
|
||||
*
|
||||
* RINI IMPLEMENTATION
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#if defined(RINI_IMPLEMENTATION)
|
||||
|
||||
#include <stdio.h> // Required for: fopen(), feof(), fgets(), fclose(), fprintf()
|
||||
#include <stdlib.h> // Required for: malloc(), calloc(), free()
|
||||
#include <string.h> // Required for: memset(), memcpy(), strcmp(), strlen()
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and macros
|
||||
//----------------------------------------------------------------------------------
|
||||
// ...
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global variables definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// ...
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module internal functions declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
static int rini_read_config_key(const char *buffer, char *key); // Get key from a buffer line containing key-value-(description)
|
||||
static int rini_read_config_value_text(const char *buffer, char *text, char *desc); // Get value text (and description) from a buffer line
|
||||
|
||||
static int rini_text_to_int(const char *text); // Convert text to int value (if possible), same as atoi()
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module functions definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// Load config from file (.ini)
|
||||
rini_config rini_load_config(const char *file_name)
|
||||
{
|
||||
rini_config config = { 0 };
|
||||
unsigned int value_counter = 0;
|
||||
|
||||
// Init config data to max capacity
|
||||
config.capacity = RINI_MAX_VALUE_CAPACITY;
|
||||
config.values = (rini_config_value *)RINI_CALLOC(RINI_MAX_VALUE_CAPACITY, sizeof(rini_config_value));
|
||||
|
||||
if (file_name != NULL)
|
||||
{
|
||||
FILE *rini_file = fopen(file_name, "rt");
|
||||
|
||||
if (rini_file != NULL)
|
||||
{
|
||||
char buffer[RINI_MAX_LINE_SIZE] = { 0 }; // Buffer to read every text line
|
||||
|
||||
// First pass to count valid config lines
|
||||
while (fgets(buffer, RINI_MAX_LINE_SIZE, rini_file))
|
||||
{
|
||||
// WARNING: fgets() keeps line endings, doesn't have any special options for converting line endings,
|
||||
// but on Windows, when reading file 'rt', line endings are converted from \r\n to just \n
|
||||
|
||||
// Skip commented lines and empty lines
|
||||
// NOTE: We are also skipping sections delimiters
|
||||
if ((buffer[0] != RINI_LINE_COMMENT_DELIMITER) &&
|
||||
(buffer[0] != RINI_LINE_SECTION_DELIMITER) &&
|
||||
(buffer[0] != '\n') && (buffer[0] != '\0')) value_counter++;
|
||||
}
|
||||
|
||||
// WARNING: We can't store more values than its max capacity
|
||||
config.count = (value_counter > RINI_MAX_VALUE_CAPACITY)? RINI_MAX_VALUE_CAPACITY : value_counter;
|
||||
|
||||
if (config.count > 0)
|
||||
{
|
||||
rewind(rini_file);
|
||||
value_counter = 0;
|
||||
|
||||
// Second pass to read config data
|
||||
while (fgets(buffer, RINI_MAX_LINE_SIZE, rini_file))
|
||||
{
|
||||
// WARNING: fgets() keeps line endings, doesn't have any special options for converting line endings,
|
||||
// but on Windows, when reading file 'rt', line endings are converted from \r\n to just \n
|
||||
|
||||
// Skip commented lines and empty lines
|
||||
if ((buffer[0] != RINI_LINE_COMMENT_DELIMITER) &&
|
||||
(buffer[0] != RINI_LINE_SECTION_DELIMITER) &&
|
||||
(buffer[0] != '\n') && (buffer[0] != '\0'))
|
||||
{
|
||||
// Get key identifier string
|
||||
memset(config.values[value_counter].key, 0, RINI_MAX_KEY_SIZE);
|
||||
rini_read_config_key(buffer, config.values[value_counter].key);
|
||||
rini_read_config_value_text(buffer, config.values[value_counter].text, config.values[value_counter].desc);
|
||||
|
||||
value_counter++;
|
||||
|
||||
// Stop reading if first count reached to avoid overflow in case count == RINI_MAX_VALUE_CAPACITY
|
||||
if (value_counter >= config.count) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(rini_file);
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// Load config from text buffer
|
||||
// NOTE: Comments and empty lines are ignored
|
||||
rini_config rini_load_config_from_memory(const char *text)
|
||||
{
|
||||
#define RINI_MAX_TEXT_LINES RINI_MAX_VALUE_CAPACITY*2 // Consider possible comments and empty lines
|
||||
|
||||
rini_config config = { 0 };
|
||||
unsigned int value_counter = 0;
|
||||
|
||||
// Init config data to max capacity
|
||||
config.capacity = RINI_MAX_VALUE_CAPACITY;
|
||||
config.values = (rini_config_value *)RINI_CALLOC(RINI_MAX_VALUE_CAPACITY, sizeof(rini_config_value));
|
||||
|
||||
if (text != NULL)
|
||||
{
|
||||
// Split text by line-breaks
|
||||
const char *lines[RINI_MAX_TEXT_LINES] = { 0 };
|
||||
int textSize = (int)strlen(text);
|
||||
lines[0] = text;
|
||||
int line_counter = 1;
|
||||
|
||||
for (int i = 0, k = 1; (i < textSize) && (line_counter < RINI_MAX_TEXT_LINES); i++)
|
||||
{
|
||||
if (text[i] == '\n')
|
||||
{
|
||||
lines[k] = &text[i + 1]; // WARNING: next value is valid?
|
||||
line_counter += 1;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Count possible values in lines
|
||||
for (int l = 0; l < line_counter; l++)
|
||||
{
|
||||
// Skip commented lines and empty lines
|
||||
// NOTE: We are also skipping sections delimiters
|
||||
if ((lines[l][0] != RINI_LINE_COMMENT_DELIMITER) &&
|
||||
(lines[l][0] != RINI_LINE_SECTION_DELIMITER) &&
|
||||
(lines[l][0] != '\n') && (lines[l][0] != '\0')) value_counter++;
|
||||
}
|
||||
|
||||
// WARNING: We can't store more values than its max capacity
|
||||
config.count = (value_counter > RINI_MAX_VALUE_CAPACITY)? RINI_MAX_VALUE_CAPACITY : value_counter;
|
||||
|
||||
// Process lines to get keys and values
|
||||
if (config.count > 0)
|
||||
{
|
||||
value_counter = 0;
|
||||
|
||||
// Second pass to read config data
|
||||
for (int l = 0; l < line_counter; l++)
|
||||
{
|
||||
// Skip commented lines and empty lines
|
||||
if ((lines[l][0] != RINI_LINE_COMMENT_DELIMITER) &&
|
||||
(lines[l][0] != RINI_LINE_SECTION_DELIMITER) &&
|
||||
(lines[l][0] != '\n') && (lines[l][0] != '\0'))
|
||||
{
|
||||
// Get key identifier string
|
||||
memset(config.values[value_counter].key, 0, RINI_MAX_KEY_SIZE);
|
||||
rini_read_config_key(lines[l], config.values[value_counter].key);
|
||||
rini_read_config_value_text(lines[l], config.values[value_counter].text, config.values[value_counter].desc);
|
||||
|
||||
value_counter++;
|
||||
|
||||
// Stop reading if first count reached to avoid overflow in case count == RINI_MAX_VALUE_CAPACITY
|
||||
if (value_counter >= config.count) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// Save config to file (*.ini)
|
||||
void rini_save_config(rini_config config, const char *file_name)
|
||||
{
|
||||
FILE *rini_file = fopen(file_name, "wt");
|
||||
|
||||
if (rini_file != NULL)
|
||||
{
|
||||
for (unsigned int i = 0; i < config.count; i++)
|
||||
{
|
||||
if ((config.values[i].key[0] == '\0') && (config.values[i].text[0] == RINI_LINE_COMMENT_DELIMITER))
|
||||
{
|
||||
if (config.values[i].desc[0] != '\0') fprintf(rini_file, "%c %s\n", RINI_LINE_COMMENT_DELIMITER, config.values[i].desc);
|
||||
else fprintf(rini_file, "%c\n", RINI_LINE_COMMENT_DELIMITER);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if RINI_USE_TEXT_QUOTATION_MARKS
|
||||
// If text is not an integer value, append text quotation-marks
|
||||
// TODO: Check also for float values? atof()
|
||||
bool valueIsInt = false;
|
||||
int value = atoi(config.values[i].text); // WARNING: Returns 0 if input not valid --> Check if (config.values[i].text len == 1 && config.values[i].text[0] == '0')
|
||||
if (((value == 0) && (strlen(config.values[i].text) == 1) && (config.values[i].text[0] == '0')) || (value != 0)) valueIsInt = true;
|
||||
|
||||
if (valueIsInt)
|
||||
{
|
||||
fprintf(rini_file, "%-28s %c %6s %c %s\n", config.values[i].key, RINI_VALUE_DELIMITER,
|
||||
config.values[i].text, RINI_DESCRIPTION_DELIMITER, config.values[i].desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(rini_file, "%-28s %c %c%6s%c %c %s\n", config.values[i].key, RINI_VALUE_DELIMITER,
|
||||
RINI_VALUE_QUOTATION_MARKS, config.values[i].text, RINI_VALUE_QUOTATION_MARKS,
|
||||
RINI_DESCRIPTION_DELIMITER, config.values[i].desc);
|
||||
}
|
||||
#else
|
||||
fprintf(rini_file, "%-28s %c %6s %c %s\n", config.values[i].key, RINI_VALUE_DELIMITER,
|
||||
config.values[i].text, RINI_DESCRIPTION_DELIMITER, config.values[i].desc);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
fclose(rini_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Save config to text buffer ('\0' EOL)
|
||||
char *rini_save_config_to_memory(rini_config config)
|
||||
{
|
||||
#define RINI_MAX_TEXT_FILE_SIZE 4096
|
||||
|
||||
// Verify required config size is smaller than memory buffer size
|
||||
// NOTE: We add 64 extra possible characters by entry line
|
||||
int requiredSize = 0;
|
||||
for (unsigned int i = 0; i < config.count; i++) requiredSize += ((int)strlen(config.values[i].key) + (int)strlen(config.values[i].text) + (int)strlen(config.values[i].desc) + 64);
|
||||
if (requiredSize > RINI_MAX_TEXT_FILE_SIZE) RINI_LOG("WARNING: Required config.ini size is bigger than max supported memory size, increase RINI_MAX_TEXT_FILE_SIZE\n");
|
||||
|
||||
// NOTE: Using a static buffer to avoid de-allocation requirement on user side
|
||||
static char text[RINI_MAX_TEXT_FILE_SIZE] = { 0 };
|
||||
memset(text, 0, RINI_MAX_TEXT_FILE_SIZE);
|
||||
int offset = 0;
|
||||
|
||||
for (unsigned int i = 0; i < config.count; i++)
|
||||
{
|
||||
if ((config.values[i].key[0] == '\0') && (config.values[i].text[0] == RINI_LINE_COMMENT_DELIMITER))
|
||||
{
|
||||
if (config.values[i].desc[0] != '\0') offset += sprintf(text + offset, "%c %s\n", RINI_LINE_COMMENT_DELIMITER, config.values[i].desc);
|
||||
else offset += sprintf(text + offset, "%c\n", RINI_LINE_COMMENT_DELIMITER);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if RINI_USE_TEXT_QUOTATION_MARKS
|
||||
// If text is not an integer value, append text quotation-marks
|
||||
// TODO: Check also for float values? atof()
|
||||
bool valueIsInt = false;
|
||||
int value = atoi(config.values[i].text); // WARNING: Returns 0 if input not valid --> Check if (config.values[i].text len == 1 && config.values[i].text[0] == '0')
|
||||
if (((value == 0) && (strlen(config.values[i].text) == 1) && (config.values[i].text[0] == '0')) || (value != 0)) valueIsInt = true;
|
||||
|
||||
if (valueIsInt)
|
||||
{
|
||||
offset += sprintf(text + offset, "%-28s %c %6s %c %s\n", config.values[i].key, RINI_VALUE_DELIMITER,
|
||||
config.values[i].text, RINI_DESCRIPTION_DELIMITER, config.values[i].desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += sprintf(text + offset, "%-28s %c %c%6s%c %c %s\n", config.values[i].key, RINI_VALUE_DELIMITER,
|
||||
RINI_VALUE_QUOTATION_MARKS, config.values[i].text, RINI_VALUE_QUOTATION_MARKS,
|
||||
RINI_DESCRIPTION_DELIMITER, config.values[i].desc);
|
||||
}
|
||||
#else
|
||||
offset += sprintf(text + offset, "%-28s %c %6s %c %s\n", config.values[i].key, RINI_VALUE_DELIMITER,
|
||||
config.values[i].text, RINI_DESCRIPTION_DELIMITER, config.values[i].desc);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// Unload config data
|
||||
void rini_unload_config(rini_config *config)
|
||||
{
|
||||
RINI_FREE(config->values);
|
||||
|
||||
config->values = NULL;
|
||||
config->count = 0;
|
||||
config->capacity = 0;
|
||||
}
|
||||
|
||||
// Get config value for provided key, returns 0 if not found or not valid
|
||||
int rini_get_config_value(rini_config config, const char *key)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
for (unsigned int i = 0; i < config.count; i++)
|
||||
{
|
||||
if (strcmp(key, config.values[i].key) == 0) // Key found
|
||||
{
|
||||
value = rini_text_to_int(config.values[i].text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Get config value for provided key with default value fallback if not found or not valid
|
||||
int rini_get_config_value_fallback(rini_config config, const char *key, int fallback)
|
||||
{
|
||||
int value = fallback;
|
||||
|
||||
for (unsigned int i = 0; i < config.count; i++)
|
||||
{
|
||||
if (strcmp(key, config.values[i].key) == 0) // Key found
|
||||
{
|
||||
// TODO: Detect if conversion fails...
|
||||
value = rini_text_to_int(config.values[i].text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Get config text for string id
|
||||
const char *rini_get_config_value_text(rini_config config, const char *key)
|
||||
{
|
||||
const char *text = NULL;
|
||||
|
||||
for (unsigned int i = 0; i < config.count; i++)
|
||||
{
|
||||
if (strcmp(key, config.values[i].key) == 0) // Key found
|
||||
{
|
||||
text = config.values[i].text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// Get config value text for provided key with fallback if not found or not valid
|
||||
RINIAPI const char *rini_get_config_value_text_fallback(rini_config config, const char *key, const char *fallback)
|
||||
{
|
||||
const char *text = fallback;
|
||||
|
||||
for (unsigned int i = 0; i < config.count; i++)
|
||||
{
|
||||
if (strcmp(key, config.values[i].key) == 0) // Key found
|
||||
{
|
||||
text = config.values[i].text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// Get config description for string id
|
||||
const char *rini_get_config_value_description(rini_config config, const char *key)
|
||||
{
|
||||
const char *desc = NULL;
|
||||
|
||||
for (unsigned int i = 0; i < config.count; i++)
|
||||
{
|
||||
if (strcmp(key, config.values[i].key) == 0) // Key found
|
||||
{
|
||||
desc = config.values[i].desc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
// Set config comment line
|
||||
int rini_set_config_comment_line(rini_config *config, const char *comment)
|
||||
{
|
||||
int result = -1;
|
||||
char text[2] = { RINI_LINE_COMMENT_DELIMITER, '\0' };
|
||||
|
||||
result = rini_set_config_value_text(config, NULL, text, comment);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Set config value and description for existing key or create a new entry
|
||||
int rini_set_config_value(rini_config *config, const char *key, int value, const char *desc)
|
||||
{
|
||||
int result = -1;
|
||||
char value_text[RINI_MAX_TEXT_SIZE] = { 0 };
|
||||
|
||||
sprintf(value_text, "%i", value);
|
||||
|
||||
result = rini_set_config_value_text(config, key, value_text, desc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Set config value text and description for existing key or create a new entry
|
||||
// NOTE: When setting a text value, if id does not exist, a new entry is automatically created
|
||||
int rini_set_config_value_text(rini_config *config, const char *key, const char *text, const char *desc)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if ((text == NULL) || (text[0] == '\0')) return result;
|
||||
|
||||
if (key != NULL)
|
||||
{
|
||||
// Try to find key and update text and description
|
||||
for (unsigned int i = 0; i < config->count; i++)
|
||||
{
|
||||
if (strcmp(key, config->values[i].key) == 0) // Key found
|
||||
{
|
||||
memset(config->values[i].text, 0, RINI_MAX_TEXT_SIZE);
|
||||
memcpy(config->values[i].text, text, strlen(text));
|
||||
|
||||
memset(config->values[i].desc, 0, RINI_MAX_DESC_SIZE);
|
||||
if (desc != NULL) memcpy(config->values[i].desc, desc, strlen(desc));
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Key not found, we add a new entry if possible
|
||||
if (result == -1)
|
||||
{
|
||||
if (config->count < config->capacity)
|
||||
{
|
||||
// NOTE: Supporting comment line entries
|
||||
if ((key == NULL) && (text[0] == RINI_LINE_COMMENT_DELIMITER))
|
||||
{
|
||||
config->values[config->count].key[0] = '\0';
|
||||
config->values[config->count].text[0] = RINI_LINE_COMMENT_DELIMITER;
|
||||
if (desc != NULL) for (int i = 0; (i < RINI_MAX_DESC_SIZE) && (desc[i] != '\0'); i++) config->values[config->count].desc[i] = desc[i];
|
||||
else config->values[config->count].desc[0] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: We do a manual copy to avoid possible overflows on input data
|
||||
for (int i = 0; (i < RINI_MAX_KEY_SIZE) && (key[i] != '\0'); i++) config->values[config->count].key[i] = key[i];
|
||||
for (int i = 0; (i < RINI_MAX_TEXT_SIZE) && (text[i] != '\0'); i++) config->values[config->count].text[i] = text[i];
|
||||
for (int i = 0; (i < RINI_MAX_DESC_SIZE) && (desc[i] != '\0'); i++) config->values[config->count].desc[i] = desc[i];
|
||||
}
|
||||
|
||||
config->count++;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Set config value description for existing key
|
||||
// WARNING: Key must exist to add description, if a description exists, it is updated
|
||||
int rini_set_config_value_description(rini_config *config, const char *key, const char *desc)
|
||||
{
|
||||
int result = 1;
|
||||
|
||||
for (unsigned int i = 0; i < config->count; i++)
|
||||
{
|
||||
if (strcmp(key, config->values[i].key) == 0) // Key found
|
||||
{
|
||||
memset(config->values[i].desc, 0, RINI_MAX_DESC_SIZE);
|
||||
if (desc != NULL) memcpy(config->values[i].desc, desc, strlen(desc));
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module internal functions declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
// Get string id from a buffer line containing id-value pair
|
||||
static int rini_read_config_key(const char *buffer, char *key)
|
||||
{
|
||||
int len = 0;
|
||||
while ((buffer[len] != '\0') && (buffer[len] != ' ') && (buffer[len] != RINI_VALUE_DELIMITER)) len++; // Skip keyentifier
|
||||
|
||||
memcpy(key, buffer, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// Get config string-value from a buffer line containing id-value pair
|
||||
static int rini_read_config_value_text(const char *buffer, char *text, char *desc)
|
||||
{
|
||||
char *buffer_ptr = (char *)buffer;
|
||||
|
||||
// Expected config line structure:
|
||||
// [key][spaces?][delimiter?][spaces?][quot-mark?][textValue][quot-mark?][spaces?][[;][#]description?]
|
||||
// We need to skip spaces, check for delimiter (if required), skip spaces, and get text value
|
||||
|
||||
while ((buffer_ptr[0] != '\0') && (buffer_ptr[0] != ' ')) buffer_ptr++; // Skip keyentifier
|
||||
|
||||
while ((buffer_ptr[0] != '\0') && (buffer_ptr[0] == ' ')) buffer_ptr++; // Skip line spaces before text value or delimiter
|
||||
|
||||
#if defined(RINI_VALUE_DELIMITER)
|
||||
if (buffer_ptr[0] == RINI_VALUE_DELIMITER)
|
||||
{
|
||||
buffer_ptr++; // Skip delimiter
|
||||
|
||||
while ((buffer_ptr[0] != '\0') && (buffer_ptr[0] == ' ')) buffer_ptr++; // Skip line spaces before text value
|
||||
}
|
||||
#endif
|
||||
|
||||
// Now buffer_ptr should be pointing to the start of value
|
||||
|
||||
int len = 0;
|
||||
while ((buffer_ptr[len] != '\0') &&
|
||||
(buffer_ptr[len] != '\r') &&
|
||||
(buffer_ptr[len] != '\n')) len++; // Get text-value and description length (to the end of line)
|
||||
|
||||
// Now we got the length from text-value start to end of line
|
||||
|
||||
int value_len = len;
|
||||
int desc_pos = 0;
|
||||
#if defined(RINI_DESCRIPTION_DELIMITER)
|
||||
// Scan text looking for text-value description (if used)
|
||||
for (; desc_pos < len; desc_pos++)
|
||||
{
|
||||
if (buffer_ptr[desc_pos] == RINI_DESCRIPTION_DELIMITER)
|
||||
{
|
||||
value_len = desc_pos - 1;
|
||||
while (buffer_ptr[value_len] == ' ') value_len--;
|
||||
|
||||
value_len++;
|
||||
|
||||
desc_pos++; // Skip delimiter and following spaces
|
||||
while (buffer_ptr[desc_pos] == ' ') desc_pos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if RINI_USE_TEXT_QUOTATION_MARKS
|
||||
// Remove starting quotation-mark from text (if being used)
|
||||
if (buffer_ptr[0] == RINI_VALUE_QUOTATION_MARKS)
|
||||
{
|
||||
buffer_ptr++; desc_pos--; len--; value_len--;
|
||||
|
||||
// Remove ending quotation-mark from text (if being used)
|
||||
if (buffer_ptr[value_len - 1] == RINI_VALUE_QUOTATION_MARKS) { value_len--; }
|
||||
}
|
||||
#endif
|
||||
|
||||
// Clear text buffers to be updated
|
||||
memset(text, 0, RINI_MAX_TEXT_SIZE);
|
||||
memset(desc, 0, RINI_MAX_DESC_SIZE);
|
||||
|
||||
// Copy value-text and description to provided pointers
|
||||
memcpy(text, buffer_ptr, value_len);
|
||||
memcpy(desc, buffer_ptr + desc_pos, ((len - desc_pos) > (RINI_MAX_DESC_SIZE - 1))? (RINI_MAX_DESC_SIZE - 1) : (len - desc_pos));
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// Convert text to int value (if possible), same as atoi()
|
||||
static int rini_text_to_int(const char *text)
|
||||
{
|
||||
int value = 0;
|
||||
int sign = 1;
|
||||
|
||||
if ((text[0] == '+') || (text[0] == '-'))
|
||||
{
|
||||
if (text[0] == '-') sign = -1;
|
||||
text++;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0');
|
||||
|
||||
//if (strlen(text) != i) // Text starts with numbers but contains some text after that...
|
||||
|
||||
return value*sign;
|
||||
}
|
||||
|
||||
#endif // RINI_IMPLEMENTATION
|
||||
@@ -0,0 +1,73 @@
|
||||
#ifndef APP_H
|
||||
#define APP_H
|
||||
|
||||
#include <config.h>
|
||||
#include <display.h>
|
||||
|
||||
#include "screen.h"
|
||||
#include "applicationstate.h"
|
||||
#include "font.h"
|
||||
#include "logo.h"
|
||||
#include "menu.h"
|
||||
#include "game.h"
|
||||
|
||||
typedef struct {
|
||||
Config config;
|
||||
State state;
|
||||
Display display;
|
||||
Font font;
|
||||
LogoState logo;
|
||||
GameState game;
|
||||
MenuState menu;
|
||||
} Application;
|
||||
|
||||
void ConfigApp(Application* app){
|
||||
InitConfig(&app->config, "config/config.ini");
|
||||
app->state.currentScreen = GetConfigInt(&app->config, "startScreen");
|
||||
app->state.running = true;
|
||||
app->state.gameStarted = false;
|
||||
app->state.flagFPS = GetConfigInt(&app->config, "showFPS");
|
||||
app->display.title = GetConfigString(&app->config, "display_title");
|
||||
app->display.width = GetConfigInt(&app->config, "display_width");
|
||||
app->display.height = GetConfigInt(&app->config, "display_height");
|
||||
}
|
||||
|
||||
void InitApp(Application *app){
|
||||
InitFont(&app->font);
|
||||
InitLogo(&app->logo);
|
||||
InitMenu(&app->menu);
|
||||
InitGame(&app->game,&app->display);
|
||||
}
|
||||
|
||||
void UpdateApp(Application *app){
|
||||
while (app->state.running)
|
||||
{
|
||||
switch (app->state.currentScreen)
|
||||
{
|
||||
case LOGO:
|
||||
{
|
||||
UpdateLogo(&app->logo, &app->state);
|
||||
RenderLogo(&app->logo, &app->state);
|
||||
}break;
|
||||
case MENU:
|
||||
{
|
||||
UpdateMenu(&app->menu, &app->state);
|
||||
RenderMenu(&app->menu, &app->state, &app->font, app->display.title);
|
||||
}break;
|
||||
case GAMEPLAY:
|
||||
{
|
||||
UpdateGame(&app->game, &app->state);
|
||||
RenderGame(&app->game, &app->state);
|
||||
}break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CleanupApp(Application *app){
|
||||
CleanupMenu(&app->menu);
|
||||
CleanupGame(&app->game);
|
||||
CleanupFont(&app->font);
|
||||
}
|
||||
|
||||
#endif //APP_H
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef BACKGROUND_H
|
||||
#define BACKGROUND_H
|
||||
#include "../engine/sprite.h"
|
||||
#include "raylib.h"
|
||||
#include <sprite.h>
|
||||
#include <raylib.h>
|
||||
|
||||
typedef struct {
|
||||
Sprite sprite;
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef BEE_H
|
||||
#define BEE_H
|
||||
#include "../engine/sprite.h"
|
||||
#include "../engine/animation.h"
|
||||
#include "../engine/physics.h"
|
||||
#include "../engine/object.h"
|
||||
#include <sprite.h>
|
||||
#include <animation.h>
|
||||
#include <physics.h>
|
||||
#include <object.h>
|
||||
|
||||
typedef enum {
|
||||
FLYING
|
||||
@@ -1,44 +1,46 @@
|
||||
#ifndef Floor_H
|
||||
#define Floor_H
|
||||
#include "../engine/sprite.h"
|
||||
#include <sprite.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
Sprite sprite;
|
||||
Rectangle bounds;
|
||||
} Floor;
|
||||
|
||||
Floor CreateFloor(Texture2D texture, float textureWidth){
|
||||
Floor CreateFloor(Texture2D texture, float textureWidth)
|
||||
{
|
||||
return (Floor){
|
||||
.sprite = {
|
||||
.texture = texture,
|
||||
.frameSize = {textureWidth,textureWidth},
|
||||
.sourceRec = { 0.0f, 0.0f, textureWidth, textureWidth},
|
||||
.frameSize = {textureWidth, textureWidth},
|
||||
.sourceRec = {0.0f, 0.0f, textureWidth, textureWidth},
|
||||
.destRec = {0.0f, 0.0f, textureWidth, textureWidth},
|
||||
.origin = {textureWidth / 2, textureWidth / 2},
|
||||
.rotation = 0.0f,
|
||||
.color = WHITE
|
||||
},
|
||||
.bounds = {0.0f,0.0f,0.0f,0.0f}
|
||||
};
|
||||
.color = WHITE},
|
||||
.bounds = {0.0f, 0.0f, 0.0f, 0.0f}};
|
||||
}
|
||||
|
||||
void UpdateFloor(Floor *floor, const Camera2D *camera){
|
||||
void UpdateFloor(Floor *floor, const Camera2D *camera)
|
||||
{
|
||||
floor->bounds.x = (int)((camera->target.x - (GetScreenWidth() / 2.0f / camera->zoom)) / floor->sprite.frameSize.x) - 1;
|
||||
floor->bounds.width = (int)((camera->target.x + (GetScreenWidth() / 2.0f / camera->zoom)) / floor->sprite.frameSize.x) + 1;
|
||||
floor->bounds.y = (int)((camera->target.y - (GetScreenHeight() / 2.0f / camera->zoom)) / floor->sprite.frameSize.y) - 1;
|
||||
floor->bounds.height = (int)((camera->target.y + (GetScreenHeight() / 2.0f / camera->zoom)) / floor->sprite.frameSize.y) + 1;
|
||||
}
|
||||
|
||||
void RenderFloor(Floor *floor){
|
||||
void RenderFloor(Floor *floor)
|
||||
{
|
||||
for (int y = (int)floor->bounds.y; y <= (int)floor->bounds.height; y++)
|
||||
{
|
||||
for (int x = (int)floor->bounds.x; x <= (int)floor->bounds.width; x++)
|
||||
{
|
||||
for (int x = (int)floor->bounds.x; x <= (int)floor->bounds.width; x++)
|
||||
{
|
||||
Vector2 floorPosition = {x * floor->sprite.frameSize.x, y * floor->sprite.frameSize.y};
|
||||
UpdateSpriteDestRec(&floor->sprite, &floorPosition);
|
||||
RenderSprite(&floor->sprite);
|
||||
}
|
||||
Vector2 floorPosition = {x * floor->sprite.frameSize.x, y * floor->sprite.frameSize.y};
|
||||
UpdateSpriteDestRec(&floor->sprite, &floorPosition);
|
||||
RenderSprite(&floor->sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //Floor_H
|
||||
#endif // Floor_H
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef FLOWERS_H
|
||||
#define FLOWERS_H
|
||||
|
||||
#include <object.h>
|
||||
|
||||
ObjectArray CreateFlowers(Texture2D texture, float frameWidth, float rotation, float fieldSize)
|
||||
{
|
||||
ObjectArray flowers = CreateObjectArray(&(Object){
|
||||
.sprite = {
|
||||
.texture = texture,
|
||||
.sourceRec = {0.0f, 0.0f, frameWidth, frameWidth},
|
||||
.destRec = {0.0f, 0.0f, frameWidth, frameWidth},
|
||||
.origin = {frameWidth / 2, frameWidth / 2},
|
||||
.rotation = rotation,
|
||||
.color = WHITE},
|
||||
.position = {0.0f, 0.0f}},
|
||||
10);
|
||||
|
||||
if (!flowers.data)
|
||||
{
|
||||
printf("Memory allocation failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SetRandomPositionForObjectArray(&flowers, (Rectangle){-fieldSize, -fieldSize, fieldSize * 2, fieldSize * 2});
|
||||
|
||||
return flowers;
|
||||
}
|
||||
|
||||
#endif // FLOWERS_H
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
void InitFont(Font *font){
|
||||
*font = LoadFont("assets/SproutLandsUI/fonts/pixelFont-7-8x14-sproutLands.fnt");
|
||||
SetTextureFilter(font->texture, TEXTURE_FILTER_POINT);
|
||||
}
|
||||
|
||||
void CleanupFont(Font *font){
|
||||
UnloadFont(*font);
|
||||
}
|
||||
|
||||
#endif //FONT_H
|
||||
@@ -1,12 +1,14 @@
|
||||
#ifndef GAME_H
|
||||
#define GAME_H
|
||||
#include "../engine/object.h"
|
||||
#include "../engine/camera.h"
|
||||
#include "../engine/input.h"
|
||||
#include "../engine/postfx.h"
|
||||
#include "../engine/soundtrack.h"
|
||||
#include "../engine/asset.h"
|
||||
#include "../engine/applicationstate.h"
|
||||
|
||||
#include <object.h>
|
||||
#include <camera.h>
|
||||
#include <input.h>
|
||||
#include <postfx.h>
|
||||
#include <soundtrack.h>
|
||||
#include <asset.h>
|
||||
|
||||
#include "applicationstate.h"
|
||||
#include "gameassets.h"
|
||||
#include "floor.h"
|
||||
#include "player.h"
|
||||
@@ -14,7 +16,8 @@
|
||||
#include "hive.h"
|
||||
#include "flowers.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
Assets assets;
|
||||
Texture2D textures[TEX_COUNT];
|
||||
PostProcessing postFX[SHADER_COUNT];
|
||||
@@ -30,52 +33,69 @@ typedef struct {
|
||||
Image image;
|
||||
} GameState;
|
||||
|
||||
void InitGame(GameState* g, Display *display){
|
||||
void InitGame(GameState *g, Display *display)
|
||||
{
|
||||
|
||||
g->assets = (Assets){
|
||||
.textureAssets = texAssets,
|
||||
.shaderAssets = shaderAssets,
|
||||
.soundtrackAssets = soundtrackAssets
|
||||
};
|
||||
.soundtrackAssets = soundtrackAssets};
|
||||
|
||||
for (int i = 0; i < TEX_COUNT; i++){
|
||||
for (int i = 0; i < TEX_COUNT; i++)
|
||||
{
|
||||
g->textures[i] = LoadTexture(g->assets.textureAssets[i].path);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SHADER_COUNT; i++){
|
||||
for (int i = 0; i < SHADER_COUNT; i++)
|
||||
{
|
||||
g->postFX[i] = CreatePostFX(g->assets.shaderAssets[i].path);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOUNDTRACK_COUNT; i++){
|
||||
for (int i = 0; i < SOUNDTRACK_COUNT; i++)
|
||||
{
|
||||
g->soundtracks[i] = LoadSoundtrack(g->assets.soundtrackAssets[i].path);
|
||||
}
|
||||
|
||||
// Target texture
|
||||
g->target = LoadRenderTexture(display->width, display->height);
|
||||
|
||||
|
||||
// Static Entities
|
||||
g->flowers = CreateFlowers(g->textures[FLOWER], g->assets.textureAssets[FLOWER].frameWidth, g->assets.textureAssets[FLOWER].rotation, 50.0f);
|
||||
g->flowers = CreateFlowers(g->textures[FLOWER], g->assets.textureAssets[FLOWER].frameWidth, g->assets.textureAssets[FLOWER].rotation, 50.0f);
|
||||
g->floor = CreateFloor(g->textures[GRASS], g->assets.textureAssets[GRASS].frameWidth);
|
||||
g->hive = CreateHive(g->textures[HIVE], g->assets.textureAssets[HIVE].frameWidth);
|
||||
|
||||
|
||||
// Animated Entities
|
||||
g->player = CreatePlayer(IDLE_DOWN, HOE, g->textures[PLAYER], g->assets.textureAssets[PLAYER].frameWidth, 4, 2, g->hive.position, g->assets.textureAssets[PLAYER].rotation, 50.0f);
|
||||
g->bee1 = CreateBee(FLYING, g->textures[BEE], g->assets.textureAssets[BEE].frameWidth, 4, 10, g->hive.position, 10.0f, &g->flowers, &g->hive);
|
||||
|
||||
|
||||
// I/O
|
||||
g->camera = CreateCamera(display->width, display->height, g->player.physics.position, 10.0f);
|
||||
|
||||
|
||||
g->mouse = CreateMouse(0.10f, 5.0f, 10.0f, &g->textures[CURSOR]);
|
||||
|
||||
g->mouse = CreateMouse(0.10f, 5.0f, 10.0f, &g->textures[CURSOR]);
|
||||
}
|
||||
|
||||
void UpdateGame(GameState* g, State *state){
|
||||
if (GetFPS() <= 60){ SetTargetFPS(0); }
|
||||
if (IsKeyPressed(KEY_ESCAPE)){ state->currentScreen = MENU; }
|
||||
if (WindowShouldClose() && !IsKeyPressed(KEY_ESCAPE)) { state->running = false; }
|
||||
for (int i = 0; i < SHADER_COUNT; i++){ UpdatePostFX(&g->postFX[i]); }
|
||||
for (int i = 0; i < SOUNDTRACK_COUNT; i++){ UpdateSoundtrack(&g->soundtracks[i]); }
|
||||
void UpdateGame(GameState *g, State *state)
|
||||
{
|
||||
if (GetFPS() <= 60)
|
||||
{
|
||||
SetTargetFPS(0);
|
||||
}
|
||||
if (IsKeyPressed(KEY_ESCAPE))
|
||||
{
|
||||
state->currentScreen = MENU;
|
||||
}
|
||||
if (WindowShouldClose() && !IsKeyPressed(KEY_ESCAPE))
|
||||
{
|
||||
state->running = false;
|
||||
}
|
||||
for (int i = 0; i < SHADER_COUNT; i++)
|
||||
{
|
||||
UpdatePostFX(&g->postFX[i]);
|
||||
}
|
||||
for (int i = 0; i < SOUNDTRACK_COUNT; i++)
|
||||
{
|
||||
UpdateSoundtrack(&g->soundtracks[i]);
|
||||
}
|
||||
|
||||
UpdateMouse(&g->mouse, &g->camera);
|
||||
UpdateCamera2D(&g->camera, &g->player.physics.position, &g->mouse);
|
||||
@@ -84,7 +104,8 @@ void UpdateGame(GameState* g, State *state){
|
||||
UpdateBee(&g->bee1, &g->flowers, &g->hive);
|
||||
}
|
||||
|
||||
void RenderComponents(GameState* g){
|
||||
void RenderComponents(GameState *g)
|
||||
{
|
||||
RenderFloor(&g->floor);
|
||||
RenderSprite(&g->hive.sprite);
|
||||
RenderObjectArray(&g->flowers);
|
||||
@@ -92,32 +113,48 @@ void RenderComponents(GameState* g){
|
||||
RenderSprite(&g->bee1.sprite);
|
||||
}
|
||||
|
||||
void RenderGame(GameState* g, const State *appState){
|
||||
void RenderGame(GameState *g, const State *appState)
|
||||
{
|
||||
BeginTextureMode(g->target);
|
||||
ClearBackground(BLACK);
|
||||
BeginMode2D(g->camera);
|
||||
RenderComponents(g);
|
||||
EndMode2D();
|
||||
DrawTextureRec(g->mouse.cursorTexture, (Rectangle){ 0, 0, g->mouse.cursorTexture.width, g->mouse.cursorTexture.height }, (Vector2){ g->mouse.screenPosition.x, g->mouse.screenPosition.y}, WHITE);
|
||||
ClearBackground(BLACK);
|
||||
BeginMode2D(g->camera);
|
||||
RenderComponents(g);
|
||||
EndMode2D();
|
||||
DrawTextureRec(g->mouse.cursorTexture, (Rectangle){0, 0, g->mouse.cursorTexture.width, g->mouse.cursorTexture.height}, (Vector2){g->mouse.screenPosition.x, g->mouse.screenPosition.y}, WHITE);
|
||||
EndTextureMode();
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
for (int i = 0; i < SHADER_COUNT; i++){
|
||||
RenderPostFX(&g->postFX[i], &g->target);
|
||||
}
|
||||
DrawText( TextFormat("%d", g->player.inventar.seedCount), 10, 10, 50, WHITE);
|
||||
|
||||
if (appState->flagFPS){
|
||||
DrawFPS(10, 10);
|
||||
}
|
||||
ClearBackground(BLACK);
|
||||
for (int i = 0; i < SHADER_COUNT; i++)
|
||||
{
|
||||
RenderPostFX(&g->postFX[i], &g->target);
|
||||
}
|
||||
DrawText(TextFormat("%d", g->player.inventar.seedCount), 10, 10, 50, WHITE);
|
||||
|
||||
if (appState->flagFPS)
|
||||
{
|
||||
DrawFPS(10, 10);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
void CleanupGame(GameState* g){
|
||||
for (int i = 0; i < SHADER_COUNT; i++){ UnloadPostFX(&g->postFX[i]); }
|
||||
for (int i = 0; i < TEX_COUNT; i++){ if (g->textures[i].id > 0) { UnloadTexture(g->textures[i]); } }
|
||||
for (int i = 0; i < SOUNDTRACK_COUNT; i++){ UnloadMusicStream(g->soundtracks[i].music); }
|
||||
void CleanupGame(GameState *g)
|
||||
{
|
||||
for (int i = 0; i < SHADER_COUNT; i++)
|
||||
{
|
||||
UnloadPostFX(&g->postFX[i]);
|
||||
}
|
||||
for (int i = 0; i < TEX_COUNT; i++)
|
||||
{
|
||||
if (g->textures[i].id > 0)
|
||||
{
|
||||
UnloadTexture(g->textures[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < SOUNDTRACK_COUNT; i++)
|
||||
{
|
||||
UnloadMusicStream(g->soundtracks[i].music);
|
||||
}
|
||||
UnloadRenderTexture(g->target);
|
||||
free(g->flowers.data);
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
#ifndef GAMEASSETS_H
|
||||
#define GAMEASSETS_H
|
||||
#include "../engine/asset.h"
|
||||
#include <asset.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
PLAYER,
|
||||
PLAYER_ACTIONS,
|
||||
TOOLS,
|
||||
@@ -24,31 +25,29 @@ const TextureAsset texAssets[TEX_COUNT] = {
|
||||
{"assets/character_bee.png", 16.0f, 16.0f, 0.0f},
|
||||
{"assets/grass.png", 16.0f, 16.0f, 0.0f},
|
||||
{"assets/hive.png", 32.0f, 32.0f, 0.0f},
|
||||
{"assets/SproutLandsUI/Spritesheets/Mouse sprites/TriangleMouseicon1.png", 16.0f, 16.0f, 0.0f }
|
||||
};
|
||||
{"assets/SproutLandsUI/Spritesheets/Mouse sprites/TriangleMouseicon1.png", 16.0f, 16.0f, 0.0f}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
POST_FX,
|
||||
SHADER_COUNT
|
||||
} ShaderID;
|
||||
|
||||
|
||||
const ShaderAsset shaderAssets[SHADER_COUNT] = {
|
||||
{"shaders/postfx.fs"}
|
||||
};
|
||||
{"shaders/postfx.fs"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
BEE_AMBIENT,
|
||||
SOUNDTRACK_COUNT
|
||||
} SoundtrackID;
|
||||
|
||||
const SoundtrackAsset soundtrackAssets[SOUNDTRACK_COUNT] = {
|
||||
{"assets/beez.mp3"}
|
||||
};
|
||||
{"assets/beez.mp3"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
#ifndef HIVE_H
|
||||
#define HIVE_H
|
||||
#include "../engine/object.h"
|
||||
#include <object.h>
|
||||
|
||||
Object CreateHive(Texture2D texture, float frameWidth){
|
||||
return (Object) {
|
||||
Object CreateHive(Texture2D texture, float frameWidth)
|
||||
{
|
||||
return (Object){
|
||||
.sprite = {
|
||||
.texture = texture,
|
||||
.sourceRec = (Rectangle){0.0f, 0.0f, frameWidth, frameWidth},
|
||||
.destRec = (Rectangle){0.0f, 0.0f, frameWidth, frameWidth},
|
||||
.origin = (Vector2){frameWidth / 2, frameWidth / 2},
|
||||
.rotation = 0.0f,
|
||||
.color = WHITE
|
||||
},
|
||||
.position = (Vector2){0.0f, 0.0f}
|
||||
};
|
||||
.color = WHITE},
|
||||
.position = (Vector2){0.0f, 0.0f}};
|
||||
}
|
||||
|
||||
#endif // HIVE_H
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef LOGO_H
|
||||
#define LOGO_H
|
||||
|
||||
#include "../engine/applicationstate.h"
|
||||
#include "applicationstate.h"
|
||||
|
||||
typedef struct {
|
||||
int frameCounter;
|
||||
@@ -1,17 +1,19 @@
|
||||
#ifndef MENU_H
|
||||
#define MENU_H
|
||||
|
||||
#include "../engine/gui.h"
|
||||
#include "../engine/applicationstate.h"
|
||||
#include "../engine/asset.h"
|
||||
#include "../engine/gamegui.h"
|
||||
#include <gui.h>
|
||||
#include <asset.h>
|
||||
#include <gamegui.h>
|
||||
#include <input.h>
|
||||
#include <soundtrack.h>
|
||||
|
||||
#include "applicationstate.h"
|
||||
#include "menuassets.h"
|
||||
#include "colors.h"
|
||||
#include "../engine/input.h"
|
||||
#include "background.h"
|
||||
#include "../engine/soundtrack.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
Assets assets;
|
||||
Mouse mouse;
|
||||
Texture2D textures[MENU_TEX_COUNT];
|
||||
@@ -26,23 +28,26 @@ typedef struct {
|
||||
Background foreground;
|
||||
} MenuState;
|
||||
|
||||
void InitMenu(MenuState *m){
|
||||
void InitMenu(MenuState *m)
|
||||
{
|
||||
|
||||
m->assets = (Assets){
|
||||
.textureAssets = menuTextureAssets,
|
||||
.soundAssets = menuSoundAssets,
|
||||
.soundtrackAssets = menuSoundtrackAssets
|
||||
};
|
||||
.soundtrackAssets = menuSoundtrackAssets};
|
||||
|
||||
for (int i = 0; i < MENU_TEX_COUNT; i++){
|
||||
for (int i = 0; i < MENU_TEX_COUNT; i++)
|
||||
{
|
||||
m->textures[i] = LoadTexture(m->assets.textureAssets[i].path);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MENU_SOUND_COUNT; i++){
|
||||
for (int i = 0; i < MENU_SOUND_COUNT; i++)
|
||||
{
|
||||
m->sounds[i] = LoadSound(m->assets.soundAssets[i].path);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MENU_SOUNDTRACK_COUNT; i++){
|
||||
for (int i = 0; i < MENU_SOUNDTRACK_COUNT; i++)
|
||||
{
|
||||
m->soundtracks[i] = LoadSoundtrack(m->assets.soundtrackAssets[i].path);
|
||||
}
|
||||
|
||||
@@ -57,55 +62,54 @@ void InitMenu(MenuState *m){
|
||||
int screenHeight = GetScreenHeight();
|
||||
Vector2 screenCenter = {screenWidth / 2, screenHeight / 2};
|
||||
|
||||
|
||||
|
||||
int boardWidth = screenWidth / m->menuScale * 2.5f;
|
||||
float boardScaleFactor = (float)boardWidth / m->assets.textureAssets[MENU_BOARD_TEX].frameWidth;
|
||||
int boardHeight = (int)(m->assets.textureAssets[MENU_BOARD_TEX].frameHeight * boardScaleFactor);
|
||||
|
||||
Vector2 boardSource = {128.0f,0.0f};
|
||||
|
||||
Vector2 boardSource = {128.0f, 0.0f};
|
||||
Rectangle boardDestRec = {
|
||||
.x = screenCenter.x - (boardWidth / 2),
|
||||
.y = screenCenter.y - (boardHeight / 2),
|
||||
.width = boardWidth,
|
||||
.height = boardHeight
|
||||
};
|
||||
.height = boardHeight};
|
||||
|
||||
m->board = CreateImageElement(&m->textures[MENU_BOARD_TEX], &m->assets.textureAssets[MENU_BOARD_TEX], &boardSource, &boardDestRec);
|
||||
|
||||
|
||||
int buttonWidth = screenWidth / m->menuScale;
|
||||
float buttonScaleFactor = (float)buttonWidth / m->assets.textureAssets[MENU_BIG_BUTTONS_TEX].frameWidth;
|
||||
int buttonHeight = (int)(m->assets.textureAssets[MENU_BIG_BUTTONS_TEX].frameHeight * buttonScaleFactor);
|
||||
int buttonSpacing = buttonHeight;
|
||||
|
||||
Vector2 playButtonNotPressed = { 0.0f, 96.0f};
|
||||
Vector2 quitButtonNotPressed = { 0.0f, 0.0f};
|
||||
Vector2 playButtonHover = { 96.0f, 96.0f};
|
||||
Vector2 quitButtonHover = { 96.0f, 0.0f};
|
||||
Vector2 playButtonPressed = { 192.0f, 96.0f};
|
||||
Vector2 quitButtonPressed = { 192.0f, 0.0f};
|
||||
Vector2 playButtonNotPressed = {0.0f, 96.0f};
|
||||
Vector2 quitButtonNotPressed = {0.0f, 0.0f};
|
||||
Vector2 playButtonHover = {96.0f, 96.0f};
|
||||
Vector2 quitButtonHover = {96.0f, 0.0f};
|
||||
Vector2 playButtonPressed = {192.0f, 96.0f};
|
||||
Vector2 quitButtonPressed = {192.0f, 0.0f};
|
||||
|
||||
Rectangle playButtonDestRec = {
|
||||
.x = screenCenter.x - (buttonWidth / 2),
|
||||
.y = screenCenter.y - (buttonHeight / 2),
|
||||
.width = buttonWidth,
|
||||
.height = buttonHeight
|
||||
};
|
||||
.height = buttonHeight};
|
||||
|
||||
Rectangle quitButtonDestRec = {
|
||||
.x = screenCenter.x - (buttonWidth / 2),
|
||||
.y = screenCenter.y - (buttonHeight / 2) + buttonSpacing,
|
||||
.width = buttonWidth,
|
||||
.height = buttonHeight
|
||||
};
|
||||
.height = buttonHeight};
|
||||
|
||||
m->playButton = CreateImageButton(NOT_CLICKED, &m->textures[MENU_BIG_BUTTONS_TEX], &m->assets.textureAssets[MENU_BIG_BUTTONS_TEX], &playButtonNotPressed, &playButtonPressed, &playButtonHover, &playButtonDestRec);
|
||||
m->quitButton = CreateImageButton(NOT_CLICKED, &m->textures[MENU_BIG_BUTTONS_TEX], &m->assets.textureAssets[MENU_BIG_BUTTONS_TEX], &quitButtonNotPressed, &quitButtonPressed, &quitButtonHover, &quitButtonDestRec);
|
||||
}
|
||||
|
||||
void UpdateMenu(MenuState *m, State *state){
|
||||
void UpdateMenu(MenuState *m, State *state)
|
||||
{
|
||||
|
||||
for (int i = 0; i < MENU_SOUNDTRACK_COUNT; i++){ UpdateSoundtrack(&m->soundtracks[i]); }
|
||||
for (int i = 0; i < MENU_SOUNDTRACK_COUNT; i++)
|
||||
{
|
||||
UpdateSoundtrack(&m->soundtracks[i]);
|
||||
}
|
||||
|
||||
UpdateBackground(&m->background);
|
||||
UpdateBackground(&m->midground);
|
||||
@@ -113,48 +117,63 @@ void UpdateMenu(MenuState *m, State *state){
|
||||
|
||||
UpdateMouseScreen(&m->mouse);
|
||||
|
||||
if (isImageButtonClicked(&m->playButton, m->sounds[HOVER_SOUND], m->sounds[CLICK_SOUND])){
|
||||
if (isImageButtonClicked(&m->playButton, m->sounds[HOVER_SOUND], m->sounds[CLICK_SOUND]))
|
||||
{
|
||||
state->gameStarted = true;
|
||||
state->currentScreen = GAMEPLAY;
|
||||
}
|
||||
|
||||
if (isImageButtonClicked(&m->quitButton, m->sounds[HOVER_SOUND], m->sounds[CLICK_SOUND]) || (WindowShouldClose() && !IsKeyPressed(KEY_ESCAPE))) {
|
||||
if (isImageButtonClicked(&m->quitButton, m->sounds[HOVER_SOUND], m->sounds[CLICK_SOUND]) || (WindowShouldClose() && !IsKeyPressed(KEY_ESCAPE)))
|
||||
{
|
||||
state->running = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RenderMenu(MenuState *m, State *appState,Font *font, const char* name){
|
||||
void RenderMenu(MenuState *m, State *appState, Font *font, const char *title)
|
||||
{
|
||||
BeginDrawing();
|
||||
ClearBackground(WHITE);
|
||||
RenderBackground(&m->background);
|
||||
RenderBackground(&m->midground);
|
||||
RenderBackground(&m->foreground);
|
||||
renderImageElement(&m->board);
|
||||
renderImageButton(&m->playButton);
|
||||
renderImageButton(&m->quitButton);
|
||||
int textWidth = MeasureText(name, font->baseSize);
|
||||
DrawTextEx(*font, name, (Vector2){ GetScreenWidth() / 2 - textWidth / 2, textWidth / 4}, (float)font->baseSize, 2, WHITE);
|
||||
DrawTexturePro(
|
||||
m->mouse.cursorTexture,
|
||||
(Rectangle){ 0, 0, m->mouse.cursorTexture.width, m->mouse.cursorTexture.height},
|
||||
(Rectangle){m->mouse.screenPosition.x, m->mouse.screenPosition.y, m->mouse.cursorTexture.width, m->mouse.cursorTexture.height},
|
||||
(Vector2){0.0f, 0.0f},
|
||||
0.0f,
|
||||
WHITE
|
||||
);
|
||||
ClearBackground(WHITE);
|
||||
RenderBackground(&m->background);
|
||||
RenderBackground(&m->midground);
|
||||
RenderBackground(&m->foreground);
|
||||
renderImageElement(&m->board);
|
||||
renderImageButton(&m->playButton);
|
||||
renderImageButton(&m->quitButton);
|
||||
int textWidth = MeasureText(title, font->baseSize);
|
||||
DrawTextEx(*font, title, (Vector2){GetScreenWidth() / 2 - textWidth / 2, textWidth / 4}, (float)font->baseSize, 2, WHITE);
|
||||
DrawTexturePro(
|
||||
m->mouse.cursorTexture,
|
||||
(Rectangle){0, 0, m->mouse.cursorTexture.width, m->mouse.cursorTexture.height},
|
||||
(Rectangle){m->mouse.screenPosition.x, m->mouse.screenPosition.y, m->mouse.cursorTexture.width, m->mouse.cursorTexture.height},
|
||||
(Vector2){0.0f, 0.0f},
|
||||
0.0f,
|
||||
WHITE);
|
||||
|
||||
if (appState->flagFPS)
|
||||
{
|
||||
DrawFPS(10, 10);
|
||||
}
|
||||
|
||||
if (appState->flagFPS){
|
||||
DrawFPS(10, 10);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
void CleanupMenu(MenuState *m){
|
||||
for (int i = 0; i < MENU_SOUND_COUNT; i++){ UnloadSound(m->sounds[i]); }
|
||||
for (int i = 0; i < MENU_TEX_COUNT; i++){ if (m->textures[i].id > 0) { UnloadTexture(m->textures[i]); } }
|
||||
for (int i = 0; i < MENU_SOUNDTRACK_COUNT; i++){ UnloadMusicStream(m->soundtracks[i].music); }
|
||||
void CleanupMenu(MenuState *m)
|
||||
{
|
||||
for (int i = 0; i < MENU_SOUND_COUNT; i++)
|
||||
{
|
||||
UnloadSound(m->sounds[i]);
|
||||
}
|
||||
for (int i = 0; i < MENU_TEX_COUNT; i++)
|
||||
{
|
||||
if (m->textures[i].id > 0)
|
||||
{
|
||||
UnloadTexture(m->textures[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < MENU_SOUNDTRACK_COUNT; i++)
|
||||
{
|
||||
UnloadMusicStream(m->soundtracks[i].music);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MENU_H
|
||||
@@ -1,8 +1,9 @@
|
||||
#ifndef MENUASSETS_H
|
||||
#define MENUASSETS_H
|
||||
#include "../engine/asset.h"
|
||||
#include <asset.h>
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
MENU_CURSOR_TEX,
|
||||
MENU_BIG_BUTTONS_TEX,
|
||||
MENU_BOARD_TEX,
|
||||
@@ -13,24 +14,24 @@ typedef enum {
|
||||
} MenuTextureID;
|
||||
|
||||
const TextureAsset menuTextureAssets[MENU_TEX_COUNT] = {
|
||||
{"assets/SproutLandsUI/Spritesheets/Mouse sprites/TriangleMouseicon1.png", 16.0f, 16.0f, 0.0f },
|
||||
{"assets/SproutLandsUI/Spritesheets/Mouse sprites/TriangleMouseicon1.png", 16.0f, 16.0f, 0.0f},
|
||||
{"assets/SproutLandsUI/Spritesheets/UIBigPlayButtonHover.png", 96.0f, 32.0f, 0.0f},
|
||||
{"assets/SproutLandsUI/Spritesheets/Settingmenu.png", 128.0f, 144.0f, 0.0f},
|
||||
{"assets/Clouds/Clouds1/1.png", 576.0f, 324.0f, 0.0f},
|
||||
{"assets/Clouds/Clouds1/2.png", 576.0f, 324.0f, 0.0f},
|
||||
{"assets/Clouds/Clouds1/4.png", 576.0f, 324.0f, 0.0f}
|
||||
};
|
||||
{"assets/Clouds/Clouds1/4.png", 576.0f, 324.0f, 0.0f}};
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
MENU_MUSIC,
|
||||
MENU_SOUNDTRACK_COUNT
|
||||
} MenuSoundtrackID;
|
||||
|
||||
const SoundtrackAsset menuSoundtrackAssets[MENU_SOUNDTRACK_COUNT] = {
|
||||
{"assets/merrygoround.wav"}
|
||||
};
|
||||
{"assets/merrygoround.wav"}};
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
HOVER_SOUND,
|
||||
CLICK_SOUND,
|
||||
MENU_SOUND_COUNT
|
||||
@@ -38,7 +39,6 @@ typedef enum {
|
||||
|
||||
const SoundAsset menuSoundAssets[MENU_SOUND_COUNT] = {
|
||||
{"assets/audio/WAV/Minimalist1.wav"},
|
||||
{"assets/audio/WAV/Abstract1.wav"}
|
||||
};
|
||||
{"assets/audio/WAV/Abstract1.wav"}};
|
||||
|
||||
#endif // MENUASSETS_H
|
||||
@@ -1,25 +1,30 @@
|
||||
#ifndef PLAYER_H
|
||||
#define PLAYER_H
|
||||
#include "../engine/sprite.h"
|
||||
#include "../engine/animation.h"
|
||||
#include "../engine/physics.h"
|
||||
#include "../engine/input.h"
|
||||
|
||||
#include <sprite.h>
|
||||
#include <animation.h>
|
||||
#include <physics.h>
|
||||
#include <input.h>
|
||||
|
||||
#include "inventar.h"
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
IDLE,
|
||||
WALKING,
|
||||
USING_TOOL
|
||||
} PlayerState;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NO_TOOL,
|
||||
HOE,
|
||||
AXT,
|
||||
CAN
|
||||
} SelectedTool;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
IDLE_DOWN,
|
||||
IDLE_UP,
|
||||
IDLE_LEFT,
|
||||
@@ -42,7 +47,8 @@ typedef enum {
|
||||
CAN_LEFT,
|
||||
} PlayerAnimationState;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
SelectedTool selectedTool;
|
||||
Sprite sprite;
|
||||
Animation animation;
|
||||
@@ -50,7 +56,8 @@ typedef struct {
|
||||
Inventar inventar;
|
||||
} Player;
|
||||
|
||||
Player CreatePlayer(PlayerAnimationState animState, SelectedTool selectedTool, Texture2D texture, float frameWidth, int maxFrame, int framesSpeed, Vector2 startPosition, float rotation, float speed){
|
||||
Player CreatePlayer(PlayerAnimationState animState, SelectedTool selectedTool, Texture2D texture, float frameWidth, int maxFrame, int framesSpeed, Vector2 startPosition, float rotation, float speed)
|
||||
{
|
||||
return (Player){
|
||||
.selectedTool = selectedTool,
|
||||
.sprite = {
|
||||
@@ -60,71 +67,80 @@ Player CreatePlayer(PlayerAnimationState animState, SelectedTool selectedTool, T
|
||||
.destRec = {0.0f, 0.0f, frameWidth, frameWidth},
|
||||
.origin = {frameWidth / 2, frameWidth / 2},
|
||||
.rotation = rotation,
|
||||
.color = WHITE
|
||||
},
|
||||
.animation = {
|
||||
.state = animState,
|
||||
.currentFrame = 0,
|
||||
.maxFrame = maxFrame,
|
||||
.framesCounter = 0,
|
||||
.framesSpeed = framesSpeed,
|
||||
.animTimer = 0.0f
|
||||
},
|
||||
.physics = {
|
||||
.position = startPosition,
|
||||
.direction = (Vector2){0.0f,0.0f},
|
||||
.speed = speed
|
||||
},
|
||||
.inventar = {
|
||||
.seedCount = 6
|
||||
}
|
||||
};
|
||||
.color = WHITE},
|
||||
.animation = {.state = animState, .currentFrame = 0, .maxFrame = maxFrame, .framesCounter = 0, .framesSpeed = framesSpeed, .animTimer = 0.0f},
|
||||
.physics = {.position = startPosition, .direction = (Vector2){0.0f, 0.0f}, .speed = speed},
|
||||
.inventar = {.seedCount = 6}};
|
||||
}
|
||||
|
||||
void UpdatePlayerAnimationState(int *state, SelectedTool *selectedTool, Vector2 *dir) {
|
||||
void UpdatePlayerAnimationState(int *state, SelectedTool *selectedTool, Vector2 *dir)
|
||||
{
|
||||
|
||||
if (IsKeyPressed(KEY_ZERO)){
|
||||
if (IsKeyPressed(KEY_ZERO))
|
||||
{
|
||||
*selectedTool = NO_TOOL;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KEY_ONE)){
|
||||
if (IsKeyPressed(KEY_ONE))
|
||||
{
|
||||
*selectedTool = HOE;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KEY_TWO)){
|
||||
if (IsKeyPressed(KEY_TWO))
|
||||
{
|
||||
*selectedTool = AXT;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KEY_THREE)){
|
||||
if (IsKeyPressed(KEY_THREE))
|
||||
{
|
||||
*selectedTool = CAN;
|
||||
}
|
||||
|
||||
if (dir->x == 0 && dir->y == 0) {
|
||||
switch (*state) {
|
||||
case WALKING_DOWN: *state = IDLE_DOWN; break;
|
||||
case WALKING_UP: *state = IDLE_UP; break;
|
||||
case WALKING_LEFT: *state = IDLE_LEFT; break;
|
||||
case WALKING_RIGHT: *state = IDLE_RIGHT; break;
|
||||
default: break;
|
||||
if (dir->x == 0 && dir->y == 0)
|
||||
{
|
||||
switch (*state)
|
||||
{
|
||||
case WALKING_DOWN:
|
||||
*state = IDLE_DOWN;
|
||||
break;
|
||||
case WALKING_UP:
|
||||
*state = IDLE_UP;
|
||||
break;
|
||||
case WALKING_LEFT:
|
||||
*state = IDLE_LEFT;
|
||||
break;
|
||||
case WALKING_RIGHT:
|
||||
*state = IDLE_RIGHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (dir->y == 1) *state = WALKING_DOWN;
|
||||
else if (dir->y == -1) *state = WALKING_UP;
|
||||
else if (dir->x == -1) *state = WALKING_LEFT;
|
||||
else if (dir->x == 1) *state = WALKING_RIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dir->y == 1)
|
||||
*state = WALKING_DOWN;
|
||||
else if (dir->y == -1)
|
||||
*state = WALKING_UP;
|
||||
else if (dir->x == -1)
|
||||
*state = WALKING_LEFT;
|
||||
else if (dir->x == 1)
|
||||
*state = WALKING_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePlayer(Player* player){
|
||||
if (IsKeyPressed(KEY_SPACE) && player->inventar.seedCount >0){
|
||||
void UpdatePlayer(Player *player)
|
||||
{
|
||||
if (IsKeyPressed(KEY_SPACE) && player->inventar.seedCount > 0)
|
||||
{
|
||||
player->inventar.seedCount--;
|
||||
}
|
||||
}
|
||||
Vector2 dir = GetDirectionVector();
|
||||
UpdatePlayerAnimationState(&player->animation.state, &player->selectedTool, &dir);
|
||||
UpdatePhysics(&player->physics, dir);
|
||||
UpdateSpriteDestRec(&player->sprite, &player->physics.position);
|
||||
UpdateAnimation(&player->animation, GetFrameTime());
|
||||
UpdateSpriteSourceRec(&player->sprite, &(Vector2){player->sprite.frameSize.x * player->animation.currentFrame, player->sprite.frameSize.y * player->animation.state});
|
||||
UpdateSpriteSourceRec(&player->sprite, &(Vector2){player->sprite.frameSize.x * player->animation.currentFrame, player->sprite.frameSize.y * player->animation.state});
|
||||
}
|
||||
|
||||
#endif // PLAYER_H
|
||||
-2966
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,8 @@
|
||||
|
||||
typedef enum Screen {
|
||||
LOGO = 0,
|
||||
MENU,
|
||||
GAMEPLAY
|
||||
MENU = 1,
|
||||
GAMEPLAY = 2
|
||||
} Screen;
|
||||
|
||||
#endif // SCREEN_H
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef APP_H
|
||||
#define APP_H
|
||||
|
||||
#include "engine/applicationstate.h"
|
||||
#include "engine/display.h"
|
||||
#include "engine/screen.h"
|
||||
#include "game/logo.h"
|
||||
#include "game/menu.h"
|
||||
#include "game/game.h"
|
||||
|
||||
typedef struct {
|
||||
State state;
|
||||
Display display;
|
||||
Font font;
|
||||
LogoState logo;
|
||||
GameState game;
|
||||
MenuState menu;
|
||||
} Application;
|
||||
|
||||
void InitApp(Application* app){
|
||||
app->state.currentScreen = LOGO;
|
||||
app->state.running = true;
|
||||
app->state.gameStarted = false;
|
||||
app->state.flagFPS = true;
|
||||
app->display = (Display){
|
||||
.name = "The Last Hive",
|
||||
.width = 1280,
|
||||
.height = 720
|
||||
};
|
||||
app->font = LoadFont("assets/SproutLandsUI/fonts/pixelFont-7-8x14-sproutLands.fnt");
|
||||
}
|
||||
|
||||
#endif //APP_H
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef FLOWERS_H
|
||||
#define FLOWERS_H
|
||||
|
||||
#include "../engine/object.h"
|
||||
|
||||
ObjectArray CreateFlowers(Texture2D texture,float frameWidth, float rotation, float fieldSize) {
|
||||
ObjectArray flowers = CreateObjectArray(&(Object){
|
||||
.sprite = {
|
||||
.texture = texture,
|
||||
.sourceRec = {0.0f, 0.0f, frameWidth, frameWidth},
|
||||
.destRec = {0.0f, 0.0f, frameWidth, frameWidth},
|
||||
.origin = {frameWidth / 2, frameWidth / 2},
|
||||
.rotation = rotation,
|
||||
.color = WHITE
|
||||
},
|
||||
.position = {0.0f, 0.0f}
|
||||
}, 10);
|
||||
|
||||
if (!flowers.data) {
|
||||
printf("Memory allocation failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SetRandomPositionForObjectArray(&flowers, (Rectangle){-fieldSize, -fieldSize, fieldSize * 2, fieldSize * 2});
|
||||
|
||||
return flowers;
|
||||
}
|
||||
|
||||
#endif // FLOWERS_H
|
||||
+5
-39
@@ -1,49 +1,15 @@
|
||||
#include <raylib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "../include/raymath.h"
|
||||
#include "app.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Application app;
|
||||
InitApp(&app);
|
||||
|
||||
InitWindow(app.display.width, app.display.height, app.display.name);
|
||||
ConfigApp(&app);
|
||||
InitWindow(app.display.width, app.display.height, app.display.title);
|
||||
InitAudioDevice();
|
||||
|
||||
SetTextureFilter(app.font.texture, TEXTURE_FILTER_POINT);
|
||||
SetTraceLogLevel(LOG_NONE);
|
||||
|
||||
InitLogo(&app.logo);
|
||||
InitMenu(&app.menu);
|
||||
InitGame(&app.game,&app.display);
|
||||
|
||||
while (app.state.running)
|
||||
{
|
||||
switch (app.state.currentScreen)
|
||||
{
|
||||
case LOGO:
|
||||
{
|
||||
UpdateLogo(&app.logo, &app.state);
|
||||
RenderLogo(&app.logo, &app.state);
|
||||
}break;
|
||||
case MENU:
|
||||
{
|
||||
UpdateMenu(&app.menu, &app.state);
|
||||
RenderMenu(&app.menu, &app.state, &app.font, app.display.name);
|
||||
}break;
|
||||
case GAMEPLAY:
|
||||
{
|
||||
UpdateGame(&app.game, &app.state);
|
||||
RenderGame(&app.game, &app.state);
|
||||
}break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
CleanupMenu(&app.menu);
|
||||
CleanupGame(&app.game);
|
||||
UnloadFont(app.font);
|
||||
InitApp(&app);
|
||||
UpdateApp(&app);
|
||||
CleanupApp(&app);
|
||||
CloseWindow();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user