Mobile game - how do you make this physic in Godot?

Godot Version

4.7.2

Question

Currently I’m looking into games which I consider as good time killer, and something about this mechanic in game make me wonder:->

How did they achieved this effect?

I mean specifically this objects how it’s rolling around, are stacked on top of each other.

I mean hopefully it’s not stacked one by one, but how could I achieve nice stack of fruit, and then have this rolling mechanic?

Here is short play from mobile device, it’s one of many games for Nectar points.

You would place the objects, either by hand or with a custom tool script. They would likely be RigidBody3Ds with “Sleeping” enabled on start.

So for hole itself, is it cutting out floor or its smart overlap, maybe decal?

Probably not cutting a hole in the floor, I could see a World Boundry being used for the floor, let’s say on layer 1, then the hole can use an Area3D to disable any overlapping RigidBody’s mask 1. To catch objects on the sides an extra ring-shaped collision(s) can be added on layer 2.

As I see it this would make the objects fall regardless of their size. What about objects that get stuck because they don’t fit the whole yet? One would need to wiggle them out of the hole (using some sort of realistic collision) in order to free the hole up again.

I think in addition to the fact that the floor lets stuff fall through a gap one would need an actual ring-shaped physical body which synchronously to the floor gap grows in size and can push things around a bit.

As for the visuals, one can create a shader material for the ground which gives the illusion of a whole at the right spot through transparency and moves synchronously with the ring-shaped physics object through shader parameters.

I tried to build it, but failed.

Looks like as fairly simple thing, but even collision shapes for RigidBody3D is a bit tricky.

I found this guide

Interesting video.

I heard it was better to avoid CSG during production builds. Not sure about that tho.

Also, if using the CSG in the first place, why not just subtracting a CSG cylinder from a CSG surface? Instead he goes through this lengthy setup with stencil mask settings. Interesting, but I don’t understand why.

Until minute 4:30 it is about the visuals, only after it starts go be about collision – the important part for the right game feel. The trick that he mentions is kind of what we described earlier.

I only don’t get what is cyan doughnut was for. I have the feeling the entire setup should work without it, but I might have misunderstood the purpose.

not sure as well.

Very similar approach with Area3D, but overall I think the idea is make it bit less jittery the objects on contact with hole, also object which doesn’t fall still affects other objects.

The original studio is “MoonActive” - I believe they used Unity in this case, but principles should be same in Godot.

I see some people made it before - GitHub - mbMayer/Godot-Hole.io: Template for Hole.io style games based on CSG nodes · GitHub

As for the visuals of the hole I would probably make the hole thing a shader like so:

shader_type spatial;

uniform vec3 hole_world_position;
uniform float hole_radius : hint_range(0.0, 5.0) = 1.0;
uniform vec4 albedo_color : source_color = vec4(1.0);

varying vec3 world_position;

void vertex() {
    world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}

void fragment() {
    float distance_to_hole = distance(world_position, hole_world_position);
    if (distance_to_hole < hole_radius) {
        discard;
    }
    ALBEDO = albedo_color.rgb;
}

Then update the shader data like so:

extends StaticBody3D
class_name MyGround

@onready var ground_mesh: MeshInstance3D = %ground_mesh
@export var target: Node3D

func _physics_process(_delta: float) -> void:
	var shader_material: ShaderMaterial = ground_mesh.material_override as ShaderMaterial
	if shader_material and target:
		shader_material.set_shader_parameter('hole_world_position', target.global_position)

I was trying to get a minimal setup working for hole mechanics myself: godot_the-hole on my Github.

I think I implemented it with much less, at least there is no non straight-forward setup. So far I think everything is quite simple.

The one exception is the hole scene itself – that is what makes you feel the physics when dropping stuff inside (these shapes are on layer 2, which is always on).

This can probably be done nicer and cleaner. For example I didn’t need a cyan doughnut. No CSG meshes.

These two signals (shown below) toggle if a fruit can fall into the hole or not; and if a fruit moves the right way it stays on top of the ground, while fruits always look for collisions on layer 2.

func _on_area_3d_body_entered(body: Node3D) -> void:
	if body is MyFruit:
		print('hi fruit')
		body.sleeping = false
		body.set_meta('over_hole', true)
		body.set_collision_mask_value(1, false)

func _on_area_3d_body_exited(body: Node3D) -> void:
	if body is MyFruit:
		print('bye fruit')
		body.set_collision_mask_value(1, true)
		body.set_meta('over_hole', false)

Time to try some fruit ?

Beautiful fruits and a nice resource too!