Skip to content

Instantly share code, notes, and snippets.

@jrmoserbaltimore
Created May 26, 2024 04:51
Show Gist options
  • Save jrmoserbaltimore/bdb5dfec15fa4f8dccc1f4e08ec1679f to your computer and use it in GitHub Desktop.
Save jrmoserbaltimore/bdb5dfec15fa4f8dccc1f4e08ec1679f to your computer and use it in GitHub Desktop.

To implement the PluginBloxel for your Minecraft-style game in Rust using Bevy, you'll need to design your WorldGrid type along with appropriate traits, components, and systems to manage the voxel grid, entities, and interactions.

Types and Components

  1. IVec3: Already provided by Bevy for grid coordinates.
  2. WorldGrid: Manages the entities in the voxel grid.
  3. Block: Represents a 1-meter cube making up the terrain.
  4. NonBlockEntity: Represents non-block entities like tables, chairs, buttons, etc.
  5. SubGrid: Represents nested WorldGrid instances.

Traits

  1. GridEntity: A trait for entities that can be placed in the WorldGrid.
  2. Interactable: A trait for entities that can be interacted with, such as buttons.

Components

  1. GridPosition: Stores the IVec3 position of an entity within the WorldGrid.
  2. InteractableComponent: Marks an entity as interactable and contains interaction logic.
  3. SubGridComponent: Associates a SubGrid with its parent WorldGrid.

Example Implementation

use bevy::prelude::*;
use bevy::math::IVec3;

struct PluginBloxel;

impl Plugin for PluginBloxel {
    fn build(&self, app: &mut AppBuilder) {
        app.add_system(coalesce_chunks.system())
           .add_system(handle_interactions.system())
           .add_system(remove_non_visible_blocks.system());
    }
}

// Components

#[derive(Component)]
struct GridPosition {
    position: IVec3,
}

#[derive(Component)]
struct InteractableComponent;

#[derive(Component)]
struct SubGridComponent {
    sub_grid: WorldGrid,
}

// Traits

trait GridEntity {
    fn get_position(&self) -> IVec3;
    fn set_position(&mut self, position: IVec3);
}

impl GridEntity for GridPosition {
    fn get_position(&self) -> IVec3 {
        self.position
    }

    fn set_position(&mut self, position: IVec3) {
        self.position = position;
    }
}

trait Interactable {
    fn interact(&self);
}

// Entities

struct Block;

impl Block {
    fn new(position: IVec3) -> Self {
        Block
    }
}

impl GridEntity for Block {
    fn get_position(&self) -> IVec3 {
        // Implementation
    }

    fn set_position(&mut self, position: IVec3) {
        // Implementation
    }
}

struct NonBlockEntity;

impl NonBlockEntity {
    fn new(position: IVec3) -> Self {
        NonBlockEntity
    }
}

impl GridEntity for NonBlockEntity {
    fn get_position(&self) -> IVec3 {
        // Implementation
    }

    fn set_position(&mut self, position: IVec3) {
        // Implementation
    }
}

impl Interactable for NonBlockEntity {
    fn interact(&self) {
        // Implementation
    }
}

// Systems

fn coalesce_chunks(mut commands: Commands, query: Query<(Entity, &GridPosition)>) {
    // Implementation for coalescing adjacent blocks
}

fn handle_interactions(mut query: Query<(&InteractableComponent, &GridPosition)>) {
    // Implementation for handling interactions
}

fn remove_non_visible_blocks(mut commands: Commands, query: Query<(Entity, &GridPosition)>) {
    // Implementation for removing non-visible blocks
}

// WorldGrid

struct WorldGrid {
    entities: Vec<Entity>,
}

impl WorldGrid {
    fn new() -> Self {
        WorldGrid { entities: Vec::new() }
    }

    fn add_entity(&mut self, entity: Entity, position: IVec3) {
        // Implementation for adding entities to the grid
    }

    fn merge_grid(&mut self, other: WorldGrid) {
        // Implementation for merging another grid into this one
    }
}

fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .add_plugin(PluginBloxel)
        .run();
}

Detailed Breakdown

  1. PluginBloxel:

    • Registers systems for chunk coalescing, handling interactions, and removing non-visible blocks.
  2. Components:

    • GridPosition: Stores the grid position (IVec3) of an entity.
    • InteractableComponent: Marks an entity as interactable.
    • SubGridComponent: Associates a sub-grid with its parent grid.
  3. Traits:

    • GridEntity: Provides methods to get and set the position of entities in the grid.
    • Interactable: Provides an interact method for interactable entities.
  4. Entities:

    • Block: Represents a 1-meter cube block.
    • NonBlockEntity: Represents non-block entities like tables and buttons.
  5. Systems:

    • coalesce_chunks: System for coalescing adjacent blocks into larger chunks.
    • handle_interactions: System for handling interactions with interactable entities.
    • remove_non_visible_blocks: System for removing non-visible blocks from the grid.
  6. WorldGrid:

    • Manages entities within a voxel grid, allowing for adding entities, merging grids, and other operations.

This structure provides a solid foundation for managing a voxel grid in a Minecraft-style game using Bevy in Rust. You can expand and refine this design based on specific game requirements and optimizations.

I am writing a Bevy plugin PluginBloxel to provide the voxel grid for a Minecraft style game in Rust, with 1 meter cubes. The game uses IVec3, a vector object in Bevy with three 32-bit integer components (x,y,z), as coordinates for objects that are settled on the grid, where the coordinate (2,2,2) on the grid is the Vec3 coordinate (2.0,2.0,2.0) in the game world. Entities that are currently moving independent of the grid are not tracked by this grid.

My goal is to have a WorldGrid type, to which such entities can be attached. These entities may include:

  1. Blocks, being 1 meter cubes that make up the terrain.
  2. Non-block entities, such as tables, chairs, buttons, traps, and the like.
  3. Other WorldGrid, with their origin aligned to a location on the WorldGrid parent.

The programmer interacts with the WorldGrid by adding entities at IVec3 locations. All operations such as coalescing adjacent blocks into larger chunks with combined hitboxes, detecting which entity was hit when such a chunk is hit, removing non-visible blocks from the world as seen by the renderer, and so forth are handled by PluginBloxel in a way not visible to the programmer.

Other considerations:

  1. Adjacent Entities which form larger objects, such as windows that can be placed next to each other to form a large pane of glass by procedurally generating a model, need to be handled automatically as well, while striking any particular point on the generated object needs to be handled as if the individual Entity was struck.
  2. Some Entities will be interactable, such as buttons, possibly by contact (collision) or by triggering.
  3. A WorldGrid may be merged onto another WorldGrid, transferring its contents to the corresponding locations.

What types, traits, and components should I provide?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment