// creates a little fireworks "bang" void create_burst(Tparticle *ps, int x, int y, int spread, int num, int life, int bmp) { int i; Tparticle *p; for(i = 0; i < num; i ++) { p = get_free_particle(ps, MAX_PARTICLES); if (p != NULL) { set_particle(p, x + rand()%spread - spread/2, y + rand()%spread - spread/2, ((double)(rand()%100))/100.0 - 0.5, ((double)(rand()%100))/100.0 - 0.5, rand()%4 + 1, (life ? life : 70 - rand()%50), bmp); } } }
void World::tick(float time) { float ay = GRAVITY * time; float damping = pow(DAMPING, time); float angular_damping = pow(ANGULAR_DAMPING, time); WeakSet<Solid*>::iterator si = solids.begin(); WeakSet<Solid*>::iterator sie = solids.end(); while (si != sie) { Solid *s = *si; // TODO: Remove sqrt float steps = floor(s->max_rad * s->vr + sqrt(s->vx * s->vx + s->vy * s->vy)); s->vx *= damping; s->vy *= damping; s->vr *= angular_damping; s->vy += ay; float vx = s->vx / steps; float vy = s->vy / steps; float vr = s->vr / steps; unsigned int i = steps; while (i--) { s->x += vx; s->y += vy; s->r += vr; float sin_r = sin(s->r); float cos_r = cos(s->r); Solid::RotationCache rc = s->get_rotation_cache(); signed int aabb[4]; aabb[Direction::up ] = s->y + rc.aabb[Direction::up ]; aabb[Direction::down ] = s->y + rc.aabb[Direction::down ]; aabb[Direction::left ] = s->x + rc.aabb[Direction::left ]; aabb[Direction::right] = s->x + rc.aabb[Direction::right]; Chunk *chunk = s->chunk; const std::vector<std::uint16_t> &cps = s->get_collision_particles(); std::vector<std::uint16_t>::const_iterator cpsi = cps.cbegin(); while (cpsi != cps.cend()) { unsigned int i = *cpsi; signed int x = s->x + s->particles[i]->rx * cos_r - s->particles[i]->ry * sin_r; signed int y = s->y + s->particles[i]->rx * sin_r + s->particles[i]->ry * cos_r; signed int cx = (x / CHUNK_SIZE) * CHUNK_SIZE; signed int cy = (y / CHUNK_SIZE) * CHUNK_SIZE; if (cx != chunk->x || cy != chunk->y) { while (cx < chunk->x) { chunk = chunk->neighbor(this, Chunk::neighbor_left); cx += CHUNK_SIZE; } while (cx > chunk->x) { chunk = chunk->neighbor(this, Chunk::neighbor_right); cx -= CHUNK_SIZE; } while (cy < chunk->y) { chunk = chunk->neighbor(this, Chunk::neighbor_up); cy += CHUNK_SIZE; } while (cx > chunk->x) { chunk = chunk->neighbor(this, Chunk::neighbor_down); cy -= CHUNK_SIZE; } } Cell *cell = chunk->cells + (x - cx) + (y - cy) * CHUNK_SIZE; switch (cell->state) { case Cell::state_air: break; case Cell::state_static: break; case Cell::state_solid: break; case Cell::state_particle: break; } cpsi++; } } si++; } WeakSet<Solid*>::iterator si = solids.begin(); WeakSet<Solid*>::iterator sie = solids.end(); while (si != sie) { Solid *s = *si; s->vx *= DAMPING; s->vy *= DAMPING; s->vy += ay; s->vr *= ANGULAR_DAMPING; s->sin_vr = sin(s->vr); s->cos_vr = cos(s->vr); si++; } WeakSet<Chunk*>::iterator ci = active_chunks.begin(); WeakSet<Chunk*>::iterator cie = active_chunks.end(); while (ci != cie) { Chunk* c = *ci; if (c->particles.empty()) { active_chunks.erase(ci, cie); continue; } WeakSet<Particle*>::iterator pi = c->particles.begin(); WeakSet<Particle*>::iterator pie = c->particles.end(); while (pi != pie) { Particle *p = *pi; Solid* solid = p->solid; if (solid) { // Get velocity from solid float dx = p->x - solid->x; float dy = p->y - solid->y; p->vx = solid->vx - solid->sin_vr * dx + solid->cos_vr * dy; p->vy = solid->vy - solid->cos_vr * dx + solid->sin_vr * dy; } else { p->vx *= DAMPING; p->vy *= DAMPING; p->vy += ay; } signed int old_x = p->x; signed int old_y = p->y; p->x += p->vx; p->y += p->vy; signed int new_x = p->x; signed int new_y = p->y; signed int dx = abs(new_x - old_x); signed int dy = abs(new_y - old_y); signed int sx = old_x < new_x ? 1 : -1; signed int sy = old_y < new_y ? 1 : -1; signed int err = dx - dy; signed int x = old_x; signed int y = old_y; while (true) { // TODO: optimization signed int e2 = err * 2; if (e2 > -dy) { err -= dy; x += sx; } if (!(x == new_x && y == new_y) && e2 < dx) { err += dx; y += sy; } Chunk *nc = c; unsigned int i = new_x + new_y * CHUNK_SIZE; if (i >= CHUNK_SIZE * CHUNK_SIZE) { if (new_x < 0) {nc = nc->neighbor(this, Chunk::neighbor_left); i += CHUNK_SIZE;} else if (new_x > CHUNK_SIZE) {nc = nc->neighbor(this, Chunk::neighbor_right); i -= CHUNK_SIZE;} if (new_y < 0) {nc = nc->neighbor(this, Chunk::neighbor_up); i += CHUNK_SIZE * CHUNK_SIZE;} else if (new_y > CHUNK_SIZE) {nc = nc->neighbor(this, Chunk::neighbor_down); i -= CHUNK_SIZE * CHUNK_SIZE;} } if (nc != c) { if (nc->particles.empty()) { active_chunks.insert(nc, ci, cie); } c->particles.erase(pi); nc->particles.insert(p); if (c->particles.empty()) { active_chunks.erase(ci); ci--; } } Cell *ncl = nc->cells + i; switch (ncl->state) { case Cell::t_air: view.update_pixel(c->x + old_x, c->y + old_y, 0, 0, 0); view.update_pixel(c->x + new_x, c->y + new_y, p->type->r, p->type->g, p->type->b); cl->state = Cell::t_air; ncl->state = Cell::t_dynamic; ncl->particle = p; break; case Cell::t_static: std::cout << "static collision" << std::endl; // TODO: Should calculate new velocity from the surface normal p->vx = -p->vx; p->vy = -p->vy; p->x += p->vx; p->y += p->vy; new_x = p->x; new_y = p->y; break; case Cell::t_dynamic: Particle *p2 = ncl->particle; // Bounce /* // Unoptimized, without mass float dx = p2->x - p->x; float dy = p2->y - p->y; float d = sqrt(dx * dx + dy * dy); dx /= d; dy /= d; float dvx = p2->vx - p->vx; float dvy = p2->vy - p->vy; float i = dvx * dx + dvy * dy; float ix = dx * i; float iy = dy * i; */ float dx = p2->x - p->x; float dy = p2->y - p->y; float d2 = dx * dx + dy * dy; float dvx = p2->vx - p->vx; float dvy = p2->vy - p->vy; float i = (dvx * dx + dvy * dy) / (d2 * (p->type->mass + p2->type->mass)); float ix = dx * i; float iy = dy * i; p->vx -= ix * p2->type->mass; p->vy -= iy * p2->type->mass; if (p->solid) { p->solid->apply_impulse(p->x, p->y, ix * p->type->mass, py * p->type->mass); } else { p2->vx += ix * p->type->mass; p2->vy += ix * p->type->mass; } break; } if (x == new_x && y == new_y) { set_particle(x, y); break; } } pi++; } ci++; } cur_timestep++; }