#i m not sure i have the capacity to

1 messages Β· Page 1 of 1 (latest)

stark shore
#

Can you show the type definition for TileType?

warm vapor
#

one sec

#

so i'm trying to use T as my switch conditional

#

essentially

#

in general i need a way to be able to say "if <T>"

#

and i don't now

stark shore
#

T needs to be a concrete type

warm vapor
#

it should be though, they're assigned by the palette as one of my tile types like grass, etc

stark shore
#

What is one of those types you are trying to check for?

warm vapor
#

flowWater

#

grass

#

dirt

stark shore
#

Yeah but what are those? Classes? Part of an enum?

warm vapor
#

the names of sprites before i dragged them to the palette. they're then converted into TileBase T

#

i just don't know how to supply another T to compare the tilebase's T to

stark shore
#

Can you show the inspector of one of your tiles?

warm vapor
#

sure anything you need

stark shore
#

Unity cannot create a new concrete implementation for a generic type from you just dragging something in the inspector, that would require code generation

warm vapor
#

are you familiar with the tilebase tilemaps thing? i'm not very, but it's part of the functionality. idk how it works behind the scenes, i'm just saying that you create the template by dragging the sprites, which creates an asset. unity then references each of those as having a Type <T>

stark shore
#

Yes, I use them a lot myself.

#

The asset you create is usually just a Tile, which inherits TileBase

#

Select a tile in the inspector, it will tell you the type at the top

warm vapor
#

ok, hang on

stark shore
warm vapor
stark shore
#

As you can see, it says dirt (Tile)

#

Meaning the dirt asset is an instance of the Tile class

warm vapor
#

ok. so then how would i create a reference to compare a given tile to

stark shore
#

There's a few options. It kind of depends on what you want to do gameplay wise

#

You can either get a reference to all the different tiles, or you can implement your functionality on top of a custom tile type

warm vapor
#

simply put: terraria with other stuff

stark shore
#

In this case you basically want to add, "additional" information to each tile, correct?

warm vapor
#

i'm in the middle of trying to make a process to make water work. first is looking at extant tiles and making a dictionary of vector3ints with their data, then is to look over that and start making changes. the issue i'm running into is in the first part. i'm hoping to be able to grab the actual tile as i do a foreach (bounds etc) and then use that information as the conditional for a switch to add other info depending on which type it is

#

yeah exactly

stark shore
#

The two options are roughly as follows:

  1. Store a reference to the tile types you want to check.
    For example, set the tiles you have in the inspector, e.g.
[SerializeField] private TileBase _waterTile;
...
TileBase tile = TileMap.GetTile(position);
if (tileBase == _waterTile) 
{
  //do something relating to water here
}
  1. The other option is to write a custom tile type that has the information you need, and then read that in your code
warm vapor
#

i started w/ strategy 2 and it just seemed less useful. but the first seems good. let me try #1 out again but i thought i tried that once

stark shore
#

I would recommend the second option, as you will eventually need to write custom tiles in a tile based game

#

Especially if gameplay data is tied to those tiles

#

It's very useful

warm vapor
#

ok so the way i was doing it was basically to associate scriptable objects. can't remember the exact method off the top of my head but is that more or less what you're talking about?

#

when i painted them they had the SOs already on them

#

or are you saying you can create a whole tile with custom fields

stark shore
#

TileBase is a ScriptableObject

#

I'll write you some code as an example for a custom tile

warm vapor
#

ah man we're getting above my head here. i've only been doing unity a couple months total and half of that was 3d MLAgents stuff, totally different

#

didn't use SOs

#

thank you

stark shore
# warm vapor didn't use SOs

I would get familiar with them, they are very useful, and you are already using them. As I mentioned, the tiles you currently have are scriptable objects

warm vapor
#

i'll take a few hours to go over some docs and videos. anything you suggest in particular?

stark shore
#

I think you will understand it a lot more from this example I will show you in a second

warm vapor
#

ok no rush, ty πŸ™‚

stark shore
#
[CreateAssetMenu(menuName = "Tiles/TerrariaTile")]
public class TerrariaTile : Tile
{
    public enum TileType
    {
        Water,
        Dirt,
        Rock
    }

    [SerializeField] private TileType _tileType;

    public TileType Type => _tileType;
}
#

This gives you the option to create a new asset type:

#

And on these tiles, you can now set the defined data:

#

This data can be checked in your code

#

e.g.

var tile = TileMap.GetTile(position) as TerrariaTile; //Assume all tiles are of type TerrariaTile
if (tile.Type == TerrariaTile.TileType.Water)
{
  //do something here
}
#

You can then also use a switch case here:

switch (tile.Type):
  case TerrariaTile.TileType.Water:
    //...
    break
#

To use the tile in the tile palette, you just need to drag the TerrariaTile asset you create (e.g. dirt) onto a square in the pallette, then you can draw it on the tilemap

warm vapor
#

what does => do?

stark shore
#

It's C# shorthand for a Get only property

warm vapor
#

ah

stark shore
#

It's the same as:

public TileType Type
{
  get => _tileType;
}
#

(since you probably don't want outside code being able to change the tile's type)

warm vapor
#

ah so i put in the custom tiles on the palette instead of the other ones

stark shore
#

Exactly

warm vapor
#

that's amazing

stark shore
#

Anything that inherits TileBase can be put on the canvas iirc

warm vapor
#

yes, this is extremely useful

stark shore
#

You can store any data you want here, e.g. drop tables, max health, etc

warm vapor
#

sick

stark shore
#

Just note that this data is not unique per tile

#

For example, you cannot use this to store the current health of a tile

#

All tiles of the same type share the instance of the scriptable object

warm vapor
#

ok that's fine bc i already have a process started to keep track of all that. being able to set specific info like that is definitely going to solve the issue and do a lot more though, from the looks of it

stark shore
#

A better example for a use-case would be a game object that is created when the tile is destroyed

warm vapor
#

i actually would like to get you to look at this, but it's in the middle of major construction so would be too confusing. will you be around in like an hour you think?

stark shore
#

It's 4am here so I was just planning to go to bed, but I'm here every day. Just write in this thread if you have any questions and I'll try to answer when I see it

warm vapor
#

thank you very much that would be really appreciated. this thread won't close on its own?

stark shore
#

I actually have no idea πŸ˜…

warm vapor
#

lol io should at least screenshot what you wrote then.

stark shore
#

It seems to stay open for 24 hours, after which point it is archived, meaning you can still access it by going to the original message where it was created

warm vapor
#

you mind if i message you later if it does close then?

stark shore
#

Sure, go ahead

warm vapor
#

alright thanks again. have a nice night!

stark shore
warm vapor
#

are you still here? i'm wondering if i'm better off actually filling empty tiles, at least ones that i encounter, with a custom 'empty' tile or if i'm better off just leaving them null. in your experience. as i said it's terraria-esque so there will be tiles coming and going all the time

stark shore
#

Why would you want to fill them with empty tiles?

#

Since null is essentially just that

warm vapor
#

idk

#

no actual reason at the moment just wondered if other ppl had found one

#

er, you had

#

sorry i had assumed you went to bad my bad

#

i got all my tiles set up though

stark shore
#

It's now 5am ☠️ ill check back tommorrow

warm vapor
#

lmao, sleep well

#

sorry for missing you πŸ™‚

warm vapor
#

looks like you're still away, but here's my very updated code. http://pastie.org/p/3ASnba1f7DMXzI08m49fbI it's working fine for Start() but errors out on update at 49 (our old friend) for tile 3,0,0. most of the script seems to be working right, but 3,0,0 shouldn't be still on the active tiles list, and i'm wondering if maybe there's some issues going on with my not timing these reads/write correctly for unity so it gets confused. any help would be very appreciated!

#

the other lists seem to be working (although i haven't gone through and checked grid coordinates, but there's the right # of them given the context)

#

actually i take that back, the 3,0,0 is erroneous with just start(). it flows correctly and is deleted correctly, but still is on activeList...hmm

stark shore
#

Hard for me to say, but I don't see anything wrong in relation to unity, so it is probably just a logic error somewhere. I recommend you use an enum instead of integers for tiletypes though

warm vapor
stark shore
#

an enum is just a number, so you can do both with the enum if you really want to

warm vapor
#

for some reason when the context to use the enum comes up, it gives the name instead of the integer, which is why i named them things like zeroEmpty oneGrass fiveStone etc

stark shore
#

Although I don't really see the point, it's just more error prone

warm vapor
#

are you saying i can just replace fiveStone with 5 and it will work?

#

when i use the enum i mean

stark shore
#

Why are you trying to use numbers for this in the first place?

#

I feel like Stone is easier to remember and gives more intention than 5

warm vapor
#

easier to convert across types

#

basically

stark shore
#

How is it easier?

warm vapor
#

so i can just say if this.5 == this.5 instead of trying to use all the enum logic that i barely understand

#

it's just easier for me to do all that IN the enum

#

er that.5

stark shore
#

You can check enum type just like anything else.
e.g. if (tile.Type == TileType.Stone) //do something if it is a stone

warm vapor
#

i'm just saying it's a lot easier for me to conceptualize a tiletypeint than enums, idk

stark shore
#

I certainly recommend you read up on them, they are very useful πŸ˜…

warm vapor
#

i can always convert once i understand it better.. it seems clunks idk

stark shore
#

c-style "enums" (basically constants) is something that isn't really used a lot anymore, with good reason

warm vapor
#

clunky.. but yeah it's probably just my ignorance

stark shore
#

Enums also specifically let you set the numbers per value, and even let you have a single value be "multiple" types

#

e.g.

[System.Flags]
enum MultiTileType
{
  None = 0,
  Stone = 1,
  Water = 2,
  StoneAndWater = Stone | Water
}
warm vapor
#

i actually did do that. it's in CreateTileEntry or whatever... i guess i just never tried to use the numbers instead of the names

#

to call

#

does the approach i'm using seem reasonable though? i was hoping to get an overall opinion on my process if you have one

stark shore
#

I don't really know what you are trying to do

#

πŸ˜…

warm vapor
#

well it's a tilemap game where i want some tiles to be active (like water) and updated on their own. this process is basically the backbone of that

stark shore
#

So you want the water to flow in a similar fashion to terraria?

warm vapor
#

for now i'm just trying to get them to make a tile below them and delete the tile if it no longer has enough water

#

yeah exactly

stark shore
#

It's the same algorithm games like noita use

warm vapor
#

yeah and i've looked at a bunch of them, and am more or less modeling after. just curious about my actual usage of C# to accomplish

#

if i'm missing anything obvious

#

or if i should take a different strategy in places

stark shore
#

It kind of depends on your map size and how performant this needs to be

warm vapor
#

i would like it to be relatively performant i guess, but it's a game like terraria. idk if that's considered performant for what it does or not tbh. if i could reach something along those lines that would be def fine.

stark shore
#

Terraria has a relatively large world, so you will at least need to do some kind of chunking system that can detect what chunks needs update. You won't want to iterate over the entire map each frame

warm vapor
#

i don't think the map size will be nearly as big as that. i would rather make stages

stark shore
#

e.g. a chunk that doesn't have any flowing water doesn't need to do anything

warm vapor
#

kind of like a largish puzzle game area

#

ok...where would i start looking into chunking?

stark shore
#

There's no real definition of it. Basically you would need to subdivide your world into some partition (e.g. 16x16 tiles), and then only update the tiles required.

#

If your map isn't very large you probably don't need to do it though

warm vapor
#

what about if i can keep it to like 200x200

#

that's still pretty big

stark shore
#

I think that should be fine, but it's hard to say

warm vapor
#

ok... well that gives me an idea at least

#

i'll just try and get it working and go back over it after if it's too slow i guess

stark shore
#

One thing to note about the tilemap system in unity, is when you are setting a large amount of tiles use the batch update methods, setting individual tiles is very slow

warm vapor
#

What is considered a large amount? I would think maybe at the VERY most it would be 500ish tiles? i'm just trying to think what a large 'lake' would be. 50x100 seems about as big as i'd go

stark shore
#

I can check how large my player view is in tiles, give me a second

warm vapor
#

awesome i fixed it by checking for a list entry before adding. i forgot they can take double values.

#

where would be a good place to put a delay in between tile 'updates' if i were to do that? the water flows at warp speed at the moment lol

#

and would the best method be yield delay? i'm gonna have to look that up but i've heard some methods can suspend threads or something so i'm just making sure

stark shore
#

I would probably add a "flow speed" to tiles, which is the required amount of update ticks a tile needs to move

warm vapor
stark shore
#

yield only works inside an IEnumerator if you are attempting to write a coroutine

warm vapor
#

is there a way to add a delay to a regular method?

stark shore
#

You can write an asynchronous method

#

Which achieves something similar to a Unity coroutine

warm vapor
#

hm.. would i be better trying to learn how to convert my EvaluateTiles method to coroutine? not really sure what that would look like...

#

it's basically iterating anyway

stark shore
#

It depends on how you want to implement your waiting

#

e.g. do you want to just not run your simulation every frame, do different tiles need different update speeds, etc

#

For example, sand falls slower than water

warm vapor
#

i just don't want the tiles to flow at warpspeed. the less fuss the better, but obviously i want to set the architecture up smartly now that the project is still smallish

#

yeah, i could see some things needing different flow speeds

stark shore
#

Then I would just set a static simulation speed, e.g. 60 times per second, and then add a flow speed to tiles, incrementing a counter per tile instance, and only if that counter exceeds the flow speed, update the tile and reset the counter

#

So if you set the flow speed of water to 60, it would "flow" once per second

warm vapor
#

ok that sounds good. can you point me to a doc on that or maybe give me an example? or both xD

stark shore
#

If you replace your Update method with FixedUpdate, the simulation will run at a fixed time step, the default is 50 times per second

#

You can set this in Edit -> Settings -> Time -> Fixed Timestep

warm vapor
#

oh nice. is using a divisible number like 64 a good idea or no?

stark shore
#

It doesn't make a difference

warm vapor
#

not even to having some kind of matching with fps?

stark shore
#

You can't really predict your FPS

warm vapor
#

oh good point.

#

alright sounds good thank you. so once i've got a fixed update, what's the syntax for waiting a portion of that time?

stark shore
#

Just watch out that this update value is also the update speed of the physics system, if you are using it

warm vapor
#

is it bad to use both update and fixedupdate? my understanding was "fixedupdate is for physics" and "update is for other things" more or less

stark shore
#

It doesn't matter. It just depends on if you want your logic to run at a fixed timestep, or if you want it to run when the game refreshes (which can be limited by things like VSync)

#

The fixed time step will always be the same, while the update speed will vary vastly from machine to machine

warm vapor
#

alright, i'm not even close to that fussy in this game. just as long as unity doesn't get confused i'm good

#

so what is the command to wait during the fixedupdate? sorry for repeat xD

#

er i mean alongside

stark shore
#

The positions in the array correspond to the tiles on the tilemap

warm vapor
#

so each fixedupdate i increment each counter until it exceeds whatever i set

stark shore
#

For example. There are multiple ways to achieve this, but that's how I would do it

warm vapor
#

i believe i'm following.. please continue πŸ™‚

#

oh

#

nvmd lol i misread

#

ok yeah that seems like it should work

#

just put that array in the main class with my other lists?

stark shore
#

My game runs at 100+ FPS at 368x160 tiles, and these aren't static, so you should be fine

warm vapor
#

nice, yeah that's more than performant enough

stark shore
#

I also use the Z axis on the tilemap so it's actually more than that

#

I recommend you do use chunk rendering on the tilemap, since that significantly improves performance

warm vapor
#

your project does?

stark shore
#

Yes

#

It changes the internal rendering to use a lot less draw calls, instead of 1 draw call per tile

#

You can set it on the tilemap renderer component:

warm vapor
#

so let me resummarize. i'm making an array of values that correspond to each tile that is 'active', and on each fixedUpdate, i iterate the value ++. then when the value exceeds the 'flowspeed' of the custom tile type, i tell my code to actually move the tile and whatnot

#

?

stark shore
#

Like I mentioned, there's a million ways to do this, that's how I would do it

warm vapor
#

cool, just making sure i understand

stark shore
#

You will probably need an array that contains information per tile anyways, so you can just write your current counter value there

warm vapor
#

i'm storing them in a dictionary. is it slow to iterate the dictionary that often?

#

i mean the stuff in the dict

stark shore
#

An array is a lot faster

warm vapor
#

ok i'll figure something out with an array then. thank you so much for all the help (again). i definitely have plenty to go on here i think.

#

oh one question: the chunk rendering you showed me. does that require a change in the code as well or is it really just changing it in inspector?

stark shore
stark shore
# warm vapor ok i'll figure something out with an array then. thank you so much for all the ...

If I were to implement a prototype for this, I would start with a much simpler version than what you have done:
Basically a struct that contains the instance information for each tile:

public struct TileData
{
  public int FlowCounter;
  //other stuff
  public void Tick()
  {
    FlowCounter++;
  }
}

public TileData[] _tileData = new TileData[TileMapWidth * TileMapHeight];

Then I would iterate that each fixed update:

for (int i = 0; i < _tileData.Length; i++)
  _tileData[i].Tick();

Then grab all tiles from the tilemap:

public TileBase[] _tiles = new TileBase[TileMapWidth * TileMapHeight];
...
TileMap.GetTilesBlockNonAlloc(new BoundsInt(0, 0, TileMapWidth, TileMapHeight), _tiles);

for (int i = 0; i < _tileData.Length; i++)
{
  //decide how to update the visuals of the tilemap according to its data here
}

TileMap.SetTilesBlock(new BoundsInt(0, 0, TileMapWidth, TileMapHeigh), _tiles);
warm vapor
#

hm i think i'm understanding

#

sorta

#

and you think doing that is more performant than just keeping track of tiles of a certain type?

stark shore
#

It depends a lot on the setup, it's hard to say

#

The easiest thing to optimize here is storing tile data as a struct in an array

#

And using SetTilesBlock instead of SetTile

warm vapor
#

hmm... how would i go about in the bottom part updating the visuals as you suggested? is that using setTile or some other method? sorry i'm pretty new to tilemaps so it's all a bit confusing

stark shore
#

My example is lazy and sets the entire tilemap each frame, you can only set a subsection of it to improve performance even more

warm vapor
#

the irony is i started with a struct and converted it all to class

stark shore
#

this TileMap.GetTilesBlockNonAlloc(new BoundsInt(0, 0, TileMapWidth, TileMapHeight), _tiles); copies each tile in the tilemap into the array

#

You can then modify all enties in the array

#

and write them back with TileMap.SetTilesBlock(new BoundsInt(0, 0, TileMapWidth, TileMapHeigh), _tiles);

warm vapor
#

so i can do a foreach with that? i guess i'm not sure how i would go about actually setting the new tile w/ the data

#

once i grab the tilemap data

stark shore
#

It's not super straightforward since a part of the falling sands algorithm is deciding what to do when two tiles "merge"

#

e.g. in a single update two water tiles fall to the same position

warm vapor
#

yeah, i've already sort of run into that. just decided to cheat with arbitrary cutoff points basically lol

#

until it's more built at least

stark shore
#

There's different ways to work with it, e.g. store a byte per water tile that indicates how "filled" that tile is with water, and if two water tiles collide, they fill, and if they overfill, they split their overflow value to the tiles left and right for example

warm vapor
#

so if i replace my cellData class with a nearly identical cellData struct...is there going to be issues? what might i not be anticipating? i just don't really understand structs which is why i switched to class

#

obviously i need to declare my variables and dicts differently... but beyond that...?

stark shore
#

It's complicated to explain easily since it requires a good grasp of computer science knowledge, but the gist of it is this:

  1. structs are allocated on the stack, classes are allocated on the heap
  2. this makes structs faster for simple data storage since they are layed out linearly in memory, which helps cache coherency immensely
  3. this makes structs better for video game development since they are not managed by the garbage collector, meaning less garbage collector stalls
  4. structs are much more limited in what they can do compared to classes
  5. structs are copied entirely when passing the variable, while a class copies the reference to the memory location on the heap (meaning you modify the same instance, instead of copying it)
#

This is the reason why unity math types are all structs, e.g. Vector2, Vector3, etc

warm vapor
#

i actually watched a few hours on structs and the heap/stack thing so i sorta know what you mean. i am just mainly asking in practical terms as far as my script and what i'm trying to accomplish here. i make regular backups so i can def experiment...

#

like as far as breaking my script more or less

stark shore
#

As long as you don't try to store the struct anywhere (e.g. by adding it to different collections) then you should be fine

#

Basically store all your tile data in one array and update that array

warm vapor
#

Can I use a list? why array?

stark shore
#

You have a fixed world size, why do you want to use a list

warm vapor
#

out of range exceptions scare me lol idk i just found them slightly easier to manage i guess

stark shore
#

You can get out of range exceptions with a list πŸ˜…

warm vapor
#

hmm.. why was it

#

oh, adding to the size!

stark shore
#

You cannot expand the capacity of an array

warm vapor
#

exactly... but you need to be adding tiles to it all the time so why would you choose that? i just don't quite understand

stark shore
#

Why do you need to "add" tiles when you have a fixed world size?

#

The array already has a "spot" in it for each tile you could add

#

That's why the size is set to new TileData[TileMapWidth * TileMapHeight]

warm vapor
#

ah. the strategy i was using only had data for tiles that actually had been drawn

#

and deleted them after they were moved

stark shore
#

That will be a lot slower than just having all of your possible data in an array

warm vapor
#

hm, ok

stark shore
#

With your dimensions it probably won't matter though, I doubt you need to optimize much for a tilemap of size 200x200

#

That's 40000 tiles, arrays can easily be multiple million entries long

#

This really only becomes an issue if you world is exceedingly large

#

My game world is 134217728 "tiles" large (1024*512*16*16), which I cannot put into an array without running out of memory

warm vapor
#

out of curiosity, just how much slower are dicts than arrays? would it, for example, be a bad idea to index all 40,000 of the tiles in a dictionary (just hypothetical)

stark shore
#

For your sizes it's not an issue. Access to a specific key is slower, because GetHashCode needs to be run on your key. You are basically trading performance for memory. The dictionary uses less memory, but is slower to access and slower to read

warm vapor
#

ok... i will definitely experiment with arrays, but i find the key value pairing really useful. that other strategy seems interesting as well but almost like it should be a different project or just an overhaul version. i'm still using this to learn too so i don't mind trying one thing and seeing then fiddling later...

stark shore
#

The way you write your code for an array or dictionary is very similar. You just write a helper function to convert your 2D coordinate to the 1D index in the array
e.g. int Index2Dto1D(int x, int y, int size) => y * size + x;

#

And then do _tileData[Index2DTo1D(xPosition, yPosition, _tileData.Length)]

warm vapor
#

helper function i'm gonna have to write that down lol

#

that sounds basic xD

#

wait, is that a formula to create an index for a coordinate? i'm not quite following

#

i tried to figure that out for like 5 hours lol

warm vapor
#

damn i even looked on google and math ppl were saying it is impossible so i gave up

stark shore
#

If you want it even more easy to use, you can write an extension function
e.g. static T From2D<T>(this T[] arr, int x, int y) => arr[y * arr.Length + x];

#

Then you can do _tileData.From2D(xPosition, yPosition);

#

And your set function would be static T Set2D<T>(this T[] arr, int x, int y, T value) => arr[y * arr.Length + x] = value;

warm vapor
#

well that's awesome. yeah i distinctly remember running into this roadblock now. i think that's why i went dicts actually.

stark shore
#

(again it's a tradeoff between memory and speed)

warm vapor
#

this is really nice to know though.

stark shore
#

If you tried to store only a single integer at the tilemap size I mentioned earlier, it would require 536 megabytes of memory, so not really feasible

warm vapor
#

what is the int size in your conversion formula?

stark shore
#

The length of the array

warm vapor
#

oh, right

stark shore
#

Oh wait, my bad

#

This won't actually work for you

#

It needs to be one dimension of your tilemap

#

The width ideally

warm vapor
#

oh, yeah... i think that's what they were saying on the math forum lol

stark shore
#

The extension function won't work then, since it needs to be passed the width in addition to that

warm vapor
#

the way i did it was literally just counting each tile i make, they don't even really need an index number though with the dict

stark shore
#

You could wrap your struct in this case if you wanted to, but there are many ways to go about this

warm vapor
#

the key. right, i just mean i gave each tile a never-repeated number (for reasons lol)

stark shore
#

You can do that, but it's more complicated to upkeep

warm vapor
#

it's pointless. i'm probably going to just remove it

#

i figured might as well put it in now and remove it later if i don't use it lol. probably a few SE jokes about that exact mentality...

#

anyway thanks again i'm gonna try and get that delay system working. cheers!

stark shore
warm vapor
#

i'll give that a read. thank you.

#

that worked like a charm. one bug left but other than that it's looking really good. so exciting, thank you! gonna take a break for a bit