Week 18 – Hand over and finishing deliverables

JUNE 24 → JUNE 27 – 2024

Tasks

Project Hand Over & Communication

  • My Monday morning started with meeting with Frank Bonsma, the programmer that works together with our client. The meeting went very well and I delivered the v1.0.0 apk file as well as the needed marker images and the source code.
  • Later during the week I also sent him a revised version with implemented fixes discussed during the first meeting.
  • Sent him ‘mouths’ that were made by Emma and Valeria so he could implement lip-syncing himself.

Technical Developments

  • Replaced old marker images
    • Two weeks ago, Joris and the client decided on a new design for the markers. Hence why I implemented them into the application. They simply replace the ones I already had.
  • Fixed flower packs on game reset
    • After resetting the game, the flower packs in scene three would remain invisible. This was due to me forgetting to reset some values and animation states previously. I fixed these and sent a revised version of the game to Frank Bonsma.
  • Fixed QR code screen showing up in last scene
    • During my implementation of the compass hamsa last week I overlooked an issue I created. After the completion of scene five,the QR code screen shows up. Even when it is the last scene and there should be no more screens after to scan.

Double Diamond

Discover

During the meeting with Frank, we discussed what else he wanted me to add this week and based off of that I implemented a few fixes.

Define

One of the main fixes revolved around preventing a game-breaking issue where the player could not proceed in scene three after the game had been reset.

Develop

My solution was to incorporate the Exit state Unity provides in it’s animation. With using this and also saving the original position of flower packs, I was able to circumvent the issue.

Deliver

I created another release on our GitHub that includes these changes and small fixes. I also sent Frank this newly updated version.


Research

The research I did this week was from conversing with Frank and figuring out what I could still add to the project.


Reflection

My final week was a good one, having met Frank Bonsma I thought it would have been good for us and the project if we had communicated with our client through him instead. He seemed to understand what I was talking about, he valued me and showed interest and was overall a very relaxing presence.

I was really happy with the last few fixes I got to implement this week and especially the pace I could do it at. It only took me a few hours to implement everything. The rest of the week was spent on rewriting my blogs, collecting images and videos for the presentation and preparing for the deadline.

More about the general process, project and client communication as well as learning goals can be found in my personal reflection document. Available on the IMTS page.

Media & code

public void ResetToStartingPosition()1
    {
        rectTransform.anchoredPosition = startingPosition;
    }
if(GameManager.Instance.CurrentSceneIndex <= 4)2
        {
            if (GameManager.Instance.CurrentSceneIndex < 4)
            {
                isGameOver = false;
            }

            if (isGameOver)
            {
                return;
            }
            else if(GameManager.Instance.CurrentSceneIndex < 4)
            {
                isGameOver = false;
            }
       }
  1. Method that resets the flower packs to it’s original position. This is called when resetting the game. ↩︎
  2. Simple statement that checks to see if we have reached the final scene, if we have the first time (at the end of scene four) the bool will be toggled. Then the next time, it will be stopped from showing the QR code screen. ↩︎

Week 17 – Finishing touches and preparing for hand over

JUNE 17 → JUNE 20 – 2024

Tasks

Technical Developments

  • Implemented compass object in scene UI
    • Joris designed and animated a compass featuring a hamsa. After every scene’s completion, this compass would pop-up with an extra ‘finger’ each time. The animation was game-ready and so all I had to do was implement it correctly. (see example below)
  • Implemented mother animation frames
    • This was basically the same thing as the grandma last week, based on the voice over I assigned textures to the mother to create the illusion of animation. (see example below)
  • Implemented bread family animation frames
    • Scene four, also known as the market scene, featured the bread family. A group of breads that were commonly used in the museum and so they had to be in our experience as well. I implemented all frames according to the voice overs to animate them too. (see example below)
  • Added dual language capability for the animation frames
    • One thing I had not thought of when developing the CharacterTextureReplacing script was different languages. Due to the timing being different per voice over, I could not simply use the ones I had made based on the English voice over. So instead, I added a localization ID much like the one used in the AudioManager to accommodate different languages.
    • This meant I also had to redo all the frames I had added already, but luckily I could copy and modify most of them.
  • Implemented all Eden frames
    • Valeria finished all character frames which allowed me to implement the main character, Eden, too.

Double Diamond

My development this week was mostly creating content again, which makes sense seeing it is the end of the dev cycle. However I did get to brainstorm about one new issue, the multiple language support for the animation frames.

Discover

To figure out the best way of tackling this issue I decided to look through my existing scripts and observe how I handled this issue previously. This ultimately lead me to my final solution.

Define

The solution was not that difficult in the end, I had to find a way to ‘bundle’ a language identifier to a set of frames.

Develop

To do this, I simply added a string to the CharacterPose class. This string would then be added to the name at Runtime due to the Awake() function. After this I could simply call script.SetPose(“Pose1” + LocalizationSettings.SelectedLocale.Formatter); to get the correct pose corresponding to the currently selected language. This also works when changing the language during the game and provides an elegant and flexible solution to the problem.

Deliver

As communication with our client was terminated I did not have any deliverables for him this week, I did however keep my team members updated by showing them gifs/videos of my progress.

I also made a release on our GitHub to prepare for the final handover. This was the 1.0.0 version.

Plan

Next week will be the final week of this project. I will hand over the .apk, marker images and source code to an associate of our client. After which I will use the remainder of the week to add any changes I still have the time for as well as working on all final deliverables for IMT&S.


Research

The research I did this week was based around researching my own code to find what solution I had used before and which was best to apply to the problem at hand.


Reflection

The week was very peaceful compared to previous weeks, most of this was due to the fact we did not have the client breathing down our necks. This led to a more comfortable and relaxed feeling among our team and also helped me to tackle more issues this week.

Next to that, I am quite happy with how I handled some problems that arose this week and I am looking forward to the final week.

Media & code

The implemented compass, animation and design done by Joris.
Implemented mom animation frames.
The implemented bread family frames.
My implementation of language dependent animation frames. The language ID is added onto the frame’s name, after which it can be called by SetPose(“POSE” + LanguageID);
protected void Awake()
    {
        for (int i = 0; i < poses.Count; i++)
        {
            poses[i].name = poses[i].name + poses[i].languageID;1
        }
    }

    public void SetPose(string pose)
    {
        textures.Clear();
    }

public class CharacterPose
{
    public string name;
    public string languageID;2
    public List<CharacterSubPose> subPoses;
    [TextArea(3, 10)]
    public string description;
}
  1. The language ID set in the editor gets added to the pose name. ↩︎
  2. The language ID, which is changeable in editor. ↩︎

Week 16 – Client conflict and finishing functionality

JUNE 10 → JUNE 13 – 2024

Tasks

Client Communication

  • Met with our client on Monday, however this time around it was not really a meeting. In the end we had to terminate all communication with the client. More on this in my personal reflection document.

Technical Developments

  • Improving game reset
    • As planned I started working on improving the game reset through adding eventHandlers which would help the script find where we were when quitting and would in turn help to quit more cleanly. However this did not provide me with the results I desired and so I decided to scrap the idea.
  • Added wolf head rotation towards player
    • To work on making the scene more immersive, I implemented rotation on the wolf in scene three. I also included a clamp, meaning the head is restricted in how far it can turn. This added some much needed responsiveness to the scene.
      (see example below)
  • Added grandma ‘animation’
    • I used my previously written CharacterTextureReplacing script to ‘animate’ the grandma. Valeria (character artist) had made more frames for the grandma which I then toggled between dependent on the voice over and set parameters. This creates the illusion of animation while simply replacing the texture with a new sprite every x seconds. (see example below)
  • Added compass interaction
    • In scene one, the player is asked to collect the compass. For this I used the same collectable setup as I did with the bracelet.
      (see example below)
  • Added book functionality
    • While I have had the paper ready for a while, the book in scene two was not yet implemented. This week however, Alejandra finished the model and animation which allowed me to implement it in the game. (see example below)
  • Added Dutch voice overs
    • As the Dutch voice overs were finally available I added them to the AudioManager, I had set it up in a way that I could easily use the correct language by adding a language formatter to the name. (see example below)

Double Diamond

Most of this week was spent creating content using the tools I had setup previously. This meant that there were no real new developments persé, but instead I finally profited from the work I had put in weeks ago.

Define

My main points this week were adding solid-looking animations as well as properly implementing the book and other interactions.

Develop

I added the wolf head rotation quite quickly as Emma, the artist responsible for the wolf, had set up the rig in an easy to understand way. This meant I could simply write a new script that would rotate the right bone towards the camera.

To add the grandma’s animation, I simply used the tool I had written before. The only time-costly part was having to listen to the voice over multiple times to get the timing right.

The compass interaction was a simple reuse of the bracelet interaction, which I had set up in a flexible manner to accommodate other interactables like the compass too.

Finally the book interaction was not too hard to implement either, Alejandra had done a superb job on the animation and all I had to do was place the pieces of paper in the book in a correct way.

Deliver

As communication with our client was terminated I did not have any deliverables this week, I did however keep my team members updated by showing them gifs/videos of my progress.

Plan

Next week I’ll work on implementing a major UI object made by Joris as well as all other animations for the characters.


Research

No real research was conducted this week.


Reflection

As the meeting on Monday had been quite a difficult one, I and other members of the team had lost most motivation. This led to this week being more difficult than others but it did unite us more than we had been before.

As far as implementing content goes, I am still very satisfied with everything I got done this week. Especially knowing about the mess our client caused. In the face of adversity we still pushed through and kept working at a steady pace.

Another big plus this week was that I finally was able to see how valuable it is to set up a project like this in a flexible and scalable manner. I was able to do more in less time because I used systems I created a few weeks ago. This felt very rewarding.

Media & code

The wolf rotating it’s head towards the player/camera.
The grandma being animated through replacing the material’s texture.
The compass using the same implementation as the bracelet.
Implemented book interaction with animation and flying papers.
The script in detail. You can set a name, delay to next frame, texture and add a description.
The CharacterTextureReplacing on the grandma.
The audio added to the AudioManager. Allows for setting a type and Localization ID.
protected void FixedUpdate()1
    {
        // Determine which direction to rotate towards
        Vector3 targetDirection = Camera.main.transform.position - head.position;

        // The step size is equal to speed times frame time.
        float singleStep = speed * Time.deltaTime;

        // Rotate the forward vector towards the target direction by one step
        Vector3 newDirection = Vector3.RotateTowards(head.forward, targetDirection, singleStep, 0.0f);

        // Draw a ray pointing at our target
        Debug.DrawRay(head.position, newDirection, Color.red);

        // Calculate a rotation a step closer to the target and apply rotation to this object
        head.rotation = Quaternion.LookRotation(newDirection);

        // Clamp the rotation to prevent full 360-degree rotation and excessive looking up/down
        float minHorizontalAngle = -140f; // minimum angle to rotate left from the initial forward direction
        float maxHorizontalAngle = 0f;  // maximum angle to rotate right from the initial forward direction
        float minVerticalAngle = 30f;   // minimum angle to look down
        float maxVerticalAngle = 100f;    // maximum angle to look up
        head.rotation = ClampRotation(head.rotation, minHorizontalAngle, maxHorizontalAngle, minVerticalAngle, maxVerticalAngle);
    }
  1. The method used to rotate the wolf’s head towards the player/camera. ↩︎

Week 15 – Game resetting and flower pack animation

JUNE 3 → JUNE 6 – 2024

Tasks

Client Communication

  • Met with our client on Monday to accommodate with his wish to be up-to date every monday.
  • He wanted to see videos of an animation experiment we proposed. We would be using AI powered video to animate the characters.
  • Another request was for us to have the papers in scene two be actual rules. This was something that we had asked about when we originally started work on the interaction and it was not necessary then. This made it a bit annoying to hear about it being important now.

Technical Developments

  • Finalised game resetting
    • Managed to implement game resetting, the player can now tap five times in the top-right corner to open the menu and switch languages or reset to main menu.
      • An issue still persists where the voice over keeps playing if it was active.
  • Refined flower seed choice with visuals and animation
    • After selecting the preferred flower, the pack now moves to the middle and after that will play an ‘opening’ animation. Animation was made by Yonah. (see video below)
    • I came up with the idea to do an opening animation and asked Yonah if he could implement it, due to some struggles I also provided an example. (see below)

Double Diamond

My development this week was based around tying up loose ends and providing the player with a way to reset their game as well as upgrading the visuals in some parts.

Define

The main issue I had to tackle in regards to the game reset was getting it working in my existing setup.

Another problem I was tasked with fixing was making sure the flower pack looked good, I decided to use code to do the animation instead as that was more flexible in my opinion.

Develop

I eventually managed to do so by separating my StartGame() method I used in the GameManager and allowing it to be called from other scripts. This way I could control when to start a new game and take the appropriate measures.

To fix the problem of having to animate the packs moving to the middle in an efficient manner I decided to use a custom script. This would make it easier as all packs can use the same script instead of having to animate them individually. (see code below)

Deliver

These changed weren’t communicated externally but they were shown to my team members for feedback.

Plan

Next week I’ll work on improving the game resetting, implementing the final interactables for the other scenes, implementing the art for the final scenes and (depending on the client) importing the Dutch voice overs.


Research

No research worth mentioning was conducted this week.


Reflection

The communication with the client got more tense this week, which was not of benefit to any of us and neither to the project.

Other than that I am happy with the additions I was able to make. The flower pack interaction really improves the whole feel of the forest scene and the game reset is a valuable addition and definitely something I should have thought of sooner myself.

Media & code

Example animation I provided to support my idea.
Final animation in game, with the MoveToMiddle script attached.
public event Action OnMiddleReached;1

protected void Update()
    {
        if(Input.GetKeyDown(KeyCode.Alpha8))
        {
            StartMoveToMiddle();
        }

        if (moveToMiddle)2
        {
            rectTransform.anchoredPosition = Vector2.Lerp(rectTransform.anchoredPosition, targetPosition, speed * Time.deltaTime);

            if (Vector2.Distance(rectTransform.anchoredPosition, targetPosition) < 0.1f)
            {
                rectTransform.anchoredPosition = targetPosition;
                moveToMiddle = false;
            }
        }
    }
    /// <summary>
    /// IEnumerator to reset the game and instantiate new environments.
    /// </summary>
    /// <returns></returns>
    public IEnumerator ResetGame()3
    {
        trashProgress.ResetScore();

        yield return new WaitUntil(imageTracking.EnvironmentsAreRemoved);

        imageTracking.RemoveEnvironments(false);

        SetSpawnablePrefabs();

        List<GameObject> newPrefabs = imageTracking.SetSpawnablePrefabs();
            GameManager.Instance.modifiableScenes[i].sceneEnvironmentPrefab = newPrefabs[i];
        }
        
        startSceneIndex = 0;

        SetActiveScene(startSceneIndex);

        AudioManager.Instance.StopAllVoiceOvers();

        DeactivateAdditionalObjects();

        mainMenuUI.SetActive(true);
    }
  1. Added an event that could be subscribed to, this way the rest of the scene will only start playing after the pack has reached the center. ↩︎
  2. Bool that could be changed through a method, after which the object will begin it’s lerped move towards the center of the screen. ↩︎
  3. Added method to reset the game, this will go through various scores and settings to reset them as well as instantiating new versions of all scenes. ↩︎

Week 14 – Market scene, new voice overs and SFX

MAY 27 → MAY 30 – 2024

Tasks

Client Meeting

  • Met with our client on Monday to accommodate with his wish to be up-to date every monday.
  • Asked him about the voice overs, it was a difficult conversation as he got quite defensive and did not answer any question other than blaming it on his own client (the museum).

Technical Developments

  • Replaced old voice overs
    • Our client provided us with Dutch voice overs, however their quality was quite lacking and I pointed this out to him. Additionally I found that he replaced the final voiceovers once again, this was one of the last straws as I had replaced the voiceovers numerous times now and was told by him that I had received the final version last week.
  • Implemented SFX
    • I scoured the internet to find public domain sound effects to use in our game for most of the interaction. Picking up paper, collecting trash and various UI sounds. These were then added to the AudioManager and allowed to be called from anywhere.
      (see example code below)
  • Implemented collectables
    • Another ‘problem’ proposed by our client and the team was that we had to be able to ‘collect’ a bracelet in scene four as well as a compass in scene one. For these collectables I wrote a separate script that has an event for when it is clicked and I added an animation to constantly rotate it.
  • Implemented game reset
    • Our client had another request, a way to ‘reset’ and quit the game early. I had not even thought about this anywhere during the development and therefore had to brute force some parts to be able to quit the game.

Double Diamond

In terms of development, the main issue this week was to be able to reset the game, as well as providing a way to collect items.

Discover

I consulted other team members about how they would handle the collection as well as researching other games. For the reset there was no real research to be done other than deep-diving back into my own code to identify areas where issues could arise as well as trying to find a way to add the feature in.

Define

The main issue for the collectable is that it could be difficult to instantiate it in the world itself. As well as it not being easiliy visible for the player.

As for the reset, the main problem would be that my current structure did not perse support a player exiting out of a scene.

Develop

My solution for the collectable issue was to parent the object to an empty object in front of the camera. That way the collectable would always be visible as well as being easy to access in terms of code. Next to that I re-used my ‘Interactable’ script that would work as a base for any other collectable object. I then added a ‘Bracelet’ script which inherits from the former.

The reset was more difficult to develop a solution for, eventually I managed to close off most things that were depending on one another, however even now there was still the issue of voice overs continuing to play. The feature was postponed to next week.

Deliver

I created another release on our GitHub that shows the complete playthrough but uses greyboxes for scenes one, four and five. This was on request of the client.

Plan

Next week I’ll work on the flower pack animation and interaction. I will also take another look at the game reset/pausing.


Research

The research I did this week mainly came from conversing with my fellow team members to identify some areas for improvement and pick their brains about collectables.


Reflection

There were some things about the project that were not so much fun anymore. Mainly our client and the communication with him, as it began to be more and more difficult and tense.

Next to that, I was not too happy with the way I set things up now that I had to figure out how to add a game reset within an existing framework that does not necessarily support it.

Media & code

public class Bracelet : Interactable1

    public void CollectBracelet()
    {
        AudioManager.Instance.Play("Paper1");2

        OnBraceletCollected.Invoke();
    }
}
  1. By inheriting from Interactable, I can easily call the needed method through my InputManager. ↩︎
  2. Line to play the SFX. ↩︎

Week 13 – Wrapping up garden scene and voice overs

MAY 20 → MAY 23 – 2024

Tasks

Technical Developments

  • Replaced old voice overs
    • As our client provided us with new voice overs so I cut them up and re-imported them into the project. As the setup remained the same I only had to replace the placeholder versions with the new files.
  • Added a script to control character frames
    • It was not feasible to expect fully rigged and 3D modelled characters due to sudden time constraints so we had to find a different way. I wrote a script that can be easily edited in the Unity editor to set what pose to use for how long.
      (see code & example below)
  • Wrapped up the second scene
    • After advancing the development of the paper interaction I brough everything together and finalised scene two as well. This included the interactions, voice overs and character placeholders.
  • Simulated scene one and four interaction
    • As I finished scene two I decided to soft implement scene one and four as well. There were no assets for these scenes yet but I implemented the needed GameSceneData script and laid out the foundations.

Miscellaneous

  • Communicational issues with our client
    • During the week we were notified by the team lead that our client was not happy with the progress and that we should have had weekly meetings so he could stay on top of it. This was apparently e-mailed to our teachers directly, surpassing us.
    • We then discussed as a team and were very suprised by this whole ordeal but decided to meet every Monday morning at 11:00 from now on.
    • I listened to the new voice overs and had some pointers that I would like to discuss with our client. He did not really help either, I was asking for the Dutch voice overs too as he had placeholders so I could at least implement them. But they were never sent.

Double Diamond

The most difficult part this week was coming up with a good solution for our problem regarding not being able to model and rig the characters.

Discover

I researched methods to achieve what I wanted but did not really find any proper sources that could be implemented. So instead I set out to create my own solution.

Define

The solution would be to create a custom script. Something that could hold multiple images as ‘poses’ and could have a set time before the next image would be used.

The only downside to this solution would be that it takes quite some time.

Develop

I wrote a custom script that holds a list of a custom CharacterPose class, which in itself holds a list of CharacterSubPoses. In this subpose, I could then easily set a name, time to next image and texture to use. These were then used as a coroutine repeatedly, so after the set time expired, there would be a new image used on the character. Creating an effect similar to animation.
(see code below)

Deliver

The progress for this week was not shown to our client, as it had become clear he did not understand the process and could not manage his expectations which impacted us negatively. Therefore, I decided to keep it under wraps for now until we were 100% sure that this was the solution that we would go with.

I did create another release on Github that showcased the full forest scene, it was now finalised and there would be no further additions.

Plan

Next week we’ll start off by having a weekly stand-up meeting with our client. After that I will start implementing SFX and try to improve some of my older scripts until I can implement new art.


Research

The research done this week was not through YouTube but instead through conversation with people around me. I picked some brains to see how they would go about ‘animating’ a character in the way we need. After taking in their opinions and notes I came up with my own solution.


Reflection

The week started off rough with the e-mail that was sent to our teachers. We did not expect that and it was not fair to us. This all left the team in a bit of a somber and unmotivated state. I am happy I still got things done but I too, did not feel too good. This was another breach of trust in my opinion and it was not the first time that there had been issues with him.

Other than that, the work I delivered was solid and I am happy with the solution I had come up with.

Media & code

My solution for our animation problem.
The garden scene, complete with interaction and the grandma changing frames.
    public void SetPose(string pose)1
    {
        textures.Clear();

        for (int i = 0; i < poses.Count; i++)
        {
            if(poses[i].name == pose)
            if (poses[i].name == pose)
            {
                material.mainTexture = poses[i].texture;
                foreach (CharacterSubPose subPose in poses[i].subPoses)
                {
                    textures.Add(subPose.texture, subPose.delayToNextPose);
                }

                if (changeTextureCoroutine != null)
                {
                    CoroutineHandler.Instance.StopCoroutine(changeTextureCoroutine);
                }

                changeTextureCoroutine = CoroutineHandler.Instance.StartCoroutine(ChangeTextureOverTime());
            }
        }
    }

    private IEnumerator ChangeTextureOverTime()2
    {
        foreach (var kvp in textures)
        {
            material.mainTexture = kvp.Key;
            yield return new WaitForSeconds(kvp.Value);
        }
    }
}

[Serializable]
public class CharacterPose3
{
    public string name;
    public List<CharacterSubPose> subPoses;
    [TextArea(3, 10)]
    public string description;
}

[Serializable]
public class CharacterSubPose
{
    public string name;
    public float delayToNextPose;
    public Texture texture;
    [TextArea(3, 10)]
    public string description;
}
  1. The method that can be called from the GameSceneData scripts by passing in the name of the desired pose. ↩︎
  2. The coroutine that is responsible for changing the frame after x time. ↩︎
  3. The pose, which is shown in-editor in the first image. This holds all necessary data and can be accessed and edited within the editor. ↩︎

Week 11 – Figuring out flying paper and new scene

MAY 6 → MAY 9 – 2024

Tasks

Technical Developments

  • Implementing paper collection hint
    • As we found that Rive (an application for vector animations that Yonah & Joris were using) did not work in our Unity project, we had to come up with a different solution.
    • I decided to write a script that would go through sprites and replace the image with the corresponding sprite.
      (see code below)
  • Working on paper physics
    • As the interactions for scene three were finished, we decided to get started on the next-most interactions heavy one. This would be the garden, as there was an interaction with paper flying around.
    • I researched paper physics and tried to find resources online of people who had previously tackled this issue.

Miscellaneous

  • Ascension day

Double Diamond

My main objective this week was tackling the issue that falling paper would be. The physics are really hard to replicate in a simple manner as it would also have to be performant enough for Android.

Discover

I conducted research into paper physics and tried to find resources of people that had previously done work like this. I also researched what would be the best way to create the effect.

Define

Eventually I decided on just animating gameobjects through script, some sort of visual effect would have been possible too but based on the particle systems in scene three I decided against it with perfomance in mind.

The goal would be to write a script that can be activated from a ‘Controller’ after which the paper flies up and floats down similarly to an actual piece of paper.

Develop

Knowing my goal I got to work and quickly stumbled upon a resource on GitHub (listed below) that was called FeatherFall. Which was a script for Unity that closely replicated a piece of paper or other light object falling down.

After importing and tweaking this script a bit I also wrote my own Paper script, that would inherit from Interactable and would be called by my InputManager when interacted with. This followed the same structure as previously used in scene three for the trash. Next to that I wrote a controller script that could simultaneously call all paper sheets.

Deliver

The progress for this week was recorded in a video. Which was also sent to our client, after which he provided feedback about the paper not being allowed to the touch the ground as it was holy. I then explained to him what the technical ramifications would be and we decided it would be fine in this case.

Plan

The plan for next week is to finish the second scene including paper interaction and physics, implement new voice overs that our client sent us. Also, I will be looking for a way to control emotions for our characters as 3D modelling and rigging them does not seem feasible anymore at this moment in time.


Research

Most of the research I have done this week was aimed towards figuring out how paper functions in terms of physics and how to convert that into Unity. For this I watched the following videos.

Falling Paper VFX for Unity https://www.youtube.com/watch?v=D0rzbu5XHOk

[Unity Asset] Falling Paper VFX https://www.youtube.com/watch?v=GDoSP_5rRBg

I also found a great resource on GitHub and read some forum posts.

How to make a simple object fall as a piece of paper? https://discussions.unity.com/t/how-to-make-simple-object-that-would-fall-as-piece-of-paper/252318

VFX Flying Paper https://assetstore.unity.com/packages/vfx/particles/vfx-flying-paper-95726

unity-feather-fall https://github.com/bjennings76/unity-feather-fall


Reflection

The paper physics were very difficult to pin down but I still feel like I could have had it done faster instead of having to move it to next week. Other than that, I am quite satisfied with my current progress; The second scene is coming along nicely due to the structure I had already set up weeks ago, as well as coming up with a creative solution for the animations that weren’t possible in rive.

Media & code

Paper flying with semi-realistic paper physics.
Swipe animation through code.
public class PaperController : MonoBehaviour1
{
    [SerializeField] private List<PaperSheet> papers;

    public void BlowPapers()
    {
        foreach(PaperSheet paper in papers)
        {
            paper.Blow();
        }
    }
}
public class ImageAnimation : MonoBehaviour
{
    public Sprite[] sprites;
    public int spritePerFrame = 6;
    public bool loop = true;
    public bool destroyOnEnd = false;

    private int index = 0;
    private Image image;
    private int frame = 0;

    private bool isPlaying = false;

    protected void Awake()
    {
        image = GetComponent<Image>();
    }

    protected void OnEnable()
    {
        isPlaying = true;
    }

    protected void OnDisable()
    {
        isPlaying = false;
    }

    protected void Update()
    {
        if (isPlaying)
        {
            if (!loop && index == sprites.Length) return;
            frame++;
            if (frame < spritePerFrame) return;
            image.sprite = sprites[index];
            frame = 0;
            index++;
            if (index >= sprites.Length)
            {
                if (loop) index = 0;
                if (destroyOnEnd) Destroy(gameObject);
            }
        }
    }
}2
  1. Class that holds a reference to all paper sheets to collectively activate them when necessary. ↩︎
  2. Script that holds all sprites from a certain sheet and replaces the image with the next sprite according to the spritePerFrame value. ↩︎

Week 10 – Beautifying the forest and mid-term presentation

APRIL 22 → APRIL 25 – 2024

Tasks

Technical Developments

  • Transitioning forest from dead to alive
    • As the player collects all trash, the forest should react accordingly. For this I added a new script that is used on every tree, this script holds a reference to the dead- and alive tree. Then, when called from the GameSceneData script, the tree will transition within a set time. (see code & gif below)
  • Major issues with referencing prefabs
    • During the week I encountered some issues where objects would not be active even when they clearly were. After hours of debugging I found that I had set up my GameManager all wrong and had been using references to the prefab of the environment instead of the instantiated version at runtime. This led to major issues where I was unable to call any methods and do anything else that had to be done so I had to rewrite a part of the original script but the logic was still solid. (see code below)
  • Added lerping between grass textures
    • After consulting Alejandra we decided on a method to lerp between grass textures when the player has collected all trash. She made the shader and I got to implement it in code.
      (see gif below)
  • Added new interaction to pick a flower seed
    • As our client had previously mentioned that he would like small interactions all over the place, I came up with an idea. As we were using a generic seed for the flower spawning and spawned the same flower every time, I thought it could be cool to have a choice. So I implemented the flowers that Alejandra made and added flower packs from which the player could choose.
      (see gif below)

Miscellaneous

  • Mid term presentation
    • Presented our current progress to our assessing teachers and our client. They provided us with a good amount of feedback which was then applied and processed accordingly.

Double Diamond

This week was an accumulation of small improvements that brought a major improvement to the scene. The goal was to implement several visual improvements and fixes like removing the fire, transitioning the trees and lerping the grass.

Discover

My research this week was not through online sources but instead through consultation with my team members. Moreover, I mainly discussed with Alejandra how to approach certain parts like lerping the grass, but also how to transition the trees and make it look good.

Define

We decided on a simple grass lerp in a shader that Alejandra would make, after which I would implement it in script. Next to that, we decided that simply scaling down one tree and scaling up another would be more than fine.

Develop

I took these definitions to Unity and implemented them as proposed. I also created a separate editor script so it would be easy for Alejandra to implement new trees and toggle between the dead/alive ones. Next to that I implemented the grass lerping by adding a boolean that waited for the trash to be collected.

Deliver

These developments resulted in a few videos that were sent to the client as well as in our teams discord to receive feedback.

Plan

Next week I plan to get started on the next scene and it’s interactions. These include picking up paper, but more importantly I aim to figure out the paper physics during the week as I want to create a semi-realistic behaviour.


Research

As mentioned the research this week was mainly from discussing with Alejandra and learning more from her about shaders in Unity as well as trying my hand at editor scripting again.


Reflection

Another solid week in my opinion. I got quite a number of things done and brough major improvements to our current scene, as well as finalising some parts that had been backlogged for a while.

The collaboration between the artists and myself went really well too and I feel like we are on the same wavelength in terms of communication and expectations.

Media & code

Transition between dead and alive trees.
Flower choice through coloured ‘packs’ and corresponding flower spawns.
The grass lerp in action through the editor.
Playthrough with characters and localized pop ups.
private void HandleTrashCollection()
    {
        int index = (int)Mathf.Floor(trashProgressScript.ReturnCurrentScore() / actionPoint);

        if(index <= particleSystemsBase.Count - 1)
        {
            particleSystemsBase[index].GetComponent<ParticleSystem>().Stop();
        }

        if (index <= particleSystemsExtra.Count - 1)
        {
            particleSystemsExtra[index].GetComponent<ParticleSystem>().Stop();
        }

        if(index <= treeSwitcher.Count - 1)
        {
            treeSwitcher[index].ActivateTransition();
        }
    }1private void HandleTrashCollection()
    {
        int index = (int)Mathf.Floor(trashProgressScript.ReturnCurrentScore() / actionPoint);

        if(index <= particleSystemsBase.Count - 1)
        {
            particleSystemsBase[index].GetComponent<ParticleSystem>().Stop();
        }

        if (index <= particleSystemsExtra.Count - 1)
        {
            particleSystemsExtra[index].GetComponent<ParticleSystem>().Stop();
        }

        if(index <= treeSwitcher.Count - 1)
        {
            treeSwitcher[index].ActivateTransition();
        }
    }
    [SerializeField] private GameObject deadTree;
    [SerializeField] private GameObject liveTree;

    [SerializeField] private float speed = 1.0f;
    [SerializeField] private AnimationCurve blendCurve;

    private Vector3 initialScale;
    public bool transitionActivated = false;
    private float blend = 0;

    protected void Start()
    {
        initialScale = transform.GetChild(0).transform.localScale;
    }

    private void Update()
    {
        if (transitionActivated)
        {
            blend = Mathf.Clamp01(blend + Time.deltaTime * speed);

            float modifiedBlend = blendCurve.Evaluate(blend);

            deadTree.transform.localScale = initialScale * (1 - modifiedBlend);

            liveTree.transform.localScale = initialScale * modifiedBlend;

            if (blend >= 1)
            {
                transitionActivated = false;
            }
        }
    }

    public void ActivateTransition()2
    {
        if (transitionActivated)
        {
            transitionActivated = false;
        }
        else
        {
            transitionActivated = true;
        }
    }
  1. Method to handle the trash collection, turn off the fire and toggle the trees to transition. ↩︎
  2. By calling this method, the blending will start and end when it reaches the full value. ↩︎

Week 9 – Structure and localization

APRIL 15 → APRIL 18 – 2024

Tasks

Technical Developments

  • Scene structure
    • Decided on a structure to use for our project, as the project has boundaries in terms of scale (e.g. five scenes) I decided to use a setup where, based on events, the next method gets called through subscription. (see code and explanation below)
  • Full scene playthrough
    • Finalised the structure of a complete scene, completed with interactions, voice overs and environment art. (see video below)
  • Localization support
    • Installed the Unity Localization package to ensure support for (at least) two languages; Dutch and English. Through the use of a string database I was able to easily add dual language support.

Miscellaneous

  • Mid term presentation preparation
    • Started collecting materials to present at the upcoming mid-term presentation.
  • Procedural art redo deadline
    • Delivered my procedural art project in time.

Double Diamond

Finally a week filled with programming once again, this week revolved around creating a flexible setup for our scenes as well as finishing up a complete playthrough of the third scene. Next to that our client had identified an issue, there was no dual language support yet. So I decided to implement that too.

Discover

My research this time around was based around researching a state-machine. I thought that this would be helpful to control the different scenes and be able to pass on data easily. I also did research into adding multiple language support.

Define

The state-machine was too large for a project like this and so instead I decided to use a subscription system. This would then work through simply subscribing to events and unsubscribing every time. This made the setup easy but possibly more time-costly then using a state-machine. However, having to set up such a machine would be a bigger time sink in total.

Develop

I set up a rigorous approach to the subscription system by using an abstract class that every scene would be based on. Then, the root object would hold this script and also contain the necessary references. After which events for interaction and voice overs were listened to and handled accordingly.
(see code below)

Deliver

These developments resulted in a full playthrough for scene three being available. I sent our client the video below and also created a release on our GitHub.

Plan

My plans for next week include presenting the mid-term presentation, adding a transition from a dead forest to a living one as well as other fixes scene three still needs.


Research

As mentioned the research this week was primarily state-machine based even when I decided against using it in the end. I watched the following videos.
These videos did inspire me to create my own, more specific and smaller setup.

Game Manager – Controlling the flow of your game https://www.youtube.com/watch?v=4I0vonyqMi8&t=497s

How to use Bolt State Machines in Unity https://www.youtube.com/watch?v=SVpkh3kMIcg

Unity 2D Scene Management Tutorial https://www.youtube.com/watch?v=E25JWfeCFPA

Programming a Better State Machine https://www.youtube.com/watch?v=qsIiFsddGV4

Build a better finite state machine in Unity https://www.youtube.com/watch?v=NnH6ZK5jt7o

The State Pattern (C# and Unity) – Finite State Machine https://www.youtube.com/watch?v=nnrOhb5UdRc&t=260s


Reflection

I was really happy with my progress this week as well as finally having a week without major distractions. The code I have written this week was really good and I am sure that it provides a stable foundation for the next scenes.

The part I am most happy with is that I came up with the solution myself, I found that it would be easier to do something small like this even when it takes more time and this also enabled me to really customize it to the experience we want to provide. I had not really used abstract classes before but I saw it in one of the researched tutorials and immediately knew I had to use it.

Media & code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract1 class GameSceneData : MonoBehaviour
{
    public abstract void OnSceneEnter();2
    public abstract void OnSceneExit();
}
public class GameSceneAdditionalObject3
{
    public int sceneIndex;
    public int inSceneIndex;
    public GameObject additionalObject;
    public Transform parent;
}
if(scene.sceneEnvironmentPrefab.GetComponent<GameSceneData>() != null)4
                {
                    scene.sceneEnvironmentPrefab.GetComponent<GameSceneData>().OnSceneEnter();
                }
public override void OnSceneEnter()5
    {
        additionalObjects = GameManager.Instance.GetAddditionalObjects();
        audioManager = AudioManager.Instance;

        trashProgress = additionalObjects[0].additionalObject;
        swipeArea = additionalObjects[1].additionalObject;
        seedSpawnpoint = additionalObjects[2].additionalObject;
        popUp = additionalObjects[3].additionalObject;

        audioManager.PlayVoiceOver("ForestScenePart1");
        audioManager.OnVoiceOverFinished += StartTrashPicking;
    }


private void StartTrashPicking()
{
    // First we de-activate the old objects

    // Then we unsubscribe from previous events
    audioManager.OnVoiceOverFinished -= StartTrashPicking;

    // Then we activate new objects and call the needed methods
    trashProgress.SetActive(true);

    // Then we subscribe to new events
    trashProgressScript.OnScoreReached += StartSeedVoiceOver;
}
  1. This class is marked as abstract to be able to override it later for every scene. ↩︎
  2. The class holds two ‘default’ methods. Meaning any script that inherits from this class has to implement those methods. ↩︎
  3. Additionally, this class holds references to objects already in the scene (usually UI). This is done as the instantiated prefab can not otherwise have references to these objects without large costs. ↩︎
  4. This if statement is found in the GameManager script, whenever a new scene is scanned, the script checks to see if it has a script that inherits from GameSceneData (the first script) and if it does it calls the OnSceneEnter method. ↩︎
  5. This is an example of an implemented version of the GameSceneData script, when entering the scene all additional objects are referenced and stored, the first voice over is activated as well as subscribing to an event for when the voice over ends. After it ends, the next method will be called etc. ↩︎
A lite playthrough of our first finished scene.