Popcorning Guinea Pig
Search Results for

    Card Game Example

    Card game example

    This example demonstrates a 3D card game implementation using the PopcorningGuineaPig Engine's advanced card system. It showcases 3D card rendering, interactive card manipulation, pile management, and complex game mechanics in a three-dimensional environment.

    Overview

    The Card Game example is located in examples/card-game/ and demonstrates:

    • 3D Card System: Full 3D card rendering and interaction
    • Card Pile Management: Draw pile, discard pile, and hand management
    • Interactive Card Sections: Clickable areas on cards (title, picture, loot)
    • Drag-and-Drop Mechanics: 3D mouse interaction with cards
    • Procedural Texture Generation: Runtime card texture creation
    • Visual Effects: Particle effects for card actions
    • 3D Camera System: Perspective camera for card table view

    Key Features

    1. 3D Card System

    Advanced 3D card representation with interactive sections:

    // Create a 3D card with front/back textures
    Card3D card = new Card3D(
        cardSpecificTexture,    // Front texture
        cardBackTexture,        // Back texture
        Vector3.Zero,           // Initial position
        new Vector2(1.5f, 2.0f), // Card dimensions
        0.05f                   // Card thickness
    );
    
    // Add interactive sections to the card
    card.AddSection("title", new Rectangle(0.1f, 0.05f, 0.8f, 0.15f));    // Top section
    card.AddSection("picture", new Rectangle(0.15f, 0.25f, 0.7f, 0.4f));  // Center section
    card.AddSection("loot", new Rectangle(0.1f, 0.75f, 0.8f, 0.2f));      // Bottom section
    
    // Enable nine-slice scaling for card textures
    card.SetFrontNineSlice(10);
    card.SetBackNineSlice(10);
    
    // Set initial state
    card.SetFaceUp(false);
    

    2. Card Pile System

    Organized card management with visual stacking:

    // Create card piles with 3D positioning
    drawPile = new CardPile3D(new Vector3(-4, 0.2f, -2.0f), Vector3.Zero, 0.01f);
    discardPile = new CardPile3D(new Vector3(2, 0.2f, 0), Vector3.Zero, 0.01f);
    
    // Add cards to pile with animation
    drawPile.AddCard(card, false); // Add without animation
    discardPile.AddCard(card, true); // Add with animation
    
    // Shuffle the deck
    drawPile.Shuffle();
    
    // Draw cards from pile
    Card3D? drawnCard = drawPile.DrawCard(true); // Draw with animation
    

    3. Procedural Texture Generation

    Runtime texture creation for cards and table:

    // Generate card back texture
    cardBackTexture = TextureGenerator.GenerateCardBackTexture(
        200, 300, 
        new Color(0, 0, 128, 255) // Blue back
    );
    
    // Generate suit-specific textures
    foreach (CardSuit suit in Enum.GetValues(typeof(CardSuit)))
    {
        suitTextures[suit] = TextureGenerator.GenerateCardFrontTexture(
            200, 300, suit, CardValue.Ace
        );
    }
    
    // Generate table texture
    tableTexture = TextureGenerator.GenerateTableTexture(1024, 1024);
    

    4. 3D Mouse Interaction

    Advanced 3D mouse picking and dragging:

    private void HandleMouseInput(float deltaTime)
    {
        Vector2 mousePos = Raylib.GetMousePosition();
        string sectionName = string.Empty;
    
        // Check for card hover with section detection
        if (currentCard != null && currentCard.IsPointOver(mousePos, camera, out sectionName))
        {
            currentCard.SetHighlight(true, Color.Yellow, 1.0f);
            hoveredSection = sectionName;
            
            // Set contextual tooltip
            switch (sectionName)
            {
                case "title":
                    sectionTooltip = "Card Title - Shows the name of this card";
                    break;
                case "picture":
                    sectionTooltip = "Card Artwork - The main illustration";
                    break;
                case "loot":
                    sectionTooltip = "Loot Icons - Rewards for playing this card";
                    break;
            }
        }
    
        // Handle card dragging in 3D space
        if (isDragging && currentCard != null)
        {
            Ray ray = Raylib.GetScreenToWorldRay(mousePos, camera);
            Vector3 planeNormal = Vector3.UnitY;
            Vector3 planePoint = new Vector3(0, 0.5f, 0);
    
            // Calculate intersection with dragging plane
            float denominator = Vector3.Dot(ray.Direction, planeNormal);
            if (Math.Abs(denominator) > 0.0001f)
            {
                float t = Vector3.Dot(planePoint - ray.Position, planeNormal) / denominator;
                if (t >= 0)
                {
                    Vector3 intersectionPoint = ray.Position + ray.Direction * t;
                    currentCard.SetPosition(new Vector3(intersectionPoint.X, 0.5f, intersectionPoint.Z));
                }
            }
        }
    }
    

    5. Card Data Structure

    Comprehensive card representation:

    public enum CardSuit
    {
        Hearts, Diamonds, Clubs, Spades
    }
    
    public enum CardValue
    {
        Ace = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6, Seven = 7,
        Eight = 8, Nine = 9, Ten = 10, Jack = 11, Queen = 12, King = 13
    }
    
    public class CardData
    {
        public CardSuit Suit { get; }
        public CardValue Value { get; }
        
        public CardData(CardSuit suit, CardValue value)
        {
            Suit = suit;
            Value = value;
        }
        
        public override string ToString() => $"{Value} of {Suit}";
    }
    

    6. Deck Creation and Management

    Systematic deck initialization:

    private void CreateDeck()
    {
        for (int i = 0; i < 10; i++)
        {
            // Create card data
            CardSuit suit = (CardSuit)(i % 4);
            CardValue value = (CardValue)((i % 13) + 1);
            CardData cardData = new CardData(suit, value);
            
            // Generate specific texture for this card
            Texture2D cardSpecificTexture = TextureGenerator.GenerateCardFrontTexture(
                200, 300, suit, value
            );
            
            // Create 3D card
            Card3D card = new Card3D(
                cardSpecificTexture, cardBackTexture,
                Vector3.Zero, new Vector2(1.5f, 2.0f), 0.05f
            );
            
            // Configure card sections and properties
            card.AddSection("title", new Rectangle(0.1f, 0.05f, 0.8f, 0.15f));
            card.AddSection("picture", new Rectangle(0.15f, 0.25f, 0.7f, 0.4f));
            card.AddSection("loot", new Rectangle(0.1f, 0.75f, 0.8f, 0.2f));
            
            card.SetFrontNineSlice(10);
            card.SetBackNineSlice(10);
            card.SetFaceUp(false);
            
            drawPile.AddCard(card, false);
        }
        
        drawPile.Shuffle();
    }
    

    7. Hand Management

    Player hand positioning and interaction:

    private void DrawCard()
    {
        if (drawPile.GetCardCount() > 0)
        {
            Card3D? card = drawPile.DrawCard(true);
            if (card != null)
            {
                playerHand.Add(card);
                
                // Calculate hand position
                int cardIndex = playerHand.Count - 1;
                float xPos = -2.0f + cardIndex * 0.4f;  // Spread cards horizontally
                float yPos = 0.3f + cardIndex * 0.02f;  // Slight vertical offset
                float zPos = 2.0f;                      // Towards player
                
                card.SetPosition(new Vector3(xPos, yPos, zPos));
                card.SetRotation(Vector3.Zero);
                card.SetFaceUp(true); // Show card face when in hand
            }
        }
    }
    

    8. Visual Effects System

    Particle effects for game actions:

    // Initialize particle effect
    private ParticleEffect discardEffect = new ParticleEffect();
    
    // Trigger effect when card is discarded
    if (discardPile.IsPointOver(mousePos, camera))
    {
        discardPile.AddCard(currentCard, true);
        
        // Trigger visual effect
        discardEffect.Trigger(discardPile.GetPosition(), Color.Gold);
        
        // Execute callback
        onCardDiscarded?.Invoke(currentCard);
        
        playerHand.Remove(currentCard);
        currentCard = null;
    }
    

    Scene Structure

    3D Environment Setup

    Creating the card table environment:

    public override void Load()
    {
        // Initialize 3D camera
        camera = new Camera3D
        {
            Position = new Vector3(0, 10, 0),    // Above the table
            Target = new Vector3(0, 0, 0),       // Looking at table center
            Up = new Vector3(0, 0, -1),          // Up vector
            FovY = 45,                           // Field of view
            Projection = CameraProjection.Perspective
        };
        
        // Create table model
        tableModel = Raylib.LoadModelFromMesh(Raylib.GenMeshCube(10.0f, 0.2f, 6.0f));
        
        // Define target area for card play
        targetArea = new BoundingBox(
            new Vector3(2, 0, -2.5f),
            new Vector3(4, 0.5f, -1.5f)
        );
    }
    

    Update Loop

    Comprehensive game state management:

    public override void Update(double deltaTime)
    {
        float dt = (float)deltaTime;
        
        // Update card piles
        drawPile.Update(dt);
        discardPile.Update(dt);
        
        // Update current card
        currentCard?.Update(dt);
        
        // Update visual effects
        discardEffect.Update(dt);
        
        // Handle mouse input
        HandleMouseInput(dt);
        
        // Update target effect timeout
        if (showTargetEffect)
        {
            Task.Delay(1000).ContinueWith(_ => showTargetEffect = false);
        }
    }
    

    3D Rendering

    Multi-layer rendering system:

    public override void Render(int width, int height)
    {
        Raylib.ClearBackground(Color.SkyBlue);
        
        Raylib.BeginMode3D(camera);
        
        // Draw environment
        Raylib.DrawModel(tableModel, Vector3.Zero, 1.0f, Color.White);
        Raylib.DrawCube(new Vector3(0, 0.1f, 0), 10.0f, 0.01f, 6.0f, tableColor);
        
        // Draw game elements
        drawPile.Draw(camera);
        discardPile.Draw(camera);
        
        // Draw player hand
        foreach (var card in playerHand)
        {
            card.Draw(camera);
        }
        
        // Draw target area
        Raylib.DrawBoundingBox(targetArea, Color.Yellow);
        
        // Draw effects
        discardEffect.Draw();
        
        if (showTargetEffect)
        {
            Vector3 center = targetArea.Min + (targetArea.Max - targetArea.Min) / 2;
            Raylib.DrawCube(center, 2, 0.6f, 2, Color.Gold);
        }
        
        Raylib.EndMode3D();
        
        // Draw 2D UI overlay
        DrawUI();
    }
    

    Running the Example

    Prerequisites

    • .NET 10.0 or later
    • PopcorningGuineaPig.Engine reference
    • Raylib-cs package

    Build and Run

    cd examples/card-game/CardGame
    dotnet build
    dotnet run
    

    Project Structure

    CardGame/
    ├── CardGame.csproj          # Project file
    ├── MyGame.cs                # Game initialization
    ├── Program.cs               # Entry point
    ├── CardData.cs              # Card data structures
    ├── TextureGenerator.cs      # Procedural texture generation
    ├── ParticleEffect.cs        # Visual effects system
    └── scenes/
        └── CardGameScene.cs     # Main game scene
    

    What You'll Learn

    1. 3D Card Rendering: Creating and managing 3D card objects
    2. Interactive Sections: Defining clickable areas on 3D objects
    3. 3D Mouse Picking: Converting 2D mouse coordinates to 3D world space
    4. Pile Management: Organizing cards in structured collections
    5. Procedural Generation: Creating textures at runtime
    6. Drag-and-Drop 3D: Implementing 3D object manipulation
    7. Camera Systems: Setting up 3D perspective cameras
    8. Visual Effects: Adding particle effects to game actions

    Advanced Techniques

    3D-to-2D Projection

    Converting world coordinates to screen space:

    Vector3 cardScreenPos = PopcorningGuineaPig.Engine.Helpers.RaycastHelper.WorldToScreen(
        currentCard.GetPosition(), 
        camera
    );
    

    Plane Intersection for Dragging

    Mathematical 3D plane intersection:

    Ray ray = Raylib.GetScreenToWorldRay(mousePos, camera);
    Vector3 planeNormal = Vector3.UnitY;
    Vector3 planePoint = new Vector3(0, 0.5f, 0);
    
    float denominator = Vector3.Dot(ray.Direction, planeNormal);
    if (Math.Abs(denominator) > 0.0001f)
    {
        float t = Vector3.Dot(planePoint - ray.Position, planeNormal) / denominator;
        if (t >= 0)
        {
            Vector3 intersectionPoint = ray.Position + ray.Direction * t;
            currentCard.SetPosition(new Vector3(intersectionPoint.X, 0.5f, intersectionPoint.Z));
        }
    }
    

    Contextual Tooltips

    Dynamic tooltip system based on interaction:

    // Set tooltip based on hovered section
    switch (sectionName)
    {
        case "title":
            sectionTooltip = "Card Title - Shows the name of this card";
            break;
        case "picture":
            sectionTooltip = "Card Artwork - The main illustration";
            break;
        case "loot":
            sectionTooltip = "Loot Icons - Rewards for playing this card";
            break;
        default:
            sectionTooltip = "Card - Drag to discard pile or click to flip";
            break;
    }
    

    Event-Driven Architecture

    Delegate-based game events:

    private Action<Card3D>? onCardDiscarded;
    
    // Set up event handler
    onCardDiscarded = (card) => {
        cardsRemaining = drawPile.GetCardCount();
        Console.WriteLine($"Card discarded! Cards remaining: {cardsRemaining}");
        
        if (drawPile.GetCardCount() == 0)
        {
            Console.WriteLine("Game over! All cards have been discarded.");
        }
    };
    

    Game Mechanics

    Target Area System

    Defined zones for card play:

    // Define target area
    targetArea = new BoundingBox(new Vector3(2, 0, -2.5f), new Vector3(4, 0.5f, -1.5f));
    
    // Check if card is played to target
    if (currentCard != null && IsPointInBoundingBox(currentCard.GetPosition(), targetArea))
    {
        Console.WriteLine("Card played to target area!");
        showTargetEffect = true;
        
        discardPile.AddCard(currentCard, true);
        playerHand.Remove(currentCard);
        currentCard = null;
    }
    

    Hand Positioning Algorithm

    Automatic hand layout:

    // Calculate position for card in hand
    int cardIndex = playerHand.Count - 1;
    float xPos = -2.0f + cardIndex * 0.4f;      // Horizontal spread
    float yPos = 0.3f + cardIndex * 0.02f;       // Slight elevation
    float zPos = 2.0f;                           // Towards player
    
    card.SetPosition(new Vector3(xPos, yPos, zPos));
    

    Performance Considerations

    1. Texture Reuse: Share textures between similar cards
    2. LOD System: Use simpler models for distant cards
    3. Culling: Don't render cards outside camera view
    4. Batch Rendering: Group similar cards for efficient rendering
    5. Memory Management: Properly dispose of textures and models

    Related Documentation

    • Card System - Detailed card system implementation
    • 3D Scenes - 3D scene management
    • UI Components - UI element integration
    • Game Architecture - Scene and game structure

    Next Steps

    After exploring this example, consider:

    1. Card Game Logic: Implement specific game rules (poker, solitaire, etc.)
    2. Multiplayer Support: Add network multiplayer capabilities
    3. Advanced Effects: Implement card flipping animations and transitions
    4. AI Opponents: Create computer players with game AI
    5. Custom Card Types: Design specialized card mechanics
    6. Save System: Implement game state persistence

    This example demonstrates the engine's capability for complex 3D interactive systems, providing a foundation for sophisticated card-based games and similar interactive 3D applications.

    • Edit this page
    In this article
    Back to top © 2024 Popcorning Guinea Pig Game Engine. A custom C# game engine for indie developers.