I'm making a simple, gravity based particle system, so I made three classes:
ParticleManager, that store the particle system
ParticleSystem, the VertexArray containing particles with an update function
Particle, a Vertex inheriting from sf::Transformable.
Actually, I'm stuck with ParticleSystem update function here's the code:
ParticleSystem()
{
particles.setPrimitiveType(PrimitiveType::Points);
int indexX = 0, indexY = 0;
for (int i = 1; i < CHUNK_SIZE; i++)
{
Particle particle;
particle.position = Vector2f(indexX, indexY);
particles.append(particle);
if (indexX < 100)
indexX++;
else
{
indexX = 0;
indexY++;
}
force.push_back(0);
}
}
void Update()
{
for (int i = 0; i < particles.getVertexCount(); i++)
{
particles[i].Update();
}
}
The compiler gives an error when calling particles[i].Update(), because VertexArray can contain just sf::Vertex;
Any suggestion for implementing that function?
Make your own vector.
std::vector<Particle> particles;
Related
I'm trying game development. I tried a sample from a tutorial site like this:
int number = 10;
std::vector<std::unique_ptr<enemy> > enemies1;
for (unsigned i = 0; i < number; ++i) {
enemies1.emplace_back(std::unique_ptr<enemy>(new enemy(sf::Vector2f(100 * i + 1500, 1000), sf::Vector2f(15, 10), sf::Color(255, 255, 255, 0))));
}
//update
for (unsigned i = 0; i < number; ++i) {
enemies1[i]->update();
}
//render
for (unsigned i = 0; i < number; ++i) {
window.draw(enemies1[i]->enemysprite);
}
I'm using vector for creating multi enemies from my enemy class. Everything is ok I can draw 10 enemies on screen and they are moving and such. But if I try to delete an enemy like this:
if (!enemies1.empty())
{
for (unsigned i = 0; i < number; ++i) {
if (enemies1[i]->rect.getGlobalBounds().intersects(sprite.getGlobalBounds()))
enemies1.erase(enemies1.begin() + 1);
}
}
when the program starts a collision occurs everything is stopping. My question is what's the best way to create multiple enemies because I need to spawn and delete them in my game and I'm still learning.
I don't know whether my implementation correct or not. I wonder what should I do? In this code, I can't erase enemies from this vector.
I appreciate every piece of advice.
This loop:
for (unsigned i = 0; i < number; ++i) {
if (enemies1[i]->rect.getGlobalBounds().intersects(sprite.getGlobalBounds()))
enemies1.erase(enemies1.begin() + 1);
}
is flawed, because when you call erase, all the subsequent array entries move down 1, so next time round the loop you access the wrong element. Also, you run off the end of the array.
Instead, you can use the erase / remove idiom:
enemies.erase (std::remove_if (enemies.begin(), enemies.end(),
[sprite] (const std::unique_ptr <enemy> &e)
{ return e->rect.getGlobalBounds().intersects(sprite.getGlobalBounds()); }, enemies.end());
My enemy class is this like on shared picture
I have the following code to initialize an array, which works:
int main() {
int particle_count = 10000;
MyRNG my_rng = MyRNG(0.0,1.0);
Particle simulation_particles[particle_count];
for (int i = 0; i < particle_count; i++)
{
for (int j = 0; j < 3; j++)
{
simulation_particles[i].assign(j,my_rng.next());
}
}
However, when I try to put the for loops in functions, all particles get set to the same values:
void initialize_particle(Particle * p,MyRNG rgen)
{
for (int i = 0; i < 3; i++)
{
float value = rgen.next();
p->assign(i,value);
}
}
void initialize_simulation_particles(int size,Particle * simulation_particles,MyRNG rgen)
{
for (int i = 0; i < size; i++)
{
initialize_particle(&simulation_particles[i],rgen);
}
}
int main() {
int particle_count = 10000;
MyRNG my_rng = MyRNG(0.0,1.0);
Particle simulation_particles[particle_count];
initialize_simulation_particles(particle_count,simulation_particles,my_rng);
In void initialize_simulation_particles(int size,Particle * simulation_particles, MyRNG rgen) you take rgen by value. That means you get a copy of the random generator my_rng from main. Since it is a pseudo random number generator that produces the same numbers on a given state and you copy the same state to the function every time it produces the same number every time. The solution is to pass it by reference in initialize_simulation_particles and initialize_particle using MyRNG &rgen so that the state of my_rng progresses and therefore produces different numbers for each particle.
I wrote a brute-force 3-dimensional N-body simulation in C++ which works as expected.
I tried to implement inelastic particle collisions by including the line "myPhys.Collisions(particleList);" as part of my for-loop in the main.cpp where "Collisions" is defined in the "Physics" class (also shown below).
The code runs and produces output in data.csv. However, sometimes the run is interrupted by "Segmentation fault: 11" and the collisions lead to unexpected behavior.
I am wondering if I am somehow not handling vectors correctly in the "Collide" function, especially in the lines
// create particle with new parameters
Particle newParticle(newMass, newPosition, newVelocity);
// replace first particle in collision with new particle
particleList[idx1] = newParticle;
// erase second particle in collision
particleList.erase(particleList.begin()+idx2);
I should also mention that I'm new to C++ so I apologize if I'm doing something stupid.
The full code is available at https://www.dropbox.com/sh/b3oq7x546c9lktv/AAAdUE7Nrzaiov0TaGtgjbfNa?dl=0
main.cpp
#include <iostream>
#include <fstream>
#include <vector>
#include "vectorops.h"
#include "particle.h"
#include "physics.h"
using namespace std;
int main(){
ofstream myData;
myData.open("data.csv");
// initialize a vector of particles
int numParticles = 20;
vector<Particle> particleList;
for(int i = 0; i < numParticles; i++){
particleList.push_back(Particle(1));
}
// declare physics engine
Physics myPhys;
// time evolution
for(int t = 0; t < 10000; t++){
// calculate force on every particle
vector< vector<double > > currentForces = myPhys.forceList(particleList);
// iterate over particleList
for(int i = 0; i < numParticles; i++){
if(i < particleList.size())
{
// compute accelerations
particleList[i].updateAcceleration(currentForces[i]);
// increment velocities
particleList[i].updateVelocity();
// increment positions
particleList[i].updatePosition();
// print coordinates of each particle
for(int j = 0; j < 3; j++){
myData << particleList[i].getPosition().at(j) << ",";
}
}
else
{
for(int j = 0; j < 3; j++){
myData << 0 << ",";
}
}
}
// update particleList after collisions
myPhys.Collisions(particleList);
myData << "\n";
}
myData.close();
return 0;
}
extract from Physics.cpp
void Physics::Collide(vector<Particle> &particleList, int idx1, int idx2){
// compute parameters of new particle
double m1 = particleList[idx1].getMass();
double m2 = particleList[idx2].getMass();
double newMass = m1+m2;
vector<double> newVelocity;
vector<double> v1 = particleList[idx1].getVelocity();
vector<double> v2 = particleList[idx2].getVelocity();
for(int i = 0; i < 3; i++){
newVelocity.push_back((m1*v1[i]+m2*v2[i])/newMass);
}
vector<double> newPosition;
vector<double> x1 = particleList[idx1].getPosition();
vector<double> x2 = particleList[idx2].getPosition();
for(int i = 0; i < 3; i++){
newPosition.push_back((m1*x1[i]+m2*x2[i])/newMass);
}
// create particle with new parameters
Particle newParticle(newMass, newPosition, newVelocity);
// replace first particle in collision with new particle
particleList[idx1] = newParticle;
// erase second particle in collision
particleList.erase(particleList.begin()+idx2);
}
void Physics::Collisions(vector<Particle> &particleList){
for(int i = 0; i < particleList.size();i++){
for(int j=0; j < i; j++){
double dist = Vectors.distance(particleList[i].getPosition(),particleList[j].getPosition());
if(dist < 0.01){
Collide(particleList,i,j);
}
}
}
}
The problem with the code is that after "particleList" is resized as a result of a collision, the positions of the particles in "myData" are not correctly aligned with the previous time step.
A quick workaround is to simply move one of the colliding particles to a large distance from the others, rather than deleting it from the vector
// create particle with new parameters
Particle newParticle(newMass, newPosition, newVelocity);
// replace first particle in collision with new particle
particleList[idx1] = newParticle;
// move second particle to large distance
vector<double> farAway;
for(int i = 0; i < 3; i++){
farAway.push_back(1000000);
}
particleList[idx2].setPosition(farAway);
This is not particularly elegant, however. I am thinking that a more elegant approach might be to store the position histories in the particle objects themselves.
all. I have some function that add sprite to layer
-(void)drawBoard {
for (int y = 0; y < 18; y++) {
for (int x = 0; x < 12; x ++) {
if (tetrisBoard[x][y] != NULL) {
[self addChild:tetrisBoard[x][y]];
}
}
}
}
But when I call this function next time my app just freezes. I think it freezes because i already have the same sprite on layer. How can i check all child on my layer and if i have the same child on layer, then do nothing ? Thanks
You can get an NSArray of the children of the layer, so you could do a check like this:
if ([[self children] containsObject:tetrisBoard[x][y]]) {
[self addChild:tetrisBoard[x][y]];
}
I'm making a Asteroids game but I can not get to play more than one explosion at a time. Just get to do one at a time ...
This is my code I call in the main loop:
for(i = 0; i < MAX_SHOTS; i++) {
for(j = 0; j < MAX_ASTEROIDS; j++) {
if(shot[i].CheckCollision(asteroide[j])) {
shot[i].SetPos(-100, 0);
explosionSnd.Play();
numAst = j;
explosion[numExp++].Enable(true);
if(numExp == MAX_EXPLOSIONS-1) {
numExp = 1;
}
}
}
}
for(i = 1; i < MAX_EXPLOSIONS; i++) {
if(explosion[i].Enable()) {
explosion[i].SetPos(asteroide[numAst].GetX(), asteroide[numAst].GetY());
explosion[i].Draw();
if(explosion[i].GetFrame() == 5) {
explosion[i].Enable(false);
}
}
}
If I shot to an asteroid and after I shot to another, the animation is cut and goes to the new asteroid.
Any help?
Thank you.
Inside your second loop, you're moving each explosion to the location of the asteroid asteroide[numAst] - you're playing all the explosions, just all at the same place!
You should only position the explosion once after you Enable(true) it, when it's created in the first loop, not each time you draw it.
Hope that helps.