use std::array;
use std::cmp::Ordering;
use std::time::Duration;
use cushy::figures::units::Px;
use cushy::figures::FloatConversion;
use cushy::figures::{Point, Rect, Size};
use cushy::kludgine::app::winit::keyboard::Key;
use cushy::kludgine::app::winit::keyboard::NamedKey;
use cushy::kludgine::drawing::Renderer;
use cushy::kludgine::shapes::Shape;
use cushy::kludgine::sprite::{Sprite, SpriteSource};
use cushy::kludgine::tilemap::{
DebugGrid, Object, ObjectLayer, TileArray, TileKind, TileMapFocus, TILE_SIZE,
};
use cushy::kludgine::Color;
use cushy::kludgine::{include_aseprite_sprite, DrawableExt};
use cushy::value::{Destination, Dynamic};
use cushy::widgets::TileMap;
use cushy::{Run, Tick};
const PLAYER_SIZE: Px = Px::new(16);
fn main() -> cushy::Result {
let mut characters = ObjectLayer::new();
let mut sprite = include_aseprite_sprite!("assets/stickguy").unwrap();
sprite.set_current_tag(Some("Idle")).unwrap();
let myself = characters.push(Player {
sprite,
current_frame: None,
hovered: false,
position: Point::new(TILE_SIZE.into_float(), TILE_SIZE.into_float()),
});
let sprite = include_aseprite_sprite!("assets/grass").unwrap();
let layers = Dynamic::new((
TileArray::new(
8,
array::from_fn::<_, 64, _>(|_| TileKind::Sprite(sprite.clone())),
),
characters,
DebugGrid,
));
let tilemap = TileMap::dynamic(layers.clone())
.focus_on(TileMapFocus::Object {
layer: 1,
id: myself,
})
.tick(Tick::times_per_second(60, move |elapsed, input| {
let mut direction = Point::new(0., 0.);
if input.keys.contains(&Key::Named(NamedKey::ArrowDown)) {
direction.y += 1.0;
}
if input.keys.contains(&Key::Named(NamedKey::ArrowUp)) {
direction.y -= 1.0;
}
if input.keys.contains(&Key::Named(NamedKey::ArrowRight)) {
direction.x += 1.0;
}
if input.keys.contains(&Key::Named(NamedKey::ArrowLeft)) {
direction.x -= 1.0;
}
let one_second_movement = direction * TILE_SIZE.into_float();
let cursor_pos = input.mouse.as_ref().map(|mouse| mouse.position);
layers.map_mut(|mut layers| {
let player = &mut layers.1[myself];
let animation_tag = match direction.x.total_cmp(&0.) {
Ordering::Less => "WalkLeft",
Ordering::Equal => "Idle",
Ordering::Greater => "WalkRight",
};
player
.sprite
.set_current_tag(Some(animation_tag))
.expect("valid tag");
player.current_frame =
Some(player.sprite.get_frame(Some(elapsed)).expect("valid tag"));
player.position += one_second_movement * elapsed.as_secs_f32();
let rect = Rect::new(player.position - Size::squared(8.), Size::squared(16.));
layers.1[myself].hovered =
cursor_pos.map_or(false, |cursor_pos| rect.cast().contains(cursor_pos));
});
}));
tilemap.run()
}
#[derive(Debug)]
struct Player {
sprite: Sprite,
current_frame: Option<SpriteSource>,
hovered: bool,
position: Point<f32>,
}
impl Object for Player {
fn position(&self) -> Point<Px> {
self.position.cast()
}
fn render(
&self,
center: Point<Px>,
zoom: f32,
context: &mut Renderer<'_, '_>,
) -> Option<Duration> {
let zoomed_size = PLAYER_SIZE * zoom;
if self.hovered {
context.draw_shape(
Shape::filled_rect(
Rect::new(Point::squared(-zoomed_size / 2), Size::squared(zoomed_size)),
Color::new(255, 255, 255, 80),
)
.translate_by(center),
);
}
if let Some(frame) = &self.current_frame {
context.draw_texture(
frame,
Rect::new(center - zoomed_size / 2, Size::squared(zoomed_size)),
1.,
);
}
self.sprite.remaining_frame_duration().ok().flatten()
}
}