Add player viewmodel and fix item icons - v1.6.1
This commit is contained in:
parent
224b80311a
commit
3d23e0c896
Binary file not shown.
|
After Width: | Height: | Size: 476 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 647 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 476 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 647 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 476 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 647 KiB |
154
src/main.cpp
154
src/main.cpp
|
|
@ -18,7 +18,8 @@
|
||||||
|
|
||||||
enum BlockType {
|
enum BlockType {
|
||||||
AIR = 0, GRASS = 1, DIRT = 2, COBBLESTONE = 3, LOG = 4, LEAVES = 5, PLANK = 6,
|
AIR = 0, GRASS = 1, DIRT = 2, COBBLESTONE = 3, LOG = 4, LEAVES = 5, PLANK = 6,
|
||||||
STONE = 7, BEDROCK = 8, DIAMOND_ORE = 9, IRON_ORE = 10, GRAVEL = 11, CRAFTING_TABLE = 12, SAND = 13
|
STONE = 7, BEDROCK = 8, DIAMOND_ORE = 9, IRON_ORE = 10, GRAVEL = 11, CRAFTING_TABLE = 12, SAND = 13,
|
||||||
|
STICK = 14, WOOD_AXE = 15
|
||||||
};
|
};
|
||||||
|
|
||||||
// Simple 2D Perlin Noise implementation
|
// Simple 2D Perlin Noise implementation
|
||||||
|
|
@ -622,7 +623,11 @@ int main(void)
|
||||||
MenuState optionsReturnState = MAIN_MENU;
|
MenuState optionsReturnState = MAIN_MENU;
|
||||||
|
|
||||||
InventorySlot mouseHeldItem(AIR, 0);
|
InventorySlot mouseHeldItem(AIR, 0);
|
||||||
float gameTime = 0.0f; // Total game time for day/night cycle
|
float gameTime = 75.0f; // Start at 6:00 AM
|
||||||
|
float breakProgress = 0.0f;
|
||||||
|
int lastHitX = -1, lastHitY = -1, lastHitZ = -1;
|
||||||
|
float swingTime = 0.0f;
|
||||||
|
bool isSwinging = false;
|
||||||
|
|
||||||
float targetZoom = 1.1f;
|
float targetZoom = 1.1f;
|
||||||
float currentZoom = 1.1f;
|
float currentZoom = 1.1f;
|
||||||
|
|
@ -676,6 +681,10 @@ int main(void)
|
||||||
// Safety Fallback: Use Planks if custom textures failed to load (prevents crash)
|
// Safety Fallback: Use Planks if custom textures failed to load (prevents crash)
|
||||||
if (craftingSideTexture.id == 0) craftingSideTexture = blockTextures[PLANK];
|
if (craftingSideTexture.id == 0) craftingSideTexture = blockTextures[PLANK];
|
||||||
if (craftingTopTexture.id == 0) craftingTopTexture = blockTextures[PLANK];
|
if (craftingTopTexture.id == 0) craftingTopTexture = blockTextures[PLANK];
|
||||||
|
blockTextures[CRAFTING_TABLE] = craftingSideTexture; // Preview for inventory
|
||||||
|
|
||||||
|
blockTextures[STICK] = LoadTexture("assets/stick.png");
|
||||||
|
blockTextures[WOOD_AXE] = LoadTexture("assets/wooden_axe.png");
|
||||||
|
|
||||||
// Inventory Crafting State
|
// Inventory Crafting State
|
||||||
InventorySlot craftingSlots[4]; // Default to AIR/0
|
InventorySlot craftingSlots[4]; // Default to AIR/0
|
||||||
|
|
@ -690,14 +699,44 @@ int main(void)
|
||||||
if (craftingSlots[0].blockType == PLANK && craftingSlots[1].blockType == PLANK &&
|
if (craftingSlots[0].blockType == PLANK && craftingSlots[1].blockType == PLANK &&
|
||||||
craftingSlots[2].blockType == PLANK && craftingSlots[3].blockType == PLANK) {
|
craftingSlots[2].blockType == PLANK && craftingSlots[3].blockType == PLANK) {
|
||||||
craftingResult = InventorySlot(CRAFTING_TABLE, 1);
|
craftingResult = InventorySlot(CRAFTING_TABLE, 1);
|
||||||
} else {
|
}
|
||||||
|
// Recipe: 2 Planks (vertical) -> 4 Sticks
|
||||||
|
else if ((craftingSlots[0].blockType == PLANK && craftingSlots[2].blockType == PLANK) ||
|
||||||
|
(craftingSlots[1].blockType == PLANK && craftingSlots[3].blockType == PLANK)) {
|
||||||
|
craftingResult = InventorySlot(STICK, 4);
|
||||||
|
}
|
||||||
|
else {
|
||||||
craftingResult = InventorySlot(AIR, 0);
|
craftingResult = InventorySlot(AIR, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto UpdateTableCrafting = [&]() {
|
auto UpdateTableCrafting = [&]() {
|
||||||
// Example: 1 plank -> 4 buttons? No, let's just keep it empty for now or add one.
|
// Wooden Axe Recipe
|
||||||
|
// [P P .]
|
||||||
|
// [P S .]
|
||||||
|
// [. S .]
|
||||||
|
if (tableSlots[0].blockType == PLANK && tableSlots[1].blockType == PLANK &&
|
||||||
|
tableSlots[3].blockType == PLANK && tableSlots[4].blockType == STICK &&
|
||||||
|
tableSlots[7].blockType == STICK) {
|
||||||
|
tableResult = InventorySlot(WOOD_AXE, 1);
|
||||||
|
}
|
||||||
|
// Sticks (vertical anywhere)
|
||||||
|
else if ((tableSlots[0].blockType == PLANK && tableSlots[3].blockType == PLANK) ||
|
||||||
|
(tableSlots[1].blockType == PLANK && tableSlots[4].blockType == PLANK) ||
|
||||||
|
(tableSlots[2].blockType == PLANK && tableSlots[5].blockType == PLANK) ||
|
||||||
|
(tableSlots[3].blockType == PLANK && tableSlots[6].blockType == PLANK) ||
|
||||||
|
(tableSlots[4].blockType == PLANK && tableSlots[7].blockType == PLANK) ||
|
||||||
|
(tableSlots[5].blockType == PLANK && tableSlots[8].blockType == PLANK)) {
|
||||||
|
tableResult = InventorySlot(STICK, 4);
|
||||||
|
}
|
||||||
|
// 4 Planks -> 1 Table (3x3 grid)
|
||||||
|
else if (tableSlots[0].blockType == PLANK && tableSlots[1].blockType == PLANK &&
|
||||||
|
tableSlots[3].blockType == PLANK && tableSlots[4].blockType == PLANK) {
|
||||||
|
tableResult = InventorySlot(CRAFTING_TABLE, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
tableResult = InventorySlot(AIR, 0);
|
tableResult = InventorySlot(AIR, 0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// Block Selection State (for wireframe)
|
// Block Selection State (for wireframe)
|
||||||
bool hitBlock = false;
|
bool hitBlock = false;
|
||||||
|
|
@ -903,13 +942,41 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hitBlock) {
|
if (hitBlock) {
|
||||||
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
|
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
|
||||||
|
if (hitX != lastHitX || hitY != lastHitY || hitZ != lastHitZ) {
|
||||||
|
breakProgress = 0.0f;
|
||||||
|
lastHitX = hitX; lastHitY = hitY; lastHitZ = hitZ;
|
||||||
|
}
|
||||||
|
|
||||||
int targetBlock = GetBlock(hitX, hitY, hitZ);
|
int targetBlock = GetBlock(hitX, hitY, hitZ);
|
||||||
if (targetBlock != BEDROCK) {
|
if (targetBlock != AIR && targetBlock != BEDROCK) {
|
||||||
|
float breakSpeed = 2.0f; // Seconds to break
|
||||||
|
|
||||||
|
// Axe logic: Wood/Plank/Logs are faster
|
||||||
|
if (targetBlock == LOG || targetBlock == PLANK || targetBlock == CRAFTING_TABLE) {
|
||||||
|
if (hotbar[activeHotbarSlot].blockType == WOOD_AXE) breakSpeed = 0.5f; // Fast
|
||||||
|
else breakSpeed = 1.5f; // Normal
|
||||||
|
} else if (targetBlock == LEAVES) {
|
||||||
|
breakSpeed = 0.2f; // Very fast
|
||||||
|
}
|
||||||
|
|
||||||
|
breakProgress += GetFrameTime();
|
||||||
|
|
||||||
|
if (breakProgress >= breakSpeed) {
|
||||||
AddToInventory(targetBlock);
|
AddToInventory(targetBlock);
|
||||||
SetBlock(hitX, hitY, hitZ, AIR);
|
SetBlock(hitX, hitY, hitZ, AIR);
|
||||||
|
breakProgress = 0.0f;
|
||||||
|
isSwinging = true; // Swing when finishing
|
||||||
}
|
}
|
||||||
} else if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
|
|
||||||
|
// Visual swing while mining
|
||||||
|
if (fmodf(breakProgress, 0.4f) < 0.1f) isSwinging = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
breakProgress = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
|
||||||
int targetBlock = GetBlock(hitX, hitY, hitZ);
|
int targetBlock = GetBlock(hitX, hitY, hitZ);
|
||||||
if (targetBlock == CRAFTING_TABLE) {
|
if (targetBlock == CRAFTING_TABLE) {
|
||||||
currentState = CRAFTING_GUI;
|
currentState = CRAFTING_GUI;
|
||||||
|
|
@ -922,6 +989,7 @@ int main(void)
|
||||||
hotbar[activeHotbarSlot].count--;
|
hotbar[activeHotbarSlot].count--;
|
||||||
if (hotbar[activeHotbarSlot].count == 0)
|
if (hotbar[activeHotbarSlot].count == 0)
|
||||||
hotbar[activeHotbarSlot].blockType = AIR;
|
hotbar[activeHotbarSlot].blockType = AIR;
|
||||||
|
isSwinging = true; // Swing when placing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -986,8 +1054,8 @@ int main(void)
|
||||||
DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE);
|
DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE);
|
||||||
EndMode2D();
|
EndMode2D();
|
||||||
|
|
||||||
// Show Version Number (v1.5.2) in Red
|
// Show Version Number (v1.6.1) in Red
|
||||||
DrawTextEx(customFont, "v1.5.2", (Vector2){ (float)currentWidth - 140, (float)currentHeight - 40 }, 22, 1.0f, RED);
|
DrawTextEx(customFont, "v1.6.1", (Vector2){ (float)currentWidth - 140, (float)currentHeight - 40 }, 22, 1.0f, RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 mousePos = GetMousePosition();
|
Vector2 mousePos = GetMousePosition();
|
||||||
|
|
@ -1417,7 +1485,7 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw Gameplay overlay if we entered gameplay
|
// Draw Gameplay overlay if we entered gameplay
|
||||||
if (currentState == GAMEPLAY || currentState == PAUSE_MENU) {
|
if (currentState == GAMEPLAY || currentState == PAUSE_MENU || currentState == CRAFTING_GUI) {
|
||||||
// ---- Day / Night Cycle Calculations ----
|
// ---- Day / Night Cycle Calculations ----
|
||||||
float cycleLength = 300.0f; // 5 minutes
|
float cycleLength = 300.0f; // 5 minutes
|
||||||
float timeOfDay = fmodf(gameTime, cycleLength) / cycleLength;
|
float timeOfDay = fmodf(gameTime, cycleLength) / cycleLength;
|
||||||
|
|
@ -1556,8 +1624,66 @@ int main(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Draw Block Selection Wireframe
|
// Draw Block Selection Wireframe
|
||||||
if (hitBlock && !inventoryOpen) {
|
if (hitBlock && !inventoryOpen && currentState != CRAFTING_GUI) {
|
||||||
DrawCubeWires((Vector3){(float)hitX, (float)hitY, (float)hitZ}, 1.02f, 1.02f, 1.02f, BLACK);
|
float size = 1.02f;
|
||||||
|
DrawCubeWires((Vector3){(float)hitX, (float)hitY, (float)hitZ}, size, size, size, BLACK);
|
||||||
|
|
||||||
|
// Draw breaking progress indicator
|
||||||
|
// Draw breaking progress indicator
|
||||||
|
if (breakProgress > 0.0f) {
|
||||||
|
float pSize = (breakProgress / 1.5f) * 1.05f; // Scale visual based on progress
|
||||||
|
if (pSize > 1.05f) pSize = 1.05f;
|
||||||
|
DrawCubeWires((Vector3){(float)hitX, (float)hitY, (float)hitZ}, pSize, pSize, pSize, RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- DRAW VIEWMODEL (ARM/HELD ITEM) ---
|
||||||
|
if (!inventoryOpen && currentState != CRAFTING_GUI) {
|
||||||
|
if (isSwinging) {
|
||||||
|
swingTime += GetFrameTime() * 8.0f;
|
||||||
|
if (swingTime >= 1.0f) {
|
||||||
|
swingTime = 0.0f;
|
||||||
|
isSwinging = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float swingVal = sinf(swingTime * PI);
|
||||||
|
|
||||||
|
rlDisableDepthTest(); // Draw on top
|
||||||
|
rlPushMatrix();
|
||||||
|
// Transform to camera space manually for the viewmodel
|
||||||
|
Vector3 forwardVM = Vector3Subtract(camera3D.target, camera3D.position);
|
||||||
|
forwardVM = Vector3Normalize(forwardVM);
|
||||||
|
Vector3 rightVM = Vector3CrossProduct(forwardVM, camera3D.up);
|
||||||
|
rightVM = Vector3Normalize(rightVM);
|
||||||
|
Vector3 upVM = Vector3CrossProduct(rightVM, forwardVM);
|
||||||
|
upVM = Vector3Normalize(upVM);
|
||||||
|
|
||||||
|
Vector3 handPos = Vector3Add(camera3D.position, Vector3Scale(forwardVM, 0.4f));
|
||||||
|
handPos = Vector3Add(handPos, Vector3Scale(rightVM, 0.25f));
|
||||||
|
handPos = Vector3Add(handPos, Vector3Scale(upVM, -0.2f - swingVal * 0.1f));
|
||||||
|
|
||||||
|
// Draw Arm
|
||||||
|
DrawCube(handPos, 0.08f, 0.2f, 0.08f, (Color){220, 180, 150, 255});
|
||||||
|
|
||||||
|
// Draw Held Item
|
||||||
|
int heldBT = hotbar[activeHotbarSlot].blockType;
|
||||||
|
if (heldBT != AIR) {
|
||||||
|
Vector3 itemPos = Vector3Add(handPos, Vector3Scale(upVM, 0.1f));
|
||||||
|
itemPos = Vector3Add(itemPos, Vector3Scale(forwardVM, 0.1f));
|
||||||
|
|
||||||
|
if (heldBT < STICK) {
|
||||||
|
// Block
|
||||||
|
DrawCube(itemPos, 0.15f, 0.15f, 0.15f, blockTint);
|
||||||
|
DrawCubeWires(itemPos, 0.151f, 0.151f, 0.151f, BLACK);
|
||||||
|
} else {
|
||||||
|
// Item (Stick/Axe) - use small thin cube for now
|
||||||
|
Color itemColor = (heldBT == STICK) ? BROWN : DARKGRAY;
|
||||||
|
DrawCube(itemPos, 0.03f, 0.25f, 0.03f, itemColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rlPopMatrix();
|
||||||
|
rlEnableDepthTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
EndMode3D();
|
EndMode3D();
|
||||||
|
|
@ -1662,6 +1788,10 @@ int main(void)
|
||||||
Rectangle dst = { (float)(px+5),(float)(py+5), (float)(invSlotSize-10),(float)(invSlotSize-10) };
|
Rectangle dst = { (float)(px+5),(float)(py+5), (float)(invSlotSize-10),(float)(invSlotSize-10) };
|
||||||
Color tint = (bt == GRASS) ? (Color){124,189,107,255} : WHITE;
|
Color tint = (bt == GRASS) ? (Color){124,189,107,255} : WHITE;
|
||||||
DrawTexturePro(tex, src, dst, (Vector2){0,0}, 0.0f, tint);
|
DrawTexturePro(tex, src, dst, (Vector2){0,0}, 0.0f, tint);
|
||||||
|
} else if (bt >= STICK) {
|
||||||
|
// Fallback rendering for items if texture failed
|
||||||
|
Color itemCol = (bt == STICK) ? BROWN : DARKGRAY;
|
||||||
|
DrawRectangle(px + 10, py + 10, invSlotSize - 20, invSlotSize - 20, itemCol);
|
||||||
}
|
}
|
||||||
Vector2 cSize = MeasureTextEx(customFont, TextFormat("%i", slot.count), 12, 1.0f);
|
Vector2 cSize = MeasureTextEx(customFont, TextFormat("%i", slot.count), 12, 1.0f);
|
||||||
DrawTextEx(customFont, TextFormat("%i", slot.count),
|
DrawTextEx(customFont, TextFormat("%i", slot.count),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue