player selection preview; patreon animations
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 1 Mar 2022 02:30:34 +0000 (20:30 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 1 Mar 2022 02:30:34 +0000 (20:30 -0600)
run_tree/assets/images/spritesheet.png [new file with mode: 0644]
run_tree/scenes/default.items
run_tree/scenes/quick_save_new.scene
src/entity/components/dispenser.onyx
src/entity/components/patreon.onyx
src/entity/components/player.onyx
src/entity/editor.onyx
src/entity/schematics/patreon.onyx
src/entity/schematics/tap.onyx
src/game.onyx
src/utils/vecmath.onyx

diff --git a/run_tree/assets/images/spritesheet.png b/run_tree/assets/images/spritesheet.png
new file mode 100644 (file)
index 0000000..9ed43d4
Binary files /dev/null and b/run_tree/assets/images/spritesheet.png differ
index d0ee5eeefbfe830f5e0a95acc3ab4a3a9210dd07..461847a8701a98518db713881a2029648ba054f1 100644 (file)
@@ -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
 
index e67ba6bf401bf0f02bd520324451a2c505065280..188450325de7a6e76f9ff30baf32c37d24f4ce06 100644 (file)
@@ -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"
-
index 748f6d80591451ce20f285c1eb3fa63c9384791c..22c0e3c613de1e8e27770e2efba18bb806a6b435 100644 (file)
@@ -45,6 +45,7 @@ DispenserComponent :: struct {
             }
 
             // This should dynamic...
+            item.pos = this.pos;
             item.size = .{16, 16};
             (item->get(ItemComponent)).item = dispenser_comp.item;
 
index bf2008877093bc5eee5264b34a569d5f1aa53cb5..4f35f829d6c2c0b38c328074413a8a32b7945f0e 100644 (file)
@@ -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);
 
index ea08206d09e2fbacdc98b384e4b583ff4caa8011..3b62e949301a4fecc9ce8edbcbca605b89ded9ed 100644 (file)
@@ -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);
+        }
     }
 }
index ffe68cbb3a2581adbc82dd3dcc7fc98fb37327dc..753bb8c6d783e94132058bab3396947f33e70f7a 100644 (file)
@@ -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;
index 617595214b594bef77a04344f459bd370a4b257c..b83056f6b17c247958026b0a5b837887e7e55f20 100644 (file)
@@ -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);
     }
 }
 
index 9c5f965e3ee8facf4aebccbda36e12fb017be98c..4c00be0b82e789261240d5ab86c867287a51d20a 100644 (file)
@@ -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);
     }
 }
 
index 7eeeacf3e1aa795fa923cd8f4402088daaf1ed70..242854db10a71d066362e836ba20117cb26b6b37 100644 (file)
@@ -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();
 
index 3bda373ca7ad5541190e1528c84bc41586a248ad..1ba7aa80c67b9b1a1478c44b5fda73721e5efe30 100644 (file)
@@ -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;