#Weird chess proto (generation + drag'n'drop)

13 messages · Page 1 of 1 (latest)

frank wave
#

I'm coming from unity, this is my first bevy project.
I have some questions regarding structure. and how to do things in a standard way.

I developed each functionality separately but I don't know if I should tend toward something more monolythic like in OOP.
The verbosity of the Resources feels like friction toward using it so in some systems I use queries each frame instead of storing something like I'd do in oop.
I also tend to use .unwrap() everywhere, should I not and use another syntax instead?
Also how would you separate that into separate files ?
would you make a plugin so to regroup all resources inserts and systems ?
And any advice on anything else.
(except for the way I generated each tile individualy instad of using a texture because I'm going to use that)

use bevy::math::U8Vec2;
use bevy::prelude::*;
use bevy::window::{PresentMode, PrimaryWindow};
fn main(){
    App::new()
    .insert_resource(BoardIndex(U8Vec2 { x: (0), y: (0) }))
    .insert_resource(DnDHoldState(false))
    .insert_resource(MouseWorldPosition(Vec3{x:0.0,y:0.0,z:0.0}))
    .insert_resource(HeldPiece(None))
    .add_systems(Startup, setup)
    .add_systems(Update, click_state_position)
    .add_systems(Update, follow_mouse)
    .add_plugins(DefaultPlugins.set(WindowPlugin{
        primary_window : Some(Window {
            present_mode : PresentMode::Immediate,
            ..default()
        }),
        ..default()
    }))
    .run();
}
#[derive(Resource)]
struct BoardIndex(U8Vec2);
#[derive(Resource)]
struct DnDHoldState(bool);
#[derive(Resource)]
#
struct MouseWorldPosition(Vec3);

fn click_state_position( // this system calculates and stores the grid position of a click, and its state
    keyboard_input : Res<ButtonInput<MouseButton>>,
    q_windows : Query<&Window, With<PrimaryWindow>>,
    q_camera : Query<(&Camera, &GlobalTransform)>,
    mut board_index : ResMut<BoardIndex>,
    mut drag_drop_hold_state : ResMut<DnDHoldState>,
    mut mouse_pos : ResMut<MouseWorldPosition>
){

    let (camera,camera_transform) = q_camera.single().unwrap();
    let cursor = q_windows.single().unwrap().cursor_position().unwrap_or(Vec2 { x: (0.0), y: (0.0) });
        
    let pos =camera.viewport_to_world(camera_transform, cursor).unwrap().origin;
    mouse_pos.0 = pos;

    let pressed = keyboard_input.just_pressed(MouseButton::Left);
    let released = keyboard_input.just_released(MouseButton::Left);
    if  pressed || released{

        
        let (x,y) = world_to_index(pos.truncate()); 
        board_index.0 = U8Vec2::new(x as u8,y as u8);
        drag_drop_hold_state.0 = pressed && !released; 
    }
}
fn world_to_index(position : Vec2) -> (i32,i32){
        let clamp_x = position.x.clamp(-247.5, 247.0);// .0 pour eviter le 9 apres le clamp 247.5+247.5 = 495. 495/55 = 9
        let clamp_y = position.y.clamp(-247.5,247.0);
        
        ( ((clamp_x +247.5 ) /55.0).floor() as i32,
         ((clamp_y +247.5 ) /55.0).floor() as i32)
}
#
fn setup( // this system creates and places all squares and the pieces in the second for loop.
    // I use separate meshes instead of a texture because I intend to change each cases color.
    mut commands : Commands,
    mut meshes : ResMut<Assets<Mesh>>,
    mut materials : ResMut<Assets<ColorMaterial>>,

){
  
    commands.spawn(Camera2d);
    
    let square = meshes.add(Rectangle::new(55.0,55.0));
    let circle = meshes.add(Circle::new(25.0));
    let pieces = "p33p34p35";
    let pieces_color = Color::hsl(0.0, 1.0, 0.5);
    for y in 0..9{
        for x in 0..9{
            
            let lightness = ((x+y)%2) as f32;
            let color = Color::hsl(0.0,0.0,lightness);
            
            commands.spawn((
            Mesh2d(square.clone()),
            MeshMaterial2d(materials.add(color)),
            Transform::from_xyz((x as f32)*55.0 -220.0 , (y as f32)*55.0 - 220.0, 0.0)));
            //debug!("{}",color.luminance())

        }
    }

    for i in 0..(pieces.len()/3){
        //println!("{}",i+1);
        let x_int: u8 = char::to_digit(pieces.chars().nth(i*3+1).unwrap(), 10).unwrap() as u8;
        let y_int: u8 = char::to_digit(pieces.chars().nth(i*3+2).unwrap(), 10).unwrap() as u8;
        let x =  x_int as f32*55.0 -220.0;
        let y =  y_int as f32*55.0 -220.0;

        commands.spawn((
            Mesh2d(circle.clone()),
            MeshMaterial2d(materials.add(pieces_color)),
            GridPosition(U8Vec2 { x: (x_int), y: (y_int) }),
            Transform::from_xyz(x,y,1.0)
        )

        );
    }
}
#
#[derive(Component)]
struct GridPosition(U8Vec2);

#[derive(Resource)]
struct HeldPiece(Option<Entity>);

fn follow_mouse( // this system manages the pieces positions when they're held and snaps them in the grid at release.
    pieces : Query<(Entity, &mut Transform,  &mut GridPosition)>,
    hold_state : Res<DnDHoldState>,
    clicked_position : Res<BoardIndex>,
    mouse_world : Res<MouseWorldPosition>,
    mut held_piece : ResMut<HeldPiece>
){
   
    for mut piece in pieces{

        if piece.2.0  == clicked_position.0{ //follow mouse
                piece.1.translation = mouse_world.0;
                held_piece.0 = Some(piece.0);
        }

        if let Some(piece_h) =  held_piece.0{ // place piece to nearest grid position and set held to none
            if !hold_state.0 && piece_h == piece.0 {
                piece.2.0 =  clicked_position.0;
                piece.1.translation = Vec3::new((clicked_position.0.x as f32)*55.0 -220.0,
                                                (clicked_position.0.y as f32)*55.0 - 220.0,
                                                0.0);
                held_piece.0 = None;
        }
        }
    }
}
pallid stirrup
#

Query.single().unwrap() can be replaced with Single

#

you can improve the nth(i*3+1) thing with step_by

#

check out bevy_picking

#

why are the x and y for the board squares 0..9? that gives 9 iterations

pallid stirrup
frank wave
#

Yeah, its voluntary I'm not making a normal chess, I wanted to have a center cross.

#

Ok thank you, ill check all that, what about the global structure ? Would you have done it that way ?

pallid stirrup
#

i'd have fewer resources

#

make HeldPiece a marker component (or relationship if you anticipate multiple cursors), drag/drop could be either moved to the picking events or HeldPiece