Clay World Plugin

The Clay World plugin provides comprehensive game world management for both 2D and 3D games. It integrates canvas rendering, physics simulation, and SVG-based level loading into cohesive world components. The plugin offers separate implementations for 2D and 3D worlds while sharing common functionality like scene loading and entity management.

Getting Started

To use the Clay World plugin in your QML files:

import Clayground.World

Core Components

  • ClayWorld2d - Complete 2D game world with Box2D physics, ClayCanvas rendering, and camera following
  • ClayWorld3d - Complete 3D game world with Qt Quick 3D physics and WASD/orbit camera controls
  • ClayWorldBase - Shared base functionality for scene loading and entity management
  • SceneLoader2d - Loads entities from SVG files into 2D worlds
  • SceneLoader3d - Loads entities from SVG files into 3D worlds
  • Minimap2d - Miniature map view of a 2D world
  • Box3DBody - 3D physics-enabled box shape
  • Usage Examples

    Basic 2D World

    
    import QtQuick
    import Clayground.World
    import Clayground.Physics
    
    ClayWorld2d {
        id: gameWorld
        anchors.fill: parent
    
        // World setup
        xWuMin: 0
        xWuMax: 100
        yWuMin: 0
        yWuMax: 50
    
        // Physics
        gravity: Qt.point(0, 10)
    
        // Camera follows player
        observedItem: player
    
        RectBoxBody {
            id: player
            xWu: 10
            yWu: 10
            widthWu: 2
            heightWu: 2
            color: "blue"
            bodyType: Body.Dynamic
        }
    }
    

    Level Loading from SVG

    
    ClayWorld2d {
        id: world
        scene: "levels/level1.svg"
        loadMapAsync: true
    
        // Register components for SVG loading
        components: new Map([
            ["Wall", wallComponent],
            ["Enemy", enemyComponent],
            ["Collectible", coinComponent]
        ])
    
        Component {
            id: wallComponent
            RectBoxBody {
                color: "#333333"
                bodyType: Body.Static
            }
        }
    
        Component {
            id: enemyComponent
            RectBoxBody {
                color: "red"
                bodyType: Body.Dynamic
            }
        }
    
        onMapLoaded: {
            console.log("Level loaded!")
        }
    }
    

    3D World Setup

    
    ClayWorld3d {
        id: world3d
        anchors.fill: parent
    
        // World size
        xWuMax: 200
        zWuMax: 200
    
        // Camera setup
        observedObject: player3d
    
        Box3DBody {
            id: player3d
            position: Qt.vector3d(50, 10, 50)
            width: 20
            height: 20
            depth: 20
            color: "orange"
        }
    
        // Load 3D scene
        scene: "levels/3d_level.svg"
        components: new Map([
            ["Platform", platform3dComponent]
        ])
    }
    

    Minimap Implementation

    
    ClayWorld2d {
        id: mainWorld
        // ... world setup
    }
    
    Minimap2d {
        world: mainWorld
        width: 200
        height: 150
    
        anchors.right: parent.right
        anchors.top: parent.top
        anchors.margins: 20
    
        // Map entity types to minimap representations
        typeMapping: new Map([
            ["Player", playerDotComponent],
            ["Enemy", enemyDotComponent],
            ["Wall", wallRectComponent]
        ])
    
        Component {
            id: playerDotComponent
            Rectangle {
                color: "green"
                radius: width * 0.5
            }
        }
    
        Component {
            id: enemyDotComponent
            Rectangle { color: "red" }
        }
    }
    

    Dynamic Entity Creation

    
    ClayWorld2d {
        id: world
    
        function spawnEnemy(x, y) {
            let enemy = enemyComponent.createObject(room, {
                xWu: x,
                yWu: y
            })
            return enemy
        }
    
        Component {
            id: enemyComponent
            RectBoxBody {
                widthWu: 2
                heightWu: 2
                color: "red"
                bodyType: Body.Dynamic
            }
        }
    
        Timer {
            interval: 5000
            repeat: true
            running: true
            onTriggered: {
                world.spawnEnemy(
                    Math.random() * world.xWuMax,
                    Math.random() * world.yWuMax
                )
            }
        }
    }
    

    Custom Scene Loading

    
    ClayWorld2d {
        id: world
    
        onPolylineLoaded: (id, groupId, points, fillColor, strokeColor, description) => {
            // Handle patrol paths
            if (description.includes("patrol_path")) {
                createPatrolPath(id, points)
            }
        }
    
        onGroupAboutToBeLoaded: (id, description) => {
            console.log("Loading group:", id)
        }
    
        onMapEntityCreated: (obj, groupId, compName) => {
            // Post-process loaded entities
            if (compName === "Enemy") {
                obj.target = player
            }
        }
    }
    

    Physics Configuration

    
    ClayWorld2d {
        // Platformer physics
        gravity: Qt.point(0, 20)
        timeStep: 1/60
    
        // Top-down physics
        // gravity: Qt.point(0, 0)
    
        // Debug rendering
        debugPhysics: true
        debugRendering: true
    
        // Pause physics
        MouseArea {
            anchors.fill: parent
            onClicked: parent.physicsEnabled = !parent.physicsEnabled
        }
    }
    

    Best Practices

    1. Scene Organization: Use SVG groups to organize level elements logically. 2. Component Registration: Register all components before loading scenes. 3. Async Loading: Use loadMapAsync: true for large levels to prevent UI freezing. 4. World Units: Always work in world units for consistency across different screen sizes. 5. Entity Management: Use the room container for proper entity lifecycle management. 6. Performance: Limit physics bodies and use static bodies where possible.

    Technical Implementation

    The Clay World plugin provides:
  • Unified World Management: Common base for 2D and 3D worlds
  • SVG Scene Loading: Parse SVG files with JSON metadata for game entities
  • Physics Integration: Seamless Box2D (2D) and Qt Quick 3D Physics integration
  • Camera Systems: Automatic following for 2D, orbit/WASD controls for 3D
  • Async Loading: Non-blocking entity creation for smooth gameplay
  • Component Factory: Map SVG descriptions to QML components
  • The plugin handles coordinate transformations, physics body creation, and proper parent-child relationships automatically, making it easy to create complex game worlds from simple SVG layouts.