diff --git a/client/pages/getting-started/basics/constants.md b/client/pages/getting-started/basics/constants.md index 928206f..ebbde11 100644 --- a/client/pages/getting-started/basics/constants.md +++ b/client/pages/getting-started/basics/constants.md @@ -1,147 +1,192 @@ # Constants Usage in Dojo Engine ๐ŸŽฎ -## What are Constants? ๐Ÿ“ +Constants are like the **configuration file** of your game - they define the fixed values that control how your game behaves. Think of them as the "rules" that determine damage amounts, health points, cooldown times, and other gameplay mechanics in your Dojo game. -Constants are fixed values used in game code to configure essential parameters such as damage, health, time durations, and other gameplay aspects. In Dojo Engine, constants are defined in Cairo files like `constants.cairo`, enabling consistent game balance and easy configuration. +## Why Constants Matter in Game Development ๐Ÿค” -## Why Use Constants? ๐Ÿค” +Imagine you're balancing a fighting game. Without constants, you'd have random numbers scattered throughout your code like: -- **Maintainability:** Changing a constant updates all parts of the code that use it. -- **Game Balance:** Allows tweaking gameplay parameters without modifying logic. -- **Clarity:** Descriptive names are easier to understand than "magic numbers." +```cairo +// โŒ Bad: Magic numbers everywhere +let damage = attack_power * 150; // What does 150 mean? +let health = base_health + level * 20; // Why 20? +``` -## Real Example: constants.cairo ๐Ÿ’ป +With constants, your code becomes self-documenting and easier to balance: ```cairo -// Game Balance Constants -// These constants control core gameplay mechanics and balance - -// Time-based constants for game progression -pub const SECONDS_PER_DAY: u64 = 86400; // Used for daily rewards and time-based events -pub const GAME_TICK_RATE: u64 = 60; // How often the game state updates - -// Combat system constants -pub const BASE_LEVEL_BONUS: u8 = 10; // Base bonus per level for character progression -pub const SUPER_EFFECTIVE: u8 = 150; // 150% damage for type advantages -pub const NORMAL_EFFECTIVENESS: u8 = 100; // 100% damage for neutral matchups -pub const NOT_VERY_EFFECTIVE: u8 = 50; // 50% damage for type disadvantages - -// Attack multipliers for strategic depth -pub const FAVORED_ATTACK_MULTIPLIER: u8 = 120; // 120% damage for favored attacks -pub const NORMAL_ATTACK_MULTIPLIER: u8 = 100; // 100% damage for normal attacks - -// Energy system constants -pub const MAX_ENERGY: u8 = 100; // Maximum energy a player can have -pub const ENERGY_REGEN_RATE: u8 = 5; // Energy points regenerated per tick -pub const ENERGY_COST_PER_ACTION: u8 = 10; // Cost of basic actions - -// Health system constants -pub const BASE_HEALTH: u8 = 100; // Starting health for new players -pub const HEALTH_REGEN_RATE: u8 = 2; // Health points regenerated per tick -pub const MAX_HEALTH_BONUS_PER_LEVEL: u8 = 20; // Health increase per level - -// Utility constants -pub fn ZERO_ADDRESS() -> ContractAddress { - contract_address_const::<0x0>() // Used for null checks and initialization -} +// โœ… Good: Clear, meaningful constants +let damage = attack_power * SUPER_EFFECTIVE; +let health = base_health + level * HEALTH_BONUS_PER_LEVEL; ``` -## Organizing Constants ๐Ÿ“Š +**Key Benefits:** +- **Easy Game Balancing**: Change one number to affect the entire game +- **Clear Code**: Anyone can understand what `MAX_ENERGY` means +- **Consistent Values**: No more accidentally using 100 in one place and 99 in another +- **Team Collaboration**: Designers can suggest balance changes without touching code logic -- Group constants by categories: combat, health, energy, time, etc. -- Use clear comments to explain each constant's purpose. -- Use uppercase snake_case naming for constants (e.g., MAX_SEARCH). +## Real-World Example: Building a Combat System ๐Ÿ’ป -## Best Practices โญ +Here's how you might structure constants for a turn-based RPG in Dojo: -- Avoid using "magic numbers" directly in code; always reference constants. -- Keep constants immutable. -- Use clear and descriptive names to avoid confusion. -- Document each constant with a brief comment. +```cairo +// constants.cairo +// Combat Balance - The heart of your game's feel -## How Constants Help in Dojo ๐Ÿš€ +// Type Effectiveness System (Rock-Paper-Scissors mechanics) +pub const SUPER_EFFECTIVE: u8 = 150; // 1.5x damage - strong advantage +pub const NORMAL_EFFECTIVENESS: u8 = 100; // 1.0x damage - neutral matchup +pub const NOT_VERY_EFFECTIVE: u8 = 50; // 0.5x damage - poor matchup -### Game Balance Tuning -Constants make it easy to adjust game balance without changing core logic. For example: -- Adjusting `ENERGY_REGEN_RATE` and `ENERGY_COST_PER_ACTION` to control gameplay pace -- Modifying `MAX_HEALTH_BONUS_PER_LEVEL` to scale difficulty with player progression -- Tweaking `SUPER_EFFECTIVE` and `NOT_VERY_EFFECTIVE` to balance combat mechanics +// Character Progression +pub const BASE_LEVEL_BONUS: u8 = 10; // Stats gained per level +pub const MAX_HEALTH_BONUS_PER_LEVEL: u8 = 20; // HP increase per level -### Code Organization -Constants help organize game parameters into logical categories: -- Combat system constants -- Energy management constants -- Health system constants -- Time-based constants -- Utility constants +// Energy Management (Prevents spam, adds strategy) +pub const MAX_ENERGY: u8 = 100; // Energy cap +pub const ENERGY_REGEN_RATE: u8 = 5; // Energy gained per turn +pub const ENERGY_COST_PER_ACTION: u8 = 10; // Energy spent per basic attack -### Maintainability -Using constants improves code maintainability by: -- Centralizing configuration values -- Making balance changes easier to track -- Reducing the risk of inconsistent values -- Simplifying testing and debugging +// Time-Based Mechanics +pub const SECONDS_PER_DAY: u64 = 86400; // For daily rewards/events +pub const GAME_TICK_RATE: u64 = 60; // How often game updates -## How to Use Constants in Your Cairo Code ๐Ÿ‘จโ€๐Ÿ’ป +// Special Attack Modifiers +pub const FAVORED_ATTACK_MULTIPLIER: u8 = 120; // 1.2x for specialized attacks +pub const NORMAL_ATTACK_MULTIPLIER: u8 = 100; // 1.0x for basic attacks -Once you define constants in `constants.cairo`, you can import and use them throughout your Dojo game modules for clear and consistent logic. +// Utility Constants +pub fn ZERO_ADDRESS() -> ContractAddress { + contract_address_const::<0x0>() // Null address for empty/invalid states +} +``` -### Importing Constants +## How to Organize Your Constants ๐Ÿ“Š +**Group by Game System:** ```cairo -// Import constants module -use constants::*; +// โšก Energy System +pub const MAX_ENERGY: u8 = 100; +pub const ENERGY_REGEN_RATE: u8 = 5; + +// โค๏ธ Health System +pub const BASE_HEALTH: u8 = 100; +pub const HEALTH_REGEN_RATE: u8 = 2; + +// โš”๏ธ Combat System +pub const SUPER_EFFECTIVE: u8 = 150; +pub const NORMAL_EFFECTIVENESS: u8 = 100; ``` -### Example 1: Using Constants in Functions +**Naming Convention:** Use `SCREAMING_SNAKE_CASE` for constants - it's the Cairo standard and makes them easy to spot in your code. + +## Putting Constants to Work ๐Ÿ‘จโ€๐Ÿ’ป + +Once you've defined your constants, here's how to use them effectively in your game logic: +### Import Your Constants ```cairo -// Function to calculate attack effectiveness based on type matchups -fn calculate_effectiveness(attacker_type: BeastType, defender_type: BeastType) -> u8 { +// At the top of your Cairo files +use dojo_examples::constants::*; +``` + +### Example 1: Combat Effectiveness Calculator +```cairo +// Calculate how effective an attack is based on elemental types +fn calculate_damage_multiplier(attacker_type: ElementType, defender_type: ElementType) -> u8 { match (attacker_type, defender_type) { - (BeastType::Light, BeastType::Shadow) | - (BeastType::Magic, BeastType::Light) | - (BeastType::Shadow, BeastType::Magic) => SUPER_EFFECTIVE, - (BeastType::Light, BeastType::Magic) | - (BeastType::Magic, BeastType::Shadow) | - (BeastType::Shadow, BeastType::Light) => NOT_VERY_EFFECTIVE, + // Fire beats Ice, Water beats Fire, Ice beats Water + (ElementType::Fire, ElementType::Ice) | + (ElementType::Water, ElementType::Fire) | + (ElementType::Ice, ElementType::Water) => SUPER_EFFECTIVE, + + // Reverse matchups are weak + (ElementType::Ice, ElementType::Fire) | + (ElementType::Fire, ElementType::Water) | + (ElementType::Water, ElementType::Ice) => NOT_VERY_EFFECTIVE, + + // Same types are neutral _ => NORMAL_EFFECTIVENESS, } } ``` -### Example 2: Using Constants for Calculations +### Example 2: Level-Up Rewards +```cairo +// Calculate how much health a player gains when leveling up +fn calculate_level_up_bonus(current_level: u8) -> u8 { + current_level * BASE_LEVEL_BONUS + MAX_HEALTH_BONUS_PER_LEVEL +} +``` +### Example 3: Energy Management ```cairo -// Calculate daily bonus based on player level -fn calculate_daily_bonus(level: u8) -> u8 { - level * BASE_LEVEL_BONUS -} +// Check if player has enough energy for an action +fn can_perform_action(current_energy: u8, action_cost: u8) -> bool { + current_energy >= action_cost +} + +// Regenerate energy each turn (with cap) +fn regenerate_energy(current_energy: u8) -> u8 { + let new_energy = current_energy + ENERGY_REGEN_RATE; + if new_energy > MAX_ENERGY { + MAX_ENERGY + } else { + new_energy + } +} ``` -### Example 3: Using Constants in Conditionals +## Game Designer's Perspective ๐ŸŽฏ + +Constants make your game **designer-friendly**. Want to make combat faster? Increase `ENERGY_REGEN_RATE`. Want to reduce grinding? Boost `BASE_LEVEL_BONUS`. + +**Before Constants:** +"The game feels too slow, but I'd need to find every energy-related calculation in the code..." + +**With Constants:** +"Change `ENERGY_REGEN_RATE` from 5 to 8 and test it!" + +## Best Practices for Dojo Games โญ + +1. **Document Your Intent**: Add comments explaining why you chose specific values +2. **Group Related Constants**: Keep all combat constants together, all time constants together +3. **Use Meaningful Names**: `CRITICAL_HIT_CHANCE` is better than `CRIT_CHANCE` +4. **Start Conservative**: It's easier to buff than nerf in live games +5. **Version Your Balance**: Keep track of constant changes for rollback purposes + +## Testing Your Constants ๐Ÿงช ```cairo -// Determine if an attack is favored based on beast type -fn is_favored_attack(beast_type: BeastType, skill_type: SkillType) -> bool { - match skill_type { - SkillType::Beam | SkillType::Slash | SkillType::Pierce | - SkillType::Wave => beast_type == BeastType::Light, - SkillType::Blast | SkillType::Freeze | SkillType::Burn | - SkillType::Punch => beast_type == BeastType::Magic, - SkillType::Smash | SkillType::Crush | SkillType::Shock | - SkillType::Kick => beast_type == BeastType::Shadow, - _ => false, +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_type_effectiveness() { + // Fire should be super effective against Ice + let multiplier = calculate_damage_multiplier(ElementType::Fire, ElementType::Ice); + assert(multiplier == SUPER_EFFECTIVE, 'Fire should beat Ice'); + } + + #[test] + fn test_energy_cap() { + // Energy should never exceed maximum + let capped_energy = regenerate_energy(MAX_ENERGY); + assert(capped_energy == MAX_ENERGY, 'Energy should be capped'); } } ``` -## Benefits โœจ +## Summary ๐Ÿ“š -- Centralized configuration for easy tuning -- Avoid hardcoding values throughout the codebase -- Improves readability and maintainability +Constants are the foundation of maintainable game development in Dojo. They transform scattered magic numbers into a centralized, editable configuration system that makes balancing your game a breeze. -## Summary ๐Ÿ“š +**Remember:** +- Constants = Game Balance Control Center +- Good naming = Self-documenting code +- Organized constants = Happy team +- Testable constants = Reliable game mechanics -Proper use of constants is essential for maintaining organized, scalable, and balanced code in Dojo Engine. Learn to define, organize, and use constants effectively to enhance your on-chain games. \ No newline at end of file +Start simple, stay organized, and let constants handle the heavy lifting of game balance while you focus on creating amazing gameplay experiences! ๐Ÿš€ \ No newline at end of file diff --git a/client/pages/getting-started/basics/helpers.md b/client/pages/getting-started/basics/helpers.md index 4d07b7f..10157de 100644 --- a/client/pages/getting-started/basics/helpers.md +++ b/client/pages/getting-started/basics/helpers.md @@ -1,152 +1,303 @@ -# Helpers Functions in Dojo Engine ๐ŸŽฎ - -## What are Helpers Functions ๐Ÿค - -Helper functions can be described as utility methods that could be useful or reusable; how does the word itself say "Helpers Functions" designed to assist other functions within a program. In Dojo Engine, helpers are defined in Cairo files like `pseudo_random.cairo`. - - -## Why Use Helper Functions? ๐Ÿ› ๏ธ - -- **Maintainability && performance:** They perform specific, often repetitive tasks, making the code cleaner, more readable and easier to maintain. - - -- **Encapsulation && readability:** Essentially, they encapsulate functionality that can be used in multiple places without duplicating code or Code Smell. - - -- **Provable logic reuse in Cairo::** In Dojo Engine, writing helper functions allows you to reuse deterministic logic (like random number generation, vector math, or bounds checking) across multiple systems or components, ensuring consistent and provable behavior across your game world. - - -## Real Example: `pseudo_random.cairo` helper function ๐Ÿ‘จ๐Ÿพโ€๐Ÿ’ป - -- **Arguments** - - * `min`: The minimum value (inclusive) of the random number range. - * `max`: The maximum value (inclusive) of the random number range. - * `unique_id`: A unique identifier used to generate entropy for randomness. - * `salt`: An additional value to modify the randomness, ensuring more variation. - - -Let's look at a real example of a helper function!!. - -### 1. Entropy Source - - ```cairo - let block_timestamp = get_block_timestamp(); - let block_number = get_block_number(); - ``` - -It pulls block data (timestamp & block number) from Starknet, which is deterministic and accessible on-chain โ€” a common approach to introducing pseudo-randomness in provable systems. - -### 2. Seed Generation - - ```cairo - let hash_state = PedersenTrait::new(0); - let hash_state = hash_state.update(hash_input); - let hash = hash_state.finalize(); - ``` - -Combines the entropy with the unique_id and salt values to customize randomness per entity or action. This makes the outcome feel unique and more secure against pattern repetition. - - -### 3. Hashing with Pedersen - - ```cairo +# Helper Functions in Dojo Engine ๐ŸŽฎ + +Helper functions are the **utility belt** of your game development toolkit. Think of them as specialized tools that solve common problems across your entire game - from generating random numbers to calculating complex formulas. Instead of writing the same logic over and over, you create one helper function and reuse it everywhere. + +## Why Helper Functions Are Game Changers ๐Ÿ› ๏ธ + +Imagine you're building an RPG where you need random numbers for: +- Loot drops when defeating enemies +- Critical hit chances in combat +- Spawning random encounters +- Determining quest rewards + +**Without helpers:** +```cairo +// โŒ Repeated random logic everywhere +// In combat system +let crit_chance = hash_something_complex(player_id, block_data, salt1); + +// In loot system +let drop_chance = hash_something_else(monster_id, block_data, salt2); + +// In quest system +let reward_amount = another_random_function(quest_id, block_data, salt3); +``` + +**With a helper function:** +```cairo +// โœ… One reusable helper +use helpers::pseudo_random::generate_random_u8; + +// Clean, consistent usage everywhere +let crit_chance = generate_random_u8(player_id, salt, 1, 100); +let drop_chance = generate_random_u8(monster_id, salt, 1, 100); +let reward_amount = generate_random_u8(quest_id, salt, 10, 50); +``` + +**Key Benefits:** +- **DRY Principle**: Don't Repeat Yourself - write once, use everywhere +- **Consistency**: Same logic produces predictable results across your game +- **Maintainability**: Fix a bug once, it's fixed everywhere +- **Testability**: Test complex logic in isolation +- **Readability**: Your game code becomes self-documenting + +## Real-World Example: Pseudo-Random Number Generation ๐ŸŽฒ + +Let's break down a production-ready random number helper that you'll use constantly in game development: + +```cairo +// helpers/pseudo_random.cairo +use starknet::{get_block_timestamp, get_block_number}; +use hash::{HashStateTrait, HashStateExTrait}; +use pedersen::PedersenTrait; + +/// Generates a pseudo-random number between min and max (inclusive) +/// Perfect for game mechanics like damage rolls, loot chances, etc. +pub fn generate_random_u8( + unique_id: u16, // Makes each call unique (player_id, monster_id, etc.) + salt: u16, // Adds extra randomness variation + min: u8, // Minimum value (inclusive) + max: u8 // Maximum value (inclusive) +) -> u8 { + // Step 1: Gather on-chain entropy + let block_timestamp = get_block_timestamp(); + let block_number = get_block_number(); + + // Step 2: Create unique seed for this specific call + let seed = unique_id.into() + salt.into() + block_timestamp + block_number; + + // Step 3: Hash the seed for cryptographic randomness let hash_state = PedersenTrait::new(0); - let hash_state = hash_state.update(hash_input); + let hash_state = hash_state.update(seed); let hash = hash_state.finalize(); - ``` - -Converts the combined seed into a hashed value. Pedersen hash is deterministic and efficient in Cairo, making it suitable for generating pseudo-random values. - - -### 4. Bounding the Random Value - - ```cairo - let range: u64 = max.into() - min.into() + 1_u64.into(); - let mod_value: u64 = (hash_u256 % range.into()).try_into().unwrap(); - let random_value: u8 = mod_value.try_into().unwrap().wrapping_add(min); - ``` - -Ensures the final output is within the user-defined [min, max] range, inclusive. - -## Test Function Example: - - ```cairo - // Tests the `generate_random_u8` function to ensure it returns a value within the specified range. - - // This test ensures that the random value generated is always between `min` and `max` inclusive. + + // Step 4: Convert to our desired range + let range: u64 = (max - min + 1).into(); + let random_in_range = (hash % range.into()).try_into().unwrap(); + + min + random_in_range +} +``` + +### How Each Step Works ๐Ÿ” + +**๐ŸŒ Step 1: On-Chain Entropy** +```cairo +let block_timestamp = get_block_timestamp(); +let block_number = get_block_number(); +``` +Uses Starknet block data as a source of randomness. This is deterministic (same block = same values) but unpredictable when the transaction is created. + +**๐ŸŽฏ Step 2: Unique Seed Creation** +```cairo +let seed = unique_id.into() + salt.into() + block_timestamp + block_number; +``` +Combines your inputs with block data to ensure different results for different entities/actions, even in the same block. + +**๐Ÿ”’ Step 3: Cryptographic Hashing** +```cairo +let hash_state = PedersenTrait::new(0); +let hash = hash_state.finalize(); +``` +Pedersen hash transforms our seed into a uniformly distributed random value - this is where the "magic" happens. + +**๐Ÿ“ Step 4: Range Conversion** +```cairo +let range: u64 = (max - min + 1).into(); +let random_in_range = (hash % range.into()).try_into().unwrap(); +``` +Mathematically ensures our result falls exactly within [min, max] bounds. + +## Practical Usage Examples ๐ŸŽฏ + +### Combat System +```cairo +// Calculate if attack is a critical hit (5% chance) +let crit_roll = generate_random_u8(attacker_id, 1, 1, 100); +let is_critical = crit_roll <= 5; + +// Random damage variance (ยฑ10%) +let base_damage = 50; +let variance = generate_random_u8(attacker_id, 2, 90, 110); +let final_damage = (base_damage * variance) / 100; +``` + +### Loot System +```cairo +// Determine loot rarity (Common: 70%, Rare: 25%, Epic: 5%) +let loot_roll = generate_random_u8(monster_id, 3, 1, 100); +let rarity = if loot_roll <= 70 { + LootRarity::Common +} else if loot_roll <= 95 { + LootRarity::Rare +} else { + LootRarity::Epic +}; +``` + +### Procedural Generation +```cairo +// Generate random dungeon room size +let room_width = generate_random_u8(room_id, 4, 5, 15); +let room_height = generate_random_u8(room_id, 5, 5, 15); +``` + +## Testing Your Helpers ๐Ÿงช + +Helper functions are perfect for unit testing because they're isolated and predictable: + +```cairo +#[cfg(test)] +mod tests { + use super::*; #[test] - #[available_gas(1000000)] - fn test_generate_random_u8() { - let min: u8 = 5; - let max: u8 = 10; - let unique_id: u16 = 12345; - let salt: u16 = 6789; - let result = generate_random_u8(unique_id, salt, min, max); - - // Assert the result is within the specified range - assert!(result >= min && result <= max, "Random number out of range"); + fn test_random_range_bounds() { + let min = 10; + let max = 20; + let result = generate_random_u8(12345, 6789, min, max); + + // Verify result is always in bounds + assert!(result >= min && result <= max, "Random value out of range"); } - ``` - -๐Ÿ” **Result**: -This test guarantees that your pseudo-random function behaves safely and deterministically, always producing values between min and max, even as inputs change. This is a great example of how pure helpers can be tested in isolation, without setting up an entire game system or world context. - -## Recommendations ๐Ÿ“š - -**Recommendations for Using Helpers in Dojo Engine** - -Helper functions are powerful tools when used wisely. Here are some best practices to ensure your helpers in Dojo Engine stay clean, reusable, and effective: - ---- - -### โœ… 1. **Keep Them Pure and Stateless** - -Helpers should ideally avoid modifying global state or relying on side effects. This makes them easier to test, reason about, and reuse. - -> Example: `generate_random_u8` is deterministic and depends only on its inputs and block data. - ---- - -### ๐Ÿงฉ 2. **Use Descriptive Names** - -Name your helpers clearly to reflect what they do. This improves readability and avoids confusion when multiple helpers are imported across modules. - -> Use names like `calculate_damage`, `spawn_enemy_with_strength`, `generate_loot_drop`, etc. - ---- - -### โ™ป๏ธ 3. **Encapsulate Repetitive Logic** - -If you find yourself copying the same logic across multiple systems (e.g., hash generation, clamping values, seeding randomness), move it into a helper. -> This reduces "code smell" and improves maintainability. - ---- - -### ๐Ÿงช 4. **Test Them Independently** - -Because helpers are stateless and modular, theyโ€™re great candidates for unit tests or simulation tests. This ensures their logic works without needing full system setup. - ---- - -### ๐Ÿš€ 5. **Keep Game Logic in Systems, Not Helpers** - -Helpers should **support** game logic, not **replace** it. Avoid embedding ECS actions (like setting components) directly in helpers โ€” keep those in systems or world-dispatchers. - ---- - -### ๐Ÿ—‚๏ธ 6. **Group Helpers by Domain** + #[test] + fn test_random_deterministic() { + // Same inputs should produce same output (deterministic) + let result1 = generate_random_u8(100, 200, 1, 10); + let result2 = generate_random_u8(100, 200, 1, 10); + + assert_eq!(result1, result2, "Random function should be deterministic"); + } -Organize helpers by theme or module (`random.cairo`, `math_utils.cairo`, `combat_helpers.cairo`, etc.) to keep your project structured and navigable. + #[test] + fn test_random_distribution() { + // Test that different inputs produce different outputs + let result1 = generate_random_u8(1, 1, 1, 100); + let result2 = generate_random_u8(2, 1, 1, 100); + + // Very likely to be different (not guaranteed, but statistically sound) + assert_ne!(result1, result2, "Different inputs should likely produce different outputs"); + } +} +``` + +## Types of Helpers You'll Need ๐Ÿ—‚๏ธ + +### **๐ŸŽฒ Randomness Helpers** +```cairo +// pseudo_random.cairo +generate_random_u8() +generate_random_bool() +roll_dice(sides: u8) +``` + +### **๐Ÿงฎ Math Helpers** +```cairo +// math_utils.cairo +clamp_value(value: u32, min: u32, max: u32) +calculate_percentage(part: u32, total: u32) +distance_between_points(x1: u32, y1: u32, x2: u32, y2: u32) +``` + +### **โš”๏ธ Combat Helpers** +```cairo +// combat_utils.cairo +calculate_damage(base: u32, multiplier: u8) +apply_elemental_weakness(damage: u32, attacker_type: Element, defender_type: Element) +calculate_experience_gain(base_exp: u32, level_difference: u8) +``` + +### **๐ŸŽฎ Game Logic Helpers** +```cairo +// game_utils.cairo +validate_move(from: Position, to: Position, movement_type: MovementType) +calculate_cooldown_remaining(last_action: u64, cooldown_duration: u64) +check_inventory_space(current_items: u8, max_capacity: u8) +``` + +## Best Practices for Dojo Helpers โญ + +### โœ… **Do's** +- **Keep them pure**: No side effects, only input โ†’ output transformations +- **Make them stateless**: Don't modify global game state +- **Use descriptive names**: `calculate_critical_hit_chance` not `calc_crit` +- **Add comprehensive tests**: Test edge cases and typical usage +- **Document parameters**: Explain what each input does and expects +- **Group by domain**: Separate files for different helper categories + +### โŒ **Don'ts** +- **Don't embed game logic**: Helpers support systems, they don't replace them +- **Don't access ECS directly**: Keep helpers independent of world state +- **Don't make them too complex**: One helper = one clear purpose +- **Don't hardcode values**: Accept parameters for flexibility + +## Advanced Helper Patterns ๐Ÿš€ + +### **Chained Helpers** +```cairo +// Combine simple helpers for complex operations +let base_damage = calculate_base_damage(attacker_stats); +let elemental_damage = apply_elemental_modifier(base_damage, element_type); +let final_damage = apply_random_variance(elemental_damage, variance_percent); +``` + +### **Configuration Helpers** +```cairo +// Use constants with helpers for game balance +let crit_chance = calculate_crit_chance( + base_chance: WARRIOR_BASE_CRIT, + weapon_bonus: weapon.crit_modifier, + level_bonus: player.level * CRIT_PER_LEVEL +); +``` + +### **Validation Helpers** +```cairo +// Input validation helpers prevent runtime errors +fn validate_position(x: u32, y: u32, map_width: u32, map_height: u32) -> bool { + x < map_width && y < map_height +} +``` + +## Integration with Dojo ECS ๐ŸŽช + +Helper functions work perfectly with Dojo's ECS pattern: + +```cairo +// In your system +#[dojo::interface] +impl CombatActionsImpl { + fn attack(ref world: IWorldDispatcher, target_id: u32) { + // Get ECS data + let attacker = get!(world, (caller), (Player)); + let target = get!(world, (target_id), (Player)); + + // Use helpers for calculations + let hit_chance = calculate_hit_chance(attacker.accuracy, target.evasion); + let hit_roll = generate_random_u8(attacker.id, 1, 1, 100); + + if hit_roll <= hit_chance { + let damage = calculate_damage(attacker.attack, target.defense); + let new_health = target.health.saturating_sub(damage); + + // Update ECS state + set!(world, (Player { id: target_id, health: new_health, ..target })); + } + } +} +``` -Absolutely! Here's a clear and concise **Conclusion** section you can use: +## Conclusion ๐ŸŽฏ ---- +Helper functions are the unsung heroes of clean, maintainable game code in Dojo Engine. They transform repetitive, error-prone calculations into reliable, reusable tools that make your systems easier to read, test, and debug. -## Conclusion ๐ŸŽฏ +**Remember:** +- **Helpers = Reusable Logic Tools** +- **Pure Functions = Predictable Results** +- **Good Tests = Confident Code** +- **Clear Names = Self-Documenting Code** -Helper functions in Dojo Engine are essential tools for writing clean, reusable, and maintainable code. By encapsulating common logic like randomness, math operations, or entity behavior, they keep your systems focused and your codebase modular. When used thoughtfully, helpers enhance readability, reduce duplication, and make your on-chain game logic more robust and scalable. +Start building your helper library early - your future self (and your teammates) will thank you when balancing, debugging, or extending your game becomes a breeze! ๐Ÿš€ -> Think of helpers as the silent teammates behind your game's core systems โ€” small, focused, and powerful. \ No newline at end of file +> Think of helpers as the silent workhorses behind your game's core systems โ€” small, focused, and incredibly powerful. \ No newline at end of file diff --git a/client/pages/integrations/ai/openai.md b/client/pages/integrations/ai/openai.md deleted file mode 100644 index f2554fd..0000000 --- a/client/pages/integrations/ai/openai.md +++ /dev/null @@ -1,3 +0,0 @@ -# OpenIA Integration - -Under development... diff --git a/client/pages/integrations/ai/openrouter.md b/client/pages/integrations/ai/openrouter.md deleted file mode 100644 index 0aa02f0..0000000 --- a/client/pages/integrations/ai/openrouter.md +++ /dev/null @@ -1,3 +0,0 @@ -# Open Router Integration - -Under development... diff --git a/client/pages/integrations/discord.md b/client/pages/integrations/discord.md deleted file mode 100644 index 98ad502..0000000 --- a/client/pages/integrations/discord.md +++ /dev/null @@ -1,3 +0,0 @@ -# Discord Integration - -Under development... diff --git a/client/pages/integrations/telegram.md b/client/pages/integrations/telegram.md deleted file mode 100644 index 71f733d..0000000 --- a/client/pages/integrations/telegram.md +++ /dev/null @@ -1,3 +0,0 @@ -# Telegram Integration - -Under development... diff --git a/client/pages/starters/full-react-starter/full-react-starter.md b/client/pages/starters/full-react-starter/full-react-starter.md new file mode 100644 index 0000000..b0a04a4 --- /dev/null +++ b/client/pages/starters/full-react-starter/full-react-starter.md @@ -0,0 +1,62 @@ +# Dojo Game Starter Template ๐Ÿš€ + +Building onchain games requires integrating many complex pieces: Cairo contracts, React frontends, wallet connections, state management, and deployment pipelines. Instead of spending weeks setting this up from scratch, you can start with a production-ready foundation. + +## What is Dojo Game Starter? ๐ŸŽฎ + +**Dojo Game Starter** is a complete template that provides everything you need to build onchain games on Starknet. It's the same foundation used by successful hackathon teams and game studios to ship games quickly. + +**In the box:** +- โœ… Complete React + Dojo integration with TypeScript +- โœ… Cartridge Controller wallet integration +- โœ… Cairo contracts with player progression system +- โœ… Achievement system implementation +- โœ… Production deployment configurations +- โœ… Comprehensive documentation for extending the game + +## Why Use a Template? ๐Ÿค” + +**Time to first playable game:** +- From scratch: 2-4 weeks of setup +- With template: 5 minutes to running game + +**What you avoid building:** +- Frontend-blockchain integration patterns +- Wallet connection and session management +- State management for onchain operations +- Achievement and progression systems +- Deployment pipeline configurations + +## Sample Game Mechanics ๐ŸŽฏ + +The template includes a simple RPG system to demonstrate core patterns: + +- **๐Ÿ‹๏ธ Train:** Gain experience (pure advancement) +- **โ›๏ธ Mine:** Earn coins, lose health (risk/reward) +- **๐Ÿ’ค Rest:** Restore health (resource management) + +These mechanics teach you how to build any onchain game system. + +## Perfect For ๐ŸŽช + +- **Hackathon teams** who need to ship in 48 hours +- **Developers** learning Dojo through hands-on practice +- **Studios** prototyping new game concepts quickly +- **Anyone** who wants to focus on game design, not infrastructure + +## Get Started ๐Ÿš€ + +```bash +git clone https://github.com/AkatsukiLabs/Dojo-Game-Starter.git +cd dojo-game-starter +``` + +**Next steps:** +1. Follow the [Frontend Guide](https://github.com/AkatsukiLabs/Dojo-Game-Starter/tree/main/client) for React development +2. Check the [Backend Guide](https://github.com/AkatsukiLabs/Dojo-Game-Starter/tree/main/contract) for Cairo contracts + +--- + +**๐Ÿ”— [Get the Template](https://github.com/AkatsukiLabs/Dojo-Game-Starter)** | **๐ŸŽฎ [Live Demo](https://dojo-game-starter.vercel.app/)** + +Ready to build your onchain game? Start with a solid foundation and focus on what makes your game unique! ๐ŸŽฎ \ No newline at end of file diff --git a/client/routes.ts b/client/routes.ts index 41b7f81..4f74af8 100644 --- a/client/routes.ts +++ b/client/routes.ts @@ -87,6 +87,16 @@ const config: Sidebar = [ }, ], }, + { + text: "Starters & Templates", + collapsed: true, + items: [ + { + text: "Full Starter React", + link: "/starters/full-react-starter", + }, + ], + }, { text: "Applications", collapsed: true, @@ -127,14 +137,6 @@ const config: Sidebar = [ text: "React", link: "/integrations/react", }, - { - text: "Telegram", - link: "/integrations/telegram", - }, - { - text: "Discord", - link: "/integrations/discord", - }, { text: "Unity", link: "/integrations/unity", @@ -150,14 +152,6 @@ const config: Sidebar = [ text: "Eliza", link: "/integrations/ai/eliza", }, - { - text: "OpenAI", - link: "/integrations/ai/openai", - }, - { - text: "OpenRouter", - link: "/integrations/ai/openrouter", - }, ], }, ],