/* * This file is part of laurelin_client * Copyright (C) 2023 Jonni Liljamo * * Licensed under GPL-3.0-only. * See LICENSE for licensing information. */ use bevy::prelude::*; use bevy_mod_picking::prelude::*; use bevy_picking_rapier::RapierPickTarget; use bevy_rapier3d::prelude::*; use bevy_text_mesh::prelude::*; use crate::game_status::Card; pub struct CardPlugin; impl Plugin for CardPlugin { fn build(&self, app: &mut App) { app.init_resource::() .add_system(on_spawn_card); } } // NOTE: kind of like using enum variants pub mod visual_card_kind { use bevy::prelude::*; #[derive(Component)] pub struct Normal; #[derive(Component)] pub struct Supply(pub usize); #[derive(Component)] pub struct Hand(pub usize); } #[derive(Component, Clone)] pub struct ClickedCard; #[derive(Component)] pub struct VisualCard { pub card: Card, } impl VisualCard { pub const ASPECT_RATIO: f32 = 5. / 8.; } impl Default for VisualCard { fn default() -> Self { Self { card: Card { name: "".to_string(), short_details: vec![], long_details: vec![], cost: 0, actions: vec![], }, } } } #[derive(Bundle)] pub struct VisualCardBundle { pub visual_card: VisualCard, pub transform: Transform, pub global_transform: GlobalTransform, pub visibility: Visibility, pub computed_visibility: ComputedVisibility, pub collider: Collider, pub rigid_body: RigidBody, } impl Default for VisualCardBundle { fn default() -> Self { Self { visual_card: VisualCard::default(), transform: Transform { translation: Vec3 { x: 0., y: 0., z: 0., }, /// defaults to being rotated 90 degress on X, so flat on the /// table. rotation: Quat::from_euler(EulerRot::XYZ, -1.571, 0., 0.), ..Default::default() }, global_transform: GlobalTransform::default(), visibility: Visibility::default(), computed_visibility: ComputedVisibility::default(), collider: Collider::cuboid( VisualCard::ASPECT_RATIO / 2., VisualCard::ASPECT_RATIO, 0.01, ), rigid_body: RigidBody::Dynamic, } } } #[derive(Resource)] pub struct VisualCardData { font_normal: Handle, font_medium: Handle, font_bold: Handle, mesh: Handle, card_background: Handle, } impl FromWorld for VisualCardData { fn from_world(world: &mut World) -> Self { let world = world.cell(); let mut meshes = world.resource_mut::>(); let mut materials = world.resource_mut::>(); let asset_server = world.resource::(); let card_background_material = StandardMaterial { unlit: true, alpha_mode: AlphaMode::Blend, base_color_texture: Some(asset_server.load("card_background.png")), ..Default::default() }; Self { font_normal: asset_server.load("fonts/FiraMono-Regular.ttf#mesh"), font_medium: asset_server.load("fonts/FiraMono-Medium.ttf#mesh"), font_bold: asset_server.load("fonts/FiraMono-Bold.ttf#mesh"), mesh: meshes.add( shape::Quad { size: Vec2::new(VisualCard::ASPECT_RATIO / 2., VisualCard::ASPECT_RATIO), ..Default::default() } .into(), ), card_background: materials.add(card_background_material), } } } fn on_spawn_card( mut commands: Commands, card_data: Res, new_cards: Query<(Entity, &VisualCard), Added>, ) { for (entity, card) in &new_cards { commands.entity(entity).insert( ( PickableBundle::default(), RapierPickTarget::default(), OnPointer::::target_component_mut::(|_over, transform| { transform.translation.y += 0.2; }), OnPointer::::target_component_mut::(|_out, transform| { transform.translation.y -= 0.2; }), OnPointer::::target_insert(ClickedCard), ) ); commands.entity(entity).with_children(|parent| { parent.spawn(( PbrBundle { material: card_data.card_background.clone(), mesh: card_data.mesh.clone(), transform: Transform { scale: Vec3::new(2., 2., 1.), ..Default::default() }, ..Default::default() }, )); // card name parent.spawn(TextMeshBundle { text_mesh: TextMesh { text: card.card.name.clone(), style: TextMeshStyle { font: card_data.font_medium.clone(), font_size: SizeUnit::NonStandard(5.), color: Color::rgb(0.2, 0.2, 0.2), ..Default::default() }, ..Default::default() }, transform: Transform::from_xyz(-0.3, 0.2, 0.), ..Default::default() }); // card cost parent.spawn(TextMeshBundle { text_mesh: TextMesh { text: card.card.cost.to_string(), style: TextMeshStyle { font: card_data.font_bold.clone(), font_size: SizeUnit::NonStandard(7.), color: Color::rgb(1., 1., 1.), ..Default::default() }, ..Default::default() }, transform: Transform::from_xyz(0.2, -0.575, 0.), ..Default::default() }); }); } }