0 votes

I want to make a carousel menu similar to "Mario and Luigi Inside Bowser" that isn't too complicated, it doesn't matter if it's with code, it's for a personal project, but I can't find the answer to this all over the internet, and many except in the godot program, if someone can help me I would be very grateful.

enter image description here

enter image description here

Godot version V3.4.4 stable
in Engine by (14 points)

I wouldn't use a scrollcontainer for this, I would suggest creating your own container node

It is a very good idea, but I have only used very few nodes, of all those that exist, but the ones I have used have served me for what I want to do, apart from that I do not know how to use all of them, since for me they are very complicated to understand and there is no video explaining node by node. But if you have any ideas how to do it, I'm open to any suggestions.

Okay, I will make a carousel menu node for you

By the way, dog on discord says that there is although no video that explains every node, you can look at the documentation to explain every node.

1 Answer

+1 vote
extends Container
class_name CircularCarousel


export var starting_angle := PI / 2
export var darkness := 0.2
export var transition_time := 0.5

var tween: Tween
var queued_turns := []


func _ready() -> void:
    tween = Tween.new()
    add_child(tween)
# warning-ignore:return_value_discarded
    tween.connect("tween_all_completed", self, "on_tween_all_completed")
    for i in get_child_count() - 1:
        var c := get_child(i)
        fit_child_in_rect(c, Rect2(calculate_child_position(i), c.rect_size))
        c.modulate = calculate_child_modulate(i)


func _input(event: InputEvent) -> void:
    if event is InputEventMouseButton:
        if event.button_index in [BUTTON_WHEEL_UP, BUTTON_WHEEL_DOWN] and event.pressed:
            if event.button_index == BUTTON_WHEEL_UP:
                if tween.is_active():
                    queued_turns.append("move_up")
                else:
                    move_up()
            else:
                if tween.is_active():
                    queued_turns.append("move_down")
                else:
                    move_down()


func move_up() -> void:
    var arr := []
    for i in get_child_count() - 1:
        arr.append(null)
    for i in get_child_count() - 1:
        if not (get_child_count() - 1) % 2:
            if i == 0:
                arr[1] = get_child(i)
            elif i == get_child_count() - 2:
                arr[i - 1] = get_child(i)
            elif i % 2:
                arr[i + 2] = get_child(i)
            else:
                arr[i - 2] = get_child(i)
        else:
            if i == 0:
                arr[1] = get_child(i)
            elif i == get_child_count() - 3:
                arr[i + 1] = get_child(i)
            elif i % 2:
                arr[i + 2] = get_child(i)
            else:
                arr[i - 2] = get_child(i)
    arr.append(tween)
    for child in get_children():
        remove_child(child)
    for child in arr:
        add_child(child)
    tween_children()


func move_down() -> void:
    var arr := []
    for i in get_child_count() - 1:
        arr.append(null)
    for i in get_child_count() - 1:
        if not (get_child_count() - 1) % 2:
            if i == 1:
                arr[0] = get_child(i)
            elif i == get_child_count() - 3:
                arr[i + 1] = get_child(i)
            elif i % 2:
                arr[i - 2] = get_child(i)
            else:
                arr[i + 2] = get_child(i)
        else:
            if i == 1:
                arr[0] = get_child(i)
            elif i == get_child_count() - 2:
                arr[i - 1] = get_child(i)
            elif i % 2:
                arr[i - 2] = get_child(i)
            else:
                arr[i + 2] = get_child(i)
    arr.append(tween)
    for child in get_children():
        remove_child(child)
    for child in arr:
        add_child(child)
    tween_children()


func tween_children() -> void:
    for i in get_child_count() - 1:
        var c := get_child(i)
# warning-ignore:return_value_discarded
        tween.interpolate_property(c, "rect_position", c.rect_position, calculate_child_position(i), transition_time)
# warning-ignore:return_value_discarded
        tween.interpolate_property(c, "modulate", c.modulate, calculate_child_modulate(i), transition_time)
# warning-ignore:return_value_discarded
    tween.start()


func calculate_child_position(i: int) -> Vector2:
    var angle_sign := -1 if i % 2 else 1
    var spacing := PI / (get_child_count() - 1) * (get_child_count() - i - 2)
    var offset := PI / (get_child_count() - 1) / 2
    var angle := starting_angle + angle_sign * spacing
    if not get_child_count() == i + 2:
        if not (get_child_count() - 1) % 2:
            angle += offset
        else:
            angle -= offset

    if not (get_child_count() - 1) % 2 and i == 0:
        angle += offset
    var center := Vector2(cos(angle), sin(angle)) * rect_size / 2 + rect_size / 2
    var top_left: Vector2 = center - get_child(i).rect_size / 2
    return top_left


func calculate_child_modulate(i: int) -> Color:
# warning-ignore:integer_division
    return Color.white.darkened(darkness * ((get_child_count() - i - 1) / 2))


func on_tween_all_completed() -> void:
    if queued_turns:
        call(queued_turns.pop_front())
by (8,155 points)

Thanks thanks, I know it sounds silly, but what Nodes and children should I use for this code? TvT, I am indebted to you.

Put the script on a Container. Make sure that the child nodes are Control-extended nodes like TextureRects or Buttons.

Dude, I'm sorry to bother you so much, because you must be busy with your own personal projects, but isn't there a way to do it with buttons instead of the mouse?

Yes, just change the _input function to listen for those buttons instead of the mouse.

Friend it shows that you have knowledge and your code is good, I do not understand it at all, honestly it did not work for me and I made many mistakes when implementing it in my game, apart from changing the mouse function to key, nothing worked, anyway, thanks . It's too complicated for my knowledge.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.