返回首页

GameMaker 网格库存:代码和 JSON

使用 ds_grid 和 JSON 物品数据库在 GameMaker 中创建网格库存的指南。描述初始化、数据加载、使用 ref-坐标 的存储以及基本操作。适合中高级开发者。

GameMaker:类似 S.T.A.L.K.E.R. 的库存网格
Advertisement 728x90

## 在 GameMaker 中实现网格物品栏:逐步详解

基于网格的物品栏系统允许你在 ds_grid 中放置各种尺寸的物品,类似于 Deus Ex 或 S.T.A.L.K.E.R. 中的机制。要开始,首先创建一个带有精灵的玩家对象 oPlayer,以及一个没有默认精灵的容器对象 oContainer。准备物品精灵:spApple (32x32)、spWaterBottle (32x64)、spMysteriousPackage (64x64)、spItemError (32x32)。在房间 rTest 中,设置 Instances 和 UI 层,并添加 oPlayer 和 oContainer 的实例。

在起始房间 rInit 中创建一个持久化对象 oGameManager。在 Create 事件中:

global.inventoryDebugMode = true;
#macro InteractionDistance 100
global.ItemDB = {};
loadItemDefinitions();
room_goto(rTest);

这会初始化调试模式、交互距离常量以及物品数据库。

Google AdInline article slot

从 JSON 加载物品数据库

将文件 items.json 放入 datafiles 中。一件物品的结构包括 Name、Type、Width、Height、MaxStack、Sprite、Description。脚本 scItemDatabase 包含 loadItemDefinitions() 函数:

function loadItemDefinitions()
{
	var _filename = "items.json";
	if (!file_exists(_filename) && global.inventoryDebugMode)
	{
		show_debug_message("Fayl " + _filename + " not found!");
		return;
	}
	
	var _buffer = buffer_load(_filename);
	var _jsonString = buffer_read(_buffer, buffer_string);
	buffer_delete(_buffer);

	var _parsedData = json_parse(_jsonString);

	var _itemIDs = struct_get_names(_parsedData);

	for (var i = 0; i < array_length(_itemIDs); ++i)
	{
		var _id = _itemIDs[i];
		var _item = _parsedData[$ _id];

		if (variable_struct_exists(_item, "Sprite"))
		{
			_item.Sprite = asset_get_index(_item.Sprite);
            
			if (_item.Sprite == -1)
			{
				_item.Sprite = spItemError;
				if (global.inventoryDebugMode)
					show_debug_message("Withprayt not found for predmeta " + _id);
			}
		}

		global.ItemDB[$ _id] = _item;
	}
    
	if (global.inventoryDebugMode)
		show_debug_message("Baza predmetov zagruzhena. Count: " + string(array_length(_itemIDs)));
}

函数 getItemData(_itemID) 返回物品结构体或 undefined。

  • ds_struct 的优势:通过 [$ _id] 使用字符串键进行动态访问。
  • 错误处理:如果精灵缺失,则回退到 spItemError。
  • 访问器:对于 ds_grid 使用 [# i, j],对于 struct 使用 [$ key]。

网格中存储物品的基础知识

物品栏是一个 ds_grid,其中:

Google AdInline article slot
  • 物品的主要单元格存储一个结构体 {itemID, quantity}。
  • 辅助单元格存储 {refX, refY},包含主要单元格的坐标。
  • 空单元格为 noone。

物品会根据数据库中的 Width/Height 占用空间,并根据 MaxStack 支持堆叠。

脚本 scInventory 从基本函数开始:

创建和销毁物品栏

function inventoryCreate(_width, _height)
{
	var grid = ds_grid_create(_width, _height);
	ds_grid_clear(grid, noone);
	return grid;
}

function inventoryDestroy(_inventory)
{
	if (ds_exists(_inventory, ds_type_grid))
	{
		ds_grid_destroy(_inventory);
		return true;
	}
	else
	{
		return false;
	}
}

网格检查和操作函数

接下来,实现空闲检查:

Google AdInline article slot
  • inventoryIsEmpty(_inventory):扫描网格中是否存在 noone。

关键物品操作:

  • 添加:根据 Width/Height 寻找空闲空间,放置主要单元格并在其他位置填充引用。
  • 移动:检查重叠,更新 refX/refY。
  • 移除:清除主要单元格和引用单元格。

交互检查:oPlayer 到 oContainer 的距离 < InteractionDistance。

显示物品栏 UI

在 UI 层,使用 draw_sprite_part 绘制网格中的物品。处理鼠标悬停高亮,通过 global.dragItem 实现拖放。

在 oPlayer 中添加 inventoryPlayer = inventoryCreate(10, 6);容器也同样处理。

关键要点

  • 使用 ds_grid 进行高效的 2D 存储,支持 [#x,y] 访问器。
  • 主要单元格仅存储 itemID/quantity;其余通过 getItemData 获取。
  • 确保原子操作:在放置前检查所有单元格。
  • DebugMode 简化加载和操作的调试。
  • 持久化 oGameManager 确保 global ItemDB 状态。

— Editorial Team

Advertisement 728x90

继续阅读