見出し画像

【ティラノスクリプト】メニュー画面のサンプル

メニュー画面のサンプルです。


【参考記事】

上記の記事を参考にさせていただきました。

【注意①】

ティラノスクリプト本体を改造しています。

不具合が発生した場合は、お手数をおかけしますが、今回貼り付けたコードを削除してください。

【注意②】

お使いのバージョンによっては使用できない場合があります。

  • Ver525b(2024/8/7 更新)

上記のバージョンで動作を確認しています。

【first.ks】

;data/others/js/main.jsを読み込み
[loadjs storage="js/main.js"]
;data/others/html/menu.htmlを読み込み
[sysview type="menu" storage="./data/others/html/menu.html"]
;data/others/css/style.cssを読み込み
[loadcss file="./data/others/css/style.css"]

【main.js】

TYRANO.kag.menu.showMenu = function (call_back) {
    if (this.kag.layer.layer_event.css("display") == "none" && this.kag.stat.is_strong_stop != true) {
        return false;
    }

    if (this.kag.stat.is_wait == true) {
        return false;
    }

    var that = this;

    that.kag.unfocus();
    this.kag.setSkip(false);
    this.kag.setAuto(false);
    this.kag.stat.is_auto_wait = false;

    var layer_menu = this.kag.layer.getMenuLayer();

    layer_menu.empty();

    var button_clicked = false;

    this.kag.html(
        "menu",
        {
            novel: $.novel
        },
        function (html_str) {
            var j_menu = $(html_str);

            layer_menu.append(j_menu);

            layer_menu
                .find(".menu_skip")
                .click(function (e) {
                    layer_menu.html("");
                    layer_menu.hide();
                    if (that.kag.stat.visible_menu_button == true) {
                        $(".button_menu").show();
                    }
                    that.kag.setSkip(true);

                    if (that.kag.layer.layer_event.css("display") == "none") {
                    } else {
                        that.kag.ftag.nextOrder();
                    }

                    e.stopPropagation();
                })
                .focusable();

            layer_menu
                .find(".menu_auto")
                .click(function (e) {
                    layer_menu.html("");
                    layer_menu.hide();
                    if (that.kag.stat.visible_menu_button == true) {
                        $(".button_menu").show();
                    }
                    that.kag.setAuto(true);

                    if (that.kag.layer.layer_event.css("display") == "none") {
                    } else {
                        that.kag.ftag.nextOrder();
                    }

                    e.stopPropagation();
                })
                .focusable();

            that.setMenuCloseEvent(layer_menu);
            that.setHoverEvent(layer_menu);

            layer_menu
                .find(".menu_window_close")
                .click(function (e) {
                    that.kag.layer.hideMessageLayers();
                    layer_menu.html("");
                    layer_menu.hide();
                    if (that.kag.stat.visible_menu_button == true) {
                        $(".button_menu").show();
                    }

                    e.stopPropagation();
                })
                .focusable();

            layer_menu
                .find(".menu_save")
                .click(function (e) {
                    if (button_clicked == true) {
                        return;
                    }
                    button_clicked = true;
                    that.kag.makeUnfocusableAll(layer_menu);
                    that.displaySave();
                    e.stopPropagation();
                })
                .focusable();

            layer_menu
                .find(".menu_load")
                .click(function (e) {
                    if (button_clicked == true) {
                        return;
                    }
                    button_clicked = true;
                    that.kag.makeUnfocusableAll(layer_menu);
                    that.displayLoad();
                    e.stopPropagation();
                })
                .focusable();

            layer_menu
                .find(".menu_log")
                .click(function (e) {
                    if (button_clicked == true) {
                        return;
                    }
                    button_clicked = true;
                    that.kag.makeUnfocusableAll(layer_menu);
                    that.displayLog();
                    e.stopPropagation();
                })
                .focusable();

            layer_menu
                .find(".menu_back_title")
                .click(function () {
                    that.kag.backTitle();
                })
                .focusable();

            $.preloadImgCallback(
                j_menu,
                function () {
                    layer_menu.stop(true, true).fadeIn('fast', function() {
                        $('.menu_wrapper').addClass('open');
                    });
                
                    $(".button_menu").hide();
                },
                that
            );
        }
    );
};

TYRANO.kag.menu.setMenuCloseEvent = function (j_parent, options = {}) {
    const j_menu = this.kag.layer.getMenuLayer();
    const target_selector = options.target || ".menu_close";
    
    j_parent
        .find(target_selector)
        .click((e) => {
           if ( $("#menu_save_wrapper").length == 0 && $("#menu_load_wrapper").length == 0 && $("#menu_backlog_wrapper").length == 0 ) {
                $('.menu_wrapper').removeClass('open');
                $('.menu_wrapper').on('transitionend', function(event) {
                    if (event.target === this && !$(this).hasClass('open')) {
                        j_menu.hide();
                        j_menu.empty();
            
                        if (typeof options.callback == "function") {
                            options.callback();
                        }
                    }
                });

            } else {
                j_menu.fadeOut(300, () => {
                    j_menu.empty();
                    if (typeof options.callback == "function") {
                        options.callback();
                    }
                });
            }
            
            if (this.kag.stat.visible_menu_button == true) {
                $(".button_menu").show();
            }
            e.stopPropagation();
        })
        .focusable();
};

TYRANO.kag.menu.displayLog = function () {
    var that = this;
    that.kag.unfocus();
    this.kag.setSkip(false);

    var j_save = $("<div></div>");

    this.kag.html(
        "backlog",
        {
            novel: $.novel
        },
        function (html_str) {
            var j_menu = $(html_str);

            var layer_menu = that.kag.layer.getMenuLayer();

            j_menu.hide();
            layer_menu.append(j_menu);
            layer_menu.show();

            that.setMenuCloseEvent(layer_menu);
            that.setHoverEvent(layer_menu);

            that.setMenuScrollEvents(j_menu, { target: ".log_body", move: 60 });

            j_menu.find(".log_body").on("touchmove", (e) => {
                e.stopPropagation();
            });

            var log_str = "";

            var array_log = that.kag.variable.tf.system.backlog;

            for (var i = 0; i < array_log.length; i++) {
                log_str += array_log[i] + "<br />";
            }

            layer_menu.find(".log_body").html(log_str);

            layer_menu.find(".log_body").css("font-family", that.kag.config.userFace);

            $.preloadImgCallback(
                layer_menu,
                function () {
                    j_menu.stop(true, true).fadeIn(300);
                    
                    layer_menu.find(".log_body").scrollTop(9999999999);
                    layer_menu.find(".block_menu").fadeOut(300);
                },
                that
            );

            $(".button_menu").hide();
        }
    );
};

【menu.html】

<div class="display_menu block_menu">
    <div class="menu_wrapper">
        <div class="menu_close">
        </div>
        <div class="menu_button">
            <div class="menu_save">SAVE</div>
            <div class="menu_load">LOAD</div>
            <div class="menu_log">BACKLOG</div>
            <div class="menu_window_close">WINDOW HIDE</div>
            <div class="menu_auto">AUTO</div>
            <div class="menu_skip">SKIP</div>
            <div class="menu_back_title">TITLE</div>
        </div>
    </div>
</div>

【style.css】

/* メニュー全体のラッパー(初期状態は非表示) */
.menu_wrapper {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(0, 0, 0, 0.8);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease-in-out;
}

/* open クラスがついたときの表示状態 */
.menu_wrapper.open {
    opacity: 1;
    pointer-events: auto;
}

/* 閉じるボタン(右上の✕ボタン) */
.menu_wrapper .menu_close {
    position: absolute;
    top: 32px;
    right: 32px;
    width: 40px;
    height: 40px;
    cursor: pointer;
    opacity: 1;
    transition: opacity 0.3s ease-in-out;
}

/* ✕ の線 */
.menu_wrapper .menu_close::before,
.menu_wrapper .menu_close::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 80%;
    height: 10%;
    background-color: #fff;
    transform-origin: center;
    transition: background-color 0.3s;
}

/* 45度回転 */
.menu_wrapper .menu_close::before {
    transform: translate(-50%, -50%) rotate(45deg);
}

/* -45度回転 */
.menu_wrapper .menu_close::after {
    transform: translate(-50%, -50%) rotate(-45deg);
}

/* ホバー時の色変更 */
.menu_wrapper .menu_close:hover::before,
.menu_wrapper .menu_close:hover::after {
    background-color: #ccc;
}

/* ボタンリスト */
.menu_button {
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* ボタンの共通スタイル */
.menu_button > div {
    padding: 10px;
    text-align: center;
    font-weight: bold;
    font-size: 32px;
    color: #fff;
    cursor: pointer;
    background-color: transparent;
    border: none;
    opacity: 0;
    transform: translateX(-30px); /* 左から */
    transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
}

/* open クラスがついたときのボタン表示(時間差あり) */
.menu_wrapper.open .menu_button > div {
    opacity: 1;
    transform: translateX(0);
}

/* ボタンの間隔 */
.menu_button > div + div {
    margin-top: 10px;
}

/* ボタンのホバーエフェクト */
.menu_button > div:hover {
    color: #ccc !important;
}

/* 各ボタンに時間差をつける(開くとき) */
.menu_wrapper.open .menu_button > div:nth-child(1) { transition-delay: 0.1s; }
.menu_wrapper.open .menu_button > div:nth-child(2) { transition-delay: 0.2s; }
.menu_wrapper.open .menu_button > div:nth-child(3) { transition-delay: 0.3s; }
.menu_wrapper.open .menu_button > div:nth-child(4) { transition-delay: 0.4s; }
.menu_wrapper.open .menu_button > div:nth-child(5) { transition-delay: 0.5s; }
.menu_wrapper.open .menu_button > div:nth-child(6) { transition-delay: 0.6s; }
.menu_wrapper.open .menu_button > div:nth-child(7) { transition-delay: 0.7s; }

/* 閉じる時は逆のアニメーション(右へフェードアウト) */
.menu_wrapper:not(.open) .menu_button > div {
    opacity: 0;
    transform: translateX(30px); /* 右へ */
}

/* 各ボタンの非表示アニメーションを **順番に** 実行 */
.menu_wrapper:not(.open) .menu_button > div:nth-child(1) { transition-delay: 0.1s; }
.menu_wrapper:not(.open) .menu_button > div:nth-child(2) { transition-delay: 0.2s; }
.menu_wrapper:not(.open) .menu_button > div:nth-child(3) { transition-delay: 0.3s; }
.menu_wrapper:not(.open) .menu_button > div:nth-child(4) { transition-delay: 0.4s; }
.menu_wrapper:not(.open) .menu_button > div:nth-child(5) { transition-delay: 0.5s; }
.menu_wrapper:not(.open) .menu_button > div:nth-child(6) { transition-delay: 0.6s; }
.menu_wrapper:not(.open) .menu_button > div:nth-child(7) { transition-delay: 0.7s; }

/* menu_wrapper のフェードアウトを最後に実行(全ボタンが消えた後) */
.menu_wrapper:not(.open) {
    transition-delay: 0.8s; /* 最後のボタンが消えた後に開始 */
}