2015年3月11日水曜日

2階オフィスの紹介

このエントリーをはてなブックマークに追加

スタッフの木下です。
予定より随分遅れてしまいましたが、2Fオフィスの改装がほぼ完成しましたので、ご紹介したいと思います(゚∀゚)♪

改装前までは執務スペースが4部屋と共有スペースが1つという感じでしたが、現在は大きな執務スペースが1つと共有スペース、総務スペース、社長室、和室という感じでガラリと雰囲気が変わりました。

ではまず入り口前にある会議室からご紹介いたします!

【会議室】





以前は全面真っ黒だった壁紙は一部、インベーダーゲームの壁紙に変わりました!!インベーダーゲーム柄の壁紙は今まで見たことがなく、初めてみた時はとっても斬新で思わず2度見をしてしまいました(゚д゚)☆
以前よりも遊び心が感じられる空間になっております^^


それでは中に入ってみましょう〜☆

扉を開けて見える景色はこんな感じになっております。






ではまずこちらの共有スペースからご紹介したいと思います!

【共有スペース】

こちらは5階の共有スペースと少し雰囲気が似ている印象で、2階も負けじとオシャレな仕上がりとなっております♪
やわらかい照明のため、肌がキレイに見えて女性にとって嬉しい効果ですよね^^w

また、全階共通して木の机とイスが2階にも用意されています!
ここでご飯を食べたり、休憩をとったりなど様々なことに活用されています。
最近ではバレンタインということで女性陣から送られた、おいしそうなチョコがたくさんおいてありました♡





2階も他の階同様、フリードリンクとなっております!
ドリンクスペースもこのようにキレイに収納されていますね♪
お茶やコーラ、野菜ジュース、紅茶、コーヒーなど様々な種類があるので、気分の合わせて飲み物も選べるのでとってもうれしいサービスです^^
私事ですが、さむ〜い今の時期はホットココアが癒やしのひとときとなっております(๑´ڡ`๑) 



ではでは次は執務スペースです^^

【執務スペース】




2階の執務スペースは青い壁紙となっており、現在あんさんぶるガールズチームとスーパーライトチームが作業をされています。 

私も一時期こちらの部屋を利用していましたが、静かな空間で集中しやすい雰囲気でした。
青色の壁紙の効果なのかな?という気がして調べてみると、実際青色には冷静になる効果があったり、飽きさせず集中力を高めることの出来る色なんだそうです!
やけに納得してしまいました♪


続いてはこちらです〜٩(๑´3`๑)۶

【畳部屋】





まぁなんて立派な富士山なんでしょう!
こういった黒い系の色の畳は初めてみましたが、畳の色が違うだけで、今までにない雰囲気でしぶ〜い和室になっています^^
また3階にもありますが、こちらも掘りごたつとなっており、ずっと正座をしなくてもいいから楽ですね♪


最近はここでお昼ごはんを食べていますが、個室ということもあり思わず話が弾みます♪


ではでは次に参りましょう〜

【総務スペース】





こちらは囲いがなく開放的な空間となっています^^

 ここが普通の壁ではなくて、透明になっていることで全体的にも広々しているように感じますよね♪
そしてまたこのシールがかわいい♡ 


元々は全部黒だったのですが、ここが違うだけでガラリと印象が変わりました!















そしてこの隣にあるのが、今回新たに作られた社長室で、このようになっています!

【社長室】





初めて拝見した時は、ハリポッターみたい!という印象でした。
この本棚の壁紙が印象的で連想させたんだなと思います♪



壁紙という感じでなく、本当にたくさんの本があるように見えますよね!
5階のレンガの壁紙同様、思わず触って確かめたくなりますw






高級そうなソファーにガラスのテーブルでクールに決まっていてカッコイイ!
と思ったらその横にハンモックがあるっていうのがこれまたいい味を出してますね^^










そしてこちらは斬新にも透明の壁となっており、総務スペースから丸見えでございますヮ(゚д゚)ォ!









といった感じで2階オフィスも集中するスペースと、リラックスできる場所があり、最適な環境となっております^^♪
こんな素敵なオフィスなので、キレイに維持できるように心がけたいと思います(≧∇≦)/



最後に・・・

当社では現在、プログラマーやインフラエンジニア、グラフィックデザイナー・イラストレーター・アニメーションデザイナー・マーケティング担当プランナー・カスタマーサポートのみなさんを応募しております!アルバイトも募集しておりますので、ぜひ一緒に働きたいという方は、ご応募ください♪
詳しくは下記URLまで↓↓
http://www.happyelements.co.jp/recruit/

2014年12月12日金曜日

ゲームってなに?

このエントリーをはてなブックマークに追加
プランナーの岡田です。

ズバリ本題ですが、初めてゲームを作ろう!、となった7〜8年前、「そもそもゲームってなに?」という当たり前だけど、踏み込むと哲学的な迷路に飛び込みました。
で、wikiを調べる等の安易な解決策に走ったわけですが、いくつかの高尚な理論を理解もできずに、右往左往していると、 「乱数による揺らぎを分かりやすく楽しめるものにすること」というような自分でも理解できて、かつ形に落としやすいシンプルな記述があって、「ああ、これだな」と、自分の中のゲームの定義にしました。
ここでいう乱数は、プログラム生成される数値だけじゃなくて、相手の思考とかも含めた「結果が予測できないもの」、位な感じです。

じゃんけんの例

一例を出すと、究極的にシンプルなゲームは仮に「じゃんけん」とします。

A君とBさん、初対面の2人がじゃんけんを10000回戦した場合、最初の1戦の勝率はやはり5割でしょう。
そして、2人とも何も考えずに10000回じゃんけんをした場合、やっぱり5000勝5000敗近辺になると思います。
ただ、A君だけが「勝ち越そう」という目的意識を持って、
  • Bさんの心理パターンを読む
  • Bさんに「俺、次パーだすから」等の陽動をかける
  • Bさんの癖を見抜く
  • 動体視力を鍛える
等々、さまざまな努力を欠かさなければ、おそらくは5200勝4800敗位で勝ち越せると思います。
勝ち越せなかったら、努力の方向性や量が間違えていた、ということで。。。

ただ、じゃんけんは「分かりやすい」、ということに異論はなくとも、「楽しみつづけられるか」という点では、やはりシンプルすぎて物足りません
乱数による揺らぎを楽しむにしても、じゃんけんほどにシンプルすぎると、どんなに分かり易くてもやっぱり飽きます。

現実世界とゲーム内のリソース

飽きがきずらい、ある程度複雑なやりとりをゲームとして形作っていくには、さまざまなルールを加えていくことが必要で、そのルールを構築するうえで、ゲーム内リソースが必要になります。
そこで、ゲーム内リソースと引き換えるために持ち込んでいただく現実世界のリソースが必要になるのですが、これは「時間・お金・運」の3つに大別できると思っています。
もうひとつ、プレイヤースキルというものもありますが、これは求めすぎると敷居が高くなるうえに、スマホゲームの特色である空き時間にストレスなく楽しめる、と相反する部分もあるので、「時間」の範疇に入れておきます。

この3要素のバランスが悪いと、「張り付きげー」や「課金ゲー」になったり、「運ゲー」になるのかと思います。
この3要素のバランスがとれていると、いろんなプレイスタイルのユーザーさんが自分なりの楽しみ方で楽しめる懐の深いゲームになるので、バランスのいいゲームと言えるのではないでしょうか。

この点、どうしても「課金」が重視されがちですが、「時間=人生」です。
時間を使って遊んでいただけること、これってとても大切ですよね。

「運」に関しては、これってもうどうしようもないです。
ただ、これこそ本当に「乱数による揺らぎ」のストレートな在り方なので、単体でゲームとよべなくもない、というちょっと苦しい擁護をしておきます。

で、この3要素と引き換えに手に入れたゲーム内リソースを使って、「乱数による揺らぎ」を攻略していくのが、私が思うゲームの定義です。
無理矢理気味にでもあてはめるなら、最初に「お金」を消費していただいて、その後に消費する「時間」を楽しんいくのがコンシューマゲーム、 協力したり、競ったり、おしゃべりしたり、といったゲームを仲立ちとするコミュニティの生成までも含めたのがソーシャルゲーム、でしょうか。


ゲームコンテンツ

次いで、この「乱数による揺らぎ」を生成するのが狭義の「ゲームコンテンツ」と言われるものかと思ってます。

ここには、「パズル」が当てはまったり、「ひっぱり」が当てはまったり、「コマンドアクション」が当てはまったり、「クイズ」が当てはまったりといろいろとあります。
ここを省略してしまったり、魅力がないとそもそも面白くない、という話になるので、一番大切なところですが、ここはもう閃き頼りなところも大きいので、絶対に面白いゲームなんて誰にも作れない、と言われる所以なのかと思ってます。
ただ、逆説的ですが、ここ以外はある程度の確度を持って組み上げられてしかるべきだし、ここをきちんと組み上げるのが「ゲームデザイナー」という「本当に必要なの?」といわれがちな職種の存在意義かと思います。

ゲームデザイナーは想定しているターゲットユーザーが各々のプレイスタイルに応じて幅広く楽しめるものであるように、乱数の揺らぎの幅やら、レベルデザインやら、ゲーム内リソースの獲得・交換・消費やら、協力や対戦のあり方やら、色々と多岐にわたって積み上げていかないといけないので、経験が必要な職種かとは思いますが、先人の知恵の「手順ではなく仕組み」を見つめつつ、「製作者自身が現実世界のリソース消費を我慢できなくなるように」組み上げていければ、面白いゲームになるのではないかと思います。

加えて、コンシューマとして成功しているゲームは、この「ゲームコンテンツ」の面白さは立証されているわけなので、業界内で言われているほど博打ではなく、ある程度の確度で成功事例は出せると思いますし、その意気込みがある方、ぜひ、一緒に仕事しましょう(笑)。


まとめ

で、長くなってきたのでまとめますと、

乱数による揺らぎを分かりやすく楽しめるものがゲーム
   ↓
シンプルすぎると飽きるので、ルールを作る
   ↓
ルール作りに必要なゲーム内のリソースは現実世界のものを持ち込む
   ↓
現実世界から持ち込むものは「時間・お金・運」
   ↓
現実世界から持ち込むものがプレイスタイル
   ↓
コンシューマゲームもソーシャルゲームもゲームの一派生
   ↓
乱数による揺らぎの生成法が「ゲームコンテンツ」
   ↓
「ゲームコンテンツ」を覆うのがゲームデザイン
   ↓
「ゲームコンテンツ」はまだまだ沢山眠っている

という感じでしょうか。

ブログネタを…、ということで徒然と書いてみましたが、なんだか当たり前のことしか書いてないみたいな気がして、色々と恐縮です。


一緒に働きたい方、絶賛 募集中

京都でスキルアップしたいエンジニアやプランナーの皆さん、ご応募お待ちしています!
社内にはプロジェクターが使えるバースペースがあり、業務後のコミュニケーションの場となっています。

京都でスキルアップしたい学生さん、アルバイトも可能なのでご応募お待ちしています!
オフィスワークでドリンク飲み放題、時給は高く、シフトの自由度も高いです。

大阪、滋賀、神戸から通勤実績あります

2014年12月3日水曜日

5階オフィスの紹介

このエントリーをはてなブックマークに追加
はじめまして、スタッフの木下です。


Happy Elementsのオフィスは、とってもこだわりがあってオシャレなんです。
最近、当社京都オフィス5階が新たに完成しましたので、お気に入りの5階オフィスを紹介させていただきます^^
5階はこちらのようになっております。



じゃじゃーん♪
レンガ柄の壁がとっても印象的ですよね。これが結構リアルで、ついつい触ってしまうのですが凹凸はありませんでした(笑)
レンガ柄とウッディーな感じがとってもオシャレですよね☆



全階共通ということで5階も、オフィスには靴を脱いで入ります。
初めオフィスに靴を脱ぐというのは、すごく珍しく驚いたのですが、これが一度体験するとすごく快適でやみつきになります。

【共用スペース】

共用スペースは、ふんわりとした優しい照明とウッドテーブル、ソフトなイス、かわいい観葉植物があり、まるでオシャレなカフェにいるようです。天井も抜いてあるので開放感があり、とってもリラックスできます♪

ここでよくお昼ご飯をいただくのですが、まるで家にいるかのように落ち着くので、すごく癒されます。
こちら打ち合わせなどにも使用されていますが、柔らかい雰囲気なので、話も弾むこと間違いなしです。


そしてこちらも全階共通してですが、お茶やコーラ、野菜ジュースなど様々な種類のドリンクが完備されており、自由に飲むことができます。使い捨てのコップなども自由に使えるのでとっても助かります。

また収納スペースもたくさんあるので、整理整頓もバッチリです^^;(のはずです)


【執務スペース】
5階の執務スペースは2つの大きい部屋があります。
1つ目はこちら〜♪




窓が大きく開放感があるので、とっても広々しています。
以前の2階とは違って、戸があるのできちんと締めるとすごく静かで集中しやすい環境で仕事に取り組むことができます。時々勢い良く締めて、みなさんを驚かせてしまう時があります。(ごめんなさい><;)


一見窓のようになっているこちら、実はクリアボードとしても利用ができるのです♪
(写真ではわかりづらいかもしれません;)
ちょっと前まではCEOが描かれたかわいい国民的人気キャラクターが描かれていたのですが、いつの間にかなくなっていてちょっとさみしいです(´・ω・`) 


2つ目のこちらの部屋は壁がレンガ風ではなく、木目調になっております。


こちらの部屋ではホワイトボードが壁に備え付けられています。出っ張りがないので、掃除にも便利です♪
ボードの上に時計という配置が、学校を思い出してとても懐かしいですね。






集中して仕事ができ、且つ休憩する時はリラックスもできる2面性を持ち合わせた、とっても環境のいいオフィスに満足しています。こういった環境でお仕事させていただけることに感謝です。

もうすぐ2階の改装が完了するそうなので、またレポートさせていただきます! 



最後に・・・

当社では現在、プログラマーやインフラエンジニア、グラフィックデザイナー・イラストレーター・マーケティング担当プランナーのみなさんを応募しております!アルバイトも募集しておりますので、オシャレなオフィスで一緒に働きたいなという方は、ぜひご応募ください♪
詳しくは下記URLまで↓↓
http://www.happyelements.co.jp/recruit/

2014年4月16日水曜日

ソーシャルゲームの不正課金。まさかそんな理由で増えるとは

このエントリーをはてなブックマークに追加
プランナーのアレックスです。
ソーシャルゲームの運営には、ある程度の不正課金はつきものだと考えています。しかし、今年の1月に、通常の何十倍もの金額の不正課金が発生したので調査したところ、不正の方法と、それが1月に集中した以外な理由がわかったのでまとめてみました。

不正課金の方法

一言で言えば、期限切れなどのクレジットカードを使って課金がされています。ほとんどの場合は決済が通らないはずですが、プラットフォームによっては通ってしまう場合があるようです。
あまり詳しいことはわかりませんが、このような流れであるという説明を受けました:
  1. ユーザーがプラットフォーム側で決済を開始
  2. すぐに結果を返すために、プラットフォームが簡単なチェックでカード情報を確認
  3. チェックが通ると、アプリサーバーに通信しアプリ内アイテムを付与
  4. 後ほどプラットフォームがもう一度しっかりカード情報を確認。この時点で決済に失敗
  5. カードの決済はキャンセルされて、支払いは行われない。しかしアイテムは付与済み
という感じで、アプリ側としては損をしてしまいますね。
さらに、このやり口のノウハウを持っている人がユーザーの代わりに不正課金を行うサービスを提供しているようです。中国のECサイトTaobaoなどで検索すると、数々の有名アプリでの代理課金サービスが宣伝されていることがわかります。
ここで肝となるのが機種変更パスワード

機種変更パスワード

ソーシャルアプリでは通常、新しいスマホを買ったユーザーがデータを以降できるように、機種変更パスワードという機能を用意しています。古い機種でパスワードを確認して、新しい機種に打ち込むと同じデータで引き続き遊べる、という仕組みです。
この機種変更パスワードを悪用すると、
  1. 不正課金ができる人と連絡を取る
  2. 機種変更パスワードを不正者に伝える
  3. 不正者が自分の端末にユーザーのデータを引き継いで、不正課金する
  4. ユーザーが機種変更パスワードを再利用して、有料アイテムを獲得したアカウントを取り戻す
デバイスのユーザーエージェントやデバイスID、モデル名などをログに残して決済時に通常と違うものに切り替わるアカウントを調査していくと、このような行為を洗い出すことができるかもしれません。

1月に不正課金が増えたわけ

不正の方法がわかったところで、ではなぜ1月にここまで集中して行われたか?
現在弊社のアプリは中国からの利用者もそれなりにいて、中にはかなりやり込んでランキング上位に入ってくれるユーザーも多く、嬉しい限りです。ただ、中国では海外(日本)で使えるクレジットカードを持つ方は少なく、スマホアプリで課金をする場合はギフトカードを店舗で購入して利用することが多いです。
そして1月の中国でのビッグイベントといえば、そう、旧正月です
正月休みに入って、いつもカードを買っているお店が閉まっている。
クレジットカードは海外では使えない。
けど新しいイベントが始まってどうしてもアイテムを買いたい。
なんとかできないか検索してみたら、代わりに課金をしてくれるサービスがあるじゃないか。機種変更パスワードが必要だったりしてちょっと怪しいけど、他に方法が無いし仕方ないからやってみよう。
このような流れで、特に海外からの上位ユーザーに集中して不本意な不正課金が行われた、ということが今回わかりました。

おわり

ユーザー自身には不正課金をしたいという気持ちがなくても他に課金手段がない、という意外な状況があると大変勉強になりました。ユーザーと連絡を取り、おかげ様で状況を理解できましたので、今後も引き続き運営側の体制、及び不正対策なども整えていきたいと考えています。

一緒に働きたい方、絶賛 募集中

京都でスキルアップしたいエンジニアやプランナーの皆さん、ご応募お待ちしています!
社内にはプロジェクターが使えるバースペースがあり、業務後のコミュニケーションの場となっています。

京都でスキルアップしたい学生さん、アルバイトも可能なのでご応募お待ちしています!
オフィスワークでドリンク飲み放題、時給は高く、シフトの自由度も高いです。

大阪、滋賀、神戸から通勤実績あります

2013年11月24日日曜日

新MBP(Mavericks)への開発環境移行について

このエントリーをはてなブックマークに追加
エンジニアの上田です。
MBAを使っていたのですが、そこからMBPへ開発環境を移行しました。
そこでいくつかつまづいたので解決した経緯をblogに記載しておきます。
同じ状況で困ってる人の参考になればと思います。

移行前PC

Mac Book Air (OSはLion)

移行後PC

Mac Book Pro (OSはMavericks)
購入直後の状態です

移行環境

  • Xcode5系最新
  • Homebrew
  • JDK6
  • ruby 1.9.3
  • memcached最新
  • Cassandra 1.1.6
  • MySQL 5.5
  • Redis 2.6

手順

command line toolsなど他のインストールに影響するものから最初にいれていきます

1. Xcode5インストール

APP Storeからダウンロードしてインストールします
インストール後、一度起動してライセンスに同意しておいてください
同意しておかないとHomebrewインストールで失敗します

2. command line toolsインストール

xcode-select --install
Command Line Developer Toolsをインストールする確認ダイアログが出るので
Installボタンを押してインストールします

他のアプリなどを入れたりした後だとなぜかxcode-select --installを入力しても
Command Line Developer Toolsインストールダイアログが立ち上がりませんでした
Xcode5をインストール直後に実行しておいたほうが良いです

3. Homebrewインストール

ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)”
インストール完了後
brew doctor
と入力し
Your system is ready to brew.
と表示されることを確認します

4. apple-gccインストール

Xcode4からコンパイラがLLVMになりました
互換性などの問題によりLLVMではCassandraのコンパイル後、起動時にAbort trap: 6というエラーがでます

brew tap homebrew/dupes
brew install apple-gcc42
sudo ln -snf /usr/local/bin/gcc-4.2 /usr/bin/gcc 
と入力してインストールします

5. JDK6インストール

http://qiita.com/m_mysht/items/a5e60d260c7078331d66
このサイトの内容を参考にインストールさせていただきました
JDK6はOracleからは入手できないのでAppleのサイトからインストールします

6. ruby 1.9.3インストール

RVMでインストールします
sudo \curl -L https://get.rvm.io | bash -s stable --ruby
sudo rvm install 1.9.3
source .bash_profile
rvm use 1.9.3 —default

7. memcachedインストール

brew install libevent
brew install memcached

8. Cassandraインストール

通常はhttp://cassandra.apache.org/download/からダウンロードしますが、入れようと思っていたバージョンの1.1.6は既にダウンロードページになかったのでhttp://archive.apache.org/dist/cassandra/1.1.6/からダウンロードしました。
apache-cassandra-1.1.6-bin.tar.gzを解凍して自分の分かりやすい場所に置きます。
brew install libevent
brew install memcached

9. MySQL5.5インストール

http://dev.mysql.com/downloads/mysql/
上記サイトから64bitのDMG Archiveをダウンロードしてインストールします

10. Redisインストール

brew install redis

開発環境移行は以上で完了です!!
だいたい3時間くらいで完了できます

開発環境移行前は2年くらい前に買ったMBAを使っていたのですが、Unityなどを使用してアプリ開発をしていると使用メモリも多く
だいぶ効率が落ちてきていると感じました。

そこで会社にお願いして新しいMBPを買ってもらいました。
退職理由は「転職先のモニターのほうが大きい」から?でも書かれていましたが、自分が働いている会社が「エンジニアが一番パフォーマンスを発揮できる環境を整えてくれる会社である」ということはとても重要であると考えます。
そんなエンジニアの気持ちを汲み取ってくれるHappy Elements株式会社で私たちと一緒に世間をあっと言わせるような面白いアプリを作ってみませんか?

Happy Elements株式会社は一緒に働く仲間を募集中です!

詳細な情報は以下のサイトをご覧ください。


Wantedly
https://www.wantedly.com/projects/3743

Happy Elements株式会社 JOBS
http://www.happyelements.co.jp/index.php/category/jobs/kyoto-office

2013年8月6日火曜日

世界平和とAndroid

このエントリーをはてなブックマークに追加
エンジニアの草苅です。
スマートフォンを扱うエンジニアの皆さんは、日々Android のバグに悩まされているのではないかと思います。弊社も類に漏れず様々な Android のバグと戦っています。

特にあんさんぶるガールズ!ではアニメーションはすべて Canvas を利用していることもあり、Android の Canvas 絡みのバグに、頭を痛めています。

Android のバッドノウハウは悩んでいる人みんなで共有した方が、世のため人のためになるのではと思い立ったので、世界平和を願っていくつかまとめてみたいと思います。

1. GPUレンダリングの設定によって Canvas で不具合が発生する

Android は OS のバージョンや、WebView のレンダリングエンジンの違いによって、GPUレンダリングOFFの場合に、Canvas が正常に表示できない端末、もしくはGPUレンダリングONの場合に、Canvas が正常に表示できない端末が存在します。

このような問題は、できれば Android OS のバージョンで統一しておいて欲しいのですが、どうも機種依存のようなので、弊社では機種に応じて GPUレンダリングONなのか、OFFなのかを個別で指定しています。

いくつか実例を挙げますと、現在のドコモのツートップ Xperia A と Galaxy S4は GPU レンダリングOFFでなければ WebView 上の Canvas は正常動作しません。それとは逆に、Nexus 7 や Arrows X は GPUレンダリングON でなければ WebView 上の Canvas は正しく表示されません。また、同じ OS のバージョンであっても Galaxy Nexus はGPUレンダリングONだとクラッシュし、Nexus 7はGPUレンダリングONでなければ Canvas が正常に表示されないということが発生します。

そのため、あんさんぶるガールズ!では、ONまたはOFFでしか動作しない端末については、次のようなメソッドを使って、アプリ側で強制的にGPUレンダリング設定を変更しています。


protected void setHardwareAccelerationEnabled(boolean enable) {
  if (enable) {
    getWindow().setFlags(
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
  } else {
    // 下位互換性を保つため、以下のコードをリフレクションで実行
    // webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    try {
      Method setLayerTypeMethod = webView.getClass().getMethod("setLayerType", new Class[] {int.class, Paint.class});
      setLayerTypeMethod.invoke(webView, new Object[] {View.LAYER_TYPE_SOFTWARE, null});
    } catch (NoSuchMethodException e) {
      // Older OS, no HW acceleration anyway
    } catch (IllegalArgumentException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    }
  }
}


2. GPUレンダリング設定以外に Canvas 周りのバグがある

Android 4.0.4 には Canvas がブラウザを巻き込んでクラッシュするというバグがあります。このバグは上記のバグと違い、WebView では再現しにくいのですが、ブラウザではかなりの頻度で発生します。

例えば Galaxy S3、Xperia SX、Xperia GX などの端末が Android 4.0.4 を搭載しています。CreateJS のコミュニティにもこの問題は上がっており、かなりの期間対処法がなかったのですが、その後、Canvas を clearRect する際、縦横に 1px だけ加えたサイズをクリアするようにすることでクラッシュしなくなるという、華麗なテクニックが編み出され、この方法が EaselJS 0.6 系に取り込まれました。

CreateJS のコミュニティの該当エントリー
http://community.createjs.com/discussions/easeljs/220-samsung-galaxy-s3-stock-android-404-browser-freezescrashes-on-stageupdate

修正のコミットログ
https://github.com/CreateJS/EaselJS/commit/7c02f0d4a7e50908b284623d23e6897f15e3bff4


また、Galaxy S4(Android 4.2.2)に関しては WebView 上で表示させたときだけ、Canvas が正しく表示されない不具合があります。
GPUレンダリングONの場合は、Canvas 全体が常に水色表示で何も出ず、OFFの場合はアニメーションが表示されたり、されなかったりがかなり不安定になってしまいます。もろもろ調べていると、日本語で次のようなブログ記事を見つけました。

Galaxy S4のWebviewで、非同期処理の中でのCanvasの描画がバグってる - 車輪を再発明 / koba04の日記
http://d.hatena.ne.jp/koba04/20130629/1372437341

この記事を見ながら「最新端末で動作しないアプリって…」と絶望していたのですが、諦めず調べていると安定してアニメーションを表示できるスピリチュアルな方法を、編み出すことができました。それはアニメーション表示直前に Canvas をクリアすることです。CreateJS であれば、Stage を作って、まずクリアしてからアニメーションを実行すると WebView 上の Canvas でも安定してアニメーションを表示することができました。

var canvas = document.getElementById('canvas');
var stage = new createjs.Stage(canvas);
stage.clear();
// clear した後アニメーションのコードを実行

3. GPUレンダリングOFFで特定のCSSが激重

さて、Canvas を正常に表示するためにGPUレンダリングを強制OFFにしたまでは良かったのですが、それに伴いスクロールが激重になってしまった端末があります。

例えば、今年の初めに発売されてツートップの発売前までドコモが推していた Xperia Z という端末は、WebView 上の Canvas を正常に表示するために GPUレンダリングを強制OFFにしたまでは良かったのですが、ほとんどのページでスクロールが激重になってしまいました。

いろいろ調べていると、shadow 系などアルファブレンディングを行うような css が GPUレンダリングOFF だと重くなってしまうようです。参考までに以下のような記事があります。

[CSS] border-radiusとbox-shadowを組み合わせると、それぞれ単体でのスタイルより5倍重たい!? - YoheiM .NET
http://yoheim.net/blog.php?q=20130713

単純に考えると、GPUレンダリングOFFの端末のみ、これらの css の重いプロパティを使用しない css で上書くというのが良さそうです。

Android には幸いなことに、Java Object を JavaScript Object として WebView に渡せるという、セキュリティ問題がとても発生しやすい、さわやかな機能があるので、これを利用します。そして、css を読み込む際、この WebView がGPUレンダリングOFFであれば、上書きする css を読み込むようにしました(以下は簡易的に書いたサンプルです)。

// this を droid という名前で JavaScript からアクセスできるようにします
webView.addJavascriptInterface(this, "droid");

// GPUレンダリングOFFのときのみ、上書き用のCSSを読み込みます。
if (!droid.webView.isHardwareAccelerated()) {
  var fileref = document.createElement("link");
  fileref.setAttribute("rel", "stylesheet");
  fileref.setAttribute("type", "text/css");
  fileref.setAttribute("href", '<%= path_to_stylesheet 'android_without_hardware_acceleration' %>');
  document.getElementsByTagName("head")[0].appendChild(fileref);
}


4. キーボード入力時に上下に揺れる端末

Android にはテキストボックスに文字を入力しようとすると、文字入力のたびになぜか画面がスクロールして、激しく上下に縦揺れするという恐ろしい端末があります。

例えばこちらに不具合が上がっています。
https://github.com/scottjehl/Device-Bugs/issues/32

あんさんぶるガールズ!では当初、コメントはすべてポップアップ画面でその場で入力できるようにしていましたが、この不具合に対応するため、Android はすべて画面遷移でテキストボックスが1つだけある画面に遷移した後、コメントを入力するように変更しました。さらに、テキスト入力中にスクロールが発生しないように、テキストボックスにフォーカスが当たった際、JavaScript でスクロールをなくす処理を入れています(以下はサンプルコードです)。

.stop-scroll {
  outline: none;
  overflow: hidden;
}

$('input[type=text]').on 'focus', (e)->
    $('body').addClass('stop-scroll')

$('input[type=text]').on 'blur', (e)->
    $('body').removeClass('stop-scroll')


おわりに

最後にうちのチームの優秀なアルバイトエンジニアの心の叫びを掲載して、世界平和を切に願いたいと思います。



Happy Elements 株式会社では世界平和を目指すエンジニア社員、およびアルバイトを募集しています。

Find Job!

Wantedly

Happy Elements株式会社 JOBS

2013年5月29日水曜日

redis-objectsがなくてもプロジェクトは回るが

このエントリーをはてなブックマークに追加

あるととても便利だと思います

はじめに

エンジニアの@ryooo321です。
よろしくお願いします。
ご存知の方も多いかもしれませんが、今回はRubyからRedisを使う際にとても扱いやすいredis-objectsをご紹介したいと思います。

https://github.com/nateware/redis-objects


特徴

・ORMではない

・Redisのデータ型(counter, value, list, hash, set, sorted-set)をサポート

・ロック機能も利用可能



好きなところ

・モデルの任意のプロパティをRedisに保存するような感覚で利用できる点。

・Redisのキー情報をシームレスに管理できる点。

・ARモデルの一部プロパティをRedisに移したりできるので、データストア単位でなく理想の単位でモデルを定義できる点。


This is not an ORM. People that are wrapping ORM’s around Redis are missing the point.
(readmeより引用)
作者の方はこのように言っており、本当にとても使いやすい形になっております。

目次

1. Counter
2. List
3. Set
4. Hash
5. Sorted Set
6. global
7. Lock
8. redisオブジェクト


1. Counter

数値をアトミックにincrement/decrementする型です。

class User < ActiveRecord::Base
  include Redis::Objects
  counter :friend_count, :start => 0
  # startは省略可
end

@user = User.find(id)

# インクリメント
@user.friend_count.increment

# 渡したブロックで例外発生もしくはnilが帰ったときは、decrementを発行して数値を戻す
@user.friend_count.increment do |new_value|
  raise 'friend count is limited by 20' if 20 < new_value
  true
end

# Userを取得せずにアクセス
friend_count = User.get_counter(:friend_count, user_id)
User.increment_counter(:friend_count, user_id)
Userを取得せずにアクセスできる点、オブジェクト経由で操作する時はuser_idを渡さないでよい点(キーがシームレス)が便利です。


2. List

配列をアトミックに操作できる型です。

class User < ActiveRecord::Base
  include Redis::Objects
  list :friend_ids, :maxlength => 20
  # startは省略可
end

@user = User.find(id)

# rubyの配列のように使えます(Enumerable)
# 追加
@user.friend_ids << 123
@user.friend_ids.push(123)

# 変更
@user.friend_ids[2] = 123

# 削除
@user.friend_ids.delete(123)

# 取得
@user.friend_ids[2]
@user.friend_ids[2..4]
@user.friend_ids.at(2)
@user.friend_ids.first
@user.friend_ids.each do |user_id|
  # hoge
end
@user.friend_ids.values

Userを取得せずに操作するメソッドは現在ありません。

しかし、⬇⬇⬇このようにしてUserオブジェクトなしにアクセスできます。

name = :friend_ids
friend_ids = Redis::List.new(User.redis_field_key(name, user_id), User.redis, User.redis_objects[name])
friend_ids.values


3. Set

重複無効な配列をアトミックに操作できる型です。

class User < ActiveRecord::Base
  include Redis::Objects
  set :friend_ids
end

@user = User.find(id)

# rubyの配列のように使えます(Enumerable)
@user.friend_ids << 123
@user.friend_ids.each do |user_id|
  # hoge
end

# setなので、重複したものは無視
@user.friend_ids << 123
@user.friend_ids << 123 # 2回目は無視
@user.friend_ids.member?(me.id)

# 共通の友達
@user.friend_ids & me.friend_ids

# どちらかの友達
@user.friend_ids | me.friend_ids
@user.friend_ids + me.friend_ids

# 共通でない友達(差分)
@user.friend_ids ^ me.friend_ids
@user.friend_ids - me.friend_ids

# Userを取得せずに操作するメソッドは現在ありませんが、List同様(前述)に取得できます


4. Hash

ハッシュをアトミックに操作できる型です。

class User < ActiveRecord::Base
  include Redis::Objects
  hash_key :item_count_map
end

@user = User.find(id)

# rubyのHashのように使えます(Enumerable)
@user.item_count_map[item_id] = 10
@user.item_count_map.each do |item_id, count|
  # hoge
end

# まとめて操作
@user.item_count_map.bulk_set(:a => 10, :b => 20, :c => 30)
@user.item_count_map.bulk_get(:a, :b)
# => {:a => 10, :b => 20}
@user.item_count_map.bulk_values(:a, :b)
# => [10, 20]

# 個別にインクリメント
@user.item_count_map.incr(:a, 50)
@user.item_count_map[:a]
# => 60

# Userを取得せずに操作するメソッドは現在ありませんが、List同様(前述)に取得できます


5. Sorted Set

ソート済みハッシュをアトミックに操作できる型です。

class User < ActiveRecord::Base
  include Redis::Objects
  sorted_set :article_rate
end

@user = User.find(id)

# articleごとに評価スコアを登録
@user.article_rate[:a] = 30
@user.article_rate[:b] = 50
@user.article_rate[:c] = 10

@user.article_rate.score(:c)
# => 10

# 順位
# 昇順
@user.article_rate.rank(:b)
# => 2

# 降順
@user.article_rate.revrank(:b)
# => 0

# スコアの範囲取得
@user.article_rate.rangebyscore(0, 100, :limit => 1)
# => [:c]
@user.article_rate.members(:with_scores => true)
# => [[:c, 10], [:a, 30], [:b, 50]]

# atomicなインクリメント
@user.article_rate.incr(:c, 100)
@user.article_rate.score(:c)
# => 110

# Userを取得せずに操作するメソッドは現在ありませんが、List同様(前述)に取得できます


6. global

すべてのデータ型クラスでglobalオプションが使えます。

trueを指定すると、クラス単位でredisキーが共通になります。

※ 同モデルのオブジェクトすべてが、同じキャッシュを見るような状態です。

class User < ActiveRecord::Base
  include Redis::Objects
  sorted_set :article_rate
  sorted_set :event_point, :global => true
end

# これは@userごとのランキング
@user.article_rate.rank(:a)

# これは全ユーザーのランキング
@user.event_point.rank(:a)


7. Lock

lockの実装としてはredisにフラグ値をsetし、そのフラグがある場合は処理を待ち合わせる作りです。

同じhoge_lockを使っている箇所とで排他制御にできます。

class User < ActiveRecord::Base
  include Redis::Objects
  lock :hoge, :expiration => 20.second, :timeout => 1.second
  
  # lockのオプション
  # timeout :
  #    指定された時間以上にロック解除を待った場合、例外を投げます。
  # expiration :
  #    万が一ロックが解除されない状態になっても、指定された時間が経つとredis側でロック解除します。
end

@user = User.find(id)

# 処理Aと処理Bは排他的に動く
@user.hoge_lock.lock do
  # 処理A
end
@user.hoge_lock.lock do
  # 処理B
end



8. redisオブジェクト

redisオブジェクトはredis gemのオブジェクトで、redis-objectsで未実装のAPIもredisオブジェクト経由で呼び出せる場合があります。

class User < ActiveRecord::Base
  include Redis::Objects
  value :hoge
end

@user = User.find(id)

# redisオブジェクトへは、下記のようにアクセスできます。
redis = User.redis
redis = @user.redis

redis.pipelined do
  redis.set "foo", "bar"
  redis.incr "baz"
end


おわりに

本稿にお付き合い下さいましてありがとうございました。

この素晴らしいプロダクトを、みなさまが少しでもよいと思っていただければ幸いです。



一緒に働きたい方、絶賛 募集中

京都でスキルアップしたいエンジニアの皆さん、ご応募お待ちしています!
社内にはプロジェクターが使えるバースペースがあり、業務後のコミュニケーションの場となっています。

京都でスキルアップしたい学生さん、アルバイトも可能なのでご応募お待ちしています!
オフィスワークでドリンク飲み放題、時給は高く、シフトの自由度も高いです。

大阪、滋賀、神戸から通勤実績あります
イラストレーターさん、シナリオライターさんも募集中(アルバイト可)です!