WCE blog

早稲田大学公認 総合デジタル創作サークル 早稲田コンピュータエンタテインメント

GDC 2013 関連記事ピックアップ

プログラミング班 @Reputeless です。

世界最大のゲーム開発者向けイベント Game Developers Conference (GDC) が、今年もサンフランシスコで開催されました。
GAME Watch4Gamer.net に掲載された現地取材レポートから、興味深い記事をピックアップして紹介します。

発表!「良いレベルデザインの10の原則」

Square Enix Montreal のクリエイターが、ゲームデザインの 10 の原則を実際の事例を交えて紹介。

「Journey(風ノ旅ビト)」のゲームデザイン解説

風ノ旅ビトが目指したのは「感情」のデザイン。そのアプローチを開発スタジオのデザイナーが解説。

「TOKYO JUNGLE」の成功から振り返る日本の感性を生かしたゲーム制作

普遍と普遍を組み合わせることで、普遍だがユニークなゲームとなった TOKYO JUNGLE の誕生秘話。

色々あったけどやっぱり気になる「シムシティ」 Part2

シムシティ開発チームがコンセプト共有のために用いた「ワン・ページ・デザイン」という手法の披露。

GAME NARRATIVE SUMMIT「教訓あるゲームを作るテクニック」

教訓や道徳を伝えるゲームの作り方を、Microsoft のシニアゲームデザイナーがアドバイス。

NASAがゲーム開発者を本気でリクルーティング

NASA が広報用に作ったゲームと、ゲームの技術を宇宙探査で活用しようとしている研究事例を紹介。

このほかにも、PS4 や Project SHIELD などのハードウェアに関する情報や、最新タイトル、エンジンのテクノロジー解説など、ゲームの舞台裏、そして未来を垣間見れる情報が盛りだくさんです。
目を通せば、きっとゲーム作りのヒントが見つかるはずです。

セルオートマトンを用いた幾何学模様の生成

f:id:WCE:20130401212821p:plain

プログラミング班2年のアゲハマです。
今回は砂山モデルの紹介と、それを使ったきれいな模様の作り方を書きたいと思います。

1.セルオートマトンとは

セルオートマトンとはセルによって構成される計算モデルです。
代表的なものにライフゲームが挙げられます。

詳しくは http://ja.wikipedia.org/wiki/セル・オートマトン へ。

2.砂山モデルの説明

今回用いる砂山モデルについて説明をします。
砂山モデルとは2次元セルオートマトンの一種で、砂山が崩れ落ちる様子をモデル化したものです。

f:id:WCE:20130401211607p:plain

エクセルのような、各セルが整数の値を持つ2次元平面を想像してください。
各セルの値はそこに積まれている砂粒の数を表したものです。
ここで、平面上の適当な場所に砂粒を落としていき、高さが4になったら隣接する4つのセルに1ずつ移動させる、という操作を繰り返します。
すると、この隣接セルへの移動が連鎖反応を引き起こし、大きな雪崩につながることがあります。
この雪崩の頻度と規模は、べき乗に分布することが知られており、べき乗法則に従う自然現象(地震など)の研究に用いられることもあるようです。

3.砂山モデルのプログラミング

では、この砂山モデルをプログラムに書き起こしてみましょう。
ここではSiv3Dライブラリを用いていますが、画像データをピクセルごとに参照できれば何を使っても大丈夫です。

#include <Siv3D.hpp>

const int repsize = 4;
const Point replacer[repsize] = 
{
    Point(-1,0),Point(1,0),Point(0,-1),Point(0,1)
};
const Color backcolor = Palette::Skyblue;
const Color sandcolor = Color(239,228,176,0);
const double scale = 1.0;
const Point size(512,512);

class SandHill
{
    std::vector<std::vector<unsigned>> m_cells,m_temp;
    Image m_image;
    DynamicTexture m_texture;

    //移動するセルの値をm_tempに保存する
    void calcFlow()
    {
        for( unsigned y=0; y<m_image.height; ++y )
        {
            for( unsigned x=0; x<m_image.width; ++x )
            {
                unsigned& cell = m_cells[y][x];
                if( repsize <= cell )
                {
                    const int plus = cell / repsize;
                    cell %= repsize;
                    
                    for(int i=0; i<repsize; ++i)
                    {
                        Point p = replacer[i]+Point(x,y);
                        p.x = Clamp<int>(p.x,0,m_image.width-1);
                        p.y = Clamp<int>(p.y,0,m_image.height-1);
                        m_temp[p.y][p.x] += plus;
                    }
                }
            }
        }
    }
    //m_tempに保存した値をセルに加える
    void updateCells()
    {
        for( unsigned y=0; y<m_image.height; ++y )
        {
            for( unsigned x=0; x<m_image.width; ++x )
            {
                m_cells[y][x] += m_temp[y][x];
                m_temp[y][x] = 0;
            }
        }
    }
    void updateImage()
    {
        for( unsigned y=0; y<m_image.height; ++y )
        {
            for( unsigned x=0; x<m_image.width; ++x )
            {
                m_image[y][x].a = 255*m_cells[y][x]/repsize;
            }
        }
    }
public:
    SandHill(int w, int h, const Color& c)
        :m_cells(h,std::vector<unsigned>(w)),m_temp(m_cells),m_image(w,h,c),m_texture(m_image){}
    void drop(const Point& pos, unsigned value)
    {
        Point p = pos;
        p.x = Clamp<int>(p.x,0,m_image.width-1);
        p.y = Clamp<int>(p.y,0,m_image.height-1);
        m_cells[p.y][p.x] += value;
    }
    void update()
    {
        calcFlow();
        updateCells();
        updateImage();
    }
    void draw()
    {
        m_texture.fill(m_image);
        m_texture.scale(scale).draw(size*(1-scale)/2);
    }
};

void Main()
{
    Window::Resize(size.x,size.y);
    Graphics::SetBackGround(backcolor);

    SandHill sandhill(size.x,size.y,sandcolor);
    
    while(System::Update())
    {
        if(Input::MouseL.pressed)//クリックした場所に砂を落とす
        {
            sandhill.drop(size/2+(Mouse::Pos()-size/2)/scale,500);
        }
        sandhill.update();
        sandhill.draw();
    }
}

実行結果:
f:id:WCE:20130401212750p:plain
なんとなく上から砂を落としているように見えますね。

4.模様を作る

先ほどのプログラムでマウスの位置を固定していると、対称的な図形が現れてきます。
初期値も行う操作も対称的なので当然と言えば当然な気もしますが、少しルールを変えればもっと綺麗な模様が作れそうです。
ということで、先ほどのソースコードの以下の部分を書き換えてみましょう。

const int repsize = 4;
const Point replacer[repsize] = 
{
    Point(-1,0),Point(1,0),Point(0,-1),Point(0,1)
};
const Color backcolor = Palette::Skyblue;
const Color sandcolor = Color(239,228,176,0);
const double scale = 1.0;

ここを以下のように書き換えてください。

const int repsize = 24;
const Point replacer[repsize] = 
{
    Point(-3,-3),Point(-2,-3),Point(-1,-3),Point(0,-3),Point(0,-2),Point(0,-1),
    Point(3,-3),Point(3,-2),Point(3,-1),Point(3,0),Point(2,0),Point(1,0),
    Point(3,3),Point(2,3),Point(1,3),Point(0,3),Point(0,2),Point(0,1),
    Point(-3,3),Point(-3,2),Point(-3,1),Point(-3,0),Point(-2,0),Point(-1,0)
};
const Color backcolor = Palette::Black;
const Color sandcolor = Alpha(0);
const double scale = 3.0;

書き換え前のreplacerは、現在のセルを中心とした相対座標で、上下左右の4つの隣接するセルを表しています。
それに対して書き換え後のreplacerは、下の画像の黒い場所を表しています。

つまり、セルに24個の砂粒が積まれたら、この画像の黒い部分に1つずつ割り振るという操作になります。
もはや砂山でも何でもないですが、実行結果は次のようになります。

実行結果:
f:id:WCE:20130401223804p:plain
面白い模様がいくつかできました。
画像がなんとなくぼやけて見えるのは、自動で補間がかかっているからです。
ちなみに、このようなドット絵を拡大する時はニアレストネイバー法を用いるとぼやけずに拡大できます。

5.まとめ

先ほどのreplacerを画像から読み込めるようにしたものがこちらです。
これで生成される画像はグレースケールなので、Photoshopのグラデーションマップなどで適切に加工すると良いと思います。

ロボット・メカの描き方 装甲の形状1

 どーも、CG班3年(新4年)の現象也です。
現象也はタイトル通りロボットやメカの描き方というマニアックな記事を書きます。
これぐらいしか、ブログにするようなネタがないんで。


 ロボットやメカの描き方を扱った書籍やHPって、メカは立方体を組み合わせて~、パースはどうとるか、関節の曲げ方だとか一般的なことに終始したものが多いと思います。
そういった内容も大事だとは思いますが、それでかっこいいロボットやメカが描ける気はしません。
例えば書籍で「面が間延びしないように凹凸を入れて描くようにしましょう」とあっても、実際どんな凹凸を入れればいいのかわかりません。
乱暴な言い方をすると「凹凸を入れるといいけど、どんな凹凸を入れるかは君のセンスに任せる!」ということです。
それってあんまりですよね・・・

 そこで現象也はセンスではなく現実的な視点からロボット・メカのデザインを導く方法を記事にしたいと思います。
タイトルでは「ロボット・メカの描き方」としてるんですが、どっちかていうと「ロボット・メカを描く際の注意点」ぐらいに理解してください。
それと言い忘れましたが、記事にするのはいわゆるリアルロボットのデザインについての個人的な考えです。
兵器も科学もへったくれもない「スーパーロボット」のデザインについては取り扱いませんし、我流なので参考程度に読んでください。


 初回は見た目を大きく左右する装甲の形状についてポイントを3つ挙げます。
f:id:WCE:20130330210811p:plain

①装甲に厚みを持たせる

被弾時に敵の砲弾やビームから機体を守るものですから、容易に貫通されないよう装甲にはある程度の厚みが必要です。
よく装甲がペラペラのイラストを観るんですが、意識しないとミスするポイントなので注意してください。
ただし、いくら厚い方がいいからと厚くしすぎると今度は鈍重な機体になります。
常に敵と正対して戦うことを想定して作られた戦車のように、一番被弾する前面装甲は厚くそうでない上面や背面の装甲は薄いといったデザインもありだと思います。

②前面での装甲の分割は避ける

せっかくの装甲なのに分割してしまっては、そこが弱点になって防御力がダウンします。
できれば分割しない方がいいのですが、巨大な装甲を一体成型するのは難しいということや装甲の取り外し、見栄えのことを考えると分割したくなります。
その場合は前面に分割ラインがくるのを避けるようにデザインしましょう。
関節の稼動を妨げないよう装甲がスライドするような機構を導入するのであればその限りではないと思います。(上のイラストの肩部装甲前面)

③適度にC面を入れる

C面というのは上のイラストの③の部分のように2面を斜めに接続する面のことを言い、C面を入れることを面取りと言います。
多くは直交する2面を45°に接続するのですが、これによって衝突時に機体の角が破損したり、衝突した物体を破損させたりするのを防ぎます。
デザイン的にはイラストの情報量が増え、面が間延びしなくなるので多用されます。
ですがあまりに小さい部品の角にまで面取りするとごみごみするので程々にしましょう。


こんな記事を書いてると合理的に描いた方がいいんだ!と思われるかもしれませんが、そんなことはありません。
リアルロボットのリアルはあくまで「それっぽい」という意味だと思います。
なので、見た目のかっこよさを重視しつつも隙あらば上記のようなポイントを抑えるというスタンスがいいと思います。

関連記事
ロボット・メカの描き方 装甲の形状2

台詞をつけるあそび

CG班新3年の灰色です。
今回は3月29日の活動報告をしたいと思います。

新歓の準備も終わり、暇になっていた僕はらくがきして遊んでいました。
すると、シナリオ班の雀荘に「ワルそうなおっさん書いてー」と頼まれたので描きました。
f:id:WCE:20130330214202p:plain
ワルそうなおっさんです。心まで悪に染まりきっています。
すると、背後でそれを見ていたジャミラスが台詞をつけてきました。
f:id:WCE:20130330214410p:plain
そしてジャミラスはこういって雀荘を煽ります。
「え?シナリオ班長なんだからもっと面白いこと言えるんじゃないですかぁ↑?」
こうしてなぜか唐突に、台詞つけ大会が始まったのでした。

というわけで、作品をまとめて紹介します。

作:ジャミラス
f:id:WCE:20130330214749p:plain

作:サムエル
f:id:WCE:20130330215256p:plain

作:ベンケイ
f:id:WCE:20130330215346p:plain

作:ジャミラス
f:id:WCE:20130330222151p:plain

作:ジャミラス
f:id:WCE:20130330222204p:plain


以上です。
いかがでしたか?個人的にはジャミラスの「池袋駅、どっちですかね」が一番ツボでした。
結構ホームページには真面目なことを書いてますが、普段の活動は結構遊んでたりもしますよっというおはなしでした。

あれ?結局雀荘が何も言ってないような・・・

新歓期の日程

新歓期の WCE のイベントは次の通りです。

サークル見学・説明会(どの日も同じ内容)

場所: 51 号館横 2 階 理工学生ラウンジ
4/10 (水) 18:15 - 19:30
4/12 (金) 18:15 - 19:30
4/17 (水) 18:15 - 19:30
4/19 (金) 18:15 - 19:30

Haskell 勉強会見学

場所: 63 号館 1 階 馬車道
【雨のため中止】4/3 (水) 10:40 - 12:10

来る際には事前連絡は不要です。当日はこのポスターが目印です。
プログラミング、CG・イラスト制作、DTM、シナリオ制作について語り合いましょう。
メンバー一同お待ちしてます!

伏せ音の入れ方

CG班新2年のベンケイです。
いよいよ明日、大学生活を共にする仲間たちと出会うことになります。
それぞれが、それぞれのvisionを思い描いて、新たな一歩を踏み出すことでしょう。
まあその初日にTOEICがあるんですけどね。
いきなり残念な気分になります。

さて、私は唯一の先進理工学部生(電生の方とかいらっしゃってもいいような気がしますが)ですので、増えてくれるといいなとか思っています。
ですから、皆さんの役に立つような内容を書ければいいなと思っているのですが、まだまだ未熟ですので、発信できるような知識・技術がありません。

ということで、豆知識的なことでもやろうと思い、「伏せ音の簡単な入れ方」を説明してみようかと思います。個人情報がとやかく言われる時代ですから思わぬ場面で役に立つかもしれません。

フリーソフトのAudacityを使ってやってみます(サウンド編集ソフトなら多分何でもOK)。

まず、一般的な「ピー音」からやってみましょう。
1. 編集したい音声データを開きます。
2. 伏せたい部分を選択します。
f:id:WCE:20130327135642p:plain
3. ジェネレータを開き、トーンをクリックします。
f:id:WCE:20130327135744p:plain
4. 波形は「サイン波」、周波数は1000くらい、振幅は音の大きさですので範囲内(0~1)で調節してください。
f:id:WCE:20130327135812p:plain  
これで完成です。

これだけではつまらないので、効果音でも入れてみましょう。
今回は「銃声音」を入れてみます。
音源はSenses Circuit様からお借りしました。
1. 編集したい音声データと効果音(今回は銃声音)を開きます。同時に開くことができます。
f:id:WCE:20130327135949p:plain
2. タイムシフトツールを使って位置を合わせます。
f:id:WCE:20130327135959p:plain
3. 伏せたい部分を選択し、ジェネレータ→無音をクリックします。
f:id:WCE:20130327140008p:plain
これで完成です。
こんな感じで簡単に編集ができます。
オリジナルの効果音を作ってやってみるのも面白いかもしれません。

参考までに今回編集したものです。
元音声
ピー音
銃声音

勉強会

WCE プログラミング班新 4 年 @Reputeless です。

f:id:WCE:20130327215805j:plain
WCE では、有志メンバーが 4 人以上集まると、サークル外部の参加者も交えた 勉強会 を開催できます。

昨年 11 月に始まった、プログラミング言語 Haskell の勉強会は、週1回(春休みは週2回)ペースで開催され 20 回目を数えます。進行はメンバーが交代で担当し、Haskell の入門書『すごい Haskell たのしく学ぼう』に沿って、わからないところを相談しあい、自分たちで問題を作って解きながら進めていきます。先日ようやくページ数にして半分が終わりました。

1人で勉強していると、途中で放置してしまったり、長い時間悩んでしまうことがよくあります。
勉強会は定期的に開催されるので、モチベーションが維持でき、難しいところはメンバーと一緒に解決できるので、とても役立ちます。

新しいことを勉強したいけれど、続けられるかどうか不安なときは、サークルで勉強会を提案してみましょう。一緒に挑戦する仲間が見つかるはずです。