Semi-random thoughts and tales of tinkering
In Lesson 9, broken blocks disappeared and we could only place stone. In real Minecraft, broken blocks go into your inventory, and you choose which block to place from your hotbar. Let's build that! 🎒
The inventory is an array of slots. Each slot holds a block type and a count.
We use null for empty slots:
// 9 hotbar slots — each is either null or { block, count }
const hotbar = [
{ block: 1, count: 5 }, // 5 grass blocks
{ block: 2, count: 10 }, // 10 dirt blocks
{ block: 3, count: 8 }, // 8 stone blocks
null, // empty slot
null, null, null, null, null
];
let selectedSlot = 0; // Which slot is currently selected
null is a special value in JavaScript that means "nothing" or "empty."
It's different from 0 (which is a number). We use it to mean
"this inventory slot has nothing in it."
When we break a block, instead of it just disappearing, we add it to the inventory:
function addToInventory(blockType) {
// First, try to stack with an existing slot of the same type
for (let i = 0; i < hotbar.length; i++) {
if (hotbar[i] && hotbar[i].block === blockType) {
hotbar[i].count++; // Add one more to the stack
return true;
}
}
// If no matching slot, find an empty slot
for (let i = 0; i < hotbar.length; i++) {
if (hotbar[i] === null) {
hotbar[i] = { block: blockType, count: 1 };
return true;
}
}
return false; // Inventory is full!
}
// When breaking a block:
if (mouse.left && block !== 0) {
addToInventory(block); // Pick it up
setBlock(col, row, 0); // Remove from world
}
When placing, we use the block type from the selected hotbar slot:
if (mouse.right) {
const item = hotbar[selectedSlot];
if (item && item.count > 0) {
setBlock(col, row, item.block); // Place the block
item.count--; // Use one from inventory
if (item.count <= 0) {
hotbar[selectedSlot] = null; // Slot is now empty
}
}
}
Number keys 1-9 select hotbar slots, and the scroll wheel cycles through them:
// Number keys
document.addEventListener('keydown', function(event) {
if (event.key >= '1' && event.key <= '9') {
selectedSlot = parseInt(event.key) - 1;
}
});
// Scroll wheel
canvas.addEventListener('wheel', function(event) {
if (event.deltaY > 0) selectedSlot = (selectedSlot + 1) % 9; // Next
else selectedSlot = (selectedSlot + 8) % 9; // Previous
});
function drawHotbar() {
const barWidth = 9 * 44 + 8 * 4; // 9 slots + gaps
const barX = (canvas.width - barWidth) / 2;
const barY = canvas.height - 54;
for (let i = 0; i < 9; i++) {
const x = barX + i * 48;
const y = barY;
// Slot background
ctx.fillStyle = i === selectedSlot ? 'rgba(255,255,255,0.3)' : 'rgba(0,0,0,0.6)';
ctx.fillRect(x, y, 44, 44);
ctx.strokeStyle = i === selectedSlot ? '#fff' : '#555';
ctx.lineWidth = 2;
ctx.strokeRect(x, y, 44, 44);
// Block icon and count
if (hotbar[i]) {
ctx.fillStyle = COLORS[hotbar[i].block];
ctx.fillRect(x + 6, y + 6, 32, 32);
ctx.fillStyle = '#fff';
ctx.font = 'bold 12px Consolas';
ctx.fillText(hotbar[i].count, x + 30, y + 40);
}
// Slot number
ctx.fillStyle = '#aaa';
ctx.font = '10px Consolas';
ctx.fillText(i + 1, x + 3, y + 12);
}
}
⬆️ Click here! AD move, Space jump, 1-9 or Scroll select slot, Left-click break, Right-click place
null represents empty slots