One More In The Bag

I'm happy to report the successful completion of another game!

I actually managed to scope correctly & get something done in a reasonable time frame, which is a damn miracle at this stage.

Dad's Last Fishing Trip is a short fishing simulator, with fairly basic fishing, but tells the story of a man's childhood fishing trips with his Dad, as they take a final fishing trip together.

Go check it out!

Fun Stuff

This project was a lot of fun, as they all are. Tackling the water shader took about half a day of frantic googling, as it's my first time properly diving into shadergraph. I'm really pleased with the results though.

The Water Shader

Essentially, it's taking a water normal map, to give it the shape, inverting it & then blending it with its inverted self to give a sort of criss-crossing water pattern. I'm then just scrolling both maps across each other to give the refraction movement you see in the video.

It then takes in the view of the camera, & reflects that back at the player, with a bit of maths involved to try & not make it a strange mirror. Then I calculate the reflectiveness of the surface, to see how metallic & shiny it looks, though I did end up tossing this in practice.

Finally, I create a basic noise gradient for the foam & stick it to the edges of the shader & allow the whole surface to undulate, creating a simple wave-like effect, based on a Sine wave.

The Fishing Rod

The rod caused me a lot of trouble. Rope physics, as you may know or imagine, can be quite tough to simulate correctly. Thankfully, I found a half-cheat that lets me constantly calculate & adjust the positions of multiple particles within the 'rope' & then apply a force to the bobber in order to keep it in place, using Verlet Integration, which allows you to integrate Newton's equations of motion, effectively finding the change over time in motion of the particles, given a position, gravity, & the placement of adjacent particles/tethers.

private void Verlet(LineParticle p, float dt)
{
    Vector3 tempPos = p.Pos;
    p.Pos += p.Pos - p.OldPos + (dt * dt * p.Acceleration);
    p.OldPos = tempPos;
}

private void PoleConstraint(LineParticle p1, LineParticle p2, float restLength)
{
    Vector3 delta = p2.Pos - p1.Pos;
    float deltaLength = delta.magnitude;
    float diff = (deltaLength - restLength) / deltaLength;

    p1.Pos += 0.5f * diff * delta;
    p2.Pos -= 0.5f * diff * delta;
}

private void FixedUpdate()
{
    foreach (LineParticle lineParticle in lineParticles)
    {
        Verlet(lineParticle, Time.fixedDeltaTime);
    }

    for (int i = 0; i < Iterations; i++)
    {
        for (int j = 0; j < Segments - 1; j++)
        {
            PoleConstraint(lineParticles[j], lineParticles[j + 1], 
              segmentLength);
        }
    }

    lineParticles[0].Pos = lineAttach.position;

    Vector3 force = (lineParticles[^1].Pos - bobber.transform.position) * 
      tensionConstant;
    bobber.AddForce(force);

    lineParticles[Segments - 1].Pos = bobber.transform.position;

    var positions = new Vector3[lineParticles.Count];
    for (int i = 0; i < lineParticles.Count; i++)
    {
        positions[i] = lineParticles[i].Pos;
    }

    lineRenderer.SetPositions(positions);
}

MUCH tweaking was required to get the cast to actually look good & it still isn't exactly perfect - the line releases too much slack immediately on cast, but I didn't have the time or the patience to fully debug that. I might go back to it at some point if I do a bigger fishing game.

Next Week

This coming weekend I'm not entirely sure what my plan is, but as soon as I figure it out, I'll fire you all a message. Suggestions are always welcome!

Thanks for reading,

Tim

Subscribe to Red Squirrel Games

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe