前書き
破壊についてはこちら
simplestar-tech.hatenablog.com
今回は配置を考えていきます。
作る前から見えている絵は…
右クリック開始で 配置先が見える
アローキーで配置先が回転
右クリック解除で配置
具体的な実装を進めてみましょう。
前回の配置は?
以下のようなコードを書いて、回転配置にも対処していた模様
internal static void RotateCube(Direction direction, ItemEntity itemEntity, Transform cameraTransform) { switch (itemEntity.cubeSt.rot) { case CubeRotation.Top000: switch (direction) { case Direction.X: itemEntity.cubeSt.rot = CubeRotation.Top270; break; case Direction.Y: switch (GetTransformDirection(cameraTransform)) { case Direction.X: itemEntity.cubeSt.rot = CubeRotation.Right090; break; case Direction.Z: itemEntity.cubeSt.rot = CubeRotation.Forward180; break; case Direction._X: itemEntity.cubeSt.rot = CubeRotation.Left270; break; case Direction._Z: itemEntity.cubeSt.rot = CubeRotation.Back000; break; default: break; } break;
マウスの右クリックイベントを発行
すでにマウス左クリックの仕組みがあったので、同様にして対処
void Start() { // キューブ選択処理のイベントを購読 this.cubeSelector.onLocateStarted += this.OnLocateStarted; this.cubeSelector.onLocateCanceled += this.OnLocateCanceled; this.cubeSelector.onChangeSelected += this.OnChangeSelected; }
右クリック完了時にキューブを配置
適当な素材の適当な回転で配置する
破壊と同じ仕組みで、空気ブロックにするところ、何かのブロックにするという対応でいけるだろうか?
空気ブロックにする実装がこちら
// 対象キューブを空気に var chunkInt3 = this.chunkCollider.gameObject.GetComponent<ChunkMeshInfo>().chunkInt3; this.cubeDataWorld.SetCubeData(this.cubeCenter, chunkInt3, CubeCategoryType.Basic, CubeRotationType.Top000, SideType.Air, SideType.Air);
かなり簡単にいけそう
this.cubeCenter = cubeObject.transform.position + raycastHit.normal; // 対象キューブ表面を適当なブロックに var chunkInt3 = this.chunkCollider.gameObject.GetComponent<ChunkMeshInfo>().chunkInt3; this.cubeDataWorld.SetCubeData(this.cubeCenter, chunkInt3, CubeCategoryType.Basic, CubeRotationType.Top000, SideType.Bubbles, SideType.Bubbles);
いけた
テストしていて、さっそく問題に…
キューブを置く場所がチャンクをまたぐと、チャンクの特定のための情報がずれる
正しい情報はキューブの位置から特定できなければならない
次の実装で期待通り動いた
var x = this.cubeCenter.x / (ChunkConst.ChunkSizeX * ChunkConst.CubeSide); if (0.5f > Mathf.Abs(this.cubeCenter.x)) { x = 0; } var y = this.cubeCenter.y / (ChunkConst.ChunkSizeY * ChunkConst.CubeSide); if (0.5f > Mathf.Abs(this.cubeCenter.y)) { y = 0; } var z = this.cubeCenter.z / (ChunkConst.ChunkSizeZ * ChunkConst.CubeSide); if (0.5f > Mathf.Abs(this.cubeCenter.z)) { z = 0; } var chunkInt3 = new Vector3Int(Mathf.FloorToInt(x), Mathf.FloorToInt(y), Mathf.FloorToInt(z)); Vector3Int CubePositionToCubeInt3(Vector3 cubePosition) { int x = Mathf.FloorToInt(cubePosition.x / ChunkConst.CubeSide) % ChunkConst.ChunkSizeX; x = 0 > x ? ChunkConst.ChunkSizeX + x : x; int y = Mathf.FloorToInt(cubePosition.y / ChunkConst.CubeSide) % ChunkConst.ChunkSizeY; y = 0 > y ? ChunkConst.ChunkSizeY + y : y; int z = Mathf.FloorToInt(cubePosition.z / ChunkConst.CubeSide) % ChunkConst.ChunkSizeZ; z = 0 > z ? ChunkConst.ChunkSizeZ + z : z; return new Vector3Int(x, y, z); }
実装ヒントは過去のキューブ情報の特定の部分から
遠くから眺めたい
デバッグ機能でいいので、ホイール操作でカメラと被写体までの距離を伸ばせませんかね
できた
void Start() { this.dollyAction.performed += ctx => { var orbit = this.cinemachineFreeLook.m_Orbits[1]; orbit.m_Radius += ctx.ReadValue<float>() * this.scale; this.cinemachineFreeLook.m_Orbits[1] = orbit; }; }
右クリック開始時に半透明のキューブの表示
もこもこの応用で素早く用意できそうな気がしてるけど
半透明ってところに困ってる
マテリアルの設定箇所を探す?
新しく ShaderGraph を作って対処しました。
いったんは小ゴールクリアですね。
www.youtube.com
アローキーで配置先が回転
まずはアローキーイベントを拾わねば
各方向へのアクションとしてDirection を定義
public enum Direction { X = 0, Y, Z, _X, _Y, _Z, Max }
アローキーアクションでこのように回転を与えます。
void Awake() { this.locatorAction.performed += ctx => { if (this.locatingFlag) { var direction = Direction.Max; var directionFloat2 = ctx.ReadValue<Vector2>(); if (0.5f < directionFloat2.x) { direction = Direction.X; } else if (-0.5f > directionFloat2.x) { direction = Direction._X; } if (0.5f < directionFloat2.y) { direction = Direction.Y; } else if (-0.5f > directionFloat2.y) { direction = Direction._Y; } this.RotatePrePutCube(direction, Camera.main.transform); this.PreLocateCube(); } }; }
そして、冒頭の過去の実装につなげれば OK。
予想通りいけました。
配置をキャンセルしたい
あとはちょっとした不具合を直します。
キューブの破壊と違って、配置場所がずれたらキャンセル扱いにしたい
となると
CubeSelector 側で新しいイベントかな
if (this.currentGridLocatePosition != gridLocatePosition) { this.currentGridLocatePosition = gridLocatePosition; this.onChangeLocatePosition?.Invoke(); }
このような実装を加えて解決した