Skip to content

Commit 2e6400f

Browse files
committed
add strategy pattern in Patterns folder
1 parent d376b72 commit 2e6400f

File tree

7 files changed

+170
-60
lines changed

7 files changed

+170
-60
lines changed

Patterns/StrategyPattern/Character.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using UnityEngine;
2+
using UnityCheatSheet.Patterns.StrategyPattern.Strategies;
3+
4+
namespace UnityCheatSheet.Patterns.StrategyPattern
5+
{
6+
public class Character : MonoBehaviour
7+
{
8+
private IAttackStrategy attackStrategy;
9+
public Transform target;
10+
11+
private void Start()
12+
{
13+
// Default to melee attack
14+
SetAttackStrategy(new MeleeAttackStrategy());
15+
}
16+
17+
public void SetAttackStrategy(IAttackStrategy strategy)
18+
{
19+
attackStrategy = strategy;
20+
Debug.Log($"Changed to {strategy.GetType().Name} - Range: {strategy.GetRange()}, Damage: {strategy.GetDamage()}");
21+
}
22+
23+
public void PerformAttack()
24+
{
25+
if (attackStrategy != null && target != null)
26+
{
27+
attackStrategy.Attack(transform, target);
28+
}
29+
else
30+
{
31+
Debug.LogWarning("Cannot attack: Missing strategy or target");
32+
}
33+
}
34+
}
35+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using UnityEngine;
2+
3+
namespace UnityCheatSheet.Patterns.StrategyPattern
4+
{
5+
public interface IAttackStrategy
6+
{
7+
void Attack(Transform attacker, Transform target);
8+
float GetDamage();
9+
float GetRange();
10+
}
11+
}

Patterns/StrategyPattern/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Strategy Pattern Example
2+
3+
A Unity example demonstrating the Strategy Pattern with a combat system.
4+
5+
## Overview
6+
7+
The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. In this example, we use it to implement different attack strategies that a character can switch between during gameplay.
8+
9+
## Implementation
10+
11+
- [`IAttackStrategy.cs`](IAttackStrategy.cs): Base interface for all attack strategies
12+
- [`Character.cs`](Character.cs): Context class that uses the strategies
13+
- Strategies:
14+
- [`MeleeAttackStrategy.cs`](Strategies/MeleeAttackStrategy.cs): Close-range attack
15+
- [`RangedAttackStrategy.cs`](Strategies/RangedAttackStrategy.cs): Long-range attack
16+
- [`AreaAttackStrategy.cs`](Strategies/AreaAttackStrategy.cs): Area-of-effect attack
17+
18+
## Usage
19+
20+
```csharp
21+
// Add Character component to a GameObject
22+
Character character = gameObject.AddComponent<Character>();
23+
24+
// Switch between different attack strategies
25+
character.SetAttackStrategy(new MeleeAttackStrategy());
26+
character.SetAttackStrategy(new RangedAttackStrategy());
27+
character.SetAttackStrategy(new AreaAttackStrategy());
28+
29+
// Perform attack with current strategy
30+
character.PerformAttack();
31+
```
32+
33+
## Benefits
34+
35+
- Easy to add new attack strategies
36+
- Switch strategies at runtime
37+
- Clean separation of attack algorithms
38+
- Encapsulated attack behavior
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using UnityEngine;
2+
3+
namespace UnityCheatSheet.Patterns.StrategyPattern.Strategies
4+
{
5+
public class AreaAttackStrategy : IAttackStrategy
6+
{
7+
private readonly float damage = 10f;
8+
private readonly float range = 5f;
9+
10+
public void Attack(Transform attacker, Transform target)
11+
{
12+
Debug.Log($"Performing area attack at {attacker.position} with radius {range}!");
13+
Debug.Log($"All enemies within range take {damage} damage!");
14+
}
15+
16+
public float GetDamage() => damage;
17+
public float GetRange() => range;
18+
}
19+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using UnityEngine;
2+
3+
namespace UnityCheatSheet.Patterns.StrategyPattern.Strategies
4+
{
5+
public class MeleeAttackStrategy : IAttackStrategy
6+
{
7+
private readonly float damage = 20f;
8+
private readonly float range = 2f;
9+
10+
public void Attack(Transform attacker, Transform target)
11+
{
12+
if (Vector3.Distance(attacker.position, target.position) <= range)
13+
{
14+
Debug.Log($"Performing melee attack for {damage} damage!");
15+
}
16+
else
17+
{
18+
Debug.Log("Target is too far for melee attack");
19+
}
20+
}
21+
22+
public float GetDamage() => damage;
23+
public float GetRange() => range;
24+
}
25+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using UnityEngine;
2+
3+
namespace UnityCheatSheet.Patterns.StrategyPattern.Strategies
4+
{
5+
public class RangedAttackStrategy : IAttackStrategy
6+
{
7+
private readonly float damage = 15f;
8+
private readonly float range = 10f;
9+
10+
public void Attack(Transform attacker, Transform target)
11+
{
12+
if (Vector3.Distance(attacker.position, target.position) <= range)
13+
{
14+
Vector3 direction = (target.position - attacker.position).normalized;
15+
Debug.Log($"Firing projectile in direction {direction} for {damage} damage!");
16+
}
17+
else
18+
{
19+
Debug.Log("Target is out of range for ranged attack");
20+
}
21+
}
22+
23+
public float GetDamage() => damage;
24+
public float GetRange() => range;
25+
}
26+
}

README.md

Lines changed: 16 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -869,77 +869,33 @@ public class StateMachine : MonoBehaviour {
869869
```
870870

871871
### Strategy Pattern
872-
```csharp
873-
// Strategy interface
874-
public interface IAttackStrategy {
875-
void Attack(Transform attacker, Transform target);
876-
}
872+
The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. This pattern lets the algorithm vary independently from clients that use it.
877873

878-
// Concrete strategy classes
879-
public class MeleeAttackStrategy : IAttackStrategy {
880-
public void Attack(Transform attacker, Transform target) {
881-
float meleeRange = 2f;
882-
if (Vector3.Distance(attacker.position, target.position) <= meleeRange) {
883-
Debug.Log("Performing melee attack!");
884-
// Implement melee attack logic here
885-
} else {
886-
Debug.Log("Target is too far for melee attack");
887-
}
888-
}
889-
}
874+
> 📘 **See the detailed example: [Strategy Pattern - Combat System Example](Patterns/StrategyPattern/README.md)**
875+
> A complete example showing how to implement a combat system using the Strategy Pattern.
890876
891-
public class RangedAttackStrategy : IAttackStrategy {
892-
public void Attack(Transform attacker, Transform target) {
893-
Debug.Log("Performing ranged attack!");
894-
// Implement ranged attack logic here, e.g., instantiate a projectile
895-
}
877+
#### Basic Example
878+
```csharp
879+
// Strategy interface
880+
public interface IStrategy {
881+
void Execute();
896882
}
897883

898-
public class AreaOfEffectAttackStrategy : IAttackStrategy {
899-
public void Attack(Transform attacker, Transform target) {
900-
Debug.Log("Performing area of effect attack!");
901-
// Implement AoE attack logic here, e.g., create an explosion effect
902-
}
884+
// Example strategy implementation
885+
public class AttackStrategy : IStrategy {
886+
public void Execute() => Debug.Log("Performing attack!");
903887
}
904888

905889
// Context class that uses the strategy
906890
public class Character : MonoBehaviour {
907-
private IAttackStrategy attackStrategy;
908-
public Transform target;
891+
private IStrategy strategy;
909892

910-
public void SetAttackStrategy(IAttackStrategy strategy) {
911-
attackStrategy = strategy;
893+
public void SetStrategy(IStrategy newStrategy) {
894+
strategy = newStrategy;
912895
}
913896

914-
public void PerformAttack() {
915-
if (attackStrategy != null && target != null) {
916-
attackStrategy.Attack(transform, target);
917-
}
918-
}
919-
}
920-
921-
// Usage example
922-
public class GameManager : MonoBehaviour {
923-
public Character character;
924-
925-
private void Start() {
926-
character.SetAttackStrategy(new MeleeAttackStrategy());
927-
}
928-
929-
private void Update() {
930-
if (Input.GetKeyDown(KeyCode.M)) {
931-
character.SetAttackStrategy(new MeleeAttackStrategy());
932-
}
933-
else if (Input.GetKeyDown(KeyCode.R)) {
934-
character.SetAttackStrategy(new RangedAttackStrategy());
935-
}
936-
else if (Input.GetKeyDown(KeyCode.A)) {
937-
character.SetAttackStrategy(new AreaOfEffectAttackStrategy());
938-
}
939-
940-
if (Input.GetKeyDown(KeyCode.Space)) {
941-
character.PerformAttack();
942-
}
897+
public void ExecuteStrategy() {
898+
strategy?.Execute();
943899
}
944900
}
945901
```

0 commit comments

Comments
 (0)