00:00:00
in this video we're going to take our
00:00:01
grid map and convert it to use generics
00:00:03
this gives us a lot more options with
00:00:05
what we can do rather than being stuck
00:00:07
on using a specific type with this base
00:00:09
we can easily make games like
00:00:10
minesweeper or terraria or easily
00:00:12
organized complex logic let's begin
00:00:18
[Music]
00:00:22
so why our goal here is to create a grid
00:00:25
that works with generics so we can use
00:00:26
it for just about anything if you're not
00:00:28
familiar with generics they are a really
00:00:30
awesome feature of CCR that essentially
00:00:32
lets us use any type we want so that
00:00:34
means that we can make our nice grid in
00:00:36
here and do something where each grid
00:00:38
position can hold various letters and
00:00:40
numbers so as I put the mouse over this
00:00:43
grid position and I hit a kink and there
00:00:45
you go I've added a letter into the
00:00:47
underlying grid object now I add another
00:00:50
letter now if I want I can press the
00:00:52
number and there we go it is added into
00:00:54
a different part of the same grid object
00:00:56
so I have my generic grid and each width
00:00:59
position is holding a custom parade
00:01:02
object another type is just using a
00:01:05
simple boolean so as you can see
00:01:06
everything is false and when I click it
00:01:09
turns into true and I've also modified
00:01:11
the heatmap visual Noor to work with the
00:01:13
generic with boolean so as I click it
00:01:16
turns from black to green so with
00:01:18
generics we can set up our grid to work
00:01:20
with whatever type we want that means
00:01:21
simple types like inns and bones but
00:01:23
also complex custom types that contain
00:01:25
whatever logic and data we want so
00:01:28
previously we made this nice red class
00:01:30
it splits the map area into a grid each
00:01:33
holding a specific value we also use
00:01:36
this where it wants to make a heat map
00:01:37
visual so when I click there you go the
00:01:39
underlying value changes as well as the
00:01:41
original representation so go check out
00:01:43
both those videos to better understand
00:01:45
our starting point now the underlying
00:01:47
code for all of this is over here we
00:01:50
have a grid array of ends now that work
00:01:53
great since over here the heat map is
00:01:55
based on a nice numeric value so we have
00:01:58
from 0 to 100 however in are not the
00:02:02
best datatype for every single problem
00:02:03
like for example let's say we want to
00:02:05
make a grid map for our path money so we
00:02:07
wanted to find areas which are walkable
00:02:09
in areas which are blocked technically
00:02:11
we could do that with int and use a one
00:02:14
for wanker bone and 0 for block however
00:02:16
that would be pretty messy code a better
00:02:18
approach would be to simply store a
00:02:20
boolean instead another use that
00:02:22
wouldn't be suitable for intz would be
00:02:24
if we want to store a list of objects
00:02:25
within that cell for example that's
00:02:27
exactly what I made when I created the
00:02:29
quadrant system in ECS
00:02:31
it stores how many entities are in a
00:02:33
specific quadrant so our in base
00:02:35
is a great starting point but we can
00:02:37
greatly expand what we can do with it if
00:02:39
we make it work with generics all right
00:02:42
so let's get to it
00:02:43
so here is our starting scene and here
00:02:46
in the project files I have the basic
00:02:48
grid as well as the heat map again this
00:02:51
was all fully created from scratch in a
00:02:53
previous video so check the link in the
00:02:54
description if you haven't seen it yet
00:02:56
so we're here we have a testing game
00:02:58
object that contains a testing script
00:03:00
and in here in our script you can see
00:03:03
it's very simple just on cert we are
00:03:04
instantiating our grid and we are
00:03:06
setting it on the heat map visual then
00:03:09
when we click we are adding a valley to
00:03:11
the grid which then updates the visual
00:03:13
so let's make it smaller for testing
00:03:15
okay so here is our grid and as you can
00:03:18
see it splits our world into various
00:03:20
grid cells and if I click there you go
00:03:22
I'm modifying the underlying grid as
00:03:24
well as the visual okay now what's going
00:03:26
to our grid class and okay here it is
00:03:28
now we're going to modify it in order to
00:03:30
use generics if you're not familiar with
00:03:32
generics they are a really awesome
00:03:34
feature of c-sharp when you make it
00:03:36
class you can define it to use a generic
00:03:37
and what you are saying is that you want
00:03:40
it to be usable by a multitude of types
00:03:42
if you use the list then you're already
00:03:44
familiar with generics so here for
00:03:47
example you know that making lists you
00:03:49
put lists then you put the type inside
00:03:52
then you comment something and you
00:03:54
create it so just like this we created a
00:03:57
list object that can only receive ends
00:03:59
however you can also do here is a nother
00:04:05
list except this one only works with
00:04:07
billions however both of these objects
00:04:10
use the very same base class
00:04:12
here is the pay's list class which as
00:04:14
you can see uses a generic so this is
00:04:16
what we're going to use now let's go
00:04:18
into our grid class and then here
00:04:20
instead of being just grid let's add
00:04:22
grid that receives a generic and call it
00:04:25
grid project so this means that when I
00:04:28
essentially the grid class I won't tell
00:04:30
it which type it should use so I could
00:04:32
use this same class to instantiate
00:04:33
record events or boolean or any custom
00:04:36
type I want so now here in our code and
00:04:39
let's replace all references of int on
00:04:41
our grid array and replace them with our
00:04:43
sometime so over here over here and so
00:04:46
on over here we have the ad Valley that
00:04:55
we made this but this one is specific
00:04:57
for the heatmap however in here we want
00:04:59
to create a generic grid class so we do
00:05:01
not want anything specific for the
00:05:03
heatmap so we get rid of this one and
00:05:05
also the ad Val
00:05:06
okay so only been changed to use a
00:05:08
custom grid object and here on the gate
00:05:11
Valley we have an error since we are
00:05:13
returning a default value now for the
00:05:15
integer we return the zero but in this
00:05:17
case we don't know what type we're going
00:05:18
to have so we can use the C sharp
00:05:20
keyword default in order to return the
00:05:22
default of the grid object so if our
00:05:25
grid is made up of ends this will return
00:05:27
0 if our grid is made up of boolean's
00:05:29
this will return false and if it's made
00:05:30
up of any custom type it won't return no
00:05:32
ok so that's pretty much it
00:05:34
now our grid script instead of working
00:05:37
just with ends it can work with any type
00:05:38
we want ok so let's go into our testing
00:05:41
and let's test it out instead of making
00:05:45
it just a grid let's make it a grater
00:05:47
receives boys so that's how we define it
00:05:52
that's how we instantiate it for now
00:05:54
let's comment out the heat map visual so
00:05:57
here on the grid let's make sure we are
00:05:59
enabling our debug and then here
00:06:01
everything should work since our debug
00:06:03
is using 2 string which is automatically
00:06:05
implemented in every single type so
00:06:08
instead of seeing a bunch of zeros we
00:06:09
should be able to see a bunch of false
00:06:10
let's see and yep as you can see our
00:06:13
grid is now correctly working with
00:06:15
boolean awesome so with this working now
00:06:17
let's make a different version of our
00:06:19
heat map in order to work with boolean
00:06:20
so let's duplicate our script and here
00:06:24
on let's call it heat map ball visual ok
00:06:28
so now in here instead of using a
00:06:29
regular grid let's use a grid that
00:06:32
receives a type volume then here on the
00:06:35
set read again something of type boolean
00:06:37
and down here on the update visual we
00:06:41
can't get value which since we have a
00:06:43
great work moon Bowens instead of
00:06:45
returning in in this one return a
00:06:46
boolean so we have the boolean for the
00:06:49
grid value and then we need the
00:06:51
normalize in order to define the color
00:06:52
that we're going to show so if it's true
00:06:54
let's return one F so we Green Square
00:06:57
not 0f so a Plex were okay so far so
00:07:01
good now here in the testing let's add a
00:07:03
serialize field for the heatmap boolean
00:07:05
visual and then here we can call set
00:07:10
grid and passing our newly created grid
00:07:13
and then here on the position instead of
00:07:15
setting add value we call the grid dot
00:07:18
set value on this position and let's put
00:07:21
it to true so wherever we click we are
00:07:23
changing from false to true and finally
00:07:26
here in the afternoon let's duplicate
00:07:27
this visual or our new volume video all
00:07:32
right so everything should be working
00:07:33
let's see okay know where everything is
00:07:36
false and everything is in black okay so
00:07:38
far so good now if I click yep there you
00:07:40
go that one went to phones to true and
00:07:42
the grid turned green so I can click
00:07:44
anywhere I want and turn a false into
00:07:46
true so as you can see our grid is now
00:07:49
working with boolean values so we have
00:07:51
successfully modified our grid to work
00:07:53
with a custom type and make the heatmap
00:07:55
work with that red generic awesome now a
00:07:58
boolean is a very simple type however
00:08:00
using generics we can set this to use
00:08:03
any type we want so over here let's
00:08:05
define an object that we're going to use
00:08:07
in our grid so it's simply College a
00:08:10
type heat map grid object this the
00:08:15
object that we're going to instantiate
00:08:16
on every position in our grid inside
00:08:19
let's simply and have a polygon for our
00:08:21
value any function to increase it and
00:08:27
now we can create a grid that uses this
00:08:29
specific grid map object so we can go
00:08:32
all the way up here and again it's
00:08:34
extremely simple to work with generics
00:08:36
we simply change from boolean to our
00:08:38
heat map great object and just like that
00:08:41
home of our functions in our grid now
00:08:43
work with this particular object for now
00:08:46
let's get rid of the visual just like
00:08:48
that and now if we run the code and
00:08:52
there we go we have a known error now
00:08:55
the reason is because our object is now
00:08:57
a class which is a reference type as
00:08:59
opposed to something like your boolean
00:09:00
which is a value type so that means that
00:09:03
the default value for every position on
00:09:04
our grid won't be no so if we run the
00:09:07
code with debug enabled you can see the
00:09:09
debug goes in here accesses
00:09:11
object and constitu string so if that
00:09:14
one is known we have our error so we
00:09:16
want to make sure we do two things one
00:09:18
make sure that the debug works with no
00:09:20
and to initialize our print with a
00:09:22
created object so first here on the grid
00:09:25
it's extremely simple to deal with the
00:09:27
no we just do a very simple no check so
00:09:29
we can simply use the null check
00:09:31
operator just like that on both places
00:09:33
where we are accessing the grid array so
00:09:36
even if those are no we're going to make
00:09:37
sure that we do the right thing and now
00:09:40
up here let's write some code to
00:09:42
initialize our grid so we're going to
00:09:44
cycle through the width and height and
00:09:50
now here we have our greater right
00:09:51
position and we can set our default
00:09:52
object so in here the question becomes
00:09:55
if we don't know the type how can we set
00:09:57
a correct starting object for a value
00:10:00
type we can just use our default keyword
00:10:02
but if we have a custom type we want to
00:10:05
new it so one way to solve this problem
00:10:07
is to receive a function to create the
00:10:09
grid object so here in our constructor
00:10:11
all let's receive a parameter which will
00:10:13
be a func now a func is a delegate very
00:10:17
much like the action except a func has a
00:10:19
return value so we're going to have a
00:10:21
phone that returns a tea grid object and
00:10:26
let's call this we create grid object so
00:10:29
you receive that in the constructor and
00:10:31
in here we simply use it so this
00:10:33
function will create the grid object
00:10:35
with whatever type we want so if we were
00:10:37
doing this with an int we would pass in
00:10:39
a function that would return a 0 and if
00:10:41
we're creating a grid with a custom
00:10:43
object then we can go into our testing
00:10:45
code and here we are creating this and
00:10:48
then for the func
00:10:50
let's pass in a function that simply
00:10:52
does a new our heat map grid object okay
00:10:56
so that's it
00:10:57
so now let's test any of their ego I
00:11:00
mean it's hard to read but you can
00:11:02
already see that every grid cell has an
00:11:03
object so every single grid zone
00:11:05
contains a heat map grid object instance
00:11:08
right awesome now let's make our heat
00:11:11
map grid object contain all the logic
00:11:13
necessary for our heat map so down here
00:11:15
we have our value field and we have our
00:11:18
simple add value function that just adds
00:11:20
to it now let's finish our logic so in
00:11:23
here we need a min and
00:11:24
maxximum so when we add the value we are
00:11:32
clamping it between our min and maximum
00:11:34
and then for our heat map we also need a
00:11:36
normalized time so just like that so now
00:11:43
we have this specific object type that
00:11:45
works with our generic grid and this
00:11:47
specific object holds all the logic that
00:11:49
we need in order to make our heat map so
00:11:51
that means that our grid script in here
00:11:53
is completely generic and it is
00:11:55
completely decoupled from any heat map
00:11:57
code now we can go here on to our quick
00:11:59
function and now in here we simply go
00:12:02
into our grid and we call get value pass
00:12:05
in the mouse world position this is you
00:12:08
can see returns a heat map grid object
00:12:12
and here we want our code to be nice and
00:12:15
clean so we should really rename this
00:12:17
function since we no longer work with a
00:12:19
direct Val so let's go in here and
00:12:21
rename all of these instead of being
00:12:23
valley to return get grid object alright
00:12:32
so now our function is now having more
00:12:34
appropriate name since we're working
00:12:35
with objects rather than thumbs now back
00:12:38
in the testing here we are getting our
00:12:39
grid object now again since we are using
00:12:41
a working side we need to make sure this
00:12:43
is not no and if it's not known then we
00:12:47
simply call our add value function all
00:12:50
right that's pretty much it now one more
00:12:52
thing over here on our object we can
00:12:55
override to string to return our current
00:12:57
value so just like this our automatic
00:13:02
debug won't work perfectly and now if we
00:13:05
run the code and if there we go now our
00:13:07
great show zeroes all over however the
00:13:09
grid isn't working just with basic ins
00:13:11
but rather with our custom object type
00:13:13
which inside holds an int now I have the
00:13:16
code in order to click and increase
00:13:18
however if I click and there you go
00:13:20
apparently nothing changed well the
00:13:22
reality is something did change but the
00:13:25
debug is only updating when the event is
00:13:26
fired so let's see where that event gets
00:13:29
fired so here is the grid class and here
00:13:32
is the event and if we go down here we
00:13:34
can see the event is fired right in here
00:13:36
now this works when don't
00:13:38
with simple types like ins since we want
00:13:40
to modify the value that is stored
00:13:41
directly on the grid so using simple
00:13:43
family types we would use this function
00:13:45
a lot
00:13:45
however with custom objects we want to
00:13:48
modify the values inside that object so
00:13:51
here on the testing the way we are
00:13:52
modifying is first we get the object and
00:13:54
then we modify the inside of that object
00:13:57
so that means that we end up by passing
00:13:59
this function so what we really need is
00:14:01
a function to trigger the event then
00:14:04
when something changes inside our object
00:14:06
we're going to trigger that function
00:14:12
okay so here it is we have this nice
00:14:14
function which triggers our event so now
00:14:17
over here on our heat map grid object in
00:14:20
here when we modify the event Li we want
00:14:22
to trigger that event so that means that
00:14:24
we also need a reference to our grid
00:14:26
object so this one won't require a
00:14:28
constructor okay so we receive the grid
00:14:39
in here and now we can go into add value
00:14:41
and call our trigger function except in
00:14:43
here now you can see that we need an x
00:14:45
and a y so let's receive that as well
00:14:51
okay so there it is now our grid map
00:14:53
object has all the logic related to the
00:14:56
heat map and when it adds value it
00:14:58
notifies the grid that something changed
00:15:00
so that other objects can update their
00:15:01
own State so now what we need is to make
00:15:04
sure that we call this with the
00:15:05
corrected values so let's go all the way
00:15:07
up here and here we have our grid
00:15:09
constructor and now in here we need to
00:15:11
actually know some values like the X to
00:15:13
Y in the grid in order to pass it to
00:15:15
this object some way to go into our grid
00:15:17
into the constructor modify our func in
00:15:21
here let's add a couple more parameters
00:15:22
so first our grid object will need a
00:15:25
reference to this grid so the first
00:15:27
parameter is a grid of type grid object
00:15:31
then we're going to require an end to
00:15:34
pass in our X and another end to pass in
00:15:37
our Y so this is going to be our method
00:15:40
signature for our cream grade object so
00:15:43
then down here
00:15:43
when we create we simply pass in those
00:15:45
votes so first for the grid that's this
00:15:47
one
00:15:48
then we pass in the
00:15:50
and finally the why so we pass in that
00:15:53
then here we can use that and just like
00:16:01
that
00:16:02
here is our funk method signature and we
00:16:05
pass all of it on to our constructor
00:16:07
then our constructor simply stores our
00:16:09
values and now we have enough
00:16:11
information in order to be able to call
00:16:13
this function which should update
00:16:14
everything else all right so this should
00:16:16
do it
00:16:17
let's test okay here we are and
00:16:19
everything is that you're all right now
00:16:21
if I click and there you go it correctly
00:16:23
updated the underlying Val so that means
00:16:26
that our event was correctly fired so I
00:16:28
can click on a lot of places and there
00:16:30
you go everything is correctly
00:16:31
responding to my inputs all right
00:16:33
awesome so now that this is working
00:16:36
let's make it work with the heat map
00:16:37
visual let's do the same thing again and
00:16:39
duplicate this just so we have a bunch
00:16:41
of code that we can see how we get there
00:16:53
so here I have named that heat map
00:16:55
generic visual and I've added a new game
00:16:57
object okay now here in the script first
00:17:00
we make our grid work with our heat map
00:17:03
grid object all right there it is and
00:17:08
now down here when we update our visual
00:17:10
we get a great object which returns a
00:17:12
heat map grid object and then we
00:17:16
calculate the grid value normalized
00:17:18
based on we go to this and get the value
00:17:21
normally so we access the function
00:17:23
inside our custom object type and that's
00:17:26
pretty much it
00:17:27
now this visual is working with our
00:17:29
custom grid object that we created in
00:17:31
here all right so let's test okay so
00:17:33
here we are and everything is black and
00:17:35
the debug is disabled and if I click yep
00:17:39
there you go it increased by five so it
00:17:40
went from black to red and I can keep
00:17:42
increasing becomes yellow and finally
00:17:44
becomes green so as you can see whenever
00:17:47
I click the underlying value changes
00:17:49
which then updates our visual
00:17:51
representation in order to show the
00:17:52
correct color so we made that our grid
00:17:54
worked with any object type and then we
00:17:56
created a heat map specific type to hold
00:17:58
all the heat map logic and made the
00:18:00
visual work with it so that means the
00:18:02
grid
00:18:03
completely decoupled from the heatmap
00:18:04
implementation right awesome now let's
00:18:08
look at another simple example to see
00:18:09
how we can use our grid for just about
00:18:11
anything alright so here it is I've made
00:18:26
a very nice string grid object now in
00:18:28
here you can see that I hold the string
00:18:30
14 letters in a string for the numbers
00:18:32
then I have these two functions in order
00:18:34
to add a letter or a number to it and as
00:18:37
you can see I'm overriding the two
00:18:38
string in order to display two letters
00:18:39
and then underneath the numbers so now
00:18:42
up here on testing over here you can see
00:19:03
that I'm in sending the world using our
00:19:05
new string grid object and then in here
00:19:08
I'm testing for a bunch of key presses
00:19:09
testing for some keys and then suddenly
00:19:12
calling the two separate functions so
00:19:14
let's see this in action okay here we
00:19:17
are and first of all the great shows
00:19:18
nothing since by default our string is
00:19:20
empty now let's say I put the mouse over
00:19:23
there and I press the a king and there
00:19:26
you go it added a nice character and now
00:19:29
on the same place I'm going to press B
00:19:30
and there you go it added another string
00:19:33
and now in here I'm gonna press two and
00:19:36
there you go it added a letter so as you
00:19:38
can see I'm adding values to the
00:19:40
underlying grid object and I can make
00:19:42
the grid object as complex as I want so
00:19:44
here I made at home two types of values
00:19:46
letters and numbers and every single
00:19:48
grid position in here contains its own
00:19:50
grid object so I can put a bunch of
00:19:52
letters all over and a bunch of numbers
00:19:54
all over so you can see how you can use
00:19:57
custom grid objects to add as much
00:19:59
complexity to the grid as you want now
00:20:02
we could for example use this class with
00:20:04
a simple innum to define a sprite type
00:20:06
and render the sprite on screen by doing
00:20:09
so we would essentially have a very nice
00:20:11
town map class and that's exactly what
00:20:13
we're going to do in the next video so
00:20:15
now you know
00:20:16
how generics work and how powerful they
00:20:18
can be with this class and knowledge of
00:20:20
generics you can now build just about
00:20:21
anything you want so go for it and make
00:20:24
a system that uses a very custom grid
00:20:26
object that fits perfectly within your
00:20:28
game as always you can download the
00:20:30
project fanzini tony's from in tacoma
00:20:32
comm subscribe the channel for more ent
00:20:34
tutorials post any questions you have in
00:20:36
the comments and I'll see you next time
00:20:39
[Music]
00:20:41
you