Kenneth Bruen
3 years ago
commit
e2a0f56261
10 changed files with 462 additions and 0 deletions
@ -0,0 +1,33 @@ |
|||||||
|
{ |
||||||
|
// Use IntelliSense to learn about possible attributes. |
||||||
|
// Hover to view descriptions of existing attributes. |
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 |
||||||
|
"version": "0.2.0", |
||||||
|
"configurations": [ |
||||||
|
{ |
||||||
|
"name": "(gdb) Launch", |
||||||
|
"type": "cppdbg", |
||||||
|
"request": "launch", |
||||||
|
"program": "${workspaceFolder}/program", |
||||||
|
"args": [], |
||||||
|
"stopAtEntry": false, |
||||||
|
"cwd": "${fileDirname}", |
||||||
|
"environment": [], |
||||||
|
"externalConsole": false, |
||||||
|
"MIMode": "gdb", |
||||||
|
"setupCommands": [ |
||||||
|
{ |
||||||
|
"description": "Enable pretty-printing for gdb", |
||||||
|
"text": "-enable-pretty-printing", |
||||||
|
"ignoreFailures": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"description": "Set Disassembly Flavor to Intel", |
||||||
|
"text": "-gdb-set disassembly-flavor intel", |
||||||
|
"ignoreFailures": true |
||||||
|
} |
||||||
|
], |
||||||
|
"preLaunchTask": "build debug" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"files.associations": { |
||||||
|
"array": "cpp" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
{ |
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558 |
||||||
|
// for the documentation about the tasks.json format |
||||||
|
"version": "2.0.0", |
||||||
|
"tasks": [ |
||||||
|
{ |
||||||
|
"label": "build", |
||||||
|
"type": "shell", |
||||||
|
"command": "make -B", |
||||||
|
"problemMatcher": [], |
||||||
|
"group": { |
||||||
|
"kind": "build", |
||||||
|
"isDefault": true |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"label": "build debug", |
||||||
|
"type": "shell", |
||||||
|
"options": { |
||||||
|
"env": { |
||||||
|
"CXX_PARAMS": "-g" |
||||||
|
} |
||||||
|
}, |
||||||
|
"command": "make -B" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
LD_PARAMS := -lglut -lGL -lGLU
|
||||||
|
SRC := src
|
||||||
|
OBJ := obj
|
||||||
|
CXX := g++
|
||||||
|
LD := g++
|
||||||
|
|
||||||
|
SOURCES := $(wildcard $(SRC)/*.cpp)
|
||||||
|
OBJECTS := $(patsubst $(SRC)/%.cpp, $(OBJ)/%.o, $(SOURCES))
|
||||||
|
|
||||||
|
all: program |
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f program
|
||||||
|
rm -rf obj
|
||||||
|
|
||||||
|
program: ${OBJECTS} |
||||||
|
$(LD) ${LD_PARAMS} $^ -o $@
|
||||||
|
|
||||||
|
$(OBJECTS): $(OBJ)/%.o: $(SRC)/%.cpp |
||||||
|
$(CXX) ${CXX_PARAMS} $< -c -o $@
|
@ -0,0 +1,6 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
class Drawable { |
||||||
|
public: |
||||||
|
virtual void draw() = 0; |
||||||
|
}; |
@ -0,0 +1,201 @@ |
|||||||
|
#include <functional> |
||||||
|
#include <string> |
||||||
|
#include <cmath> |
||||||
|
|
||||||
|
#include <GL/gl.h> |
||||||
|
#include <GL/glu.h> |
||||||
|
#include <GL/glut.h> |
||||||
|
|
||||||
|
#include "pixel_wise.h" |
||||||
|
#include "drawable.h" |
||||||
|
#include "utils.hpp" |
||||||
|
|
||||||
|
GLfloat deltaTime; |
||||||
|
|
||||||
|
bool gameRunning = false; |
||||||
|
|
||||||
|
bool mouseDown = false; |
||||||
|
int leftScore = 0; |
||||||
|
int rightScore = 0; |
||||||
|
|
||||||
|
int leftMove = 0; |
||||||
|
int rightMove = 0; |
||||||
|
|
||||||
|
void mouse(int button, int state, int x, int y) { |
||||||
|
if (state == GLUT_DOWN) { |
||||||
|
gameRunning = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class BoardMiddle : public Drawable { |
||||||
|
public: |
||||||
|
virtual void draw() { |
||||||
|
glBegin(GL_POLYGON); |
||||||
|
glColor3ub(0xBD, 0xBD, 0xBD); |
||||||
|
glVertex2fv(PW::nm(-2, -1).data()); |
||||||
|
glVertex2fv(PW::nm(2, -1).data()); |
||||||
|
glVertex2fv(PW::nm(2, 1).data()); |
||||||
|
glVertex2fv(PW::nm(-2, 1).data()); |
||||||
|
glEnd(); |
||||||
|
} |
||||||
|
} bm; |
||||||
|
|
||||||
|
class Ball : public Drawable { |
||||||
|
public: |
||||||
|
GLfloat radius; |
||||||
|
GLfloat x, y; |
||||||
|
GLfloat veloX, veloY; |
||||||
|
|
||||||
|
Ball(GLfloat x, GLfloat y) : x(x), y(y), radius(0.025), veloX(0.4) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
virtual void draw() { |
||||||
|
glBegin(GL_POLYGON); |
||||||
|
glColor3ub(0xFF, 0xEE, 0x58); |
||||||
|
for (float i = 0; i < 360; i += 0.5) { |
||||||
|
const auto rad = Utils::toRad(i); |
||||||
|
glVertex2f(x + radius * cos(rad), y + radius * sin(rad)); |
||||||
|
} |
||||||
|
glEnd(); |
||||||
|
} |
||||||
|
|
||||||
|
void update() { |
||||||
|
x += veloX * deltaTime; |
||||||
|
y += veloY * deltaTime; |
||||||
|
} |
||||||
|
} ball {0, 0}; |
||||||
|
|
||||||
|
class Text : public Drawable { |
||||||
|
std::function<std::string()> strObtainer; |
||||||
|
public: |
||||||
|
std::function<GLfloat()> x, y; |
||||||
|
void *font; |
||||||
|
Text(std::function<std::string()> strObtainer, GLfloat x, GLfloat y) : strObtainer(strObtainer), x([=](){return x;}), y([=](){return y;}), font(GLUT_BITMAP_HELVETICA_18) {} |
||||||
|
Text(std::function<std::string()> strObtainer, std::function<GLfloat()> x, std::function<GLfloat()> y) : strObtainer(strObtainer), x(x), y(y), font(GLUT_BITMAP_HELVETICA_18) {} |
||||||
|
Text(std::function<std::string()> strObtainer, std::array<GLfloat, 2> pos) : strObtainer(strObtainer), x([=](){return pos[0];}), y([=](){return pos[1];}), font(GLUT_BITMAP_HELVETICA_18) {} |
||||||
|
Text(std::function<std::string()> strObtainer, std::function<std::array<GLfloat, 2>()> pos) : strObtainer(strObtainer), x([=](){return pos()[0];}), y([=](){return pos()[1];}), font(GLUT_BITMAP_HELVETICA_18) {} |
||||||
|
|
||||||
|
virtual void draw() { |
||||||
|
glRasterPos2f(x(), y()); |
||||||
|
for (const auto& c: strObtainer()) { |
||||||
|
glutBitmapCharacter(font, c); |
||||||
|
} |
||||||
|
} |
||||||
|
} leftScoreText{[](){ return std::to_string(leftScore); }, [](){return PW::tm(-100, 20);}}, |
||||||
|
rightScoreText{[](){ return std::to_string(rightScore); }, [](){return PW::tm(100, 20);}}; |
||||||
|
|
||||||
|
class Paddle : public Drawable { |
||||||
|
public: |
||||||
|
GLfloat height, width; |
||||||
|
GLfloat x, y; |
||||||
|
|
||||||
|
Paddle(GLfloat x, GLfloat y) : x(x), y(y), height(0.4), width(0.02) {} |
||||||
|
|
||||||
|
virtual void draw() { |
||||||
|
glBegin(GL_POLYGON); |
||||||
|
glVertex2f(x, y); |
||||||
|
glVertex2f(x + width, y); |
||||||
|
glVertex2f(x + width, y + height); |
||||||
|
glVertex2f(x, y + height); |
||||||
|
glEnd(); |
||||||
|
} |
||||||
|
} leftPaddle{-0.9, -0.2}, rightPaddle{0.9 - 0.02, -0.2}; |
||||||
|
|
||||||
|
void display(void) { |
||||||
|
glClear(GL_COLOR_BUFFER_BIT); |
||||||
|
|
||||||
|
bm.draw(); |
||||||
|
ball.draw(); |
||||||
|
|
||||||
|
glColor3ub(0x66, 0xBB, 0x6A); |
||||||
|
leftScoreText.draw(); |
||||||
|
leftPaddle.draw(); |
||||||
|
|
||||||
|
glColor3ub(0x42, 0xA5, 0xF5); |
||||||
|
rightScoreText.draw(); |
||||||
|
rightPaddle.draw(); |
||||||
|
|
||||||
|
glFlush(); |
||||||
|
} |
||||||
|
|
||||||
|
int gameTime; |
||||||
|
|
||||||
|
const GLfloat paddleMoveSpeed = 0.75; |
||||||
|
|
||||||
|
void idle() { |
||||||
|
int newTime = glutGet(GLUT_ELAPSED_TIME); |
||||||
|
deltaTime = (newTime - gameTime) / 1000.0; |
||||||
|
gameTime = newTime; |
||||||
|
|
||||||
|
if (gameRunning) { |
||||||
|
ball.update(); |
||||||
|
|
||||||
|
// Move paddle
|
||||||
|
leftPaddle.y += leftMove * paddleMoveSpeed * deltaTime; |
||||||
|
rightPaddle.y += rightMove * paddleMoveSpeed * deltaTime; |
||||||
|
|
||||||
|
// Clamp paddle to stay on screen
|
||||||
|
if (leftPaddle.y < -1) leftPaddle.y = -1; |
||||||
|
if (rightPaddle.y < -1) rightPaddle.y = -1; |
||||||
|
if (leftPaddle.y > 1 - leftPaddle.height) leftPaddle.y = 1 - leftPaddle.height; |
||||||
|
if (rightPaddle.y > 1 - rightPaddle.height) rightPaddle.y = 1 - rightPaddle.height; |
||||||
|
} |
||||||
|
|
||||||
|
glutPostRedisplay(); |
||||||
|
} |
||||||
|
|
||||||
|
void keyDown(unsigned char key, int x, int y) { |
||||||
|
switch(key) { |
||||||
|
case 'w': |
||||||
|
case 'W': |
||||||
|
leftMove = 1; |
||||||
|
break; |
||||||
|
case 's': |
||||||
|
case 'S': |
||||||
|
leftMove = -1; |
||||||
|
break; |
||||||
|
case 'p': |
||||||
|
case 'P': |
||||||
|
rightMove = 1; |
||||||
|
break; |
||||||
|
case ';': |
||||||
|
case ':': |
||||||
|
rightMove = -1; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void keyUp(unsigned char key, int x, int y) { |
||||||
|
switch(key) { |
||||||
|
case 'w': |
||||||
|
case 'W': |
||||||
|
case 's': |
||||||
|
case 'S': |
||||||
|
leftMove = 0; |
||||||
|
break; |
||||||
|
case 'p': |
||||||
|
case 'P': |
||||||
|
case ';': |
||||||
|
case ':': |
||||||
|
rightMove = 0; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) |
||||||
|
{ |
||||||
|
glutInit(&argc, argv); |
||||||
|
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); |
||||||
|
glutInitWindowSize(600, 600); |
||||||
|
glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) * 0.6, (glutGet(GLUT_SCREEN_HEIGHT) - 600) * 0.5); |
||||||
|
glutCreateWindow("Pong"); |
||||||
|
glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF); |
||||||
|
glutKeyboardFunc(keyDown); |
||||||
|
glutKeyboardUpFunc(keyUp); |
||||||
|
glutDisplayFunc(display); |
||||||
|
glutMouseFunc(mouse); |
||||||
|
glutIdleFunc(idle); |
||||||
|
glutMainLoop(); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
#include "pixel_wise.h" |
||||||
|
|
||||||
|
#include <GL/glut.h> |
||||||
|
#include "utils.hpp" |
||||||
|
|
||||||
|
// For personal reference:
|
||||||
|
// x - left->right
|
||||||
|
// y - bottom->top
|
||||||
|
|
||||||
|
std::array<GLfloat, 2> PW::toRelative(GLfloat x, GLfloat y, PW::Anchor anchor) { |
||||||
|
auto winWidth = glutGet(GLUT_WINDOW_WIDTH); |
||||||
|
auto winHeight = glutGet(GLUT_WINDOW_HEIGHT); |
||||||
|
|
||||||
|
std::array<GLfloat, 2> result; |
||||||
|
|
||||||
|
switch (anchor) { |
||||||
|
case PW::BOTTOM_LEFT: |
||||||
|
case PW::MID_LEFT: |
||||||
|
case PW::TOP_LEFT: |
||||||
|
case PW::NONE_LEFT: |
||||||
|
result[0] = Utils::nummap(x, (GLfloat)0, (GLfloat)winWidth, (GLfloat)-1, (GLfloat)1); |
||||||
|
break; |
||||||
|
case PW::BOTTOM_MID: |
||||||
|
case PW::CENTER: |
||||||
|
case PW::TOP_MID: |
||||||
|
case PW::NONE_MID: |
||||||
|
result[0] = Utils::nummap(x, -((GLfloat)winWidth) / 2, ((GLfloat)winWidth) / 2, (GLfloat)-1, (GLfloat)1); |
||||||
|
break; |
||||||
|
case PW::BOTTOM_RIGHT: |
||||||
|
case PW::MID_RIGHT: |
||||||
|
case PW::TOP_RIGHT: |
||||||
|
case PW::NONE_RIGHT: |
||||||
|
result[0] = Utils::nummap(x, -(GLfloat)winWidth, (GLfloat)0, (GLfloat)-1, (GLfloat)1); |
||||||
|
break; |
||||||
|
default: |
||||||
|
result[0] = x; |
||||||
|
} |
||||||
|
|
||||||
|
switch (anchor) { |
||||||
|
case PW::TOP_LEFT: |
||||||
|
case PW::TOP_MID: |
||||||
|
case PW::TOP_RIGHT: |
||||||
|
case PW::TOP_NONE: |
||||||
|
result[1] = Utils::nummap(y, (GLfloat)0, (GLfloat)winHeight, (GLfloat)1, (GLfloat)-1); |
||||||
|
break; |
||||||
|
case PW::MID_LEFT: |
||||||
|
case PW::CENTER: |
||||||
|
case PW::MID_RIGHT: |
||||||
|
case PW::MID_NONE: |
||||||
|
result[1] = Utils::nummap(y, -((GLfloat)winHeight) / 2, ((GLfloat)winHeight) / 2, (GLfloat)1, (GLfloat)-1); |
||||||
|
break; |
||||||
|
case PW::BOTTOM_LEFT: |
||||||
|
case PW::BOTTOM_MID: |
||||||
|
case PW::BOTTOM_RIGHT: |
||||||
|
case PW::BOTTOM_NONE: |
||||||
|
result[1] = Utils::nummap(y, (GLfloat)0, -(GLfloat)winHeight, (GLfloat)1, (GLfloat)-1); |
||||||
|
break; |
||||||
|
default: |
||||||
|
result[1] = y; |
||||||
|
} |
||||||
|
|
||||||
|
return std::move(result); |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <array> |
||||||
|
|
||||||
|
#include <GL/gl.h> |
||||||
|
|
||||||
|
namespace PW { |
||||||
|
enum Anchor |
||||||
|
{ |
||||||
|
MID_LEFT, |
||||||
|
TOP_LEFT, |
||||||
|
TOP_MID, |
||||||
|
TOP_RIGHT, |
||||||
|
MID_RIGHT, |
||||||
|
BOTTOM_RIGHT, |
||||||
|
BOTTOM_MID, |
||||||
|
BOTTOM_LEFT, |
||||||
|
CENTER, |
||||||
|
TOP_NONE, |
||||||
|
MID_NONE, |
||||||
|
BOTTOM_NONE, |
||||||
|
NONE_LEFT, |
||||||
|
NONE_MID, |
||||||
|
NONE_RIGHT, |
||||||
|
}; |
||||||
|
|
||||||
|
/// Convert pixel-space x and y to relative-space (-1 -> 0 -> 1) coords
|
||||||
|
std::array<GLfloat, 2> toRelative(GLfloat x, GLfloat y, Anchor anchor); |
||||||
|
/// Mid-Left `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> ml(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::MID_LEFT); |
||||||
|
} |
||||||
|
/// Top-Left `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> tl(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::TOP_LEFT); |
||||||
|
} |
||||||
|
/// Top-Mid `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> tm(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::TOP_MID); |
||||||
|
} |
||||||
|
/// Top-Right `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> tr(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::TOP_RIGHT); |
||||||
|
} |
||||||
|
/// Mid-Right `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> mr(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::MID_RIGHT); |
||||||
|
} |
||||||
|
/// Bottom-Right `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> br(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::BOTTOM_RIGHT); |
||||||
|
} |
||||||
|
/// Bottom-Mid `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> bm(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::BOTTOM_MID); |
||||||
|
} |
||||||
|
/// Bottom-Left `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> bl(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::BOTTOM_LEFT); |
||||||
|
} |
||||||
|
/// Center `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> c(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::CENTER); |
||||||
|
} |
||||||
|
/// Top-None `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> tn(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::TOP_NONE); |
||||||
|
} |
||||||
|
/// Mid-None `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> mn(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::MID_NONE); |
||||||
|
} |
||||||
|
/// Bottom-None `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> bn(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::BOTTOM_NONE); |
||||||
|
} |
||||||
|
/// None-Left `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> nl(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::NONE_LEFT); |
||||||
|
} |
||||||
|
/// None-Mid `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> nm(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::NONE_MID); |
||||||
|
} |
||||||
|
/// None-Right `toRelative`
|
||||||
|
inline std::array<GLfloat, 2> nr(GLfloat x, GLfloat y) { |
||||||
|
return PW::toRelative(x, y, PW::NONE_RIGHT); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
namespace Utils { |
||||||
|
const double PI = 3.14159265358979323846; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
T nummap(T input, T inMin, T inMax, T outMin, T outMax) { |
||||||
|
// From: https://www.arduino.cc/reference/en/language/functions/math/map/
|
||||||
|
return (input - inMin) * (outMax - outMin) / (inMax - inMin) + outMin; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
constexpr T toRad(T deg) { |
||||||
|
return deg * PI / 180; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue