Hello,
What can I try to solve this problem? In this example I am using OpenGL 1.1 with deprecated functions like: glEnableClientState, glMatrixMode, glTexCoordPointer, and so on. Yes, I know that using deprecated functions is bad. I also use shaders. But this is a task that I do for a student. His teacher demands to use deprecated functions. Thanks in advance.
main.cpp
#include <GLFW/glfw3.h>
#include <iostream>
#include <map>
#include <box2d/box2d.h>
#include <fmod.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
using namespace std;
#define W 516
#define H 432
// Font: https://www.fontspace.com/category/mario
FMOD_SYSTEM *soundSystem;
FMOD_SOUND *mainTheme;
FMOD_SOUND *jumpSound;
map<int, bool> keys;
b2Vec2 gravity(0.0f, 9.8f);
b2World world(gravity);
const float WORLD_SCALE = 30.f;
b2Body *playerBody;
GLFWwindow *window;
GLuint spriteTexture;
char spritePath[] = "assets/sprites/small-mario.png";
GLuint backgroundTexture;
char backgroundPath[] = "assets/sprites/background.png";
const float imageWidth = 288.f;
float vertPositions[] = {-0.5f, -0.5f, 0.f, // Idle
-0.5f, 0.5f, 0.f,
0.5f, -0.5f, 0.f,
0.5f, 0.5f, 0.f,
-0.5f, -0.5f, 0.f, // Run 0
-0.5f, 0.5f, 0.f,
0.5f, -0.5f, 0.f,
0.5f, 0.5f, 0.f,
-0.5f, -0.5f, 0.f, // Run 1
-0.5f, 0.5f, 0.f,
0.5f, -0.5f, 0.f,
0.5f, 0.5f, 0.f,
-0.5f, -0.5f, 0.f, // Run 2
-0.5f, 0.5f, 0.f,
0.5f, -0.5f, 0.f,
0.5f, 0.5f, 0.f,
0.f, 0.f, 0.f, // Background
0.f, 1.f, 0.f,
1.f, 0.f, 0.f,
1.f, 1.f, 0.f,
-0.5f, -0.5f, 0.f, // Enemy 0
-0.5f, 0.5f, 0.f,
0.5f, -0.5f, 0.f,
0.5f, 0.5f, 0.f,
-0.5f, -0.5f, 0.f, // Coin
-0.5f, 0.5f, 0.f,
0.5f, -0.5f, 0.f,
0.5f, 0.5f, 0.f};
float texCoords[] = {0.f, 0.f, // Idle
0.f, 1.f,
16.f / imageWidth, 0.f,
16.f / imageWidth, 1.f,
32.f / imageWidth, 0.f, // Run 0
32.f / imageWidth, 1.f,
48.f / imageWidth, 0.f,
48.f / imageWidth, 1.f,
48.f / imageWidth, 0.f, // Run 1
48.f / imageWidth, 1.f,
64.f / imageWidth, 0.f,
64.f / imageWidth, 1.f,
64.f / imageWidth, 0.f, // Run 2
64.f / imageWidth, 1.f,
80.f / imageWidth, 0.f,
80.f / imageWidth, 1.f,
0.f, 0.f, // Background
0.f, 1.f,
1.f, 0.f,
1.f, 1.f,
224.f / imageWidth, 0.f, // Enemy 0
224.f / imageWidth, 1.f,
240.f / imageWidth, 0.f,
240.f / imageWidth, 1.f,
272.f / imageWidth, 0.f, // Coin
272.f / imageWidth, 1.f,
288.f / imageWidth, 0.f,
288.f / imageWidth, 1.f};
GLuint createTexture(char *path)
{
int h_image, w_image, cnt;
unsigned char *data = stbi_load(path, &w_image, &h_image, &cnt, 0);
if (data == NULL)
{
cout << "Failed to load an image" << endl;
glfwTerminate();
exit(-1);
}
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_image, h_image, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
}
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
return texture;
}
void keyboard(GLFWwindow *window, int key, int scode, int action, int smode)
{
// Jump Press
if ((key == GLFW_KEY_W || key == GLFW_KEY_UP || key == GLFW_KEY_SPACE) && (action == GLFW_REPEAT || action == GLFW_PRESS))
{
// Check if onGround
bool onGround = false;
b2Vec2 pos = playerBody->GetPosition();
pos.y += 9 / WORLD_SCALE;
for (b2Body *it = world.GetBodyList(); it != 0; it = it->GetNext())
{
for (b2Fixture *f = it->GetFixtureList(); f != 0; f = f->GetNext())
{
if (f->TestPoint(pos))
{
onGround = true;
}
}
}
if (onGround)
{
float impulse = playerBody->GetMass() * -6.7f;
playerBody->ApplyLinearImpulse(b2Vec2(0, impulse), playerBody->GetWorldCenter(), true);
// FMOD_System_PlaySound(soundSystem, jumpSound, 0, false, 0);
}
}
// Press a left key
if ((key == GLFW_KEY_A || key == GLFW_KEY_LEFT) && (action == GLFW_REPEAT || action == GLFW_PRESS))
{
keys[key] = true;
}
// Press a right key
if ((key == GLFW_KEY_D || key == GLFW_KEY_RIGHT) && (action == GLFW_REPEAT || action == GLFW_PRESS))
{
keys[key] = true;
}
// Release a left key
if ((key == GLFW_KEY_A || key == GLFW_KEY_LEFT) && action == GLFW_RELEASE) // Left
{
keys[key] = false;
}
// Release a right key
if ((key == GLFW_KEY_D || key == GLFW_KEY_RIGHT) && action == GLFW_RELEASE) // Right
{
keys[key] = false;
}
}
int main()
{
if (!glfwInit())
{
cout << "Failed to init GLFW" << endl;
return -1;
}
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
window = glfwCreateWindow(W, H, "GLFW, OpenGL 1.1", nullptr, nullptr);
if (!window)
{
cout << "Failed to create the GLFW window" << endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glClearColor(0.2f, 0.5f, 0.3f, 1.f);
glViewport(0, 0, W, H);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 256, 216, 0, -100.f, 100.f);
spriteTexture = createTexture(spritePath);
backgroundTexture = createTexture(backgroundPath);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertPositions);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glfwSetKeyCallback(window, keyboard);
FMOD_System_Create(&soundSystem, FMOD_VERSION);
FMOD_System_Init(soundSystem, 32, FMOD_INIT_NORMAL, 0);
// FMOD_System_CreateSound(soundSystem, "assets/sounds/01-main-theme-overworld.mp3", FMOD_LOOP_NORMAL | FMOD_2D, 0, &mainTheme);
// FMOD_System_PlaySound(soundSystem, mainTheme, 0, false, 0);
FMOD_System_CreateSound(soundSystem, "assets/sounds/smb_jump-small.wav", FMOD_LOOP_OFF | FMOD_2D, 0, &jumpSound);
// Player
b2CircleShape playerShape;
playerShape.m_radius = 8.f / WORLD_SCALE;
b2BodyDef playerBodyDef;
playerBodyDef.type = b2_dynamicBody;
playerBody = world.CreateBody(&playerBodyDef);
playerBody->CreateFixture(&playerShape, 5.f);
playerBody->SetTransform(b2Vec2(100.f / WORLD_SCALE, 100.f / WORLD_SCALE), 0.f);
playerBody->SetFixedRotation(true);
const float playerSpeed = 3.f;
// Ground
b2PolygonShape groundShape;
groundShape.SetAsBox(500.f / WORLD_SCALE, 16.f / WORLD_SCALE);
b2BodyDef groundBodyDef;
groundBodyDef.type = b2_staticBody;
b2Body *groundBody = world.CreateBody(&groundBodyDef);
groundBody->CreateFixture(&groundShape, 0.f);
groundBody->SetTransform(b2Vec2(100.f / WORLD_SCALE, 208.f / WORLD_SCALE), 0.f);
b2BodyDef platformBodyDef;
platformBodyDef.type = b2_staticBody;
// Platform 1
b2PolygonShape platform1Shape;
platform1Shape.SetAsBox(8.f / WORLD_SCALE, 8.f / WORLD_SCALE);
b2Body *platform1Body = world.CreateBody(&platformBodyDef);
platform1Body->CreateFixture(&platform1Shape, 0.f);
platform1Body->SetTransform(b2Vec2(98.f / WORLD_SCALE, 136.f / WORLD_SCALE), 0.f);
// Platform 2
b2PolygonShape platform2Shape;
platform2Shape.SetAsBox(40.f / WORLD_SCALE, 8.f / WORLD_SCALE);
b2Body *platform2Body = world.CreateBody(&platformBodyDef);
platform2Body->CreateFixture(&platform2Shape, 0.f);
platform2Body->SetTransform(b2Vec2(194.f / WORLD_SCALE, 136.f / WORLD_SCALE), 0.f);
// Platform 3
b2PolygonShape platform3Shape;
platform3Shape.SetAsBox(8.f / WORLD_SCALE, 8.f / WORLD_SCALE);
b2Body *platform3Body = world.CreateBody(&platformBodyDef);
platform3Body->CreateFixture(&platform3Shape, 0.f);
platform3Body->SetTransform(b2Vec2(194.f / WORLD_SCALE, 72.f / WORLD_SCALE), 0.f);
float currentTime, deltaTime;
float lastTime = glfwGetTime();
float animationTime = 0.f;
const float timePeriod = 0.1f;
unsigned int drawingIndex = 0;
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
currentTime = glfwGetTime();
deltaTime = currentTime - lastTime;
lastTime = currentTime;
world.Step(deltaTime, 6, 2);
if (keys[GLFW_KEY_A] || keys[GLFW_KEY_LEFT])
{
b2Vec2 vel = playerBody->GetLinearVelocity();
vel.x = -playerSpeed;
playerBody->SetLinearVelocity(vel);
}
if (keys[GLFW_KEY_D] || keys[GLFW_KEY_RIGHT])
{
b2Vec2 vel = playerBody->GetLinearVelocity();
vel.x = playerSpeed;
playerBody->SetLinearVelocity(vel);
}
if (!keys[GLFW_KEY_A] && !keys[GLFW_KEY_LEFT] && !keys[GLFW_KEY_D] && !keys[GLFW_KEY_RIGHT])
{
b2Vec2 vel = playerBody->GetLinearVelocity();
vel.x = 0.f;
playerBody->SetLinearVelocity(vel);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Player
glBindTexture(GL_TEXTURE_2D, spriteTexture);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(playerBody->GetPosition().x * WORLD_SCALE,
playerBody->GetPosition().y * WORLD_SCALE, 10.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, drawingIndex, 4);
// Coin
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(178.f, 120.f, 10.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 24, 4);
// Enemy
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(194.f, 184.f, 10.f);
glScalef(16.f, 16.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
// Background
glBindTexture(GL_TEXTURE_2D, backgroundTexture);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.f, 0.f, 0.f);
glScalef(256.f, 216.f, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
glfwSwapBuffers(window);
// animationTime += deltaTime;
// if (animationTime >= timePeriod)
// {
// animationTime = 0.f;
// glMatrixMode(GL_MODELVIEW);
// glLoadIdentity();
// glTranslatef(playerBody->GetPosition().x * WORLD_SCALE,
// playerBody->GetPosition().y * WORLD_SCALE, 0.f);
// glScalef(50.f, 50.f, 1.f);
// glDrawArrays(GL_TRIANGLE_STRIP, drawingIndex, 4);
// glfwSwapBuffers(window);
// // cout << drawingIndex << endl;
// drawingIndex += 4;
// if (drawingIndex >= 12)
// {
// drawingIndex = 0;
// }
// }
// glPushMatrix();
// {
// }
// glPopMatrix();
}
glfwTerminate();
return 0;
}
makefile
# command to build: mingw32-make
INC = -I"E:\Libs\glfw-3.3.8-mingw-64bit\include" \
-I"E:\Libs\stb_image-2.27\include" \
-I"E:\Libs\box2d-2.4.1-mingw-64-bit\include" \
-I"C:\Program Files\FMOD SoundSystem\FMOD Studio API Windows\api\core\inc"
LIB = -L"E:\Libs\glfw-3.3.8-mingw-64bit\lib" \
-L"E:\Libs\box2d-2.4.1-mingw-64-bit\lib"
all: main.o
g++ main.o $(LIB) -lglfw3 -lgdi32 -lopengl32 -lbox2d -o app.exe \
"C:\Program Files\FMOD SoundSystem\FMOD Studio API Windows\api\core\lib\x64\fmod.dll"
main.o: main.cpp
g++ -c $(INC) main.cpp