0%

关于Unity的笔记 - 续

因为上一篇太乱了没看懂于是新开一篇(靠).




Temp

1
[RequireComponent(typeof(CharacterController))]

Get Instance.

1
2
3
4
5
6
7
8
9
10
private PlayerInput _input;
private CharacterController _characterController;

void Start()
{
// dynamicly finding it -> because it is singleton?
_input = PlayerInput.GetInstance();
// this is finding the component attached to the same game object
_characterController = GetComponent<CharacterController>();
}
1
2
3
4
void GroundCheck()
{
_isGrounded = Physics.CheckSphere(_groundCheck.position, _groundCheckDistance, _groundMask);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class Interactor : MonoBehaviour
{
protected PlayerInput _input;

private void Start()
{
_input = PlayerInput.GetInstance();
}

private void Update()
{
Interact();
}

public abstract void Interact();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class SimpleInteractor : Interactor
{
[Header("Interact")]
[SerializeField] private Camera _cam;
[SerializeField] private LayerMask _interactionLayer;
[SerializeField] private float _interactionDistance;

private RaycastHit _raycastHit;
protected ISelectable _selectable;

public override void Interact() {
Ray ray = _cam.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0)); // **Physics.Raycast**
if (Physics.Raycast(ray, out _raycastHit, _interactionDistance, _interactionLayer))
{
_selectable = _raycastHit.transform.GetComponent<ISelectable>();
if (_selectable != null) {
_selectable.OnHoverEnter();

if (_input._interactPressed) {
_selectable.OnSelect();
}
}
}

if (_raycastHit.transform == null && _selectable != null)
{
_selectable.OnHoverExit();
_selectable = null;
}


}

}
1
2
3
4
5
public enum Input
{
Primary,
Secondary
}

Code

Action

1
2
3
4
5
6
7
8
9
10
11
12
13
using UnityEngine.Events;

public Action<float> OnHealthUpdated;
// this means onHealthUpdated func will take float as parameter
public Action OnDeath;
// this does not take parameter

OnHealthUpdated += AnotherFunc_OnHealthUpdate;

void AnotherFunc_OnHealthUpdate(float health){
// actions
// can be different script
}


Unity Events

1



Generics

可以用来代表不定的parameter.

1
2
3
4
5
6
7
8
9
10
11
12
13
using UnityEngine;
using System.Collections;

public class SomeClass
{
//Here is a generic method. Notice the generic
//type 'T'. This 'T' will be replaced at runtime
//with an actual type.
public T GenericMethod<T>(T param)
{
return param;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using UnityEngine;
using System.Collections;

public class SomeOtherClass : MonoBehaviour
{
void Start ()
{
SomeClass myClass = new SomeClass();

//In order to use this method you must
//tell the method what type to replace
//'T' with.
myClass.GenericMethod<int>(5);
}
}



Collision / Trigger

OnCollisionEnter OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider.
OnCollisionExit OnCollisionExit is called when this collider/rigidbody has stopped touching another rigidbody/collider.
OnCollisionStay OnCollisionStay is called once per frame for every Collider or Rigidbody that touches another Collider or Rigidbody.
OnTriggerEnter When a GameObject collides with another GameObject, Unity calls OnTriggerEnter.
OnTriggerExit OnTriggerExit is called when the Collider other has stopped touching the trigger.
OnTriggerStay OnTriggerStay is called almost all the frames for every Collider other that is touching the trigger. The function is on the physics timer so it won’t necessarily run every frame.


Joints

也有2Djoints.



Observer Design Pattern

UnityEvents and Actions are Unity-specific implementations of the Observer pattern.
● AddListener and RemoveListener are the subscription functions.
● Invoking the Action/UnityEvent is the notify behavior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
using System;
using System.Collections.Generic;

// Observer interface
public interface IObserver
{
void Update(double stockPrice);
}

// Concrete Observer class
public class Investor : IObserver
{
private string name;

public Investor(string name)
{
this.name = name;
}

public void Update(double stockPrice)
{
Console.WriteLine($"{name} received an update:
Stock price is now {stockPrice:C}");
}
}

// Subject (Observable) class
public class Stock
{
private double price;
private List<IObserver> investors = new List<IObserver>();

public void Attach(IObserver observer)
{
investors.Add(observer);
}

public void Detach(IObserver observer)
{
investors.Remove(observer);
}

public void SetPrice(double newPrice)
{
price = newPrice;
Notify();
}

private void Notify()
{
foreach (var investor in investors)
{
investor.Update(price);
}
}
}

// Usage
class Program
{
static void Main()
{
Stock techStock = new Stock();

Investor investor1 = new Investor("John");
Investor investor2 = new Investor("Jane");

techStock.Attach(investor1);
techStock.Attach(investor2);

techStock.SetPrice(150.50);
// Outputs:
// John received an update: Stock price is now $150.50
// Jane received an update: Stock price is now $150.50

techStock.Detach(investor1);

techStock.SetPrice(155.25);
// Outputs:
// Jane received an update: Stock price is now $155.25
}
}


The Command Design Pattern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;

// Command interface
public interface ICommand
{
void Execute();
}

// Concrete Command classes
public class LightOnCommand : ICommand
{
private Light light;

public LightOnCommand(Light light)
{
this.light = light;
}

public void Execute()
{
light.TurnOn();
}
}

public class LightOffCommand : ICommand
{
private Light light;

public LightOffCommand(Light light)
{
this.light = light;
}

public void Execute()
{
light.TurnOff();
}
}

// Receiver class
public class Light
{
public void TurnOn()
{
Console.WriteLine("Light is ON");
}

public void TurnOff()
{
Console.WriteLine("Light is OFF");
}
}

// Invoker class
public class RemoteControl
{
private ICommand command;

public void SetCommand(ICommand command)
{
this.command = command;
}

public void PressButton()
{
command.Execute();
}
}

// Usage
class Program
{
static void Main()
{
Light livingRoomLight = new Light();

ICommand lightOn = new LightOnCommand(livingRoomLight);
ICommand lightOff = new LightOffCommand(livingRoomLight);

RemoteControl remote = new RemoteControl();

remote.SetCommand(lightOn);
remote.PressButton(); // Outputs: Light is ON

remote.SetCommand(lightOff);
remote.PressButton(); // Outputs: Light is OFF
}
}


Object Pool Design Pattern

Create a pool of instantiated objects, and use them as needed without destroying them, just return them to the pool.



State Design Pattern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// State interface
public interface ITrafficSignalState
{
void Handle();
}

// Concrete State classes
public class RedLightState : ITrafficSignalState
{
public void Handle()
{
Console.WriteLine("Traffic signal: RED - Stop!");
}
}

public class GreenLightState : ITrafficSignalState
{
public void Handle()
{
Console.WriteLine("Traffic signal: GREEN - Go!");
}
}

public class YellowLightState : ITrafficSignalState
{
public void Handle()
{
Console.WriteLine
("Traffic signal: YELLOW - Prepare to stop.");
}
}

// Context class
public class TrafficSignal
{
private ITrafficSignalState currentState;

public TrafficSignal(ITrafficSignalState initialState)
{
currentState = initialState;
}

public void ChangeState(ITrafficSignalState newState)
{
currentState = newState;
}

public void Request()
{
currentState.Handle();
}
}

// Usage
class Program
{
static void Main()
{
TrafficSignal
trafficSignal = new TrafficSignal(new RedLightState());

trafficSignal.Request();
// Outputs: Traffic signal: RED - Stop!

trafficSignal.ChangeState(new GreenLightState());
trafficSignal.Request();
// Outputs: Traffic signal: GREEN - Go!
}
}


The Strategy Design Pattern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Strategy interface
public interface IAbilityStrategy
{
void Execute();
}

// Concrete Strategy classes
public class AttackStrategy : IAbilityStrategy
{
public void Execute()
{
Console.WriteLine("Character attacks!");
}
}

public class HealStrategy : IAbilityStrategy
{
public void Execute()
{
Console.WriteLine("Character heals!");
}
}

// Context class
public class Character
{
private IAbilityStrategy ability;

public Character(IAbilityStrategy initialAbility)
{
ability = initialAbility;
}

public void SetAbility(IAbilityStrategy newAbility)
{
ability = newAbility;
}

public void UseAbility()
{
ability.Execute();
}
}

// Usage
class Program
{
static void Main()
{
Character warrior = new Character(new AttackStrategy());
Character healer = new Character(new HealStrategy());

warrior.UseAbility();
// Outputs: Character attacks!
healer.UseAbility();
// Outputs: Character heals!

// Switching abilities dynamically
warrior.SetAbility(new HealStrategy());
warrior.UseAbility();
// Outputs: Character heals!
}
}


Notes

Universal RP

这个在unity 3D universal中自带,但3D core中没有.
导致部分material会出现显示错误(pink).

可以把material给成standard或者增添这个package.



Data Structure

一些过去的回忆.就只贴点图了.



Recursive factorial function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int Factorial(int n)
{
// Base case: factorial of 0 is 1
if (n == 0)
return 1;

// Recursive case: multiply n by factorial of (n - 1)
return n * Factorial(n - 1);
}

// Example usage
int result = Factorial(5);

// Output: 120
Console.WriteLine(result);


Dijkstra’s Algorithm.

One of the most common algorithms used for finding the shortest path in graphs is Dijkstra’s algorithm.
Here’s a simplified explanation of how it works:

Start by assigning a tentative distance value to every vertex in the graph.
Set the distance of the source vertex to 0 and all other vertices to infinity.
Mark the source vertex as the current vertex.
For the current vertex, consider all of its unvisited neighbors and calculate their tentative distances by summing the distance of the current vertex and the weight of the edge between them.
If the calculated tentative distance of a neighbor is less than its current assigned distance, update the neighbor’s distance value.
Once all the neighbors of the current vertex have been considered, mark the current vertex as visited and select the unvisited vertex with the smallest tentative distance as the next current vertex.
Repeat steps 3-5 until the destination vertex is marked as visited or there are no more unvisited vertices.
The shortest path can then be reconstructed by backtracking from the destination vertex to the source vertex using the recorded distances and visited vertices.
Dijkstra’s algorithm guarantees that the shortest path is found, given that the graph doesn’t contain negative weight cycles.
It explores vertices in a greedy manner, always selecting the vertex with the smallest tentative distance as the next current vertex.



Quick Sort implementation in C#.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Function to perform Quick Sort
void QuickSort(int[] array, int low, int high)
{
if (low < high)
{
// Partition the array and get the pivot index
int pivotIndex = Partition(array, low, high);

// Recursively sort the subarrays before and after the pivot
QuickSort(array, low, pivotIndex - 1);
QuickSort(array, pivotIndex + 1, high);
}
}

// Function to partition the array and find the pivot index
int Partition(int[] array, int low, int high)
{
int pivot = array[high]; // Choose the last element as the pivot
int i = low - 1;

for (int j = low; j < high; j++)
{
if (array[j] < pivot)
{
i++;
// Swap elements at indices i and j
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}

// Place the pivot in its correct position
int pivotIndex = i + 1;
int temp2 = array[pivotIndex];
array[pivotIndex] = array[high];
array[high] = temp2;

return pivotIndex;
}

// Example usage
int[] numbers = { 5, 2, 9, 1, 3 };
QuickSort(numbers, 0, numbers.Length - 1);

// Output: 1, 2, 3, 5, 9
Console.WriteLine(string.Join(", ", numbers));


What is the difference between a layer and a tag?

Layers are used to isolate things in the engine. Tags are used to label or categorize things.