Tilemap updates

This commit is contained in:
Jonathan Johnson 2023-12-09 08:20:18 -08:00
parent 16af20269e
commit 95555ce928
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
12 changed files with 258 additions and 54 deletions

27
Cargo.lock generated
View file

@ -623,7 +623,7 @@ dependencies = [
[[package]]
name = "figures"
version = "0.1.0"
source = "git+https://github.com/khonsulabs/figures#1809e94c19e56aaf9df36d7553ffa9e65523369d"
source = "git+https://github.com/khonsulabs/figures#312f390a33025c902e94124cfab10c3dafdfb5f1"
dependencies = [
"bytemuck",
"euclid",
@ -968,9 +968,9 @@ dependencies = [
[[package]]
name = "intentional"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "509e910bdc87b3c71b1085ae9659c11ea74f9667f1e15b54a6fe68a307600560"
checksum = "bbc48117ac1523428c576e39831e93043112e2d2be0223bb0c0593af944e4e38"
[[package]]
name = "interner"
@ -1030,6 +1030,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "justjson"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7e253b574775d0ebd7975c471fc18f72f0775a4d42b563b5fbc3c4068aa1075"
[[package]]
name = "kempt"
version = "0.2.2"
@ -1056,7 +1062,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "kludgine"
version = "0.1.0"
source = "git+https://github.com/khonsulabs/kludgine#abb5625c3557c3c3b22e088fe1523b1544e7ddb7"
source = "git+https://github.com/khonsulabs/kludgine#924198daa5fc9fe758efd7c56084f8a05ef783d1"
dependencies = [
"ahash",
"alot",
@ -1067,6 +1073,7 @@ dependencies = [
"figures",
"image",
"intentional",
"justjson",
"lyon_tessellation",
"pollster",
"smallvec",
@ -1935,9 +1942,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.26"
version = "0.38.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
checksum = "bfeae074e687625746172d639330f1de242a178bf3189b51e35a7a21573513ac"
dependencies = [
"bitflags 2.4.1",
"errno",
@ -3127,18 +3134,18 @@ checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
[[package]]
name = "zerocopy"
version = "0.7.29"
version = "0.7.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d075cf85bbb114e933343e087b92f2146bac0d55b534cbb8188becf0039948e"
checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.29"
version = "0.7.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86cd5ca076997b97ef09d3ad65efe811fa68c9e874cb636ccb211223a813b0c2"
checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba"
dependencies = [
"proc-macro2",
"quote",

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

View file

@ -0,0 +1,45 @@
{ "frames": {
"Swaying_0.aseprite": {
"frame": { "x": 0, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 300
},
"Swaying_1.aseprite": {
"frame": { "x": 32, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 500
},
"Still_2.aseprite": {
"frame": { "x": 64, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 500
}
},
"meta": {
"app": "http://www.aseprite.org/",
"version": "1.2.17",
"image": "grass.png",
"format": "RGBA8888",
"size": { "w": 96, "h": 32 },
"scale": "1",
"frameTags": [
{ "name": "Swaying", "from": 0, "to": 1, "direction": "forward" },
{ "name": "Still", "from": 2, "to": 2, "direction": "forward" }
],
"layers": [
{ "name": "Layer 1", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 2", "opacity": 255, "blendMode": "normal" }
],
"slices": [
]
}
}

BIN
examples/assets/grass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
examples/assets/k.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

View file

@ -0,0 +1,99 @@
{
"frames": {
"Idle_0.aseprite": {
"frame": { "x": 0, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 500
},
"Idle_1.aseprite": {
"frame": { "x": 32, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 500
},
"Idle_2.aseprite": {
"frame": { "x": 64, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 500
},
"Idle_3.aseprite": {
"frame": { "x": 96, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 500
},
"WalkRight_4.aseprite": {
"frame": { "x": 128, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 200
},
"WalkRight_5.aseprite": {
"frame": { "x": 160, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 200
},
"WalkRight_6.aseprite": {
"frame": { "x": 192, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 200
},
"WalkLeft_7.aseprite": {
"frame": { "x": 224, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 200
},
"WalkLeft_8.aseprite": {
"frame": { "x": 256, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 200
},
"WalkLeft_9.aseprite": {
"frame": { "x": 288, "y": 0, "w": 32, "h": 32 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
"sourceSize": { "w": 32, "h": 32 },
"duration": 200
}
},
"meta": {
"app": "http://www.aseprite.org/",
"version": "1.2.17",
"image": "stickguy.png",
"format": "RGBA8888",
"size": { "w": 320, "h": 32 },
"scale": "1",
"frameTags": [
{ "name": "Idle", "from": 0, "to": 3, "direction": "forward" },
{ "name": "WalkRight", "from": 4, "to": 6, "direction": "pingpong" },
{ "name": "WalkLeft", "from": 7, "to": 9, "direction": "pingpong" }
],
"layers": [{ "name": "Flattened", "opacity": 255, "blendMode": "normal" }],
"slices": []
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

View file

@ -1,3 +1,7 @@
use std::array;
use std::cmp::Ordering;
use std::time::Duration;
use gooey::kludgine::app::winit::keyboard::Key;
use gooey::kludgine::figures::units::Px;
use gooey::kludgine::figures::{Point, Rect, Size};
@ -6,42 +10,38 @@ use gooey::kludgine::shapes::Shape;
use gooey::kludgine::tilemap::{Object, ObjectLayer, TileKind, TileMapFocus, Tiles, TILE_SIZE};
use gooey::kludgine::Color;
use gooey::value::Dynamic;
use gooey::widget::MakeWidget;
use gooey::widgets::{Label, Stack, TileMap};
use gooey::widgets::TileMap;
use gooey::{Run, Tick};
use kludgine::app::winit::keyboard::NamedKey;
use kludgine::figures::FloatConversion;
use kludgine::DrawableExt;
use kludgine::sprite::{Sprite, SpriteSource};
use kludgine::{include_aseprite_sprite, DrawableExt};
const PLAYER_SIZE: Px = Px::new(16);
#[rustfmt::skip]
const TILES: [TileKind; 64] = {
const O: TileKind = TileKind::Color(Color::PURPLE);
const X: TileKind = TileKind::Color(Color::WHITE);
[
X, X, X, X, X, X, X, X,
X, O, O, O, O, O, O, X,
X, O, X, O, O, X, O, X,
X, O, O, O, O, O, O, X,
X, O, X, O, O, X, O, X,
X, O, O, X, X, O, O, X,
X, O, O, O, O, O, O, X,
X, X, X, X, X, X, X, X,
]
};
fn main() -> gooey::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 {
color: Color::RED,
sprite,
current_frame: None,
hovered: false,
position: Point::new(TILE_SIZE.into_float(), TILE_SIZE.into_float()),
});
let layers = Dynamic::new((Tiles::new(8, 8, TILES), characters));
let sprite = include_aseprite_sprite!("assets/grass").unwrap();
let debug_message = Dynamic::new(String::new());
let layers = Dynamic::new((
Tiles::new(
8,
8,
array::from_fn::<_, 64, _>(|_| TileKind::Sprite(sprite.clone())),
),
characters,
));
let tilemap = TileMap::dynamic(layers.clone())
.focus_on(TileMapFocus::Object {
@ -70,24 +70,37 @@ fn main() -> gooey::Result {
let cursor_pos = input.mouse.as_ref().map(|mouse| mouse.position);
layers.map_mut(|layers| {
let pos = &mut layers.1[myself].position;
*pos += one_second_movement.x * elapsed.as_secs_f32();
let player = &mut layers.1[myself];
let rect = Rect::new(*pos - Size::squared(8.), Size::squared(16.));
layers.1[myself].color =
match cursor_pos.map_or(false, |cursor_pos| rect.cast().contains(cursor_pos)) {
true => Color::RED,
false => Color::BLUE,
};
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));
});
}));
Stack::rows(tilemap.expand().and(Label::new(debug_message))).run()
tilemap.run()
}
#[derive(Debug)]
struct Player {
color: Color,
sprite: Sprite,
current_frame: Option<SpriteSource>,
hovered: bool,
position: Point<f32>,
}
@ -96,14 +109,30 @@ impl Object for Player {
self.position.cast()
}
fn render(&self, center: Point<Px>, zoom: f32, context: &mut Renderer<'_, '_>) {
fn render(
&self,
center: Point<Px>,
zoom: f32,
context: &mut Renderer<'_, '_>,
) -> Option<Duration> {
let zoomed_size = PLAYER_SIZE * zoom;
context.draw_shape(
Shape::filled_rect(
Rect::new(Point::squared(-zoomed_size / 2), Size::squared(zoomed_size)),
self.color,
)
.translate_by(center),
)
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)),
);
}
self.sprite.remaining_frame_duration().ok().flatten()
}
}

View file

@ -70,14 +70,37 @@ where
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
let focus = self.focus.get();
// TODO this needs to be updated to support being placed in side of a scroll view.
self.layers.map(|layers| {
tilemap::draw(layers, focus, self.zoom, context.gfx.inner_graphics());
});
let redraw_after = match &mut self.layers {
Value::Constant(layers) => tilemap::draw(
layers,
focus,
self.zoom,
context.elapsed(),
context.gfx.inner_graphics(),
),
Value::Dynamic(layers) => {
let mut layers = layers.lock();
layers.prevent_notifications();
tilemap::draw(
&mut *layers,
focus,
self.zoom,
context.elapsed(),
context.gfx.inner_graphics(),
)
}
};
context.draw_focus_ring();
if let Some(tick) = &self.tick {
// When we are driven by a tick, we ignore all other sources of
// refreshes.
tick.rendered(context);
} else {
if let Some(redraw_after) = redraw_after {
context.redraw_in(redraw_after);
}
self.focus.redraw_when_changed(context);
self.layers.redraw_when_changed(context);
}
@ -168,10 +191,11 @@ where
_location: Point<Px>,
_device_id: DeviceId,
button: kludgine::app::winit::event::MouseButton,
_context: &mut EventContext<'_, '_>,
context: &mut EventContext<'_, '_>,
) -> EventHandling {
if let Some(tick) = &self.tick {
tick.mouse_button(button, ElementState::Pressed);
context.focus();
HANDLED
} else {
IGNORED