Added Splines1 Video
This commit is contained in:
parent
0a38b0b740
commit
20e551029e
219
OneLoneCoder_Splines1.cpp
Normal file
219
OneLoneCoder_Splines1.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
OneLoneCoder.com - Splines Part 1
|
||||
"Bendy Wavy Curly" - @Javidx9
|
||||
|
||||
Disclaimer
|
||||
~~~~~~~~~~
|
||||
I don't care what you use this for. It's intended to be educational, and perhaps
|
||||
to the oddly minded - a little bit of fun. Please hack this, change it and use it
|
||||
in any way you see fit. BUT, you acknowledge that I am not responsible for anything
|
||||
bad that happens as a result of your actions. However, if good stuff happens, I
|
||||
would appreciate a shout out, or at least give the blog some publicity for me.
|
||||
Cheers!
|
||||
|
||||
Background
|
||||
~~~~~~~~~~
|
||||
Curvy things are always better. Splines are a nice way to approximate
|
||||
curves and loops for games. This video is the first of two parts
|
||||
demonstrating how Catmull-Rom splines can be implemented.
|
||||
|
||||
Use Z + X to select a point and move it with the arrow keys
|
||||
Use A + S to move the agent around the spline loop
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
Twitter: @javidx9
|
||||
Blog: www.onelonecoder.com
|
||||
|
||||
Video:
|
||||
~~~~~~
|
||||
https://youtu.be/9_aJGUTePYo
|
||||
|
||||
Last Updated: 06/08/2017
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
#include "olcConsoleGameEngine.h"
|
||||
|
||||
struct sPoint2D
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct sSpline
|
||||
{
|
||||
vector<sPoint2D> points;
|
||||
|
||||
sPoint2D GetSplinePoint(float t, bool bLooped = false)
|
||||
{
|
||||
int p0, p1, p2, p3;
|
||||
if (!bLooped)
|
||||
{
|
||||
p1 = (int)t + 1;
|
||||
p2 = p1 + 1;
|
||||
p3 = p2 + 1;
|
||||
p0 = p1 - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p1 = (int)t;
|
||||
p2 = (p1 + 1) % points.size();
|
||||
p3 = (p2 + 1) % points.size();
|
||||
p0 = p1 >= 1 ? p1 - 1 : points.size() - 1;
|
||||
}
|
||||
|
||||
t = t - (int)t;
|
||||
|
||||
float tt = t * t;
|
||||
float ttt = tt * t;
|
||||
|
||||
float q1 = -ttt + 2.0f*tt - t;
|
||||
float q2 = 3.0f*ttt - 5.0f*tt + 2.0f;
|
||||
float q3 = -3.0f*ttt + 4.0f*tt + t;
|
||||
float q4 = ttt - tt;
|
||||
|
||||
float tx = 0.5f * (points[p0].x * q1 + points[p1].x * q2 + points[p2].x * q3 + points[p3].x * q4);
|
||||
float ty = 0.5f * (points[p0].y * q1 + points[p1].y * q2 + points[p2].y * q3 + points[p3].y * q4);
|
||||
|
||||
return{ tx, ty };
|
||||
}
|
||||
|
||||
sPoint2D GetSplineGradient(float t, bool bLooped = false)
|
||||
{
|
||||
int p0, p1, p2, p3;
|
||||
if (!bLooped)
|
||||
{
|
||||
p1 = (int)t + 1;
|
||||
p2 = p1 + 1;
|
||||
p3 = p2 + 1;
|
||||
p0 = p1 - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p1 = (int)t;
|
||||
p2 = (p1 + 1) % points.size();
|
||||
p3 = (p2 + 1) % points.size();
|
||||
p0 = p1 >= 1 ? p1 - 1 : points.size() - 1;
|
||||
}
|
||||
|
||||
t = t - (int)t;
|
||||
|
||||
float tt = t * t;
|
||||
float ttt = tt * t;
|
||||
|
||||
float q1 = -3.0f * tt + 4.0f*t - 1;
|
||||
float q2 = 9.0f*tt - 10.0f*t;
|
||||
float q3 = -9.0f*tt + 8.0f*t + 1.0f;
|
||||
float q4 = 3.0f*tt - 2.0f*t;
|
||||
|
||||
float tx = 0.5f * (points[p0].x * q1 + points[p1].x * q2 + points[p2].x * q3 + points[p3].x * q4);
|
||||
float ty = 0.5f * (points[p0].y * q1 + points[p1].y * q2 + points[p2].y * q3 + points[p3].y * q4);
|
||||
|
||||
return{ tx, ty };
|
||||
}
|
||||
};
|
||||
|
||||
class OneLoneCoder_Splines : public olcConsoleGameEngine
|
||||
{
|
||||
public:
|
||||
OneLoneCoder_Splines()
|
||||
{
|
||||
m_sAppName = L"Splines";
|
||||
}
|
||||
|
||||
private:
|
||||
sSpline path;
|
||||
int nSelectedPoint = 0;
|
||||
float fMarker = 0.0f;
|
||||
|
||||
protected:
|
||||
// Called by olcConsoleGameEngine
|
||||
virtual bool OnUserCreate()
|
||||
{
|
||||
//path.points = { { 10, 41 },{ 40, 41 },{ 70, 41 },{ 100, 41 } };
|
||||
path.points = { { 10, 41 },{ 20, 41 },{ 30, 41 },{ 40, 41 },{ 50, 41 },{ 60, 41 },{ 70, 41 },{ 80, 41 },{ 90, 41 },{ 100, 41 } };
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called by olcConsoleGameEngine
|
||||
virtual bool OnUserUpdate(float fElapsedTime)
|
||||
{
|
||||
// Clear Screen
|
||||
Fill(0, 0, ScreenWidth(), ScreenHeight(), L' ');
|
||||
|
||||
// Handle input
|
||||
if (m_keys[L'X'].bReleased)
|
||||
{
|
||||
nSelectedPoint++;
|
||||
if (nSelectedPoint >= path.points.size())
|
||||
nSelectedPoint = 0;
|
||||
}
|
||||
|
||||
if (m_keys[L'Z'].bReleased)
|
||||
{
|
||||
nSelectedPoint--;
|
||||
if (nSelectedPoint < 0)
|
||||
nSelectedPoint = path.points.size() - 1;
|
||||
}
|
||||
|
||||
if (m_keys[VK_LEFT].bHeld)
|
||||
path.points[nSelectedPoint].x -= 30.0f * fElapsedTime;
|
||||
|
||||
if (m_keys[VK_RIGHT].bHeld)
|
||||
path.points[nSelectedPoint].x += 30.0f * fElapsedTime;
|
||||
|
||||
if (m_keys[VK_UP].bHeld)
|
||||
path.points[nSelectedPoint].y -= 30.0f * fElapsedTime;
|
||||
|
||||
if (m_keys[VK_DOWN].bHeld)
|
||||
path.points[nSelectedPoint].y += 30.0f * fElapsedTime;
|
||||
|
||||
if (m_keys[L'A'].bHeld)
|
||||
fMarker -= 5.0f * fElapsedTime;
|
||||
|
||||
if (m_keys[L'S'].bHeld)
|
||||
fMarker += 5.0f * fElapsedTime;
|
||||
|
||||
if (fMarker >= (float)path.points.size())
|
||||
fMarker -= (float)path.points.size();
|
||||
|
||||
if (fMarker < 0.0f)
|
||||
fMarker += (float)path.points.size();
|
||||
|
||||
// Draw Spline
|
||||
for (float t = 0; t < (float)path.points.size(); t += 0.005f)
|
||||
{
|
||||
sPoint2D pos = path.GetSplinePoint(t, true);
|
||||
Draw(pos.x, pos.y);
|
||||
}
|
||||
|
||||
// Draw Control Points
|
||||
for (int i = 0; i < path.points.size(); i++)
|
||||
{
|
||||
Fill(path.points[i].x - 1, path.points[i].y - 1, path.points[i].x + 2, path.points[i].y + 2, PIXEL_SOLID, FG_RED);
|
||||
DrawString(path.points[i].x, path.points[i].y, to_wstring(i));
|
||||
}
|
||||
|
||||
// Highlight control point
|
||||
Fill(path.points[nSelectedPoint].x - 1, path.points[nSelectedPoint].y - 1, path.points[nSelectedPoint].x + 2, path.points[nSelectedPoint].y + 2, PIXEL_SOLID, FG_YELLOW);
|
||||
DrawString(path.points[nSelectedPoint].x, path.points[nSelectedPoint].y, to_wstring(nSelectedPoint));
|
||||
|
||||
// Draw agent to demonstrate gradient
|
||||
sPoint2D p1 = path.GetSplinePoint(fMarker, true);
|
||||
sPoint2D g1 = path.GetSplineGradient(fMarker, true);
|
||||
float r = atan2(-g1.y, g1.x);
|
||||
DrawLine(5.0f * sin(r) + p1.x, 5.0f * cos(r) + p1.y, -5.0f * sin(r) + p1.x, -5.0f * cos(r) + p1.y, PIXEL_SOLID, FG_BLUE);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
OneLoneCoder_Splines demo;
|
||||
demo.ConstructConsole(160, 80, 10, 10);
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
@ -117,7 +117,9 @@ enum COLOUR
|
||||
enum PIXEL_TYPE
|
||||
{
|
||||
PIXEL_SOLID = 0x2588,
|
||||
PIXEL_THREEQUARTERS = 0x2593
|
||||
PIXEL_HALF = 0x2592,
|
||||
PIXEL_QUARTER = 0x2591,
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user