How to change voxelMeshAsset on runtime / optimise voxel_meshes

Hi all,

I’m new to crayta, and I’m trying to build my own game, but I’ve some problems:

I’m trying to build a wall made up of several square tiles. The idea is to let them change their color when they’re shot, going from color1 to color2 to color3. I firstly tried to create 3 “tile” voxelMesh assets (“tileColor1”, “tileColor2”, “tileColor3”), and script the first one in order to change it’s “mesh” property in tileColor2.mesh or tileColor3.mesh. (I also created a template from the scripted tile in order to replicate it)

Well, it kinda worked, but idk why, it changed after a while when it was shot, and it’s the same thing of changing the meshName from the Crayta editor UI, it takes a while and sometimes (since the 3 assets are similar but for the color) it doesn’t change at all.

So, to solve the problem I decided to change approach, and I picked up a “tileColor1”, created a template, and added tileColor2 and tileColor3 as children of the tileColor1. Then I applied a script to the first tile, making one of the three visible and collidable, and the other 2 invisible and uncollidable. Now it works very well, the problem is that I need more than 500 square tiles on my game and it seems to be too heavy for the server, which crashes when I test the game.

So my questions are:

  1. Is it possible to change the asset of a tile on runtime in a different, lighter way?
  2. How can I optimise it? I don’t know how to create a single “wall” voxel mesh asset, because I need every tile to be a separated entity, with its own color and its own characteristics, so it needs every time to load every tile

Thanks in advance for your help,

Allin18

A voxel mesh is just a collection of voxels. They don’t need to be the same material, but they will contain the same properties. You can keep a 2d array of the current state of each voxel “cube” and when shot (check via raycasting), you can change the state of that voxel cube. Then in the voxel mesh, update the cube at that position with the new material.

2 Likes

Hi, thanks a lot for your help.

I’m not sure I understood your hint:

  1. How am I supposed to understand which cube was hit? I just discovered what a raycast is, and I’m not sure about how to use it. I was thinking about using the hitResponse passed to the OnDamage() function (I think it comes from a raycast sent automatically when shooting), and using its “relative position” property to understand (with some math) which cube was hit basing on the coordinates with respect to the center of the entity. Is this what you were talking about?

  2. I suppose I should then create a table in which to store the center of each cube, and use the SetVoxelBox function to change the voxels starting from that center, right?

  3. Is there a way to destroy those voxels (for example when the cube is red and someone shots at it, it disappears)? I’ve seen the ApplyRadialDamage function, but I guess it acts on a sphere, whilst I want to destroy a cube

Thanks in advance again,

Alessandro

I apologize for any notification this sends, since it’s just bad news. But unfortunately I haven’t checked the docs thoroughly enough to see how this is done. It might be a solid question to ask on the official discord channel, though. A lot of talented people and the devs frequently lurk and answer questions there :slight_smile:

Hi @Allin18,

I’ve only had a couple of mins to try to digest this thread currently, so apologies if this is on the wrong track, but you should be able to use the result of the raycast to call a function on the impacted tile.

So something like the below:

GetWorld():Raycast(rayStart, rayEnd, player, 
	function(hitActor, hitPoint, hitNormal)
		if (hitActor) then
			-- Call a function on the tile here
			end
		end
	end
)

Let me know if that fails to help you, and we can try getting some extra help in tomorrow.

Don’t worry, and thanks for the interest. Thanks to your answer I got to know the raycast function :slight_smile: and maybe I find a way to use it to achieve my goal.

Hi,

First of all thanks for your answer.

I’ve some doubts about this:

In this code I can’t understand where should I call the Raycast function from (should I call it anytime someone shoots?)

Plus, I haven’t a script on the tile, since I’m trying to eliminate the concept of tile from my game.

The point is that making a “tileTemplate” and replicating it hundreds of times seems to be very heavy for the server, so I can’t have any single tile as an individual entity with its own script. My initial question was: “How can I make it lighter?” , "Is there a way to create a single “wall” entity (VoxelMesh) with a single script attached to it handling all the tiles? How can I tell the game to change the color of the tile on position (x,y) since the game doesn’t know what a tile is? And last but not least would this be useful to avoid the server to crash for having too many entities?

Here is my idea:

I could use the onDamage() function of the script attached to the wall entity, since the API says:

 OnDamage function Script:OnDamage(number damageAmount, Entity damageCauser, **HitResult** hitResult) … end Server Called when an entity is damaged on all scripts of the entity. TODO: work out what gets passed in here for radial damage instead of the HitResult. 

So when someone shoots at a part of the wall, I can use the hitResult structure passed to the onDamage function in order to get the relative position of the damaged voxel with respect to the entire wall.

Then I should use the relative position to mathematically compute which tile is that (for example (0,1) ), compute the center of the tile and use SetVoxelBox to change the voxels starting from the center.

The problem is that, even if I could try to do this, I’m not sure this would make the game lighter, neither i’m sure this is the fastest/easier way to do it.

Maybe there is a smarter way to partition a voxel mesh without crying so much :laughing:

What do you think about it?

Thanks for the details, I’ve got a stronger understanding of the problem now :slight_smile:

And I think you’re definitely on the right track: having a continual wall of voxels (not entities) and then using SetVoxelBox() to change the colour of the tiles (and you calculate the tile position based on HitResult) sounds like the most efficient approach to me. From my understanding of the codebase I think this is about the most lightweight way of achieving this.

Thanks a lot for your interest, and also thanks to @Alex for sharing the thread on the discord channel :blush:

I’ll try when I’ll find some time, and i’ll let you know if this approach works :slight_smile:

1 Like