ヘキサ日記 Blog

 

  • 2017年2月27日

    10周年!

               

     

     

    こんにちは、まつしたです。
    昨日、2月26日は、ヘキサドライブの創立記念日でした!

     

     

    20170227_10th

    本日の営業日から10周年!

    11年目に突入です。

     

    なんというか、あっという間…というのが正直な所。

     

    初めはプログラマー5人で始まったヘキサドライブが、
    少しずつ人数を増やし、10年で100人。
    10年の月日の中では既に卒業してしまったスタッフもいますが、
    その人たちも含め、優秀なスタッフ達が会社の歴史を作ってくれました。

     

    本当にありがとう。

     

     

    勿論、これまでやってこれたのは周りの方々のサポートも多大です。
    色々な事情に理解を示してくれたクライアント様や、
    私たちのプロダクトを評価して頂いたユーザー様、
    気軽に相談にのってくださった同業他社の皆様。
    お仕事をお手伝い頂いたパートナー会社の方々。
    専門学校や大学の先生方、スタッフのご家族の皆様。
    数え上げるとキリがありません。

     

    本当にありがとうございます。

     

     

    じたばたしながらの10年、
    しかしながら振り返ると自分達らしい10年だったと思っています。
    固い所は固く、それでいてチャレンジもしてきました。

     

    これからも、ヘキサドライブらしさを失わず、
    チャレンジを続けていきたいと思いますので、
    どうぞ応援宜しくお願い致します。


  •            

    三度の飯より鯵のたたき東京デザイナーのエドモンドです

    先日同郷の友人と久々に秋葉原に遊びに行ったのですが

    「私もそうだと思う、そうしようかな、あーわかるわかる、わかるしかない」

    と、いつものようにイエスマンをしていたところ気が付いたら5万円の海外のドールを購入していました。

    こういう人が壷を買うんだろうなと我ながら思いました

     

    さてさて本日はお絵かきはお休みをしてこちらで遊ぼうと思います。
    じゃじゃーん、羊毛フェルトです!

     

    1

    羊毛フェルトとは羊毛をフェルティングニードルという長めの針を使用しちくちく刺していくとあら不思議

    お人形などが作れるという手芸の一種です
    少し前に天下のダイソーさんで道具を買ってきて放置していたので手をつけてみようと思います

     

    今回はかわいいかわいいラグドールという種類猫ちゃんの顔を作ります!
    より頭の中のものに近く作りたいため完成イメージも描いてみました

     

    3

    さてさてこれを参考にさっそくかわいいかわいい猫ちゃんを作り始めます

     

     

    1.準備

     

    まずは羊毛フェルトを作る上で必要なものですが、

    羊毛、フェルティングニードル、フェルティング用マット、小さめのはさみ、などは必須です。

    その他にもパーツを繋ぐときの仮留め用のまちばりや、

    接着用のボンドなどがあると良いようです。
    また針が指に刺さる危険があるので(すごく痛い)羊毛フェルト道を極める予定の方は

    指を保護する用のカバーを購入すると安全ですね

     

     

    2.形を作っていく

     

    最初にフェルトをほぐした後にさまざまな方向から中心に向けニードルを刺していきます。

    2
    はじめからフェルトを手でまとめすぎたりすると固まってきたときに柔らかい箇所と固い箇所のむらができてしまうので注意です。
    これを繰り返していると…

     

    4
    いい感じにまとまって小籠包っぽくなってきましたね!

    今にも中から肉汁たっぷりのスープが出てきそうです
    ちなみにフェルティングニードルは大変折れやすいためご注意ください。
    前回ちくちくしていたときに針先が折れ、もこもこのカーペットの中に入り込み針先探しで作業が取り止めになりました。
    そして未だにその針先は見つからず迷宮入りしました。カーペットの上の生活がとてもスリリングですね

     

     

    3.耳や顔の模様をつける

     

    羊毛フェルトは繊維同士を絡めて形を作ります。パーツをつける作業が簡単でよいですね

    5
    耳は小さめにまるめ頭に向かってまたちくちく刺してゆきます。

     

     

    ちくちく…お顔の模様をつけます
    ちょっと耳が小さいかな?

     

    999

     

     

    おっ、雲行きが怪しくなってきましたね…

     

    888

     

     

    そして…

     

    35636

    完成~~!すご~い!!

    わ~い!かわいい~~!!

     

     

     3新規キャンバ777

    どうでしょうか?多少なりともイメージ図とは異なるものが完成いたしましたが
    人間の誰しもが抱えている理想と現実のギャップを上手く表現した作品になったのではないかと思います!

    皆さんも是非羊毛フェルトお試しください!

    ではでは


  •            

    どうも、タッキーです。

     

    本田翼さんがユニットを組んでくれなさそうなので、

    キャプテンの翼君にユニット申請を出そうかなと思っている昨今、

    皆さんは折り紙は好きですか?  

     

    私は技術こそさほど高くはありませんが、
    むらむらっと「何でもいいからものを作りたいなぁ」と思ったときに
    折り紙を折って遊んだりしております。

    基本私は、1枚の紙に切り込みを入れて、折鶴を連結させた形で折る、
    「連鶴」というジャンルの折り方で作ります。

    「連鶴」という折り方には、いくつかの折り方があるようですが、

    私は特に意識せずに作っておりました。

     

    【最近作った「連鶴」の例】

    DSC_0658
    「芙蓉(ふよう)」という作品らしいです。今日知りました(笑)

    消しゴムよりも小さく折ってます。

    DSC_0724
    こちらはB4の印刷用紙1枚を全て使って作成した「連鶴」。

    「タッキー川クリスタル」です。...オリジナルです、はい。

     

    鶴の折り方と、つなげ方がある程度頭にインプットされていれば
    どこでも紙一枚あれば何パターンでも創作ができてしまう代物が「連鶴」です。

    しかし、ここで1つの問題を発見しました。
    「俺、ただボーっと折ってるだけだ!!」
    完成図の目標もなく、「こうしたらどうなるだろう?」という実験をした結果

    似通ったものばかりを作ってしまっていたようです。

    「やっぱりものづくりをするからにはゴールを決めて作れるようにならねば!!」
    という方針をもっていこうと思いました。

     

    ゴールを目指して闇雲に、道をうろうろしてても意味がありません。
    ゴールから逆算して最短距離を見極める力も欲しいところです。

    私はそんな将棋のようなシミュレーションは大の苦手なので、
    この機会に道選びをしていく力を身につけて行きたいですね。

    (おしまい。。。)

     

     

    ここから本編です。

    「にらみ折り」という高等テクニックをマスターしたいと思います!!

    「にらみ折り」とは・・・完成された折り紙と、折り紙の展開図をもとに、

    折り方を探るテクニックのことを言います。

    にらみを利かせるためには、どのように折るべきかを見極める折りの知識と経験が必要となります。

     

    今回の「にらみ折り」第1弾は慣れ親しんだ折鶴の展開図をにらむことで、
    「にらみ折り」道に入門したいと思います。

     

    まず、折鶴の展開図はこちらです。
    展開図_折鶴

    折鶴の折り方を順に追っています。

     

    ①正方形を作ります(ざっくり)

    折鶴01  展開図_折鶴04

    ここまでの工程で出来る展開図です。

    白い面を表として青が谷折り、赤が山折りです。

    ②鶴の基本形と呼ばれる(らしい)形にします。

    折鶴02  展開図_折鶴03

    ここまでの工程で出来る展開図です。
    白い面を表として青が谷折り、赤が山折りです(2回目)。

    ③痩せさせます。

    折鶴03  展開図_折鶴02

    ここまで…(以下略)。

    ④頭と尾を作って完成です。

    折鶴04  展開図_折鶴01

    (以下略)。

    こうしてみると、
    展開図に使われている線に、より複雑に線が入り組んでいることがわかりますね。

     展開図_折鶴      展開図_折鶴01

     

    折り目をつけるためにつけられた線が加わっているのだと思われます。
    展開図に書かれている線をもとに折り目の線がどこに出来そうか考えて、
    完成図と展開図のにらめっこをするとよさそうだということでしょうか。

     

    こんな感じで何度か「にらみ折り」の研究をして、
    いつか「マスター・ニラミ・オリ」になりたいものです。
    ゆくゆくは自身の創作折り紙なんかも出来るようになったらいいなぁなんて。

     

    長くなったので、今回はここまでです。
    それでは、失礼して。。。


  • 2017年2月22日

    TAとOpenMaya SkinCluster

               

     こんにちは、Ritaro です。

     

     こちらに記事を書くのはこれで2回目となります。

    今回も、よろしくお願い致します。

     

     TAにとって開発上の問題点を解くのに 技術的な引き出しを色々な持っておくことが必要、

    と前回の記事に書いた部分を・・もう少し紹介したいと思います。

     

    近年はゲームを開発する上で DCCツール(MayaやMotionBuilder)の知識だけでなく、

    ミドルウェア(UnityやUnrealEngine)の知識もたくさん 必要となって来ているという点は、

    もちろんあります。

    その中でTAがグラフィックに関する部分を任されると 必然的にシェーダーの開発の話にもなったりします。

    で、TAなのですからその作業というのは、

    ゲームで使うと決められるようなシェーダーの判断材料の制作になります。

    ”前準備”ですね。

    DCC側でのデータの準備をどう工夫してミドルウェアに持っていくのか、

    その場合の作業簡易ツールはどうあるべきか、

    ミドルウェア側ではそのデータを使ってどう組むと目的に近いシェーダーになるのか。

    更にはその処理負荷はどのくらいなのかもです。

    これはこれで、たくさん引き出しが必要そうですね。

     

    と、更にもう1つの引き出しとしては、アニメーションに関してもあるはずです。

    キャラクターセットアップ用のツールやモーション出力用のツールなども

    ミドルウェアと合わせて用意したりします。

    これはこれで、たくさんの引き出しが必要そうです~。

     

     ちょっと具体的な、面白い対処法、

    でもあったら『おお、使えるかも』 ・・って思うようなものをまた1つご紹介してみましょう。

     


     

    「OpenMayaを使ってSkinClusterを取得してツールの高速化をはかりたい!!」

     

    Mayaを使ってキャラクター用のツールを開発する時、

    避けて通れないのかSkinBindしたポリゴンメッシュデータの編集、

    特にWeight値に関するツール開発は最たるものです。

    しかも通常のPythonコマンドでも便利ツールは作れるのに・・

    処理速度がイマイチなものが出来上がります。

     

     便利ツール出来たー!! > 実行 > 遅~い ;_;   です。

     

    そこで、OpenMayaなるものに挑戦して高速化を図る訳です。

    OpenMayaの引き出しも必要になって来ました~。

     

    情報として良く探れるものにはWeight値を扱う例があったりします、

    ・・・・ありがたきかな(「一握の砂」)。

    で、そのはじめの部分はこんな感じのスクリプトから山開きしています。

     

    clusterName = 'skinCluster1'
    
    selList = OpenMaya.MSelectionList()
    selList.add(clusterName)
    clusterNode = OpenMaya.MObject()
    selList.getDependNode(0, clusterNode)
    skinFn = OpenMayaAnim.MFnSkinCluster(clusterNode)
    
    infDags = OpenMaya.MDagPathArray()
    skinFn.influenceObjects(infDags)
    ・・・・
    

    で、私的には気になる、”前準備”的なところがある訳なんです。

    ?? ‘skinCluster1′ って書いてあるスキンクラスター名はどうやって取ってるの?。

     

    MayaのSkinBindされたキャラクターデータを見ると、

    そのJointにはそのポリゴンメッシュの数分だけ SkinClusterも存在しています。

    ここはその数だけのループ処理が発生しているはずです。

     

    こんなアプローチでどうぞ。

    SkinBindされたポリゴンを1つ選択した状態で実行すると

    スキンクラスター名が取得出来ます。

     

    *— ”前々準備”

    Iterator には、以下あり。

    kDepthFirst = 深さ優先探索 、kBreadthFirst = 幅優先探索

     

    dagIterator = OpenMaya.MItDag(OpenMaya.MItDag.kDepthFirst,OpenMaya.MFn.kInvalid)

    で、前のデータが残っている場合があるので、リセットします。

    dagIterator.reset(***.node(),OpenMaya.MItDag.kDepthFirst,OpenMaya.MFn.kInvalid)

    if文の curr_obj.hasFn(OpenMaya.MFn.kMesh) は 選択したものがポリゴンメッシュなら、です。

    そして、skinFnの名前 skinFn.name() がスキンクラスター名です。

    ポリゴンメッシュにスキンクラスター名が無い場合は、

    BindSkinされてないポリゴンとして別処理(処理を飛ばす等が)出来ます。

    *—

    (Weight値処理部分は記載しておりません)
    <ツールは自己責任でお使いください>

     

    import maya.OpenMaya as OpenMaya
    import maya.OpenMayaAnim as OpenMayaAnim
    
    
    selList = OpenMaya.MSelectionList()
    OpenMaya.MGlobal.getActiveSelectionList(selList)
    
    selList_iter = OpenMaya.MItSelectionList(selList)
    sel_obj = OpenMaya.MObject()
    selList_iter.getDependNode(sel_obj)
    DagPath = OpenMaya.MDagPath.getAPathTo(sel_obj)
    
    dagIterator = OpenMaya.MItDag(OpenMaya.MItDag.kDepthFirst,
        OpenMaya.MFn.kInvalid)
    dagIterator.reset(DagPath.node(),OpenMaya.MItDag.kDepthFirst,
        OpenMaya.MFn.kInvalid)
    
    clusterName = ""
    while not dagIterator.isDone():
        curr_obj = dagIterator.currentItem()
        if (curr_obj.hasFn(OpenMaya.MFn.kMesh)):
            objMeshName = OpenMaya.MObject(curr_obj)
            itDG = OpenMaya.MItDependencyGraph(objMeshName,
                OpenMaya.MFn.kSkinClusterFilter,
                OpenMaya.MItDependencyGraph.kUpstream)
    
            while not itDG.isDone():
                try:
                    currentCluster = itDG.currentItem()
                    skinFn = OpenMayaAnim.MFnSkinCluster(currentCluster)
                    clusterName = skinFn.name()
                    break
                except:
                    clusterName = ""
        dagIterator.next()
    
    print clusterName
    

     

     


  •            

    こんにちは

    東京開発、デザイナーのモリモです。

     今までアート関連の投稿をいくつかしてきましたが、今回は全く変わった話になります。

     

     

    全くの料理ド素人ですが、ココナッツミルクアイスを作っていきます!

     

    以前、千葉のタイ料理屋さんで食べたココナッツミルクアイスが忘れられず・・・

    あの味を家で無限に食べられたらと思い立ちました。

     

    早速材料を集めました↓

     20170221_2

    (会社近くのKルディで大体揃いました!買いすぎですね!)

     

    千葉のタイ料理屋さんでは謎のタピオカ入りの緑色ココナッツミルクが器の底に敷かれてあり、その上に細切りにしたパパイヤの実入りのココナッツミルクアイスが乗っかっている

    というものでしたが。。。パパイヤの実は近所では手に入りませんでしたorz

     

     

    パパイヤの実が入ってると食感がおもしろく、食べてて飽きがこないのです!

    乾燥マンゴーや干し芋を使うか・・?と考えましたが、今回はナタデココで代用してみようと思います!

    (地味にアイスの上に乗っけたかったミントも手に入りませんでした。フォトショで合成すりゃいいかと思いましたがさすがに自重しました。)

     

     

    材料についてはネットで調べたものをベースに

    【アイス】

    ・ココナッツミルク500ml

    ・卵黄4個

    ・生クリーム100ml

    ・グラニュー糖70g

    【その他】

    ・下敷きのタピオカ入りココナッツミルク

    ・ココナッツロング

    ・ナタデココ(パパイヤの代用)←写真のものには入れ忘れてますorz

     

    完成です!

     20170221_1

    (Dイソーで200円出して買ったアイスクリームボーラーを使ったのですが、使うのが難しくてグダグダになってしまいました。。)

     

    ~試食した感想~

    普通のバニラアイスと大して変わらないやん。。

    これを残り500グラム食べきらないといけないのか。。。orz

     

    以下敗因です

    ・卵黄を4個も入れてしまったので、すっきりしたココナッツの風味が消えてしまった

    ・下敷きのタピオカミルクの味もココナッツだったので、抹茶ミルクとかに代えるとメリハリが効きそう

    ・ ココナッツロング入れすぎて砂利を食べているみたい

    などなど。。。

     

    見事に失敗してしまいましたが、上白糖ではなく、よりココナッツ味に適しているらしいグラニュー糖を入れていた事など良い偶然もありました!

     

     

    次に作るときはしっかり研究した上で、お店のココナッツミルクアイスを再現してみようと思います!プロを舐めたらだめですね!!


  • 2017年2月20日

    ゲームと個人情報

               

    今週”ニーア オートマタ”が発売するのでテンション上がり始めています。おのってぃです。

     

    前回のブログで「生体情報を簡単にとる方法的なものの紹介しようかな」と最後にチラッといいましたが、

    準備時間が足りなかったため、第二回にしてすでに脱線回になります。

     

     

    ゲーム内で主人公のキャラクリエイトは昔からありましたが、

    僕が知っている限り、前世代機の頃から自分の顔を付属のカメラで正面から撮影し、

    それをゲーム内アバターに反映させるソフトが多数出始めた気がします。

    近年では顔のパーツが細分され、より自分に近い顔を作成することも可能になっていますね。

     

    それに関連してこんな記事がありました。

    生体情報に関するゲームと個人情報保護法の関係

    http://jp.gamesindustry.biz/article/1702/17020802/

    さらに原文に近いところではこちら https://www.bloomberglaw.com/public/desktop/document/RICARDO_VIGIL_ET_AL_Plaintiffs__against__TAKETWO_INTERACTIVE_SOFT?1487556562

     

    簡単に記事をまとめると NBA2K15において、

    ・ハード専用のカメラを利用して、自分の顔をスキャンすることでオリジナルキャラクタを作る機能がある

    ・そのキャラクタをオンライン対戦で利用できる

    上記二点の合わせ技で、オンラインでオリジナルキャラクタを利用するために

    そのキャラクタ情報をTake-Two Interactive Software内に収集・保持する必要があり

    そのことが生体情報プライバシー法案に違反しているのではないか、と集団訴訟を受けたそうです。

     

    結果的に今回訴訟は退けられたものの、

    技術の進歩によりゲームは今までよりも多くのユーザー情報を収集・保持することができ、

    一方で、個人情報のデジタルデータについての各国の法整備もこれから進んでいくと予想されるので、

    ユーザー情報の利用については視界の片隅で気にしておく必要がありそうですね。

     

     

    今週発売の”スパロボV”でクスィーガンダム・ブラックサレナ・ヴィルキスの3体をメインで常時使用しようと思っておりテンション上がり始めているおのってぃでした。


  • 2017年2月17日

    本日の Maya Python API2.0

               

    皆様、スープカレーは食べていますか。ヨセミテです。

    なんということでしょう、スープカレーの話題が切れてしまいました。

    そろそろ新規開拓をしたいところ。あぁ、気軽に北海道に行きたい。

     

     


     

    • Maya Python API2.0の話

    今回も前回同様、Maya Python API2.0を触っていこうと思います。

    さて、ブログを書き出した段階で特に何をするかを考えておりませんでした。

    勉強の機会としてAPIリファレンスを眺めてあまり触ったことの無いクラスから何が出来るかを考えて試したいと思います。

     

    ところで、mayaAPIのクラスの名称には「M~」、「MFn~」、「MPx~」、「MIt~」の4種類の頭文字があり、以下のサポートで命名規則の意味合いが記述されています。

     

    • クラスの命名規則

    https://knowledge.autodesk.com/ja/search-result/caas/CloudHelp/cloudhelp/2015/JPN/Maya-SDK/files/API-Naming-Conventions-htm.html

     

    プログラミング知識の浅い僕としてはちょっと難しかったので、以下の様な認識をしています。(浅学ゆえ、完全に正しい認識ではないかも知れません)

     

    • M~ :ベクターや選択リスト等、取り扱うデータを作成するためのクラス(MGlobalのような例外もある)。
    • MFn~ : cmdsのような実行するための関数群。
    • MPx~ : ノードやコマンドを作成したい際に利用するクラス。
    • MIt~ : MFn同様、実行するための関数群。頂点のような複数の処理対象を前提に考えられている。

     

    今回の目的である「良く知らないクラスを即興で試す」に適するのはMFn、もしくはMItに属するクラスですね。

    試しに「MFnTransform」を使ってみることにします。transformノードを扱うための関数群らしいので覚えておくと汎用性がありそうです。

     


     

    キャプチャ3

    シーンに適当なポリゴンモデルを作成します。今回の実行環境はmaya2017です。

     

    ここで利用しているMGlobalというクラスは汎用的な値を取得できるクラスで現在選択されているオブジェクトもMGlobalでMSelectionListとして取得できます。そしてMFn系のクラスを利用するために使うMDagPathはMselectionListから取得できます。

     

    import maya.api.OpenMaya as om2
    selList = om2.MGlobal.getActiveSelectionList() # 選択対象からSelectionListを取得
    selDag = selList.getDagPath(0) # MSelectionListからindexを指定してDagPathの取得
    MFnTransIns = om2.MFnTransform(selList.getDagPath(0)) # MFnTransFormインスタンスを作成
    

     

    これでMFn関数群の利用が可能になりました。

    以下を入力するとcmdsライブラリでも出来たscaleコマンドと同じようなことが出来ました。なんだか懐かしい気持ちになります。

    MFnTransIns.setScale([4.0,1.0,2.0]) # スケール値を設定
    print MFnTransIns.scale() # transformが保持するスケール値を取得
    
    # 実行結果
    [4.0, 1.0, 2.0]
    

    同様に移動値と回転値もMFnクラスで取得、設定ができました。

    scaleと異なり、移動値MVectorクラスで指定しないといけなかったり、空間指定をMSpaceクラスで定義されている定数で指定したりが必要でしたが、概ねcmdsと同様の処理を行うことは可能そうでした。

    MFnTransIns.setRotationComponents([45.0, 45.0, 45.0, 1], om2.MSpace.kTransform) # 回転値を設定
    print MFnTransIns.rotationComponents() # 回転値を取得
    MFnTransIns.setTranslation(om2.MVector([5.0, 10.0, 15.0]), om2.MSpace.kWorld) # 移動値を設定
    print MFnTransIns.translation(om2.MSpace.kWorld) # 移動値を取得
    

    キャプチャ4

     

    これで次からトランスフォームを扱う記述を書いていくことが問題なく出来そうです。

    Maya Python API2.0では今回のようなDagPathを取得する流れでMFn関数群は大概が利用可能になるはずです。コマンド化しないとヒストリに残らないことだけは注意して下さい。

    段々理解できてきた、高速で扱いのしやすいMaya Python API2.0。是非とも有効利用したいところです。

    ではでは

     

     


  •            

    ハローハロー。東京デザイナーのとりっぴー です。

     

    突然ですが、皆さんは「リフレッシュ」できていますか?
    学生の方は課題や就職活動、社会人の方はお仕事など、
    忙しい毎日をお過ごしの方も多いのではと思います

     

    私は、学校や仕事のことなどを考える「オン」の状態から
    オフ」のリラックスモードに切り替えるのがあまり得意ではなく…。
    とはいえ、ずっと「オン」の状態だと疲れてしまい、効率も良くないですよね
    やはり時には、難しいことを考えないで思いっきり楽しめるような、
    リフレッシュの時間を作ることも、心身の健康には大切かと思います

     

    私の場合、旅行や写真撮影などの趣味が良いリフレッシュになっています

    本日は、以前行って非常に素晴らしかった、宮城蔵王キツネ村をご紹介します

     

    森の中に整備された園内では、様々な種類のキツネが100頭以上放し飼いにされていて、
    大自然に近い形で、のびのびと過ごすキツネたちの様子を見ることができます。
    (放し飼いされているキツネに触るのはNGですが、
    「ふれあいコーナー」のどうぶつは係員さんの指導のもと、ふれあえるようですよ)


    20170216_fox_a2 20170216_fox_c
    基本的に大人しいのですが、カメラを構えてその場でじっと動かないで居ると、
    後ろから近寄ってきてつんつんされたりします。
    振り向くと逃げてしまうので、臆病なのにいたずらっ子なんですね。(かわいい・・・)

     

     20170216_fox_a 20170216_fox_d3

    カメラ目線、いただきました!(か、かわいい・・・・・・)

     

    20170216_fox_b 20170216_fox_b2
    お天気が良く、ひなたぼっこをしながらお昼寝しているキツネがたくさん居ました。(とても、かわいい・・・・・・)

     

    20170216_fox_c2 20170216_fox_d2
    凛々しかったり、あくびをしていたり、多彩な表情を見られるのも魅力です。(やっぱり、かわいい・・・・・・)

     

    20170216_fox_e_heart
    ハートの形で寝そべっている2頭を発見。ここはもはや、地上の楽園(So Pretty・・・・・・!)

     

    …とこんな塩梅で、何時間も楽しんでいたのでカメラのデータがキツネたちでいっぱいに。

    もはやキツネのモフモフ以外のことは、考えられなくなります

     

    ご興味のある方は、足を伸ばしてみるのもいかがでしょうか。

    大変愛らしいキツネに夢中になってしまいますが、園内のルールを守りお互い安全に楽しめるよう気配りも忘れずに!

     

    自分なりの「リフレッシュ」の時間も大切にすることで、
    良い状態で仕事ができ、良いものを作るサイクルを心がけていきます。

    それではまたの機会に

     

     


  •            

    こんにちは。ブリテンです。

     

    半年ぐらい前に思い立ってバイオリンを始めました。

    自分のバイオリンも購入し、毎日せっせと練習しています。

    20170215

     

    とはいえ、バイオリンは難しい楽器です。独学ではきつい。

    そんなわけで、毎週せっせとバイオリン教室に通っています。

    こういった所謂○○教室のいい所は、きちんとカリキュラムが組まれている所です。

    つまり、

     

    ①バイオリンの持ち方を覚える 

     

    ②音の出し方を覚える

     

    ③音をいくつか出して、繋げる

     

    ④(習ったことで出来る)曲を弾く

     

    のような基本サイクルを繰り返していくことで、プレイヤーのバイオリン技術を向上させるわけですね。

    いわば、「バイオリンのレベルデザイン」なわけです。

     

    プレイヤーがバイオリンに挫折してしまわぬよう、

    プレイヤーがバイオリンに飽きてしまわぬよう、

    プレイヤーがバイオリンが上達していることが実感できるよう、

    「バイオリン教室のレベルデザイナー」はきっと頭を悩ませ、捻らせたはずでしょう。

     

    しかしその丁寧な努力は「音楽を楽しんでもらうこと」に繋がり、

    「プレイヤーの満足度」に繋がります。

     

    「ゲームのレベルデザイン」をする上でも、この丁寧な努力を怠らないようにしたいものですね。

     

     

     

     

     

     

     

     

     

     


  •            

    Switchの予約ができてゼルダが待ち遠しい某(なにがし)です
    スプラトゥーン2の試射会もとても楽しみにしています

     

     

    そういえば今日はバレンタインですね。

     

     

    しかし、今回はUnityのプログラムネタです。ごめんなさい。
    新しいことではないですが、uGUIでよくある問題の対処法をひとつ紹介します。

     

     

    uGUIはとっつきやすく便利ですが、

     

    スクロールビュー上のボタン押しにくい(クリックしにくい)

     

    という問題に悩まされる人は多いんじゃないかと思います。

     

     

    スクロールビュー上のボタンをドラッグするとスクロールが始まりますが、
    この時点でボタンに指を離したイベントが発生して押下状態がキャンセルされ、
    クリックイベントの対象から外れてしまいます

     

    だから、少しでもドラッグするとボタンがクリックできず、押しにくいわけですね・・・

     

    マウスならまだマシですが、
    これがタッチ操作のときは気になるので、なんとかしたいと思います

     

     

    考えられる方針は、

     

    1. ドラッグイベントを開始するドラッグ距離の閾値を与える(ドラッグ判定の遅延)。
    2. ドラッグ開始前に押下していたボタンに、
      ドラッグ終了時にクリックイベントを直接飛ばす(ドラッグで押下状態をキャンセルしない)。

     

    こんなところでしょうか。

     

     

    1.は一瞬でできます

     

    EventSystemコンポーネントのDrag Threshold(pixelDragThreshold)がまさにドラッグ判定の閾値です。
    これを大きめの値に設定すれば良いのですが、すべてのドラッグ判定に影響するのがイマイチな感じです

     

    それに、スクロールビューのスクロール方向とは異なる向きの移動にも反応するため、
    なんだか少しやりたいことと違う気がします

     

     

    イベントの発行はBaseInputModuleの仕事であり、
    普通なら、その派生クラスであるTouchInputModuleStandaloneInputModuleに任せていると思います。

     

    BaseInputModuleを継承して、独自のイベント管理を実装するのも良い気がしますが、
    それは仰々しいのでイベント処理側で簡単に対応します

     

     

    今回は2.の方針で考えます。

     

     

    実装の前に仕組みへの理解を深めるため、まずUnityのイベント処理の流れを簡単に説明します。

     

    1. タッチ入力されると、ポインティングされた座標にカメラからレイキャストを飛ばす。
      (対象はRaycastTargetにチェックを入れたGraphic派生コンポーネントを持つゲームオブジェクト)
    2. レイキャストに一番手前でヒットしたオブジェクトから親オブジェクトへと辿っていき、
      そのときのイベントに対応したイベントハンドラを持つゲームオブジェクトを探す。
      (例えば、OnPointerDownイベントならIPointerDownHandlerが対応)
    3. 見つけたゲームオブジェクトに対してイベント処理のメッセージを送信する。

     

    起点となるオブジェクトを決定して、親を辿ってイベントハンドラを探す、
    という流れを理解すれば、イベントシステムの使い方が見えてきます。

     

     

    これもあるある話だと思うのですが、
    スクロールビューの要素となるゲームオブジェクトにEventTriggerを持たせると、
    ドラッグイベントも全てここで奪われてスクロールできなくなるといった問題が起きます。
    上の処理内容を知らないと混乱しますよね。

     

     

    このあたりの挙動はドキュメントでは詳しく説明されていなかったりしますが、
    uGUIって実はブラックボックスではないんです。

     

    Unity-Technologies / UI — Bitbucket

     

    UnityさんがBitbucket上でuGUIのソースコードを公開しています。
    何かと困ったらソースコードを見てみるのが早いです。

     

     

    実際にソースコードを見てみると、PointerEventDataオブジェクトに
    押下中オブジェクト(pointerPress)ドラッグ中オブジェクト(pointerDrag)への参照を持たせて、
    これをそのままイベントシステムで利用しているのがわかります。

     

    ドラッグイベント処理では、pointerPressとpointerDragが別のオブジェクトだった場合、
    pointerPressにOnPointerUpイベントを送信して、参照をnullに差し替えています。

     

    とすると、それまでにpointerPressで持っていた参照を独自で記憶するしかないですね

     

     

    ということで、ScrollRectを拡張します。(ここまで長かった・・・)

     

    1. OnInitializePotentialDragでpointerPressを記憶
    2. OnEndDragのときの指の位置を見て、改めてレイキャストを飛ばして
      記憶していたpointerPressにヒットすれば、OnPointerClickイベントを送信する。

     

    実装例を以下に示します。

     

    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    public class CustomScrollRect : ScrollRect
    {
    	public override void OnInitializePotentialDrag(PointerEventData eventData)
    	{
    		var lastObj = EventSystem.current.currentSelectedGameObject;
    
    		base.OnInitializePotentialDrag(eventData);
    		if(!checkValidEvent(eventData)) return;
    
    		// 直前の選択オブジェクトを記憶
    		_lastSelectedObj = null;
    		if(lastObj != null) {
    			_lastSelectedObj = lastObj;
    		}
    	}
    
    	public override void OnEndDrag(PointerEventData eventData)
    	{
    		base.OnEndDrag(eventData);
    		if(!checkValidEvent(eventData)) return;
    
    		// 直前の選択オブジェクトがあればイベント通知
    		if(_lastSelectedObj != null) {
    			EventSystem.current.RaycastAll(eventData, _raycastResults);
    			var raycast = getFirstRaycast(_raycastResults);
    			_raycastResults.Clear();
    
    			notifyClickEvent(raycast, eventData);
    		}
    
    		_lastSelectedObj = null;
    	}
    
    	protected static RaycastResult getFirstRaycast(IEnumerable results)
    	{
    		foreach(var result in results) {
    			if(result.gameObject != null) {
    				return result;
    			}
    		}
    		return new RaycastResult();
    	}
    
    	protected void notifyClickEvent(RaycastResult raycast, PointerEventData original)
    	{
    		if(_lastSelectedObj == null) return;
    
    		var target = raycast.gameObject;
    		if(target == null) return;
    
    		// イベントハンドラを取得
    		var handler = ExecuteEvents.GetEventHandler(target);
    		if(handler == null) return;
    		if(handler != _lastSelectedObj) return;
    
    		// 通知用のイベントデータ生成
    		var eventData = copyEventData(original);
    		eventData.pointerCurrentRaycast = raycast;
    		eventData.pointerPressRaycast = raycast;
    		eventData.pointerPress = handler;
    		eventData.rawPointerPress = target;
    		eventData.eligibleForClick = true;
    
    		// イベント実行
    		ExecuteEvents.Execute(eventData.pointerPress, eventData, ExecuteEvents.pointerClickHandler);
    	}
    
    	protected bool checkValidEvent(PointerEventData eventData)
    	{
    		if(eventData.button != PointerEventData.InputButton.Left) {
    			return false;
    		}
    
    		return IsActive();
    	}
    
    	protected PointerEventData copyEventData(PointerEventData original)
    	{
    		return new PointerEventData(EventSystem.current) {
    			selectedObject = original.selectedObject,
    			hovered = original.hovered,
    			button = original.button,
    			clickCount = original.clickCount,
    			clickTime = original.clickTime,
    			delta = original.delta,
    			dragging = original.dragging,
    			eligibleForClick = original.eligibleForClick,
    			pointerCurrentRaycast = original.pointerCurrentRaycast,
    			pointerDrag = original.pointerDrag,
    			pointerEnter = original.pointerEnter,
    			pointerId = original.pointerId,
    			pointerPress = original.pointerPress,
    			pointerPressRaycast = original.pointerPressRaycast,
    			position = original.position,
    			pressPosition = original.pressPosition,
    			rawPointerPress = original.rawPointerPress,
    			scrollDelta = original.scrollDelta,
    			useDragThreshold = original.useDragThreshold,
    		};
    	}
    
    	private static List _raycastResults = new List();
    
    	private GameObject _lastSelectedObj = null;
    }

     

    使用中のイベントデータを書き換えると不都合がありそうなので、
    強引ですが丸ごとコピーしたものを一部書き換えて使ってます。

     

    これだけでだいぶボタンを押しやすくなり、押しやすさ改善の基礎はできました。

     

     

    あとは、

     

    • ドラッグ開始時にOnPointerUpイベントが呼ばれてしまうのを
      OnPointerClickとタイミングを合わせる
      (ボタンの押下時アニメーションを継続したい)。
    • 一定距離スクロールしたら、記憶したpointerPressを忘れて、
      クリックイベントが飛ばないようにする。

     

    このあたり対応すれば、なんだかとっても良い感じになるでしょう。

     

    記事が長くなったので、この先の説明は割愛しますが、
    今回の話を理解していれば難しい話ではないと思います。

     

     

    実は、去年秋にリリースした「アイテム代は経費で落ちない ~no item, no quest~」では、
    ここまで手が回らなかったんです。やり残したことのひとつでした・・・

     

    このタイトルはあと少しだけアップデート予定があるので、
    3月のアップデート内容にスクロールの挙動改善を入れました
    アップデートによってどのように変わるか見てみると、なるほどなと思っていただけると思います

     

    それでは、
    「アイテム代は経費で落ちない ~no item, no quest~」
    をよろしくお願いします(宣伝)


ヘキサブログ ピックアップ



過去の日記はこちら

2017年3月
« 2月    
 12345
6789101112
13141516171819
20212223242526
2728293031