月別アーカイブ: 11月 2016

unityチュートリアルSpaceShooterその3「攻撃」

標準

https://saitottammas.wordpress.com/2015/11/14/unity-spaceshooter1/

https://saitottammas.wordpress.com/2015/11/16/unity-spaceshooter2/

に続く第三弾

1.shot(弾)を作る。

1)画面上のPlayer(飛行艇)が邪魔になるので、インスペクターのPlayer前のチェックをはずして「非表示」にする。

2)Empty GameObjectを作成し(shift-CTRL-N)、名前を「Bolt」に変更する。リセットして位置を原点に戻す。

3)新規にQuadを作り、名前を「VFX」に変更する。場所をリセットする。

4)このVFXをドラッグしてBoltの下(childとして)に持っていく。

5) シーンビューで見ると、Quadの向きがカメラに水平になっているので、x軸で90度回転し、上から見て表面が見えるようにする。

6) ダウンロードしたアセットのテクスチャフォルダから、レーザーオレンジの画像を出す。

7) 単にテクスチャをドラッグする方法もあるが、今回は、マテリアル作成をしてみる。マテリアルフォルダを選択しておいてから、ヒエラルキーのcreateメニューから、create new materialを選ぶ。

名前をFX Bolt Orangeに変更する。

8)マテリアルのインスペクターウィンドウで、アセットピッカー(右上)を使い、テクスチャを選ぶか、テクスチャフォルダから画像をインスペクターフィールドにドラッグする。

9) 作成したマテリアルを、シーンビューのQuadにドラッグする。

10) このままでは、画面上に黒い四角が見えているので 、Shaderの変更をする必要がある。

デフォルトのDiffuseというのは、色を表示するShaderなので、代わりに、Particle→additiveを選ぶ。これは黒を透明にし、白を強調してくれる。他にも、mobile→particle→additiveでも良い。

mobile Shaderは、モバイルゲームでなくても有効である。

11)さて、Boltには現在何のコンポーネントも付いていないが、衝突計算も必要なため、rigidコンポーネントとコライダコンポーネントが必要になる。

まず、Rigidコンポーネントを追加し、重力を非選択する。

12) VFXオブジェクトを確認すると、mesh コライダーが自動的に付いているが、これは不要なので、removeコンポーネントする。

親のBoltオブジェクトに戻り、カプセルコライダーを追加する。カプセルの軸をy軸でなく、z軸にして弾の向きに合わせる。サイズも合わせて、隙間のないようにする。(真上からみると、半径0.03あたり、高さ0.5あたりが良さそうである)

13)コライダーコンポーネント設定で、Triggerのチェックをオンにする。

14) c#スクリプトを追加し、Moverと名づけて編集する。

using UnityEngine;
using System.Collections;

public class Mover : MonoBehaviour
{
private Rigidbody rb;
public float speed;

void Start ()
{
rb=GetComponent<Rigidbody>();
rb.velocity = rb.transform.forward * speed;
}
}

15)このBoltをヒエラルキーのPrefabsフォルダ(なければ作成する)にドラッグして、プレファブ化する。

16) 初期画面からBoltを削除し、ゲームプレイ中にこのプレファブをヒエラルキーウィンドウにドラッグすると、まっすぐに飛んでいくBoltを確認できる。

 

2.Fireボタンをクリックで発射

1)Shot(弾)は、プレファブ化したのだから、それをゲーム内で実体化する必要がある。

これをするのが、Instantiate(インスタンス化)である。ファイアボタン(マウス左ボタンか左コントロールキーに割り当てられている)
をクリックしたら弾が発射するようにする。これは、単にUpdate()関数の中に記述すればよい。

Instantiateの使い方:
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation);

ここでは、プレファブ化したBoltをVector3の位置とクォータにオン回転角度 で指定する。
これらの情報はどこで確認すればいいかというと、Inspectorの一番上にTransformというコンポーネントに
コンパクトに格納されている。

2)プレファブ化されているのは、Bolt(弾)であるから、それを使うとして、位置については、Player機の子供として
取り付けた、Shot Spawnを指定する。空(から)のGame Objectを追加し、Shot Spawnと名前を変更する。位置回転をリセットしたら、
これをPlayerオブジェクトの子供としてとりつける(Playerにドラッグする)。

3)弾が放出される場所を見つける。Shot SpawnはPlayerとの相対的な位置関係で座標が表示されるので、Z方向(機の前方)へずらし、適切な位置を探る。ここでは、Z位置が1.25ぐらいでちょうどよさそうである。BoltプレファブをShot Spawnの子供として配置して
みるとイメージしやすい(あとで削除するが)。

4)PlayerControllerスクリプトの修正

まず、public gameObject shot; 追加
public gameObject shotSpawn; のかわりに、 public Transform shotSpawn; 追加

void Update(){

Instantiate(shot, shotSpawn.position, shotSpawn.rotation);

}

このまま、Boltをshotの欄に、Shot SpawnをshotSpawnの欄にドラッグしてゲームスタートすると、連続して発射するプレイヤー機が見られる。

5)Fireボタンを押すと発射

コマンドマニュアルを開くと、サンプルコードが見られるので、それをコピペしてもいいのだが、
Input.GetButton(“Fire1”)
というコマンドはUnityに最初から設定済みである。

if(Input.GetButton(“Fire1”)を追加すると、左Ctrlキーかマウス左ボタンを押すと連続弾が発射される。

6)発射間隔を制限する工夫

fireRateという、射撃間隔を導入する。

それから計算すると、次の射撃は、nextFire = Time.deltaTime + fireRate になる。

public float fireRate;
private float nextFire;

void Update () {
if (Input.GetButton(“Fire1”) && Time.time > nextFire)
{
nextFire =Time.time+ fireRate;
Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
}
}

fireRate の初期設定は秒当たり4発ぐらいでよさそうなので、0.25にする。

このままでは、実体化したBoltが山ほど溜まってしまうので、次の章では、境界線を超えたら、削除(destroy)するというプログラムを書く

ーーーーーーーーー

PlayerControllerに追加し、弾を撃てるようにする。

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Boundary
{
public float xMin, xMax, zMin, zMax;
}

public class PlayerController : MonoBehaviour
{
public float speed;
public float tilt;
public Boundary boundary;
private Rigidbody rb;

public GameObject shot;
public Transform shotSpawn;
public float fireRate;

private float nextFire;

void Start () {
rb = GetComponent<Rigidbody>();
}

void Update ()
{
if (Input.GetButton(“Fire1”) && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
Instantiate(shot, rb.shotSpawn.position, rb.shotSpawn.rotation);
}
}

void FixedUpdate ()
{
float moveHorizontal = Input.GetAxis (“Horizontal”);
float moveVertical = Input.GetAxis (“Vertical”);

Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.velocity = movement * speed;

rb.position = new Vector3
(
Mathf.Clamp (rb.position.x, boundary.xMin, boundary.xMax),
0.0f,
Mathf.Clamp (rb.position.z, boundary.zMin, boundary.zMax)
);

rb.rotation = Quaternion.Euler (0.0f, 0.0f, rb.velocity.x * -tilt);
}
}

ーーーーーーー

広告

Blender Pythonでローレンツアトラクタ

標準

Blender Pythonでルンゲクッタ計算できるのではないかと、書いてみました。

ただ、グラボ970積んだマシンでも、途中「応答なし」表示で20分ぐらい待ちます。

別のところでX,Y,Z座標を計算し、結果だけBlenderで表示するほうが実用的でしょう^^;

計算以外の表示や初期設定は、こちらをだいぶ参考にさせてもらっています。

lorentz-render01
import bpy

#ウィンドウ上のオブジェクトを一度削除
for item in bpy.context.scene.objects:
 if item.type == 'MESH':
 bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
 if item.type == 'MESH':
 bpy.data.objects.remove(item)
for item in bpy.data.meshes:
 bpy.data.meshes.remove(item)
for item in bpy.data.materials:
 bpy.data.materials.remove(item)

#ローレンツの微分方程式を3つ定義
def fx(xx,yy,zz):
 q=-s*xx+s*yy
 return q
 
def fy(xx,yy,zz):
 q=r*xx-yy-xx*zz
 return q

def fz(xx,yy,zz):
 q=-b*zz+xx*yy
 return q
 
#初期定数設定
s=10
b=8/3
r=28
dt=0.01 #微分間隔 0.1にするとぼんやりした画像に

tmax=1000 #繰り返し回数 最初は100ぐらいで試すほうが無難
X=Y=Z=1.0
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 1, size = 0.2, location = (X,Y,Z))

#ルンゲクッタ法による微分方程式の解の近似値を求めて描画
for i in range(0,tmax):
 d1x=dt*fx(X,Y,Z)
 d1y=dt*fy(X,Y,Z)
 d1z=dt*fz(X,Y,Z) 
 d2x=dt*fx(X+d1x*0.5,Y+d1y*0.5,Z+d1z*0.5)
 d2y=dt*fy(X+d1x*0.5,Y+d1y*0.5,Z+d1z*0.5)
 d2z=dt*fz(X+d1x*0.5,Y+d1y*0.5,Z+d1z*0.5) 
 d3x=dt*fx(X+d2x*0.5,Y+d2y*0.5,Z+d2z*0.5)
 d3y=dt*fy(X+d2x*0.5,Y+d2y*0.5,Z+d2z*0.5)
 d3z=dt*fz(X+d2x*0.5,Y+d2y*0.5,Z+d2z*0.5) 
 d4x=dt*fx(X+d3x,Y+d3y,Z+d3z) 
 d4y=dt*fy(X+d3x,Y+d3y,Z+d3z) 
 d4z=dt*fz(X+d3x,Y+d3y,Z+d3z) 
 X=X+(d1x+2*d2x+2*d3x+d4x)/6.0
 Y=Y+(d1y+2*d2y+2*d3y+d4y)/6.0
 Z=Z+(d1z+2*d2z+2*d3z+d4z)/6.0
 bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 1, size = 0.2, location = (X, Y, Z))
lorentz-02lorentz-01 lorentz-03

Can download from github:

https://github.com/saitottammas/lorentz-in-blender