Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9297

【Unity】Minecraftを作りたい!!Part1

$
0
0

はじめに

Minecraftが好きなので,Unityでサンドボックス系オンラインゲームを作りたいなと思いました.
具体的にはMinecraftのようなサンドボックス + 2ちゃんねる or Twitterのようなコミュニケーションツールを目標にしています.
進捗報告&技術備忘録的な記事として書いています.

今回の進捗:マイクラ風コントローラー作成

マイクラ風のコントローラーはアセットとして既に無料で配布されているらしいのですが,作りたかったので作りました.(о´∀`о)
controller.gif
WASDで移動し,マウスで視点を振って,SPACEキーでジャンプします.

ソースコード

※行き当たりばったりで書いてるので命名規則が雑だったり短縮できる冗長な部分もあるかもしれないですがご了承ください.

Player.cs
usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassPlayer:MonoBehaviour{publicfloatspeed=6f;publicfloatmouseSensitivity=0.1f;publicfloatjumpPower=4f;publicGameObjectcamera;publicGameObjectcursor;privateVector3viewVec=newVector3(1,0,0);privateVector3moveVec;privateVector3camPos;privateRigidbodyRigidbody;privateBoxCollidergroundCollider;privateboolisGround=false;voidStart(){// Get componentRigidbody=GetComponent<Rigidbody>();groundCollider=GetComponent<BoxCollider>();// ViewpointLookAtSet();// Hide mouseCursor.lockState=CursorLockMode.Locked;Cursor.visible=false;}voidUpdate(){// Camerafloatmouse_x=Input.GetAxis("Mouse X")*mouseSensitivity;floatmouse_y=Input.GetAxis("Mouse Y")*mouseSensitivity;Vector3nomVec=newVector3(viewVec.z,viewVec.y,-viewVec.x);viewVec+=nomVec.normalized*mouse_x;nomVec=Vector3.up;viewVec+=nomVec.normalized*mouse_y;viewVec=viewVec.normalized;// MoveboolisMove=false;if(Input.GetKey(KeyCode.W)){isMove=true;moveVec=newVector3(viewVec.x,0,viewVec.z).normalized*speed*Time.deltaTime;Rigidbody.velocity=newVector3(moveVec.x,Rigidbody.velocity.y,moveVec.z);}if(Input.GetKey(KeyCode.S)){isMove=true;moveVec=newVector3(-viewVec.x,0,-viewVec.z).normalized*speed*Time.deltaTime;Rigidbody.velocity=newVector3(moveVec.x,Rigidbody.velocity.y,moveVec.z);}if(Input.GetKey(KeyCode.A)){isMove=true;moveVec=newVector3(-viewVec.z,0,viewVec.x).normalized*speed*Time.deltaTime;Rigidbody.velocity=newVector3(moveVec.x,Rigidbody.velocity.y,moveVec.z);}if(Input.GetKey(KeyCode.D)){isMove=true;moveVec=newVector3(viewVec.z,0,-viewVec.x).normalized*speed*Time.deltaTime;Rigidbody.velocity=newVector3(moveVec.x,Rigidbody.velocity.y,moveVec.z);}if(!isMove){Rigidbody.velocity=newVector3(0,Rigidbody.velocity.y,0);}// Jumpif(Input.GetKey(KeyCode.Space)&&isGround){isGround=false;Rigidbody.AddForce(Vector3.up*jumpPower,ForceMode.Impulse);}// ViewpointLookAtSet();}voidOnTriggerEnter(Collidercoll){isGround=true;}voidOnTriggerExit(Collidercoll){isGround=false;}voidLookAtSet(){camPos=this.transform.position+viewVec;this.transform.LookAt(newVector3(camPos.x,this.transform.position.y,camPos.z));camera.transform.position=newVector3(camPos.x,this.transform.position.y+0.5f,camPos.z);camera.transform.LookAt(camera.transform.position+viewVec);}}

プレイヤーは1x2x1の直方体で,コンポーネントにはこのスクリプトとRigidBody,BoxColliderを2つ(体の当たり判定用と足元の地面設置判定用)をアタッチしています.地面設置用のBoxColliderはisTrrigerにチェックを付けています.

解説

視点変更

// ViewpointvoidLookAtSet(){camPos=this.transform.position+viewVec;this.transform.LookAt(newVector3(camPos.x,this.transform.position.y,camPos.z));camera.transform.position=newVector3(camPos.x,this.transform.position.y+0.5f,camPos.z);camera.transform.LookAt(camera.transform.position+viewVec);}

これは,カメラの座標とカメラの向き,プレイヤーの向きを指定する関数となります.
viewVecにはプレイヤーの視点の長さ1のベクトルが保存されています.
camPosはXZ座標(上から見た状態)でのカメラの位置をXとZのパラメータに保存しています.
<GameObject>.transform.LookAt()はゲームオブジェクトに引数の3次元ベクトルの方向を向かせる関数です.Y座標はジャンプ以外で動いてほしくないので上記のように個別で指定しています.
上のように<GameObject>.transform.LookAt()の引数に(オブジェクトの座標)+(向きベクトル)を渡すと視点ベクトルで管理する時に見やすく書くことが出来ます.

カメラ

// Camerafloatmouse_x=Input.GetAxis("Mouse X")*mouseSensitivity;floatmouse_y=Input.GetAxis("Mouse Y")*mouseSensitivity;Vector3nomVec=newVector3(viewVec.z,viewVec.y,-viewVec.x);viewVec+=nomVec.normalized*mouse_x;nomVec=Vector3.up;viewVec+=nomVec.normalized*mouse_y;viewVec=viewVec.normalized;

Input.GetAxis("Mouse X")Input.GetAxis("Mouse Y")によって毎フレームのマウスの移動距離を取得できます.
視点ベクトルにその法線のベクトルを足すと,こんな風に直角三角形の斜辺のようなベクトルが得られます.(下図)
これで視点の左右回転を再現しています.
wedgrethtf.png
また,視点ベクトルに上ベクトルを足すと,上下回転した後のベクトルが得られます.(下図では上ベクトルをマイナス倍している)
drfthftykfsgnfdgty.png
マウスの上下左右の移動量と正負を用いて(スカラー積)回転の向きと回転量を定義しています.
ただこのままでは視点を振るたびにベクトルが永遠に伸び続けるので,最後の行に.nomalizedで正規化しています.
ここで視点ベクトルを計算して上の視点変更の関数で実際にカメラを動かしています.

移動

// MoveboolisMove=false;if(Input.GetKey(KeyCode.W)){isMove=true;moveVec=newVector3(viewVec.x,0,viewVec.z).normalized*speed*Time.deltaTime;Rigidbody.velocity=newVector3(moveVec.x,Rigidbody.velocity.y,moveVec.z);}if(Input.GetKey(KeyCode.S)){isMove=true;moveVec=newVector3(-viewVec.x,0,-viewVec.z).normalized*speed*Time.deltaTime;Rigidbody.velocity=newVector3(moveVec.x,Rigidbody.velocity.y,moveVec.z);}if(Input.GetKey(KeyCode.A)){isMove=true;moveVec=newVector3(-viewVec.z,0,viewVec.x).normalized*speed*Time.deltaTime;Rigidbody.velocity=newVector3(moveVec.x,Rigidbody.velocity.y,moveVec.z);}if(Input.GetKey(KeyCode.D)){isMove=true;moveVec=newVector3(viewVec.z,0,-viewVec.x).normalized*speed*Time.deltaTime;Rigidbody.velocity=newVector3(moveVec.x,Rigidbody.velocity.y,moveVec.z);}if(!isMove){Rigidbody.velocity=newVector3(0,Rigidbody.velocity.y,0);}

ここではWASDそれぞれ入力を受け付けて,移動ベクトルを計算し,プレイヤーに速度を与えています.(似通った処理だからまとめられそう…)
moveVecでは前後左右のベクトルを計算するのですが,視点ベクトルを基準に前後左右を決めるためviewVecを使用して計算しています.
移動時の速度のYのパラメータは,moveVecのYが0となっているので個別で指定しています.
また,最後のif文ではキーを離した瞬間にピタッと止まらず少しスリップするのが嫌だったので速度を0に指定しています.

ジャンプ

// Jumpif(Input.GetKey(KeyCode.Space)&&isGround){isGround=false;Rigidbody.AddForce(Vector3.up*jumpPower,ForceMode.Impulse);}...voidOnTriggerEnter(Collidercoll){isGround=true;}voidOnTriggerExit(Collidercoll){isGround=false;}

ジャンプに関する記述はシンプルで,地面に接地しているか確認して,接地時にスペースが押されているとジャンプをするという流れになっています.ジャンプ時にすぐ接地フラグをFalseにし,接地後にTrueに戻すことによって,押しっぱなしで連続ジャンプになるようにしてみました.
記事を書いているうちにOnTriggerExit(地面から離れた瞬間オフにする記述)の部分いらないんじゃねーかって気がしてきました.ガバガバソースコードですね.

おわりに

今後は,
・プロシージャルマッピング(スクリプトによるマップ生成)
・PUN2の導入(PhotonUnityNetworking2というオンライン機能を実装するアセット)
・ブロックの設置
辺りをやっていきたいと思います.

…Part2書けるかなぁ()


Viewing all articles
Browse latest Browse all 9297

Trending Articles