Skip to content

Commit 0411932

Browse files
committed
Started adding spatial partition
1 parent 287c929 commit 0411932

12 files changed

+827
-0
lines changed

Assets/Patterns/19. Spatial Partition.meta

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/Patterns/19. Spatial Partition/Grid.meta

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/Patterns/19. Spatial Partition/Grid/Scripts.meta

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace SpatialPartition.Grid
6+
{
7+
//Implementation of the Spatial Partion pattern from the book Game Programming Patterns
8+
public class GameController : MonoBehaviour
9+
{
10+
11+
void Start()
12+
{
13+
14+
}
15+
16+
17+
void Update()
18+
{
19+
20+
}
21+
}
22+
}

Assets/Patterns/19. Spatial Partition/Grid/Scripts/GameController.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace SpatialPartition.Grid
6+
{
7+
//The grid class which will also handle fighting
8+
public class Grid
9+
{
10+
public const int NUM_CELLS = 10;
11+
12+
public const int CELL_SIZE = 20;
13+
14+
private Unit[,] cells = new Unit[NUM_CELLS, NUM_CELLS];
15+
16+
//If two units are within this distance they can attack each other
17+
private const float ATTACK_DISTANCE = 0.5f;
18+
19+
20+
21+
public Grid()
22+
{
23+
//Clear the grid
24+
for (int x = 0; x < NUM_CELLS; x++)
25+
{
26+
for (int y = 0; y < NUM_CELLS; y++)
27+
{
28+
cells[x, y] = null;
29+
}
30+
}
31+
}
32+
33+
34+
35+
//Add unit to grid
36+
//This is also used when a unit already on the grid is moving into a new cell
37+
public void Add(Unit newUnit)
38+
{
39+
//Determine which grid cell it's in
40+
Vector2Int cellPos = ConvertFromWorldToCell(newUnit.transform.position);
41+
42+
//Add the unit to the front of list for the cell it's in
43+
newUnit.prev = null;
44+
newUnit.next = cells[cellPos.x, cellPos.y];
45+
46+
//Associate the cell with this unit
47+
cells[cellPos.x, cellPos.y] = newUnit;
48+
49+
//If there already was a unit in this cell, it should point to the new unit
50+
if (newUnit.next != null)
51+
{
52+
Unit nextUnit = newUnit.next;
53+
54+
nextUnit.prev = newUnit;
55+
}
56+
}
57+
58+
59+
60+
//Move a unit on the grid
61+
public void Move(Unit unit, Vector3 newPos)
62+
{
63+
//See what cell it was in
64+
Vector2Int oldCellPos = ConvertFromWorldToCell(unit.transform.position);
65+
66+
//See which cell it's moving to
67+
Vector2Int newCellPos = ConvertFromWorldToCell(newPos);
68+
69+
//TODO: Validate if this is a valid cell pos
70+
71+
unit.transform.position = newPos;
72+
73+
//If it didn't change cell, we are done
74+
if (oldCellPos.x == newCellPos.x && oldCellPos.y == newCellPos.y)
75+
{
76+
return;
77+
}
78+
79+
//Unlink it from the list of its old cell
80+
UnlinkUnit(unit);
81+
82+
//If this unit is the head of a linked-list in this cell, remove it
83+
if (cells[oldCellPos.x, oldCellPos.y] == unit)
84+
{
85+
cells[oldCellPos.x, oldCellPos.y] = unit.next;
86+
}
87+
88+
//Add it back to the grid at its new cell
89+
Add(unit);
90+
}
91+
92+
93+
94+
//Unlink a unit from its linked list
95+
private void UnlinkUnit(Unit unit)
96+
{
97+
if (unit.prev != null)
98+
{
99+
//The previous unit should get a new next
100+
unit.prev.next = unit.next;
101+
}
102+
103+
if (unit.next != null)
104+
{
105+
//The next unit should get a new prev
106+
unit.next.prev = unit.prev;
107+
}
108+
}
109+
110+
111+
112+
//Help method to convert from Vector3 to cell pos
113+
public Vector2Int ConvertFromWorldToCell(Vector3 pos)
114+
{
115+
//Dividing coordinate by cell size converts from world space to cell space
116+
//Casting to int converts from cell space to cell index
117+
int cellX = (int)(pos.x / CELL_SIZE);
118+
int cellY = (int)(pos.z / CELL_SIZE); //z instead of y because y is up in Unity's coordinate system
119+
120+
Vector2Int cellPos = new Vector2Int(cellX, cellY);
121+
122+
return cellPos;
123+
}
124+
125+
126+
127+
//
128+
// Fighting
129+
//
130+
131+
//Make the units fight
132+
public void HandleMelee()
133+
{
134+
//Loop through all cells
135+
for (int x = 0; x < NUM_CELLS; x++)
136+
{
137+
for (int y = 0; y < NUM_CELLS; y++)
138+
{
139+
HandleCell(new Vector2Int(x, y));
140+
}
141+
}
142+
}
143+
144+
145+
146+
//Handles fight for a single cell
147+
private void HandleCell(Vector2Int cellPos)
148+
{
149+
Unit unit = cells[cellPos.x, cellPos.y];
150+
151+
//Make each unit fight all other units once in this cell
152+
//It works like this: If the units in the cell are linked like: A-B-C-D
153+
//We always start with the first unit A, which we get from the cells[x, y]
154+
//Loop 1: A vs B, C, D. Change to unit B
155+
//Loop 2: B vs C, D. Change to unit C. (A-B where fighting in round 1, so they dont need to fight again)
156+
//Loop 3: C vs D. Change to unit D (C-A and C-B have already been fighting)
157+
//Loop 4: unit will be null so the loop will terminate
158+
while (unit != null)
159+
{
160+
//Try to fight other units in this cell
161+
HandleUnit(unit, unit.next);
162+
163+
//We also should try to fight units in the 8 surrounding cells because some of them might be within the attack distance
164+
//But we cant check all 8 cells because then some units might fight each other two times, so we only check half (it doesnt matter which half)
165+
//We also have to check that there's a surrounding cell because the current cell might be the border
166+
//This assumes attack distance is less than cell size, or we might have to check more cells
167+
if (cellPos.x > 0 && cellPos.y > 0)
168+
{
169+
HandleUnit(unit, cells[cellPos.x - 1, cellPos.y - 1]);
170+
}
171+
if (cellPos.x > 0)
172+
{
173+
HandleUnit(unit, cells[cellPos.x - 1, cellPos.y - 0]);
174+
}
175+
if (cellPos.y > 0)
176+
{
177+
HandleUnit(unit, cells[cellPos.x - 0, cellPos.y - 1]);
178+
}
179+
if (cellPos.x > 0 && cellPos.y < NUM_CELLS - 1)
180+
{
181+
HandleUnit(unit, cells[cellPos.x - 1, cellPos.y + 1]);
182+
}
183+
184+
unit = unit.next;
185+
}
186+
}
187+
188+
189+
190+
//Handles fight for a single unit versus a linked-list of units
191+
private void HandleUnit(Unit unit, Unit other)
192+
{
193+
while (other != null)
194+
{
195+
//Make them fight if they have similar position - use square distance because it's faster
196+
if ((unit.transform.position - other.transform.position).sqrMagnitude < ATTACK_DISTANCE * ATTACK_DISTANCE)
197+
{
198+
HandleAttack(unit, other);
199+
}
200+
201+
other = other.next;
202+
}
203+
}
204+
205+
206+
207+
//Handles attack between two units
208+
private void HandleAttack(Unit one, Unit two)
209+
{
210+
//Insert fighting mechanic
211+
Debug.Log("Two units are fighting! monkaS");
212+
}
213+
}
214+
}

Assets/Patterns/19. Spatial Partition/Grid/Scripts/Grid.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace SpatialPartition.Grid
6+
{
7+
//Code for one unit on a grid
8+
public class Unit : MonoBehaviour
9+
{
10+
//The body is child to an empty game object
11+
public GameObject unitBody;
12+
13+
private Grid grid;
14+
15+
//Pointers to other units so we can put them in a doubly-linked-list
16+
//We dont want these to show up in the inspector
17+
[System.NonSerialized] public Unit prev;
18+
[System.NonSerialized] public Unit next;
19+
20+
//So we can change the unit's color
21+
private MeshRenderer meshRenderer;
22+
23+
private Color unitColor;
24+
25+
26+
27+
public void InitUnit(Grid grid, Vector3 startPos)
28+
{
29+
this.grid = grid;
30+
31+
transform.position = startPos;
32+
33+
prev = null;
34+
next = null;
35+
36+
//Add the unit to the grid
37+
grid.Add(this);
38+
39+
meshRenderer = unitBody.GetComponent<MeshRenderer>();
40+
41+
//Give it a random color
42+
unitColor = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 1f);
43+
44+
LookingForFight();
45+
}
46+
47+
48+
public void Move(Vector3 newPos)
49+
{
50+
//transform.position = newPos;
51+
52+
grid.Move(this, newPos);
53+
}
54+
55+
56+
//To see that the unit is fighting we change the color
57+
public void Fight()
58+
{
59+
meshRenderer.sharedMaterial.color = Color.red;
60+
}
61+
62+
public void LookingForFight()
63+
{
64+
meshRenderer.sharedMaterial.color = unitColor;
65+
}
66+
}
67+
}

Assets/Patterns/19. Spatial Partition/Grid/Scripts/Unit.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)