Beispiel #1
0
// 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);
		}
	}
}
Beispiel #2
0
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++;
}