Home
In opdracht van

Over:

Wrap it up is een 4 player co-op game dat gemaakt is in 2 weken. Het doel is om samen te werken om zoveel mogelijk pakketjes te maken in een bepaalde tijd. Dit project heb ik samen gedaan met didier vermunt en jipp jansen

Mijn bijdrage:

Crafting

Om de game lastiger te maken hebben we een crafting systeem toegevoegd. In dit systeem moet een speler een of meerdere items op een station leggen om vervolgens nieuwe items mee te maken.
Hierbij heb ik scriptable objects gebruikt om items en recepies de maken. Zodat we makkelijk nieuwe items kunnen toevoegen. En zodat we onze stappen voor het maken van een item snel kunnen aanpassen. Elke plek waar een item op geplaatst kan worden is in pricipe een station. Maar een craft station bewaard de items en wanneer de station vol is zou een item gemaakt worden
                
private bool IsAllowedToPlace => CurrentObjects.Count < Limit && !IsCrafting;
public override bool AddObject(UseObject useObject)
{
    //check if it is the right time to place and it is allowed to place this object on this station
    if (!IsAllowedToPlace || !UniqueItems.Contains(useObject.Item))
        // dont allow player to place item on station
        return false;

    CurrentObjects.Add(useObject);
    MyCraftUI.SetImages(CurrentObjects);

    // disable object and set reference
    useObject.gameObject.SetActive(false);
    useObject.Station = this;

    // find a recipie that is useable with the current objects
    // if no recipie is found, the item will be turned into scrap
    GetRecipie();
    if (CurrentObjects.Count == Limit)
        Craft();
        return base.AddObject(useObject);
}

private void GetRecipie()
{
    Recipe recipie;
    Recipes.FindValidRecipie(CurrentObjects.Select(x => x.Item).ToList(), out recipie);
    if (recipie)
    {
        CurrentRecipe = recipie;
        Result = recipie.Output;
    }
}

public static bool FindValidRecipie(this IEnumerable recipes, IEnumerable items, out Recipe Result)
{

    // get count from ienumerable
    int itemcount = items.Count();
    
    Result = null;
    foreach (Recipe recipe in recipes)
    {
        // check if item count is same as items needed for recipie
        if (recipe.Inputs.Length != itemcount)
        continue;
        
        // create copy of list
        var ItemsNeeded = recipe.Inputs.ToList();
        foreach(Item item in items)
        {
            // get index of a item in the recipie
            int index = ItemsNeeded.IndexOf(item);
            if(index != -1)
                ItemsNeeded.RemoveAt(index);
        }
        // If all items required for the recipie are present. Return the result
        if (ItemsNeeded.Count == 0)
        {
            Result = recipe;
            return true;
        }
        
    }
// no recipies have been found
return false;
}
                
            

Tutorial

Om uit te leggen heb ik 2 delen gemaakt voor tutorial. De eerste is altijd zichtbaar in het begin. Dit is om de stappen van de crafting uit te leggen. Voor een extra uitleg in het begin heb ik ook een help systeem gemaakt die aangeeft langs welke stations je moet gaan om succesvol een pakketje te maken
Tutorial popup om een hint te geven aan de speler
Image die crafting laat zien aan het begin van het level

Controller Management

Omdat we de game makkelijk wouden laten kunnen spelen hadden we een systeem nodig waarbij controllers makkelijk toegevoegd en verwijdert kunnen worden. Dit heb ik met 2 delen makkelijk gemaakt
De eerste is een unieke kleur voor elke speler en controller. Elke controller index wordt ook aan de common kleuren toegevoegd
De Tweede is een notificatie systeem die aangeeft wanneer spelers connecten en disconnecten.
            
public void OnPlayerJoin(PlayerInput input)
{
    //create record of the player
    var player = new Player
    {
        Id = Players.Count,
        Input = input,
        WorldObject = input.gameObject,
        Movement = input.GetComponent()
    };
    Players.Add(player);

    player.Movement.enabled = MovementEnabled;

    //bind special actions
    input.currentActionMap.actions.First(e => e.name == "Disconnect").performed += (e) => OnPlayerDisconnect(e, player);
    input.currentActionMap.actions.First(x => x.name == "Ready").performed += (x) => PlayerReady(player);


    // if this is the first player to join, take controll of ui
    if (Players.Count == 1)
    {
        input.uiInputModule = uiInputModule;
        uiInputModule.enabled = true;
    }

    // if this is the first time someone joins. invoke event
    if (!FirstPlayerJoined)
    {
        FirstPlayerJoined = true;
        OnFirstplayerJoined.Invoke();
    }
    OnplayerJoined.Invoke(input);

    // update player skins
    UpdatePlayers(true);

    // prevent player from being destroyed between scene loading
    DontDestroyOnLoad(input.gameObject);
}
                
            
            
private void PlayerReady(Player player)
{
    // check if ready is needed
    if (!AllowedToGetReady)
        return;
    
    // update players
    player.Ready = true;
    UpdatePlayers();
    
    // if ready to play. start
    if (Players.TrueForAll(e => e.Ready))
        OnAllPlayersReady.Invoke();
}

public void OnPlayerLeave(PlayerInput input)
    {
        // get player via input
        var player = Players.First(x => x.Input == input);

        // if player is the first one to join. reassign the ui input module
        // if no players are left. disable it
        if (player.Id == 0)
            if (Players.Count >= 2)
                Players[1].Input.uiInputModule = uiInputModule;  
            else
                uiInputModule.enabled = false;

        // remove the players and reassign ids.
        Players.Remove(player);
        int i = 0;
        Players.ForEach(e =>
        {
            e.Id = i;
            i++;
        });
        
        // update player skins and invoke event
        OnplayerLeave.Invoke(input);
        UpdatePlayers(true);
    }