mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-30 02:51:29 +08:00
389 lines
10 KiB
JavaScript
389 lines
10 KiB
JavaScript
// 背包系统:管理拾取的物品,支持网格类型的背包系统
|
|
|
|
export class Inventory {
|
|
constructor(width = 6, height = 4) {
|
|
this.width = width; // 背包宽度(网格数)
|
|
this.height = height; // 背包高度(网格数)
|
|
this.grid = this.createGrid(); // 创建背包网格
|
|
this.items = new Map(); // 存储背包中的物品
|
|
this.totalWeight = 0; // 总重量
|
|
this.totalVolume = 0; // 总体积
|
|
}
|
|
|
|
/**
|
|
* 创建背包网格
|
|
* @returns {Array} 二维数组表示的网格
|
|
*/
|
|
createGrid() {
|
|
const grid = [];
|
|
for (let y = 0; y < this.height; y++) {
|
|
grid[y] = [];
|
|
for (let x = 0; x < this.width; x++) {
|
|
grid[y][x] = null; // null表示空格子
|
|
}
|
|
}
|
|
return grid;
|
|
}
|
|
|
|
/**
|
|
* 检查物品是否可以放置在指定位置
|
|
* @param {Object} item - 要放置的物品
|
|
* @param {number} x - 起始X坐标
|
|
* @param {number} y - 起始Y坐标
|
|
* @returns {boolean} 是否可以放置
|
|
*/
|
|
canPlaceItem(item, x, y) {
|
|
const { gridSize } = item;
|
|
|
|
// 检查物品尺寸是否在背包范围内
|
|
if (x < 0 || y < 0 || x + gridSize.width > this.width || y + gridSize.height > this.height) {
|
|
return false;
|
|
}
|
|
|
|
// 检查物品占用的所有格子是否都是空的或属于物品自身
|
|
for (let dy = 0; dy < gridSize.height; dy++) {
|
|
for (let dx = 0; dx < gridSize.width; dx++) {
|
|
const gridX = x + dx;
|
|
const gridY = y + dy;
|
|
const cellItemId = this.grid[gridY][gridX];
|
|
|
|
// 如果格子不是空的,且不是物品自身,则不能放置
|
|
if (cellItemId !== null && cellItemId !== item.id) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 放置物品到背包中
|
|
* @param {Object} item - 要放置的物品
|
|
* @param {number} x - 起始X坐标
|
|
* @param {number} y - 起始Y坐标
|
|
* @returns {boolean} 是否放置成功
|
|
*/
|
|
placeItem(item, x, y) {
|
|
if (!this.canPlaceItem(item, x, y)) {
|
|
return false;
|
|
}
|
|
|
|
const { gridSize } = item;
|
|
|
|
// 记录物品在背包中的位置信息 - 同时设置position和positionInInventory确保一致性
|
|
item.position = { x, y };
|
|
item.positionInInventory = { x, y };
|
|
item.inventory = this;
|
|
item.inInventory = true;
|
|
|
|
// 更新网格和物品列表
|
|
for (let dy = 0; dy < gridSize.height; dy++) {
|
|
for (let dx = 0; dx < gridSize.width; dx++) {
|
|
this.grid[y + dy][x + dx] = item.id;
|
|
}
|
|
}
|
|
|
|
this.items.set(item.id, item);
|
|
this.totalWeight += item.weight;
|
|
this.totalVolume += item.volume;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 查找物品在背包中的位置
|
|
* @param {string} itemId - 物品ID
|
|
* @returns {Object|null} 物品位置信息
|
|
*/
|
|
findItemPosition(itemId) {
|
|
for (let y = 0; y < this.height; y++) {
|
|
for (let x = 0; x < this.width; x++) {
|
|
if (this.grid[y][x] === itemId) {
|
|
return { x, y };
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 从背包中移除物品
|
|
* @param {string} itemId - 物品ID
|
|
* @returns {Object|null} 移除的物品
|
|
*/
|
|
removeItem(itemId) {
|
|
const item = this.items.get(itemId);
|
|
if (!item) {
|
|
return null;
|
|
}
|
|
|
|
const { position, gridSize } = item;
|
|
|
|
// 清空网格
|
|
for (let dy = 0; dy < gridSize.height; dy++) {
|
|
for (let dx = 0; dx < gridSize.width; dx++) {
|
|
this.grid[position.y + dy][position.x + dx] = null;
|
|
}
|
|
}
|
|
|
|
// 更新物品信息和统计数据 - 同时清空position和positionInInventory
|
|
item.position = null;
|
|
item.positionInInventory = null;
|
|
item.inventory = null;
|
|
item.inInventory = false;
|
|
this.items.delete(itemId);
|
|
this.totalWeight -= item.weight;
|
|
this.totalVolume -= item.volume;
|
|
|
|
return item;
|
|
}
|
|
|
|
/**
|
|
* 移动背包中的物品
|
|
* @param {string} itemId - 物品ID
|
|
* @param {number} newX - 新的X坐标
|
|
* @param {number} newY - 新的Y坐标
|
|
* @returns {boolean} 是否移动成功
|
|
*/
|
|
moveItem(itemId, newX, newY) {
|
|
console.log('moveItem called:', itemId, 'to position:', { newX, newY });
|
|
const item = this.items.get(itemId);
|
|
if (!item) {
|
|
console.log('moveItem failed: 物品不存在');
|
|
return false;
|
|
}
|
|
|
|
console.log('移动物品:', item.name, '当前位置:', item.position, '目标位置:', { newX, newY });
|
|
|
|
// 检查新位置是否可以放置
|
|
if (!this.canPlaceItem(item, newX, newY)) {
|
|
console.log('moveItem failed: 新位置无法放置物品');
|
|
return false;
|
|
}
|
|
|
|
// 保存旧位置信息
|
|
const oldX = item.position.x;
|
|
const oldY = item.position.y;
|
|
const { gridSize } = item;
|
|
|
|
console.log('清空旧位置网格:', { oldX, oldY }, '尺寸:', gridSize);
|
|
// 清空旧位置的网格
|
|
for (let dy = 0; dy < gridSize.height; dy++) {
|
|
for (let dx = 0; dx < gridSize.width; dx++) {
|
|
this.grid[oldY + dy][oldX + dx] = null;
|
|
}
|
|
}
|
|
|
|
// 更新物品位置
|
|
item.position = { x: newX, y: newY };
|
|
item.positionInInventory = { x: newX, y: newY };
|
|
console.log('更新物品位置:', item.position);
|
|
|
|
// 更新新位置的网格
|
|
for (let dy = 0; dy < gridSize.height; dy++) {
|
|
for (let dx = 0; dx < gridSize.width; dx++) {
|
|
this.grid[newY + dy][newX + dx] = item.id;
|
|
}
|
|
}
|
|
|
|
console.log('moveItem success:', item.name, '已移动到', { newX, newY });
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 交换两个物品的位置
|
|
* @param {string} itemId1 - 第一个物品ID
|
|
* @param {string} itemId2 - 第二个物品ID
|
|
* @returns {boolean} 是否交换成功
|
|
*/
|
|
swapItems(itemId1, itemId2) {
|
|
console.log('swapItems called:', itemId1, '与', itemId2);
|
|
const item1 = this.items.get(itemId1);
|
|
const item2 = this.items.get(itemId2);
|
|
|
|
if (!item1 || !item2) {
|
|
console.log('swapItems failed: 物品不存在');
|
|
return false;
|
|
}
|
|
|
|
console.log('交换物品:', item1.name, '与', item2.name);
|
|
console.log('物品1位置:', item1.position, '物品2位置:', item2.position);
|
|
|
|
const pos1 = { ...item1.position };
|
|
const pos2 = { ...item2.position };
|
|
|
|
// 移除两个物品
|
|
console.log('移除两个物品');
|
|
this.removeItem(itemId1);
|
|
this.removeItem(itemId2);
|
|
|
|
// 尝试在对方位置放置
|
|
console.log('尝试将物品1放置到物品2的位置:', pos2);
|
|
if (!this.placeItem(item1, pos2.x, pos2.y)) {
|
|
// 回滚:将两个物品放回原位置
|
|
console.log('swapItems failed: 物品1无法放置到物品2的位置,回滚');
|
|
this.placeItem(item1, pos1.x, pos1.y);
|
|
this.placeItem(item2, pos2.x, pos2.y);
|
|
return false;
|
|
}
|
|
|
|
console.log('尝试将物品2放置到物品1的位置:', pos1);
|
|
if (!this.placeItem(item2, pos1.x, pos1.y)) {
|
|
// 回滚:将第一个物品放回原位置,第二个物品也放回原位置
|
|
console.log('swapItems failed: 物品2无法放置到物品1的位置,回滚');
|
|
this.removeItem(itemId1);
|
|
this.placeItem(item1, pos1.x, pos1.y);
|
|
this.placeItem(item2, pos2.x, pos2.y);
|
|
return false;
|
|
}
|
|
|
|
console.log('swapItems success: 物品交换成功');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 查找第一个可用的空位
|
|
* @param {Object} item - 要放置的物品
|
|
* @returns {Object|null} 可用位置
|
|
*/
|
|
findEmptySpot(item) {
|
|
const { gridSize } = item;
|
|
|
|
// 确保物品尺寸不会超过背包尺寸
|
|
if (gridSize.width > this.width || gridSize.height > this.height) {
|
|
console.log(`物品尺寸(${gridSize.width}x${gridSize.height})超过背包尺寸(${this.width}x${this.height})`);
|
|
return null;
|
|
}
|
|
|
|
// 遍历背包网格,寻找可用位置
|
|
for (let y = 0; y <= this.height - gridSize.height; y++) {
|
|
for (let x = 0; x <= this.width - gridSize.width; x++) {
|
|
if (this.canPlaceItem(item, x, y)) {
|
|
return { x, y };
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log("未找到可用空位");
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 添加物品到背包(自动寻找空位)
|
|
* @param {Object} item - 要添加的物品
|
|
* @returns {boolean} 是否添加成功
|
|
*/
|
|
addItem(item) {
|
|
const spot = this.findEmptySpot(item);
|
|
if (!spot) {
|
|
return false;
|
|
}
|
|
|
|
return this.placeItem(item, spot.x, spot.y);
|
|
}
|
|
|
|
/**
|
|
* 获取背包中指定位置的物品
|
|
* @param {number} x - X坐标
|
|
* @param {number} y - Y坐标
|
|
* @returns {Object|null} 物品
|
|
*/
|
|
getItemAt(x, y) {
|
|
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
|
|
return null;
|
|
}
|
|
|
|
const itemId = this.grid[y][x];
|
|
return itemId ? this.items.get(itemId) : null;
|
|
}
|
|
|
|
/**
|
|
* 获取背包中的所有物品
|
|
* @returns {Map} 物品映射
|
|
*/
|
|
getAllItems() {
|
|
return this.items;
|
|
}
|
|
|
|
/**
|
|
* 获取背包的统计信息
|
|
* @returns {Object} 统计信息
|
|
*/
|
|
getStats() {
|
|
return {
|
|
width: this.width,
|
|
height: this.height,
|
|
totalItems: this.items.size,
|
|
totalWeight: this.totalWeight,
|
|
totalVolume: this.totalVolume,
|
|
emptySlots: this.calculateEmptySlots()
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 计算空位数
|
|
* @returns {number} 空位数
|
|
*/
|
|
calculateEmptySlots() {
|
|
let count = 0;
|
|
for (let y = 0; y < this.height; y++) {
|
|
for (let x = 0; x < this.width; x++) {
|
|
if (this.grid[y][x] === null) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* 清空背包
|
|
*/
|
|
clear() {
|
|
this.grid = this.createGrid();
|
|
this.items.clear();
|
|
this.totalWeight = 0;
|
|
this.totalVolume = 0;
|
|
}
|
|
|
|
/**
|
|
* 导出背包数据
|
|
* @returns {Object} 背包数据
|
|
*/
|
|
exportData() {
|
|
const items = [];
|
|
this.items.forEach(item => {
|
|
items.push({
|
|
...item.getInfo(),
|
|
position: item.position
|
|
});
|
|
});
|
|
|
|
return {
|
|
width: this.width,
|
|
height: this.height,
|
|
items: items
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 导入背包数据
|
|
* @param {Object} data - 背包数据
|
|
*/
|
|
importData(data) {
|
|
this.clear();
|
|
this.width = data.width;
|
|
this.height = data.height;
|
|
this.grid = this.createGrid();
|
|
|
|
data.items.forEach(itemData => {
|
|
// 这里需要重新创建物品实例
|
|
// 假设Item类有一个静态方法createFromData
|
|
const item = Item.createFromData(itemData);
|
|
if (item) {
|
|
this.placeItem(item, itemData.position.x, itemData.position.y);
|
|
}
|
|
});
|
|
}
|
|
} |