Содружество Независимых Программистов

Объявление

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Содружество Независимых Программистов » Статьи на [около]программистскую тематику » Переписываем примеры простых игр из туторалов на шейдерный OpenGL


Переписываем примеры простых игр из туторалов на шейдерный OpenGL

Сообщений 1 страница 5 из 5

1

Переписываем примеры простых игр из туторалов на шейдерный OpenGL

На сайте NoobTuts есть короткая статья Make small Games. В ней говориться, что нужно тренироваться на простых играх. Скопировал на форум, на всякий случай:

Make small Games

Make small Games

Foreword

Time to create the first game. Let's make a big MMORPG right?

The Problem

Game developers are enthusiasts. Game developers have big ideas in their head. Now what usually happens is that for their first game they decide to jump right into their dream project.

Time goes by, code gets written and after half a year the project fails due to the overwhelming project size. People get disappointed, teams split up, toes are being stepped on. After taking a little break, they realize that they still love game development and jump right into the next project. This time it's no MMORPG, just a Skyrim clone.

The pattern repeats itself. After a few months people get overwhelmed again. But what is it? Is it the team? Is it the wrong game engine? Is it a lack of skill?

Working on a game project for half a year takes a whole lot of time and hard work. Failing it and knowing that the time was pretty much wasted is the most painful experience that beginners make. And sadly, they make it over and over again.

The Solution

The solution is incredibly simple: make small games. When starting the first game project, the most important thing is to keep it small. From all the ideas you have, pick the smallest one. Maybe make something of the size of pong with a few more special effects, but make it as polished as a game can be.

One month later, chances are high that you will have a finished game in your portfolio. It might be a small one, but it's fun, it's polished and finishing it will be a great ego boost for you. Who knows, maybe you can even make a few dollars with it.

Now the next game project starts. The goal should be a game that is just slightly bigger than the previous one. If the first one took one month to make it, try to make a two months game now. Finish it, polish it, release it and learn from it. That's the process that leads to finishing your dream project some day! And on a side note: looking at a list of 20 games that you finished successfully is a great feeling.

Summary

Starting small and getting confidence and experience is the single most important thing to learn about making games. There is not a single successful MMORPG out there that was created by people who made their first game. Even smaller multiplayer games like Minecraft are usually not someones first project. To be exact, the creator was making games for 20 years already, this should give you an idea about how important experience really is.

В этой теме мы берём туториалы по устаревшему OpenGL версии 1, либо по другим API или движкам и переписываем на актуальный шейдерный OpenGL. Я буду переписывать на TypeScript и WebGL 1.0, потому что это кросс-платформа и запускается в один клик. Возможно буду ещё переписывать на C#/OpenTK, но не в этом году, и даже, наверное, не в следующем. У меня в приоритете TypeScript, WebGL, браузерные интерактивные 3D веб приложения с анимациями, графики на WebGL, небольшие браузерные игры с мультиплеером. TypeScript близок к C#. Есть interface, дженерики. Автором языка TypeScript является Андерс Хейлсберг. Он так же является автором таких языков как: Turbo Pascal, Delphi и C#. Если вам нравится данный челлендж и вы чувствуете, что он будет для вас полезен, то выкладывайте переписанные примеры на своём любимом языке программирования. Главное, чтобы использовался шейдерный OpenGL.

Для удобства навигации, в данном первом сообщении будет содержание со ссылками на соответствующие сообщения. Может вестись переписка и при этом будет сохранён быстрый доступ к нужному коду.

Содержание:

- Змейка на C++, SDL2 и OpenGL3.3 из видео туториала от FamTrinli:  Создание игр на C++: Змейка

- Змейка на TypeScript  и WebGL 1.0 из туториала NoobTuts: Python Snake Game

Отредактировано 8Observer8 (Пн, 9 Дек 2019 12:31)

0

2

Змейка на C++, SDL2 и OpenGL3.3 из видео туториала от FamTrinli: Создание игр на C++: Змейка

http://s5.uploads.ru/t/3c6GM.png

Этот пример я переписал ровно два года назад с устаревшего OpenGL на актуальный шейдерный. Проект создавался в VS2015. Нём все библиотеки подключены. По идее вы можете открыть его в новой VS, например, в VS 2019 и он должен запуститься: Snake_FamTrinliToOpenGL33.zip

main.cpp
Код:
#include <glad/glad.h>
#include <SDL.h>
 
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
 
#include <vector>
#include <string>
#include <iostream>
 
enum class GameState { PLAY, EXIT };
 
class Color
{
public:
    GLfloat r, g, b;
    Color(GLfloat r, GLfloat g, GLfloat b) :
        r(r), g(g), b(b)
    {
    }
};
 
class Point
{
public:
    GLfloat x, y;
    Point(GLfloat x, GLfloat y) :
        x(x), y(y)
    {
    }
};
 
void initVertexBuffers();
GLuint createShaderProgram();
 
void drawSquare(const glm::vec3 &pos, const Color &color, GLfloat size = 1.0f, GLfloat angle = 0.0f);
 
GameState g_gameState = GameState::PLAY;
SDL_Window *g_window;
GLuint g_vao;
GLuint g_program;
 
float g_frameTime;
float g_maxFPS = 3.0f;
float g_fps;
 
const int N = 30;
const int M = 20;
 
const int SCALE = 25;
 
const int W = SCALE * N;
const int H = SCALE * M;
 
int dir, num = 4;
 
struct
{
    int x, y;
} s[100];
 
class Fruits
{
public:
    int x, y;
 
    void createNew()
    {
        x = rand() % N;
        y = rand() % M;
    }
 
    void drawFruit()
    {
        drawSquare(glm::vec3(x * SCALE, y * SCALE, 0.0f), Color(0.0f, 1.0f, 0.0f), SCALE);
    }
} m[10];
 
const char *vertexShaderSource =
"#version 130 core\n"
 
"in vec2 a_position;"
 
"uniform mat4 u_mvp;"
 
"void main()"
"{"
"    gl_Position= u_mvp * vec4(a_position, 0.0, 1.0);"
"}";
 
const char *fragmentShaderSource =
"#version 130 core\n"
"precision mediump float;"
 
"in vec3 v_Color;"
"out vec4 fragColor;"
 
"uniform vec3 u_color;"
 
"void main()"
"{"
"    fragColor = vec4(u_color, 1.0);"
"}";
 
void fatalError(std::string errorString)
{
    std::cout << errorString << std::endl;
    std::cout << "Enter any key to quit..." << std::endl;
    int tmp;
    std::cin >> tmp;
    SDL_Quit();
    exit(1);
}
 
void processInput()
{
    SDL_Event event;
 
    while (SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_QUIT:
                g_gameState = GameState::EXIT;
                break;
            case SDL_KEYDOWN:
                switch (event.key.keysym.sym)
                {
                    case SDLK_w:
                        dir = 0;
                        break;
                    case SDLK_a:
                        dir = 1;
                        break;
                    case SDLK_s:
                        dir = 2;
                        break;
                    case SDLK_d:
                        dir = 3;
                        break;
                }
                break;
        }
    }
}
 
void setGeneralInfo(const glm::vec3 &pos, const Color &color, const glm::vec3 &scale, GLfloat angle)
{
    // Rotate
    GLfloat radian = glm::radians(angle);
    glm::mat4 xformRotateMatrix = glm::rotate(radian, glm::vec3(0.0f, 0.0f, 1.0f));
 
    // Translate
    glm::mat4 xformTranslateMatrix = glm::translate(glm::mat4(), pos);
 
    // Scale
    glm::mat4 xformScaleMatrix = glm::scale(glm::vec3((scale.x, scale.y, scale.z)));
 
    // Set Matrixes
    glm::mat4 projMatrix = glm::ortho(0.0f, (float)W, 0.0f, (float)H, 100.0f, -100.0f);
    glm::mat4 viewMatrix = glm::lookAt(
        glm::vec3(0.0f, 0.0f, 3.0f),    // Camera position
        glm::vec3(0.0f, 0.0f, 0.0f),    // Looks at the origin
        glm::vec3(0.0f, 1.0f, 0.0f));   // Head is up
    glm::mat4 modelMatrix = xformTranslateMatrix * xformRotateMatrix * xformScaleMatrix;
    //glm::mat4 modelMatrix = glm::scale(xformTranslateMatrix, glm::vec3(50.0, 50.0f, 50.0f));
 
    // Set MVP
    glm::mat4 mvp = projMatrix * viewMatrix * modelMatrix;
    GLint u_mvp = glGetUniformLocation(g_program, "u_mvp");
    glUniformMatrix4fv(u_mvp, 1, false, &mvp[0][0]);
 
    // Set Color
    GLint u_color = glGetUniformLocation(g_program, "u_color");
    glUniform3f(u_color, color.r, color.g, color.b);
}
 
void drawSquare(const glm::vec3 &pos, const Color &color, GLfloat size /*= 1.0f*/, GLfloat angle /*= 0.0f*/)
{
    setGeneralInfo(pos, color, glm::vec3(size, size, size), angle);
 
    // Draw
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
 
void drawLine(Point p1, Point p2, const Color &color)
{
    Point center(p1.x + (p2.x - p1.x) / 2.0f, p1.y + (p2.y - p1.y) / 2.0f);
 
    GLfloat a = p2.y - p1.y;
    GLfloat b = p2.x - p1.x;
    GLfloat tan = a / b;
    GLfloat angle = glm::degrees(glm::atan(tan));
    GLfloat length = glm::length(glm::vec2(b, a));
    
    setGeneralInfo(
        glm::vec3(center.x, center.y, 0.0f),
        color,
        glm::vec3(1.0f, 1.0f, length),
        angle);
    glDrawArrays(GL_LINES, 4, 2);
}
 
void drawField()
{
    Color color(0.0f, 1.0f, 0.0f);
 
    for (size_t i = 0; i < W; i += SCALE)
    {
        drawLine(Point(i, 0.0f), Point(i, H), color);
    }
 
    for (size_t j = 0; j < H; j += SCALE)
    {
        drawLine(Point(0.0f, j), Point(W, j), color);
    }
}
 
void drawSnake()
{
    for (size_t i = 0; i < num; i++)
    {
        drawSquare(glm::vec3(s[i].x * SCALE, s[i].y * SCALE, 0.0f), Color(0.0f, 0.0f, 1.0f), SCALE);
    }
}
 
void display()
{
    // Clear a screen
    glClear(GL_COLOR_BUFFER_BIT);
 
    // Set a viewport on whole screen
    glViewport(0, 0, W, H);
 
    for (size_t i = 0; i < 10; i++)
    {
        m[i].drawFruit();
    }
 
    drawField();
 
    drawSnake();
 
    SDL_GL_SwapWindow(g_window);
}
 
void calculateFPS()
{
    static const int NUM_SAMPLES = 10;
    static float frameTimes[NUM_SAMPLES];
    static int currentFrame = 0;
 
    static float prevTicks = SDL_GetTicks();
    float currentTicks;
    currentTicks = SDL_GetTicks();
 
    g_frameTime = currentTicks - prevTicks;
    frameTimes[currentFrame % NUM_SAMPLES] = g_frameTime;
 
    prevTicks = currentTicks;
 
    int count;
    currentFrame++;
 
    if (currentFrame < NUM_SAMPLES)
    {
        count = currentFrame;
    }
    else
    {
        count = NUM_SAMPLES;
    }
 
    float frameTimeAverage = 0;
    for (int i = 0; i < count; i++)
    {
        frameTimeAverage += frameTimes[i];
    }
    frameTimeAverage /= count;
 
    if (frameTimeAverage > 0)
    {
        g_fps = 1000.0f / frameTimeAverage;
    }
    else
    {
        g_fps = 60.0f;
    }
}
 
void tick()
{
    for (size_t i = num; i > 0; --i)
    {
        s[i].x = s[i - 1].x;
        s[i].y = s[i - 1].y;
    }
 
    if (dir == 0)
    {
        s[0].y += 1;
    }
    if (dir == 1)
    {
        s[0].x -= 1;
    }
    if (dir == 2)
    {
        s[0].y -= 1;
    }
    if (dir == 3)
    {
        s[0].x += 1;
    }
 
    for (size_t i = 0; i < 10; i++)
    {
        if ((s[0].x == m[i].x) && (s[0].y == m[i].y))
        {
            num++;
            m[i].createNew();
        }
    }
 
    if (s[0].y > M)
    {
        dir = 2;
    }
 
    if (s[0].x < 0)
    {
        dir = 3;
    }
 
    if (s[0].y < 0)
    {
        dir = 0;
    }
 
    if (s[0].x > N)
    {
        dir = 1;
    }
 
    for (size_t i = 1; i < num; i++)
    {
        if (s[0].x == s[i].x && s[0].y == s[i].y)
        {
            num = i;
        }
    }
}
 
void gameLoop()
{
    while (g_gameState != GameState::EXIT)
    {
        processInput();
        float startTicks = SDL_GetTicks();
 
        tick();
        
        display();
 
        calculateFPS();
        // Print only once every 10 frames
        static int frameCounter = 0;
        frameCounter++;
        if (frameCounter == 10)
        {
            std::cout << g_fps << std::endl;
            frameCounter = 0;
        }
 
        float frameTicks = SDL_GetTicks() - startTicks;
        // Limit the FPS to the max FPS
        if (1000.0f / g_maxFPS > frameTicks)
        {
            SDL_Delay(1000.0f / g_maxFPS - frameTicks);
        }
    }
 
    SDL_DestroyWindow(g_window);
 
    SDL_Quit();
}
 
int main(int argc, char **argv)
{
    SDL_Init(SDL_INIT_EVERYTHING);
 
    g_window = SDL_CreateWindow(
        "Snake FamTrinli To OpenGL 3.0",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        W, H,
        SDL_WINDOW_OPENGL);
 
    if (g_window == nullptr)
    {
        fatalError("SDL Window could not be created");
    }
 
    SDL_GLContext glContext = SDL_GL_CreateContext(g_window);
    if (glContext == nullptr)
    {
        fatalError("SDL_GL context could not be created");
    }
 
    if (!gladLoadGL())
    {
        fatalError("Could not initialize glad!");
    }
 
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
 
    g_program = createShaderProgram();
    initVertexBuffers();
 
    for (size_t i = 0; i < 10; i++)
    {
        m[i].createNew();
    }
 
    s[0].x = 10;
    s[0].y = 0;
    for (size_t i = 1; i < num; i++)
    {
        s[i].x = s[0].x;
        s[i].y = s[i - 1].y - 1;
    }
 
    gameLoop();
    return 0;
}
 
GLuint createShader(const char *shaderSource, int shaderType)
{
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &shaderSource, NULL);
    glCompileShader(shader);
    GLint status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE)
    {
        GLint maxLength = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
        std::vector<GLchar> errorLog(maxLength);
        glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
        glDeleteShader(shader); // Don't leak the shader.
        std::printf("%s\n", &(errorLog[0]));
        fatalError("Shader failed to compile");
    }
    return shader;
}
 
GLuint createShaderProgram()
{
    GLuint program = glCreateProgram();
    GLuint vShader = createShader(vertexShaderSource, GL_VERTEX_SHADER);
    GLuint fShader = createShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
 
    glAttachShader(program, vShader);
    glAttachShader(program, fShader);
    glLinkProgram(program);
    glUseProgram(program);
 
    return program;
}
 
void initVertexBuffers()
{
    GLfloat vertices[] = {
        0.0f, 1.0f,    // Square
        0.0f, 0.0f,
        1.0f, 1.0f,
        1.0f, 0.0f,
        -0.5f, 0.0f,    // Line
        0.5f, 0.0f
    };
 
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    int numVertices = sizeof(vertices) / sizeof(vertices[0]);
    glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
 
    glGenVertexArrays(1, &g_vao);
    glBindVertexArray(g_vao);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
 
    GLint a_position = glGetAttribLocation(g_program, "a_position");
    glVertexAttribPointer(a_position, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(a_position);
}

- Окно создаётся с помощью библиотеки SDL2
- Для создания матриц (трансформаций, матрицы перспективы и вида) используется математическая библиотека GLM
- Для загрузки указателей на функции OpenGL используется библиотека GLAD

Отредактировано 8Observer8 (Пн, 9 Дек 2019 12:33)

0

3

Змейка на WebGL 1.0 и TypeScript из туториала NoobTuts: Python Snake Game

http://s7.uploads.ru/t/YOkeX.png

Игровая демка и исходники в песочнице: запустить в один клик на любой ОС

Исходники на GitHub

Этот код я переписал ровно год назад. Получается, что раз в год у меня случается обострение. Код близок к оригиналу. Оригинал на устаревшем OpenGL версии 1. Я поменял ортогональный вид на вид с перспективой.

Описание:
- Музыка и звуки с помощью HTMLAudioElement
- Графика с помощью WebGL 1.0 и GLSL
- Трансформации с помощью математической библиотеки glMatrix
- Язык программирования TypeScript
- Настроена компиляция из TS в ES5
- Настроена установка точек останова и пошаговое выполнение в редакторе кода VSCode с использованием Source Maps
- Настроена загрузка AMD-модулей в браузер с помощью библиотеки RequireJS

Запуск игры локально из исходников, при условии, что установлен NodeJS
- Скачать архив по ссылкам выше
- Перейти в папку с игрой из консоли
- Набрать в консоле команду: npm install
- Набрать в консоле команду: tsc
- Запустить index.html по localhost с сервера

Отредактировано 8Observer8 (Пн, 9 Дек 2019 12:32)

0

4

Ты не там темы размещаешь. Я для этого раздел выделил: Статьи на [около]программистскую тематику
Переместить туда?

0

5

Я подумал, что это на статьи мало похоже, это ближе к обсуждению. Да, можно переместить.

0


Вы здесь » Содружество Независимых Программистов » Статьи на [около]программистскую тематику » Переписываем примеры простых игр из туторалов на шейдерный OpenGL