https://www.youtube.com/watch?v=ogz-3r0EHKM&ab_channel=JelleVermandere
General
- To download packages in Window » Package Manager, check that "show preview packages" is selected
- Always make changes in Scene with the gameplay stopped, never in Game with it active, or they will be lost
- Saving Scene makes it appear in the assets. Double clicking loads respective scene.
- Add Scenes to BuildSettings: File » Build Settings » Add Open Scenes to add all we have » Select them
- Everything that is common in multiple scenes should be a prefab, so that changing one has repercussions in all uses. Ex: Camera, Player, GameManager... That, before duplicating the scene or creating new ones
- Shortcuts Q, W, R, T: to Grab, Rotate, Scale and All at the same time
- To view from top or sides, we can click on the axis. For a isometric view, we can click on the cube at the center.
- To add object to scene, go to Hierarchy » right click and add object we want
- To focus view on object, select object in Hierarchy » hit F
- To center object in scene, go to Transform panel at the right » right click word» select Reset
- To assign materials to objects: Assets » right click + Create + Material » change Inspector properties » drag it to object we want to tint
- Ensure that objects have a Box Collider checked in the Inspector unless we want things to go through. Also, there are types of colliders more appropriate for other objects, ex: a Sphere object should have a Sphere Collider (just search "sphere" in Add Component), to make sure you switch to the more appropriate component.
- Ensure that objects have a Mesh Renderer checked in the Inspector unless we want them invisible
- Add physics to object: select object in Hierarchy » Inspector » Add Component » Physics » Ex: Rigidbody (btw, bigger objects probably should have higher Mass)
- Add Tags: Inspector » selected Untagged under object name » Add Tag » create tag » change tag of our object with the one we created
- When we change something in a prefab object, under assets, and want it to be applied to other objects created from the same prefab, we have to hit Apply.
- To select objects but not the platform/ground/wtv from the top or smt, we can disable selection by: selecting Ground » Add Layer (under name in Inspector) » create smt like Environment » assign layer we created as the ground layer » go to the Layers toggle (on top of Inspector) » click to lock the layer we created
- Make objects snap to grid (usually from top or side view): Edit » Snap Settings » move objects while holding Ctrl will make it snap according to the number of units we specified in the settings
Scripts - and some utilities with them
- To add script to object: Select Object » Inspector » Add Component » New Script » name it and keep C# » Create and Add » double click it to open in editor. We can add script to object by dragging it from the assets to the top of the object
- Debug: In the Start Function of the scripts, use Debug.Log("msg"); » Check what appears in console when running game
- Reference components in scripts and change properties: public/private ComponentName varName » varName will appear listed in the script component, and we can drag a component (of the right type) to its slot to finish the reference » To change a property, we write varName.property = value;
- Ex: public Rigidbody rb; » drag respective component to script slot in inspector; » rb.useGravity = false; (in the component, the property was named Use Gravity)
- or rb.AddForce(); By the way, with Force it may be better to restrict rotation constraints in the Rigidbody component. Or we can add a created PhysicsMaterial to our ground and set the frictions to 0 to avoid rotation when collision occurs and ensure slipping.
- Update function in scripts runs once per frame - meaning it gives differents results depending on how many frames each computer runs on. Some things, like the force, can be multiplied by Time.deltaTime. We should also change name to FixedUpdate.
- Obtain user input (usually inside if statements or such):
- in the script, write Input.GetKey("d");
- D is for positive x force and A is for negative.
- Instead of just adding a force with x,y,z, we shouls make it respond better to input by adding a fourth parameter, ForceMode.VelocityChange. That required higher force values (to the sides) and feels better with Drag(in RigidBody) as 1, not 0.
- Make Camera follow player:
- One way: in Hierarchy, drag Camera to inside/under Player object to create parenting and inherit movement script. That's a problem when player rotates tho, because it would rotate as well and that might not be the desired effect.
- Other way: Add to camera a script FollowPlayer, with a var Transform player that references player and in the update, write transform.position = player.position + offset; (transform.position is the position of the camera, not the player, because transform not capitalized refers to script's object)(offset is a Vector3 var whose values we set in the Inspector, so that camera is not inside player)(dont forget to reference the Player)
- Actions when collision occurs:
- create script » create function void OnCollisionEnter(Collision collisionInfo) » use the collisionInfo.collider.name or collisionInfo.collider.tag to know what we accessed and add an action
- It's better practice to detect objects by tags. To add Tags, see General
- When we lose, we probably want to disable player movement. So we create a variable to store that component, PlayerMovement movement and then set movement.enable = false;
- To make the collision be better detected, which is important if we want accurate scores, we should go to RigidBody » Collision Detection » change Discrete to Continuous. That for both the obstacle and the player or wtv collides
- Make UI change dynamically:
- import: using UnityEngine.UI;
- create var to change the Text: public Text text;
- update var: scoreText.text = "..." (we could change other things as well)
- GameManager to manage the game states - the player, who can die, doesn't have that responsibility:
- It should also be a prefab. Along with the player and everything that is common between scenes
- create EmptyObject and rename it (+ reset transform) » create script GameManager responsible for managing the states of the game
- add a EndGame() method to the script
- add a bool gameHasEnded = false; at the start, and set it to true inside method EndGame() inside a if (gameHasEnded == false). The if prevents game from "ending multiple times".
- add a Restart() method » import using UnityEngine.SceneManagement » inside method, write SceneManager.LoadScene(SceneManager.GetActiveScene().name OR .buildIndex); » call method inside the if from EndGame(), as Invoke("Restart", delayVar); (it's not called as Restart() because we want delay, and delay is a var to be adjusted in Inspector)
- add a LevelWon() method » create a var GameObject winnersUi, that is initially disabled besides the name, and reference it » inside method, call winnersUi.setActive(true)
- Time to call method to end: To reference GameManager, we could create a reference usually inside the player, but it would be reset if player died. Instead, we should search for it: FindObjectOfType<GameManager>().ourFunctionFromThatScript();
- To call LevelWon(), do it normally inside the OnTriggerEnter() created next
- Create a Trigger area, to end the game or start a cutscene or wtv: Create an object that covers the area » disable rendering to make it invisible » for dev to know the object is there, select a color icon besides the name in the Inspector » check Is Trigger in the Box Collider » add a script with a function OnTriggerEnter() » reference the GameManager normally » call wtv we want inside from the GameManager
- For Buttons, scripts are added in OnClick() events » then we reference object that has script » and select the method
UI
- Go to Hierarchy » Create » UI » Text
- To see it: change view to 2D » select objects in Hierarchy » hit F
- move text to inside the canvas » center it and customize it
- avoid trimming if text reaches boundaries: select Text object » Horizontal Overflow » Overflow
- make canvas resize with screen size: select Canvas object » Canvas Scaler » UI Scale Mode » Scale with Screen Size
- unfocused or unsharpened?: Canvas » check Pixel Perfect
- download a new font (ex: Roboto): download zip from google fonts » extract » move it to a folder in the assets » select Text » change font for one we imported
- background that fits the screen: create a Panel inside the Canvas » change Source Image to None if we want a solid color » add Text inside
- add Animation: see animations
- See how to make it change dynamically in Scripts
Terrain
- How to create:
- On Scene, we can Create 3D Object » Terrain.
- Alternatively, we can go to Window » Terrain » Terrain Toolbox » Create, which allows us to create terrains with specific settings and is better to work with several terrains at once. We can place it next to other windows.
- We can also create a base from a heightmap.raw image, that we import to our assets » Terrain Toolbox » check Import Heightmap » select image and maybe change the resolution and dimensions » ensure it doesn't have the same Group ID as other terrains » Create.
- We will have a Terrain Folder with a terrain inside, in the assets
- Disable fog at the top to see things better, we can enable it later. Also go to lighting window and TURN OFF AUTO generated lighting!!!!!! (or reloading scenes will look weird)
- Go to Window » Package Manager » Make sure "All Packages" and "Show preview Packages" are checked » search and download Terrain Tools
- Go to Asset Store » search, download and import Terrain Sample Assets » We will see everything under Samples folder assets. Optional but useful and recommended assets:
- Outdoor Ground Textures
- Flooded Grounds
- For trees: Conifers
- Grass Flowers Pack Free
- Stylized Nature Pack (used for "The First Tree")
- Fantasy Skybox
- Some people, before starting painting terrain, go to Inspector » Terrain Settings (last icon) and make it bigger, downsizing when they are finished. Don't forget to use the Terrain Toolbox do to it in multiple terrains. In the Terrain Settings, we can also hide things like trees if we need by uncheking "Draw" in the details section.
- It's useful to place a character or a cube for size reference.
- To start painting, go to Inspector » Select painting brush icon » Then select our paint mode (like "Raise or lower terrain") and paint. Suggestions: Noise, scaled to something bigger like 20x20, looks really cool. Shortcuts:
- Ctrl is used to invert (either reverse the effect of the brush or delete)
- S scales brush.
- A changes strength of the brush
- To create neighbour terrains, in the first icon of the inspector, we can click on what neighbor terrains we want. Make sure they have the same Group ID, otherwise we can sculpt multiple terrains at the same time. They also need the same resolution.
- To paint, as in actual colors, we go back to Inspector » Paint mode » Create/Add Layer. To Create » Select texture, like dirt » rename the asset. It is a good idea to import the normal and mask map for that layer, which usually are textures in from of the one we chose. Increasing tile size looks better. To Add » import one from the sample assets, like moss.
- To add trees, to to the Tree icon » Add Tree » Chose prefab from assets » change brush settings to affect area or add more trees per stroke or wtv. To remove a specific tree, use Ctrl and a small brush size and delete, making sure the corresponding prefab in the list of trees is selected or nothing will happen.
- For grass, it's the same as with the trees. Don't forget we can edit the chosen prefab like the colors and height. We can chose prefabs for texture grass or detail mesh grass. To add detail Mesh, we can use some from the asset store like Flooded Grounds. It works the same way as with prefabs, but it's more detailed and less optimized.
Post Effects and Post Processing
- Object properties, materials, shaders...:
- Obvs organize the assets
- To create, go to Assets (top) » Create » Material. Change properties, can be a texture
- Popular shaders (picked on the top of the sidebar for material): Standard, Legacy Diffuse(evenly distributed), Legacy Specular.
- Popular shaders imported: Skybox (recommended from the start), Joepie (stylized, wobble), MirrorReflection(load heavy), Screenspace (cute stylized patterns)
- Recs:
- How to treat mmd characters: see blender post
- Fog https://www.youtube.com/watch?v=1ZsKBZnbAB8
- water https://www.youtube.com/watch?v=mWg4CE6ybKE
- Lights:
- Inspector » Main Camera » Layer UI to Post Processing
- Chose Directional Lights in the Scene and edit it » Maybe decrease intensity
- Go to the Lighting Window (Window » Rendering » Lighting) » Environment (top) » replace the Skybox material for Sky or smt, maybe even Solid Color » Scene (top) » check the new settings » uncheck Baked Global Illumination » Generate » Shader of Sky with less exposure » check Fog
- Lighting Window (Window » Rendering » Lighting) » Environment (top) » Environment Reflections» change to Custom » set cubemap to a white image marked in the inspector as Cube in the texture shape https://www.youtube.com/watch?v=XatLA5SGgAs
- Main Camera object
- check Post-Processing Volume box!!! » thinker with Ambient Occlusion vars
- in Light area, change Flare to Sun
- in the camera Inspector » Rendering Path to Forward
- in the Color Grading of the Inspector » Mode to ACES
- in the Bloom area of Inspector » check and change vars, in particular Threshold » maybe that will require to play with the Shader of the Sky in the light Environment and keep changing the Color Grading
- Add Effect » Vignette
- Add Effect » Chromatic Ab
Animations
- Window » Animation (not Animator! it allows to transition and play animations, not create them)
- Create Animation and save it inside folder
- In the assets, select animation itself (what shows first) » disable Loop Time for it to just play once
- In Record Mode, gameplay icons are red and recording is shown with red circle
- Add key frames for what we want - they are the icons with a losango
- We can add Animation Events to later trigger other actions - we just select the timeframe and click the icon besides the keyframe
- We could add a function to it. We can also create a script belonging to what we are animating, with a function inside, and add that function to the event.