191 lines
3.9 KiB
C++
191 lines
3.9 KiB
C++
#define OSH_H_IMPLEMENTATION
|
|
#include "osh.h"
|
|
|
|
#include <GL/glew.h>
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#define GRAVITY 0.05
|
|
#define FLOOR_HEIGHT -0.9
|
|
#define JUMP_TIMEOUT 0.14
|
|
#define JUMP_FORCE 0.3
|
|
#define DRAG 0.98
|
|
#define PLAYER_RADIUS 0.02
|
|
|
|
#define PLAYER_COLOR 1.0, 1.0, 1.0
|
|
#define FLOOR_COLOR 0.15, 0.05, 0.05
|
|
#define BACKGROUND_COLOR 0.05, 0.05, 0.05, 1.0
|
|
|
|
void onError(const int error, const char* description) {
|
|
(void) error;
|
|
osh::panic("GLFW error:", description);
|
|
}
|
|
|
|
struct Vector2 {
|
|
double x, y;
|
|
|
|
Vector2(double x = 0, double y = 0) : x(x), y(y) {}
|
|
|
|
Vector2 conjugate() {
|
|
return {x, -y};
|
|
}
|
|
|
|
Vector2 operator*(double d) {
|
|
return {x*d, y*d};
|
|
}
|
|
|
|
Vector2 operator*=(double d) {
|
|
x *= d;
|
|
y *= d;
|
|
return *this;
|
|
}
|
|
|
|
Vector2 operator+(Vector2 v) {
|
|
return {x+v.x, y+v.y};
|
|
}
|
|
|
|
Vector2 operator+=(Vector2 v) {
|
|
x += v.x;
|
|
y += v.y;
|
|
return *this;
|
|
}
|
|
|
|
Vector2 operator-(Vector2 v) {
|
|
return {x-v.x, y-v.y};
|
|
}
|
|
|
|
Vector2 operator-=(Vector2 v) {
|
|
x -= v.x;
|
|
y -= v.y;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
void print1(osh::Formatter auto& fmt, const Vector2& v) {
|
|
osh::printp(fmt, '(', v.x, ", ", v.y, ')');
|
|
}
|
|
|
|
void onResize(GLFWwindow* window, int width, int height) {
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
glViewport(0, 0, width, height);
|
|
|
|
glLoadIdentity();
|
|
glOrtho(
|
|
-double(width) / height, double(width) / height,
|
|
-1, 1,
|
|
0, 1);
|
|
}
|
|
|
|
void fillRect(Vector2 pos, Vector2 size) {
|
|
glBegin(GL_POLYGON);
|
|
|
|
glVertex2d(pos.x, pos.y);
|
|
glVertex2d(pos.x + size.x, pos.y);
|
|
glVertex2d(pos.x + size.x, pos.y - size.y);
|
|
glVertex2d(pos.x, pos.y - size.y);
|
|
|
|
glEnd();
|
|
}
|
|
|
|
void drawPoint(Vector2 pos, double radius) {
|
|
glPointSize(radius);
|
|
glBegin(GL_POINTS);
|
|
glVertex2d(pos.x, pos.y);
|
|
glEnd();
|
|
}
|
|
|
|
struct Player {
|
|
double jumpTimeout = 0;
|
|
Vector2 pos, vel, acc, size;
|
|
|
|
Player() : size(PLAYER_RADIUS, PLAYER_RADIUS) {}
|
|
|
|
void push(Vector2 force) {
|
|
acc += force;
|
|
}
|
|
|
|
void jump() {
|
|
vel.y = JUMP_FORCE;
|
|
jumpTimeout = JUMP_TIMEOUT;
|
|
}
|
|
|
|
void update(double dt) {
|
|
if (jumpTimeout > 0) {
|
|
push({0, JUMP_FORCE});
|
|
jumpTimeout -= dt;
|
|
}
|
|
|
|
vel += acc;
|
|
vel *= DRAG;
|
|
acc = {0, 0};
|
|
|
|
pos += vel * dt;
|
|
pos.y = osh::max(pos.y, FLOOR_HEIGHT + size.y);
|
|
}
|
|
|
|
void draw() {
|
|
glColor3d(PLAYER_COLOR);
|
|
fillRect(pos - size.conjugate(), size*2);
|
|
|
|
glColor3d(1.0, 0, 0);
|
|
drawPoint(pos, 10);
|
|
}
|
|
};
|
|
|
|
Player player;
|
|
|
|
void onKey(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
|
(void) window;
|
|
(void) scancode;
|
|
(void) mods;
|
|
|
|
if (action == GLFW_PRESS) {
|
|
if (key == GLFW_KEY_SPACE) {
|
|
player.jump();
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(void) {
|
|
glfwSetErrorCallback(onError);
|
|
|
|
glfwInit();
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
|
GLFWwindow* window = glfwCreateWindow(640, 480, "HopHop", NULL, NULL);
|
|
|
|
glfwSetKeyCallback(window, onKey);
|
|
glfwSetWindowSizeCallback(window, onResize);
|
|
|
|
glfwMakeContextCurrent(window);
|
|
|
|
if (glewInit() != GLEW_OK) {
|
|
osh::panic("glewInit() failed");
|
|
}
|
|
|
|
double last = glfwGetTime();
|
|
while (!glfwWindowShouldClose(window)) {
|
|
double now = glfwGetTime();
|
|
double dt = now - last;
|
|
|
|
glfwPollEvents();
|
|
|
|
glClearColor(BACKGROUND_COLOR);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
player.push({0, -GRAVITY});
|
|
player.update(dt);
|
|
|
|
player.draw();
|
|
|
|
glColor3d(FLOOR_COLOR);
|
|
fillRect({ -1, FLOOR_HEIGHT }, {2, 2});
|
|
|
|
glfwSwapBuffers(window);
|
|
last = now;
|
|
}
|
|
|
|
glfwDestroyWindow(window);
|
|
glfwTerminate();
|
|
return 0;
|
|
}
|