ウマ娘の特殊タグ練習帳   作:uso800

5 / 6
貼った後で気づいたけど、ハーメルン、タブが消えるから、コピーした後、タブ(インデント)を手動で補完する必要がありますね……
タブをtransparentタグに変換してもいいですが……それでもまだ見にくいと思う……
いいアイデアがあったらコメントください。
タブの補完はそれほど難しいことではないと思いますが……


時間に関係する特殊タグを自動生成するPythonのコード

import math

import sys

from datetime import datetime, timedelta

from decimal import ROUND_HALF_EVEN, ROUND_HALF_UP, Decimal

from random import randrange

from string import Template

from typing import Optional

 

 

class Blink:

"""

オプションを選択して実行すると点滅のタグが自動生成される。

オプションの詳細は公公式ドキュメントを参照して下さい。

点滅させる文字はcontentという名称で指定してください。

すべてのオプションに対応しているわけではありません。

 

動作例

>>> Blink(content="ゴリラ")

ゴリラ

 

>>> Blink(content="ゴリラ", inview=True)

ゴリラ

 

>>> Blink(content="ゴリラ", start_ratio=10, end_ratio=50, loop_count=1,total_time=1, inview=True, forwards=True)

ゴリラ

 

>>> Blink(content="必要なオプションだけ指定して下さい。", loop_count=1,total_time=1, inview=True, forwards=True)

必要なオプションだけ指定して下さい。

 

<TODO> speed が 1より大きいときの動作のテスト。

<TODO> オプションを一個も指定しないとき<<blink>>が理想だが、実際には<<blink:>>で始まってるので':'を取り除く。

<TODO> inview, forwards 以外のオプションへの対応

"""

 

# ハーメルンに貼ると内容が評価されてバグるので、bl_inkにした。

template = Template("《bl ink:${options}》${content}《/blink》")

"""

def __init__(

self,

content: str | int = "hello",

start_ratio: Optional[int] = None,

end_ratio: Optional[int] = None,

delay_time: Optional[float | int] = None,

loop_count: Optional[float | int] = None,

total_time: Optional[float | int] = None,

inview: Optional[bool] = False,

forwards: Optional[bool] = False,

ext: Optional[str] = None,

):

self.content = content

self.range_option = (

f"v{int(start_ratio)}-{int(end_ratio)}"

if (start_ratio or start_ratio == 0)

and start_ratio >= 0

and 100 >= end_ratio >= start_ratio

else None

)

self.delay_time = f"d{round(delay_time)}" if delay_time else None

self.loop_count = f"l{round(loop_count)}" if loop_count else None

self.time_option = f"t{round(total_time)}" if total_time else None

self.inview_option = "inview" if inview else None

self.forwards_option = "forwards" if forwards else None

self.ext = ext

 

def _merge_options(self):

base_options = [

self.range_option,

self.delay_time,

self.loop_count,

self.time_option,

self.inview_option,

self.forwards_option,

self.ext,

]

 

return ",".join(list(filter(lambda item: item is not None, base_options)))

 

def _substitude_template(self):

return self.template.substitute(

options=self._merge_options(), content=self.content

)

 

def __str__(self):

return self._substitude_template()

 

@classmethod

def supply(cls, args):

return cls(**args)._substitude_template()

 

 

class FadeInSpeech:

"""FadeInSpeech.

 

長い文章をフェードインさせるとき、上記のBlink機能を使って一文字づつ表示開始時間を計算させるのは人間技ではないのでまとめて計算する。

content (文字列+一時停止), speed (文字ごとの間隔), delay_time, is_inview, is_forwards(公式ドキュメント参照)を指定できる。

 

使用例

>>> FadeInSpeech(contents="ゴリラ")

 

>>> FadeInSpeech(contents="hello/1.1/world",speed=0.1)

helloworld

 

一時停止について

一時停止は/{秒数}/を文字列に入れると動作する。

例えば"前/10/後"を文字列の中に入れると前を表示した後、10秒停止してから後が表示される。

/10/をコンテンツの中に入れると、10秒、そこで停止する。

なおspeed分の停止時間と一時停止の時間は加算されて処理される。

例えば『content='前/1/後', speed=1』の場合、「前」が表示されてから二秒後に「後」は表示される。

/1.11/などの少数も入力可能。

 

delay_timeについて

『content='前/1/後', speed=1, delay=2』と『content='/2/前/1/後', speed=1』は同義。

 

小数について

最終出力時にはすべてミリ秒まで四捨五入されるが、計算ロジックの中ではそれより先も保持しているので他の端数と合算しての繰り上がりなどが有効。

例えば『content='前/0.001/中/0.001/後',speed=0.001, delay=0.001』のような指定の場合、

「前」と「中」(内部的には0.003秒後)は0.00秒後に同時に表示されるが、「後」(内部的には0.005秒後)は0.01秒後に表示される。

 

contentsについて

list型を入れることもできる。

>>> FadeInSpeech(contents=["ゴリラ", "ラッパ"])

ゴリララッパ

ただし、listを入れた場合は、一時停止は正常に動作しない。

>>>FadeInSpeech(contents=["ゴリラ", "/10/", "ラッパ"])

ゴリラ/10/ラッパ

"""

 

def __init__(

self,

contents: str | int | list[str] = "hello worlds",

speed: int | float = 0.10,

delay_time: int | float = 0,

is_inview: bool = True,

is_forwards: bool = True,

ext: Optional[str] = None,

):

self.showing_time = len(contents) * speed

self.speed = speed

self.delay_time = delay_time

self.is_inview = is_inview

self.is_forwards = is_forwards

self.contents = contents

self.sleep_flag = False

self.ext = ext

 

def make_simple_blinks(self):

"""

簡単なロジックでブリンク郡を作る。

文字列が短いと正常に動作しないし、文字列が長すぎても正常に動作しない。

雑に実装するとこうなる。

 

抱えてる問題(解決方法はsimple_blinksを参照)

t(整数(>=1)、文字の表示にかかる時間の合計) を与えられると、tの時間を100等分にした上で一文字辺りの表示時間を計算し、各文字に開始時間を割り振る。

これでは、最小のtが1であるため細かな制御が効かない。例えば2文字だと、一文字の表示にかかる時間が0.5秒になりかなり遅い。体感、10文字以下でこの問題が顕著。

100等分なので文字が(t * 100)文字以上だと同時に表示させる必要のある文字が出てくる。(t * 100)文字以下であったとしても、文字が多めだと表現の幅が狭くなる。

"""

blinks = []

 

for index, content in enumerate(self.contents):

start_ratio = index * 100 // len(self.contents)

end_ratio = 100

total_time = self.showing_time

args = {

"content": content,

"start_ratio": start_ratio,

"end_ratio": end_ratio,

"delay_time": self.delay_time,

"loop_count": 1,

"total_time": total_time,

"inview": self.is_inview,

"forwards": self.is_forwards,

}

 

blinks.append(Blink.supply(args))

# print(blinks)

 

return blinks

 

def make_blinks(self):

"""

simple_blinksの問題を解消させたもの。

simple_blinksとの違い。

 

文字数が100文字を越えても表現の幅が狭まらないように、個別の文字に対して、全体の中の特定の文字、ではなく、別個に表示タイミングを計算している。

「100秒で完結する100個ロジックの10個目のブリンク」を「10個目のブリンクは10.00秒後に動作を開始するブリンク」に変換している。

そのため最短指定の秒数が一秒を切っている。(やろうと思ったら素数を活用したさらに細かな分割とかできるが、やりたくはない)

つまり「1秒で完結する2個のロジック(表示時間0.5秒)」しかできなかったのを「0.2秒毎に2文字をブリンクさせる」ができるようになっている。

あと、文の途中のスリープを有効にした。

"""

blinks = []

blink_work_time = math.ceil(self.speed)

sleep_count = []

sleep_delay: float = 0.00

is_sleeping = False

 

# contentsがlist[str]のときは、スリープ関係の動作が正常に動作しない。

 

for index, content in enumerate(self.contents):

# スリープ関係の処理に入るか

 

if content == "/" or is_sleeping:

# 開始、終了系か

 

if content == "/":

if not is_sleeping:

is_sleeping = True

 

else:

is_sleeping = False

sleep_delay += float("".join(sleep_count))

sleep_count = []

 

# スリープ時間の読み取り

elif is_sleeping:

try:

if content != ".":

float(content)

except ValueError:

print("多分、スリープのタグを閉じるのを忘れています")

sys.exit()

sleep_count.append(content)

 

continue

 

start_time = index * self.speed + sleep_delay

start_f, start_i = math.modf(start_time)

 

# <TODO> ここら辺りの処理、スピードが一秒より長いとバグりそう。

 

if start_f != 1:

start_ratio = round(start_f * 100)

blink_start_time = start_i

else:

start_ratio = 50

 

blink_work_time = start_i + 1

 

args = {

"content": content,

"start_ratio": start_ratio,

"end_ratio": 100,

"delay_time": self.delay_time + blink_start_time,

"loop_count": 1,

"total_time": blink_work_time,

"inview": self.is_inview,

"forwards": self.is_forwards,

"ext": self.ext,

}

 

blinks.append(Blink.supply(args))

 

return blinks

 

def __str__(self):

return "".join(self.make_blinks())

  1. 目次
  2. 小説情報
  3. 縦書き
  4. しおりを挟む
  5. お気に入り登録
  6. 評価
  7. 感想
  8. ここすき
  9. 誤字
  10. 閲覧設定

▲ページの一番上に飛ぶ
X(Twitter)で読了報告
感想を書く ※感想一覧 ※ログインせずに感想を書き込みたい場合はこちら
内容
0文字 10~5000文字
感想を書き込む前に 感想を投稿する際のガイドライン に違反していないか確認して下さい。
※展開予想はネタ潰しになるだけですので、感想欄ではご遠慮ください。