top of page

    void CalculateNLIForm()
    {

        // for each line segment, compute the position using NLI

        for (int t = 0; t <= tMax; t++)
        {
            line.points[t] = NLI(t * oneDivByTMax);
        }
    }

​

    Vector3 NLI(float t)
    {

        // copy of points needed to compute nested linear interpolation formula
        List<Vector3> tempPoints = new List<Vector3>();

        foreach (Vector3 vec in controlPointPositions)
        {
            tempPoints.Add(new Vector3(vec.x, vec.y, vec.z));
        }

​

        // use dynamic programming to compute the point at t

        for (int i = 0; i <= d; i++)
        {
            for (int j = 0; j < d - i; j++)
            {
                tempPoints[j] = (1 - t) * tempPoints[j] + t * tempPoints[j + 1];
            }
        }

​

        // the calculated point is stored in the first index

        return tempPoints[0];
    }

This code that I wrote for my Curves and Surfaces class takes bezier control points and computes the positions of each line segment of a line by using Nested Linear Interpolation.

 

In order to get the most out optimizing, I chose to implement the dynamic programming algorithm without recursion.

​

I used Vector3 so that the code can be used to draw 3-dimensional curves.

    public void Grow()

    {
        if (!wheel.IsOpen())
            return;
        actionList.Clear();
        actionList.Add(new ScaleAction(gameObject, 0.5f, new Vector3(1.2f, 1.2f, 1.0f)));
        actionList.Add(new SetColorAction(gameObject, 0.5f, 0.0f, highlightColor));

        Project2Sounds.PlaySound(SoundType.Select);
    }

​

    public void Shrink()
    {
        actionList.Clear();
        actionList.Add(new ScaleAction(gameObject, 0.25f, new Vector3(1.0f, 1.0f, 1.0f)));
        actionList.Add(new SetColorAction(gameObject, 0.25f, 0.0f, mainColor));
    }

This code that I wrote for my Game Feel class grows and shrinks an element of the weapon wheel when the player hovers over it with the mouse.

​

The task of scaling the object and setting its color is assigned to an action list which then takes care of interpolating those values over time.

    private void UpdateMovement(float jerk, ref float acceleration, ref float velocity,

                                                         float currVelocityCap, Vector3 axis)
    {
        // if the object is trying to break or stop accelerating

        // reset the acceleration to make it easier to slow down
        if ((jerk > 0.0f && acceleration < 0.0f) ||
            (jerk < 0.0f && acceleration > 0.0f) ||
            (jerk == 0.0f))
        {
            acceleration = 0.0f;
        }

​

        // check if the object has reached it's capped max velocity
        if (velocity >= currVelocityCap)
        {
            return;
        }

​

        // if a jerk force is being applied, change the acceleration
        if (jerk != 0)
        {
            acceleration = Mathf.Clamp(acceleration + jerk * Time.deltaTime, -maxAcceleration, maxAcceleration);
        }

        velocity = Mathf.Clamp(velocity + acceleration * Time.deltaTime, -currVelocityCap, currVelocityCap);

​

        // add force along the axis

        rb.AddForce(axis * rb.mass * acceleration,  ForceMode.Impulse);
    }

This code that I wrote for my current team project updates the acceleration and velocity of an object along any axis. It is being used to control the movement of the submarine that the player pilots.

void Level::Render()
{
   // get the data read earlier from Tiled
   const std::vector<int>& levelgrid = tiled_data_->GetGrid();
   int w = tiled_data_->GetWidth();

   int h = tiled_data_->GetHeight();

​

    // calculate the scale matrix (only needs to be done once)
   glm::vec3  scale = transform_->GetScale();
   glm::mat4 scaleM = glm::scale(glm::mat4(1.0f), scale);


    int tile_type = 0;
   glm::vec3 camPos = _mainCamera->getPos();


   // for each tile
   for (int y = 0; y < h; y++)
   {
       for (int x = 0; x < w; x++)
       {
           // get the tile position
           glm::vec3 tilePos = tiled_data_->TileIndexToWorldPos(x, y);


           // if the tile is not on screen, there is no point in drawing it
           if (!tiled_data_->TileIsOnScreen(tilePos, camPos))
           {
               continue;
           }
           
           // determine which tile sprite to draw
           tile_type = levelgrid[y * w + x];

​

            // if the tile has no type, there is nothing to draw
           if (tile_type != 0)
           {
               // draw the tile
               tile_sheet_->SetFrame(tile_type);
               glm::mat4 translateM = glm::translate(glm::mat4(1.0f), tilePos);
               glm::mat4 matrix = (translateM * scaleM);
               _mainCamera->SetModelMatrix(matrix);
               tile_sheet_->Render();
           }
       }
   }
}

This is code that I wrote for my sophomore team project which used a custom engine. It takes the tile map data and uses it to draw each grid of the level.

​

In order to significantly reduce the computational cost of the level renderer, I limited repeat calculations and didn't bother rendering the tiles that would be off screen.

bool TileMap::TileIsOnScreen(glm::vec3 tilePos, glm::vec3 camPos) const
{
   float winWidth = _mainOpenGL->getWinWidth();
   float winHeight =  _mainOpenGL->getWinHeight();

 

   //go .05f over the radius just in case
   int x_radius = winWidth * 0.55f + dimensions_;
   int y_radius = winHeight * 0.55f + dimensions_;


   //checking if the position is currently in the camera
   if (tilePos.x + camPos.x < x_radius &&
       tilePos.x + camPos.x > -x_radius &&
       tilePos.y + camPos.y < y_radius &&
       tilePos.y + camPos.y > -y_radius)
   {
       return true;
   }
   return false;
}

bottom of page