kazumalab tech log

流行りとリラックマと嵐が大好きです。技術的ログ。

RubyでOpenGLを動かすところまでのお話

かずまです。

今日は入社式とか研修とかでした。
帰ってバタンキューだったのですがなんか妙な時間に目覚めてしまったのでRubyOpenGLAPI叩けないかなーってことで調べてたら
あった!


別にRubyでゲーム作りたいとか、ではないのですが、使えると便利かな、ぐらいです。

github.com

ちゃんとありました。
DirectXは基本WindowsAPIになっているのでMacLinuxユーザーとしてはOpenGLかなって感じですね。
まぁVM立ててWindows立ち上げるみたいなので力技はできますが。

Sampleを動かす

先程のgithubからCloneしてきてSampleを動かしてみることにします。

GemのOpenGLとかを入れるのですが、まぁプロジェクトごとに管理できるのが一番いいのでBundlerを入れてしまいます。
入ってる場合は飛ばします。

こことかを参考にして

blog.tokoyax.com

$ gem install bundler

Fetching: bundler-1.14.6.gem (100%)
Successfully installed bundler-1.14.6
Parsing documentation for bundler-1.14.6
Installing ri documentation for bundler-1.14.6
Done installing documentation for bundler after 4 seconds
1 gem installed

OK、これでExampleディレクトリに移動して、

$ bundle init
$ vim Gemfile

ここでGemfileの中身を書き加えます。

gem 'opengl'
gem 'glu'
gem 'glut'

これで後は

$ bundle install --path=vendor/bundle

これでここのディレクトリのみにGemがインストールされるはずです。
よしこれで動く環境は整いました、examples/Neheに移動してrubyで叩いてみます!

$ bundle exec ruby nehe_lesson02.rb 

f:id:kazumalab:20170404023612p:plain

おぉー表示されました。
いいですね。

頂点をきめたりするところ

glBegin GL_POLYGON do
    glVertex3f  0.0,  1.0, 0.0
    glVertex3f  1.0, -1.0, 0.0
    glVertex3f -1.0, -1.0, 0.0
end

ここで三角形の頂点を決めてますね。
GL_POLYGONの部分でどんな形をレンダリングするかです。

ちなみにGL_QUADSのところを

glBegin GL_POINTS do
    glVertex3f -1.0,  1.0, 0.0
    glVertex3f  1.0,  1.0, 0.0
    glVertex3f  1.0, -1.0, 0.0
    glVertex3f -1.0, -1.0, 0.0
  end

GL_POINTSに変更すると

f:id:kazumalab:20170404033516p:plain

見えにくいですが点がレンダリングされます。

使うとよさそうな一覧が乗ったページがありますのでこちらを参考にするといいかも。
glBegin

今日は時間も遅いのでここまで。
お疲れ様でした。

敵ロックオン機能をUnityで実装する <ゼルダの伝説シリーズ>

かずまです。

今回も引き続き、ゼル伝シリーズをやっていきます。


そういえば今回のゼルダの伝説は一応ストーリー全クリしました。
ただマップの開放とかいっぱいやることはありますね。

ネタバレっぽくなっちゃいますが、感動した!これだけ言っておきます!笑

気になる方はこちら!
ゼルダの伝説 ブレス オブ ザ ワイルド


テーマ

今回は画面内に入った敵を注目してLボタンでロックオンするところです。
ロックオンして、タイミングよくバク転か、サイドステップをするとラッシュ攻撃ができます。

これです。
ちなみに一定の範囲内に入った時に注目できるよって示すマークを出します。

考察

ロックオン(注目)で重要な点は

  • 注目できる敵の上になにか表示
  • 注目したらなにか表示(上とは違うものを)
  • 注目しているときは敵を見続ける
  • 画面外になったときは解除される

これぐらいです。

下準備

まずは重要な点でも言ったなにか表示の部分の準備です。
注目している場合の画像は、今回いいのがあったのでフリーを使います。

yajidesign.com
この末広がりのやじるしです。

[指し示すだけの三角]
f:id:kazumalab:20170402082026p:plain
白紙ですが、この上に有ります。

これをSpriteRendererで違和感のないサイズに変更し、名前を"Point"に変更し、Prefab化します。

f:id:kazumalab:20170402090702p:plain
サイズ的にはこんな感じ。

そのPrefabに次のスクリプトをアタッチします。


これでPrefabにくっつけます。
この時、InspectorからSpriteをセットし忘れないように...。

EnemyManagerを作る

今回Enemyが画面に入ったらリストに追加、削除していきます。
そこから最短のEnemyを取り出したりすることができます。

これを作りました。
MonoBehaviourは継承しません。継承しちゃうとインスタンス生成できなくなりますかね。

次にEnemyManagerをPlayer.cs内でインスタンス生成します。
前回のPlayer.csを使い、変数とStart関数、新規メソッドを追加します。
ついでにXbox One ControllerのLBをLTriggerとしてUnityにセットしておきます。

// 変数
public EnemyManager EnemyMGR;

// Start関数でインスタンス生成、コンストラクタとしてPlayerが必要なので自分をいれる
private void Start () {
		EnemyMGR = new EnemyManager (this);
		CharactorCTL = GetComponent<CharacterControl> ();
		CameraCTL = GameObject.Find ("Main Camera").GetComponent<CameraControl> ();
	}

// 新規メソッド追加
public void Locked () {
		if (Input.GetAxis ("LTrigger") > 0.9f) {
			Enemy enemy = EnemyMGR.getNearEnemy ();
			if (enemy != null) {
                                // あとでEnemyAttentionメソッドを記載します
				enemy.Attention ();
			}
		}
	}

Enemyスクリプトに追記

次にEnemyは画面に入った、出た場合のタスクとして、そのEnemyManagerに自身を突っ込んでもらいます。
画面外は自分をリストから削除します。

画面に入った入ってないは

qiita.com

このQiitaで完結に解説されています。

// 画面外にでた
private void OnBecameInvisible () {
	player.EnemyMGR.DeleteEnemy (this);
}

// 画面内に入った
private void OnBecameVisible () {
	player.EnemyMGR.AddEnemy (this);
}

private void OnWillRenderObject() {
  // あとで記載
}

EnemyはPlayerを常に見ている状態なのでPlayerのEnemyManagerにもアクセスできることになります。
これで画面に入ったりでたりというのが確認できます。

注目しているかしていないか、Player側に持っておくのではなくEnemy側で管理します。
Enemy.csに変数とメソッドをもう少し付け加えます。

private readonly float AttentionDistance = 4f;

public bool isDrawingAttention = false;

public void Attention () {
	player.transform.LookAt (transform.position);
	isDrawingAttention = true;
}

public void UnAttention () {
	isDrawingAttention = false;
}

private void OnWillRenderObject() {
   // あとで記載と書いていた場所
	if (getDistance () < AttentionDistance) {
		transform.FindChild ("Point").GetComponent<SpriteRenderer> ().enabled = true;
	} else {
		transform.FindChild ("Point").GetComponent<SpriteRenderer> ().enabled = false;
	}
}

あとはこれでEnemyの子どもとしてPointのPrefabをセットします。
isDrawAttentionがtrueのときは注目している画像になればOKです!

結果

f:id:kazumalab:20170402181518g:plain

もっと派手なエフェクトほしいけどまた今度!
なんか雑になってきたやばい...。

追記

  • クラス図とか書こうと思う
  • オブジェクト指向プログラミング意識しよう
  • ちゃんと寝よう

敵の目線の動きをUnityで実装する <ゼルダの伝説シリーズ>

かずまです。

前回まではPlayerの動きを実装していました。



blog.kazumalab.com

ちなみにSwitchのゼルダの伝説の動きが気になる方はこちら。

ゼルダの伝説 ブレス オブ ザ ワイルド

テーマ

今回のテーマは"敵の動き"です。
敵がいないと始まらないですからね。

考察


敵の動きを見てみます。

気づかれると注目して見られる

音に気づく

目線があうと気づかれる

隠れると見失う

ココらへんが結構重要だと思います。
この章では歩くことはあとで実装します。

Enemyを追加

EnemyをPlayerと同じものを作ります。
前回作ったCharactorControlをつけます。

今度はEnemy.csを作ります。


気づいたときのアクション

EnemyにつけるNoticeObjectを作ります。

気づいたときのびっくりマークとはてなマークをPhotoShopとかIllustratorで作ります。
[びっくり]
f:id:kazumalab:20170331001612p:plain
[はてな]
f:id:kazumalab:20170331001727p:plain

両方背景透明なので白く見えますがあります。

Notice.csを作成

先程用意した画像をSpriteにして、SpriteRendererで表示します。
その時につけるスクリプトです。

以下のように設定します。
f:id:kazumalab:20170331002330p:plain

WarningはHatenaのSpriteを入れて、
DiscoveryはBikkuriのSpriteを入れます。

これをPrefab化して、その後、NoticeObjectに入れます。

ここからは重要な部分だけを取り上げて解説していきたいと思います。

Playerとの距離

Unity C#では

Vector3.Distance (Vector3 a, Vector3 b)

で距離を求めますが、今回は簡単なので実装してみます。
PowはC++でもライブラリがあるみたいなので、ちょっと意識して...

// Enemy.cs
Vector3 dv = player.transform.position - transform.position;
return Mathf.Pow ((dv.x * dv.x + dv.y * dv.y + dv.z * dv.z), 0.5f);

unitylab.wiki.fc2.com
いや、ここのサイトのように正規化したほうが良さそう。

EnemyはPlayerを探す

EnemyにはSearchメソッドがあって、そこの中でPlayerを探しています。

検索方法としては、

目線

Enemy.cs内でenum設定している

  • Warning

これは気づくか気づかないかを表します。
はてなマークのアイコンを使います。

  • Discovery

これは気づいたときを表します。
ビックリマークのアイコンを使います。

距離

これは先程、使ったメソッドを使って距離を測っています。
次の足音が小さければ距離が近くても気づかれないです。

足音

今回のゼルダから導入されました、足音の機能です。
気づかれず、回り込めば不意打ちを噛ませます。

これを実装します。

入力の力に合わせて足音を実装する

今回はXbox Controllerのスティックを使っているためGetAxisを使うことができます。

float dx = Input.GetAxis ("Horizontal");
float dy = Input.GetAxis ("Vertical");

WalkVolume = (Vector3.right * dx + Vector3.up * dy).magnitude;
getWalkVolumeStatus ();


Player.cs内のこの部分でmagnitudeで入力の加減を取っています。
これを足音としています。
スティックを強く押し込むと足音が大きく、軽く押し込むと小さくなります。


VolumeのStatusでどの動きか、を取ることができます。

  1. Quiet
  2. Small
  3. Loud

f:id:kazumalab:20170331013058g:plain

こんな感じ。
これに音をつければそれっぽくなります。

後半へばってしまいましたが、今回はこんな感じです。

f:id:kazumalab:20170331013805g:plain
デザインとかも実装したいですがうーん笑


コードのデザインもうまくいかないのでそこまで手が回らなそう。
もっとこうしたらいいよ、みたいなのがありましたら言ってください...!

カメラワークとプレイヤーの動きをUnityで実装する Part2 <ゼルダの伝説シリーズ>

かずまです。
前回の記事はこちら。

blog.kazumalab.com

そう、ゼルダの伝説です。

テーマ

今回のテーマはゼルダの伝説のプレイヤーの動きとカメラの動きを再現します。
しかし、昨日試行錯誤したのですが、ちょっと違うっぽい動きになってしまいました。
そのうち改善します。

考察

リンクの動きはカメラの方向が正面になります。
なので、動いている時にカメラを回転させたらその方向に移動する感じですね。

Playerを実装

まずはPlayerを動かします。
今回は拡張性を踏まえてCharactorControllerを使わないで自分で実装します。

上記スクリプトを書きます。
CharactorControllerではisGroundがあったので、それも実装してしまいます。

  1. Raycastで距離を測る
  2. Colliderでのあたり判定

この2つによって実装されます。
Colliderだけだと天井などに当たったときに反応してしまうのでRaycastも使います。


つけるコンポーネントは以下の通りです。
RigidbodyをつけてFreeze Rotationをすべてチェックいれます。
これをしないと物に当たった時に制御できなくなります。

f:id:kazumalab:20170328195415p:plain

次にPlayer.csを実装します。

これをPlayerのオブジェクトにくっつけます。
前回のブログでもちょこっとかきましたが、それにすこし付け足します。

UnityでXboxOneコントローラを使う…前に | 蒼玉亭
ここを参考にして、Playerの動きはXbox Controllerの左スティック、カメラの動きは右スティックを使って制御します。

Edit -> Project Settings -> Input
からMouse XとMouse Yがあるとおもうので、以下のように変更してあげます。
これでInput.GetAxis("Mouse X")でOKになります。

f:id:kazumalab:20170328200927p:plain

MacXbox Controllerを使う

Driverが必要だそうです。
github.com

ここからdmgを落としてくるなりでOKです。
再起動されます。

結果

ホントはこれ、カメラ動かしてないときはPlayerも回転させてかったけど...だめだった。
そのうち他のところ実装しながら思いついたらやり直します。

カメラワークをUnityで実装する Part1 <ゼルダの伝説シリーズ>

かずまです。

Switchが発売され、スプラトゥーンの試射会も行われ、
ようやく落ち着いた感じがします。

あいかわらずSwitchは台数が少ないみたいで、品薄みたいですね。
ちなみに沖縄のゲオは数台ありました。

今日日曜日も入荷するとか...


さて、今日からシリーズで書いていきたいと思います。

テーマ

今回のシリーズは今流行りの「ゼルダの伝説」を取り上げていきます。
もちろん、開発の方です。

僕はゲームの中で一番と言っていいほどゼルダが大好きなのですが、
何と言ってもゲーム性と操作性、全てに置いて素晴らしいですね。

僕もゼルダの開発に携わりたい、というのが一生の夢ですが、もしかするとゲーム開発が手軽になった今、自分でも近いものが実装できるのでは?
と思ったわけです。(無謀)

今回のお題

"プレイヤーを写すカメラの動き"です。
これはゲームに置いて結構重要なのではないでしょうか。

考察

まずは実際に見てみます。
もちろん僕は実際にプレーもしました。

れいなカメラワークですね。
プレイヤーが中心でその周りをカメラが移動していますね。
常にプレイヤーに向いている感じ。
あとは上下の限界を決めてますね。

実装部分

今回実装する部分の詳細は以下になります。

スティックを倒した時にカメラの回転と高さの変更

天井が低い場所に行った場合のカメラの位置を下げる

カメラワークのリセット

3つになります。
ほんとは移動の常に倒した方向に移動するところとかまで行きたかったけど仕方なく、次回です。

プログラミング & ゲーミング

やりつつ、コード書きつつと言った形でやってみました。

f:id:kazumalab:20170326075502g:plain

こんな感じです。

実装

はじめ、カメラを子オブジェクトにして、それを回転させればできそう!と思って作ってたのですが、高さを変更する時とかバグったため、それは諦めました。

ただし、構造は同じです。
f:id:kazumalab:20170326080057p:plain

カメラに空の親オブジェクトをくっつけて、その親は常にPlayerの座標に位置するというものです。

上のスクリプトをMain Cameraにアタッチします。
そのあとPlayer.csを作成します。
これはPlayerのゲームオブジェクトにくっつけます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour {


	public float HeightToRoof = 0f;
	// Use this for initialization
	void Start () {
	}
	
	// Update is called once per frame
	void Update () {
		HeightToRoof = getHeadHeight ();
	}


	public float getHeadHeight () {
		RaycastHit hit;

		if (Physics.Raycast (transform.position, Vector3.up, out hit)) {
			print ("Found an object - distance: " + hit.distance);
			return transform.position.y + hit.distance;
		}
		return 100f;
	}

これでInspectorのところでターゲットとなるPlayerと、親を入れてあげればOK!

解説

CameraではLookAtを使ってPlayerの方向を向かせています。
これはまぁこれでいいかと思います。

回転部分

回転部分は三角関数を使って計算しています。
入力はGetAxisを使ってますが、場合に合わせて変更してください。

参考はこちら
r-dimension.xsrv.jp

とある角度a(float)に対してのSinはy座標、Cosはx座標となるので半径をrとするととある座標pは

x = r \bullet cos(a)
y = r \bullet sin(a)

これで座標pのx,yが求まりますね。
Cameraは子オブジェクトなのでこの座標をローカル座標に入れて上げることで円形を書いて回転します。

上下の位置を変更する場合は、Verticalの値をそのまま高さにかけてあげます。

自動カメラ下げ

Player.csではRaycastを書いたと思います。
体から上方向にRayを飛ばして、天井との高さを返しています。
あとはカメラのグローバル座標をその高さにするだけです。

リセット

スペースを押せばリセットされるようになっています。
ここの値は強制...してますです。

まとめ

さて、今回はUnityでカメラワークを実装してきました。
本家の方はどうなってるんでしょうね、気になりますが、それなりに上手く行ったと思います。

たぶん、これだとターゲットの部分を変更すると自動的にターゲット変更できるかも...
あと

www.asset.techmatome.com

dtweenとかと組み合わせるといいですね。

次回はプレイヤーの移動に関しての記事を書こうとおもいます。