3 min read
ShipWrecked Bird

ShipWrecked Bird gameplay

The ShipWrecked Bird project is a game developed in Unity that incorporates elements of machine learning, fuzzy logic, and various intriguing mechanics. The game is compatible with mobile devices, desktop systems, and supports VR technology.

🦘 Game Physics

The game does not utilize physics libraries; instead, its mechanics are entirely based on mathematical models. For instance, the character’s jump is a modified version of a parabolic trajectory. The Move method shifts an object in 3D space from one point to another, with an additional curve effect along the Y-axis.

public void Move(
    Transform target,
    Vector3 startPosition,
    Vector3 endPosition,
    float time
)
{
    const float fallFactor = 0.2f;

    float modifiedTime = (time > 0.5f)
        ? 0.5f + fallFactor * (time - 0.5f)
        : time;

    float targetX = startPosition.x +
        (endPosition.x - startPosition.x) * time;

    float targetY = startPosition.y +
        (endPosition.y - startPosition.y) * modifiedTime +
        0.6f * (1 - (Mathf.Abs(0.5f - modifiedTime) / 0.5f) *
        (Mathf.Abs(0.5f - modifiedTime) / 0.5f));

    float targetZ = startPosition.z +
        (endPosition.z - startPosition.z) * time;

    target.position = Vector3.Lerp(
        target.position,
        new Vector3(targetX, targetY, targetZ),
        1f
    );
}

Super Mario Bros jump proces

šŸ† Fuzzy Logic

The game features an intriguing difficulty model where the level of difficulty is determined by two parameters: the player’s high score and the current number of collected coins during gameplay. This approach aims to make the game more challenging for experienced players compared to novices, ensuring it remains a constant challenge without requiring players to repeatedly face levels that are too easy for them.

Fuzzy Logic model

šŸ¤– Machine Learning

The opponents’ logic was trained using reinforcement learning with the ML Agents library.

public class EnemyLogicAgent : Agent
{
    public override void CollectObservations(VectorSensor sensor)
    {
        sensor.AddObservation(EnemyManager.GetCoordinates()[0]);
        sensor.AddObservation(EnemyManager.GetCoordinates()[1]);
        sensor.AddObservation(EnemyManager.GetDirection());
        sensor.AddObservation(EnemyManager.GetDistanceToPlayer());
        sensor.AddObservation(PlayerManager.GetCoordinates()[0]);
        sensor.AddObservation(PlayerManager.GetCoordinates()[1]);
    }

    public override void OnActionReceived(ActionBuffers actions)
    {
        switch (actions.DiscreteActions[0])
        {
            case 0:
                EnemyManager.GoUP();
                break;
            case 1:
                EnemyManager.GoLeft();
                break;
            case 2:
                EnemyManager.GoRight();
                break;
        }

        CheckEnemyPosition();
    }

    public override void OnEpisodeBegin()
    {
        BoxManager.ResetGame();
        PlayerManager.ResetGame();
        EnemyManager.ResetGame();
    }

    private void CheckEnemyPosition()
    {
        if (EnemyManager.GetPosition() == PlayerManager.GetPosition())
        {
            SetReward(+1f);
            EndEpisode();
        }
        else if (EnemyManager.GetPositionStatus() == 3)
        {
            SetReward(-1f);
            EndEpisode();
        }
    }
}

Indicators of successful learning include parameters such as the dynamics of reward accumulation over time:

the dynamics of reward accumulation over time

and the change in episode length over time:

the change in episode length over time

šŸš€ Curious About Project?

The game is still in its top-secret beta phase. It’s been put on hold while the developer’s ā€˜to-do’ list mysteriously grew to the size of a novel.

Stay tuned, because this game’s coming—just as soon as we figure out how to clone ourselves or invent a 48-hour day!

Screenshot of the tutorial