From 8028320cef26978a52e47a6076b2467a71e3f941 Mon Sep 17 00:00:00 2001
From: Tamir Atias <engine.games@gmail.com>
Date: Tue, 17 Apr 2012 20:23:48 +0300
Subject: [PATCH] [Add] Tile based collisions.

---
 Data/Img/CollisionTileset.png     | Bin 0 -> 921 bytes
 Data/Map/Ugly.tmx                 |   8 ++++
 src/Actor/Actor.cpp               |  15 ++++--
 src/Actor/Actor.h                 |   6 ++-
 src/Actor/NPC.cpp                 |   2 +-
 src/Actor/NPC.h                   |   2 +-
 src/Actor/Player.cpp              |   9 +---
 src/Actor/Player.h                |   2 +-
 src/Animation/AnimatingSprite.cpp |   4 ++
 src/Animation/AnimatingSprite.h   |   6 +++
 src/Level/Level.cpp               |  73 ++++++++++++++++++++++++++++++
 src/Level/Level.h                 |   3 ++
 src/Main/Game.cpp                 |   4 +-
 13 files changed, 117 insertions(+), 17 deletions(-)
 create mode 100644 Data/Img/CollisionTileset.png

diff --git a/Data/Img/CollisionTileset.png b/Data/Img/CollisionTileset.png
new file mode 100644
index 0000000000000000000000000000000000000000..0eabc26af41e07f9f3bd32c111a8d199fcb2f5cf
GIT binary patch
literal 921
zcmV;K17`e*P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02*{fSaefwW^{L9
za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv0009BNkl<ZcwXh3F;>Gc3_v}0>=D>lIRFDA
zM_}wR7<-c*fsrFHGBPqUFmx*e4~o>d#BO3+wk11GhP=XirR0ChvMi_SsMJwk+avt6
zm`kbEuTswn;5Untpy83b8}TJcFyJ8q_I=1NLBa(*4E&8f=jSY81RkS*nDpi-!2v%m
zU~W0V1Me0vl<?T(@)&^k3m8h+G$p}?f5(J3cK_kR$Ic0DNKk4GOWX^lICw?)E7#zK
z1+*3k9sDZ=K0F1?(zu04h=h+5&_%-5D4VA>9TMQ<1zbpgP<xm}VoZcj6JSUH0bg+4
zSCx<fpDti35;EcQ1k{$m0G}_QmINkv9swW$^1x27yYe}K5uQx|eozq!Har$P&I*s3
zm}!+Du~#T6VF<sbLi*mvDnKj}gy31HfN9x?guQDQMjkyucrgJNk&rGy7+zFBwuA!k
z;sTN-6oM}zAX)+}ZIDCWbX|c<9ZR;)Ylsk+L1$tk^yW@~+reW82Rk{~(Gi6&76BUW
zbQY)KhKbRJ$M>zsD@DctvDX3Kn|4J)CHS%ta2_RF!Uv4>tr7OcM*cidWg}o*!nd9l
z#o_BjfR+HGeht?_!yoYX5_A6Yf7FVA|7`!G)F-utEg`79fMLQTA7ZpGz?JQpn;bEs
z%0&R2&3UtZB?)B&bnsaGV1?(-_7x<^3!uXHOQd<WhkF9ia#&VCEd00x(G8KDfK>Rx
z5@ZDA!WWdlFTjR>%HGx4ODFqu;1yuQ?_$>Dz%J746R=9)6CefOPX`eRJOZTQ1tsJQ
zQ0mSoa`?jD)#Vws&9XX2Spx9k2z*FFS9tR9<B^cnM@SY>4W3y-l7Q;)wuJB=!_zd4
z7BCt3UIJ~S<&Y31U~=#b637B33!f>0Bw+IJ84`j5nt^vo2%H*u1vCdgF2P%$I0fKi
zuvLnjjB`F~Lq#ml#|0QqhMyjH;kv29pF@e@p@5lvX(}Ya7BDmTbL9FY^a5rIACk}s
vm^r*p!eZcE5>Nod!0Fnyn(brn+sp}ny`t7tLo&G600000NkvXXu0mjfZTX3K

literal 0
HcmV?d00001

diff --git a/Data/Map/Ugly.tmx b/Data/Map/Ugly.tmx
index e61661e..c074773 100644
--- a/Data/Map/Ugly.tmx
+++ b/Data/Map/Ugly.tmx
@@ -6,6 +6,9 @@
  <tileset firstgid="1" name="AwesomeTileset" tilewidth="64" tileheight="64">
   <image source="../Img/AwesomeTileset.png" width="256" height="128"/>
  </tileset>
+ <tileset firstgid="9" name="Collision" tilewidth="64" tileheight="64">
+  <image source="../Img/CollisionTileset.png" width="64" height="64"/>
+ </tileset>
  <layer name="Tile Layer 1" width="60" height="60">
   <data encoding="base64" compression="zlib">
    eJzt0MENgDAQA8EA13/NtHCBoFhiHvv3uMYYx4+qgA28vLy8vLzVbPfOVV2Nup/MtNv95o/Zkr1f/PfUewbFy8vLy8ubEC8vLy8vb0K8vLy8vLwJ8fLy8vLyJsTLy8vLy5sQLy8vLy9vQry8vLy8a703oRIWWw==
@@ -16,4 +19,9 @@
    eJztleEOgjAMBrcfwPu/sTGhSf06tDNCNd4lDZDNdrdOaK21xUXbr+sexnowb5F5mzzP5LuKe70uV1tTd/ej3+nYKmMz+a7C77Wtz/rR9zjqr+/bqK+jfFrz6v4enb/eHn03FzZP8/jQfbFcbfB8JeZr9a0v2t+R7yZ5/Bz9n2h/K1x9be+rY0fnWX09+j7wc6rfVx5/zqrO3JksyfgnsnsyE/9Ela9+QzTOYtb31Tqz8ey8farGaP/e8f0mMuvHNw++teAbwTcPvrXgG8E3D7614BvBNw++teAbwTcPvrXgG8E3D7614BvBNw++teAbwTcPvrXgG8E3D7614BvBNw++teAbwTcPvrXgG8E3D761/IrvDT5XCI0=
   </data>
  </layer>
+ <layer name="Collision" width="60" height="60">
+  <data encoding="base64" compression="zlib">
+   eJzt1MEKgCAMANBd/f8f7hripoSYh/cgarKNaKOIiPa6YhD3Z1VeJPFKv1Pa5N4/Z3Vfzv6wa77ZnG+db/8uVU5Vl32XWb9TqrlkOVVd1uemfc7i0U7O9ndUu9IPdhj9Z+wbAAAAAAAAAAAAAACwywOaowOg
+  </data>
+ </layer>
 </map>
diff --git a/src/Actor/Actor.cpp b/src/Actor/Actor.cpp
index 6c32dec..fc7828c 100644
--- a/src/Actor/Actor.cpp
+++ b/src/Actor/Actor.cpp
@@ -2,8 +2,11 @@
 
 #include "Actor.h"
 #include "../Sound/SoundEffect.h"
+#include "../Level/Level.h"
+
+Actor::Actor(const Level* level) {
+  _level = level;
 
-Actor::Actor(void) {
   _stepSFX[0] = sfxManager.Load("../Data/SFX/step_cloth1.wav");
   _stepSFX[1] = sfxManager.Load("../Data/SFX/step_cloth2.wav");
   _stepSFX[2] = sfxManager.Load("../Data/SFX/step_cloth3.wav");
@@ -54,10 +57,16 @@ void Actor::Update(float dt) {
   float oldX = x;
   float oldY = y;
 
-  // We should check for collisions now.
-
   Move(dt);
 
+  if(x != oldX || y != oldY) {
+    if(_level->CheckCollision(x, y, GetAnimation()->GetMaxWidth(), GetAnimation()->GetMaxHeight())) {
+      x = oldX;
+      y = oldY;
+      return;
+    }
+  }
+
   if(x != oldX || y != oldY) {
     GetAnimation()->SetCurrentAnimation(1);
 
diff --git a/src/Actor/Actor.h b/src/Actor/Actor.h
index 228c0fd..462af3f 100644
--- a/src/Actor/Actor.h
+++ b/src/Actor/Actor.h
@@ -6,6 +6,7 @@
 #include "../Math/Vec2.h"
 
 class SoundEffect;
+class Level;
 
 class Actor {
 public:
@@ -23,7 +24,7 @@ public:
     HURT
   };
 
-  Actor(void);
+  Actor(const Level* level);
   ~Actor(void);
 
   void LoadSprites(const String& basename);
@@ -47,6 +48,8 @@ protected:
 
   AnimatingSprite* GetAnimation(void);
 
+  const Level* _level;
+
   float _velocity;
 
   AnimatingSprite* _actorLeft;
@@ -61,6 +64,7 @@ protected:
   float y;
 
 private:
+
   SoundEffect* _stepSFX[4];
   int _lastStepSFXPlayed;
 
diff --git a/src/Actor/NPC.cpp b/src/Actor/NPC.cpp
index c344ab1..673b8fe 100644
--- a/src/Actor/NPC.cpp
+++ b/src/Actor/NPC.cpp
@@ -1,6 +1,6 @@
 #include "NPC.h"
 
-NPC::NPC(void) : Actor() {
+NPC::NPC(const Level* level) : Actor(level) {
 }
 
 NPC::~NPC(void) {
diff --git a/src/Actor/NPC.h b/src/Actor/NPC.h
index 3f96100..f5b3d61 100644
--- a/src/Actor/NPC.h
+++ b/src/Actor/NPC.h
@@ -4,7 +4,7 @@
 
 class NPC : public Actor {
 public:
-  NPC(void);
+  NPC(const Level* level);
   ~NPC(void);
 
   void Update(float dt);
diff --git a/src/Actor/Player.cpp b/src/Actor/Player.cpp
index 11a16c5..42dfeb2 100644
--- a/src/Actor/Player.cpp
+++ b/src/Actor/Player.cpp
@@ -1,7 +1,7 @@
 #include "Player.h"
 #include "../IO/Input.h"
 
-Player::Player(void) : Actor() {
+Player::Player(const Level* level) : Actor(level) {
   _direction = Actor::RIGHT;
 }
 
@@ -34,11 +34,4 @@ void Player::Move(float dt) {
     _direction = Actor::FRONT;
   }
 
-  if(KeyDown(SDLK_LSHIFT)) {
-    // Run!
-    _velocity += 3;
-  }
-  if(KeyUp(SDLK_LSHIFT)) {
-    _velocity -= 3;
-  }
 }
diff --git a/src/Actor/Player.h b/src/Actor/Player.h
index 3a4e67c..61f4c0e 100644
--- a/src/Actor/Player.h
+++ b/src/Actor/Player.h
@@ -7,7 +7,7 @@
 
 class Player : public Actor{
 public:
-  Player(void);
+  Player(const Level* level);
   ~Player(void);
 
   void Update(float dt);
diff --git a/src/Animation/AnimatingSprite.cpp b/src/Animation/AnimatingSprite.cpp
index ee384aa..8c625d3 100644
--- a/src/Animation/AnimatingSprite.cpp
+++ b/src/Animation/AnimatingSprite.cpp
@@ -49,6 +49,8 @@ void AnimatingSprite::Update(float dt) {
 
 
 void AnimatingSprite::LoadAnimatingSprite(const char* filename, const char* sequence, int frames, float animationSpeed) {
+  _maxWidth = 0;
+  _maxHeight = 0;
   for(int i = 0; i < frames; i++) {
     String tempFilename;
     tempFilename = "";
@@ -62,6 +64,8 @@ void AnimatingSprite::LoadAnimatingSprite(const char* filename, const char* sequ
     }
     _sprites[_spriteCounter] = new Sprite();
     _sprites[_spriteCounter]->LoadSprite((const char*)tempFilename);
+    if(_sprites[_spriteCounter]->GetWidth() > _maxWidth) _maxWidth = _sprites[_spriteCounter]->GetWidth();
+    if(_sprites[_spriteCounter]->GetHeight() > _maxHeight) _maxHeight = _sprites[_spriteCounter]->GetHeight();
     _spriteCounter++;
   }
   _numberOfFrames = frames;
diff --git a/src/Animation/AnimatingSprite.h b/src/Animation/AnimatingSprite.h
index d55cb8e..f45ed63 100644
--- a/src/Animation/AnimatingSprite.h
+++ b/src/Animation/AnimatingSprite.h
@@ -16,6 +16,9 @@ public:
   int GetTotalFrames(void)  { return _sequence->GetAnimation(_currentAnimation)->frameEnd; }
   Sprite* GetCurrentFrameSprite(void) { return _sprites[_currentFrame - 1]; }
 
+  int GetMaxWidth(void) const { return _maxWidth; }
+  int GetMaxHeight(void) const { return _maxHeight; }
+
   void Update(float dt);
 
   void Render(void);
@@ -34,4 +37,7 @@ private:
   int           _numberOfFrames;
 
   const char*   _currentAnimation;
+
+  int _maxWidth;
+  int _maxHeight;
 };
diff --git a/src/Level/Level.cpp b/src/Level/Level.cpp
index 2960fbd..e7706a2 100644
--- a/src/Level/Level.cpp
+++ b/src/Level/Level.cpp
@@ -13,6 +13,7 @@ Level::Level() {
   _tileWidth = 0;
   _tileHeight = 0;
   _bgm = NULL;
+  _collisions = NULL;
 }
 
 Level::~Level() {
@@ -26,6 +27,11 @@ Level::~Level() {
   }
   _tilesets.clear();
 
+  if(_collisions) {
+	delete[] _collisions;
+	_collisions = NULL;
+  }
+
   if(_bgm) {
     musicManager.Destroy(_bgm);
     _bgm = NULL;
@@ -59,8 +65,23 @@ bool Level::Load(const std::string& filename) {
     tilesetMap.insert(std::pair<const Tmx::Tileset*, Tileset*>(tmxTileset, tileset));
   }
 
+  _collisions = new bool[_width * _height];
+  for(int i = 0; i < (_width * _height); i++) {
+    _collisions[i] = false;
+  }
+
   for(int i = 0; i < map.GetNumLayers(); i++) {
     const Tmx::Layer* tmxLayer = map.GetLayer(i);
+	
+    if(!stricmp(tmxLayer->GetName().c_str(), "collision")) {
+      for(int x = 0; x < _width; x++) {
+        for(int y = 0; y < _height; y++) {
+          Tmx::MapTile tile = tmxLayer->GetTile(x, y);
+          _collisions[y * _width + x] = tile.gid != 0;
+        }
+      }
+      continue;
+    }
     
     Layer* layer = new Layer(
       tmxLayer->GetWidth(), tmxLayer->GetHeight(),
@@ -114,3 +135,55 @@ void Level::Draw(int xOffset, int yOffset) {
     (*i)->Draw(xOffset, yOffset);
   }
 }
+
+bool Level::CheckCollision(float x, float y, float w, float h) const {
+  if(x < 0.0f || x > (float)(_width * _tileWidth) ||
+     y < 0.0f || y > (float)(_height * _tileHeight)) {
+    return true;
+  }
+  
+  int tileX;
+  int tileY;
+  
+  // Check Top Left
+  tileX = (int)(x / (float)_tileWidth);
+  tileY = (int)(y / (float)_tileHeight);
+  if(tileX >= 0 && tileX < _width &&
+     tileY >= 0 && tileY < _height) {
+    if(_collisions[tileY * _width + tileX]) {
+      return true;
+    }
+  }
+
+  // Check Top Right
+  tileX = (int)((x + w) / (float)_tileWidth);
+  tileY = (int)(y / (float)_tileHeight);
+  if(tileX >= 0 && tileX < _width &&
+     tileY >= 0 && tileY < _height) {
+    if(_collisions[tileY * _width + tileX]) {
+      return true;
+    }
+  }
+
+  // Check Bottom Right
+  tileX = (int)((x + w) / (float)_tileWidth);
+  tileY = (int)((y + h) / (float)_tileHeight);
+  if(tileX >= 0 && tileX < _width &&
+     tileY >= 0 && tileY < _height) {
+    if(_collisions[tileY * _width + tileX]) {
+      return true;
+    }
+  }
+
+   // Check Bottom Left
+  tileX = (int)(x / (float)_tileWidth);
+  tileY = (int)((y + h) / (float)_tileHeight);
+  if(tileX >= 0 && tileX < _width &&
+     tileY >= 0 && tileY < _height) {
+    if(_collisions[tileY * _width + tileX]) {
+      return true;
+    }
+  }
+
+  return false;
+}
diff --git a/src/Level/Level.h b/src/Level/Level.h
index ce0a8fe..3f09c6d 100644
--- a/src/Level/Level.h
+++ b/src/Level/Level.h
@@ -24,6 +24,8 @@ public:
   int GetTileWidth() const { return _tileWidth; }
   int GetTileHeight() const { return _tileHeight; }
 
+  bool CheckCollision(float x, float y, float w, float h) const;
+
 private:
   int _width;
   int _height;
@@ -32,4 +34,5 @@ private:
   std::list<Layer*> _layers;
   std::list<Tileset*> _tilesets;
   Music* _bgm;
+  bool* _collisions;
 };
diff --git a/src/Main/Game.cpp b/src/Main/Game.cpp
index 09b69b0..1592f7e 100644
--- a/src/Main/Game.cpp
+++ b/src/Main/Game.cpp
@@ -16,9 +16,9 @@
 #include "Game.h"
 
 Game::Game(void) {
-  _player = new Player();
-  _NPC    = new NPC();
   _level  = new Level();
+  _player = new Player(_level);
+  _NPC    = new NPC(_level);
 
   _NPC->SetXY(30.0f, 30.0f);