Skip to content

Commit

Permalink
episode 10 - the level class - part 4
Browse files Browse the repository at this point in the history
  • Loading branch information
mark committed Sep 29, 2015
1 parent c2ce873 commit 2d4ffc0
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 6 deletions.
22 changes: 21 additions & 1 deletion maps/Map 1.tmx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" renderorder="right-down" width="20" height="16" tilewidth="16" tileheight="16" nextobjectid="1">
<map version="1.0" orientation="orthogonal" renderorder="right-down" width="20" height="16" tilewidth="16" tileheight="16" nextobjectid="18">
<tileset firstgid="1" name="PrtCave" tilewidth="16" tileheight="16">
<image source="../content/tilesets/PrtCave.png" width="256" height="80"/>
</tileset>
Expand Down Expand Up @@ -651,4 +651,24 @@
<tile gid="0"/>
</data>
</layer>
<objectgroup name="collisions">
<object id="1" x="144.823" y="17.4994" width="14.1805" height="14.4823"/>
<object id="2" x="144.219" y="64.8685" width="15.3874" height="14.4823"/>
<object id="3" x="111.634" y="79.9541" width="80.2559" height="15.3874"/>
<object id="4" x="58.2308" y="28.0594" width="23.5337" height="107.41"/>
<object id="5" x="53.4033" y="125.513" width="60.041" height="16.5943"/>
<object id="6" x="107.41" y="126.116" width="6.03427" height="58.2308"/>
<object id="7" x="128.53" y="144.219" width="47.0673" height="15.6891"/>
<object id="8" x="192.493" y="145.124" width="15.3874" height="14.1805"/>
<object id="9" x="209.088" y="128.228" width="31.0765" height="14.784"/>
<object id="11" x="174.089" y="25.6457" width="12.0685" height="37.7142"/>
<object id="14" x="238.052" y="98.6604" width="11.4651" height="32.2834"/>
<object id="15" x="114.35" y="185.252" width="93.833" height="13.2754"/>
<object id="16" x="206.372" y="161.719" width="7.84456" height="25.6457"/>
</objectgroup>
<objectgroup color="#00ff00" name="spawn points">
<object id="17" name="player" x="158.337" y="136.764" width="2.57298" height="2.77091">
<ellipse/>
</object>
</objectgroup>
</map>
57 changes: 57 additions & 0 deletions notes/episode 10 - the level class - part 4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
=====================================================
Remaking Cavestory in C++
Episode 10 - The level class - Part 4
By: Limeoats
Website: www.limeoats.com
Twitter: @Limeoats
Github: https://github.com/Limeoats/cavestory-development
Reddit: http://www.reddit.com/r/Limeoats
=====================================================


=====================================================
Problem
=====================================================
-We need gravity to be applied to our character
-Collision!
-Specify spawn point in Tiled



=====================================================
Details
=====================================================
-Gravity constants:
GRAVITY = 0.002f;
GRAVITY_CAP = 0.8f;

-Spawn point: 280, 252


=====================================================
Solution
=====================================================
-Add gravity to the player
-Create "side" namespace in globals
-Create the rectangle class
-Add collisionRects vector to Level
-Draw the collisions in Tiled
-Parse the collisions
-Check tile collisions!
-Bounding box
-getCollisionSide in sprite class
-handleTileCollisions in player class
-Finally, add it all to the game class!!
-Draw spawn point in Tiled
-Parse it and save it in spawn point
-Change spawn point in game class to use it

=====================================================
Next time
=====================================================
-We finally finished the level class!!!!!!!!
...or did we?

-SLOPES
-A very complicated subject

19 changes: 19 additions & 0 deletions source/headers/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,25 @@ namespace globals {
const float SPRITE_SCALE = 2.0f;
}

namespace sides {
enum Side {
TOP,
BOTTOM,
LEFT,
RIGHT,
NONE
};

inline Side getOppositeSide(Side side) {
return
side == TOP ? BOTTOM :
side == BOTTOM ? TOP :
side == LEFT ? RIGHT :
side == RIGHT ? LEFT :
NONE;
}
}


enum Direction {
LEFT,
Expand Down
6 changes: 6 additions & 0 deletions source/headers/level.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "globals.h"
#include "tile.h"
#include "rectangle.h"

class Graphics;
struct SDL_Texture;
Expand All @@ -20,6 +21,10 @@ class Level {
void update(int elapsedTime);
void draw(Graphics &graphics);

std::vector<Rectangle> checkTileCollisions(const Rectangle &other);

const Vector2 getPlayerSpawnPoint() const;

private:
std::string _mapName;
Vector2 _spawnPoint;
Expand All @@ -31,6 +36,7 @@ class Level {

std::vector<Tile> _tileList;
std::vector<Tileset> _tilesets;
std::vector<Rectangle> _collisionRects;

/* void loadMap
* Loads a map
Expand Down
10 changes: 9 additions & 1 deletion source/headers/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Graphics;
class Player : public AnimatedSprite {
public:
Player();
Player(Graphics &graphics, float x, float y);
Player(Graphics &graphics, Vector2 spawnPoint);
void draw(Graphics &graphics);
void update(float elapsedTime);

Expand All @@ -30,10 +30,18 @@ class Player : public AnimatedSprite {

virtual void animationDone(std::string currentAnimation);
virtual void setupAnimations();

void handleTileCollisions(std::vector<Rectangle> &others);

const float getX() const;
const float getY() const;

private:
float _dx, _dy;

Direction _facing;

bool _grounded;
};

#endif
56 changes: 56 additions & 0 deletions source/headers/rectangle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#ifndef RECTANGLE_H
#define RECTANGLE_H

#include "globals.h"

class Rectangle {
public:
Rectangle() {}

Rectangle(int x, int y, int width, int height) :
_x(x),
_y(y),
_width(width),
_height(height)
{}

const int getCenterX() const { return this->_x + this->_width / 2; }
const int getCenterY() const { return this->_y + this->_height / 2; }

const int getLeft() const { return this->_x; }
const int getRight() const { return this->_x + this->_width; }
const int getTop() const { return this->_y; }
const int getBottom() const { return this->_y + this->_height; }

const int getWidth() const { return this->_width; }
const int getHeight() const { return this->_height; }

const int getSide(const sides::Side side) const {
return
side == sides::LEFT ? this->getLeft() :
side == sides::RIGHT ? this->getRight() :
side == sides::TOP ? this->getTop() :
side == sides::BOTTOM ? this->getBottom() :
sides::NONE;
}

//bool collidesWith
//Takes in another Rectangle and checks if the two are colliding
const bool collidesWith(const Rectangle &other) const {
return
this->getRight() >= other.getLeft() &&
this->getLeft() <= other.getRight() &&
this->getTop() <= other.getBottom() &&
this->getBottom() >= other.getTop();
}

const bool isValidRectangle() const {
return (this->_x >= 0 && this->_y >= 0 && this->_width >= 0 && this->_height >= 0);
}

private:
int _x, _y, _width, _height;
};


#endif
8 changes: 8 additions & 0 deletions source/headers/sprite.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

#include <string>

#include "rectangle.h"
#include "globals.h"

class Graphics;

/* Sprite class
Expand All @@ -20,10 +23,15 @@ class Sprite {
virtual void update();
void draw(Graphics &graphics, int x, int y);

const Rectangle getBoundingBox() const;
const sides::Side getCollisionSide(Rectangle &other) const;

protected:
SDL_Rect _sourceRect;
SDL_Texture* _spriteSheet;

Rectangle _boundingBox;

float _x, _y;
private:
};
Expand Down
9 changes: 8 additions & 1 deletion source/src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ void Game::gameLoop() {
Input input;
SDL_Event event;

this->_player = Player(graphics, 100, 100);
this->_level = Level("Map 1", Vector2(100, 100), graphics);
this->_player = Player(graphics, this->_level.getPlayerSpawnPoint());

int LAST_UPDATE_TIME = SDL_GetTicks();
//Start the game loop
Expand Down Expand Up @@ -83,4 +83,11 @@ void Game::draw(Graphics &graphics) {
void Game::update(float elapsedTime) {
this->_player.update(elapsedTime);
this->_level.update(elapsedTime);

//Check collisions
std::vector<Rectangle> others;
if ((others = this->_level.checkTileCollisions(this->_player.getBoundingBox())).size() > 0) {
//Player collided with at least one tile. Handle it.
this->_player.handleTileCollisions(others);
}
}
65 changes: 65 additions & 0 deletions source/src/level.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,56 @@ void Level::loadMap(std::string mapName, Graphics &graphics) {
}
}

//Parse out the collisions
XMLElement* pObjectGroup = mapNode->FirstChildElement("objectgroup");
if (pObjectGroup != NULL) {
while (pObjectGroup) {
const char* name = pObjectGroup->Attribute("name");
std::stringstream ss;
ss << name;
if (ss.str() == "collisions") {
XMLElement* pObject = pObjectGroup->FirstChildElement("object");
if (pObject != NULL) {
while (pObject) {
float x, y, width, height;
x = pObject->FloatAttribute("x");
y = pObject->FloatAttribute("y");
width = pObject->FloatAttribute("width");
height = pObject->FloatAttribute("height");
this->_collisionRects.push_back(Rectangle(
std::ceil(x) * globals::SPRITE_SCALE,
std::ceil(y) * globals::SPRITE_SCALE,
std::ceil(width) * globals::SPRITE_SCALE,
std::ceil(height) * globals::SPRITE_SCALE
));

pObject = pObject->NextSiblingElement("object");
}
}
}
//Other objectgroups go here with an else if (ss.str() == "whatever")
else if (ss.str() == "spawn points") {
XMLElement* pObject = pObjectGroup->FirstChildElement("object");
if (pObject != NULL) {
while (pObject) {
float x = pObject->FloatAttribute("x");
float y = pObject->FloatAttribute("y");
const char* name = pObject->Attribute("name");
std::stringstream ss;
ss << name;
if (ss.str() == "player") {
this->_spawnPoint = Vector2(std::ceil(x) * globals::SPRITE_SCALE,
std::ceil(y) * globals::SPRITE_SCALE);
}

pObject = pObject->NextSiblingElement("object");
}
}
}

pObjectGroup = pObjectGroup->NextSiblingElement("objectgroup");
}
}
}

void Level::update(int elapsedTime) {
Expand All @@ -160,3 +210,18 @@ void Level::draw(Graphics &graphics) {
this->_tileList.at(i).draw(graphics);
}
}

std::vector<Rectangle> Level::checkTileCollisions(const Rectangle &other) {
std::vector<Rectangle> others;
for (int i = 0; i < this->_collisionRects.size(); i++) {
if (this->_collisionRects.at(i).collidesWith(other)) {
others.push_back(this->_collisionRects.at(i));
}
}
return others;
}

const Vector2 Level::getPlayerSpawnPoint() const {
return this->_spawnPoint;
}

Loading

0 comments on commit 2d4ffc0

Please sign in to comment.