recursal/Fanatic-Fandom huggingface dataset:
Pausing Timeline audio

Audio played from Unity Timelines does not get paused when an AC game is paused. This component can be used to pause it manually, as well as update its volume to AC Options values.

To use it:

1. Paste the script below into a new C# file named TimelineAudioPauser.cs
2. Attach the new Timeline Audio Pauser component to the Playable Director that is controlling the Timeline
3. In the component's Inspector, set the "Sound Type" as well as the "Track Index" to control. Note that regular tracks start from index=1, with index=0 being reserved for events.

TimelineAudioPauser.cs:

```
using UnityEngine;

using UnityEngine.Timeline;

using UnityEngine.Playables;

using AC;

public class TimelineAudioPauser : MonoBehaviour

{

	[SerializeField] private SoundType soundType;

	[SerializeField] private int trackIndex = 1;

	private AudioSource audioSource;

	private PlayableDirector director;

	private AudioTrack audioTrack;

	private double pausedTime;

	private void Awake ()

	{

		director = GetComponent <PlayableDirector>();

		audioTrack = (director.playableAsset as TimelineAsset).GetOutputTrack (trackIndex) as AudioTrack;

	}

	private void OnEnable ()

	{

		EventManager.OnChangeVolume += OnChangeVolume;

		EventManager.OnInitialiseScene += OnInitialiseScene;

		EventManager.OnEnterGameState += OnEnterGameState;

		EventManager.OnExitGameState += OnExitGameState;

	}

	private void OnDisable ()

	{

		EventManager.OnChangeVolume -= OnChangeVolume;

		EventManager.OnInitialiseScene -= OnInitialiseScene;

		EventManager.OnEnterGameState += OnEnterGameState;

		EventManager.OnExitGameState += OnExitGameState;

	}

	private void OnInitialiseScene ()

	{

		OnChangeVolume (soundType, GetDesiredVolume ());

	}

	private void OnChangeVolume (SoundType soundType, float volume)

	{

		if (this.soundType == soundType)

		{

			audioTrack.CreateCurves ("nameOfAnimationClip");

			audioTrack.curves.SetCurve (string.Empty, typeof (AudioTrack), "volume", AnimationCurve.Linear (0f, volume, 1f, volume));

		}

	}

	private void OnEnterGameState (GameState gameState)

	{

		if (gameState == GameState.Paused)

		{

			if (director && director.state == PlayState.Playing)

			{

				audioSource = director.GetGenericBinding (audioTrack) as AudioSource;

				audioSource.volume = 0;

				pausedTime = director.time;

			}

		}

	}

	private void OnExitGameState (GameState gameState)

	{

		if (gameState == GameState.Paused)

		{

			if (director && director.state == PlayState.Playing)

			{

				director.time = pausedTime;

				audioSource.volume = 1;

			}

		}

	}

	private float GetDesiredVolume ()

	{

		switch (soundType)

		{

			case SoundType.Music:

				return Options.GetMusicVolume ();

			case SoundType.Speech:

				return Options.GetSpeechVolume ();

			case SoundType.SFX:

				return Options.GetSFXVolume ();

			default:

				return 1f;

		}

	}

}

```
Auto-transfer items to Containers

By default, clicking items in the Player's inventory, inside the Container menu, will select them - allowing the Player to then click inside the ContainerItems element to transfer them.

This script automates the process, so that clicking such items moves them to the Container instantly.

To use it:

* Copy/paste the code below into a new C# script named AutoTransferToContainer.cs
* Attach the script as a new component in the scene (or, if using Unity UI, to the UI prefab's root)
* Fill in the Inspector's fields with details of the elements involved. Default values are set to match the default Container menu
* In the Menu Manager, select the PlayerInventory element of the Container menu, and check "Prevent selection?"

```
using UnityEngine;
using AC;

public class AutoTransferToContainer : MonoBehaviour
{

 public string menuName = "Container";
 public string inventoryBoxName = "PlayerInventory";
 public string containerElementName = "ContainerItems";

 private void OnEnable () { EventManager.OnMenuElementClick += OnMenuElementClick; }
 private void OnDisable () { EventManager.OnMenuElementClick -= OnMenuElementClick; }

 private void OnMenuElementClick (Menu menu, MenuElement element, int slot, int buttonPressed)
 {
 if (menu.title == menuName && element.title == inventoryBoxName)
 {
 MenuInventoryBox inventoryBox = element as MenuInventoryBox;
 MenuInventoryBox containerBox = !string.IsNullOrEmpty (containerElementName) ? menu.GetElementWithName (containerElementName) as MenuInventoryBox : null;

 Container container = (containerBox != null && containerBox.OverrideContainer) ? containerBox.OverrideContainer : KickStarter.playerInput.activeContainer;
 if (container == null) return;

 InvInstance clickedInstance = inventoryBox.GetInstance (slot);
 container.Add (clickedInstance);
 }
 }

}

```
Link an Animator parameter to a Variable

**NOTE: This script is included in AC v1.74.0 and later.**

This script allows you to sync up an Animator parameter's value with an AC component variable. To use it:

1. Attach a Variables component to the Animator, and define a Bool, Integer, or Float parameter that matches the name of the Animator parameter you want to sync with.
2. Set its Link to field to Custom Script
3. Place the script below into a C# file named AnimatorParameterLink.cs
4. Add the component Animator Parameter Variable Link to your Animator component
5. In the component's Inspector, enter the name of the variable/parameter into the "Shared Variable Name" field. If the parameter is only intended to be read - and not set via the variable's value - check "Download Only".

AnimatorParameterLink.cs:

```
using UnityEngine;
using AC;

public class AnimatorParameterLink : MonoBehaviour
{

 public string sharedVariableName;
 public bool downloadOnly;
 private Variables variables;
 private Animator \_animator;

 private void OnEnable()
 {
 variables = GetComponent <Variables>();
 \_animator = GetComponent <Animator>();

 EventManager.OnDownloadVariable += OnDownload;
 EventManager.OnUploadVariable += OnUpload;
 }

 private void OnDisable()
 {
 EventManager.OnDownloadVariable -= OnDownload;
 EventManager.OnUploadVariable -= OnUpload;
 }

 private void OnDownload (GVar variable, Variables variables)
 {
 {
 return;
 }

 if (this.variables == variables && variable.label == sharedVariableName)
 {
 switch (variable.type)
 {
 case VariableType.Boolean:
 variable.BooleanValue = \_animator.GetBool (sharedVariableName);
 break;

 case VariableType.Integer:
 variable.IntegerValue = \_animator.GetInteger (sharedVariableName);
 break;

 case VariableType.Float:
 variable.FloatValue = \_animator.GetFloat (sharedVariableName);
 break;

 default:
 break;
 }
 }
 }

 private void OnUpload (GVar variable, Variables variables)
 {
 {
 return;
 }

 if (this.variables == variables && variable.label == sharedVariableName)
 {
 switch (variable.type)
 {
 case VariableType.Boolean:
 \_animator.SetBool (sharedVariableName, variable.BooleanValue);
 break;

 case VariableType.Integer:
 \_animator.SetInteger (sharedVariableName, variable.IntegerValue);
 break;

 case VariableType.Float:
 \_animator.SetFloat (sharedVariableName, variable.FloatValue);
 break;

 default:
 break;
 }

 }

 }

}

```
Make a 2D camera follow the mouse

A "GameCamera 2D" camera type follows the player character by default, but it can be made to follow the cursor instead with a simple script.

1. Create a C# script named FollowCursor.cs, and paste the contents of the script below into it
2. Create a new GameObject in your scene named "CursorReference"
3. Attach the new FollowCursor component to the CursorReference GameObject
4. In your GameCamera 2D, uncheck Target is Player? and assign CursorReference in the new Target field

FollowCursor.cs:

```
using UnityEngine;
using System.Collections;
using AC;

public class FollowCursor : MonoBehaviour
{

    private void Update ()
    {
        Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
        mouseWorldPosition.z = 0f;
        transform.position = mouseWorldPosition;
    }

}

```
Anima2D and sorting maps

Characters can use Unity's Anima2D asset if they rely on AC's Sprite Unity Complex animation engine, and have the following hierarchy:

* <Root object>
* --- <Sprite child>
* --- --- <Anima2D Sprite Mesh tree>
* --- --- <Anima2D Rig tree>

However, an extra script is necessary to have them work with AC's Sorting Maps, as Anima2D relies on its own Renderer to draw its sprites.

Attach a **FollowSortingMap** component as normal, and then add a "blank" SpriteMeshRenderer component that has no sprite, but will be updated by the **FollowSortingMap** component at runtime. Then attach the following script and assign the fields. This script will transfer the SpriteMeshRenderer's **Sorting Order** and **Order In Layer** fields into the Anima2D SpriteMeshInstance.

```
using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Anima2D;

public class CopySpriteOrder : MonoBehaviour

{

	[SerializeField] private SpriteMeshInstance spriteMeshInstanceToUpdate;

	[SerializeField] private SpriteRenderer spriteRendererToCopy;

	void Update ()

	{

		spriteMeshInstanceToUpdate.sortingLayerName = spriteRendererToCopy.sortingLayerName;

		spriteMeshInstanceToUpdate.sortingOrder = spriteRendererToCopy.sortingOrder;

	}

}

```
Grab a draggable without holding down input

As of AC v1.74.0, draggable objects can be manually picked up and dropped.  This script demonstrates this by allowing draggables to be picked up with a single press of the "1" key, and dropped with a press of the "2" key.

To use it:

1. Create a new C# file named ForceGrab.cs and paste in the code below
2. Add a GameObject to the scene and attach the Force Grab component
3. Press "1" when the mouse is over a draggable object to grab it, and "2" to drop it

ForceGrab.cs:

```
using UnityEngine;
using AC;

[DefaultExecutionOrder (100)]
public class ForceGrab : MonoBehaviour
{

 private DragBase dragBase;
 private HeldObjectData heldObjectData = null;
 private Vector3 lastMousePosition;

 private void OnEnable ()
 {
 dragBase = GetComponent<DragBase> ();
 EventManager.OnGrabMoveable += OnGrabMoveable;
 EventManager.OnDropMoveable += OnDropMoveable;
 }

 private void OnDisable ()
 {
 EventManager.OnGrabMoveable -= OnGrabMoveable;
 EventManager.OnDropMoveable -= OnDropMoveable;
 }

 private void Update ()
 {
 if (Input.GetKeyDown (KeyCode.Alpha1) && heldObjectData == null)
 {
 dragBase.Grab (dragBase.transform.position + Vector3.one);
 }
 else if (Input.GetKeyDown (KeyCode.Alpha2) && heldObjectData != null)
 {
 dragBase.LetGo ();
 }

 if (heldObjectData != null)
 {
 Vector2 deltaDragMouse = (Input.mousePosition - lastMousePosition) / Time.deltaTime;
 heldObjectData.Drag (Vector3.zero, deltaDragMouse, Input.mousePosition);
 }

 lastMousePosition = Input.mousePosition;
 }

 private void OnGrabMoveable (DragBase dragBase)
 {
 if (this.dragBase == dragBase)
 {
 heldObjectData = KickStarter.playerInput.GetHeldObjectData (dragBase);
 heldObjectData.IgnoreDragState = true;
 heldObjectData.IgnoreBuiltInDragInput = true;
 }
 }

 private void OnDropMoveable (DragBase dragBase)
 {
 if (this.dragBase == dragBase)
 {
 heldObjectData = null;
 }
 }

}

```
Change movement method dynamically

This script can be used to switch the game's "Movement method" between "Direct" and "Point And Click", based on the last input.

To use it:

1. Create a new C# file named DynamicMovement.cs and paste in the code below
2. Create a new GameObject in the scene and attach the new Dynamic Movement component
3. When a keyboard key is pressed, the game will switch to Direct movement. When the mouse is pressed, it will switch to Point And Click
4. (Optional) The script's SetMovementMethod function can be modified to run any additional desired code at the time such a switch occurs

```
using UnityEngine;
using AC;

public class DynamicMovement : MonoBehaviour
{

 [SerializeField] private MovementMethod defaultMovementMethod;

 private void Start ()
 {
 SetMovementMethod (defaultMovementMethod, true);
 }

 private void Update ()
 {
 if (Input.anyKeyDown)
 {
 {
 SetMovementMethod (MovementMethod.PointAndClick);
 }
 else
 {
 SetMovementMethod (MovementMethod.Direct);
 }
 }
 }

 private void SetMovementMethod (MovementMethod movementMethod, bool force = false)
 {
 if (KickStarter.settingsManager.movementMethod != movementMethod || force)
 {
 KickStarter.settingsManager.movementMethod = movementMethod;

 switch (movementMethod)
 {
 case MovementMethod.Direct:
 KickStarter.player.EndPath ();
 break;

 default:
 break;
 }
 }
 }

}

```
CNControls Integration (Virtual Joystick)

**NOTE: CN Controls has been deprecated - a similar script that works with Simple Touch Controller can be found here.**

 This script allows you to integrate the free CN Controls asset to AC.

Same as Rewired's integration, attach the script to any active object in the hierarchy, which you know is always going to exist on every scene, or which doesn't get destroyed on loading (You may also put it on the AC PersistentEngine or GameEngine prefabs). Also, make sure CN Controls' Virtual Joystick is using "Vertical" and "Horizontal" as the input names.

```
using UnityEngine;

using CnControls;

public class ACInputCNControls : MonoBehaviour

{

  void Start()

  {

    //Call AC delegate for the joystick Axis

    AC.KickStarter.playerInput.InputGetAxisDelegate = CustomGetAxis;

  }

  private float CustomGetAxis(string AxisName)

  {

    //get the axis from CNControls' joystick

    return CnInputManager.GetAxis(AxisName);

  }

}

```
Hold input to flash Hotspots

The "FlashHotspots" input button can be used to flash up Hotspot highlight effects to reveal their location. However, this only works for the moment the input button is first pressed. The following script allows you to instead highlight Hotspots for the entire duration an input button is held down.

To use it:

1. Define an input button in Unity's Input Manager named "FlashHold". This can replace the existing "FlashHotspots" input, if defined.
2. Create a new C# script named HoldToFlash.cs, and paste the code below into it
3. Attach the new Flash To Hold component to an empty GameObject in the scene

HoldToFlash.cs:

```
using UnityEngine;
using AC;

public class HoldToFlash : MonoBehaviour
{

 public string inputName = "FlashHold";

 private void Update ()
 {
 if (KickStarter.stateHandler.IsInGameplay () && KickStarter.playerInput.InputGetButton (inputName))
 {
 FlashHotspots ();
 }
 else
 {
 FlashHotspots (true);
 }
 }

 private void FlashHotspots (bool cancel = false)
 {
 foreach (Hotspot hotspot in KickStarter.stateHandler.Hotspots)
 {
 if (hotspot.highlight)
 {
 if (cancel)
 {
 hotspot.highlight.CancelFlash ();
 }
 else if (hotspot.IsOn () && hotspot.PlayerIsWithinBoundary () && hotspot != KickStarter.playerInteraction.GetActiveHotspot ())
 {
 hotspot.highlight.flashHoldTime = 1000f;
 hotspot.highlight.Flash ();
 }
 }
 }
 }

}

```
Override portrait graphic elements

Graphic menu elements set to "Dialog Portrait" will, by default, display the portrait graphic of the currently-speaking character.

This Action allows you to override that with a specific character, so that it always shows that character's portrait - regardless of whether they're talking or not.

ActionPortraitOverride.cs:

```
using UnityEngine;

using System.Collections.Generic;

#if UNITY_EDITOR

using UnityEditor;

#endif

namespace AC

{

	[System.Serializable]

	public class ActionPortraitOverride : Action

	{

		public string menuName;

		public string graphicElementName;

		public bool isPlayer;

		public AC.Char character;

		private AC.Char runtimeChar;

		public ActionPortraitOverride ()

		{

			this.isDisplayed = true;

			category = ActionCategory.Menu;

			title = "Set portrait override";

		}

		public override void AssignValues (List<ActionParameter> parameters)

		{

			runtimeChar = (isPlayer) ? KickStarter.player : character;

		}

		public override float Run ()

		{

			MenuElement element = PlayerMenus.GetElementWithName (menuName, graphicElementName);

			if (element != null && element is MenuGraphic)

			{

				MenuGraphic menuGraphic = (MenuGraphic) element;

				menuGraphic.PortraitCharacterOverride = runtimeChar;

			}

			return 0f;

		}

		#if UNITY_EDITOR

		public override void ShowGUI ()

		{

			menuName = EditorGUILayout.TextField ("Menu name:", menuName);

			graphicElementName = EditorGUILayout.TextField ("Graphic element name:", graphicElementName);

			isPlayer = EditorGUILayout.Toggle ("Map to Player?", isPlayer);

			if (!isPlayer)

			{

				character = (AC.Char) EditorGUILayout.ObjectField ("Character to map to:", character, typeof (AC.Char), true);

			}

			AfterRunningOption ();

		}

		#endif

	}

}

```
Light a room with the cursor

This script can be used to create a "flashlight" effect, where a light is shone in the scene where the cursor is pointing.

To use it:

1. Create a new C# file named CursorLight.cs, and paste in the code below
2. Create a Light in your scene (Spotlight if 3D, Point Light if 2D) and attach the new Cursor Light component
3. Configure the Inspector, setting the light's default's state, and whether it's 3D or not.
4. To turn on and off at runtime, use the **Object: Send message** Action to pass Turn On and Turn Off commands to the Light object

CursorLight.cs:

```
using UnityEngine;
using AC;

public class CursorLight : MonoBehaviour
{

 public float depth = 2f;
 public bool isOn = true;
 public bool is3D = true;

 public void TurnOn ()
 {
 isOn = true;
 }

 public void TurnOff ()
 {
 isOn = false;
 }

 void Update ()
 {
 if (isOn)
 {
 Vector3 mousePosition = KickStarter.playerInput.GetMousePosition ();
 mousePosition.z = depth;
 Vector3 mouseWorldPosition = KickStarter.CameraMain.ScreenToWorldPoint (mousePosition);

 if (is3D)
 {
 transform.position = KickStarter.CameraMain.transform.position;
 transform.forward = mouseWorldPosition - transform.position;
 }
 else
 {
 transform.position = mouseWorldPosition;
 }
 }
 else
 {
 transform.position = new Vector3 (-1000f, 0f, 0f);
 }
 }

}

```
Adding a separate crosshair

When AC's cursor is locked, it can optionally be displayed in the centre of the screen. However, it will still use the "Main cursor" texture assigned in the Cursor Manager.

This script allows you to display a separate texture, such as a crosshair, on-screen when the cursor is locked. To use it:

1. Create a new C# script named **Crosshair**, and copy/paste the code below.
2. Add a new Unity UI Canvas to the scene, and add an **Image** with a crosshair texture to it as a child, positioned in the centre of the screen.
3. Add a **Canvas Group** component to the Canvas' root, and uncheck **Interactable**.
4. To the same GameObject, add the new **Crosshair** component, and assign the Canvas Group in its Inspector.
5. In AC's Settings Manager, check **Hide cursor when locked in screen's centre?**.

Crosshair.cs:

```
using UnityEngine;
using AC;

public class Crosshair : MonoBehaviour
{

 public CanvasGroup canvasGroup;

 private void Update ()
 {
 if (canvasGroup) canvasGroup.alpha = KickStarter.playerInput.IsCursorLocked () ? 1f : 0f;
 }

}

```
Lock move direction while jumping

This script locks the player's movement direction while jumping / in mid-air. It is intended for Direct or First Person movement methods, as it works by locking the "Horizontal" and "Vertical" input axes to their values when the player was last on the ground.

To use it, create a new C# script named LockJumpDirection.cs, paste the code below into it, and attach it to a GameObject in your scene:

```
using UnityEngine;

using System.Collections;

using AC;

public class LockJumpDirection : MonoBehaviour

{

	private float lastGroundedHorizontalValue;

	private float lastGroundedVerticalValue;

	private void Start ()

	{

		KickStarter.playerInput.InputGetAxisDelegate = MyGetAxis;

	}

	private float MyGetAxis (string axisName)

	{

		float inputValue = Input.GetAxis (axisName);

		if (KickStarter.stateHandler.IsInGameplay ())

		{

			if (axisName == "Horizontal")

			{

				if (KickStarter.player.IsGrounded ())

				{

					lastGroundedHorizontalValue = inputValue;

				}

				else

				{

					return lastGroundedHorizontalValue;

				}

			}

			else if (axisName == "Vertical")

			{

				if (KickStarter.player.IsGrounded ())

				{

					lastGroundedVerticalValue = inputValue;

				}

				else

				{

					return lastGroundedVerticalValue;

				}

			}

		}

		return inputValue;

	}

}

```
Menu interactions in VR

This script allows you to interact with a menu using VR controllers.

1. Create a menu that uses Unity UI as its Source, and set its Canvas to act in World Space.
2. For each Button in contains, attach a Box Collider that covers it.
3. Copy/paste the script below into a C# script named TouchUI.cs, and attach it to each of the VR rig's controllers (the objects with the Tracked Pose Driver component)
4. Fill in the Touch UI Inspector, optionally assigning a Line Renderer to provide a line pointing from the controller.
5. For each, assign a Trigger Input Axis name, and define this name in Unity's Input Manager. Give the input a positive button of "joystick button 14" and "joystick button 15" for LeftTrigger / RightTrigger respectively.

TouchUI.cs:

```
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class TouchUI : MonoBehaviour
{

 #region Variables

 [Header ("Input")]
 [SerializeField] public LayerMask layerMask = new LayerMask ();
 [SerializeField] private string triggerInputAxis;

 [Header ("Visual")]
 [SerializeField] LineRenderer lineRenderer = null;
 [SerializeField] private Color lineSelectColor = Color.white;
 [SerializeField] private Color lineDeselectColor = Color.grey;
 [SerializeField] private float lineWidth = 0.06f;

 private Vector3[] points;
 private Selectable selectable;
 private bool waitForTriggerRelease;

 #endregion

 #region UnityStandards

 private void Start ()
 {
 points = new Vector3[2];
 points[0] = Vector3.zero;
 points[1] = transform.position + new Vector3 (0, 0, 20);

 if (lineRenderer)
 {
 lineRenderer.startWidth = lineWidth;
 lineRenderer.endWidth = lineWidth;
 lineRenderer.SetPositions (points);
 lineRenderer.enabled = true;
 }
 }

 private void Update ()
 {
 AlignLineRenderer ();
 DetectClicks ();
 }

 #endregion

 #region PrivateFunctions

 private void AlignLineRenderer ()
 {
 Ray ray = new Ray (transform.position, transform.forward);
 RaycastHit hit;

 if (Physics.Raycast (ray, out hit, layerMask))
 {
 points[1] = transform.forward + new Vector3 (0, 0, hit.distance);

 if (lineRenderer)
 {
 lineRenderer.startColor = lineSelectColor;
 lineRenderer.endColor = lineSelectColor;
 }

 selectable = hit.collider.gameObject.GetComponent<Selectable> ();
 if (selectable)
 {
 selectable.Select ();
 }
 }
 else
 {
 points[1] = transform.forward + new Vector3 (0, 0, 20);

 if (lineRenderer)
 {
 lineRenderer.startColor = lineDeselectColor;
 lineRenderer.endColor = lineDeselectColor;
 }

 if (selectable)
 {
 if (EventSystem.current.currentSelectedGameObject && EventSystem.current.currentSelectedGameObject == selectable.gameObject)
 {
 EventSystem.current.SetSelectedGameObject (null);
 }

 selectable = null;
 }
 }

 if (lineRenderer)
 {
 lineRenderer.SetPositions (points);
 lineRenderer.material.color = lineRenderer.startColor;
 }
 }

 private void DetectClicks ()
 {
 if (Input.GetAxis (triggerInputAxis) > 0f)
 {
 if (waitForTriggerRelease)
 {
 return;
 }

 if (selectable)
 {
 Button button = selectable as Button;
 if (button)
 {
 button.onClick?.Invoke ();
 }

 waitForTriggerRelease = true;
 }
 }
 else
 {
 waitForTriggerRelease = false;
 }
 }

 #endregion

}

```
Flip portraits with character direction

Character portraits can be placed inside a Subtitles menu (see this tutorial). This script causes them to be flipped horizontally whenever the character is facing sceen-left, so that their portrait is consistent with their facing direction.

To use it:

1. Configure your Subtitles menu with a portrait graphic, and have the Menu use Unity UI.
2. Copy/paste the code below into a C# script named FlipPortraitLeft.
3. Attach the Flip Portrait Left component to your UI Canvas prefab, and assign both the Canvas, and the portrait Image components, in its Inspector.
4. Adjust your portrait graphics so that they all face screen-right.

FlipPortraitLeft.cs:

```
using UnityEngine;
using UnityEngine.UI;
using AC;

public class FlipPortraitLeft : MonoBehaviour
{

 public Canvas canvas;
 public Image portraitImage;

 void Update ()
 {
 Speech speech = KickStarter.dialog.GetLatestSpeech ();
 Menu menu = KickStarter.playerMenus.GetMenuWithCanvas (canvas);
 if (menu != null && menu.speech != null)
 {
 speech = menu.speech;
 }
 if (speech == null) return;
 Char speaker = speech.GetSpeakingCharacter ();
 if (speaker == null ) return;
 bool isFacingRight = Vector3.Dot (speaker.TransformForward, Camera.main.transform.right) > 0f;
 Vector3 scale = portraitImage.rectTransform.localScale;
 if (isFacingRight)
 {
 if (scale.x < 0f) scale.x \*= -1f;
 }
 else
 {
 if (scale.x > 0f) scale.x \*= -1f;
 }
 portraitImage.rectTransform.localScale = scale;
 }

}

```
Mousewheel-scrolling through lists

This script allows you to offset element slots (e.g. a DialogList or InventoryBox) with the mousewheel. To use it:

1. Create a new C# script named ScrollWheelMenuList.cs, and paste in the code below
2. For each element you wish to enable scrolling for, place an instance of the script in the scene. For Unity UI-linked Menus, the script can be attached to the prefab's root Canvas.
3. Configure the Inspector values. You will need to ensure that the Input Name field matches an Input defined in Unity's Input Manager.

ScrollWheelMenuList.cs:

```
using UnityEngine;

using AC;

public class ScrollWheelMenuList : MonoBehaviour

{

	[SerializeField] private string inputName = "Mouse ScrollWheel";

	[SerializeField] private float inputThreshold = 0.05f;

	[SerializeField] private string menuName = "Conversation";

	[SerializeField] private string elementName = "DialogueList";

	private bool allowScrollWheel;

	private bool menuIsOn;

	private bool hasCanvas;

	private void OnEnable ()

	{

		EventManager.OnMenuTurnOn += OnMenuTurnOn;

		EventManager.OnMenuTurnOff += OnMenuTurnOff;

		hasCanvas = (GetComponent<Canvas> () != null);

	}

	private void OnDisable ()

	{

		EventManager.OnMenuTurnOn -= OnMenuTurnOn;

		EventManager.OnMenuTurnOff -= OnMenuTurnOff;

	}

	private void Update ()

	{

		if (menuIsOn || hasCanvas)

		{

			float scrollInput = Input.GetAxisRaw (inputName);

			if (scrollInput > inputThreshold)

			{

				if (allowScrollWheel)

				{

					PlayerMenus.GetElementWithName (menuName, elementName).Shift (AC_ShiftInventory.ShiftPrevious, 1);

					allowScrollWheel = false;

				}

			}

			else if (scrollInput < -inputThreshold)

			{

				if (allowScrollWheel)

				{

					PlayerMenus.GetElementWithName (menuName, elementName).Shift (AC_ShiftInventory.ShiftNext, 1);

					allowScrollWheel = false;

				}

			}

			else

			{

				allowScrollWheel = true;

			}

		}

	}

	private void OnMenuTurnOn (Menu menu, bool isInstant)

	{

		if (menu.title == menuName)

		{

			menuIsOn = true;

		}

	}

	private void OnMenuTurnOff (Menu menu, bool isInstant)

	{

		if (menu.title == menuName)

		{

			menuIsOn = false;

		}

	}

}

```
Snap 2D characters the ground

A characters in a 2D game normally moves freely within a NavMesh / collision boundary. This script causes them to instead snap vertically to the top edge of a collider. If that collider's shape is that of the ground, they will appear to move along the ground without moving vertically inappropriately.

To use it:

1. Create a new GameObject and attach a 2D Collider (e.g. Polygon Collider 2D) to it, and reshape it to match the ground's shape and position.
2. Create a new C# script named StickToGroundY.cs and attach it to your character
3. Configure the Stick To Ground Y's Inspector, assigning its Ground Layer field to match that of the ground GameObject created in step 1.
4. Set the character's starting position to be above the ground, at a distance no more than the length of the component's "Raycast Distance" field.

StickToGroundY.cs:

```
using UnityEngine;

public class StickToGroundY : MonoBehaviour
{

 public LayerMask groundLayer;
 public float raycastDistance = 1f;
 private RaycastHit2D hitInfo = new RaycastHit2D ();

 private void LateUpdate ()
 {
 hitInfo = Physics2D.Raycast (transform.position + Vector3.up \* 0.1f, -Vector3.up, raycastDistance, groundLayer);
 if (hitInfo.collider)
 {
 transform.position = hitInfo.point;
 }
 }

}

```
Easy Performant Outline integration

The built-in method of highlighting Hotspots when selecting them is to brighten their materials. This script provides a way to instead display an outline effect around them - through use of the Easy Performant Outline asset. This asset provides outline effects in 2D, 3D and the render pipeliens.

To use it:

1. Import Easy Performant Outline into your AC project
2. Attach the Outliner component to your AC MainCamera
3. Create a new C# script file named EasyOutline.cs, and paste in the code below
4. To any Hotspot you want to affect, attach the Easy Outline component to it. The Hotspot's Highlight field, if set, can be removed.
5. An Outlinable component will be added automatically. Configure its Inspector so that it affects the correct meshes.
6. The script will, by default, only show the front outline in a white colour. The script can be editied to change the style of outline if desired.

EasyOutline.cs:

```
using UnityEngine;

using System.Collections;

using EPOOutline;

using AC;

[RequireComponent (typeof (Outlinable))]

public class EasyOutline : MonoBehaviour

{

	#region Variables

	private Hotspot hotspot = null;

	private Outlinable outlinable = null;

	private const float speed = 5f;

	#endregion

	#region UnityStandards

	private void Awake ()

	{

		hotspot = GetComponent<Hotspot>();

		outlinable = GetComponent<Outlinable>();

		outlinable.RenderStyle = RenderStyle.FrontBack;

		outlinable.enabled = false;

		outlinable.BackParameters.Enabled = false;

		outlinable.FrontParameters.Color = Color.white;

		outlinable.FrontParameters.DilateShift = 0f;

	}

	private void OnEnable ()

	{

		EventManager.OnHotspotSelect += OnHotspotSelect;

		EventManager.OnHotspotDeselect += OnHotspotDeselect;

	}

	private void OnDisable ()

	{

		EventManager.OnHotspotSelect -= OnHotspotSelect;

		EventManager.OnHotspotDeselect -= OnHotspotDeselect;

	}

	#endregion

	#region PrivateFunctions

	private void OnHotspotSelect (Hotspot hotspot)

	{

		if (this.hotspot == hotspot)

		{

			StopAllCoroutines ();

			StartCoroutine (TransitionOn ());

		}

	}

	private void OnHotspotDeselect (Hotspot hotspot)

	{

		if (this.hotspot == hotspot)

		{

			StopAllCoroutines ();

			StartCoroutine (TransitionOff ());

		}

	}

	private IEnumerator TransitionOn ()

	{

		outlinable.enabled = true;

		while (outlinable.FrontParameters.DilateShift < 1f)

		{

			float newShift = outlinable.FrontParameters.DilateShift + (speed * Time.deltaTime);

			newShift = Mathf.Clamp01 (newShift);

			outlinable.FrontParameters.DilateShift = newShift;

			yield return new WaitForEndOfFrame ();

		}

	}

	private IEnumerator TransitionOff ()

	{

		while (outlinable.FrontParameters.DilateShift > 0f)

		{

			float newShift = outlinable.FrontParameters.DilateShift - (speed * Time.deltaTime);

			newShift = Mathf.Clamp01 (newShift);

			outlinable.FrontParameters.DilateShift = newShift;

			yield return new WaitForEndOfFrame ();

		}

		outlinable.enabled = false;

	}

	#endregion

}

```
Controlling Text Scroll Speed With Speech Event Tokens

Here is way to Adjust how fast a Characters Text scrolls with a Speech Event Token in the Dialogue action.

First you will need to attach this Script to your Game Engine Prefab:

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using AC;

public class SpeechTokenMonitor : MonoBehaviour
{
 // Start is called before the first frame update
 void Start()
 {

 }

 // Update is called once per frame
 void Update()
 {

 }
 private void OnEnable()
 {
 KickStarter.dialog.SpeechEventTokenKeys = new string[1] { "textspeed" };
 EventManager.OnSpeechToken += OnSpeechToken;
 }
 private void OnDisable()
 {
 EventManager.OnSpeechToken -= OnSpeechToken;
 }
 private void OnSpeechToken(AC.Char speakingCharacter, int lineID,
 string tokenKey, string tokenValue)
 {
 if (tokenKey != "textspeed") return;
 // Try to parse the tokenValue string to a float
 if (float.TryParse(tokenValue, out float parsedValue))
 {
 AC.KickStarter.speechManager.textScrollSpeed = parsedValue;
 Debug.Log(speakingCharacter + " said token [" + tokenKey + ":" + parsedValue + "]");
 }
 else
 {
 Debug.LogError("Failed to parse token value as float: " + tokenValue);
 }
 }

}

```
This Script allows the Speech event Token "textspeed"

So if you want to now change a characters Text scroll speed, it would look like this:

"[textspeed:50]these chars will be printed with 50 speed. [textspeed:100] these chars will be printed with 100 speed"

Be aware however that changing the scroll speed caries over to edit mode, so you may want to attach this additional script to the subtitles UI prefab, or any UI element that is using text scrolling. This Script resets the Scroll speed to your default (Delineated in the int field of this script)

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using AC;

public class TextScrollDefaults : MonoBehaviour
{
 public float TextScrollSpeed = 90;
 // Start is called before the first frame update
 void Start()
 {

 }
 private void OnEnable()
 {
 AC.KickStarter.speechManager.textScrollSpeed = TextScrollSpeed;
 }
 // Update is called once per frame
 void Update()
 {

 }
}

```
Hope this Helps!
2.5D Occlusion of meshes behind a transparent front mesh

This shader script allows you to have a front mesh be fully transparent, allowing it to appear as the background, while still occluding the meshes going behind it. This creates the effect that the behind elements are under/behind/hidden by actual elements drawn in a simple image background.

The script was found here: https://stackoverflow.com/questions/72477399/occluding-parts-of-an-object-behind-a-transparent-object

To use it, simply set up a background as a Raw Image, create a Custom Shader script in Unity with the below script, and create a material from it that will be added to the meshes you want transparent.

```
Shader "Custom/Mask"
{
    Properties
    {
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" "Queue" = "Geometry-1" }
        LOD 100

        Blend Zero One

        Pass
        {

        }
    }
}
```
Wait a random time within an specified time range (Action)

Note: This action allows you to wait a randomized amount of time between a time range.

There are two ways to create the script:

1 Create a blank text file, paste the code, then rename the file to the name of the class and change the extension to .cs (ActionPauseRandom.cs).

Or

2. Create a script inside unity in the library tab named as mentioned before, then just replace the whole text in the file.

Then, just drop this in the Actions folder in AC or make your own custom Action folder, go to the Actions manager in AC and then set the folder for custom action in there.

Here's code:

```
 using UnityEngine;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace AC
{

   [System.Serializable]
   public class ActionPauseRandom : Action
   {

       public int parameterIDMin = -1;
       public int parameterIDMax = -1;
       public float timeToPauseMin;
       public float timeToPauseMax;

       public override ActionCategory Category { get { return ActionCategory.Engine; } }
       public override string Title { get { return "Wait Random"; } }
       public override string Description { get { return "Waits a random time between the values continuing."; } }

       override public void AssignValues (List<ActionParameter> parameters)
       {
           timeToPauseMin = AssignFloat (parameters, parameterIDMin, timeToPauseMin);
           timeToPauseMin = Mathf.Max (0f, timeToPauseMin);
           timeToPauseMax = AssignFloat(parameters, parameterIDMax, timeToPauseMax);
           timeToPauseMax = Mathf.Max(0f, timeToPauseMax);
       }

       override public float Run ()
       {
           if (!isRunning)
           {
               isRunning = true;
               return Random.Range (timeToPauseMin, timeToPauseMax);
           }
           isRunning = false;
           return 0f;
       }

       #if UNITY_EDITOR
       override public void ShowGUI (List<ActionParameter> parameters)
       {
           parameterIDMin = Action.ChooseParameterGUI ("Minimum wait time (s):", parameters, parameterIDMin, ParameterType.Float);
           if (parameterIDMax < 0)
           {
               timeToPauseMin = EditorGUILayout.FloatField ("Minimum wait time (s):", timeToPauseMin);
           }
           parameterIDMax = Action.ChooseParameterGUI ("Maximum wait time (s):", parameters, parameterIDMax, ParameterType.Float);
           if (parameterIDMax < 0)
           {
               timeToPauseMax = EditorGUILayout.FloatField ("Maximum wait time (s):", timeToPauseMax);
           }
       }

       public override string SetLabel ()
       {
           return " (" + timeToPauseMin+"-"+ timeToPauseMax + "s)";
       }

       #endif
   }
}

```

[Code provided by user: Teshla]
Change a Timeline's current time

This Action allows you to change the time a Timeline is currently at. To use it:

1. Create a new C# file named ActionTimelineTime and place it in a unique folder, or existing custom Actions folder.
2. Point to this folder from the Actions Manager's Custom Actions file browser
3. The Action is now available to use as the "Custom: Set Timeline time" Action.

ActionTimelineTime.cs:

```
using UnityEngine;
using System.Collections.Generic;
#if UNITY\_EDITOR
using UnityEditor;
#endif
using UnityEngine.Playables;

namespace AC
{

 [System.Serializable]
 public class ActionTimelineTime : Action
 {

 public override ActionCategory Category { get { return ActionCategory.Custom; }}
 public override string Title { get { return "Set Timeline time"; }}
 public override string Description { get { return "Sets a Timline's current time to a specific moment."; }}

 public PlayableDirector director;
 public int directorConstantID;
 protected PlayableDirector runtimeDirector;

 public float time;

 public override void AssignValues (List<ActionParameter> parameters)
 {
 runtimeDirector = AssignFile <PlayableDirector> (directorConstantID, director);
 }

 public override float Run ()
 {
 if (runtimeDirector)
 {
 runtimeDirector.time = time;
 runtimeDirector.Evaluate ();
 }
 return 0f;
 }

 public override void Skip ()
 {
 Run ();
 }

 #if UNITY\_EDITOR

 public override void ShowGUI ()
 {
 director = (PlayableDirector) EditorGUILayout.ObjectField ("Director:", director, typeof (PlayableDirector), true);
 directorConstantID = FieldToID <PlayableDirector> (director, directorConstantID);
 director = IDToField <PlayableDirector> (director, directorConstantID, false);

 time = EditorGUILayout.FloatField ("New time (s):", time);
 }

 #endif

 }

}

```
Rewired integration

Notes: Attach the script to any active object in the hierarchy, which you know is always going to exist on every scene, or which doesn't get destroyed on loading (You may also put it on the AC persistent engine or game engine prefabs). Also, make sure your actions are correctly setup.

In Rewired, they need to have the exact same names as the AC inputs listed under the AC's Settings Manager. Make sure you don't have Unity inputs which may clash with your actions, too, or they will fight for control. So once the Rewired actions are setup you can delete your Unity inputs (in unity's input manager). For the rest follow Rewired's documentation.

```
using UnityEngine;

public class ACInputRewired : MonoBehaviour
{
 public int playerId = 0;
 private Rewired.Player player;

 void Start()
 {
 AC.KickStarter.playerInput.InputGetButtonDownDelegate = CustomGetButtonDown;
 AC.KickStarter.playerInput.InputGetButtonUpDelegate = CustomGetButtonUp;
 AC.KickStarter.playerInput.InputGetButtonDelegate = CustomGetButton;
 AC.KickStarter.playerInput.InputGetAxisDelegate = CustomGetAxis;
 player = Rewired.ReInput.players.GetPlayer(playerId);
 }

 private bool CustomGetButtonDown(string buttonName)
 {
 return player.GetButtonDown(buttonName);
 }

 private float CustomGetAxis(string AxisName)
 {
 return player.GetAxis(AxisName);
 }

 private bool CustomGetButton(string buttonName)
 {
 return player.GetButton(buttonName);
 }

 private bool CustomGetButtonUp(string buttonName)
 {
 return player.GetButtonUp(buttonName);
 }

}

```
Cancel Interaction Menus

This is useful if you want to simulate traditional console style controls, which usually have an Accept and a Cancel buttons. note however that you will need to create the extra Input in your input manager to get the script to work. Add the following code to a C# script (the basic Unity script template):

```
void Update ()

{

  // This simply adds Cancel Functionality

  if (Input.GetButtonDown ("Cancel"))

  {

    // De-select the current Hotspot

    AC.KickStarter.playerInteraction.DeselectHotspot ();

    // Close the Interaction menu(s)

    AC.KickStarter.playerMenus.SetInteractionMenus (false);

  }

}

```
Fix Blurry Pixel Art Style Fonts in Unity

The article was originally written by Ryan Nielson, reproduced here by kind permission. Here's the original blog post: https://nielson.dev/2016/09/fix-blurry-pixel-art-style-fonts-in-unity

The Unity UI system is great, but by default it doesn’t tend to work well when using fonts that require very sharp edges like those seen in pixel art style games. Though the fonts look alright, upon closer inspection the edges of the characters are slightly blurry and sometimes the characters look off. In the image below, if you look closely, you can see some blurriness around the character edges.

Switching the font’s import setting `Rendering Mode` to `Hinted Raster` can help a bit with the blurriness, but it doesn’t seem to reproduce the characters properly. This leads to letters that look slightly different than they do in the original font.

Luckily there’s a way to fix this issue in the Unity editor that doesn’t require too much additional work. Begin by bringing a font into your project like you normally would. For this example I’m using a font called Press Start. Next click on your font in the project window to open the inspector, change the `Character` dropdown to `Unicode`, and click `Apply`. This process prepares Unity for the next step.

Click on the cog in the top right of the font inspector, and select `Create Editable Copy`. In your project window you should now see a new material, texture, and font asset with similar names to your existing font. By default when Unity imports a font it doesn’t give you the ability to modify the related material and texture. `Create Editable Copy` gives you these assets to modify to your heart’s content.

Now click on the newly created texture, which should open the texture inspector. Switch `Texture Type` to advanced and change the `Filter Mode` from `Bilinear` to `Point`. This should remove the blurriness from your font’s texture. The settings I’ve used are in the image below. Sometimes it seems as though selecting the incorrect settings can cause issues when displaying your font, so if you are having issues just start the process over and try to match the settings below.

Now click on your UI Text object in the hierarchy, and replace the existing font with the new font asset (PrStart\_copy in my case). You should immediately see sharper text in your game view. The image below shows the old font on the top, and the new font on the bottom. Hopefully it’s clear enough to illustrate the difference the above steps make.
Post processing depth of field

**Post Processing Stack v1**

This script updates the active post-processing profile with the AC-calculated depth-of-field focus distance.

To use:

1. Download and install Unity's Post Processing Stack asset here
2. Attach the Post Processing Behaviour component to AC's MainCamera, and enable Depth Of Field in the profile
3. Attach the script below to the MainCamera as well

CopyDOF.cs:

```
using UnityEngine;
using UnityEngine.PostProcessing;
using AC;

public class CopyDOF : MonoBehaviour
{

    public float fStop = 2f;
    private PostProcessingProfile profile;

    private void Start ()
    {
        profile = GetComponent <PostProcessingBehaviour>().profile;
    }

    private void Update ()
    {
        DepthOfFieldModel.Settings dofSettings = profile.depthOfField.settings;
        dofSettings.focusDistance = KickStarter.mainCamera.GetFocalDistance ();
        dofSettings.aperture = fStop;
        dofSettings.useCameraFov = true;
        profile.depthOfField.settings = dofSettings;
    }

}

```

**Post Processing Stack v2**

To use:

1. Download and install Unity's Post Processing Stack v2 asset from Github here (Note: Installing via package currently causes problems)
2. Attach the Post Processing Layer component to AC's MainCamera, and add a global Post Processing Volume in the scene that the MainCamera makes use of
3. Add a Depth Of Field effect to the Post Processing Volume and override the Focus Distance property
4. Attach the script below to the same GameObject and assign the Profile field

CopyDOFv2.cs:

```
using UnityEngine;

using UnityEngine.Rendering.PostProcessing;

using AC;

public class CopyDOFv2 : MonoBehaviour

{

    [SerializeField] private PostProcessProfile profile;

    private void Update ()

    {

        DepthOfField dofSettings = profile.GetSetting <DepthOfField>();

        dofSettings.focusDistance.value = KickStarter.mainCamera.GetFocalDistance ();

    }

}

```
Portrait graphics - saving

As of AC v1.73.0, changes made to character portrait textures (using the "Character: Change portrait" Action) are no longer saved automatically. To save such changes, attach the RememberPortrait script to the character:

```
using UnityEngine;
#if AddressableIsPresent
using System.Collections;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.AddressableAssets;
#endif

namespace AC
{

 [AddComponentMenu ("Adventure Creator/Save system/Remember Portrait")]
 public class RememberPortrait : Remember
 {

 private Char character;

 public override string SaveData ()
 {
 PortraitData portraitData = new PortraitData ();
 portraitData.objectID = constantID;
 portraitData.savePrevented = savePrevented;

 if (Character)
 {
 portraitData.portraitGraphic = AssetLoader.GetAssetInstanceID (Character.portraitIcon.texture);
 }
 return Serializer.SaveScriptData<NameData> (portraitData);
 }

 public override void LoadData (string stringData)
 {
 PortraitData data = Serializer.LoadScriptData<PortraitData> (stringData);
 if (data == null) return;

 SavePrevented = data.savePrevented;
 if (savePrevented) return;

 if (Character && !string.IsNullOrEmpty (data.portraitGraphic))
 {
 #if AddressableIsPresent
 if (KickStarter.settingsManager.saveAssetReferencesWithAddressables)
 {
 StartCoroutine (LoadDataFromAddressables (data));
 }
 else
 #endif
 {
 Character.portraitIcon.ReplaceTexture (AssetLoader.RetrieveAsset (Character.portraitIcon.texture, data.portraitGraphic));
 }
 }
 }

 #if AddressableIsPresent

 private IEnumerator LoadDataFromAddressables (PortraitData data)
 {
 AsyncOperationHandle<Texture> textureHandle = Addressables.LoadAssetAsync<Texture> (data.portraitGraphic);
 yield return textureHandle;
 if (textureHandle.Status == AsyncOperationStatus.Succeeded)
 {
 Character.portraitIcon.ReplaceTexture (textureHandle.Result);
 }
 Addressables.Release (textureHandle);
 }

 #endif

 private Char Character
 {
 get
 {
 if (character == null) character = GetComponent <Char>();
 return character;
 }
 }
 }

 [System.Serializable]
 public class PortraitData : RememberData
 {

 public string portraitGraphic;

 public PortraitData ()
 { }

 }
}

```