mirror of https://github.com/skeeto/pixelcity.git
323 lines
9.0 KiB
C++
323 lines
9.0 KiB
C++
/*-----------------------------------------------------------------------------
|
|
|
|
Car.cpp
|
|
|
|
2009 Shamus Young
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
This creates the little two-triangle cars and moves them around the map.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
#define DEAD_ZONE 200
|
|
#define STUCK_TIME 230
|
|
#define UPDATE_INTERVAL 50 //milliseconds
|
|
#define MOVEMENT_SPEED 0.61f
|
|
#define CAR_SIZE 3.0f
|
|
|
|
#include <windows.h>
|
|
#include <math.h>
|
|
#include <gl\gl.h>
|
|
#include <gl\glu.h>
|
|
#include <gl\glaux.h>
|
|
#include "glTypes.h"
|
|
|
|
#include "building.h"
|
|
#include "car.h"
|
|
#include "camera.h"
|
|
#include "mesh.h"
|
|
#include "macro.h"
|
|
#include "math.h"
|
|
#include "random.h"
|
|
#include "render.h"
|
|
#include "texture.h"
|
|
#include "world.h"
|
|
#include "visible.h"
|
|
#include "win.h"
|
|
|
|
static GLvector direction[] =
|
|
{
|
|
0.0f, 0.0f, -1.0f,
|
|
1.0f, 0.0f, 0.0f,
|
|
0.0f, 0.0f, 1.0f,
|
|
-1.0f, 0.0f, 0.0f,
|
|
};
|
|
|
|
static int dangles[] = { 0, 90, 180, 270};
|
|
|
|
static GLvector2 angles[360];
|
|
static bool angles_done;
|
|
static unsigned char carmap[WORLD_SIZE][WORLD_SIZE];
|
|
static CCar* head;
|
|
static unsigned next_update;
|
|
static int count;
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
int CarCount ()
|
|
{
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void CarClear ()
|
|
{
|
|
|
|
CCar* c;
|
|
|
|
for (c = head; c; c = c->m_next)
|
|
c->Park ();
|
|
ZeroMemory (carmap, sizeof (carmap));
|
|
count = 0;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void CarRender ()
|
|
{
|
|
|
|
CCar* c;
|
|
|
|
if (!angles_done) {
|
|
for (int i = 0 ;i < 360; i++) {
|
|
angles[i].x = cosf ((float)i * DEGREES_TO_RADIANS) * CAR_SIZE;
|
|
angles[i].y = sinf ((float)i * DEGREES_TO_RADIANS) * CAR_SIZE;
|
|
}
|
|
}
|
|
glDepthMask (false);
|
|
glEnable (GL_BLEND);
|
|
glDisable (GL_CULL_FACE);
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
glBindTexture (GL_TEXTURE_2D, 0);
|
|
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_HEADLIGHT));
|
|
for (c = head; c; c = c->m_next)
|
|
c->Render ();
|
|
glDepthMask (true);
|
|
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void CarUpdate ()
|
|
{
|
|
|
|
CCar* c;
|
|
unsigned now;
|
|
|
|
if (!TextureReady () || !EntityReady ())
|
|
return;
|
|
now = GetTickCount ();
|
|
if (next_update > now)
|
|
return;
|
|
next_update = now + UPDATE_INTERVAL;
|
|
for (c = head; c; c = c->m_next)
|
|
c->Update ();
|
|
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
CCar::CCar ()
|
|
{
|
|
|
|
m_ready = false;
|
|
m_next = head;
|
|
head = this;
|
|
count++;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
bool CCar::TestPosition (int row, int col)
|
|
{
|
|
|
|
//test the given position and see if it's already occupied
|
|
if (carmap[row][col])
|
|
return false;
|
|
//now make sure that the lane is going the right direction
|
|
if (WorldCell (row, col) != WorldCell (m_row, m_col))
|
|
return false;
|
|
return true;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void CCar::Update (void)
|
|
{
|
|
|
|
int new_row, new_col;
|
|
GLvector old_pos;
|
|
GLvector camera;
|
|
|
|
//If the car isn't ready, place it on the map and get it moving
|
|
camera = CameraPosition ();
|
|
if (!m_ready) {
|
|
//if the car isn't ready, we need to place it somewhere on the map
|
|
m_row = DEAD_ZONE + RandomVal (WORLD_SIZE - DEAD_ZONE * 2);
|
|
m_col = DEAD_ZONE + RandomVal (WORLD_SIZE - DEAD_ZONE * 2);
|
|
//if there is already a car here, forget it.
|
|
if (carmap[m_row][m_col] > 0)
|
|
return;
|
|
//if this spot is not a road, forget it
|
|
if (!(WorldCell (m_row, m_col) & CLAIM_ROAD))
|
|
return;
|
|
if (!Visible (glVector ((float)m_row, 0.0f, (float)m_col)))
|
|
return;
|
|
//good spot. place the car
|
|
m_position = glVector ((float)m_row, 0.1f, (float)m_col);
|
|
m_drive_position = m_position;
|
|
m_ready = true;
|
|
if (WorldCell (m_row, m_col) & MAP_ROAD_NORTH)
|
|
m_direction = NORTH;
|
|
if (WorldCell (m_row, m_col) & MAP_ROAD_EAST)
|
|
m_direction = EAST;
|
|
if (WorldCell (m_row, m_col) & MAP_ROAD_SOUTH)
|
|
m_direction = SOUTH;
|
|
if (WorldCell (m_row, m_col) & MAP_ROAD_WEST)
|
|
m_direction = WEST;
|
|
m_drive_angle = dangles[m_direction];
|
|
m_max_speed = (float)(4 + RandomVal (6)) / 10.0f;
|
|
m_speed = 0.0f;
|
|
m_change = 3;
|
|
m_stuck = 0;
|
|
carmap[m_row][m_col]++;
|
|
}
|
|
//take the car off the map and move it
|
|
carmap[m_row][m_col]--;
|
|
old_pos = m_position;
|
|
m_speed += m_max_speed * 0.05f;
|
|
m_speed = MIN (m_speed, m_max_speed);
|
|
m_position += direction[m_direction] * MOVEMENT_SPEED * m_speed;
|
|
//If the car has moved out of view, there's no need to keep simulating it.
|
|
if (!Visible (glVector ((float)m_row, 0.0f, (float)m_col)))
|
|
m_ready = false;
|
|
//if the car is far away, remove it. We use manhattan units because buildings almost always
|
|
//block views of cars on the diagonal.
|
|
if (fabs (camera.x - m_position.x) + fabs (camera.z - m_position.z) > RenderFogDistance ())
|
|
m_ready = false;
|
|
//if the car gets too close to the edge of the map, take it out of play
|
|
if (m_position.x < DEAD_ZONE || m_position.x > (WORLD_SIZE - DEAD_ZONE))
|
|
m_ready = false;
|
|
if (m_position.z < DEAD_ZONE || m_position.z > (WORLD_SIZE - DEAD_ZONE))
|
|
m_ready = false;
|
|
if (m_stuck >= STUCK_TIME)
|
|
m_ready = false;
|
|
if (!m_ready)
|
|
return;
|
|
//Check the new position and make sure its not in another car
|
|
new_row = (int)m_position.x;
|
|
new_col = (int)m_position.z;
|
|
if (new_row != m_row || new_col != m_col) {
|
|
//see if the new position places us on top of another car
|
|
if (carmap[new_row][new_col]) {
|
|
m_position = old_pos;
|
|
m_speed = 0.0f;
|
|
m_stuck++;
|
|
} else {
|
|
//look at the new position and decide if we're heading towards or away from the camera
|
|
m_row = new_row;
|
|
m_col = new_col;
|
|
m_change--;
|
|
m_stuck = 0;
|
|
if (m_direction == NORTH)
|
|
m_front = camera.z < m_position.z;
|
|
else if (m_direction == SOUTH)
|
|
m_front = camera.z > m_position.z;
|
|
else if (m_direction == EAST)
|
|
m_front = camera.x > m_position.x;
|
|
else
|
|
m_front = camera.x < m_position.x;
|
|
}
|
|
}
|
|
m_drive_position = (m_drive_position + m_position) / 2.0f;
|
|
//place the car back on the map
|
|
carmap[m_row][m_col]++;
|
|
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void CCar::Render ()
|
|
{
|
|
|
|
GLvector pos;
|
|
int angle;
|
|
int turn;
|
|
|
|
if (!m_ready)
|
|
return;
|
|
if (!Visible (m_drive_position))
|
|
return;
|
|
if (m_front)
|
|
glColor3f (1, 1, 0.8f);
|
|
else
|
|
glColor3f (1, 0.2f, 0);
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
angle = dangles[m_direction];
|
|
pos = m_drive_position;//
|
|
angle = 360 - (int)MathAngle (m_position.x, m_position.z, pos.x, pos.z);
|
|
angle %= 360;
|
|
turn = (int)MathAngleDifference ((float)m_drive_angle, (float)angle);
|
|
m_drive_angle += SIGN (turn);
|
|
pos += glVector (0.5f, 0.0f, 0.5f);
|
|
|
|
|
|
glTexCoord2f (0, 0);
|
|
glVertex3f (pos.x + angles[angle].x, -CAR_SIZE, pos.z + angles[angle].y);
|
|
glTexCoord2f (1, 0);
|
|
glVertex3f (pos.x - angles[angle].x, -CAR_SIZE, pos.z - angles[angle].y);
|
|
glTexCoord2f (1, 1);
|
|
glVertex3f (pos.x - angles[angle].x, CAR_SIZE, pos.z - angles[angle].y);
|
|
glTexCoord2f (0, 1);
|
|
glVertex3f (pos.x + angles[angle].x, CAR_SIZE, pos.z + angles[angle].y);
|
|
|
|
|
|
/*
|
|
glVertex3f (m_position.x, m_position.y, m_position.z);
|
|
glVertex3f (m_position.x, m_position.y, m_position.z + 1);
|
|
glVertex3f (m_position.x + 1, m_position.y, m_position.z + 1);
|
|
glVertex3f (m_position.x + 1, m_position.y, m_position.z);
|
|
*/
|
|
/*
|
|
glTexCoord2f (0, 0);
|
|
glVertex3f (m_position.x, m_position.y, m_position.z + 0.2f);
|
|
glTexCoord2f (0, 2);
|
|
glVertex3f (m_position.x, m_position.y, m_position.z + 1 - 0.2f);
|
|
glTexCoord2f (1, 2);
|
|
glVertex3f (m_position.x + 1, m_position.y, m_position.z + 1 - 0.2f);
|
|
glTexCoord2f (1, 0);
|
|
glVertex3f (m_position.x + 1, m_position.y, m_position.z + 0.2f);
|
|
|
|
*/
|
|
|
|
glEnd ();
|
|
|
|
} |