class Red { Vector2D m_Position; Vector2D m_Direction; float m_Width; float m_Height; float m_HalfWidth; float m_HalfHeight; int m_ExcitedCounter; int m_State; //0 - normal //1 - excited //2 - dead void Initialize() { m_Position = new Vector2D(); m_Position.x = 200.f; m_Position.y = 200.f; m_Direction = new Vector2D(); m_Direction.x = 1.f; m_Direction.y = 0.f; m_Width = 12.f; m_Height = 12.f; m_HalfWidth = m_Width / 2.f; m_HalfHeight = m_Height / 2.f; } void Update() { //don't update if we're dead if( m_State == 2 ) return; //update position m_Position.Add( m_Direction ); if( m_State == 1 ) { m_Position.Add( m_Direction ); --m_ExcitedCounter; if( m_ExcitedCounter <= 0 ) { m_ExcitedCounter = 0; m_State = 0; } } //cap if( m_Position.x < 0.f ) { m_Position.x = 0.f; m_Direction.x = -m_Direction.x; } else if( m_Position.x > (float)SCREEN_WIDTH ) { m_Position.x = (float)SCREEN_WIDTH; m_Direction.x = -m_Direction.x; } if( m_Position.y < 0.f ) { m_Position.y = 0.f; m_Direction.y = -m_Direction.y; } else if( m_Position.y > (float)SCREEN_HEIGHT ) { m_Position.y = (float)SCREEN_HEIGHT; m_Direction.y = -m_Direction.y; } //determine grid cell we're in int curCellIndexX = (int)(m_Position.x / GRID.m_CellWidth); int curCellIndexY = (int)(m_Position.y / GRID.m_CellWidth); curCellIndexX = CapInt( curCellIndexX, 0, GRID.m_NumCellsX - 1 ); curCellIndexY = CapInt( curCellIndexY, 0, GRID.m_NumCellsY - 1 ); //determine what we can see Vector2D sightLeft = new Vector2D( m_Direction.x, m_Direction.y ); sightLeft.Multiply( 30.f ); Vector2D sightRight = new Vector2D( sightLeft.x, sightLeft.y ); sightLeft.RotateByAngle( -.6f ); sightRight.RotateByAngle( .6f ); //determine cells of what we can see int ftrCellIndexX = (int)((m_Position.x + sightLeft.x) / GRID.m_CellWidth); int ftrCellIndexY = (int)((m_Position.y + sightLeft.y) / GRID.m_CellWidth); ftrCellIndexX = CapInt( ftrCellIndexX, 0, GRID.m_NumCellsX - 1 ); ftrCellIndexY = CapInt( ftrCellIndexY, 0, GRID.m_NumCellsY - 1 ); //now that we've got the extent of the current and future cells, check them for obstacles int minXCell = min( curCellIndexX, ftrCellIndexX ); int maxXCell = max( curCellIndexX, ftrCellIndexX ); int minYCell = min( curCellIndexY, ftrCellIndexY ); int maxYCell = max( curCellIndexY, ftrCellIndexY ); int x, y; for( x = minXCell; x <= maxXCell; ++x ) { for( y = minYCell; y <= maxYCell; ++y ) { int gridCell = y * GRID.m_NumCellsX + x; CheckCellAgainstSight( gridCell ); } } //determine cells of what we can see to the right ftrCellIndexX = (int)((m_Position.x + sightRight.x) / GRID.m_CellWidth); ftrCellIndexY = (int)((m_Position.y + sightRight.y) / GRID.m_CellWidth); ftrCellIndexX = CapInt( ftrCellIndexX, 0, GRID.m_NumCellsX - 1 ); ftrCellIndexY = CapInt( ftrCellIndexY, 0, GRID.m_NumCellsY - 1 ); //now that we've got the extent of the current and future cells, check them for obstacles minXCell = min( curCellIndexX, ftrCellIndexX ); maxXCell = max( curCellIndexX, ftrCellIndexX ); minYCell = min( curCellIndexY, ftrCellIndexY ); maxYCell = max( curCellIndexY, ftrCellIndexY ); for( x = minXCell; x <= maxXCell; ++x ) { for( y = minYCell; y <= maxYCell; ++y ) { int gridCell = y * GRID.m_NumCellsX + x; CheckCellAgainstSight( gridCell ); } } m_Direction.Normalize(); } void CheckCellAgainstSight( int Cell ) { GRID.m_Cells[Cell].m_InSight = true; int i, j; //check grid cell for shadow bits in the way for( i = 0; i < GRID.m_Cells[Cell].m_NumBits; ++i ) { int shadowBitIndex = GRID.m_Cells[Cell].m_ShadowBits[i]; if( shadowBitIndex != -1 ) { //check to see if this is the player if( shadowBitIndex == 0 ) { //if the player isn't completely hidden, have the red freak out if( PLAYER.IsHidden() ) { m_State = 1; m_ExcitedCounter = 120; for( j = 0; j < NUM_RED_SCREAMS; ++j ) { if( RED_SCREAMS[j].m_UpdateCount == 30 ) { RED_SCREAMS[j].SetActive( m_Position.x, m_Position.y ); break; } } } } //check to see if this bit has movement else if( SHADOW_BITS[ shadowBitIndex ].m_Forces.x != 0.f || SHADOW_BITS[ shadowBitIndex ].m_Forces.y != 0.f ) { m_State = 1; m_ExcitedCounter = 120; for( j = 0; j < NUM_RED_SCREAMS; ++j ) { if( RED_SCREAMS[j].m_UpdateCount == 30 ) { RED_SCREAMS[j].SetActive( m_Position.x, m_Position.y ); break; } } } Vector2D themToUs = new Vector2D(); themToUs.x = m_Position.x - SHADOW_BITS[ shadowBitIndex ].m_Position.x; themToUs.y = m_Position.y - SHADOW_BITS[ shadowBitIndex ].m_Position.y; float distance = themToUs.MagnitudeSquared(); if( distance < MAX_AFFECT_DIST ) { themToUs.Normalize(); float distRatio = (MAX_AFFECT_DIST - distance) / MAX_AFFECT_DIST; distRatio *= 1.5f; themToUs.Multiply( distRatio ); m_Direction.Add( themToUs ); } } } } void Die() { m_State = 2; } void Draw() { stroke( 255, 0, 0 ); fill( 255, 0, 0 ); switch( m_State ) { case 2: { line( m_Position.x - 7.5f, m_Position.y, m_Position.x + 7.5f, m_Position.y ); line( m_Position.x, m_Position.y - 7.5f, m_Position.x, m_Position.y + 7.5f ); line( m_Position.x - 7.5f, m_Position.y - 7.5f, m_Position.x + 7.5f, m_Position.y + 7.5f ); line( m_Position.x - 7.5f, m_Position.y + 7.5f, m_Position.x + 7.5f, m_Position.y - 7.5f ); } break; case 1: { line( m_Position.x - 7.5f, m_Position.y, m_Position.x + 7.5f, m_Position.y ); line( m_Position.x, m_Position.y - 7.5f, m_Position.x, m_Position.y + 7.5f ); line( m_Position.x - 7.5f, m_Position.y - 7.5f, m_Position.x + 7.5f, m_Position.y + 7.5f ); line( m_Position.x - 7.5f, m_Position.y + 7.5f, m_Position.x + 7.5f, m_Position.y - 7.5f ); } case 0: { ellipse( m_Position.x, m_Position.y, m_Width, m_Height ); line( m_Position.x, m_Position.y, m_Position.x + (m_Direction.x * 7.5f), m_Position.y + (m_Direction.y * 7.5f) ); } break; } } }; class RedScream { Vector2D m_Position; int m_UpdateCount; void Initialize() { m_Position = new Vector2D(); m_UpdateCount = 30; } void Update() { ++m_UpdateCount; if( m_UpdateCount > 30 ) { m_UpdateCount = 30; } } void Draw() { if( m_UpdateCount < 30 ) { stroke( 255, 0, 0 ); noFill(); ellipse( m_Position.x, m_Position.y, m_UpdateCount*3.f, m_UpdateCount*3.f ); } } void SetActive( float X, float Y ) { m_UpdateCount = 0; m_Position.x = X; m_Position.y = Y; } }