diff --git a/Engine/BasicTypes.h b/Engine/BasicTypes.h
index cd87db912025e47f05f5668d597c66cc0e9050ed..1916c8157a62599fdbd147d1cbc3d32be47e3ff8 100644
--- a/Engine/BasicTypes.h
+++ b/Engine/BasicTypes.h
@@ -149,7 +149,9 @@ struct Vector
 	friend Vector operator*(Vector obj, const float& obj2) { obj *= obj2; return obj; }
 	friend Vector operator*(const float& obj, Vector obj2) { obj2 *= obj; return obj2; }
 
-	friend Vector operator/(const Vector& obj, const Vector& obj2) { return Vector(obj2.X / obj.X, obj2.Y / obj.Y, obj2.Z / obj.Z); }
+	friend Vector operator/(const Vector& obj, const Vector& obj2) { return Vector(obj.X / obj2.X, obj.Y / obj2.Y, obj.Z / obj2.Z); }
+	friend Vector operator/(const Vector& obj, const int obj2) { return Vector(obj.X / obj2, obj.Y / obj2, obj.Z / obj2); }
+	friend Vector operator/(const Vector& obj, const float obj2) { return Vector(obj.X / obj2, obj.Y / obj2, obj.Z / obj2); }
 
 	friend bool operator==(const Vector& obj, const Vector& obj2) { return obj2.X == obj.X && obj2.Y == obj.Y && obj2.Z == obj.Z; }
 
diff --git a/Engine/Core.h b/Engine/Core.h
index 3f7d4f2274cce868dbc77066d9cb2cbca97162ec..14d0ad3b3d766cc0420e7e750c776553de600218 100644
--- a/Engine/Core.h
+++ b/Engine/Core.h
@@ -18,47 +18,48 @@ void Exit();
 template <class T>
 class Ref : public RefHold
 {
+protected:
 	mutable T* Pointer;
 	mutable Data* DataPtr;
 public:
 	Ref() { Pointer = nullptr; DataPtr = nullptr; }
 	Ref(T* ptr) : Pointer(ptr) { 
-		DataPtr = dynamic_cast<Data*>(ptr);
-		if (DataPtr == nullptr) {
-			Pointer = nullptr;
+		this->DataPtr = dynamic_cast<Data*>(ptr);
+		if (this->DataPtr == nullptr) {
+			this->Pointer = nullptr;
 			return;
 		}
 		ObjectManager::AddRef(GetRecord(), this);
 	}
 
-	~Ref() {
+	virtual ~Ref() {
 		if(Pointer != nullptr) ObjectManager::RemoveRef(GetRecord(), this);
 		NullThis();
 	}
 
 	virtual const void NullThis() const {
-		Pointer = nullptr;
-		DataPtr = nullptr;
+		this->Pointer = nullptr;
+		this->DataPtr = nullptr;
 	}
 
 	virtual const RecordInt GetRecord() const override {
-		return DataPtr ? DataPtr->GetRecord() : RecordInt(0);
+		return this->DataPtr ? this->DataPtr->GetRecord() : RecordInt(0);
 	}
 
 	T* GetPointer() { return Pointer; }
 	
 	Ref(const Ref& old) { 
 		ObjectManager::AddRef(old->GetRecord(), this);
-		if (DataPtr != nullptr) ObjectManager::RemoveRef(GetRecord(), this);
-		Pointer = old.Pointer;
-		DataPtr = old.DataPtr;
+		if (this->DataPtr != nullptr) ObjectManager::RemoveRef(this->GetRecord(), this);
+		this->Pointer = old.Pointer;
+		this->DataPtr = old.DataPtr;
 	}
 
 	Ref& operator=(const Ref& old) {
 		ObjectManager::AddRef(old->GetRecord(), this);
-		if (DataPtr != nullptr) ObjectManager::RemoveRef(GetRecord(), this);
-		Pointer = old.Pointer;
-		DataPtr = old.DataPtr;
+		if (this->DataPtr != nullptr) ObjectManager::RemoveRef(this->GetRecord(), this);
+		this->Pointer = old.Pointer;
+		this->DataPtr = old.DataPtr;
 		return *this;
 	}
 
@@ -71,6 +72,31 @@ public:
 	bool operator!=(const void* other) { return Pointer != other; }
 };
 
+template <class T>
+class RefWeak : public Ref<T>
+{
+	const bool bWeak = true;
+
+public:
+	RefWeak(T* ptr) : Ref<T>(ptr) {}
+	RefWeak() : Ref<T>() {}
+
+	RefWeak(const RefWeak& old) {
+		ObjectManager::AddRef(old->GetRecord(), this);
+		if (this->DataPtr != nullptr) ObjectManager::RemoveRef(this->GetRecord(), this);
+		this->Pointer = old.Pointer;
+		this->DataPtr = old.DataPtr;
+	}
+
+	RefWeak& operator=(const RefWeak& old) {
+		ObjectManager::AddRef(old->GetRecord(), this);
+		if (this->DataPtr != nullptr) ObjectManager::RemoveRef(this->GetRecord(), this);
+		this->Pointer = old.Pointer;
+		this->DataPtr = old.DataPtr;
+		return *this;
+	}
+};
+
 template <class T = BaseObject>
 T* SpawnObject()
 {
diff --git a/Engine/GameLoop.cpp b/Engine/GameLoop.cpp
index 26e385446bb8a54281446ecfe5457c015c28f9cd..28b62f8cabe90c161f67e8d3cd4136559b4a2d0e 100644
--- a/Engine/GameLoop.cpp
+++ b/Engine/GameLoop.cpp
@@ -6,6 +6,7 @@
 #include "GameLoop.h"
 #include "WinConsole.h"
 #include "GarbageCollector.h"
+#include "Physics.h"
 #include "Timer.h"
 
 using namespace std;
@@ -96,7 +97,10 @@ int GameLoop::MainLoop()
 			if (found) continue;
 			t->Tick(duration.count());
 		}
+
 		Timer::UpdateTimers(duration.count());
+		Physics::CheckCollisions();
+
 		RI->Render(duration.count());
 
 		std::unique_lock<std::mutex> lock(TickListMutex);
diff --git a/Engine/Gameplay/PlayerController.cpp b/Engine/Gameplay/PlayerController.cpp
index ecb2fd9e8bcc60ac1118d3debe208f463d16535a..464bc92a5af005f5481c60d9985e91d7989d3921 100644
--- a/Engine/Gameplay/PlayerController.cpp
+++ b/Engine/Gameplay/PlayerController.cpp
@@ -3,6 +3,7 @@
 Player::Player() : Actor()
 {
 	PlayerCamera = RI->CreateCamera();
+	PlayerCamera->SetLocation(Vector(0.f, 0.f, 1.5f));
 	RI->SetActiveCamera(PlayerCamera);
 }
 
diff --git a/Engine/IRender.h b/Engine/IRender.h
index 28921c6e549748ef0ef6c16f41326ed15b96968c..194911d8a94cab63812586c127d030db1bb203d2 100644
--- a/Engine/IRender.h
+++ b/Engine/IRender.h
@@ -10,6 +10,7 @@ class RenderObject;
 class VisibleObject;
 class LoadedMesh;
 struct LightData;
+struct Vertex;
 
 class Camera
 {
@@ -27,6 +28,9 @@ public:
 
 	virtual void SetFov(float) = 0;
 	virtual void SetPerspective(bool perspective) = 0;
+	void SetParent(VisibleObject* p) { Parent = p; }
+protected:
+	VisibleObject* Parent;
 };
 
 class IRender
@@ -84,6 +88,15 @@ protected:
 	double MouseY;
 };
 
+struct AABB
+{
+	AABB() {}
+	AABB(float f) { mins = -f; maxs = f; }
+	AABB(Vector min, Vector max) { mins = min; maxs = max; }
+	Vector mins;
+	Vector maxs;
+};
+
 class RenderMesh
 {
 public:
@@ -92,6 +105,10 @@ public:
 	virtual void SetMaterial(uint section, Material* nextMat) = 0;
 	virtual Material* GetMaterial(uint section) const = 0;
 	virtual void SetInstances(int count, Transformation* dispArray) = 0;
+	AABB GetAABB() const { return bounds; }
+	void SetAABB(AABB bounds) { this->bounds = bounds.maxs.Length(); }
+protected:
+	AABB bounds;
 };
 
 class IMesh
@@ -99,6 +116,7 @@ class IMesh
 public:
 	virtual ~IMesh() {}
 	virtual RenderMesh* LoadData(VisibleObject* parent, String name) = 0;
+	virtual RenderMesh* CreateProcedural(VisibleObject* parent, String name, std::vector<Vector>& positions, std::vector<Vector> UV, std::vector<Vector>& normal, std::vector<Vector>& tangent, std::vector<uint32>& indices) = 0;
 	virtual void StartLoading() = 0;
 
 protected:
diff --git a/Engine/ObjectManager.cpp b/Engine/ObjectManager.cpp
index 6548498e1dc13f2e4f0af10472b20307dbf0bb39..2895c80cda9ca61ae817f36678348a6ad4a77edf 100644
--- a/Engine/ObjectManager.cpp
+++ b/Engine/ObjectManager.cpp
@@ -9,6 +9,9 @@ Record::~Record()
 	for (const auto& p : pointerRefs) {
 		p->NullThis();
 	}
+	for (const auto& p : weakRefs) {
+		p->NullThis();
+	}
 	auto t = dynamic_cast<Tickable*>(object);
 	if (t != nullptr) Loop->RemoveFromTick(t);
 	delete object;
diff --git a/Engine/ObjectManager.h b/Engine/ObjectManager.h
index 7ecda6ded3821d09ffb14c8f16ed01dfb81d332a..3db23a9a1423731f7e00ca0f3a67d7ce53476b17 100644
--- a/Engine/ObjectManager.h
+++ b/Engine/ObjectManager.h
@@ -10,6 +10,7 @@ struct Record
 	Record(Data* o, short p) : object(o), protection(p), checkCount(0) {}
 	~Record();
 	std::list<const RefHold*> pointerRefs;
+	std::list<const RefHold*> weakRefs;
 	short protection;
 	short checkCount;
 	Data* object;
@@ -24,11 +25,13 @@ public:
 	}
 
 	static void AddRef(const uint64 record, const RefHold* obj) {
-		ObjectRecords[record]->pointerRefs.push_back(obj);
+		if (obj->bWeak) ObjectRecords[record]->weakRefs.push_back(obj);
+		else ObjectRecords[record]->pointerRefs.push_back(obj);
 	}
 
 	static void RemoveRef(const uint64 record, const RefHold* obj) {
-		ObjectRecords.find(record)->second->pointerRefs.remove(obj);
+		if (obj->bWeak) ObjectRecords.find(record)->second->weakRefs.remove(obj);
+		else ObjectRecords.find(record)->second->pointerRefs.remove(obj);
 	}
 
 	static void CreateRecord(Data* object, short protection = 0) {
diff --git a/Engine/Objects/BaseObject.h b/Engine/Objects/BaseObject.h
index 30ab13d709895c2311407a08178d91080c02fe5a..dee9e7d66acc6583ccbb242e685ff8ea304c5247 100644
--- a/Engine/Objects/BaseObject.h
+++ b/Engine/Objects/BaseObject.h
@@ -10,6 +10,8 @@ public:
 	virtual const void NullThis() const = 0;
 	virtual const RecordInt GetRecord() const = 0;
 protected:
+	friend class ObjectManager;
+	const bool bWeak = false;
 };
 
 class Data
diff --git a/Engine/Objects/MovementComponent.cpp b/Engine/Objects/MovementComponent.cpp
index 50c666361c34bae51c14ee3a14a5cd8581b969c7..142ff32cd4ff97f218abdc835a57c1220b561130 100644
--- a/Engine/Objects/MovementComponent.cpp
+++ b/Engine/Objects/MovementComponent.cpp
@@ -1,20 +1,31 @@
-#include "Objects/Actor.h"
+#include "Physics.h"
+#include <Objects/Terrain.h>
 #include "Objects/MovementComponent.h"
 
 MovementComponent::MovementComponent()
 {
 	mass = 1.f;
-	in_acceleration = 100.f;
+	in_acceleration = 600.f;
 	max_speed = 10.f;
 	isPhysics = false;
 	isGravity = true;
+	inAir = true;
 	direction_count = 0;
+	force_count = 0;
 	drag = 1.f;
-	brake = 1000.f;
+	brake = 2000.f;
+	air_control = 0.05f;
+	Physics::AddMovable(this);
+}
+
+void MovementComponent::OnDestroyed()
+{
+	Physics::RemoveMovable(this);
 }
 
 void MovementComponent::Tick(float time)
 {
+	OldState = DesiredState;
 	if (Object == nullptr) return;
 	switch (isPhysics)
 	{
@@ -23,9 +34,9 @@ void MovementComponent::Tick(float time)
 		const Vector gravity(0.f, 0.f, -9.8f);
 		Vector delta;
 
-		if (isGravity) acceleration += gravity * time;
-		velocity += acceleration * time;
-		delta = velocity * time;
+		if (isGravity) DesiredState.acceleration += gravity * time;
+		DesiredState.velocity += DesiredState.acceleration * time;
+		delta = DesiredState.velocity * time;
 		Object->AddLocation(delta);
 	}
 	break;
@@ -37,25 +48,67 @@ void MovementComponent::Tick(float time)
 			delta_a += directions[i];
 		}
 		delta_a = delta_a.Normalize();
-		delta_a *= in_acceleration;
+		delta_a *= in_acceleration * (inAir ? air_control : 1.f);
+
+		for (int i = 0; i < force_count; i++) {
+			delta_a += forces[i].Direction;
+		}
 
-		const Vector drag_a = velocity.Normalize() * brake * time;
+		const Vector drag_a = Vector(DesiredState.velocity.X, DesiredState.velocity.Y, 0.f).Normalize() * brake * time;
 
 		const Vector total_a = delta_a - drag_a;
 
-		acceleration = total_a;
+		DesiredState.acceleration = total_a;
 
-		if (isGravity) {
+		DesiredState.velocity += DesiredState.acceleration * time;
+		Vector temp = DesiredState.velocity;
+		temp.Z = 0.f;
+		if (temp.Length() > max_speed) temp = temp.Normalize() * max_speed;
+		else if (temp.Length() < 0.01f) temp = Vector(0.f);
+		DesiredState.velocity.X = temp.X;
+		DesiredState.velocity.Y = temp.Y;
+
+		if (isGravity && inAir) {
 			const Vector gravity_const(0.f, 0.f, -9.8f);
-			gravity += gravity_const * time;
+			DesiredState.velocity += gravity_const * time;
 		}
-		velocity = velocity + acceleration * time;
-		if (velocity.Length() > max_speed) velocity = velocity.Normalize() * max_speed;
-		else if (velocity.Length() < 0.1f) velocity = Vector(0.f);
 		
-		Object->AddLocation((velocity + gravity) * time);
+		DesiredState.location = Object->GetLocation() + (DesiredState.velocity) * time;
+
+		if (Terra != nullptr) {
+			float height = Terra->GetHeight(DesiredState.location.X, DesiredState.location.Y);
+			
+			if (DesiredState.location.Z < height) {
+				DesiredState.location.Z = height;
+				if (DesiredState.velocity.Z < 0.f) DesiredState.velocity.Z = 0.f;
+				if (DesiredState.acceleration.Z < 0.f) DesiredState.acceleration.Z = 0.f;
+				inAir = false;
+			}
+			else {
+				if (DesiredState.location.Z > height)
+					inAir = true;
+			}
+		}
 	}
 	break;
 	}
 	direction_count = 0;
+	force_count = 0;
+
+}
+
+void MovementComponent::SetTarget(Actor* t)
+{
+	Object = t;
+	Physics::RemoveStatic(t);
+}
+
+void MovementComponent::SetGround(Terrain* t)
+{
+	Terra = t;
+}
+
+void MovementComponent::ApplyMovement()
+{
+	Object->SetLocation(DesiredState.location);
 }
diff --git a/Engine/Objects/MovementComponent.h b/Engine/Objects/MovementComponent.h
index f7a052cef4a4d274d4858f751d574deda687975a..5e6261c4b9d24e4fe359db69ff2b0230c085d368 100644
--- a/Engine/Objects/MovementComponent.h
+++ b/Engine/Objects/MovementComponent.h
@@ -1,7 +1,8 @@
 #pragma once
 #include <Core.h>
+#include <Objects/Actor.h>
 
-class Actor;
+class Terrain;
 
 struct Force
 {
@@ -10,41 +11,62 @@ struct Force
 	float duration;
 };
 
+struct State
+{
+	Vector location;
+	Vector rotation;
+	Vector velocity;
+	Vector angular_v;
+	Vector acceleration;
+	Vector angular_a;
+};
+
 class MovementComponent : public BaseObject, public Tickable
 {
 public:
 	MovementComponent();
 
+	virtual void OnDestroyed() override;
+
 	virtual void BeginPlay() override {}
 	virtual void Tick(float) override;
 
-	void SetTarget(Actor* t) { Object = t; }
+	void SetTarget(Actor* t);
+	void SetGround(Terrain* t);
+	Actor* GetTarget() const { return Object; }
 	void SetMass(float m) { mass = m; }
 	void SetMaxSpeed(float speed) { max_speed = speed; }
 	void SetPhysics(bool p) { isPhysics = p; }
 	void SetGravity(bool g) { isGravity = g; }
+	void ApplyMovement();
 
 	void AddInput(const Vector dir) { directions[direction_count++] = dir; }
+	void AddImpulse(const Force& f) { forces[force_count++] = f; }
+	void AddImpulse(const Vector& d) { Force f; f.Direction = d; forces[force_count++] = f; }
+	bool IsInAir() { return inAir; }
+
+	State DesiredState;
+	State OldState;
 
 private:
 
 	Ref<Actor> Object;
-
-	Vector velocity;
-	Vector acceleration;
-	Vector gravity;
+	RefWeak<Terrain> Terra;
 
 	bool isPhysics;
 	bool isGravity;
+	bool inAir;
 
 	float mass;
 	float in_acceleration;
 	float max_speed;
 	float drag;
 	float brake;
+	float air_control;
 
 	Force forces[16];
 	Vector directions[16];
 	int direction_count;
+	int force_count;
 };
 
diff --git a/Engine/Objects/Terrain.cpp b/Engine/Objects/Terrain.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2124f7c1a0bedbb732949dfcdd4f42f8958d7783
--- /dev/null
+++ b/Engine/Objects/Terrain.cpp
@@ -0,0 +1,331 @@
+#include "Terrain.h"
+
+namespace Noise {
+	/* coherent noise function over 1, 2 or 3 dimensions */
+	/* (copyright Ken Perlin) */
+
+	#include <stdlib.h>
+	#include <stdio.h>
+	#include <math.h>
+
+	#define B 0x100
+	#define BM 0xff
+
+	#define N 0x1000
+	#define NP 12   /* 2^N */
+	#define NM 0xfff
+
+	static int p[B + B + 2];
+	static float g3[B + B + 2][3];
+	static float g2[B + B + 2][2];
+	static float g1[B + B + 2];
+	static int start = 1;
+
+	static void init(void);
+
+	#define s_curve(t) ( t * t * (3. - 2. * t) )
+
+	#define lerp(t, a, b) ( a + t * (b - a) )
+
+	#define setup(i,b0,b1,r0,r1)\
+		t = vec[i] + N;\
+		b0 = ((int)t) & BM;\
+		b1 = (b0+1) & BM;\
+		r0 = t - (int)t;\
+		r1 = r0 - 1.;
+
+		double noise1(double arg)
+		{
+			int bx0, bx1;
+			float rx0, rx1, sx, t, u, v, vec[1];
+
+			vec[0] = arg;
+			if (start) {
+				start = 0;
+				init();
+			}
+
+			setup(0, bx0, bx1, rx0, rx1);
+
+			sx = s_curve(rx0);
+
+			u = rx0 * g1[p[bx0]];
+			v = rx1 * g1[p[bx1]];
+
+			return lerp(sx, u, v);
+		}
+
+		float noise2(float vec[2])
+		{
+			int bx0, bx1, by0, by1, b00, b10, b01, b11;
+			float rx0, rx1, ry0, ry1, * q, sx, sy, a, b, t, u, v;
+			register int i, j;
+
+			if (start) {
+				start = 0;
+				init();
+			}
+
+			setup(0, bx0, bx1, rx0, rx1);
+			setup(1, by0, by1, ry0, ry1);
+
+			i = p[bx0];
+			j = p[bx1];
+
+			b00 = p[i + by0];
+			b10 = p[j + by0];
+			b01 = p[i + by1];
+			b11 = p[j + by1];
+
+			sx = s_curve(rx0);
+			sy = s_curve(ry0);
+
+	#define at2(rx,ry) ( rx * q[0] + ry * q[1] )
+
+			q = g2[b00]; u = at2(rx0, ry0);
+			q = g2[b10]; v = at2(rx1, ry0);
+			a = lerp(sx, u, v);
+
+			q = g2[b01]; u = at2(rx0, ry1);
+			q = g2[b11]; v = at2(rx1, ry1);
+			b = lerp(sx, u, v);
+
+			return lerp(sy, a, b);
+		}
+
+		float noise3(float vec[3])
+		{
+			int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+			float rx0, rx1, ry0, ry1, rz0, rz1, * q, sy, sz, a, b, c, d, t, u, v;
+			register int i, j;
+
+			if (start) {
+				start = 0;
+				init();
+			}
+
+			setup(0, bx0, bx1, rx0, rx1);
+			setup(1, by0, by1, ry0, ry1);
+			setup(2, bz0, bz1, rz0, rz1);
+
+			i = p[bx0];
+			j = p[bx1];
+
+			b00 = p[i + by0];
+			b10 = p[j + by0];
+			b01 = p[i + by1];
+			b11 = p[j + by1];
+
+			t = s_curve(rx0);
+			sy = s_curve(ry0);
+			sz = s_curve(rz0);
+
+	#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
+
+			q = g3[b00 + bz0]; u = at3(rx0, ry0, rz0);
+			q = g3[b10 + bz0]; v = at3(rx1, ry0, rz0);
+			a = lerp(t, u, v);
+
+			q = g3[b01 + bz0]; u = at3(rx0, ry1, rz0);
+			q = g3[b11 + bz0]; v = at3(rx1, ry1, rz0);
+			b = lerp(t, u, v);
+
+			c = lerp(sy, a, b);
+
+			q = g3[b00 + bz1]; u = at3(rx0, ry0, rz1);
+			q = g3[b10 + bz1]; v = at3(rx1, ry0, rz1);
+			a = lerp(t, u, v);
+
+			q = g3[b01 + bz1]; u = at3(rx0, ry1, rz1);
+			q = g3[b11 + bz1]; v = at3(rx1, ry1, rz1);
+			b = lerp(t, u, v);
+
+			d = lerp(sy, a, b);
+
+			return lerp(sz, c, d);
+		}
+
+		static void normalize2(float v[2])
+		{
+			float s;
+
+			s = sqrt(v[0] * v[0] + v[1] * v[1]);
+			v[0] = v[0] / s;
+			v[1] = v[1] / s;
+		}
+
+		static void normalize3(float v[3])
+		{
+			float s;
+
+			s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+			v[0] = v[0] / s;
+			v[1] = v[1] / s;
+			v[2] = v[2] / s;
+		}
+
+		static void init(void)
+		{
+			int i, j, k;
+
+			for (i = 0; i < B; i++) {
+				p[i] = i;
+
+				g1[i] = (float)((rand() % (B + B)) - B) / B;
+
+				for (j = 0; j < 2; j++)
+					g2[i][j] = (float)((rand() % (B + B)) - B) / B;
+				normalize2(g2[i]);
+
+				for (j = 0; j < 3; j++)
+					g3[i][j] = (float)((rand() % (B + B)) - B) / B;
+				normalize3(g3[i]);
+			}
+
+			while (--i) {
+				k = p[i];
+				p[i] = p[j = rand() % B];
+				p[j] = k;
+			}
+
+			for (i = 0; i < B + 2; i++) {
+				p[B + i] = p[i];
+				g1[B + i] = g1[i];
+				for (j = 0; j < 2; j++)
+					g2[B + i][j] = g2[i][j];
+				for (j = 0; j < 3; j++)
+					g3[B + i][j] = g3[i][j];
+			}
+		}
+}
+
+Terrain::Terrain()
+{
+	isTexture = false;
+	Heightmap = nullptr;
+
+	resolution = 0;
+	noise_scale = 0.010;
+	amplitude = 10.0;
+
+	Mesh = SpawnObject<VisibleObject>();
+}
+
+#pragma optimize("", off)
+void Terrain::InitTerrain(int r, Vector scale)
+{
+	resolution = r;
+	Scale = scale / r;
+
+	std::vector<Vector> pos;
+	std::vector<Vector> uvs;
+	std::vector<Vector> normals;
+	std::vector<Vector> tangents;
+	std::vector<uint32> inds;
+
+	pos.reserve(r * r);
+
+	Vector offset = scale / 2;
+	offset.Z = 0.f;
+
+	for (int32 y = 0; y < r + 1; y++) {
+		for (int32 x = 0; x < r + 1; x++) {
+			pos.emplace_back(Vector(Scale.X * x, Scale.Y * y, GetHeight(Scale.X * x, Scale.Y * y)));
+			uvs.emplace_back(Vector((x - 1) / (float)r, (y - 1) / (float)r, 0.f));
+			normals.emplace_back(Vector(0.f, 0.f, 1.f));
+			if (y < r && x < r) {
+				inds.emplace_back(y * (r + 1) + x);
+				inds.emplace_back((y + 1) * (r + 1) + x);
+				inds.emplace_back((y + 1) * (r + 1) + x + 1);
+
+				inds.emplace_back(y * (r + 1) + x);
+				inds.emplace_back((y + 1) * (r + 1) + x + 1);
+				inds.emplace_back(y * (r + 1) + x + 1);
+			}
+		}
+	}
+
+	normals.resize(pos.size());
+	tangents.resize(pos.size());
+
+	Mesh->SetModel(MI->CreateProcedural(Mesh, "Terrain_" + std::to_string(GetRecord()), pos, uvs, normals, tangents, inds));
+	Mesh->GetModel()->SetMaterial(0, RI->LoadMaterialByName("Shaders/ground"));
+}
+//
+//float fract(float p)
+//{
+//	return p - floor(p);
+//}
+//
+//float hash1(float px, float py)
+//{
+//	px = 50.0 * fract(px * 0.3183099);
+//	py = 50.0 * fract(py * 0.3183099);
+//	return fract(px * py * (px + py));
+//}
+//
+//float clamp(float x, float lowerlimit, float upperlimit) {
+//	if (x < lowerlimit)
+//		x = lowerlimit;
+//	if (x > upperlimit)
+//		x = upperlimit;
+//	return x;
+//}
+//
+//float smoothstep(float edge0, float edge1, float x) {
+//	x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+//	return x * x * (3 - 2 * x);
+//}
+//
+//float noise(float x, float y)
+//{
+//	float px = floor(x);
+//	float py = floor(x);
+//	float wx = fract(x);
+//	float wy = fract(x);
+//
+//	float ux = wx * wx * wx * (wx * (wx * 6.0 - 15.0) + 10.0);
+//	float uy = wy * wy * wy * (wy * (wy * 6.0 - 15.0) + 10.0);
+//
+//	float a = hash1(px, py);
+//
+//	float b = hash1(px + 1, py + 0);
+//
+//	float c = hash1(px + 0, py + 1);
+//
+//	float d = hash1(px + 1, py + 1);
+//
+//	return -1.0 + 2.0 * (a + (b - a) * ux + (c - a) * uy + (a - b - c + d) * ux * uy);
+//}
+//
+//float fbm_9(float x, float y)
+//{
+//	float f = 1.9;
+//	float s = 0.55;
+//	float a = 0.0;
+//	float b = 0.5;
+//	for (int i = 0; i < 9; i++)
+//	{
+//		float n = noise(x, y);
+//		a += b * n;
+//	}
+//	return a;
+//}
+
+float Terrain::GetHeight(float x, float y)
+{
+	//const float sca = 0.010;
+	//const float amp = 10.0;
+	//x *= sca;
+	//y *= sca;
+	//float e = fbm_9( x + 1.0, y + -2.0);
+	//float a = 1.0 - smoothstep(0.12, 0.13, abs(e + 0.12)); // flag high-slope areas (-0.25, 0.0)
+	//e = e + 0.15 * smoothstep(-0.08, -0.01, e);
+	//e *= amp;
+	//return e;
+	x *= noise_scale;
+	y *= noise_scale;
+	float arr[] = { x, y };
+	return Noise::noise2(arr) * amplitude;
+}
+#pragma optimize("", on)
diff --git a/Engine/Objects/Terrain.h b/Engine/Objects/Terrain.h
new file mode 100644
index 0000000000000000000000000000000000000000..87f66be35970fcf120ecbc7d7fa52b7be9368307
--- /dev/null
+++ b/Engine/Objects/Terrain.h
@@ -0,0 +1,27 @@
+#pragma once
+#include <Core.h>
+#include <Objects/VisibleObject.h>
+
+class Terrain : public BaseObject
+{
+public:
+	Terrain();
+
+	virtual void BeginPlay() override {}
+
+	void InitTerrain(int r, Vector scale = Vector(1.f));
+	float GetHeight(float x, float y);
+private:
+
+	int resolution;
+	Vector Scale;
+
+	float noise_scale = 0.010;
+	float amplitude = 10.0;
+
+	bool isTexture;
+	Texture* Heightmap;
+
+	Ref<VisibleObject> Mesh;
+};
+
diff --git a/Engine/Objects/VisibleObject.cpp b/Engine/Objects/VisibleObject.cpp
index 59ef3355909b670a06bf5dac128505c3cef32d81..68162f64681d47ebb9587307bf9a416d81da9bce 100644
--- a/Engine/Objects/VisibleObject.cpp
+++ b/Engine/Objects/VisibleObject.cpp
@@ -1,4 +1,5 @@
 #include "VisibleObject.h"
+#include "Physics.h"
 
 VisibleObject::VisibleObject() : BaseObject()
 {
@@ -6,6 +7,12 @@ VisibleObject::VisibleObject() : BaseObject()
 	Rotation = Vector(0, 0, 0);
 	Scale = Vector(1, 1, 1);
 	RenderData = nullptr;
+	Physics::AddStatic(this);
+}
+
+void VisibleObject::OnDestroyed()
+{
+	Physics::RemoveStatic(this);
 }
 
 void VisibleObject::SetLocation(Vector NewLocation)
@@ -31,3 +38,9 @@ void VisibleObject::SetModel(std::string Name)
 	RenderData = MI->LoadData(this, Name);
 	if (RenderData != nullptr) RenderData->ApplyTransform();
 }
+
+void VisibleObject::SetModel(RenderMesh* mesh)
+{
+	RenderData = mesh;
+	if (RenderData != nullptr) RenderData->ApplyTransform();
+}
diff --git a/Engine/Objects/VisibleObject.h b/Engine/Objects/VisibleObject.h
index 36cc007f61f6f8e9cbe598a1001a9cec5f73b00e..537012734d3bab629ca12b927f8951636048d797 100644
--- a/Engine/Objects/VisibleObject.h
+++ b/Engine/Objects/VisibleObject.h
@@ -8,6 +8,7 @@ class VisibleObject : public BaseObject
 public:
 	VisibleObject();
 	virtual ~VisibleObject() { delete RenderData; }
+	virtual void OnDestroyed() override;
 
 	void SetLocation(Vector NewLocation);
 	void SetRotation(Vector NewRotation);
@@ -19,6 +20,7 @@ public:
 	const Vector GetScale() const { return Scale; }
 
 	void SetModel(std::string Name);
+	void SetModel(RenderMesh* mesh);
 	std::string GetModelName() const { return std::string(); }
 	RenderMesh* GetModel() const { return RenderData; }
 
diff --git a/Engine/OpenGLRenderer/Mesh.cpp b/Engine/OpenGLRenderer/Mesh.cpp
index b0b15f9e826d8c81f9ffef40325922a3b43cbd84..a6d070c4ffbbf5b05b97c538213e12f842ace013 100644
--- a/Engine/OpenGLRenderer/Mesh.cpp
+++ b/Engine/OpenGLRenderer/Mesh.cpp
@@ -62,6 +62,7 @@ RenderObject::RenderObject(LoadedMesh* mesh)
 {
 	mesh->Users++;
 	Mesh = mesh;
+	float extent = 0.f;
 
 	SectionCount = mesh->HolderCount;
 	Sections = new Section[SectionCount]();
@@ -92,7 +93,10 @@ RenderObject::RenderObject(LoadedMesh* mesh)
 		glBindVertexArray(0);
 		SetMaterial(i, mesh->Holders[i]->Instance);
 		Sections[i].Parent = this;
+
+		if (Sections[i].GetRadius() > extent) extent = Sections[i].GetRadius();
 	}
+	bounds = extent;
 }
 
 RenderObject::~RenderObject()
diff --git a/Engine/OpenGLRenderer/Renderer.cpp b/Engine/OpenGLRenderer/Renderer.cpp
index 70defaa7e5bda5be229d381c15020a924e677245..5f9b8514fae57f322bcf9fad3012162439c9df97 100644
--- a/Engine/OpenGLRenderer/Renderer.cpp
+++ b/Engine/OpenGLRenderer/Renderer.cpp
@@ -3,12 +3,11 @@
 #include <GLFW/glfw3.h>
 #include "Core.h"
 #include "Renderer.h"
-#include "Batcher.h"
 #include "Camera.h"
 #include "Mesh.h"
 #include "Texture.h"
 #include "RenderBuffer.h"
-#include "../Objects/VisibleObject.h"
+#include <Objects/VisibleObject.h>
 #include "LightData.h"
 #include "Settings.h"
 #include <filesystem>
@@ -1205,7 +1204,7 @@ void processMesh(LoadedMesh* meshHolder, aiMesh* mesh)
 		vertex.position.x = mesh->mVertices[i].x;
 		vertex.position.y = mesh->mVertices[i].y;
 		vertex.position.z = mesh->mVertices[i].z;
-		if (radius < mesh->mVertices[i].Length()) radius = mesh->mVertices[i].Length();
+		if (radius < mesh->mVertices[i].x) radius = mesh->mVertices[i].x;
 
 		vertex.normal.x = mesh->mNormals[i].x;
 		vertex.normal.y = mesh->mNormals[i].y;
@@ -1238,7 +1237,7 @@ void processMesh(LoadedMesh* meshHolder, aiMesh* mesh)
 	}
 	std::vector<uint> adjacent;
 	MeshDataHolder* section = new MeshDataHolder(vertices.data(), vertices.size(), indices.data(), indices.size());
-	section->Radius = radius * 1.5f;
+	section->Radius = radius;
 	/*section->FaceCount = indices.size() / 3;
 	section->VertexCount = vertices.size();
 
@@ -1388,6 +1387,41 @@ RenderMesh* GLMesh::LoadData(VisibleObject* parent, String name)
 	}
 }
 
+RenderMesh* GLMesh::CreateProcedural(VisibleObject* parent, String name, std::vector<Vector>& positions, std::vector<Vector> UV, std::vector<Vector>& normal, std::vector<Vector>& tangent, std::vector<uint32>& indices)
+{
+	LoadedMesh* mesh = new LoadedMesh();
+
+	std::vector<Vertex> verts;
+	verts.reserve(positions.size());
+
+	AABB bounds;
+	for (auto i = 0; i < positions.size(); i++) {
+		if		(bounds.mins.X > positions[i].X) bounds.mins.X = positions[i].X;
+		else if (bounds.maxs.X < positions[i].X) bounds.maxs.X = positions[i].X;
+		if		(bounds.mins.Y > positions[i].Y) bounds.mins.Y = positions[i].Y;
+		else if (bounds.maxs.Y < positions[i].Y) bounds.maxs.Y = positions[i].Y;
+		if		(bounds.mins.Z > positions[i].Z) bounds.mins.Z = positions[i].Z;
+		else if (bounds.maxs.Z < positions[i].Z) bounds.maxs.Z = positions[i].Z;
+
+		verts[i].position = glm::vec3(positions[i].X, positions[i].Z, positions[i].Y);
+		verts[i].uv = glm::vec3(UV[i].X, UV[i].Y, UV[i].Z);
+		verts[i].normal = glm::vec3(normal[i].X, normal[i].Z, normal[i].Y);
+		verts[i].tangent = glm::vec3(tangent[i].X, tangent[i].Z, tangent[i].Y);
+	}
+
+	MeshDataHolder* section = new MeshDataHolder(verts.data(), positions.size(), indices.data(), indices.size());
+
+	mesh->HolderCount++;
+	mesh->Holders.push_back(section);
+	section->Radius = bounds.maxs.Length();
+
+	LoadedMeshes.emplace(name, mesh);
+	RenderObject* obj = new RenderObject(mesh);
+	obj->SetParent(parent);
+	obj->SetAABB(bounds);
+	return obj;
+}
+
 void GLMesh::StartLoading()
 {
 	namespace fs = std::filesystem;
diff --git a/Engine/OpenGLRenderer/include/Renderer.h b/Engine/OpenGLRenderer/include/Renderer.h
index 94723ae0c513ecac0ca51bf4ac6d5342f60d656d..dbf0c6f37a46e5d6dbcc10bc32d672a246637698 100644
--- a/Engine/OpenGLRenderer/include/Renderer.h
+++ b/Engine/OpenGLRenderer/include/Renderer.h
@@ -3,7 +3,6 @@
 
 class Shader;
 class Texture;
-class RenderBatch;
 class GLCamera;
 class PreDepthBuffer;
 class PostBuffer;
@@ -107,6 +106,7 @@ public:
 	GLMesh();
 	virtual ~GLMesh();
 	virtual	RenderMesh* LoadData(VisibleObject* parent, String name) override;
+	virtual RenderMesh* CreateProcedural(VisibleObject* parent, String name, std::vector<Vector>& positions, std::vector<Vector> UV, std::vector<Vector>& normal, std::vector<Vector>& tangent, std::vector<uint32>& indices) override;
 	virtual void StartLoading() override;
 
 private:
diff --git a/Engine/Physics.cpp b/Engine/Physics.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..15bbdbb3df5a7cfdb2d6a2010698784939d7d509
--- /dev/null
+++ b/Engine/Physics.cpp
@@ -0,0 +1,159 @@
+#include <Objects/VisibleObject.h>
+#include <Objects/MovementComponent.h>
+#include <limits>
+#include "Physics.h"
+
+namespace Physics
+{
+	namespace
+	{
+		std::vector<RefWeak<VisibleObject>> Statics;
+		std::vector<RefWeak<MovementComponent>> Movables;
+
+		bool intersect(AABB a, AABB b) {
+			return (a.mins.X <= b.maxs.X && a.maxs.X >= b.mins.X) &&
+				(a.mins.Y <= b.maxs.Y && a.maxs.Y >= b.mins.Y) &&
+				(a.mins.Z <= b.maxs.Z && a.maxs.Z >= b.mins.Z);
+		}
+
+		float sign(float v) {
+			return v < 0.f ? -1.0f : 1.0f;
+		}
+
+		struct Hit {
+			AABB collider;
+			bool collided;
+			Vector pos;
+			Vector delta;
+			Vector normal;
+			Vector time;
+		};
+
+		struct Sweep {
+			Hit hit;
+			Vector pos;
+			float time;
+		};
+		/*
+		Hit intersectSegment(const AABB& box, Vector pos, Vector delta, Vector padding)
+		{
+			Vector scale = Vector(1.0) / delta;
+			Vector vsign = Vector(sign(scale.X), sign(scale.Y), sign(scale.Z));
+			Vector nearTime = (box.position - vsign * (hwidth + padding) - pos) * scale;
+			Vector farTime = (position + vsign * (hwidth + padding) - pos) * scale;
+			if ((nearTime.X > farTime.Y) || (nearTime.X > farTime.Z) || (nearTime.Y > farTime.X) || (nearTime.Y > farTime.Z) || (nearTime.Z > farTime.X) || (nearTime.Z > farTime.Y))
+				return Hit(false);
+
+			float near = std::max(std::max(nearTime.X, nearTime.Y), nearTime.Z);
+			float far = std::min(std::min(farTime.X, farTime.Y), farTime.Z);
+
+			if ((near >= 1) || (far <= 0))
+				return Hit(false);
+
+			Hit hit;
+			hit.time = near;//glm::clamp(near , 0.f, 1.f);
+			if ((nearTime.X > nearTime.Y) && (nearTime.X > nearTime.Z))
+			{
+				hit.normal = Vector(-vsign.X, 0, 0);
+			}
+			else if ((nearTime.Y > nearTime.X) && (nearTime.Y > nearTime.Z))
+			{
+				hit.normal = Vector(0, -vsign.Y, 0);
+			}
+			else if ((nearTime.Z > nearTime.Y) && (nearTime.Z > nearTime.X))
+			{
+				hit.normal = Vector(0, 0, -vsign.Z);
+			}
+
+			hit.delta = hit.time * delta;
+
+			hit.pos = pos + hit.delta;
+			hit.time = nearTime;
+
+			return hit;
+
+		}
+		Sweep sweepAABB(AABB first, AABB box, Vector delta)
+		{
+			if (delta == Vector(0, 0, 0))
+			{
+				Sweep s;
+				s.hit.collided = false;
+				s.time = 1;
+				return s;
+			}
+			Sweep sweep;
+			sweep.hit = intersectSegment(first, box.position, delta, box.hwidth);
+
+			if (sweep.hit.collided)
+			{
+				sweep.time = glm::clamp(sweep.hit.time - EPSILON, 0.f, 1.f);
+				sweep.pos = box.position + (delta * sweep.time);
+
+				Vector direction = delta.Normalize();
+
+				sweep.hit.pos += direction * box.hwidth;
+				sweep.item = box.getSimple();
+				sweep.other = getSimple();
+			}
+			else
+			{
+				sweep.pos = box.position + delta;
+				sweep.time = 1;
+			}
+			return sweep;
+		}*/
+	}
+
+#pragma optimize("", off)
+	void CheckCollisions()
+	{
+		//printf("Colliding objects...\n");
+		//printf("Statics: %u, Movables: %u\n", Statics.size(), Movables.size());
+
+		for (const auto& o : Movables) {
+			if (o->GetTarget() == nullptr || o->GetTarget()->GetModel() == nullptr) continue;
+			Vector& d_loc = o->DesiredState.location;
+			const Vector& o_loc = o->OldState.location;
+			const AABB& d_AABB = o->GetTarget()->GetModel()->GetAABB();
+
+
+
+			std::vector<VisibleObject*> Collisions;
+			for (const auto& s : Statics) {
+				const AABB& bounds = s->GetModel()->GetAABB();
+				const Vector& loc = s->GetLocation();
+				
+			}
+		}
+
+		for (const auto& m : Movables) {
+			m->ApplyMovement();
+		}
+	}
+#pragma optimize("", on)
+
+	void AddStatic(VisibleObject* obj)
+	{
+		Statics.push_back(obj);
+	}
+
+	void RemoveStatic(VisibleObject* obj)
+	{
+		for (auto i = Statics.begin(); i != Statics.end(); i++) {
+			if (i->GetPointer() == obj) { Statics.erase(i); break; }
+		}
+	}
+
+	void AddMovable(MovementComponent* obj)
+	{
+		Movables.push_back(obj);
+	}
+
+	void RemoveMovable(MovementComponent* obj)
+	{
+		for (auto i = Movables.begin(); i != Movables.end(); i++) {
+			if (i->GetPointer() == obj) Movables.erase(i);
+		}
+	}
+}
diff --git a/Engine/Physics.h b/Engine/Physics.h
new file mode 100644
index 0000000000000000000000000000000000000000..fafedc905ea75318f82df912ee3fa95d736cbdce
--- /dev/null
+++ b/Engine/Physics.h
@@ -0,0 +1,15 @@
+#pragma once
+#include <Core.h>
+
+class VisibleObject;
+class MovementComponent;
+
+namespace Physics
+{
+	void CheckCollisions();
+	void AddStatic(VisibleObject* obj);
+	void RemoveStatic(VisibleObject* obj);
+	void AddMovable(MovementComponent* obj);
+	void RemoveMovable(MovementComponent* obj);
+};
+
diff --git a/Eril.vcxproj b/Eril.vcxproj
index 63807319ce8f3719e4344f57e822f91b05f757e4..65ae8a62d8dd74ab5eb2799f0a0359ceff148d17 100644
--- a/Eril.vcxproj
+++ b/Eril.vcxproj
@@ -215,6 +215,7 @@
     <ClCompile Include="Engine\Objects\BaseObject.cpp" />
     <ClCompile Include="Engine\Objects\InstancedObject.cpp" />
     <ClCompile Include="Engine\Objects\MovementComponent.cpp" />
+    <ClCompile Include="Engine\Objects\Terrain.cpp" />
     <ClCompile Include="Engine\Objects\VisibleObject.cpp" />
     <ClCompile Include="Engine\OpenGLRenderer\Batcher.cpp" />
     <ClCompile Include="Engine\OpenGLRenderer\Camera.cpp" />
@@ -224,6 +225,7 @@
     <ClCompile Include="Engine\OpenGLRenderer\RenderBuffer.cpp" />
     <ClCompile Include="Engine\OpenGLRenderer\Renderer.cpp" />
     <ClCompile Include="Engine\OpenGLRenderer\Texture.cpp" />
+    <ClCompile Include="Engine\Physics.cpp" />
     <ClCompile Include="Engine\Settings.cpp" />
     <ClCompile Include="Engine\Timer.cpp" />
     <ClCompile Include="Engine\WinConsole.cpp" />
@@ -244,6 +246,7 @@
     <ClInclude Include="Engine\Objects\BaseObject.h" />
     <ClInclude Include="Engine\Objects\InstancedObject.h" />
     <ClInclude Include="Engine\Objects\MovementComponent.h" />
+    <ClInclude Include="Engine\Objects\Terrain.h" />
     <ClInclude Include="Engine\Objects\VisibleObject.h" />
     <ClInclude Include="Engine\OpenGLRenderer\ext\glfw\deps\glad\gl.h" />
     <ClInclude Include="Engine\OpenGLRenderer\include\Batcher.h" />
@@ -254,6 +257,7 @@
     <ClInclude Include="Engine\OpenGLRenderer\include\RenderBuffer.h" />
     <ClInclude Include="Engine\OpenGLRenderer\include\Renderer.h" />
     <ClInclude Include="Engine\OpenGLRenderer\include\Texture.h" />
+    <ClInclude Include="Engine\Physics.h" />
     <ClInclude Include="Engine\Settings.h" />
     <ClInclude Include="Engine\Timer.h" />
     <ClInclude Include="Engine\WinConsole.h" />
diff --git a/Eril.vcxproj.filters b/Eril.vcxproj.filters
index bbdb8b37704656a7e3b30c1daac746a50316c5b1..83df4967bedb9ee6dd60f32a249717235e1b7214 100644
--- a/Eril.vcxproj.filters
+++ b/Eril.vcxproj.filters
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\Engine\OpenGLRenderer\ext\glfw\deps\glad_gl.c">
@@ -88,6 +88,12 @@
     <ClCompile Include="Game\FallingCube.cpp">
       <Filter>Game</Filter>
     </ClCompile>
+    <ClCompile Include="Engine\Physics.cpp">
+      <Filter>Engine\Private</Filter>
+    </ClCompile>
+    <ClCompile Include="Engine\Objects\Terrain.cpp">
+      <Filter>Engine\Objects</Filter>
+    </ClCompile>
     <ClCompile Include="Engine\Timer.cpp">
       <Filter>Engine\Private</Filter>
     </ClCompile>
@@ -203,6 +209,12 @@
     <ClInclude Include="Game\FallingCube.h">
       <Filter>Game</Filter>
     </ClInclude>
+    <ClInclude Include="Engine\Physics.h">
+      <Filter>Engine\Public</Filter>
+    </ClInclude>
+    <ClInclude Include="Engine\Objects\Terrain.h">
+      <Filter>Engine\Objects</Filter>
+    </ClInclude>
     <ClInclude Include="Engine\Timer.h">
       <Filter>Engine\Public</Filter>
     </ClInclude>
diff --git a/Game/TestPlayer.cpp b/Game/TestPlayer.cpp
index b488d5f43826698810bfa0a6706e810e4ee4348b..5e62e46fc7fa185ec20eec38dd18430c77c793ab 100644
--- a/Game/TestPlayer.cpp
+++ b/Game/TestPlayer.cpp
@@ -3,6 +3,7 @@
 #include "TestPlayer.h"
 #include "Objects/MovementComponent.h"
 #include "FallingCube.h"
+#include "Objects/Terrain.h"
 #include "Timer.h"
 
 TestPlayer::TestPlayer() : Player()
@@ -26,14 +27,23 @@ TestPlayer::TestPlayer() : Player()
 	II->RegisterKeyInput(256, &TestPlayer::InputExit, this);
 	II->RegisterMouseInput(0, &TestPlayer::MouseMoved, this);
 
+	SetModel("Cube");
+	RenderData->SetAABB(AABB(Vector(-0.5f), Vector(0.5f)));
+
+	terra = SpawnObject<Terrain>();
+	terra->InitTerrain(1000, Vector(100.f, 100.f, 1.f));
+
 	Movement = SpawnObject<MovementComponent>();
 	Movement->SetTarget(dynamic_cast<Actor*>(this));
-	Movement->SetGravity(false);
+	Movement->SetGravity(true);
+	Movement->SetGround(terra);
 }
 
 void TestPlayer::RunInputW(float delta, bool KeyDown)
 {
-	Movement->AddInput(-GetCamera()->GetForwardVector());
+	Vector dir = -GetCamera()->GetForwardVector();
+	dir.Z = 0.f;
+	Movement->AddInput(dir.Normalize());
 }
 
 void TestPlayer::RunInputA(float delta, bool KeyDown)
@@ -48,12 +58,15 @@ void TestPlayer::RunInputD(float delta, bool KeyDown)
 
 void TestPlayer::RunInputS(float delta, bool KeyDown)
 {
-	Movement->AddInput(GetCamera()->GetForwardVector());
+	Vector dir = GetCamera()->GetForwardVector();
+	dir.Z = 0.f;
+	Movement->AddInput(dir.Normalize());
 }
 
 void TestPlayer::RunInputSpace(float delta, bool KeyDown)
 {
-	
+	if (!Movement->IsInAir() && KeyDown)
+		Movement->AddImpulse(Vector(0.f, 0.f, 300.f));
 }
 
 void TestPlayer::InputOne(float delta, bool KeyDown)
@@ -105,10 +118,10 @@ void TestPlayer::MouseMoved(float X, float Y)
 
 void TestPlayer::Tick(float)
 {
-	GetCamera()->SetLocation(Location);
+	GetCamera()->SetLocation(Location + Vector(0.f, 0.f, 1.5f));
 	GetCamera()->SetRotation(Rotation);
 
-	if (spawnCounter++ == 30) {
+	/*if (spawnCounter++ == 40) {
 
 		FallingCube* obj = SpawnObject<FallingCube>();
 
@@ -119,7 +132,7 @@ void TestPlayer::Tick(float)
 		obj->SetLocation(Vector(rx * size, ry * size, 15.f));
 
 		spawnCounter = 0;
-	}
+	}*/
 }
 
 #include "Objects/InstancedObject.h"
@@ -142,14 +155,15 @@ void TestPlayer::BeginPlay()
 	DirLight->Data.Rotation = Vector(45.0, 0.0, 0.0);
 
 	LastSphere = SpawnObject<Actor>();
-	LastSphere->SetModel("sphere");
-	LastSphere->SetLocation(Vector(1.5f, 0.0f, 0.0f));
-	LastSphere->GetModel()->SetMaterial(0, RI->LoadMaterialByName("Shaders/metal"));
+	LastSphere->SetModel("Cube");
+	LastSphere->SetLocation(Vector(3.5f, 0.0f, 0.0f));
+	LastSphere->SetScale(Vector(1.f, 1.f, 0.2f));
+	LastSphere->GetModel()->SetMaterial(0, RI->LoadMaterialByName("Shaders/rocks"));
 
-	LastSphere2 = SpawnObject<Actor>();
+	/*LastSphere2 = SpawnObject<Actor>();
 	LastSphere2->SetModel("sphere");
 	LastSphere2->SetLocation(Vector(3.f, 0.0f, 0.0f));
-	LastSphere2->GetModel()->SetMaterial(0, RI->LoadMaterialByName("Shaders/metal"));
+	LastSphere2->GetModel()->SetMaterial(0, RI->LoadMaterialByName("Shaders/metal"));*/
 
 	Timer::CreateTimer(5.f, TimeFunction, false);
 
@@ -183,20 +197,20 @@ void TestPlayer::BeginPlay()
 
 	float size = 80.f;
 
-	for (int x = 0; x < 100; x++) {
-		VisibleObject* next = SpawnObject<VisibleObject>();
-		next->SetModel("Cube");
-		float rx = (float)rand() / (float)RAND_MAX - 0.5f;
-		float ry = (float)rand() / (float)RAND_MAX - 0.5f;
-		float rz = (float)rand() / (float)RAND_MAX;
-		//float scale = (float)rand() / (float)RAND_MAX * 2.f;
-		//next->SetScale(Vector(scale));
-		next->GetModel()->SetMaterial(0, RI->LoadMaterialByName("Shaders/rocks"));
-		next->SetLocation(Vector(rx * size, ry * size, rz * size / 3));
-		Spheres[x] = next;
-	}
-
-	Spheres[10]->SetScale(2.f);
+	//for (int x = 0; x < 100; x++) {
+	//	VisibleObject* next = SpawnObject<VisibleObject>();
+	//	next->SetModel("Cube");
+	//	float rx = (float)rand() / (float)RAND_MAX - 0.5f;
+	//	float ry = (float)rand() / (float)RAND_MAX - 0.5f;
+	//	float rz = (float)rand() / (float)RAND_MAX;
+	//	//float scale = (float)rand() / (float)RAND_MAX * 2.f;
+	//	//next->SetScale(Vector(scale));
+	//	next->GetModel()->SetMaterial(0, RI->LoadMaterialByName("Shaders/rocks"));
+	//	next->SetLocation(Vector(rx * size, ry * size, rz * size / 3));
+	//	Spheres[x] = next;
+	//}
+
+	//Spheres[10]->SetScale(2.f);
 
 	/*for (int x = 0; x < 20; x++) {
 		for (int y = 0; y < 20; y++) {
diff --git a/Game/TestPlayer.h b/Game/TestPlayer.h
index 6d8ada866dfc87750e2dc83761fbf2787add7488..630476b3d12a139e61911b6f283c1f6243323cc9 100644
--- a/Game/TestPlayer.h
+++ b/Game/TestPlayer.h
@@ -7,6 +7,7 @@ class Actor;
 class InstancedObject;
 class Light;
 class MovementComponent;
+class Terrain;
 
 class TestPlayer : public Player
 {
@@ -45,6 +46,7 @@ private:
 
 	Ref<Actor> LastSphere;
 	Ref<Actor> LastSphere2;
+	Ref<Terrain> terra;
 
 	int spawnCounter;
 };
\ No newline at end of file