Help with TileMap interaction from left side and bottom of each tile

Thank you very much for getting back to me. I apologize for being so scattered. I am trying to put this together in my head and hopefully when I am in app I can see it coming together. While I should know how to at least do things like get the array of selected cells to remove, I find myself still stumped at those basic levels.

Like I try to make things happen that can’t. I’m going to try watching more tutorials on loops, I have seen them pop up a couple of times but they are so intimidating. I actually feel like I understand signals, at least how they operate and what they are, they were also very intimidating for a long time. Going to dig in and try figuring out.

I think one of my problems here too is I have been trying to avoid loops and get all the tiles from a single collision or with many collisioshapes. Sorry again for the clutter. Going to try getting those tiles in an array and applying what you have said here.

Appreciate you coming back again and helping me.

When you say functions, do you mean built-in functions like the tilemaps local_to_map() func? The functions you create like random_func()? Or both?

Functions are kind of important (understatement) to programming in godot. If you have any specific confusion I can try and help you understand functions better.

So, at least for func you create, they dont do anything in of themselves. You tell them what to do. They have four primary parts.

Name → some_func
Arguments → (some_value1, some_value2)
Return type → void, int, bool, ect…
Body → everything you make it do.

Name is just to communicate wjat it does, and to call it.

Args are if your func needs to know information coming from the caller, you can pass data ro the func that it then uses.

Return type is to specify what type of value it sends back to the caller, this is optional if needed like args. If you set it to a type other than void it will require you to add return (followed by a value).

The body is where your func does whatever it is you need it to.

For the example of getting the array of cells you can have two func, one destroy_cells() the other explosion_size() → Array.

In destroy_cell you call explosion_size, like this.

var tiles = explosion_size()

Now tiles will call explosion_size and store its return value of type array.

You can now use the var tiles do eliminate the tiles choses in your explosion_size().

Sorry I wasn’t able to write the code out, on my phone.

1 Like

Sorry I was actually just coming to edit my comment. I meant loops… like

for x in exp_size:
for y in exp_size:

sorry for my confusion. I appreciate you still laying this out for me. I will see if I can put it together and get some tiles blown away.

Thank you, and sorry again for my miscommunication.

Man I feel like I’m so close but missing a key element. I think I finally got the tnt scene to recognize the tilemap collisions, but when I run the explosion size function it’s telling me I have infinite recursion.

So I thought setting parameters would help and it did not. I’m just drawing blanks again. Sorry for the bother again. I know you spelled it all out for me. I feel like I’m looking right at the solution but I can’t comprehend it. If you are interested and wouldn’t mind looking, here is what I have, in the TNT script extending Characterbody2d:

var tile_map_colliders: Array = []

@onready var character_body_2d: CharacterBody2D = $CharacterBody2D

func _physics_process(delta: float) -> void:
	
	for i in get_slide_collision_count():
		var collision = get_slide_collision(i)
		var tilemap = collision.get_collider()
		if tilemap.is_in_group("MudWall"):
			tile_map_colliders.append(tilemap)
	move_and_slide()
	explosion_size()


func explosion_size():
	if tile_map_colliders.size() > 0 and tile_map_colliders.size() < 300:
		for x in explosion_size():
			for y in explosion_size():
				tile_map_colliders.append(Vector2i(x,y))
		EventController.tile_destruction.emit(tile_map_colliders, global_position)
		queue_free()

I’m sure the > and < 300 just looks so silly, I thought I was figuring it out lol and omg I just realized that I’m appending the tilemap colliders and then also below appending the vector2i of the explosion size so I am way off and it all looks silly, going to try kind of looking at it more and seeing if I can’t maybe figure how to do the collisions inside of the explosion sizebut then in the tilemap script it’s the exact same as what you put previously:

func destroy_tile(tiles, origin):
	var map_origin = local_to_map(to_local(origin))
	for cell in tiles:
		map_origin + cell

As I was typing I realized too I didn’t connect the signal to the tilemap script so I did that and still got the same error shoot, just for clarity sake here is the event controller signal:

signal tile_destruction(tiles, bombspot)

Sorry for the contintued notifications

So, remember when we were setting up drill we switched from you using collisions to tilemap coords? We should do the same here to simplify. However, that is not the reason you are getting that error.

You are calling a func in a for loop, so it never ends the loop, each time it goes over it get a new list of things to loop through.

I apologize for the confusion, I realize I explained two different things but using the same name.

I started out at the beginning using a var explosion_size, later I used that same name for an examlple func.

Have your signal tile_destruction(tile_list, bombspot)

If you create a var explosion_size: int = 3

Then have a func exploded_tiles():

In exploded_tiles.

var tiles: Array
for x in explosion_size:
     for y in explosion_size:
          tiles.append(Vector2i(x,y))
explode_tnt.emit(tiles, global_position)

To give further explanation of for loop. It will cycle through whatever value you have after the in keyword. In my example x and y are just the reference for each iteration of the value which in an int. If you create a never ending loop, you will get the recursion error.

In my example x will = (0,1,2), since it will loop 3 times.

Y will = (0,1,2), so that is why I can use these values to create an array of Vector2i.

For each loop of x, the y for loop will give the value (0,1,2).

So at the end you will have all values between Vector2i(0,0) and Vector2i(2,2).

You can now send this signal to wherever you will calculate and destroy your tiles.

In that func() that recieves the signal you will take the two values (array, global_position) and that is the part of the code that I wrote using var map_origin.

You copied it exactly, however that func doesn’t do anything. I said you needed to use map_origin + cell to destroy the tile you want.

Something like set_cell(0, map_origin + cell, -1) put this under the for loop like you have written right now replacing map_origin + cell.

Edit:

I also noticed you have a check, is_in_grouo(“Mudwalls”), have you thought of using tilemap layers to avoid this needed group. Just create a designated layer for mudwalls, now when you destroy tiles instead of set_cell(0,pos,-1) you would set the first number to whichever layer mudwalls are on.

1 Like

Wow ok so, “for x in” is almost like saying “var x =” and it’s just a temporary variable that will always be the size of whatever it is looping through, so it has to be an int. Wow when you say it like that it sounds so clear and understandable. I really just could not figure that out. And then counting up to that int running what is inside the body literally for each number in the count. And then the for y loop is literally just a loop nested in the x loop and could be counting through anything with a size count. Maybe saying “anything with a size count” isn’t correct.

You are making so much sense to me. You are really awesome at explaining the info, just as much as you are with the knowledge itself. No doubt. Even though I now feel a sense of understanding for the looping functions and I feel like I can see the general sense of what you’re saying, there is no way in any circle of the underworld that I would actually be able to figure these methods and connect them to behave in the way like you are able to figure. The confusion is all lack of understanding on my end and I apologize for any headache caused having to rehash so many things.

It’s funny you mention that mudwalls group. I have not thought about that at all. I honestly didn’t quite understand the 0 and thought “well that’s what goes there” definitely showing my comprehension level. But I’m thinking of putting in tiles that can’t be destroyed so having it on it’s own layer sounds like a great idea. Thank you for bringing that up I will do that

I was way off the mark and I appreciate you showing me how I was missing it.
Going to try putting this together right now. Thank you for all your help.

No worries mate. Just some follow up clarification about for loops. So in my example x = the current iteration of what you are cycling through.

You can cycle through more than int. It is very useful for arrays and dict as well.

My for x and for y use int, but tgey populate an array which I suggested using a for loop to cycle through to get each coord stored in the array.

Hope that helps clarify.

1 Like

Thanks for your addition. I’m trying to see what you’re saying here too and I thought I had it I was gonna say it would be good for like if you wanted to find all the apples in an array of grocery items like
array = [apple, orange, orange, eraser, banana, apple, milk] you would have a for loop, but then I’m like would it have to be

for apple in array and wouldn’t apple still be an int of the count size.

so ok it could still be x or anything it’s just grabbing the instances and then in the body you’d check if x was equal to the apple object that is stored in that array and then do logic to it there

Sorry about this you don’t have to spend all day with my dumb ace. I won’t give up on learning this stuff and I’m going to continue strongly considering our conversation as well as any more additions you add. I can’t tell you enough how much I appreciate your help.

So, for your example it’d be better to used the arrays built in func count() to find how many times apple is in an array.

Say, though you had an array of references to unique fruit, and some were apples. Your apple nodes has a class_name Apple. Now in your for loop.

var bowl: Array = [$Apple1, $Orange, Apple2]
for fruit in bowl:
     if not fruit is Apple:
          continue
     #do something with apples

Here, you iterate over the array, checking if the node is not of class_name Apple, in which case it ends the current loop iteration and checks next item in array, until it finds an Apple, then some logic is executed.

You can also use break to end a loop early.

for x in array:
     if something == true:
          break
     #do logic

Here the loop will run until it has gone through the whole array, or something is true, then it’ll stop.

1 Like

Wow that is very interesting and thank you for sharing that. So you can literally check if the iteration the for loop is on is currently of the Apple class that is set in the object. Your knowledge just blows me away. I’m trying to rack my brain and think of a for loop that would loop through objects in the array instead of the count size. Wouldn’t we just be able to check for the class of any object in the array eliminating the need to loop through anything besides the int of the array size?

You could do something like this, I’m not sure if it would be better then directly looping through the array, unless you were wanting to change the array while looping, which you don’t want to do it you are currently looping through it.

for idx in array.size() - 1:
     if array[idx] is Apple: 
          #do something
           break

Thank you for that information. I can’t wrap my head around that last loop but I am going to stew on it.

That last one uses an int based on an arrays size() - 1 (since arrays start at 0).

Then when it finds the first Apple in the array it breaks the loops.

Edit:
For anyone who sees this, this is wrong. For finding last instance in an array you can use array.size() - 1. However, for loops start going through int at 0 automatically, so you just need to write array.size().

I came back to say you completely nailed explosions. I truly am amazed and grateful. Thank you for your help. I also wanted to relook at that last loop function and I just don’t get it. Does this mean it will start at the end of the array or am I just missing something totally right in front of my face? I’m sorry to get back to you so late. I am so glad to be discussing this with you.

So, I was messing around with a loop in a little project I am doing, and I actually used a for loop like that.

I realized I made a slight error in writting that. When getting the last index of an array you need to use array.size() - 1, however the for loop automatically starts integer loops at 0. So, this is how you would write the loop.

for idx in array.size(): 
     pass #the -1 was because I forgot for loops start int iterations at 0 which is first entrance in an array.

My little project I had two arrays that were set up and I wanted access to their information in the loop.

So I did this.

for idx in array.size():
     var value = array[idx] * array2[idx]

This allowed me to access both arrays by index in the same for loop, I also had an enum set up (which are int values) so I also used the idx to match.

enum {FIRST,SECOND}

match idx:
     FIRST:
          #do something
     SECOND:
          #do something
     _:
          continue
1 Like

I went away for a while and tried coming back refreshed and I still just can’t figure how you are figuring this stuff. Like I can see how the for idx in array.size() works, but then how it knows to check the size of the value variable set within the loop. And then even moreso how you knew to multiply those two values together to make it do what you wanted. I would have thought to add the values if anything.

It just shows I’m on a lower level of critical thinking. I’ve tried watching videos about stuff to see if there were any clues on how to see a problem and be figure it similar to how you are but I keep like over and underthinking it. Still I appreciate you working through this with me. If you have more insight that you think may help me understand the loops within your project I would love to see and try to comprehend it.

Thanks a lot for sharing sorry have been away for a while. Was related to personal life, but thought the time away would help me see it better on a second viewing and I was not correct

Hey mate no worries, I am still finding myself mystified by some peoples ability to solve problems.

So, the loop doesn’t “know” anything. In my project I had two arrays that held values I needed to multiply with each other at the same index value, hense the value.

So, my code knows what to do because I tell it what to do. I just use the size() to get the index so I can get the values stored in two equal size arrays.

What I am currently doing in my project is making an Array of RefCounted objects. These objects have a var name: String.

I then use a excel spreadsheet that I saved as a .csv file to search through, each line is an array of values, the first value is the same as one of my object.name. i use that fiest value to create a key in a dictionary, and store the rest of the array value under that key.

Now I can use my array of objects, to search that dict and retrieve their information.

Don’t worry to much about how I ised for loops. I found using them in projects helped me to understand them slowly but surely. When I first discovered them I was mesmerized. As far as things I use in my coding for loops and return have changed how I do things the most.

1 Like

Thank you for clarifying. Now I think I am seeing that how that for loop is working. It’s multiplying the values at that same index for two different arrays. And the 2nd array is an object within the first array? So my current understanding is you are getting the index’s index when you multiply the currently iterated parent index by child index. I just still am only barely wrapping my head around that if I’m in the ballpark at all. It’s so funny you mentioned return because that is also a humongous headscratcher for me. I just can’t see when to use it. The only time I ever have is when xplicitly directed to do so in a tutorial.

Yeah so in my example for loop, I use the for loop to get a number that corresponds to an entry in two arrays.

I then use that number to multiply two values found in those two different arrays.

Return can be used to stop a func early, it is good for block statements, such as

if not something: return

This allows you to stop code from executing.

However, what I find super useful is returning a value. This allows me to streamline my code, make it more organized. Otherwise either I’d be doing a lot of calculations within the body of one func, or needing to use signals.

func some_func():
     if not _some_helper_func():
          return
     #do something in code body
     var array = $Child.array_func()
     for x in array:
     #do things

func _some_helper_func() -> bool:
     #have some checks
     if something:
          return true
     else:
          return false

#in child code
func array_func() -> Array:
     #create array
     var array_created: Array
     return array_created

So, the func in the if statement returns the value true or false. That, if statement can be useful for checking various parameters and not clog up your func, especially for like physics and process func that tend to get clogged up.

The second example removes need to either directly call back the parent, or send a signal. It also, eliminates need to have an extra func to handle the value given by the other node. It took my honestly longer to start using return then it did to use for loops.

1 Like