From 6b1dcc5df51df4a2d8b724187eb1bcdb4fd9df8b Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 14 Mar 2015 19:25:23 -0400 Subject: Added sound when you hit the ground Also split up components.cpp into files for each class, fixed a bug concerning falling off the screen when you change maps, and converted collision data into doubles. --- src/components/map_collision.cpp | 211 +++++++++++++++++++++++++++++++++++++ src/components/map_collision.h | 46 ++++++++ src/components/map_render.cpp | 39 +++++++ src/components/map_render.h | 19 ++++ src/components/physics_body.cpp | 65 ++++++++++++ src/components/physics_body.h | 20 ++++ src/components/player_physics.cpp | 117 ++++++++++++++++++++ src/components/player_physics.h | 25 +++++ src/components/player_sprite.cpp | 60 +++++++++++ src/components/player_sprite.h | 23 ++++ src/components/simple_collider.cpp | 14 +++ src/components/simple_collider.h | 18 ++++ src/components/static_image.cpp | 11 ++ src/components/static_image.h | 18 ++++ src/components/user_movement.cpp | 100 ++++++++++++++++++ src/components/user_movement.h | 19 ++++ 16 files changed, 805 insertions(+) create mode 100644 src/components/map_collision.cpp create mode 100644 src/components/map_collision.h create mode 100644 src/components/map_render.cpp create mode 100644 src/components/map_render.h create mode 100644 src/components/physics_body.cpp create mode 100644 src/components/physics_body.h create mode 100644 src/components/player_physics.cpp create mode 100644 src/components/player_physics.h create mode 100644 src/components/player_sprite.cpp create mode 100644 src/components/player_sprite.h create mode 100644 src/components/simple_collider.cpp create mode 100644 src/components/simple_collider.h create mode 100644 src/components/static_image.cpp create mode 100644 src/components/static_image.h create mode 100644 src/components/user_movement.cpp create mode 100644 src/components/user_movement.h (limited to 'src/components') diff --git a/src/components/map_collision.cpp b/src/components/map_collision.cpp new file mode 100644 index 0000000..f385320 --- /dev/null +++ b/src/components/map_collision.cpp @@ -0,0 +1,211 @@ +#include "map_collision.h" +#include "map.h" +#include "game.h" + +MapCollisionComponent::MapCollisionComponent(const Map& map) : map(map) +{ + addCollision(-6, 0, GAME_WIDTH, Direction::left, (map.getLeftMap() == nullptr) ? Collision::Type::wrap : Collision::Type::teleport); + addCollision(GAME_WIDTH+6, 0, GAME_WIDTH, Direction::right, (map.getRightMap() == nullptr) ? Collision::Type::reverse : Collision::Type::teleport); + + for (int i=0; i 0) && (tile < 28) && (!((tile >= 5) && (tile <= 7)))) + { + addCollision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::right, Collision::Type::wall); + addCollision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::left, Collision::Type::wall); + addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::wall); + addCollision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::up, Collision::Type::wall); + } else if ((tile >= 5) && (tile <= 7)) + { + addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::platform); + } else if (tile == 42) + { + addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::danger); + } + } +} + +void MapCollisionComponent::addCollision(double axis, double lower, double + upper, Direction dir, Collision::Type type) +{ + std::list::iterator it; + + switch (dir) + { + case Direction::up: + it = up_collisions.begin(); + for (; it!=up_collisions.end(); it++) + { + if (it->axis < axis) break; + } + + up_collisions.insert(it, {axis, lower, upper, type}); + + break; + case Direction::down: + it = down_collisions.begin(); + for (; it!=down_collisions.end(); it++) + { + if (it->axis > axis) break; + } + + down_collisions.insert(it, {axis, lower, upper, type}); + + break; + case Direction::left: + it = left_collisions.begin(); + for (; it!=left_collisions.end(); it++) + { + if (it->axis < axis) break; + } + + left_collisions.insert(it, {axis, lower, upper, type}); + + break; + case Direction::right: + it = right_collisions.begin(); + for (; it!=right_collisions.end(); it++) + { + if (it->axis > axis) break; + } + + right_collisions.insert(it, {axis, lower, upper, type}); + + break; + } +} + +void MapCollisionComponent::detectCollision(Game& game, Entity&, Entity& collider, std::pair old_position) +{ + if (collider.position.first < old_position.first) + { + for (auto collision : left_collisions) + { + if (collision.axis > old_position.first) continue; + if (collision.axis < collider.position.first) break; + + if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper)) + { + // We have a collision! + processCollision(game, collider, collision, Direction::left, old_position); + + break; + } + } + } else if (collider.position.first > old_position.first) + { + for (auto collision : right_collisions) + { + if (collision.axis < old_position.first+collider.size.first) continue; + if (collision.axis > collider.position.first+collider.size.first) break; + + if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper)) + { + // We have a collision! + processCollision(game, collider, collision, Direction::right, old_position); + + break; + } + } + } + + if (collider.position.second < old_position.second) + { + for (auto collision : up_collisions) + { + if (collision.axis > old_position.second) continue; + if (collision.axis < collider.position.second) break; + + if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper)) + { + // We have a collision! + processCollision(game, collider, collision, Direction::up, old_position); + + break; + } + } + } else if (collider.position.second > old_position.second) + { + for (auto collision : down_collisions) + { + if (collision.axis < old_position.second+collider.size.second) continue; + if (collision.axis > collider.position.second+collider.size.second) break; + + if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper)) + { + // We have a collision! + processCollision(game, collider, collision, Direction::down, old_position); + + break; + } + } + } +} + +void MapCollisionComponent::processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair old_position) +{ + if (collision.type == Collision::Type::wall) + { + if (dir == Direction::left) + { + collider.position.first = collision.axis; + collider.send(game, Message::Type::stopMovingHorizontally); + } else if (dir == Direction::right) + { + collider.position.first = collision.axis - collider.size.first; + collider.send(game, Message::Type::stopMovingHorizontally); + } else if (dir == Direction::up) + { + collider.position.second = collision.axis; + collider.send(game, Message::Type::stopMovingVertically); + } else if (dir == Direction::down) + { + collider.position.second = collision.axis - collider.size.second; + collider.send(game, Message::Type::hitTheGround); + } + } else if (collision.type == Collision::Type::wrap) + { + if (dir == Direction::left) + { + collider.position.first = GAME_WIDTH-collider.size.first/2; + } else if (dir == Direction::right) + { + collider.position.first = -collider.size.first/2; + } else if (dir == Direction::up) + { + collider.position.second = GAME_HEIGHT-collider.size.second/2-1; + } else if (dir == Direction::down) + { + collider.position.second = -collider.size.second/2; + } + } else if (collision.type == Collision::Type::teleport) + { + if (dir == Direction::left) + { + game.loadMap(*map.getLeftMap(), std::make_pair(GAME_WIDTH-collider.size.first/2, old_position.second)); + } else if (dir == Direction::right) + { + game.loadMap(*map.getRightMap(), std::make_pair(-collider.size.first/2, old_position.second)); + } + } else if (collision.type == Collision::Type::reverse) + { + if (dir == Direction::right) + { + collider.position.first = collision.axis - collider.size.first; + collider.send(game, Message::Type::walkLeft); + } + } else if (collision.type == Collision::Type::platform) + { + Message msg(Message::Type::drop); + msg.dropAxis = collision.axis; + + collider.send(game, msg); + } else if (collision.type == Collision::Type::danger) + { + game.playerDie(); + } +} diff --git a/src/components/map_collision.h b/src/components/map_collision.h new file mode 100644 index 0000000..3b718b6 --- /dev/null +++ b/src/components/map_collision.h @@ -0,0 +1,46 @@ +#ifndef MAP_COLLISION_H +#define MAP_COLLISION_H + +#include "entity.h" +#include + +class Map; +class Game; + +class MapCollisionComponent : public Component { + public: + MapCollisionComponent(const Map& map); + void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair old_position); + + private: + enum class Direction { + up, left, down, right + }; + + struct Collision { + enum class Type { + wall, + wrap, + teleport, + reverse, + platform, + danger + }; + + double axis; + double lower; + double upper; + Type type; + }; + + void addCollision(double axis, double lower, double upper, Direction dir, Collision::Type type); + void processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair old_position); + + std::list left_collisions; + std::list right_collisions; + std::list up_collisions; + std::list down_collisions; + const Map& map; +}; + +#endif diff --git a/src/components/map_render.cpp b/src/components/map_render.cpp new file mode 100644 index 0000000..d93afe6 --- /dev/null +++ b/src/components/map_render.cpp @@ -0,0 +1,39 @@ +#include "map_render.h" +#include "map.h" +#include "game.h" + +MapRenderComponent::MapRenderComponent(const Map& map) : screen(GAME_WIDTH, GAME_HEIGHT) +{ + screen.fill(screen.entirety(), 0, 0, 0); + + Texture tiles("../res/tiles.png"); + + for (int i=0; i 0) + { + screen.blit(tiles, src, dst); + } + } + + Texture font("../res/font.bmp"); + const char* map_name = map.getTitle(); + int start_x = (40/2) - (strlen(map_name)/2); + for (size_t i=0; i TERMINAL_VELOCITY_X) velocity.first = TERMINAL_VELOCITY_X; + if (velocity.second < -TERMINAL_VELOCITY_Y) velocity.second = -TERMINAL_VELOCITY_Y; + if (velocity.second > TERMINAL_VELOCITY_Y) velocity.second = TERMINAL_VELOCITY_Y; + + // Do the movement + entity.position.first += velocity.first * dt; + entity.position.second += velocity.second * dt; +} + +void PhysicsBodyComponent::detectCollision(Game& game, Entity& entity, Entity& collider, std::pair old_position) +{ + // If already colliding, do nothing! + if ((old_position.first + collider.size.first > entity.position.first) + && (old_position.first < entity.position.first + entity.size.first) + && (old_position.second + collider.size.second > entity.position.second) + && (old_position.second < entity.position.second + entity.size.second)) + { + return; + } + + // If newly colliding, SHOCK AND HORROR! + if ((collider.position.first + collider.size.first > entity.position.first) + && (collider.position.first < entity.position.first + entity.size.first) + && (collider.position.second + collider.size.second > entity.position.second) + && (collider.position.second < entity.position.second + entity.size.second)) + { + Message msg(Message::Type::collision); + msg.collisionEntity = &collider; + + entity.send(game, msg); + } +} diff --git a/src/components/physics_body.h b/src/components/physics_body.h new file mode 100644 index 0000000..079cc51 --- /dev/null +++ b/src/components/physics_body.h @@ -0,0 +1,20 @@ +#ifndef PHYSICS_BODY_H +#define PHYSICS_BODY_H + +#include "entity.h" +#include + +class Game; + +class PhysicsBodyComponent : public Component { + public: + void receive(Game& game, Entity& entity, const Message& msg); + void tick(Game& game, Entity& entity, double dt); + void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair old_position); + + protected: + std::pair velocity; + std::pair accel; +}; + +#endif diff --git a/src/components/player_physics.cpp b/src/components/player_physics.cpp new file mode 100644 index 0000000..1be43b6 --- /dev/null +++ b/src/components/player_physics.cpp @@ -0,0 +1,117 @@ +#include "player_physics.h" +#include "muxer.h" +#include "game.h" + +#define JUMP_VELOCITY(h, l) (-2 * (h) / (l)) +#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l)) + +PlayerPhysicsComponent::PlayerPhysicsComponent() +{ + jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3); + jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3); + jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233); + + accel.second = jump_gravity_short; +} + +void PlayerPhysicsComponent::receive(Game&, Entity& entity, const Message& msg) +{ + if (msg.type == Message::Type::walkLeft) + { + velocity.first = -90; + direction = -1; + } else if (msg.type == Message::Type::walkRight) + { + velocity.first = 90; + direction = 1; + } else if (msg.type == Message::Type::stopWalking) + { + velocity.first = 0.0; + direction = 0; + } else if (msg.type == Message::Type::stopMovingHorizontally) + { + velocity.first = 0.0; + } else if (msg.type == Message::Type::stopMovingVertically) + { + velocity.second = 0.0; + } else if (msg.type == Message::Type::hitTheGround) + { + if (isFalling) + { + playSound("../res/Randomize27.wav", 0.05); + isFalling = false; + } + + velocity.second = 0.0; + } else if (msg.type == Message::Type::jump) + { + playSound("../res/Randomize87.wav", 0.25); + + velocity.second = jump_velocity; + accel.second = jump_gravity; + } else if (msg.type == Message::Type::stopJump) + { + accel.second = jump_gravity_short; + } else if (msg.type == Message::Type::canDrop) + { + canDrop = true; + } else if (msg.type == Message::Type::cantDrop) + { + canDrop = false; + } else if (msg.type == Message::Type::drop) + { + if (canDrop) + { + canDrop = false; + } else { + entity.position.second = msg.dropAxis - entity.size.second; + velocity.second = 0; + } + } else if (msg.type == Message::Type::die) + { + frozen = true; + } else if (msg.type == Message::Type::stopDying) + { + frozen = false; + } +} + +void PlayerPhysicsComponent::tick(Game& game, Entity& entity, double dt) +{ + // If frozen, do nothing + if (frozen) + { + return; + } + + // Continue walking even if blocked earlier + if (velocity.first == 0) + { + if (direction < 0) + { + velocity.first = -90; + } else if (direction > 0) + { + velocity.first = 90; + } + } + + // Increase gravity at the height of jump + if ((accel.second == jump_gravity) && (velocity.second >= 0)) + { + accel.second = jump_gravity_short; + } + + // Do the movement + std::pair old_position = entity.position; + PhysicsBodyComponent::tick(game, entity, dt); + + // Check for collisions + game.detectCollision(entity, old_position); + + // Are we moving due to gravity? + if (velocity.second != 0.0) + { + isFalling = true; + } +} diff --git a/src/components/player_physics.h b/src/components/player_physics.h new file mode 100644 index 0000000..26f1fae --- /dev/null +++ b/src/components/player_physics.h @@ -0,0 +1,25 @@ +#ifndef PLAYER_PHYSICS_H +#define PLAYER_PHYSICS_H + +#include "entity.h" +#include "physics_body.h" + +class Game; + +class PlayerPhysicsComponent : public PhysicsBodyComponent { + public: + PlayerPhysicsComponent(); + void tick(Game& game, Entity& entity, double dt); + void receive(Game& game, Entity& entity, const Message& msg); + + private: + double jump_velocity; + double jump_gravity; + double jump_gravity_short; + int direction = 0; + bool canDrop = false; + bool frozen = false; + bool isFalling = false; +}; + +#endif diff --git a/src/components/player_sprite.cpp b/src/components/player_sprite.cpp new file mode 100644 index 0000000..2814852 --- /dev/null +++ b/src/components/player_sprite.cpp @@ -0,0 +1,60 @@ +#include "player_sprite.h" + +PlayerSpriteComponent::PlayerSpriteComponent() : sprite("../res/Starla.png") +{ + +} + +void PlayerSpriteComponent::render(Game&, Entity& entity, Texture& buffer) +{ + animFrame++; + + int frame = 0; + if (isMoving) + { + frame += 2; + + if (animFrame % 20 < 10) + { + frame += 2; + } + } + + if (facingLeft) + { + frame++; + } + + double alpha = 1.0; + if (dying && (animFrame % 4 < 2)) + { + alpha = 0.0; + } + + Rectangle src_rect {frame*10, 0, 10, 12}; + Rectangle dst_rect {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second}; + buffer.blit(sprite, src_rect, dst_rect, alpha); +} + +void PlayerSpriteComponent::receive(Game&, Entity&, const Message& msg) +{ + if (msg.type == Message::Type::walkLeft) + { + facingLeft = true; + isMoving = true; + } else if (msg.type == Message::Type::walkRight) + { + facingLeft = false; + isMoving = true; + } else if (msg.type == Message::Type::stopWalking) + { + isMoving = false; + } else if (msg.type == Message::Type::die) + { + dying = true; + isMoving = false; + } else if (msg.type == Message::Type::stopDying) + { + dying = false; + } +} diff --git a/src/components/player_sprite.h b/src/components/player_sprite.h new file mode 100644 index 0000000..b1ac0af --- /dev/null +++ b/src/components/player_sprite.h @@ -0,0 +1,23 @@ +#ifndef PLAYER_SPRITE_H +#define PLAYER_SPRITE_H + +#include "entity.h" +#include "renderer.h" + +class Game; + +class PlayerSpriteComponent : public Component { + public: + PlayerSpriteComponent(); + void render(Game& game, Entity& entity, Texture& buffer); + void receive(Game& game, Entity& entity, const Message& msg); + + private: + Texture sprite; + int animFrame = 0; + bool facingLeft = false; + bool isMoving = false; + bool dying = false; +}; + +#endif diff --git a/src/components/simple_collider.cpp b/src/components/simple_collider.cpp new file mode 100644 index 0000000..f4b414e --- /dev/null +++ b/src/components/simple_collider.cpp @@ -0,0 +1,14 @@ +#include "simple_collider.h" + +SimpleColliderComponent::SimpleColliderComponent(std::function callback) : callback(callback) +{ + +} + +void SimpleColliderComponent::receive(Game& game, Entity&, const Message& msg) +{ + if (msg.type == Message::Type::collision) + { + callback(game, *msg.collisionEntity); + } +} diff --git a/src/components/simple_collider.h b/src/components/simple_collider.h new file mode 100644 index 0000000..15d78cf --- /dev/null +++ b/src/components/simple_collider.h @@ -0,0 +1,18 @@ +#ifndef SIMPLE_COLLIDER_H +#define SIMPLE_COLLIDER_H + +#include "entity.h" +#include + +class Game; + +class SimpleColliderComponent : public Component { + public: + SimpleColliderComponent(std::function callback); + void receive(Game& game, Entity& entity, const Message& msg); + + private: + std::function callback; +}; + +#endif diff --git a/src/components/static_image.cpp b/src/components/static_image.cpp new file mode 100644 index 0000000..9fa8dca --- /dev/null +++ b/src/components/static_image.cpp @@ -0,0 +1,11 @@ +#include "static_image.h" + +StaticImageComponent::StaticImageComponent(const char* filename) : sprite(Texture(filename)) +{ + +} + +void StaticImageComponent::render(Game&, Entity& entity, Texture& buffer) +{ + buffer.blit(sprite, sprite.entirety(), {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second}); +} diff --git a/src/components/static_image.h b/src/components/static_image.h new file mode 100644 index 0000000..2dec78b --- /dev/null +++ b/src/components/static_image.h @@ -0,0 +1,18 @@ +#ifndef STATIC_IMAGE_H +#define STATIC_IMAGE_H + +#include "entity.h" +#include "renderer.h" + +class Game; + +class StaticImageComponent : public Component { + public: + StaticImageComponent(const char* filename); + void render(Game& game, Entity& entity, Texture& buffer); + + private: + Texture sprite; +}; + +#endif diff --git a/src/components/user_movement.cpp b/src/components/user_movement.cpp new file mode 100644 index 0000000..e499fee --- /dev/null +++ b/src/components/user_movement.cpp @@ -0,0 +1,100 @@ +#include "user_movement.h" +#include "renderer.h" + +void UserMovementComponent::input(Game& game, Entity& entity, int key, int action) +{ + if (action == GLFW_PRESS) + { + if (key == GLFW_KEY_LEFT) + { + holdingLeft = true; + + if (!frozen) + { + entity.send(game, Message::Type::walkLeft); + } + } else if (key == GLFW_KEY_RIGHT) + { + holdingRight = true; + + if (!frozen) + { + entity.send(game, Message::Type::walkRight); + } + } else if (key == GLFW_KEY_UP) + { + if (!frozen) + { + entity.send(game, Message::Type::jump); + } + } else if (key == GLFW_KEY_DOWN) + { + if (!frozen) + { + entity.send(game, Message::Type::canDrop); + } + } + } else if (action == GLFW_RELEASE) + { + if (key == GLFW_KEY_LEFT) + { + holdingLeft = false; + + if (!frozen) + { + if (holdingRight) + { + entity.send(game, Message::Type::walkRight); + } else { + entity.send(game, Message::Type::stopWalking); + } + } + } else if (key == GLFW_KEY_RIGHT) + { + holdingRight = false; + + if (!frozen) + { + if (holdingLeft) + { + entity.send(game, Message::Type::walkLeft); + } else { + entity.send(game, Message::Type::stopWalking); + } + } + } else if (key == GLFW_KEY_DOWN) + { + if (!frozen) + { + entity.send(game, Message::Type::cantDrop); + } + } else if (key == GLFW_KEY_UP) + { + if (!frozen) + { + entity.send(game, Message::Type::stopJump); + } + } + } +} + +void UserMovementComponent::receive(Game& game, Entity& entity, const Message& msg) +{ + if (msg.type == Message::Type::die) + { + frozen = true; + + entity.send(game, Message::Type::stopWalking); + } else if (msg.type == Message::Type::stopDying) + { + frozen = false; + + if (holdingLeft) + { + entity.send(game, Message::Type::walkLeft); + } else if (holdingRight) + { + entity.send(game, Message::Type::walkRight); + } + } +} diff --git a/src/components/user_movement.h b/src/components/user_movement.h new file mode 100644 index 0000000..1bcf05e --- /dev/null +++ b/src/components/user_movement.h @@ -0,0 +1,19 @@ +#ifndef USER_MOVEMENT_H +#define USER_MOVEMENT_H + +#include "entity.h" + +class Game; + +class UserMovementComponent : public Component { + public: + void input(Game& game, Entity& entity, int key, int action); + void receive(Game&, Entity&, const Message& msg); + + private: + bool holdingLeft = false; + bool holdingRight = false; + bool frozen = false; +}; + +#endif -- cgit 1.4.1