Skip to content

Commit c1df7b1

Browse files
committed
ParticleEmitter
1 parent 7dfa686 commit c1df7b1

File tree

7 files changed

+124
-23
lines changed

7 files changed

+124
-23
lines changed

resources/shaders/particle/shader.vert

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ out vec2 uv;
88
uniform mat4 projection;
99
uniform vec2 offset;
1010

11-
float scale = 10.0f;
11+
float scale = 15.0f;
1212

1313
void main() {
1414
uv = vertex.zw;

resources/shaders/sprite/shader.frag

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
in vec2 uv;
44
out vec4 finalColor;
55

6-
uniform sampler2D image;
6+
uniform sampler2D sprite;
77
uniform vec3 color;
88

99
void main() {
10-
finalColor = texture(image, uv) * vec4(color, 1.0f);
10+
finalColor = texture(sprite, uv) * vec4(color, 1.0f);
1111
}

resources/textures/particle.png

18.5 KB
Loading

src/Game.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ void Game::input(GLfloat delta) {
6464

6565
void Game::update(GLfloat delta) {
6666
ball_->update(delta);
67+
particleEmitter_->update(delta, *ball_, 5, glm::vec2(ball_->radius() / 2));
6768
this->checkCollisions();
6869
}
6970

@@ -75,6 +76,7 @@ void Game::render() {
7576

7677
levels_[currentLevel_]->render(spriteRenderer_);
7778
player_->render(spriteRenderer_);
79+
particleEmitter_->render();
7880
ball_->render(spriteRenderer_);
7981
}
8082

@@ -105,19 +107,28 @@ void Game::initGL() {
105107
}
106108

107109
void Game::initResources() {
108-
auto shader = resourceManager_.createShaderProgram("sprite",
109-
Shader(ShaderType::VERTEX,
110-
"../resources/shaders/sprite/shader.vert"),
111-
Shader(ShaderType::FRAGMENT,
112-
"../resources/shaders/sprite/shader.frag"));
110+
auto spriteShader = resourceManager_.createShaderProgram("sprite",
111+
Shader(ShaderType::VERTEX,
112+
"../resources/shaders/sprite/shader.vert"),
113+
Shader(ShaderType::FRAGMENT,
114+
"../resources/shaders/sprite/shader.frag"));
113115
glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(window_->width()),
114116
static_cast<GLfloat>(window_->height()), 0.0f,
115117
-1.0f, 1.0f);
116-
shader->use();
117-
shader->setUniform("projection", projection);
118-
shader->setUniform("image", 0);
118+
spriteShader->use();
119+
spriteShader->setUniform("projection", projection);
120+
spriteShader->setUniform("sprite", 0);
119121

120-
spriteRenderer_.init(shader);
122+
spriteRenderer_.init(spriteShader);
123+
124+
auto particleShader = resourceManager_.createShaderProgram("particle",
125+
Shader(ShaderType::VERTEX,
126+
"../resources/shaders/particle/shader.vert"),
127+
Shader(ShaderType::FRAGMENT,
128+
"../resources/shaders/particle/shader.frag"));
129+
particleShader->use();
130+
particleShader->setUniform("projection", projection);
131+
particleShader->setUniform("sprite", 0);
121132

122133
resourceManager_.createTexture("background",
123134
"../resources/textures/background.jpg",
@@ -134,6 +145,13 @@ void Game::initResources() {
134145
resourceManager_.createTexture("paddle",
135146
"../resources/textures/paddle.png",
136147
512, 128, 4, GL_RGBA);
148+
resourceManager_.createTexture("particle",
149+
"../resources/textures/particle.png",
150+
500, 500, 4, GL_RGBA);
151+
152+
particleEmitter_ = std::make_unique<ParticleEmitter>(resourceManager_.shaderProgram("particle"),
153+
resourceManager_.texture("particle"),
154+
500);
137155

138156
levels_.push_back(std::make_unique<GameLevel>(
139157
"../resources/levels/1.txt", window_->width(), window_->height() / 2));

src/Game.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "game/GameLevel.h"
1111
#include "game/Player.h"
1212
#include "game/Ball.h"
13+
#include "graphics/ParticleEmitter.h"
1314
#include <memory>
1415
#include <vector>
1516

@@ -37,6 +38,7 @@ class Game {
3738
ResourceManager& resourceManager_ = ResourceManager::Instance();
3839

3940
SpriteRenderer& spriteRenderer_ = SpriteRenderer::Instance();
41+
std::unique_ptr<ParticleEmitter> particleEmitter_;
4042

4143
void initWindow(int width, int height, bool isFullScreen);
4244
void initGL();

src/graphics/ParticleEmitter.cpp

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,115 @@
11
#include "ParticleEmitter.h"
2+
#include <cstdlib>
23
#include <iostream>
34

45
ParticleEmitter::ParticleEmitter(ShaderProgram *shaderProgram,
56
Texture *texture,
67
GLuint amount)
7-
: shaderProgram_(shaderProgram), texture_(texture), amount_(amount) {
8+
: shaderProgram_(shaderProgram), texture_(texture), amount_(amount), lastUsedParticle_(0) {
89
std::cout << "ParticleEmitter constructor" << std::endl;
910

11+
GLfloat quad[] = {
12+
0.0f, 1.0f, 0.0f, 1.0f,
13+
1.0f, 0.0f, 1.0f, 0.0f,
14+
0.0f, 0.0f, 0.0f, 0.0f,
1015

16+
0.0f, 1.0f, 0.0f, 1.0f,
17+
1.0f, 1.0f, 1.0f, 1.0f,
18+
1.0f, 0.0f, 1.0f, 0.0f
19+
};
20+
21+
glGenVertexArrays(1, &VAO_);
22+
glGenBuffers(1, &VBO_);
23+
glBindVertexArray(VAO_);
24+
25+
glBindBuffer(GL_ARRAY_BUFFER, VBO_);
26+
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
27+
28+
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid *) 0);
29+
glEnableVertexAttribArray(0);
30+
31+
glBindVertexArray(0);
32+
33+
for (GLuint i = 0; i < amount_; i++) {
34+
particles_.push_back(Particle());
35+
}
1136
}
1237

1338
ParticleEmitter::~ParticleEmitter() {
1439
std::cout << "ParticleEmitter destructor" << std::endl;
40+
41+
glDeleteVertexArrays(1, &VAO_);
42+
glDeleteBuffers(1, &VBO_);
1543
}
1644

1745
void ParticleEmitter::update(float delta,
18-
const GameObject& object,
46+
const Ball& object,
1947
int newParticles,
2048
const glm::vec2 offset) {
49+
// Add new particles
50+
for (GLuint i = 0; i < newParticles; i++) {
51+
int unusedParticle = this->getFirstUnusedParticle();
52+
this->respawnParticle(particles_[unusedParticle], object, offset);
53+
}
2154

55+
// Update all particles
56+
for (auto& particle: particles_) {
57+
particle.lifespan -= delta;
58+
if (particle.lifespan > 0.0f) {
59+
particle.position -= particle.velocity * delta;
60+
particle.color.a -= delta * 2.5;
61+
}
62+
}
2263
}
2364

2465
void ParticleEmitter::render() {
25-
66+
// Use additive blending to give it a 'glow' effect
67+
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
68+
shaderProgram_->use();
69+
for (auto& particle: particles_) {
70+
if (particle.lifespan > 0.0f) {
71+
shaderProgram_->setUniform("offset", particle.position);
72+
shaderProgram_->setUniform("particleColor", particle.color);
73+
texture_->bind();
74+
glBindVertexArray(VAO_);
75+
glDrawArrays(GL_TRIANGLES, 0, 6);
76+
glBindVertexArray(0);
77+
}
78+
}
79+
// Reset to default blending mode
80+
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2681
}
2782

2883
GLuint ParticleEmitter::getFirstUnusedParticle() {
29-
return 0;
84+
// First search from last used particle, this will usually return almost instantly
85+
for (GLuint i = lastUsedParticle_; i < amount_; i++) {
86+
if (particles_[i].lifespan <= 0.0f) {
87+
lastUsedParticle_ = i;
88+
return i;
89+
}
90+
}
91+
92+
// Otherwise, do a linear search
93+
for (GLuint i = 0; i < lastUsedParticle_; i++) {
94+
if (particles_[i].lifespan <= 0.0f) {
95+
lastUsedParticle_ = i;
96+
return i;
97+
}
98+
}
99+
100+
// All particles are taken, override the first one
101+
// (note that if it repeatedly hits this case, more particles should be reserved)
102+
lastUsedParticle_ = 0;
103+
return lastUsedParticle_;
30104
}
31105

32-
void ParticleEmitter::respawnParticle(const Particle& particle,
33-
const GameObject& object,
106+
void ParticleEmitter::respawnParticle(Particle& particle,
107+
const Ball& object,
34108
const glm::vec2& offset) {
35-
109+
GLfloat random = ((rand() % 100) - 50) / 10.0f;
110+
GLfloat color = (GLfloat) 0.5 + ((rand() % 100) / 100.0f);
111+
particle.position = object.position() + random + offset;
112+
particle.color = glm::vec4(color, color, color, 1.0f);
113+
particle.lifespan = 1.0f;
114+
particle.velocity = object.velocity() * 0.1f;
36115
}

src/graphics/ParticleEmitter.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
#include "Texture.h"
44
#include "ShaderProgram.h"
5-
#include "../game/GameObject.h"
65
#include "Particle.h"
6+
#include "../game/Ball.h"
77
#include <GL/glew.h>
88
#include <vector>
99

@@ -13,7 +13,7 @@ class ParticleEmitter {
1313
~ParticleEmitter();
1414

1515
void update(float delta,
16-
const GameObject& object,
16+
const Ball& object,
1717
int newParticles,
1818
const glm::vec2 offset = glm::vec2(0.0f));
1919
void render();
@@ -26,8 +26,10 @@ class ParticleEmitter {
2626
GLuint VAO_;
2727
GLuint VBO_;
2828

29+
GLuint lastUsedParticle_;
30+
2931
GLuint getFirstUnusedParticle();
30-
void respawnParticle(const Particle& particle,
31-
const GameObject& object,
32+
void respawnParticle(Particle& particle,
33+
const Ball& object,
3234
const glm::vec2& offset = glm::vec2(0.0f));
3335
};

0 commit comments

Comments
 (0)