2020年2月19日水曜日

Python+Kivy 地獄編 無意味なアプリを作って地獄の扉を開けてみる


…四の五の言わずに先ずは出来上がったモノなんですけどね。

※例によって Linux Mint 19.2 + Python2.7 です
画面下の方に見えるのは以前作ったカラーを決めるGUI群。中央に見えるのは解りづらいですが、ディレクトリ検索。上に見えるのは Blender をパク…リスペクトしたファイル作成GUI。
しかして、「CREATE」ボタンを押すと…
指定した色の15x15ドットの24ビットカラーの四角いBMPファイルができるだけ。
しかもエラー処理も書いてないから、上書き禁止フォルダに書き込もうとすると落ちる等バグは放置してます。

何かの役に立つアプリを作る気は毛頭なくて、
Python でバイナリファイルを作る処理を組む
Bitmap ファイルの扱い方を思い出す
という目標と後述する目的の足掛かりとして作成しました。

コード

## make bmp ##

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.slider import Slider

from kivy.uix.floatlayout import FloatLayout

import os
from os.path import join,isdir

from kivy.uix.filechooser import FileChooserIconView
from kivy.uix.filechooser import FileChooserListView

### Input Directory
#class DirectoryChooser(FileChooserListView):
class DirectoryChooser(FileChooserIconView):
    def is_dir(self,directory,filename):
        self.parent.parent.t1.text = directory
        return isdir(join(directory,filename))

class BoxSelectFile(BoxLayout):
    orientation='vertical'
    def __init__(self,**kwargs):
        super(BoxSelectFile,self).__init__(**kwargs)
        self.dc =DirectoryChooser(size_hint_y=1)
        self.dc.filters=[self.dc.is_dir]
        self.add_widget(self.dc)

### Input FileName
class BtSave(Button):
    def on_press(self):
        self.parent.parent.MakeFile()

class BoxSaveFileName(BoxLayout):
    orientation='horizontal'
    def __init__(self,**kwargs):
        super(BoxSaveFileName,self).__init__(**kwargs)
        self.t1 = TextInput(text='',size_hint_x=5,multiline=False)
        self.l1 = Label(text='.bmp',size_hint_x=2)
        self.b1 = BtSave(text='CREATE',size_hint_x=3)

        self.add_widget(self.t1)
        self.add_widget(self.l1)
        self.add_widget(self.b1)

### Input Color Value
class TxiColor(TextInput):
    def on_text_validate(self):
        value = int(self.text)
        if value <= self.parent.max and value >= self.parent.min:
            self.parent.SetValue(value)
        self.parent.ReDraw()

class SlColor(Slider):
    def on_touch_up(self,touch):
        value = int(self.value)
        self.parent.SetValue(value)
        self.parent.ReDraw()

class BoxColor(BoxLayout):
    def __init__(self,**kwargs):
        super(BoxColor,self).__init__(**kwargs)
        self.SetUp('',0,100)

    def SetUp(self,text,min,max):
        self.tName = text
        self.min = min
        self.max = max
        self.value = min

        self.clear_widgets()
        self.orientation='horizontal'

        self.l1 = Label(text=self.tName,size_hint_x=1)
        self.s1 = SlColor(min=self.min,max=self.max,value=self.value,size_hint_x=7)
        self.t1 = TxiColor(text=str(self.value),size_hint_x=2,multiline=False)

        self.add_widget(self.l1)
        self.add_widget(self.s1)
        self.add_widget(self.t1)

    def SetValue(self,value):
        self.value = value

    def ReDraw(self):
        self.s1.value = self.value
        self.t1.text = str(self.value)

### BMP File cotrol
class BMPFileControl():
    def __init__(self,size_w,size_h):
        # 24bit Color Only
        self.header = bytearray(range(54))
        self.padding = (4-(size_w*3)%4)%4
        self.w = size_w
        self.h = size_h

        imagesize = int(size_w*3 + self.padding)*size_h
        filesize = int(54 + imagesize)

        # FILE HEADER
        # 'BM'
        self.header[0] = 'B'
        self.header[1] = 'M'
        # FileSize
        self.header[2] = filesize & 0xff
        self.header[3] = (filesize >> 8) & 0xff
        self.header[4] = (filesize >> 16) & 0xff
        self.header[5] = (filesize >> 24) & 0xff
        # Reserved1
        self.header[6] = 0
        self.header[7] = 0
        # Reserved2
        self.header[8] = 0
        self.header[9] = 0
        # Offset
        self.header[10] = 54
        self.header[11] = 0
        self.header[12] = 0
        self.header[13] = 0

        # INFO HEADER
        # DIB header size
        self.header[14] = 40
        self.header[15] = 0
        self.header[16] = 0
        self.header[17] = 0
        # image w
        self.header[18] = size_w & 0xff
        self.header[19] = (size_w >> 8) & 0xff
        self.header[20] = (size_w >> 16) & 0xff
        self.header[21] = (size_w >> 24) & 0xff
        # image h
        self.header[22] = size_h & 0xff
        self.header[23] = (size_h >> 8) & 0xff
        self.header[24] = (size_h >> 16) & 0xff
        self.header[25] = (size_h >> 24) & 0xff
        # planes
        self.header[26] = 0
        self.header[27] = 0
        # Bits per Pixel
        self.header[28] = 24 # 24bit Color Only
        self.header[29] = 0
        # Compression
        self.header[30] = 0
        self.header[31] = 0
        self.header[32] = 0
        self.header[33] = 0
        # Imagesize
        self.header[34] = imagesize & 0xff
        self.header[35] = (imagesize >> 8) & 0xff
        self.header[36] = (imagesize >> 16) & 0xff
        self.header[37] = (imagesize >> 24) & 0xff
        # Resolution W
        self.header[38] = 0
        self.header[39] = 0
        self.header[40] = 0
        self.header[41] = 0
        # Resolution H
        self.header[42] = 0
        self.header[43] = 0
        self.header[44] = 0
        self.header[45] = 0
        # Palette
        self.header[46] = 0
        self.header[47] = 0
        self.header[48] = 0
        self.header[49] = 0
        # Essential Color
        self.header[50] = 0
        self.header[51] = 0
        self.header[52] = 0
        self.header[53] = 0

    def MakeBMPFile(self,filepath,r,g,b):
        with open(filepath,'wb') as f:
            data = self.header
            pixel = [chr(b),chr(g),chr(r)]
            linedata = pixel*self.w
            for p in range(self.padding):
                linedata.append(0x00)
            mapdata = linedata*self.h
            data.extend(mapdata)
            f.write(data)

class Display(BoxLayout):
    orientation='vertical'
    def __init__(self,**kwargs):
        super(Display,self).__init__(**kwargs)

        self.t1 = TextInput(text="",size_hint_y=1,multiline=False,readonly=True)
        self.add_widget(self.t1)

        self.boxSave = BoxSaveFileName(size_hint_y=1)
        self.add_widget(self.boxSave)

        self.boxFile = BoxSelectFile(size_hint_y=15)
        self.add_widget(self.boxFile)

        self.boxR = BoxColor(size_hint_y=1)
        self.boxR.SetUp('R',0,255)
        self.add_widget(self.boxR)

        self.boxG = BoxColor(size_hint_y=1)
        self.boxG.SetUp('G',0,255)
        self.add_widget(self.boxG)

        self.boxB = BoxColor(size_hint_y=1)
        self.boxB.SetUp('B',0,255)
        self.add_widget(self.boxB)

    def MakeFile(self):
        txtFilepath=self.t1.text+'/'+self.boxSave.t1.text+self.boxSave.l1.text
        print(txtFilepath)

        bmp = BMPFileControl(15,15)
        bmp.MakeBMPFile(txtFilepath,self.boxR.value,self.boxG.value,self.boxB.value)

class MainApp(App):
    def build(self):
        layout = Display()
        return layout

if __name__=='__main__':
    MainApp().run()


自覚しているので最初に書いてしまうと、ツッコミ所は BMPFileControl クラスです。冗長ってレベルじゃねーぞ。
VC++で BMP 取り扱いクラスを書いていた時はヘッダー構造体を作って、コレを継承するクラスを書いた後、this ポインタにヘッダ構造体ポインタをキャストしてファイル出力に直接流していた記憶がうっすらあるのですが…
慣れていないせいなのでしょうけど python でバイナリファイルを扱おうとすると非常に面倒ですね。
時代の流れで、データサイズを明示したり、ポインタ渡しなどメモリアドレスを直接触れさせる処理を隠蔽していった流れが悪い方に出てしまったように感じるのは私が古い人間だからでしょうか?
4バイト数値をいちいちビットシフトしているのはビッグエンディアン系のCPUも考えると悪くは無いと考えているのですがどうでしょう?

10数年ぶりに Bitmap を取り扱うアプリを作って、大分いろいろ忘れてますね…パディングってなんだっけ?とか、1画素の色の並びをRGBにして失敗したりとか(正解はBGRの順。大昔のハードウェアの都合だったハズ)。

あと、いい加減 Python 3 系にしろと言われそうですが、Linux mint (というか ubuntu)と Blender と kivy の FileChooser が対応してくれない事には身動きとれません。どうにかできる地力も無いですし。


  • さて、コレの何処が地獄なのよ?

昔々、20代後半~30くらいでゲーム会社でプログラマーをやっていた頃、髪の毛がザラザラ抜けた仕事が二つありまして、一つは社内ゲーム開発用エフェクトツールを作っていた時、もう一つはテクスチャファイルコンバータを作っていた時なのですよ。
31で引退して以来髪の毛が減っていない事から(注:増えてもいない)、アレは毛根に厳しい仕事だったなと今でも思うのですが、モデリングがある程度片付いてきたのでテクスチャ用の BMP→S3TC(DXTC)コンバータに再挑戦しようかなと思いまして、その足掛かりとして作りました。
…まあ、正直そんなに乗り気では無かったのですが、購入するとすごく高いんですよ、あのコンバータ。みんな貧乏が悪いんや。


  • 最後に

今回 python kivy について検索していたら Google 先生の日本の検索上位にこのページが出た事があったのですよ。物を書いている以上、読まれているのは構わないのですが…
閲覧数10回以下
… python + kivy で物作ってる日本人は絶滅種なのでは?と不安になりました。

2020年2月12日水曜日

Python+Kivy 備忘録 スライダー、テキストボックス連動編

半年ぶりですね。
思い出して、作って、忘れて、又思い出すというとんでもなく生産性の悪い事をしております。
…だから備忘録が必要な訳で、私は間違っていない…ハズ。
今回はそこそこ汎用性のありそうな、ラベル、スライダー、テキストボックスのセットを作りまして、スライダーとテキストボックスの連動を行ってみたのですが…
検索すると判ると思いますが、kv ファイルを用いたサンプルはネット上にあったのですが、例によって python オンリーが無くてですね、結構試行錯誤してようやく動いたのですが…

コード

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.slider import Slider
from kivy.uix.floatlayout import FloatLayout

### Input Color Value
class TxiColor(TextInput):
    def on_text_validate(self):
        value = int(self.text)
        if value <= self.parent.max and value >= self.parent.min:
            self.parent.SetValue(value)
        self.parent.ReDraw()

class SlColor(Slider):
    def on_touch_up(self,touch):
        value = int(self.value)
        self.parent.SetValue(value)
        self.parent.ReDraw()

class BoxColor(BoxLayout):
    def __init__(self,**kwargs):
        super(BoxColor,self).__init__(**kwargs)
        self.SetUp('',0,100)

    def SetUp(self,text,min,max):
        self.tName = text
        self.min = min
        self.max = max
        self.value = min

        self.clear_widgets()
        self.orientation='horizontal'

        self.l1 = Label(text=self.tName,size_hint_x=1)
        self.s1 = SlColor(min=self.min,max=self.max,value=self.value,size_hint_x=7)
        self.t1 = TxiColor(text=str(self.value),size_hint_x=2,multiline=False)

        self.add_widget(self.l1)
        self.add_widget(self.s1)
        self.add_widget(self.t1)

    def SetValue(self,value):
        self.value = value

    def ReDraw(self):
        self.s1.value = self.value
        self.t1.text = str(self.value)

class Display(BoxLayout):
    orientation='vertical'
    def __init__(self,**kwargs):
        super(Display,self).__init__(**kwargs)

        self.boxR = BoxColor(size_hint_y=1)
        self.boxR.SetUp('R',0,255)
        self.add_widget(self.boxR)

        self.boxG = BoxColor(size_hint_y=1)
        self.boxG.SetUp('G',0,255)
        self.add_widget(self.boxG)

        self.boxB = BoxColor(size_hint_y=1)
        self.boxB.SetUp('B',0,255)
        self.add_widget(self.boxB)

class MainApp(App):
    def build(self):
        layout = Display()
        return layout

if __name__=='__main__':
    MainApp().run()


実行結果※ python2.7 Linux Mint 19.2 上のものです

キモが BoxColor クラスなのは見れば判ると思うのですが…不可解な部分が有るんですよね。
ソレが変色させた部分。
実は普通に BoxColor に再描画処理を書いて子クラスから呼ばせる方法で作っていたのですが、どうしてもエラーが出る為、苦し紛れに書いたら動いてしまったのですよ。
ReDraw 関数の中身は見ての通り、各子クラスのメンバー変数に値を入れているだけです。…私の頭が古いせいか、子クラスのメンバー変数に直接値を代入するだけでも保守性が心配になるのですが…
どうして再描画されたのか?そもそも再描画のタイミングとは?動きはしたものの疑問がいっぱいです。

2020年2月5日水曜日

拳を作る

半年ぶり3度目。ついでに書いてしまうと初回は17年の11月です…製作が遅すぎる。
人間の指は開くと外側に、閉じると内側に集まるものでして、コレを表現するために指に捻じれ(ロール値)を入れていました。
※黄色の線のように指にロール値を入れて、赤線のように開閉するように調整している
ただ、左右反転を行うにあたってロール値が入っているといろいろと面倒なのでロール値を全て0にリセット、ロール値を前提としてた指の動きがおかしくなった所が前回までのお話。

先ず最初の作業として、各指の第一関節を直接角度を入力する方法から、ターゲット追従型に変えました。
※指の先端の先に見えるのがターゲット
で、次に人差し指、薬指、小指に関しては掌の中にある第一関節の根元の骨「中手骨」を追加。さらに中手骨のわずかな開閉を行う「骨間筋」を作り、中手骨を動かす事にしました。
骨間筋の収縮は各指先の先端が開閉方向に動いたときにストレッチするボーンを作りココから係数をとっています。
…とは言え本当にわずかにしか中手骨は開閉しませんが。

中手骨が八の字から平行になっていくのが判るでしょうか?

親指の付け根に肉が足りないような気もしますが、ほぼ指の隙間が無く拳が握れています。
ひとまずこれにて拳は一旦〆として次に行こうと思います。

2020年2月1日土曜日

諸々雑記


  • 昨年末に載せていた宝くじですが、結論から言うと大ハズレでした。

電源は入るのですがBIOS画面が出ない。
考えられる可能性はCPUが壊れている、BIOSが飛んでいる、マザーボード内蔵グラフィックが死んでいる等で、マザーボードのアンプ回路のみ無事である訳ですが…。
…外付けビデオボードを刺しても起動しなかった為、グラフィックの線は無くなりまして、はてコレを使うかと言うと…多分修理しようとすると新品より高くなりますね。
正月を挟んだので初期不良期間すら過ぎてしまって完全にゴミです。

ちなみに、ベストな状態は?というと当然完動品であるというのは最低条件ですが…
コレ、セット商品の抜き取り品だと踏んでいたのですよ。
で、1151はWindows10専用世代のボードですから、10のインストーラを使ってアクティベーションが通っていればそのまま使って、
CPU交換→ゲーミング用にしようかなと。駄目なら内蔵グラフィックのみで linux 機に。
Win10のアップデートはとっても主記憶装置に負荷をかけるので、HDDは絶対ダメなのは当然ですが、M.2SSDが載るならM.2にOSを入れるべきだと思います。ハイ。
ギルティギアの新作までにはゲーミングPCを用意したいのですけどねえ。
当ブログPVの7割はジャンク系記事だったりするのですが…今年はジャンクはあんまり手を出せない、というか節約しないといけないのです。


  • イベント終って

結局、イベントはその後あ号の攻略中に秋霜と平戸を取得して、残り時間をE3でコメットの熟練度を上げて終了。
…豪運ではあるのだけど、E2で石垣が取れるのをすっかり忘れていました。というわけで、石垣以外の全ての艦が揃いました。

なんだか色々と新しい任務が増えましたが…要するにウィークリーやマンスリーと並行して解けって事でして、フラグ管理がひたすら面倒くさいです。
数百もある任務の計算を母港に帰る度にやらせる訳にもいかないので、6個以下しか同時選択できないのでしょうけど…うーん。
そして、地味に面倒なのが六水の任務。どうもクウォータリーらしいのですけどね…
睦月型を遠征専用としていまして、同時ケッコンしてレベルを横並びにしていた関係で睦月、如月が出せません。
という事で、弥生と卯月を出しているのですが…ケッコン前で耐久24、ケッコン後で28のド直球の4n艦。
悲惨なのが6-4と6-5。夕張+弥生、卯月で攻略しなくてはならないのですが、火力にならない上に食らったら即大破の罰ゲームみたいな任務です。…いや、睦月、如月改二で揚陸車両載せれば良い訳で、セルフ縛りプレーしているから悪いのですが。


  • 以前 PSO2 は Ep3 で引退と書いていたのですが、 Ep2 でした。

アニメ見て気づきました。クーナの話の次辺りで引退したハズです。
アニメを見る限りだと案外悪くないものなんですけどねえ…コレがこのあと、学園コメディー、なんちゃってアメリカ、どういうわけか対戦艦大和、中世ファンタジーに遷移したっていうのだから字面だけで迷走感が半端ないです。


  • 半月ぶりにアッシュアームズのWikiを見たら…

新キャラ3機追加、新スキン追加、新システム追加、AI修正?(被害が出やすくなったという反応があるんですが)だそうで、更新速度がすごいですね。このペースで行くと半年後にはキャラクター数が100を突破するのでは?
以前から大量にいるスキルが説明と違う連中は修正されつつある(説明文を修正)そうですが、すでにCVが居ないキャラクターも出始めていて、キャラ追加の節操のなさが足を引っ張りそう。
…画集を出版するまで頑張って欲しいのですけどね。
新キャラのパーシングを見てぜかまし枠かな?と思ったら中の人まで同じで笑いました。

2020年1月20日月曜日

Blender でボーンのロール値を一括0にしてみる

月に150時間も空けば何をするか…睡眠時間を取り戻す。
まあ、そうなんですが。ひとまずサボっていた Blender を再開ですよ。今年は動画を作りたい。
さて、半身状態で制作を行っていますが、そろそろくっつけ合わせたいと言う事で、以前ボーンウェイトの両面化を行っていましたが、今回はボーンロール(つまりボーンの捻り角度)を一括で0にしたいと思います。

当然数百もあるものを手動な訳には行きませんのでスクリプトを流します

コード (Blender 2.79 用です)

import bpy

if bpy.context.mode == 'EDIT_ARMATURE':
    #print('EDIT_ARMATURE')
    for obj in bpy.context.selected_objects:
        #print(obj.name)
        # Use armature only
        if obj.type == 'ARMATURE':
            print(obj.name)
            for bone in obj.data.edit_bones:
                print(bone.name)
                bone.roll = 0

アーマチュアを選択し、編集モードで実行すると選択されたアーマチュアのボーンのロール値が全て0になります。

…うん、解ってたんだけどね。意図的にロール値を入れていた部分がハチャメチャになったよ。

…宿祢を殴ったオリバみたいな事に。

ここら辺は編集し直しかなあ。今後はこまめにこのスクリプトを実行する事にしよう。

2020年1月15日水曜日

アッシュアームズやってみたその4

Yakさんのイベントは気付くのが遅れてその日のうちにとは行きませんでしたが、終了できました。
各種150体という割と難度の高いクエストですが、私は溜まりに溜まった偵察3を使い、偵察ノーマルB森丘を周回しました。

次は自動周回が追加になるのだそうですが…又、〇〇勲章とか追加になるんでしょうかね?
人気投票の方は私がスクリーンショットを撮った時点ではヴィルさんの1%は私が投票しているというカオスな状態でしたが…
コレ、総得票数/1.5万辺りがアクティブユーザー数なんではないでしょうか?

といった所でアシュアから卒業したいと思います。
なんというか、重いのですよ。2か月程プレーしましたが、他と並行しているとは言えプレー時間が300時間を超えている状態。
スマホに入れずにコレなので、部屋に居る間中タブレットが稼働している状態に。

そして、メインクエストの枯渇。
コレが枯渇すると結晶石がデイリークエの100、ログボの100他になり、10回ガチャを無料で回せるのは月に1、2度。
まあ、列車を回していれば日に1度くらい1回ガチャを回すことも可能ですが。
この状態だと以前否定していた「新キャラが出る度に課金ガチャ」の可能性も無きにしも非ず。※まあ、そこまで無料でプレーさせてくれているのだから良心的とも言えますが

更にガチャでダブった際の「情報の断片」も手に入らないので、情報構成体を掘る必要が出てきて周回プレーが開幕します。

いや、このゲーム別にどのキャラが強すぎるって程バランスは悪くないですし、数体だけ強化すれば大抵どうにかなるのですが…
キャラ育成の終了が見えて来ているのですよね。恐らく近い将来レベルキャップ開放はすると思いますが。列車が追加になった時点で、それまでの同時レベル上げ可能数が6体から18体に増えた上で、列車の方が経験値効率が良い為、一気にレベル上げは加速しました。
…とは言えこのゲームのレベルは「アイテムとパーツ(ゲーム内通貨)を使って強化できる権利を得る」だけで、耐久以外のパラメータはほとんど上がらないのですが。


このゲームは割とハイペースに内容の更新があるのですが、改悪しちゃう事があるんですよねえ。オート操作とか。
サービス開始当時、戦闘終了時に毎回オート設定がオフになっていましたが、現在は一度オンにすると常にオン。
再戦するならともかく、ステージを変えてもチーム編成を変えてもオン。いやいや、AIさん操作下手くそなんだから勝手に動かすなよ、と。


  • 最後ですし、AIの残念さを少し解説してしまいましょう。

例えば、こんな戦闘。
空だけキャラを配置して、陸は無しの状態。

アッシュアームズの勝利条件は現状敵の殲滅で、敵も同様ですが、敵側はコレに加えて、味方側の最奥に到達すれば勝ちというルールがあります。
…このルールで、到達を妨げる陸のキャラが配置されていませんから、当然最奥に到達しそうな敵から優先して空対地攻撃しないといけません。
…が、AIは「極力前進してから手近の敵を倒す」という残念な思考で行動する為、前進してきている(到達しそうな)敵ほどスルーします。しかも打ち漏らしても倒しに引き返そうとしません。
結果、完全にスルーした敵が無傷で自軍の最奥に到達して敗退という事態が多発します。
アッシュアームズの自軍AIはゲームの戦闘ルールを理解していません
…開発の優先順位って奴が…


  • あとはやっぱり周回ですかね。

周回作業の苦痛を緩和する為に作業を追加しました…ってどう考えても矛盾していると思うんですよね。
単純にハイリスクハイリターンモードを追加するのではダメだったのかと。
消費合金数倍で報酬数倍とか。
もちろん、一方的に勝てるパターンが複数ある上に自動操作ツール使用者がやたらに有利なこのゲームですから対策は必要です。
毎回敵の編成が変わるとか、連戦するたび難易度と報酬がどんどん上がるが、敗退すると全て失う All or nothing モードとか、ハイリターンモードだけオート戦闘不可にして、連戦中に唐突に5x5パズルを挟むとか…

…ぶっちゃけてしまえば、当初の予定通り、戦闘中のカットイン演出を強化してコンシューマで出してくれた方が良かった気も…(乳揺れカットイン要員が多すぎて工数取られるから、新キャラが軒並み貧乳になりそうですが)

なんにしろ、惜しいゲームだなという印象でした。キャラ良し、メカ良し、世界観良し、戦闘の基本ルールも頭使って操作できて良かったです。イラスト集とかが出たら買ってみたいですね。

2020年1月6日月曜日

秋?イベ終了

一週間遅れで開始した秋?イベントはひとまず甲甲甲乙乙乙で1/3攻略完了。
お陰で大掃除がまだ終わってません。
コレに加えてフレッチャーも着てます。
…掘ってないんですけどね。なんという豪運。というか、新規を掘らないといけないって流れは辞めて良いと思うのですよ。堀用に海防艦やまるゆ、既存イベント艦があるのは良いと思うのですが。

今回、2期で初の大型イベントだそうです…といっても春の中型詐欺イベントがありましたからね。だいぶ、イベントというものが安定してきまして、序盤で実用度の高いアイテムを高難度で撒き、後半の高難度は趣味のアイテムという流れです。
又、札は相変わらずで、第一海域が5隻艦隊になるかと思いますが、6海域で最低59隻に札がつくのではないでしょうか?

開始時にメンテナンスが丸一日くらい時間がかかりましたが、クリスマス、年末、年始のオンメンテ分の仕込みに加えて新年クエまで仕込んでいたのであれば確かに納得です。

クリアした感想としては、E4以降を甲でやらない分には良イベントです。

ちなみにイベント開始時の資材


ラスダン前

クリア

アレ?バケツ?掘りを一切やらない上で援軍が来なければイベントに挑まないという牛歩戦術で進めました。又、EOの5-5と6-5の攻略はお休みしました。
中間報告時にE6の攻略者が45%だったのも納得です。

今回は良く考えられたイベントだと感じました。
E5(2ゲージ目)も一見すると春の残念イベントを彷彿とさせるような、潜水艦と空襲に水雷戦隊が殴られるだけのイベント…っぽいのですが、序盤で潜水艦と連戦後空襲に入ります。対策をしなければ潜水艦には一方的に負けますが、対策すればA以上、私は難易度乙だったので確実にS勝利2連続でした。
このためコンディション値(いわゆるキラキラ)が剥がれづらく、攻略しやすくなっていました。

又、今回特徴的だったのはギミックで、ギミックを解かないとボスへのルートが開かないといった必須のギミックが存在しません。
なんなら解かずに攻略する事も可能です。ちなみにE6乙の2個目のギミックは解かずにクリアしました。
さらに、ソロモンはレーダー射撃により大打撃を受けた海域だったと記憶していますが、不満が多かったのかレーダー射撃マスはありませんでした。

艦これのイベントにある不満点といえばざっくり3つ。
理不尽な「難易度」
同じことをやたらに繰り返す「反復」
艦隊に制限をかける「縛り」
だと思ってます。


  • 「難易度」

8分目程度を選択すれば良いわけです。甲勲章にこだわりがなければ。報酬も後半の甲のアイテムが人権級なら文句も出ますが、趣味のアイテムなら無理はしなくてもいいですし。尚、どんな難易度でも取得できるクリア報酬艦が人権級な点については不満がありません。


  • 「反復」

キラづけ…1艦隊を1回出撃させる度に12回1-1に出撃するとかいう苦行ですね。ちなみに私は一切やりません。
堀…春のフレッチャー堀でこのゲームは堀をしてはいけないと悟りました。多分、運営も「イベントで同海域に一定数出撃を続けた提督の数カ月後のアクティブ率→堀で爆死ないし燃え尽きた人の引退率」を算出したのではないでしょうか?
防空ギミック…わざわざ飛行機に殴られに行って、優勢状態を規定数とってくる虚無作業ですね。ある程度までは許せるのですが、限度がある気がします。


  • 「縛り」

バフがかかる史実艦、出撃制限がかかる大型艦、出禁になるハイパーズ等など…コレのおかげで、イベント告知が出ると、内容を予測し出撃艦を鍛える必要が出る等、定期試験感がバリバリ。
さらに、予測が外れれば、この艦隊イマイチだなあと思いながら出撃させてやっぱり負けたの繰り返し。「お気に入りの艦娘達で、貴方だけの無敵艦隊」という公式トップはなんだったのか。
ただ、今回は正解の艦隊は優遇のスタート地点及びルート、それ以外は迂回ルートから出発等で完全にゴールにたどり着けない程の制限はかけていなかったようです。
又、毎度面倒な「制空値計算」や「索敵値計算」も減ったような。コレ、表のパラメータに対してマスク値(表示されない裏パラメータ)が多すぎるんですよね。改修値の√★加算から始まって、装備種別に対する係数等々、攻略サイトの情報と外部の計算サイトを使ってやっと本当の値が判るという。
…ある程度の年数やってる提督で、この計算知らずにWikiに質問とか書くと袋叩きに逢うんですよね…アレはダメな文化です。
まぐれで通過出来る事もありますが、「自分で操作していてなんで通過したのかも判らない」コレに加えてルート分岐に一定ランダムなんかがあった日には計算が合っていたのかすら判らなくなっていく…


全体的に不満点に対して一定の回答をしたイベントだったかなあという印象です。
ちなみに細かい不満としては援軍で着た神通さんが探照灯を炊いていない事ですかね、軽巡棲姫ですら炊いていたのに。
当方はE6の2ゲージ目以降第二艦隊旗艦暁がひたすら探照灯を炊いていました。ロマンも大事です。

うーん今後は掘る気は無いんだけど、あ号消化分くらいはE5を回すかなあ…