Initial commit
This commit is contained in:
commit
e2a0f56261
10 changed files with 462 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
program
|
||||
obj/**
|
33
.vscode/launch.json
vendored
Normal file
33
.vscode/launch.json
vendored
Normal file
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"array": "cpp"
|
||||
}
|
||||
}
|
27
.vscode/tasks.json
vendored
Normal file
27
.vscode/tasks.json
vendored
Normal file
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
20
Makefile
Normal file
20
Makefile
Normal file
|
@ -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 $@
|
6
src/drawable.h
Normal file
6
src/drawable.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
class Drawable {
|
||||
public:
|
||||
virtual void draw() = 0;
|
||||
};
|
201
src/main.cpp
Normal file
201
src/main.cpp
Normal file
|
@ -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;
|
||||
}
|
63
src/pixel_wise.cpp
Normal file
63
src/pixel_wise.cpp
Normal file
|
@ -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);
|
||||
}
|
89
src/pixel_wise.h
Normal file
89
src/pixel_wise.h
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
16
src/utils.hpp
Normal file
16
src/utils.hpp
Normal file
|
@ -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…
Add table
Reference in a new issue