Пример #1
0
bool Wall::clippoint (vect2d npt, double rad, vect2d* clip, vect2d* hitpt, double *oprio,
	      double surfaceepsilon)
{
    double distm=-1;
    double prio=0;
    
    // Transform the point into the coordinate space of the wall. (so
    // that the wall becomes <0, 0> to <len, 0>
    vect2d tp(j * (npt-v1), ~j * (npt-v1));
    vect2d ret;

    if (tp.x >= 0 && tp.x <= len && tp.y <= rad && tp.y >= -rad) {
	ret.x=tp.x;
	if (tp.y > 0) {
	    ret.y = rad;
	    distm = rad-tp.y;
	} else {
	    ret.y = -rad;
	    distm = rad+tp.y;
	}
	prio=rad*1000;
    } else {
	double ln2 = vlen2(tp);
	double r2=rad*rad;
	if (ln2 < r2) {
	    double ln = sqrt (ln2);
	    distm = rad-ln;
	    ret = tp * (rad / ln);
	} else {
	    tp.x-=len;
	    ln2=vlen2(tp);
	    if (ln2<r2) {
		double ln = sqrt (ln2);
		distm = rad-ln;
		ret = tp * (rad / ln);
		ret.x += len;
	    }
	}
    }
    
    // If the circle intersected, and clipx is not null, transform the
    // point back to normal coordinate space.
    if (distm>EPSILON) {
	if (clip) *clip = v1 + j*ret.x + ~j*ret.y;
	if (ret.x < 0) ret.x=0;
	else if (ret.x > len) ret.x=len;
	if (hitpt) *hitpt = v1 + j*ret.x;
	if (oprio) *oprio=distm+prio;
	return true;
    }
    return false;
}
Пример #2
0
double Plane::getzbound(Area* limit, vect2d pt, double rad, double height, bool clipsolid)
{
    PROBEGIN(checkz_fast);
    PROBEGIN(checkz_slow);

    if (slope==0 && !clipsolid) {
	// Special case: slope is zero, so bound is z [+-] height.
	return cpt.z+(ceil?-height:height);
    }
    if (rad == 0) {
	return getz(pt)+(ceil?-height:height);
	
    }

    // Calculate the highest (or lowest) point where the cylinder
    // intersects with the plane. This is always <px, py> [+-] <ix, iy>*rad

    vect2d tpt = pt;

    if ((slope>0) == ceil) {
	tpt -= dir*rad;
    } else {
	tpt += dir*rad;
    }

    // If the limit area is not specified, or <tpx, tpy> is in the
    // area, simply return the value of the plane at that point [+-] height.

    if ((limit == NULL) || limit->pointin(tpt)) {
	PROEND(checkz_fast);
        double ret = getz(tpt);

        if (ceil) {
            ret -= height;
        } else {
            ret += height;
        }

        return ret;
    }

    // Ok, so the point is not in the area. So, we have to find some
    // other point to be the (max|min)imum. This point will either be
    // 1. a vertex of the area, or
    // 2. a point along one of the walls.
    //
    // We start out with the value at [+-]infinity, and then check all
    // possible points. We loop through the walls, checking the vertex
    // if the vertex is inside the circle, then check the points where
    // the circle intersects the wall.

    double cz = (ceil?INFINITY:-INFINITY);

#define ckz(pt) {                                       \
	double tz=getz(pt) + (ceil?-height:height);     \
	if (ceil == (tz<cz)) cz = tz;                   \
    }
    double rad2 = sqr(rad);
    FOREACHW(w, limit) {
	double a, ta;

	// Check the vertex.
	if (vlen2(w->v1-pt) < rad2) {
	    ckz(w->v1);
	}

	// Transform the point to wall coordinate space.
	double doti = ~w->j*(pt-w->v1);
	double dotj = w->j*(pt-w->v1);

	// Circle does not intersect.
	if (fabs(doti)>rad+EPSILON) continue;

	// Check intersection points.
	a = sqrt(rad2-sqr(doti));
	if (isnan(a)) a = 0;
	ta = dotj+a;
	if (ta >= 0 && ta <= w->len) {
	    ckz(w->v1+w->j*ta);
	}

	ta = dotj-a;
	if (ta >= 0 && ta <= w->len) {
	    ckz(w->v1+w->j*ta);
	}
    }
Пример #3
0
//-----------------------------------------------------------------------------
void RunGame()
{
	// Control main ship
	if (g_gs == GS_VICTORY || g_gs == GS_STARTING)
	{
		if (MAIN_SHIP.vel.y < SHIP_CRUISE_SPEED)
		{
			MAIN_SHIP.vel.y = SAFEADD(MAIN_SHIP.vel.y, SHIP_INC_SPEED, SHIP_CRUISE_SPEED);
		}
		MAIN_SHIP.fuel = SAFESUB(MAIN_SHIP.fuel, FRAME_FUEL_COST);
	}

	// Heal main ship
	if (g_gs != GS_DYING)
	{
		if (MAIN_SHIP.energy < MAX_ENERGY && MAIN_SHIP.fuel > MIN_FUEL_FOR_HEAL)
		{
			MAIN_SHIP.energy = SAFEADD(MAIN_SHIP.energy, ENERGY_HEAL_PER_FRAME, MAX_ENERGY);
			MAIN_SHIP.fuel = SAFESUB(MAIN_SHIP.fuel, FUEL_HEAL_PER_FRAME);
			LOG(("- energy: %f, fuel: %f\n", MAIN_SHIP.energy, MAIN_SHIP.fuel));
		}
	}

	// Move entities
	for (int i = MAX_ENTITIES - 1; i >= 0; i--)
	{
		if (g_entities[i].type != E_NULL)
		{
			g_entities[i].pos = vadd(g_entities[i].pos, g_entities[i].vel);

			// Remove entities that fell off screen
			if (g_entities[i].pos.y < g_camera_offset - G_HEIGHT)
				g_entities[i].type = E_NULL;
		}
	}

	// Advance "stars"
	for (int i = 0; i < MAX_ENTITIES; i++)
	{
		if (g_entities[i].type == E_STAR)
			g_entities[i].gfxscale *= 1.008f;
	}

	// Dont let steering off the screen
	if (MAIN_SHIP.pos.x < MAINSHIP_RADIUS)
		MAIN_SHIP.pos.x = MAINSHIP_RADIUS;
	if (MAIN_SHIP.pos.x > G_WIDTH - MAINSHIP_RADIUS)
		MAIN_SHIP.pos.x = G_WIDTH - MAINSHIP_RADIUS;

	// Check collisions
	if (g_gs == GS_PLAYING)
	{
		// Check everything against ship
		for (int i = 1; i < MAX_ENTITIES; i++)
		{
			// Should check against ship?
			if (g_entities[i].type == E_ROCK
				|| g_entities[i].type == E_JUICE
				|| g_entities[i].type == E_MINE
				|| g_entities[i].type == E_DRONE)
			{
				float distance = vlen2(vsub(g_entities[i].pos, MAIN_SHIP.pos)); // Distance from object to ship
				float crash_distance = CORE_FSquare(g_entities[i].radius + MAIN_SHIP.radius); // Minimum allowed distance before crash
				if (distance < crash_distance)
				{
					switch (g_entities[i].type)
					{
					case E_ROCK:
						if (g_entities[i].energy > 0)
						{
							MAIN_SHIP.energy = SAFESUB(MAIN_SHIP.energy, ROCK_CRASH_ENERGY_LOSS);
							MAIN_SHIP.vel.y = SHIP_START_SPEED;
							
							// Set rock velocity
							vec2 vel_direction = vsub(g_entities[i].pos, MAIN_SHIP.pos); // direction of rock velocity, away from ship
							vec2 normalized_vel_direction = vunit(vel_direction); // normalize
							vec2 vel = vscale(normalized_vel_direction, CRASH_VEL); // Scale, ie give the rock correct speed.
							g_entities[i].vel = vel;
							g_entities[i].energy = 0;
						}
						break;

					case E_JUICE:
						MAIN_SHIP.fuel = SAFEADD(MAIN_SHIP.fuel, JUICE_FUEL, MAX_FUEL);
						g_entities[i].type = E_NULL;
						break;

					case E_MINE:
						MAIN_SHIP.energy = SAFESUB(MAIN_SHIP.energy, MINE_CRASH_ENERGY_LOSS);
						MAIN_SHIP.vel.y = SHIP_START_SPEED;
						g_entities[i].type = E_NULL;
						break;

					case E_DRONE:
						MAIN_SHIP.energy = SAFESUB(MAIN_SHIP.energy, MINE_CRASH_ENERGY_LOSS);
						MAIN_SHIP.vel.y = SHIP_START_SPEED;
						g_entities[i].type = E_NULL;
						break;

					default:
						break;
					}
				}
			}
			else if (g_entities[i].type == E_ROCKET)
			{
				// Check all hit-able objects against this rocket
				for (int j = 1; i < MAX_ENTITIES; j++) 
				{
					// Should check against rocket?
					if (g_entities[j].type == E_ROCK
						|| g_entities[j].type == E_MINE
						|| g_entities[j].type == E_DRONE)
					{
						float distance = vlen2(vsub(g_entities[i].pos, g_entities[j].pos));
						float crash_distance = CORE_FSquare(g_entities[i].radius + g_entities[j].radius);
						if (distance < crash_distance)
						{
							// Impact!
							g_entities[i].type = E_NULL;
							g_entities[j].type = E_NULL;

							break;
						}
					}
				}
			}
		}
	}

	// Generate new level elements as we advance
	GenNextElements();

	// Possibly insert new juice
	if (g_gs == GS_PLAYING)
	{
		float trench = MAIN_SHIP.pos.y - g_current_race_pos; // How much advanced from previous frame
		if (CORE_RandChance(trench * JUICE_CHANCE_PER_PIXEL))
		{
			vec2 pos = vmake(CORE_FRand(0.f, G_WIDTH), g_camera_offset + G_HEIGHT + GEN_IN_ADVANCE); // Random x, insert 400y above window
			vec2 vel = vmake(CORE_FRand(-1.f, +1.f), CORE_FRand(-1.f, +1.f)); // Random small velocity to make rocks "float"
			InsertEntity(E_JUICE, pos, vel, JUICE_RADIUS, g_juice, false, true);
		}
	}

	// Set camera to follow the main ship
	g_camera_offset = MAIN_SHIP.pos.y - G_HEIGHT / 8.f;

	g_current_race_pos = MAIN_SHIP.pos.y;
	if (g_gs == GS_PLAYING)
	{
		if (g_current_race_pos >= RACE_END) // Check if victory
		{
			g_gs = GS_VICTORY;
			g_gs_timer = 0.f;
			MAIN_SHIP.gfxadditive = true;
		}
	}

	// Advance game mode
	g_gs_timer += FRAMETIME;
	switch (g_gs)
	{
	case GS_STARTING:
		if (g_gs_timer >= STARTING_TIME) // Start delay before starting to play
		{
			g_gs = GS_PLAYING;
			g_gs_timer = 0.f;
		}
		break;
	case GS_DYING:
		if (g_gs_timer >= DYING_TIME)
		{
			ResetNewGame();
		}
		break;
	case GS_PLAYING:
		if (MAIN_SHIP.energy <= 0.f || MAIN_SHIP.fuel <= 0.f) // No energy or fuel --> die
		{
			g_gs = GS_DYING;
			g_gs_timer = 0.f;
			MAIN_SHIP.gfx = g_ship_RR;
		}
		break;
	case GS_VICTORY:
		if (CORE_RandChance(1.f / 10.f))
		{
			InsertEntity(E_STAR, MAIN_SHIP.pos, vadd(MAIN_SHIP.vel, vmake(CORE_FRand(-5.f, 5.f), CORE_FRand(-5.f, 5.f))), 0, g_star, false, true);
		}
		
		if (g_gs_timer >= 8.f) // Should use VICTORY_TIME, but stupid VS dont want me to...
		{
			ResetNewGame();
		}
		break;
	}
	g_time_from_last_rocket += FRAMETIME;
}