From 658678ffa7f631205b31ae518bdadb30ebd5a794 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 28 Feb 2022 20:30:34 -0600 Subject: [PATCH] player selection preview; patreon animations --- run_tree/assets/images/spritesheet.png | Bin 0 -> 3155 bytes run_tree/scenes/default.items | 2 +- run_tree/scenes/quick_save_new.scene | 25 ++----- src/entity/components/dispenser.onyx | 1 + src/entity/components/patreon.onyx | 37 +++++++++-- src/entity/components/player.onyx | 87 +++++++++++++++++-------- src/entity/editor.onyx | 26 ++++++-- src/entity/schematics/patreon.onyx | 2 +- src/entity/schematics/tap.onyx | 7 +- src/game.onyx | 5 +- src/utils/vecmath.onyx | 11 +++- 11 files changed, 138 insertions(+), 65 deletions(-) create mode 100644 run_tree/assets/images/spritesheet.png diff --git a/run_tree/assets/images/spritesheet.png b/run_tree/assets/images/spritesheet.png new file mode 100644 index 0000000000000000000000000000000000000000..9ed43d4b3842502ca8cc177715dad9fdeac2662f GIT binary patch literal 3155 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 L=Y)P?<8$>tCtJ%3 literal 0 HcmV?d00001 diff --git a/run_tree/scenes/default.items b/run_tree/scenes/default.items index d0ee5ee..461847a 100644 --- a/run_tree/scenes/default.items +++ b/run_tree/scenes/default.items @@ -1,6 +1,6 @@ :beer name="Beer" -texture_path="./assets/images/beer-1.png" +texture_path="./assets/images/spritesheet.png" texture_pos = 0 0 texture_size = 16 16 diff --git a/run_tree/scenes/quick_save_new.scene b/run_tree/scenes/quick_save_new.scene index e67ba6b..1884503 100644 --- a/run_tree/scenes/quick_save_new.scene +++ b/run_tree/scenes/quick_save_new.scene @@ -29,7 +29,7 @@ color.a = 1.0000 [Player] id = 12 flags = 2 -pos.x = 379.7975 +pos.x = 379.7973 pos.y = 175.1558 size.x = 32.0000 size.y = 32.0000 @@ -122,8 +122,8 @@ max_timeout = 2.0000 [Patreon] id = 22 flags = 3 -pos.x = 385.0000 -pos.y = 248.0000 +pos.x = 388.6049 +pos.y = 284.5303 size.x = 32.0000 size.y = 32.0000 :RenderComponent @@ -134,7 +134,10 @@ color.b = 0.0000 color.a = 1.0000 :PatreonComponent state = 0 +seat_location.x = 400.0000 +seat_location.y = 400.0000 order_item = "beer" +order_show_animation = 0.0000 holding = 0 consume_timeout = 0.0000 @@ -211,19 +214,3 @@ color.a = 1.0000 item = "beer" max_timeout = 2.0000 -[Item_Entity] -id = 21 -flags = 4 -pos.x = 187.7317 -pos.y = 106.9191 -size.x = 16.0000 -size.y = 16.0000 -:RenderComponent -layer = 10 -color.r = 1.0000 -color.g = 1.0000 -color.b = 1.0000 -color.a = 1.0000 -:ItemComponent -item = "beer" - diff --git a/src/entity/components/dispenser.onyx b/src/entity/components/dispenser.onyx index 748f6d8..22c0e3c 100644 --- a/src/entity/components/dispenser.onyx +++ b/src/entity/components/dispenser.onyx @@ -45,6 +45,7 @@ DispenserComponent :: struct { } // This should dynamic... + item.pos = this.pos; item.size = .{16, 16}; (item->get(ItemComponent)).item = dispenser_comp.item; diff --git a/src/entity/components/patreon.onyx b/src/entity/components/patreon.onyx index bf20088..4f35f82 100644 --- a/src/entity/components/patreon.onyx +++ b/src/entity/components/patreon.onyx @@ -2,6 +2,7 @@ use package core #local Patreon_State :: enum { + Walking_To_Seat; Waiting_To_Place_Order; Waiting_For_Order; Consuming_Order; @@ -12,12 +13,15 @@ PatreonComponent :: struct { use component: Component; state := Patreon_State.Waiting_To_Place_Order; + seat_location: Vector2; order_item: str; + order_show_animation: f32; holding: Entity_ID; consume_timeout: f32; init :: (use this: ^PatreonComponent) { order_item = "beer"; + seat_location = .{ 400, 400 }; } added :: (use this: ^PatreonComponent, entity: ^Entity) { @@ -29,6 +33,16 @@ PatreonComponent :: struct { } update :: (use this: ^PatreonComponent, entity: ^Entity, dt: f32) { + if state == .Walking_To_Seat { + delta := Vector2.norm(seat_location - entity.pos) * 100; + entity.pos += delta * dt; + + if Vector2.square_mag(seat_location - entity.pos) < 16 { + entity.pos = seat_location; + state = .Waiting_To_Place_Order; + } + } + if consume_timeout > 0 && state == .Consuming_Order { consume_timeout -= dt; if consume_timeout < 0 { @@ -39,10 +53,17 @@ PatreonComponent :: struct { } } + if state == .Waiting_For_Order { + if order_show_animation > 0 { + order_show_animation *= 0.75; + } + } + if holding != Entity_Nothing { holding_object := scene->get(holding); r := Entity.get_rect(holding_object); - holding_object.pos = entity.pos + .{-10, 0}; + target_pos := entity.pos + .{-10, 0}; + holding_object.pos += (target_pos - holding_object.pos) * 0.25; } } @@ -53,6 +74,7 @@ PatreonComponent :: struct { case .Waiting_To_Place_Order { if interactor->has(PlayerComponent) { patreon.state = .Waiting_For_Order; + patreon.order_show_animation = 1.0f; } } @@ -74,10 +96,17 @@ PatreonComponent :: struct { } post_render :: (use this: ^PatreonComponent, entity: ^Entity) { - if state == .Waiting_For_Order { - r := entity->get_rect(); + r := entity->get_rect(); - r = Rect.{ r.x + (r.w - 24) / 2, r.y - r.h / 2 - 16, 24, 24 }; + r = Rect.{ r.x + (r.w - 24) / 2, r.y - r.h / 2 - 16, 24, 24 }; + r.y += 24 * order_show_animation; + + if state == .Waiting_To_Place_Order { + immediate_set_color(.{1, 1, 1}); + immediate_subimage(^Spritesheet, r.x + 4, r.y + 4, 16, 16, 1*16, 4*16, 16, 16); + } + + if state == .Waiting_For_Order { immediate_set_color(.{0, 0, 0}); immediate_rectangle(r.x, r.y, r.w, r.h); diff --git a/src/entity/components/player.onyx b/src/entity/components/player.onyx index ea08206..3b62e94 100644 --- a/src/entity/components/player.onyx +++ b/src/entity/components/player.onyx @@ -7,24 +7,55 @@ PlayerComponent :: struct { holding : Entity_ID; + #tag Editor_Hidden, Entity_Store.Skip + nearby_holding, nearby_interact : Entity_ID; + update :: (player: ^PlayerComponent, use this: ^Entity, dt: f32) { // Highlight the object that you are going to interact with + { + player.nearby_interact = Entity_Nothing; + area := Rect.{pos.x - size.x, pos.y - size.y, size.x * 2, size.y * 2}; + objects := scene->query_by_component(area, InteractableComponent); + defer memory.free_slice(^objects); - movement := this->get(MovementComponent); + dist := size.x * size.x + size.y * size.y; - // Try to interact with nearby objects - // - if is_key_just_up(movement.controls.interact) { + for objects { + d := Vector2.square_mag(pos - it.pos); + if d < dist { + player.nearby_interact = it.id; + dist = d; + } + } + } + + { + player.nearby_holding = Entity_Nothing; area := Rect.{pos.x - size.x, pos.y - size.y, size.x * 2, size.y * 2}; - objects := scene->query_by_component(area, InteractableComponent); + objects := scene->query_by_flags(area, .Carryable); defer memory.free_slice(^objects); + dist := size.x * size.x + size.y * size.y; + for objects { - interact_comp := it->get(InteractableComponent); - interact_comp.interact(it, this); + d := Vector2.square_mag(pos - it.pos); + if d < dist { + player.nearby_holding = it.id; + dist = d; + } } } + movement := this->get(MovementComponent); + + // Try to interact with nearby objects + // + if is_key_just_up(movement.controls.interact) && player.nearby_interact != Entity_Nothing { + it := scene->get(player.nearby_interact); + interact_comp := it->get(InteractableComponent); + interact_comp.interact(it, this); + } + // // Try to pick up nearby objects // @@ -38,23 +69,10 @@ PlayerComponent :: struct { holding_object.pos = pos + facing_to_direction_vector(movement.facing) * d; player.holding = Entity_Nothing; - } else { - area := Rect.{pos.x - size.x, pos.y - size.y, size.x * 2, size.y * 2}; - objects := scene->query_by_flags(area, .Carryable); - defer memory.free_slice(^objects); - - // This should first sort by the distance to the object - while i := 0; i < objects.count { - defer i += 1; - if objects[i] == this do continue; - - target_object := objects[i]; - target_object.flags ^= .Carryable; // This only works because we assume that it is Carryable, otherwise this would make it carryable. - player.holding = target_object.id; - break; - } - - // Should this fire an event on the target object? + } elseif player.nearby_holding != Entity_Nothing { + target_object := scene->get(player.nearby_holding); + target_object.flags ^= .Carryable; // This only works because we assume that it is Carryable, otherwise this would make it carryable. + player.holding = target_object.id; } } @@ -65,12 +83,29 @@ PlayerComponent :: struct { if player.holding != Entity_Nothing { holding_object := scene->get(player.holding); r := Entity.get_rect(holding_object); - holding_object.pos = pos - .{0, (size.y + r.h) / 2}; + target_pos := pos - .{0, (size.y + r.h) / 2}; + holding_object.pos += (target_pos - holding_object.pos) * 0.25; } } render :: (use this: ^Entity) { rect := Entity.get_rect(this); - immediate_image(^Player.assets.texture, rect.x, rect.y, rect.w, rect.h); + immediate_subimage(^Spritesheet, rect.x, rect.y, rect.w, rect.h, 0*16, 4*16, 16, 16); + } + + post_render :: (use this: ^PlayerComponent, entity: ^Entity) { + if nearby_interact != Entity_Nothing { + it := scene->get(nearby_interact); + r := it->get_rect(); + immediate_set_color(.{.2, .2, .8, .7}); + immediate_rectangle(r.x, r.y, r.w, r.h); + } + + if nearby_holding != Entity_Nothing && holding == Entity_Nothing { + it := scene->get(nearby_holding); + r := it->get_rect(); + immediate_set_color(.{.2, .8, .2, .7}); + immediate_rectangle(r.x, r.y, r.w, r.h); + } } } diff --git a/src/entity/editor.onyx b/src/entity/editor.onyx index ffe68cb..753bb8c 100644 --- a/src/entity/editor.onyx +++ b/src/entity/editor.onyx @@ -220,6 +220,8 @@ editor_draw :: () { if selected_entity_id != Entity_Nothing { selected_entity := scene->get(selected_entity_id); render_entity_fields(selected_entity, x, y, w, h); + } else { + render_entity_list(x, y, w, h); } } } @@ -255,6 +257,17 @@ editor_draw :: () { draw_checkbox(.{x, y + 150, w, 36.0f}, ^dumb, "Testing checkboxes"); } +#local render_entity_list :: (x, y, w, h: f32) { + buf: [256] u8; + for scene.entities { + msg := conv.format(buf, "{} ({})", it.schematic, cast(u32) it.id); + if draw_button(.{ x, y, w, 32 }, msg, increment=~~it) { + selected_entity_id = it.id; + } + y += 32; + } +} + #local render_entity_fields :: (entity: ^Entity, x, y, w, h: f32) { assert(entity != null, "entity is null"); @@ -277,12 +290,15 @@ editor_draw :: () { y += 32; for^ entry: entity.components.entries { + immediate_set_color(.{0, 0, 0}); + immediate_rectangle(x, y, w, 4); + y += 16; info = ~~ type_info.get_type_info(entry.key); - font_print(editor_font, x + 2, y + 24, info.name); + font_print(editor_font, x + 2, y + 20, info.name); y, i = render_struct_fields(any.{~~entry.value, entry.key}, i, x, y, w, h); - y += 16; + y += 32; } } @@ -327,7 +343,7 @@ editor_draw :: () { immediate_rectangle(x, y + 2, w, Field_Height + 2); } - font_print(editor_font, x + 2, y + Field_Height, it.name); + font_print(editor_font, x + 2, y + Field_Height - 2, it.name); #persist depth_colors := Color.[ Color.{0.4, 0.2, 0.2}, @@ -345,7 +361,7 @@ editor_draw :: () { } else { value_buf: [1024] u8; value_str := conv.format_va(value_buf, "{}", .[member_any]); - font_print(editor_font, x + w - font_get_width(editor_font, value_str) - 2, y + Field_Height, value_str); + font_print(editor_font, x + w - font_get_width(editor_font, value_str) - 2, y + Field_Height - 2, value_str); } } @@ -420,7 +436,7 @@ editor_draw :: () { } #local { - background_color :: Color.{0.5, 0.5, 0.5, 1}; + background_color :: Color.{0.15, 0.15, 0.15, 1}; editor_font: Font; editor_big_font: Font; diff --git a/src/entity/schematics/patreon.onyx b/src/entity/schematics/patreon.onyx index 6175952..b83056f 100644 --- a/src/entity/schematics/patreon.onyx +++ b/src/entity/schematics/patreon.onyx @@ -24,7 +24,7 @@ Patreon :: struct { render :: (use this: ^Entity) { r := this->get_rect(); - immediate_image(^Player.assets.texture, r.x, r.y, r.w, r.h); + immediate_subimage(^Spritesheet, r.x, r.y, r.w, r.h, 0*16, 4*16, 16, 16); } } diff --git a/src/entity/schematics/tap.onyx b/src/entity/schematics/tap.onyx index 9c5f965..4c00be0 100644 --- a/src/entity/schematics/tap.onyx +++ b/src/entity/schematics/tap.onyx @@ -25,12 +25,7 @@ Tap :: struct { render :: (use this: ^Entity) { rect := this->get_rect(); - immediate_image(^Tap.assets.texture, rect.x, rect.y, rect.w, rect.h); - } - - #persist assets: struct { - #tag "./assets/images/keg.png" - texture: Texture; + immediate_subimage(^Spritesheet, rect.x, rect.y, rect.w, rect.h, 0*16, 2*16, 32, 32); } } diff --git a/src/game.onyx b/src/game.onyx index 7eeeacf..242854d 100644 --- a/src/game.onyx +++ b/src/game.onyx @@ -13,13 +13,14 @@ item_store: Item_Store; scene_render_offset: Vector2; scene_canvas: Canvas; +Spritesheet: Texture; + game_init :: () { scene_canvas = canvas_make(800, 600); // This process of queueing the asset bucket should // be made automatic somehow... - queue_assets(^Player.assets); - queue_assets(^Tap.assets); + Spritesheet', _ := texture_lookup(#cstr "./assets/images/spritesheet.png"); load_assets(); diff --git a/src/utils/vecmath.onyx b/src/utils/vecmath.onyx index 3bda373..1ba7aa8 100644 --- a/src/utils/vecmath.onyx +++ b/src/utils/vecmath.onyx @@ -2,6 +2,15 @@ Vector2 :: struct { x, y: f32; mag :: macro (v: Vector2) => math.sqrt(v.x * v.x + v.y * v.y); + + square_mag :: macro (v: Vector2) => v.x * v.x + v.y * v.y; + + norm :: macro (v: Vector2) -> Vector2 { + l := math.sqrt(v.x * v.x + v.y * v.y); + return .{ v.x / l, v.y / l }; + } + + Zero :: Vector2.{0, 0} #struct_tag conv.Custom_Format.{format_vector2} @@ -50,7 +59,7 @@ Vector3 :: struct { #operator + macro (v1, v2: Vector2) => (typeof v1).{ v1.x + v2.x, v1.y + v2.y }; #operator - macro (v1, v2: Vector2) => (typeof v1).{ v1.x - v2.x, v1.y - v2.y }; -#operator * macro (v: Vector2, s: f32) => (typeof v1).{ v.x * s, v.y * s }; +#operator * macro (v: Vector2, s: f32) => (typeof v ).{ v.x * s, v.y * s }; #operator * macro (v1, v2: Vector2) => (typeof v1).{ v1.x * v2.x, v1.y * v2.y }; #operator == macro (v1, v2: Vector2) => v1.x == v2.x && v1.y == v2.y; -- 2.25.1