diff --git a/src/entity/entity.cpp b/src/entity/entity.cpp index 1e02e43..c8bea21 100644 --- a/src/entity/entity.cpp +++ b/src/entity/entity.cpp @@ -55,10 +55,14 @@ void Entity::update() { void Entity::die() { for (int i = 0; i < world->i_window->objects.size(); i++) { - if (world->i_window->objects.at(i) == this) { - world->i_window->objects.erase(world->i_window->objects.begin() + i); + if (getWindow()->objects.at(i) == this) { + getWindow()->objects.erase(getWindow()->objects.begin() + i); delete this; return; } } } + +MWindow* Entity::getWindow() { + return world->i_window; +} diff --git a/src/entity/entity.h b/src/entity/entity.h index 9149cff..672b9ac 100644 --- a/src/entity/entity.h +++ b/src/entity/entity.h @@ -53,6 +53,8 @@ class Entity : public Renderable { virtual void die(); + MWindow* getWindow(); + }; #endif // M_ENTITY_H diff --git a/src/entity/item.cpp b/src/entity/item.cpp index 1f3d50e..91014b0 100644 --- a/src/entity/item.cpp +++ b/src/entity/item.cpp @@ -38,7 +38,7 @@ void EntityItem::updateSpritePosition(MWindow& relativeTo) { void EntityItem::update() { Entity::update(); Player* player; // For later type casts - for (Renderable* obj : world->i_window->objects) { + for (Renderable* obj : getWindow()->objects) { player = dynamic_cast(obj); if (player) { // Checking to see if the player is in bounds for pick up diff --git a/src/entity/player.cpp b/src/entity/player.cpp index 891fed7..2bed51b 100644 --- a/src/entity/player.cpp +++ b/src/entity/player.cpp @@ -10,6 +10,8 @@ Player::Player(M2DWorld& world) height = 2; width = 0.2; + hotbarPosition = 8; + headLeft.setTexture(HEAD_TEX_LEFT, true); headRight.setTexture(HEAD_TEX_RIGHT, true); body.setTexture(BODY_TEX, true); @@ -266,3 +268,50 @@ sf::Vector2f& findSpawnLocation(M2DWorld& world) { // For now, just returns a high spawn return *(new sf::Vector2f(1, 10)); } + + +void Player::updateBlock(int xPos, int yPos, bool destroy) { + // Based on the mouse coordinates given, find the block to break + + // We only want to detect if in the main game + if (getWindow()->state != MAIN_GAME) return; + + // The x and y differences + float xDiff = xPos - PLAYER_HEAD_X; + float yDiff = PLAYER_HEAD_Y - yPos; + + sf::Vector2f pos(xPos, yPos); + + // So we don't declare 100 times in a loop + sf::Vector2f incrementedPosition = *screenToBlock(*getWindow(), pos); + + // How much to increment x and y by + double distance = sqrt((xDiff*xDiff) + (yDiff*yDiff)); + double xStep = (xDiff / distance) * PLAYER_REACH / BLOCK_BREAK_COMPARISONS; + double yStep = (yDiff / distance) * PLAYER_REACH / BLOCK_BREAK_COMPARISONS; + + // I'll improve window.player->world some other time + // We send out a ray from the player's head (actually increment a position) + for (int i = 0; i < BLOCK_BREAK_COMPARISONS; i++) { + int inX = (int) floor(incrementedPosition.x); + int inY = (int) floor(incrementedPosition.y); + if (inX > 0 && inX < WORLD_WIDTH && inY > 0 && inY < WORLD_HEIGHT_LIMIT) + if (world->blocks[inX][inY]->str_type != "air") { + if (destroy) { + world->b_break(inX, inY + 1); + return; + } else { + world->b_place( + (int) floor(incrementedPosition.x - xStep), + (int) floor(incrementedPosition.y - yStep + 1), + inventory->sections[0]->contents[hotbarPosition] + ); + return; + } + } + // Increment the position + incrementedPosition.x += xStep; + incrementedPosition.y += yStep; + } + +} diff --git a/src/entity/player.h b/src/entity/player.h index d153f2c..e0021e4 100644 --- a/src/entity/player.h +++ b/src/entity/player.h @@ -40,6 +40,9 @@ class Player : public Entity { // Is the player facing left (false) or right (true)? bool facing; + // Which item stack the player is holding (0 through 8) + int hotbarPosition; + Player(M2DWorld& world); void render(MWindow& window) const override; void updateSpritePosition(MWindow& relativeTo) override; @@ -64,6 +67,8 @@ class Player : public Entity { void sneak(); void update() override; + + void updateBlock(int xPos, int yPos, bool destroy); }; sf::Vector2i* floorCoords(sf::Vector2f* coords); diff --git a/src/gui/hotbar_renderer.cpp b/src/gui/hotbar_renderer.cpp index c3be663..19aff6a 100644 --- a/src/gui/hotbar_renderer.cpp +++ b/src/gui/hotbar_renderer.cpp @@ -1,6 +1,6 @@ #include "hotbar_renderer.h" -InventoryFrame::InventoryFrame(MWindow& window, int x, int y) +InventoryFrame::InventoryFrame(MWindow& window, int x, int y, bool held) : // Initialize the rects b(sf::Vector2f(FRAME_SIZE, FRAME_THICKNESS)), @@ -12,6 +12,12 @@ r(sf::Vector2f(FRAME_THICKNESS, FRAME_SIZE)) { t.setPosition(sf::Vector2f(x - (FRAME_SIZE / 2), y - (FRAME_SIZE / 2))); l.setPosition(sf::Vector2f(x - (FRAME_SIZE / 2), y - (FRAME_SIZE / 2))); r.setPosition(sf::Vector2f(x + (FRAME_SIZE / 2) - (FRAME_THICKNESS / 2), y - FRAME_SIZE / 2)); + if (held) { + b.setFillColor(sf::Color::Black); + t.setFillColor(sf::Color::Black); + l.setFillColor(sf::Color::Black); + r.setFillColor(sf::Color::Black); + } } void InventoryFrame::render(MWindow& window) { @@ -27,7 +33,9 @@ void renderHotbar(MWindow& window, InventorySection* section) { sf::Text text; // For later for (int i = 0; i < section->size; i++) { centerX = WN_WIDTH / 2 - (section->size * FRAME_SIZE / 2) + (i * FRAME_SIZE); - InventoryFrame(window, centerX, HOTBAR_DISPLAY_HEIGHT).render(window); + InventoryFrame ( + window, centerX, HOTBAR_DISPLAY_HEIGHT, window.player->hotbarPosition == i + ).render(window); section->contents[i]->spr.setPosition( centerX - (200 * 0.4 / 2), HOTBAR_DISPLAY_HEIGHT - (200 * 0.4 / 2) ); diff --git a/src/gui/hotbar_renderer.h b/src/gui/hotbar_renderer.h index a15da19..e1a0ad7 100644 --- a/src/gui/hotbar_renderer.h +++ b/src/gui/hotbar_renderer.h @@ -25,7 +25,7 @@ class InventorySection; class InventoryFrame { public: sf::RectangleShape b, t, l, r; // The four sides - InventoryFrame(MWindow& window, int xPos, int yPos); + InventoryFrame(MWindow& window, int xPos, int yPos, bool held); void render(MWindow& window); }; diff --git a/src/main.cpp b/src/main.cpp index 2582c9e..6d0e213 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,8 +58,6 @@ int main() { MWindow wn(WN_WIDTH, WN_HEIGHT, "2D Minecraft"); wn.color = WN_BG_COLOR; - InventoryFrame test(wn, 1000, 1000); - // Buttons for actions MButton startGame(wn, startNewGame, "New Game", sf::Color(100, 100, 100), 1000, 1000); MButton retButton(wn, returnToGame, "Resume", sf::Color(100, 100, 100), 1000, 800, true); diff --git a/src/main.h b/src/main.h index 3242835..18ea494 100644 --- a/src/main.h +++ b/src/main.h @@ -17,7 +17,7 @@ // Physics settings #define GRAVITY_STRENGTH 0.00003 #define FRICTION 0.05 -#define JUMP_HEIGHT 0.005 +#define JUMP_HEIGHT 0.008 #define WALK_SPEED 0.005 void loadButtonFont(); diff --git a/src/render/m_window.cpp b/src/render/m_window.cpp index 7d7b7a3..7773941 100644 --- a/src/render/m_window.cpp +++ b/src/render/m_window.cpp @@ -13,7 +13,7 @@ MWindow::MWindow(int x, int y, std::string title) color(0, 0, 0) { xShift = yShift = 0; player = nullptr; - lastMousePressed = false; + lastMousePressedLeft = lastMousePressedRight = false; state = MAIN_MENU; } @@ -39,12 +39,23 @@ void MWindow::cycle() { } // Mouse presses - if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left) && !lastMousePressed) { - onClick(sf::Mouse::getPosition(*this).x, sf::Mouse::getPosition(*this).y); - lastMousePressed = true; - } else if (!(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) && lastMousePressed) { - offClick(sf::Mouse::getPosition(*this).x, sf::Mouse::getPosition(*this).y); - lastMousePressed = false; + + // Left + if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left) && !lastMousePressedLeft) { + onClick(sf::Mouse::getPosition(*this).x, sf::Mouse::getPosition(*this).y, true); + lastMousePressedLeft = true; + } else if (!(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) && lastMousePressedLeft) { + offClick(sf::Mouse::getPosition(*this).x, sf::Mouse::getPosition(*this).y, true); + lastMousePressedLeft = false; + } + + // Right + if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Right) && !lastMousePressedRight) { + onClick(sf::Mouse::getPosition(*this).x, sf::Mouse::getPosition(*this).y, false); + lastMousePressedRight = true; + } else if (!(sf::Mouse::isButtonPressed(sf::Mouse::Button::Right)) && lastMousePressedRight) { + offClick(sf::Mouse::getPosition(*this).x, sf::Mouse::getPosition(*this).y, false); + lastMousePressedRight = false; } // Display the screen @@ -75,28 +86,39 @@ void MWindow::add(Renderable* obj) { objects.push_back(obj); } -void MWindow::onClick(int x, int y) { - MButton* button; - for (Renderable* object : objects) { - button = dynamic_cast(object); - if (button) { - if (button->contains(x, y)) { - button->onClick(); - return; +void MWindow::onClick(int x, int y, bool m) { + if (m) { + MButton* button; + for (Renderable* object : objects) { + button = dynamic_cast(object); + if (button) { + if (button->contains(x, y)) { + button->onClick(); + return; + } } } + if (player) { + this->player->updateBlock(x, y, true); + } + } else { + // Right click + if (player) { + player->updateBlock(x, y, false); + } } - breakBlock(*this, x, y); } -void MWindow::offClick(int x, int y) { - MButton* button; - for (Renderable* object : objects) { - button = dynamic_cast(object); - if (button) { - if (button->clicked) { - button->offClick(*this); - return; +void MWindow::offClick(int x, int y, bool m) { + if (m) { + MButton* button; + for (Renderable* object : objects) { + button = dynamic_cast(object); + if (button) { + if (button->clicked) { + button->offClick(*this); + return; + } } } } @@ -153,6 +175,7 @@ void MWindow::handleWindowEvents(sf::Event event) { } void MWindow::handleKeyPresses() { + // Player movement if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space) && player->isCollided()) { if (player) player->jump(); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) || @@ -168,44 +191,33 @@ void MWindow::handleKeyPresses() { if (player->facing && player) player->moveRight(); else if (player) player->moveLeft(); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) { if (player->facing && player) player->moveLeft(); else if (player) player->moveRight(); + + // Escape menu } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) { escape(*this); } -} - -void breakBlock(MWindow& window, int xPos, int yPos) { - // Based on the mouse coordinates given, find the block to break - - // We only want to detect if in the main game - if (!(window.player) || (window.state != MAIN_GAME)) return; - - // The x and y differences - float xDiff = xPos - PLAYER_HEAD_X; - float yDiff = PLAYER_HEAD_Y - yPos; - - sf::Vector2f pos(xPos, yPos); - - // So we don't declare 100 times in a loop - sf::Vector2f incrementedPosition = *screenToBlock(window, pos); - - // How much to increment x and y by - double distance = sqrt((xDiff*xDiff) + (yDiff*yDiff)); - double xStep = (xDiff / distance) * PLAYER_REACH / BLOCK_BREAK_COMPARISONS; - double yStep = (yDiff / distance) * PLAYER_REACH / BLOCK_BREAK_COMPARISONS; - // I'll improve window.player->world some other time - // We send out a ray from the player's head (actually increment a position) - for (int i = 0; i < BLOCK_BREAK_COMPARISONS; i++) { - int inX = (int) floor(incrementedPosition.x); - int inY = (int) floor(incrementedPosition.y); - if (inX > 0 && inX < WORLD_WIDTH && inY > 0 && inY < WORLD_HEIGHT_LIMIT) - if (window.player->world->blocks[inX][inY]->str_type != "air") { - window.player->world->b_break(*(window.player->world), inX, inY + 1); - return; + // Maybe I can do this better? Who knows? + if (player) { + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num1)) { + player->hotbarPosition = 0; + } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num2)) { + player->hotbarPosition = 1; + } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num3)) { + player->hotbarPosition = 2; + } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num4)) { + player->hotbarPosition = 3; + } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num5)) { + player->hotbarPosition = 4; + } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num6)) { + player->hotbarPosition = 5; + } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num7)) { + player->hotbarPosition = 6; + } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num8)) { + player->hotbarPosition = 7; + } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Num9)) { + player->hotbarPosition = 8; } - // Increment the position - incrementedPosition.x += xStep; - incrementedPosition.y += yStep; } } diff --git a/src/render/m_window.h b/src/render/m_window.h index 6828002..488483c 100644 --- a/src/render/m_window.h +++ b/src/render/m_window.h @@ -27,7 +27,8 @@ class MWindow : public sf::RenderWindow { int state; // For mouse press handling - bool lastMousePressed; + bool lastMousePressedLeft; + bool lastMousePressedRight; Player* player; @@ -52,8 +53,8 @@ class MWindow : public sf::RenderWindow { void add(Renderable* obj); - void onClick(int x, int y); - void offClick(int x, int y); // x and y might be useful here, who knows? + void onClick(int x, int y, bool m); + void offClick(int x, int y, bool m); // x and y might be useful here, who knows? }; void changeState(MWindow& window, bool escape = true); @@ -61,6 +62,5 @@ void escape(MWindow& window); void returnToGame(MWindow& window); sf::Vector2f* screenToBlock(MWindow& relativeTo, sf::Vector2f& coords); -void breakBlock(MWindow& window, int xPos, int yPos); #endif // M_WINDOW_H diff --git a/src/world/block.cpp b/src/world/block.cpp index 10fb0b7..df3f4f6 100644 --- a/src/world/block.cpp +++ b/src/world/block.cpp @@ -29,6 +29,16 @@ EntityItem* Block::destroy(M2DWorld& world) { return new EntityItem(&world, is, x + 0.5, y + 0.5); } +void Block::place(M2DWorld& world, ItemStack* i) { + if (i->name != "empty") { + setTypeTo(i->name); + i->count--; + if (i->count == 0) { + i->name = "empty"; + } + } +} + void Block::setTypeTo(std::string type) { str_type = type; itemStack->name = type; diff --git a/src/world/block.h b/src/world/block.h index 218f447..b368047 100644 --- a/src/world/block.h +++ b/src/world/block.h @@ -25,7 +25,10 @@ class Block : public Renderable { Block(MWindow& window, int x, int y, std::string type=""); void render(MWindow& window) const override; void updateSpritePosition(MWindow& relativeTo) override; + EntityItem* destroy(M2DWorld& world); + void place(M2DWorld& world, ItemStack* i); + void setTypeTo(std::string type); }; diff --git a/src/world/world.cpp b/src/world/world.cpp index 172a1b4..ac1edc5 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -34,6 +34,10 @@ void M2DWorld::render(MWindow& target) const { } } -void M2DWorld::b_break(M2DWorld& world, int xPos, int yPos) { - blocks[xPos][yPos]->destroy(world); +void M2DWorld::b_break(int xPos, int yPos) { + blocks[xPos][yPos]->destroy(*this); +} + +void M2DWorld::b_place(int xPos, int yPos, ItemStack* i) { + blocks[xPos][yPos]->place(*this, i); } diff --git a/src/world/world.h b/src/world/world.h index 307f6a6..b549ea1 100644 --- a/src/world/world.h +++ b/src/world/world.h @@ -3,12 +3,14 @@ #include #include "../render/renderable.h" +#include "../item/item_stack.h" #define WORLD_HEIGHT_LIMIT 16 #define WORLD_WIDTH 10 // Temporary class MWindow; class Block; +class ItemStack; // Represents a world made up of blocks. @@ -26,8 +28,9 @@ class M2DWorld { // Renders every component block void render(MWindow& target) const; - // Breaking a block - void b_break(M2DWorld& world, int xPos, int yPos); + // Block updates + void b_break(int xPos, int yPos); + void b_place(int xPos, int yPos, ItemStack* i); }; #endif // M2D_WORLD_H