top of page

Bijian Wu's Development Log

  • bijian wu
  • Apr 28, 2020
  • 37 min read

Updated: May 4, 2020

Inspiration and research

Since our team members all agreed to make a game that have similar features to the popular game called “Monument Valley” in initial GDD. Then I carried out the research on how Monument Valley were made by watching Monument Valley’s creator ustwo studio’s technical lead explaining how he used different techniques to make the mechanics for Monument Valley, and how Monument Valley works in general:


(Figure 1: ustwo’s technical lead in Unity Talk)


Also, luckily, I also found a YouTube video which author explains his approach to how to make similar game to Monument Valley. The author also included his project link to download then play around. After I downloaded the project, and played around with it, it helped me solidify the understanding of how the game works, and the techniques used to create the game, also the challenges the author is facing when creating the game, plus bugs the author leaves in his project.

Link for Monument Valley remake: https://www.youtube.com/watch?v=hetaWVfaLQc

From above sources, it helped gain solid understanding of how Monument Valley works.



Initial Prototype Game creation

I created a new 3D project in unity called GameManagementProject to start with. Once project has created, I started Create Folders for this project. Just to keep things tidy, they are called There are as follows, Fonts, Materials, Models, Prefabs, Scenes, Scripts, Sounds, Sprites and textures:



Then I renamed the SampleScene comes from Unity to Level 1 to start creating first prototype level. I started creating first basic level, that have the illusion of perspective puzzle feeling.

I took the level layout from Monument Valley to use as my reference image.


Firstly, I started tweak with the camera in order to create the desired effect. I first changed the projection to Orthographic mode instead of default Perspective when first created the project. Also, I changed the Size to be 7, just to fit more gameobjects in one view. Also the rotation of the camera been set to x equal to35.064, y eaqual to 45 and z eaqual to 0. Since illusion will only happedn to one angle, this change of rotation will match that angle.


I also added two new Layers called “Top” and “OutMost”, OutMost layer tag will be assigned to gameobjects that will be draw on top of everything, Top is the layer tag will be assigned to gameobject that will be draw on top of the gameobjects that are on another Layers apart from gameobjects that are on OutMost. I also duplicated the main camera twice, I changed the first duplicated main camera’s Culling mask to only Top, this means that this newly duplicated main camera only going to rerender the gameobjects who are on the Top layer, and its name been changed to Camera Top Layer, also its Clear Flags to Depth Only. its Depth value been changed to 1, all this changes will make sure this camera will make gameobjects that on Top Layer drawn on top of the main camera, Audio Listener been removed since the main camera has got one audio listener.


The second duplicated Camera been renamed to Camera OutMost Layer, its Culling mask been changed to OutMost only, Its clear flags been changed to depth only, its Depth value been changed to 2, all this changes will make sure this camera will make gameobjects that on OutMost Layer drawn on top of the main camera and Camera Top Layer, Audio Listener been removed since the main camera has got one audio Listener. After camera been set up properly, I started to create the game environment.

I first imported two very basic primitive shapes, cube as a single plane from Maya, in order to start prototype the game.Two primitive models shown as following:


Now I started to create the level layout. I first check open The Grid and Snap setting, then I changed the move to be 1. Because each cube is exacly 1 unity unit.


I placed the cube one by one but with Ctrl Kep being holded down, which will enable the snap setting. I First created a empty Gameobject called “Environment” which is the root of the envrionment, used to keep the scene hireachy tidy. I also renamed the “Building_block” to “Building_block (1)”, in this way when I duplicate the “Building_block (1)” game object, the second one will automatically being renamed “Building_block (2)”, so on as so forth. Which makes the object’s name more meaningful. I also draged the cube into prefabs folder to create a prefab out of it. Following is the screenshot.



I created a cube then I changed its scale value to .1 on X, 7 on Y, and 0.1 on Z, to mimic the look of thin pillar.

I create two new materials one is Mat_Red, one is Mat_Blue. Mat_Red is used to mark the end point, Mat_blue is used to make the part can be rotated.

I also created a Empty gameoject called “Rotate_Part”, which is used to set the part that can be rotate. And its position been set to be in the middle of the rotating point. Which helps when later rotating the block. I also created a new Capsule 3D gameobject, and its scale value been changed to 1 to X, 0.05 on Y and 1 on Z. and it has been assigned a red Material, it is used to represent the end point of the game.


Following is the protype level’s looking with the rotaing point being rotated to create a new path:


Plane I imported earlier was used to make the illusion looks better, some of them been assigned Top Layer tag, it will make it be drawn on top of the Default layer, it creates a sense of depth to the game.


(screenshot of some of the plane been assigned Top layer tag)

Lastly, on the Project Settings, Quality setting I deleted qualities that re higher than Medium, and changed the Medium setting’s Shadows to Disable Shadow. This will make the illusion more realisitic also improved the overall performance since our game is targeting Andriond Platform.

Finally, I back up the project by using GitHub. I first created a new repository called GameManagementProject and set it to be a private repository, lastly I added a default .gitignore for Unity. After I created a the repository, I commit and push the project to GitHub repository. I constantly push little changes to the GitHub repository I made, so that, if anything is not working, I get the chance to rever it back.


Player path finding, spinning trigger for changing the platform cubes.


I first create a Simple cube to represent the player with a Green Material.


I then imported Dotween package from Unity asset store. This package provides the functionalities to move objects around in a timely manner, which is perfectly and suited for this project.


I first created a Walkable class to attach to all walking cubes in the current scene where player can walk on it. It contains several Boolean fields, like is isStair, isMovingGround and dontRotate, as the name suggested, it is used to determine whether current walking cube whether is a stair or moving ground and not supposed to be rotated. Also it contains two float variable walkPointOffset e and stairOffset variable, these two were then used to in this class’ member method GetWalkPoint, to determine position player should be standing on top on this cube based on above Booleans and offset values. Code snippet can be found bellow.


Also, a simple class called WalkPath got created, which only contains two fields, a Transform type named target and a Boolean type called active. Walkable class then created an array of WalkPath, which is used later doing player’s path finding. Lastly, a previousBlock variable with Transform type got created. After Walkable class got set up. I add the Walkable script as component to all walking cubes in the scene that can be moved by player, most of the walking cube will have 2 possible paths, target references the walking cube in the scene, and active to denote if it is been set to active or not, and Booleans like is stair, etc, and offsets were set up properly.


(example Walkable component settings for a walking cube)

I then created a PlayerController class script, with few member fields, Boolean type variable walking (used for later implement player animation), currentCube variable with Transform type (represent the current cube player is standing on), ClickedCube with Transform type (used to hold the reference of where player clicked on the map), indicator with Transform type (used in the game as indicator to where player has clicked on the map), final path is a List of Ttransform (holds found pathes from current standing cube to clicked cube) and finalPathIndex used to count how far player has moved from current Walkable cube to destination cube.

First, I determine where player is standing on the cube by created a method that gets called inside Update method called RayCastDown, it shots a ray from player’s first child object downwards, this first child object just used to position where ray going to shoot from, if it detectes anything that is Walkable, then change the currentCube to it, script snippet can be seen below.


I then detect user’s touch on mobile screen by using Raycasy method provided by Unity to shoot a ray from camera to mouse clicked position

Part of the code snippet can be seen below.

After touch screen detection has developed, I started to make a path finding algorithm for the player, in the if block of mouse hit check if the clicked cube is a Walkable, clickedCube variable will be set to the clicked Walkable’s cube, also a FindPath member method will get called, this method first declares two list of Transforms nextcubes and pastCubes, then traverses all the possible paths from player current standing cube if it is actice, then add it to the nextCubes list and set its previousBlock to currentCube, pastCubes list only contains player’s currentCube, afterwas ExploreCube and BuildPath methods get called. FindPath methods were shown below.


ExploreCube is a recursive method that keeps calling itself to set all the Walkable cube’s previousBlock up properly, each time remove one from nextCubes. It stops if the nextCubes list is emty. After setting previousBlock, Then BuildPath method will construct the path based on previousBlock set up In here.

exploreCube’s code snippet can be seen below:


BuildPath method works based on previousBlock built from ExploreCube method, from currentCube to clickedCube, then add it to the finalPath list, after finalPath being built, FollowPath method gets called to move the player around. code snippet can be seen below.


FollowPath method works by first set finalPathIndex to 0, then creates a DOTween Sequence, it works by looing final path backwards from the last element to first element, then it checks if that Walkable cube’s isStair Boolean is been set to true or false, then it calculates the time it takes to move to that one, Append is the method in DOTween library that allows a sequence of movement happens seamlessly in timely manner, in this case, every Walkable that takes from player to research destination (clicked cube) were blinded into this sequence by transform.DoMove, then it also checks if that Walkable cube’s dontRotate Boolean is true or false, if yes, then it joins a transfor.DOLookAt alongside with the DOMove, which means it will rotate to look at the position that it is walking towards. Also, a callback method called StopMovingIfPathBecomeInvalid gets appended to each step of sequence, this is the one used later when platform gets moved, it will stop player if the path has changed that different to the finalPath player is taken. Lastly, when sequence is done, a callback method gets triggered, which simply clears out the previousBlock set when calculate the path, also finalPath list got cleared,

FollowPath script code snippet:


StopMovingIfPathBecomeInvalid method code snippet


I then going to create touch control for rotating the platform cubes. First, scene needs to set up, for every block that can be rotated, it will be duplicated 3 times, one for each angle, also, they got named differently, with sufix 270 degree, 90 degree, 0 degree and 180 degree, this were used later when programming, the one that have the same degree as the rotation point (center parent) will be enabled, but others will be set to inactive, because based on which angle rotation point is, the walking path will be different.


(Example scene hierarchy with same object that have four different angles set up)

Afterwards, GameManager class script got created and it has been attached to an empty gameobject called GameManager in the scene, which were used in this game to hold global variables, like player, pivots to hold rotation point, and all the UI elements, it has been set up in this way to allow other scripts have easy access to those global variables. The GameMnager will be exist in every new level created in the future, as each level is different, it presents as a centre object that holds reference for everything that each element in the game wants to access. Thus, it has a public static variable instance which is a type of GameManager itself, then in its Awake method, it is then been set to the current GameMnager gameobject in the scene. Every game level will have its own GameManager, since each level will be different.

GameManager’s Awake method code snippet.


Afterwards, CheckPathSpinningTrigger class script got created, it is the one used in this protype level to set objects to inactive or active or enable paths. CheckPathSpinningTrigger were built on top of a base abstrcut class called CheckForPathBase, CheckForPathBase only contains an abstract method called CheckPath().

CheckForPathBase class code snippet


By derive from this class, CheckPathSpinningTrigger will have to implement CheckForPathBase’s CheckPath method, which is then later got called in GameManager’s update loop. For member variables set up in CheckPathSpinningTrigger class, it stores array of gameobjects to hide in each angle, 0, 90, 180 and 270 respectively, named d0, d90, d180 and d270 in the class. Also, several conditions to check for different angle, lastly, paths in different angles to check for. This whole class only contains one method that is CheckPath, it checks the rotation point’s rotation angle is equal to angle conditions set up for 0, 90, 180 and 270 angles. For example, if 0 angle condition is met, then only the d0paths and d0objects that will be enabled, remaining rest will be set to inactive. But if none of the angle conditions were met, then all the d0, d90, d180 and d270 paths and objects will be set to inactive, present player from moving one. After script got created, it then be assigned to an empty object in the scene hirachy, with all the paths and conditions set up properly.


(CheckPathSpinningTrigger component’s settings, like objects to hide, conditions to chek and paths to enable)

CheckPathSpinningTrigger class code snippet


GameManager calls CheckPath Method by first created a public member variable with an array of CheckForPathBase, array was used here, because in the future there might be more conditions to check for, this array was then got filled in unity’s inspector panel by drag the instance of CheckPathBase in. Then also an int member variable called currentPathToCheckIndex to hold the current which element in an array of CheckForPathBase to listen for, in this case it will be 0, since this array only contains 1 element in this protype scene. Then in update method of GameManager, following code got called:


In order to rotate the platform, a TouchControl script has been created, it then been assigned to an empty gameobject called Rotation Handle, with a box Collider, a Rigibody and newly created Touch Control script attached to it.


How touch control works is that it uses OnMouseOver and OnMouseDrag call back built-in method from Unity together to detect Mobile finger dragging. FingerDown is the method used to detect finger movement, 1 new Boolean variable gets created in GameManager class, it is isRotating, if it is true then player cannot move at all by checking isRotating is true. Code snippet shows as following.


The same code been put into PlayerController class in Update method and FingerDown method in TouchControl class.

In FingerDown method, it checks if current user put at least one finger on the screen, if yes, it further checks to see if the user tries to do dragging on the screen by check touch phase is equal to Moved or not. If all the yes, then it means player is dragging their finger on the screen. Then further checks to see which direction player is dragging the most by compare x and y of the deltaPostion, deltaPosition means the changes on finger movement from last frame, afterwards it the value of touch position will clamped for smooth touch movement, then, it changes the block rotation and set isRotating flag from GameManager to true. Then in Update method, it checks to see if user has not put any of their finger on screen, if yes it further checks to see which angle range was the rotation be set to, then it snaps to nearest condition angles, 0, 90, 180 and 270 degrees. Lastly isRotating been set to false, means player can now move again. ChangeMatOnClick variable is a custom class used to reference to object in the scene that its material needs to be change when user is pressing their finger down.

Touch Controls code snippet can be found below:


A Simple rotation trigger handle got made by using Unity’s primitive shape objects, to represent the handle user can touch on.


ChangeMatOnClick was the method created to change the color of the rotation trigger handle when user draging on it, by just simply setting the mateial on the MeshRenderer’s slot to new material when draged, to old material when user not draging at more.



Level 1 looks like following with above things implemented:


After prototype level got created, I started to do the testing.


Initial testing

I did an Initial testing for team members to see how the current prototype game is. But only Owen and James were able to do it. Following is the testing questionnaire.

1. Did you find any glitches or bugs when testing the game?

2. What do you like about the game?

3. What do you dislike about the game?

4. Any future development suggestions?

5. Share about your level design ideal? What kind of level layout would you expect to see next? (It is better to provide images to illustrate it)

After summarised questionnaires filled by James and Owen, they both all suggested this is good starting point, but just the touch control was a bit hard to control, and model used in the game were too basic and bland, also, there should be a connection point between rotation trigger and the actual platform.

Based on the above feedback, I requested a model from Owen and James to represent the rotation trigger gameobject and some models to spice the game up, also, I adjust the touch sensitivity of the touch control, and added extra condition to check once player is at the end of the platform cube called StopPlayer, with box collider marked as trigger and with a rigidbody on.




PlayerMesh class script were added to the player gameobject, it only contains a reference to the PlayerController. This is used in stop player script to access the PLayerControll component on player, since the gameobject got PlayerController attached to does not have a collider, but collider with attached to its child.

PlayerMesh code snippet is as following:


StopPlayer class script only contains one method that is OnTriggerStay, inside the method, it checks to see if the player entered overlapped with this trigger box is player, if yes, it then loops through player’s finalPath list, if any of the Walkable path is inactive, then it stops player straight away, by kill player’s followSequence, then set its walking Boolean to false.

StopPlayer code snippet can be found below:


Also, I got assets from Owen, to beautify the scene a bit, and shows the connection between the spinning trigger and the platform, they are show as bellow.


After I done with modify the scene and game mechanics according to feedbacks got from Owen and James, I asked them to test the game again. And the new feedback got back was good enough so that I can carry on creating another level.


Adding Second level

Based on the experience gained from creating first level, now I have more experience creating second level.

Second were based on one of Monument Valley’s level, as shown as follow:


Then, I uses the walking cube to build the level like above, and set up Walking cube’s walking paths for each walking cube.

Since this level uses different rotating mechanics than the first level, it does not require to hide and show the gameobjects. This level also uses the GameManager class script, but with different settings, I firstly created the CheckPathRotatingTrigger class script based on CheckForPathBase, then linked it to the GameManager’s script, so that this script’s CheckPath method will be called inside GameManager’s Update callback method. It also holds reference variable to paths to enable and angle conditions to check as first level’s CheckPathSpinningTrigger class script does, but this script does not need to hide and show the gameobjects, check path logic is very similar to CheckPathSpinningTrigger class in first level, when certain angle condition were met, only that path will be enabled, but other paths for other angle conditions were disabled. But if none of the conditions were met, it means platform is rotating, then it simply stops player if player is on edge platform and is currently walking.

CheckPathRotatingTrigger class script code snippet can be seen below.


The touchControl used in this level is different from first level, first level checks for rotation on Z Axis, but this level checks rotation on Y axis. Then I created an empty object called CubicTouchControl that has got a Box Collider and CubicTouchControl script acted as component to it. Following is the CubicTouchControl gameobject looks like in Unity’s inspector.


CubicTouchControl is the class script used in this level to detect user touches, it has got three member float variables for touchSensitivity, rotation threshold x and y, and a ChangeMaterialsOnTouch custom created class type, it is used to change the certain object’s material when user touches and drags on the gameobject, to indicate dragging is on. This script shares many similarities as TouchControl script in the first level, the only differences being that only touch’s delta position x or y is greater than the x or y threshold variables defined at the top of class, then user’s touch will be register.

Trigger button is the new feature I added to the level 2, it just has got box component with trigger enabled, rigibody and a RotatePathChange class script. it has been set up properly to enable paths and make certain block to rotate.


(Trigger button looks like in game)

All RotatePathChange holds references the pathes to enable, the block needed to change rotation, also few interpolation parameters, all it does is that when player enterd trigger area, it will calls a coroutine to slowing move down the block to make it visually applealing, also, a RoatePath uses DOTween Seqence to smoothly interpolate between angles.

RotatePathChange class code snippet shows as below:


Finally, the level 2 looks like following:



Adding third level.

Third level was inspired by one of levels from Monument Valley. Reference image can be found below:


I build a relatively simple level based on above reference and set up the Walkable component for each walking cube.

This level lets player manipulate some part of the geometries’ position rather than rotation found in level 1 and level2.

So that the condition to check would be a bit different than previous 2 levels, I called it sliding trigger in this level. CheckPathSlidingTrigger is the script I used in this level to enable and disable paths. This script relatively simple then previous two levels script, this script also derives from CheckForPathBase abstract class, which means this script must contains a method called CheckPath, then later I put this script into GameManager CheckForPathBase reference variable, then it will be called inside GameManager’s Update method. CheckPathSlidingTrigger only contains conditions to check and paths to enable and disable for different conditions, then in CheckPath method.

After CheckPathSlidingTrigger is created, I created an empty game object in the scene hierarchy, then attached CheckPathSlidingTrigger script to it, then filled up the CheckPathSlidingTrigger script’s variables and references in the inspector.


CheckPathSlidingTrigger class script code snippet can be seen below:


The control uses in this level also be a bit different when compare previous 2 levels, it changes two objects position at once, but only first object’s position were being restricted to the max and min value, this also has the effect on second object. OnMouseOver and OnMouseDrag were used to check if the game has paused, if yes, do not do anything, if no continue to check player finger touch on the screen, it checks the touch in 2 phases, first one is when player put their finger on the screen without moving, to set the originalY to that touch position, then it checks if the user moving their finger after first touch, then moved to Moved phase, in this phase, it stops player from moving if player is about to move from edge of the walking cube to the moving platform, then it do a calculation to only checks the y position of user’s finger movement, it first checks to see if differences in Y, then moving the object1 to the position, but move object2 to opposite position, also change selected object’s material to new one to indicate the moving is taking place. Then in the Update method, it checks to see if user has lifted their finger up, if yes, it then checks to see if the

Object’s position is a whole name, if not then it rounds the number up to down based on the decimal number. Then change the selected object’s mater back to normal to indicate the movement has completed.

VerticallySlidingControl class script code snippet shows as below:


Then later in the scene hierarchy, I created an Empty object named the same as the script, to attach the script component to it. Then filled up the relevant reference and value information.

This level also features button trigger, when place stand up on the trigger button, then the trigger button will be triggered. MovePathChange script is the one created specificly for this level, it uses OnTriggerEnter method to acts as a trigger button, since this trigger button only going to be triggered once by player. it has a member varibale called beenTriggered, which will be set to true once gets triggered, thus privent it from happending twice. When player first time entered this trigger button, beenTriggered boolean been set to true, and two coroutine method get called, SlowlyMove and MoveCubeInPlace. SlowlyMove just sink down the trigger button gradully by time specified in member varibale amountToMove. MoveCubeInPlace is a bit complext, which moves move all the obejcts in unitsToMove array one by one, each time index variable gets increased by 1, if the index is greater than or eaqual the the length of unitsToMove, paths will be enbale, if not it increase the index, then calls MoveCubeInPlace coroutine once again, then check the above condition again. At the end, it has a effect that trigger button gradullay sinked down, then each element in unitsToMove will gradullay move up one by one.

MovePathChange class script code snippet can be seen below:


Then I created a 3DBox gameobject named MoveTriggerButton, it has got Box Collider with trigger checkbox checked, rigibody used to enbale OnTriggerEnter method, and a MovePathChange script as component to this gameobject, then filled up required value and reference information, screenshot of MoveTrigerButton’s Inspector can be seen below.


Finally level 3 looks like following:



Simple level transition UI.

Since there are three levels in the game, I need to find a way to let user to make transition from one level to another level, so that I created a empty scene called LevelSelection, it is the level that will be first loaded to let user to choose which level they want to play. I then created a Canvas for inside this level then changed its UI Scale mode to “Scale with Screen size”, and set Reference resolution to 1080 and 1920, so that I will scale well even under different screen resolutions.


I then created a black panel with a vertical layout group component added, then I changed vertical layout group component’s child alignment method to Middle Center, which will help to automatically align child elements space out evenly. I then added three buttons underneath the black panel elements, they are named Level1, Level2 and Level3. I then created a simple LevelSelection, which have three public methods they are called LoadLevel1Scene, LoadLevel2Scene and LoadLevel3Scene, which then hooked into each button elment’s OnClick event. Which then will be trigger when the button gets clicked.


3 button UI elements shows in the scene hierarchy and in the actual game scene view


After level selection scene got created, then I move on to create in game menus. I first created an Overlay canvas first, named MainOverlayCanvas, then I changed its UI Scale mode to “Scale with Screen size”, and set Reference resolution to 1080 and 1920, also I changed Reference Pixels Per Unit to 256, so that it will be displayed and scaled well on different resolution mobile device. MainOverlayCanvas settings can be seen below.


I then added text element at fixed position on the screen to provide hint to player., for each level it will be different.


Afterwards, I created a Win UI panel with a text element to show which level they have completed, two buttons one is used to Load Next level, another one is used to let user click then back to menu. Back to menu button’s OnClick event were hooked to GameManager’s newly created method OnBackToLevelSelectionButtonClicked, Load Next Level button’s OnClick event were also hooked to GameManager’s newly created method OnLoadNextLevelButtonClicked.

Bottom methods can be seen below. Also, inside GameManager script, it has a member variable called nextLevelName, which will be filled in each level’s GameManager, so that one method can be reused in all levels.


Win panel looks like in Unity editor view.


After Win panel got created, I set it in a disabled mode, then I started to add the end point trigger area to each level’s end point. End point is a gameobject that has got capsule collider marked as trigger, a red material to show that it is a end point, and a rigidbody to let other object get into this gameobject and trigger the trigger event. Lastly, this end point gameobject been tagged as EndPoint. Then a EndPoint class script been added to player, which only contains a OnTriggerEnter method, that used to detect if player entered a tagged trigger gameobject “EndPoint”, if yes, then set the win panel to true.

End point class script code snippet.



(end point gameobject screenshot)

Moreover, I added a script called OnWinPanelActivate that attached to Win Panel, also a IsCurrentLevelFinished Boolean variable been created in GameManager, that used to tell game is ended. And the following code snippet were added to player’s update method and each level’s touch control script’s update method to prevent them doing anything if game is ended.


OnWinPanelActivate were used to create a fade in effect by setting its panel image component’s alpha value gradually towards 1, 1 means fully opaque. The OnWinPanelActivate’s code snippet shows as bellow.


After win panel has been created, then I started to create the in-game menu, that user can click, then it can take user back to menu or restart the current level.

I first created a Setting menu UI button, Settings panel that contains BackButton, BackToMenuButton and RestartLevelButton, BackToMenuPanel that contains text, BackToMenuNoButton and BackToMenuYesButton, RestartCurrentLevelPanel that contains text, RestartLevelNoButton, RestartLevelYesButton, all without functionalities. I named them in a way that by only look at it, it can tell what they were doing.


(Settings Panel looks like)



(Back to Menu panel looks like)


(RestartCurrentLevel panel looks like)


Frist, I created few reference variables that going to be filled inside GameManager’s inspector panel. They are follows.


also, a Boolean variable isGamePaused also gets created, that used to tell if game is paused if settings button gets pressed. Then inside player’s and each level’s touch scrip’ Update method, added the following check:



This will prevent player from moving and tries to manipulate the environment when game is paused.

Then I created few methods inside GameManager, that hooked into each button created above. Methods are shows as bellow, which basically just disable another panel or buttons to switch between different panels, and load level or restart level method for the restart level and back to menu buttons.

UI methods code snippet shows as below:


Lastly, I also added a panel contains a black image called GameStartPanel, that is full opaque, then put an script on it, called OnGameStartFadeIn, or it does, is that when game starts, it sets isGamePaused from GameManager to true, then gradually decrease its image’s alpha value to 0, then alpha value is 0, it turns isGamePasued to false, which means player can move.

OnGameStartFadeIn code can be seen below:


After UI got created, I started to drag it Prefab folder and turn it into Prefabs, in this way, each level can have it just by drag it out to the scene hierarchy, also in the future, when UI’s looking gets changed because of new UI sprite gets in, it will automatically update every scene, which saved a lot of time.


(MainOverlayCanvas sit on the Prefabs folder)


Following are the screenshots of newly created UI looks like in gameplay, and how they work.


(Level selection menu screenshot)


(settings button and onscreen hint text)


(Setting menu’s sub menu, first one is resume gameplay button, second one is back to menu button, third one is restart current level button, when any of them got pressed, settings menu will disappear, and sub menu will pop up if back to menu button or restart current level button got pressed)


(screenshot of restart level button got clicked, sub menu of restart level pop up, when no button got clicked, it returns to settings menu, when yes got pressed, it restarts the current level)


(screenshot of back to menu button got clicked, then sub menu of back to menu with yes or no pop up, then user click on no, it takes user back to settings menu, when yes gets pressed, it returns user back to menu scene)


Second testing

After three levels been build up, I started to do a first testing with team members, but only got two team members involved, they are James and Owen, other people just kept silent for some reason.

And the feedback I got from them were valuable as they found some bugs and giving suggestions how to future level layout would looks like.

The bugs they reported, and my fixes shows as follows:


  • · On the second level by accidently moving the blue platform as the player was getting on the same platform, player is able suspend in the mid-air.

To fix the above issues, I first added isEdge Boolean to the Walkable class, as name suggests, it is used to indicate if current Walkable cube is on the edge or not. Then I added the following code snippet to every level’s FingerDown method, because that is when user tries to change the alter the geometires player can move. The code below first checks to see if player is walking on the edge on any verge side of Walkable cube, by checking isEdge Boolean combined with walking Boolean from PlayerController class, if it yes, it prevents player from moving on then set player’s position to nearest Walkable cube.

Code snippet been put in every level’s touch control’s FingerDown method.


  • · Level 3’s touch sliding trigger were a bit hard to control.

So, I went back to Unity and change the sensitively setting then it worked fine as I asked them to test it again.

The suggestions they provided were add more models and textures from team members to decorate the scene to look better. So that I discuss with team members about the new assets, and ask them to provide me the new assets, so that I can put it into the game.


Decorate the scene

I and team members have lots of discussions over how the assets should look like in the game, and after the discussion they were able to provide me with the assets I want. New assets like Walking Cube, sci-fi towers, player character (without animation configured) etc. all with nice textures on them, new particles effects, which used to represent the end point, new UI sprites to replace the UI sprites I used from Unity built-in UI sprites. Since I made most of the objects in the scene into prefabs, so that, when updating the scene, I only need to place the prefab one, and it will automatically update the old one.

Following were the screenshots of levels looks like when new assets got putted in.


(Level 1)


(Level 2)


(Level 3)


(Back to menu button)



(restart level button)

I also created a very simple level 0 that used to show the optical illusion effect well as introduction level, it then been renamed to level 1 later, then all the levels were pushed backwards by 1 number, so total 4 levels:


(level 0, but later changed to level 1)

I also added UIMover script attached to hint text object, I then move the hint text object to centre of the screen, then made an empty target gameobejct to represent the end position, then the target gameobejct got assigned to the UIMover’s reference variable. In UIMover’s start method, a custom defined coroutine called MoveSelectedObject gets called, all this coroutine does is that does is that it first wait for specified time by the member variable timeToStayOnScreen, then gradually move the objectToMove object to the target location constrained by moveSpeed.


Following is the screenshot of UIMover’s component looks like in Unity editor’s inspector:


Also, I added loading bar between scene transitions, which enhanced the gameplay experience, so that player will not just see a black screen when during scene transition. I first created a slider UI gameobject, then change its UI sprite to the one created by James, then added a progress text in the middle to denote the progress, following is what the slider looks like in game:


After slider UI got created, I then developed a LevelLoader script and then created an empty gameobject in scene named LevelLoader as well, to attach this script to it, and modified all the load scene features in the game to use LevelLoader’s LoadLevel method, which takes in a level name to load, then change the slider value and progress as level is loading.


Lastly, as I got two spaceship assets from team members, I then decided to add random spaceship flying behind the scene into the game. I first created a empty gameobject with custom SpaceShipPatrolling script attached to it, then two different spaceships were added to as children to this gameobject.


(First space ship turned on )



(Second space ship turned on )

Both child gameobjects were turned off by default, then it is moved by the SpaceShipPatrolling script.

What SpaceShipPatrolling does is that has a timer and flap to tell when the count down should start, and if count down is finished or not. If count down reached zero, it first selects one space as active, then give it random starting point y to start with, then move it to the destination linearly by using DOTween’s sequence method, then a callback method were attached to the sequence when it is done to reset everything, then start it again.

SpaceShipPatrolling class script code snippet shows as bellow:



(Spaceship patrol settings)


Player animation

After I got player animations from one of my team member Sam, I started to configure the player animation. I first added an Animator component to player, then created an empty animator controller in Unity called Cosmo_Animator and assign this to Animator component on the player. Then I started to tweak Cosmo_Animator. The player has two animations, one is idle, and one is walking, I dragged both into Cosmo_Animator graph and set Idle one as default animation to play, then created a Boolean isRunning inside animator graph, and made a transition from Idle to Running when isRunning is true and set Has exit time to true. Then transition from running to idle when isRunning is equal to false and set Has exit time to false.


(transition settings from idle animation to running)


(transition settings from running animation to idle)

After animator grapha is set, then I go back to PlayerControll script, then add a reference Animator varibale, which will be set in the Unity by drag the Animator component from player components inspector to this field.

Then in the Update and FollowPath methods in Player, I added the folowing lines:


Since player’s walking member variable is already determine if player is walking not, I just set animator’s IsRunning variable to walking is they are different.

And finally, player animations have been set up.


Level 5 with enemies.

Now I started to make add one more level with enemies. I got inspiration from one of Monument Valley’s level. Screenshot shows as below:


I first try to build the level that looks like reference image above, then set up the Walkable paths for each walking cube. And put a simple red cube to represent the enemies, my level was a bit different than the one in the reference image, there only two rotatable moving platforms in my level, but in reference image’s level, it has rotatable moving platforms. Also, there are two enemies in this level, one just patrols around a set of paths back and forth, one patrolling around a flipable moving platform, last one patrolling around moving platform that go up and down. Following are the levels looks like after I builded the level:


(two sets of platforms, with darker colors, the one at the left side can be flipped upside down, one in the middle can go up and down)

Then I started to work on the path check system for this level, in this level, it has two set of paths to check, one is the flipable platform got flipped and another one can go up and down.

I then first try to work on the first flipable platform, this platform is bit different than before, it has got two same walkingcube put in the same place, one for each side, with different layer, one is FrontBlock and another one is BackBlock, as the name suggests, one is used when the platform is in upside down, one is used when platform is in normal angle, they having different offset value for walking, so that when player standing on top, it will be in the right position. See following two images for two walking cubes that are in the same position but with different layer.


(one moving platform’s walking cube with layer FrontBlock)


(one moving platform’s walking cube with layer BackBlock)

I created a script called CheckPathSpinningTriggerMultiple that derived from CheckForPathBase, it is very simple, inside its CheckPath method, it checks to see conditions set up in the top is fit or not, then it enables paths based on the condition. Also, it changes the player’s raycast down layer which used for detecting for which platform is underneath, and it changes the player’s mouseClick layer which used for user finger click on the platform, based on what angle the platform is, one setting of raycast down layer and mouseClick layer is just one with frontBlock enabled and backBlock disabled for testing, and another setting just with frontBlock disabled and backblock enabled.

Player’s raycast method for mouse click and raycast down were also changed to reflect the changes used in this level.

Raycast down method is as bellow:


Mouse click raycast method as below:


Following is the CheckPathSpinningTriggerMultiple script:


Then I created an empty gameobject in the scene named CheckPathSpinningTriggerMultiple (1) and attach CheckPathSpinningTriggerMultiple to it, then drag the this script to GameManager’s CheckForPathBase array’s first element, so that this scrip’s CheckPath method will be called in GameManager’s Update method.

After flipable platform check path is done, I started to make the check path system for platform that can go up and down, first two new Boolean variable gets created for this level called isInHighestSetting and isInLowestSetting, these two variables are used to tell if the platform is at the highest possible point or lowest point, it is used later for touch control system to determine Whether to continue up or lower the platform or go the opposite. I made a script called CheckPositionSpinningTrigger, it is also derived from CheckForPathBase, so it will have CheckPath method. All it does just enable or disable the path based on the position of the platform, and also set isInHighestSetting if the moving platform is at the highest possible position, set isInLowestSetting, if moving platform is in lowest possible position.

CheckPositionSpinningTrigger class script code snippet can be seen below:


After the script is created, I started to create an empty object in the scene, to hold this script, and set up the reference variables for this script, and drag and drop this script into GameManager’s CheckForPathBase array, so this script’s CheckPath script will be called in GameManager’s update method.

After two moving platform path control system got created, I started working on the enemies, but before I work on enemies, I started to add two new Booleans into Walkable class script, they are called isEnemyOnTop and isPlayerOnTop, they are used to tell if the enemy or player on top of the walking cube or not.

There are two types of enemies, one for flipable moving platform and normal enemy, and one for moving platform that can go up and down, enemies designed in this game will not harm the player, but instead, it just block player, to prevent player from moving on. I first created an EnemyPatrol script and EnemyCencor for flipable enemy patrol on moving platform and normal patrol enemy to use. EnemyPatrol is used for control enemy’s movement, it uses DoTween library to linearly move enemy around, and to resume movement if player not found or if it is in a rotating moving platform.

EnemeyCencor is used for detecting if player is within range of enemy, it uses OnTriggerEnter and OnTriggerStaymethod to tell if player is within range, then it uses OnTriggerExit to resume enemy back to patrol state after a short amount of delay declared in ResumeParentEnemyWalking coroutine’s wait time.it is then attached to enemy’s child gameobject with a box collider marked as trigger and a rigidbody, if it founds player, then it started to pause enemy movement, then when player gets out of range, it resumes enemy’s movement after few seconds.


(EnemeyCencor’s attached to a gameobject with Box Collider and Rigidbody on it to detect player)

EnemyPatrol class script code snippet shows as bellow:


EnemyCencor class script code snippet shows as below:


For the enemy patrolling around the moving platform which can move up and down, it needs a special script than the one used for normal enemy, I called this type of enemy AdvancedEnemy. Before I created the script for this AdvancedEnemy, I added method called CheckIfPlayerOnTop, that being called inside GameManager’s Update loop,which keeps track which walking cube is player on, and which cube is AdvancedEnemy sit on top, because there are more paths AdvancedEnemy can go to, than the normal enemy.

CheckIfPlayerOnTop method code snippet can be seen below:


For AdvancedEnemy, I created an AdvancedEnemy script and AdvancedEnemyCencor to get it function properly. The same traits between AdvancedEnemy and EnemyPatrol they both uses DOTween library to move enemy forth and back, but AdvancedEnemy is a bit more complex than normal EnemyPatrol script, as it needs to check if AdvancedEnemy is walking on the normal path or secret path, secret path being the paths located between the moving platform, if it is walking on a normal path and moving platform position gets change, and that the walking path for the enemy will be just the normal path part. But if AdvanedEnemy is walking on the secret path, then the moving platfotm’s position gets changed, then it will stay in that secret path.

AdvancedEnemyCencor works just like the normal EnemyCencor that attached to enemy’s child gameobject with trigger box collider and rigidbody to detect trigger events, but it is a lot simple than EnemyCencor, because most of the they are dealing with different moving platform.

AdvancedEnemy class script shows as bellow:


AdvancedEnemyCencor class script shows as bellow:


After all enemies and paths’ check were take care, then I started to work on the touch control for this level, I created an AdvancedTouchControl script to handle the touch controls. As there are two moving platforms in this level, one is flipable moving platform uses rotation axis x, and another moving platform uses position on y axis. I use swipe to rotate the flipable moving platform to next 180 degree on y axis, then based on what side the user is trying to swipe, the moving platform that use position will go up and down.

AdvancedTouchControl class script code snippet shows as bellow:


After AdvancedTouchControl script got created, I then created an empty gameobject with BoxCollider, rigidbody and AdvancedTouchControl attached to it, to enable the user able to wipe on mobile device.


(AdvancedTouchControl inspector settings)


Enemy character animation

As team member provide me with the enemy character, textures and its animation assets, I started to put the assets into the game.

Following is the enemy’s character I imported to unity with textures putted on:


There are only two types of enemy animations, patrol and attacking (attacking in this case means shocking the player, as this enemy will not really trying to attack the player, but to command player to move away).

Then I added Animator component to this enemy, then created animator controller for this enemy called Robot_Anim_Controller assigned to Animator’s controller reference field.

I then started to configure the Robot_Anim_Controller, I dragged two newly imported animations into the graph, then set patrol animation as default play animation. Then I created a Boolean variable called IsAttacking, it is the one used to decide which animation should be playing, the transition from enemy patrol to attack is when IsAttacking is equal to true and turned off Has Exit Time setting, so that I will transition to attacking animation immediately. The transition from attack to patrol is when IsAttacking is equal to false and Has Exit Time has check box has been turned off.


(Animator graph view)

(settings for transition from patrol to attack)

(settings for transition from attack to patrol)

After animator been set up, I started to program it to get it working.

I first created a public animato reference variable in both normal EnemyPatrol and AdvancedEnemy class script, but the core functionality was in the both enemy’s censor class scripts.

On both on trigger enter and on trigger exit methods at enemy censor component, following code snippet were added to change parent’s animator’s Boolean parameter, to make enemy transition from patrol to attacking.


Then in the at the ResumeParentEnemyWalking coroutine method, it then sets IsAttacking to false, to change the enemy’s back to patrol.


Following screenshot shows the final result:


(Enemies Patrolling around the scene)


Sound effects

Team members has contributed just enough sound effects to use inside the game, they are as following:

  • · Spaceship Passing By sound

  • · End Stage sound

  • · In Game Button Press sound

  • · Menu Button Press sound

  • · Robot Alarm sound

  • · Spaceman Walking sound

  • · Enemy Attack Sound

  • · Menu background Sound

  • · Gameplay background Sound

I first created a script called AudioManager, it uses pure singleton design pattern to persist between scenes without worrying about duplicates, as to prevent sound from cut off between sound transitions. Also, I created an Empty class in the first scene to hold this AudioManager script, so that it can be persist between scenes.

I the created a separate class called Sound that has an attribute of System.Serializable so that it can be displayed in Unity’s inspector. Sound class just a data structure that hold data information of the clip, like name, volume, pitch, isLooping and actual audioSource, as audioSource is the plays the sound. AudiosManager holds a public array of Sound called Sounds, which then later been filled up with sounds with different settings in the Unity’s Inspector, see below example sounds and their attributes:


After sounds been assigned in the Unity’s inspector, it then got initialised by creating a separate AudioSource for each sound, so that they can be controlled differently, also each sound uses settings filled up in Unity’s inspector. There are four helper methods created in AudioManager, they are PlayMenuBGSound, PlayGameplayBGSound, PlaySound and StopPlaySound. PlayMenuBGSound just simply start playing menu background sound but also disable playing game play sound, PlayGameplayBGSound did the opposite. PlaySound is a method that takes in a name of the sound to play, so does StopPlaySound takes in a name of sound to stop playing.

AudioManager class script shows as below:


After AudioManager got created, I then started to use it to play sounds, with a simple call, for example, it works fine for playing simple one-shot sound, like the code shows below:


But for menu looping sound, gameplay looping sound and player steps sound, it will not work.

For playing menu looping sound, I created an simple script called PlayMenuBGSound that attached to an empty game object in menu scene, with just few lines code, to that it will play when the menu scene loads,

PlayMenuBGSound code shows below,



For the gameplay sound, I did the same logic, I created a script called PlayGameplayBGSound that attached to an empty gameobject in each level, so that when that each level scene plays, it plays the gameplay sound.

PlayGameplayBGSound code snippet shows as below:



But for player walking sound, I did it differently, I first duplicate the original spaceman walking sound provided by team member, so that I always have a copy of it.

I extracted single step sounds from walking sequence of steps sound using Audacity software. I first by click and select only small portion of sound from the whole sound effect, then hit play, to hear only that part of sound effect, I do this so many times just to find out which one is better, Once I found it, I started select the rest of the sound then delete them, so at the end only the selected sound were remaining, then I hit export the sound as WAV at the end. Audacity is doing good in this case, because sometimes I deleted some of the part what wasn’t meant to be deleted, I can always go back and undo the action.


(I play around in Audacity)

At the end, I extracted 3 single step sounds from original spaceman walking sound, then hooked all them up into AudioManager class script.


(3 steps sound extracted from Audacity)

I then created an PlayStepSound method in PlayerMesh script, which just randomly pick a single step sound from the three to play.

PlayStepSound method code snippet shows as bellow:


This method then get called from Animation Events in player walking animation, at beginner frame, middle frame and end frame of walking animations, I hooked up the method PlayStepSound into it. In this way, the walking sound will gets played automatically when the specified animation frame reached.


(Add PlayStepSound method to play in walking animation)

At the end, I have a working sound system for the game.


Adding more assets from team members, to decorate the scene

In this part, I applied all the assets from team members into the game.

Player model’s textures been added, following is what the player looks like after textures been applied:


Then I started to add Post processing effects to the game, to make game looks good,

I install the postprocessing effect from Package manager.


(install post processing to the game)

Then I created a Postprocessing profile called Main Post Processing Profile, which will be used in every scene.


(Main Post Processing Profile created for the game)

Then I created an empty gameobject called PostProcessing Global, then added PostProcessing Volume component to it, also assign the Main Post-Processing Profile created earlier to it. then I also created a new Layer called Post Processing Layer assign to this newly created gameobject.

Then I added a Post Processing Layer to the main camera, set its affect Layer to PostProcessing Layer.


(Post-process Layer setting)

After everything has set up, I then only add a simple bool effect to the Post Processing Global because this game is targeting mobile device, I, with Intensity set to 7, threshold to 1, Anamorphic ratio to 1 and fast mode to 1. All this setting will add a little bit of bloom to the game. I then repeat the process of adding post processing for all every level.


(Bloom post processing effect setting)


I added 3D set of space station model from team members to make a proper menu scene and level selection.Following are the looking of the models:


(menu scene)


(level selection scene)

I place the camera near to the model, so that the space station model filled up the almost entire scene view. I then added a simple Rotator Script to each of the model, what this script does, is that it will rotate the attached model gameobject rotate around the y axis back and forth, created a sense of dynamic to the game.

Rotator class script code snippet shows as follows:


In addition to rotating space station models for each level, I also updated the UI used in menu scene and level selection scene, following is the final looking of menu scene and level selection scene:


(menu scene)



(level selection scene)

Since our game has 5 levels so far, I decided to ask for team members to provide me with different colour of models to be used in different level, by using different colours for each level, it makes a sense of progression for the player, and more pleasing to their eyes. Also, I added models from team members to further decorate the scene. Moreover, I added the background particle effects to the game for decorate the scene even more. Following are screenshots of level 1 to level 5 scene looks like:


(level 1)

(level 2)

(level 3)

(level 4)

(level 5)


Final testing and fix bugs.

After game has been produced, I started to ask team members to test the game once again. This game all the team members has participated and were able to provide feedback from little to details.

Every people tested the game were like the games, but there are some minor bugs still presented in the game, their fixes are also presented:

1. The running animation were a little off, it takes time to see the player turn into running animation.

To fix the problem, I changed the settings from idle animation transition to running animation I changed transition duration and transition offset value from transition duration 0.25 to 0.169, transition offset from 0 to 0.265 and interruption source from none to next state. By doing this, the problem was fixed, because it changed when, how and what frame to be played first from idle to running animation, follow are the screenshot of the settings been changed:


After the change, I asked them to test the game, and it works fine.

2. Fourth level’s control not working at all

This problem is different from phones to phones, as most people do not have this problem, but it happens in one of team members’ phone what I have done is that I changed touch control’s layer to custom layer called TouchSlidingControl, and put it to render under out most camera, so that it will always be on top of everything.


(change layer of TouchSlidingControl to TouchSlidingControl)

(Add TouchSlidingControl to Outmost camera)

3. in level 5, as level is bigger, player at level 5 were cut off

Most people in the team does not have this problem that is because they all using somewhat bigger phone with bigger resolution, but the team member who had this problem were using a small size phone with lower resolution, to fix this, I added the following code to the Awake method of GameManager, which grabs all the cameras first, and checks to see if the user’ screen resolution is small than the target resolution or not, if yes, than all cameras’ view size were increased to 19.

Following is the code snippet used in GameManager’s awake method:

After retest the game with this team member, I was able to solve the problem.

4.1. Spaceship were flying backwards

This is the problem due to not rotate the spaceship to the right angle, so I just flip the angle on y axis, and the works at the end

After all the bugs got fixed, everyone was happy about this final game we were producing.

Comments


Site Last Updated: 30/04/2020

All copy rights and trademarks are a property of Game Ready Studios and their respected members. Please ask permission before using any of our original work.

©2019 by Samantha Richardson. Proudly created with Wix.com and powered by Star Dust

bottom of page