库存
最后更新于
Item_Definition_Desc :: struct {
id: string;
name: string;
icon: Texture_Asset;
stack_size: s64; // 1 = 不可堆叠,-1 = 无限
tier: Item_Tier;
}
Items :: struct {
// 物品栏
create_inventory :: proc(unique_id: string, capacity: s64) -> Inventory;
destroy_inventory :: proc(inventory: Inventory) -> bool;
set_capacity :: proc(inventory: Inventory, capacity: s64);
// 物品定义 + 实例
register_item_definition :: proc(desc: Item_Definition_Desc, $Definition_Type: typeid = Item_Definition, instance_type: typeid = Item_Instance) -> Definition_Type;
create_item_instance :: proc(definition: Item_Definition, count: s64 = 1) -> Item_Instance;
create_item_instance :: proc(definition: Item_Definition, $T: typeid, count: s64 = 1) -> T;
destroy_item_instance :: proc(instance: Item_Instance, count: s64 = -1);
// 移动物品
can_move_item_to_inventory :: proc(instance: Item_Instance, inventory: Inventory, will_destroy_item: ref bool) -> bool;
move_item_to_inventory :: proc(instance: Item_Instance, inventory: Inventory);
move_as_many_items_as_possible_to_inventory :: proc(instance: Item_Instance, inventory: Inventory, destroyed_item: ref bool) -> s64;
remove_item_from_inventory :: proc(instance: Item_Instance, inventory: Inventory);
can_move_all_items :: proc(entries: []Item_Transaction_Entry) -> bool;
move_all_items :: proc(entries: []Item_Transaction_Entry);
can_swap_items :: proc(inventory_a: Inventory, inventory_b: Inventory, slot_a: s64, slot_b: s64) -> bool;
swap_items :: proc(inventory_a: Inventory, inventory_b: Inventory, slot_a: s64, slot_b: s64);
// 查询
calculate_room_in_inventory_for_item :: proc(definition: Item_Definition, inventory: Inventory) -> s64;
destroy_all_items :: proc(inventory: Inventory);
// UI(可选)
draw_inventory :: proc(rect: Rect, inventory: Inventory, options: Inventory_Draw_Options) -> bool;
draw_hotbar :: proc(player: Player, inventory: Inventory, options: Inventory_Draw_Options) -> Draw_Hotbar_Result;
}
Inventory :: class {
get_item :: proc(inventory: Inventory, index: s64) -> Item_Instance;
has_item_id :: proc(inventory: Inventory, item_id: string) -> bool;
capacity: s64 #read_only;
}
Item_Definition :: class {
get_icon :: method() -> Texture_Asset;
id: string #read_only;
name: string #read_only;
type: typeid #read_only;
instance_type: typeid #read_only;
tier: Item_Tier #read_only;
}
Item_Instance :: class {
quantity: s64 #read_only; // 堆叠数量
slot_index: s64 #read_only; // 父物品栏中的槽位
inventory: Inventory #read_only; // 父物品栏(如果不在任何物品栏中则为 null)
get_definition :: method() -> Item_Definition;
}
Item_Transaction_Entry :: struct {
instance: Item_Instance;
inventory: Inventory;
}
Inventory_Draw_Options :: struct {
title: string;
show_exit_button: bool;
show_scroll_bar: bool;
show_background: bool;
allow_drag_drop: bool;
drag_drop_color_multiplier: v4;
hotbar_item_count: s32;
columns: s32;
rows: s32;
force_select_hotbar_index: s32;
hide_bag_button: bool;
enable_selection: bool;
scroll_item_selection: bool;
keyboard_item_selection: bool;
enable_use_from_hotbar: bool;
on_before_draw: (proc(item: Item_Instance, rect: Rect));
on_after_draw: (proc(item: Item_Instance, rect: Rect));
default :: proc() -> Inventory_Draw_Options;
}
Draw_Hotbar_Result :: struct {
selected_item: Item_Instance;
selected_item_index: s64;
dropped_item: Item_Instance;
entire_rect: Rect;
inventory_open: bool;
inventory_open_t: float;
}// 可选:自定义物品类型
Weapon_Definition :: class : Item_Definition {
damage: s64;
}
Weapon_Item :: class : Item_Instance {
durability: s64 @ao_serialize; // @ao_serialize 会让该字段在不同会话之间自动保存
}
sword_defn: Weapon_Definition;
ao_before_scene_load :: proc() {
sword_defn = Items.register_item_definition(
{id="sword", name="Iron Sword", icon=get_asset(Texture_Asset, "icons/sword.png"), stack_size=1, tier=.COMMON},
Weapon_Definition,
Weapon_Item
);
sword_defn.damage = 10;
}
give_sword :: proc(player: Player) {
item := Items.create_item_instance(sword_defn, Weapon_Item);
will_destroy: bool;
if Items.can_move_item_to_inventory(item, player.default_inventory, ref will_destroy) {
item.durability = 100;
Items.move_item_to_inventory(item, player.default_inventory);
// 如果 will_destroy 为 true,则该物品已被吸收到现有堆叠中
// 移动后不应再使用这个物品引用。
}
else {
// 物品栏已满 → 销毁我们创建的实例
Items.destroy_item_instance(item);
}
}Player :: class : Player_Base {
ao_late_update :: method(dt: float) {
if this.is_local_or_server() {
draw_player_hotbar(this);
}
}
}
draw_player_hotbar :: proc(player: Player) {
options := Inventory_Draw_Options.default();
options.hide_bag_button = false;
result := Items.draw_hotbar(player, player.default_inventory, options);
// result.selected_item 是当前高亮的物品(或 null)
// result.inventory_open 告诉你完整背包 UI 是否正在显示
}give_sword_if_needed :: proc(player: Player) {
if player.default_inventory.has_item_id("sword") return;
give_sword(player);
}room := Items.calculate_room_in_inventory_for_item(sword_defn, player.default_inventory);
if room > 0 {
give_sword(player);
}chest_inventory := Items.create_inventory("chest_01", 12);for i: 0..<chest_inventory.capacity {
item := chest_inventory.get_item(i);
if item == null continue;
defn := item.get_definition();
log_info("Slot %: %", {i, defn.name});
}moves: [..]Item_Transaction_Entry;
moves.append({instance = sword, inventory = player.default_inventory});
moves.append({instance = shield, inventory = player.default_inventory});
if Items.can_move_all_items(moves) {
Items.move_all_items(moves);
}import "core:dropped_items"item := Items.create_item_instance(sword_defn, Weapon_Item);
dropped := Dropped_Item.spawn(player.entity.world_position, item);gameplay_rng: u64;
dropped.do_spawn_animation(ref gameplay_rng, navmesh); // navmesh 可选result := Items.draw_hotbar(player, player.default_inventory, Inventory_Draw_Options.default());
dropped: Dropped_Item;
if Dropped_Item.handle_dropped_item(result, player.entity.world_position, ref dropped) {
dropped.do_spawn_animation(ref gameplay_rng, navmesh);
}