Unity - Change cube color before placement - unity3d

So, I am making a Minecraft-like game, and you basically move around on a pre-generated floor and place blocks. My problem is that I need to get the ability for the player to change the block color by hitting a numberpad key, ex: 1 for red, 2 for blue, and so on.
Here is the script that generates the floor, and handles block placement.
var range : float = Mathf.Infinity;
var hit : RaycastHit;
for (var y = -4; y < 50; ++y)
for (var x = -4; x < 50; ++x) {
var block : GameObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
block.transform.position = transform.position + Vector3(x, -3, y);
}
function Update () {
if (Input.GetMouseButtonDown(0) && Hit()) {
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = hit.transform.position + hit.normal;
}
if (Input.GetMouseButtonDown(1) && Hit())
Destroy(hit.transform.gameObject);
if (Input.GetKeyDown(KeyCode.Keypad1)) {
cube.renderer.material.color = Color.red;
}
if (Input.GetKeyDown(KeyCode.Keypad2)) {
cube.renderer.material.color = Color.blue;
}
if (Input.GetKeyDown(KeyCode.Keypad3)) {
cube.renderer.material.color = Color.yellow;
}
if (Input.GetKeyDown(KeyCode.Keypad4)) {
cube.renderer.material.color = Color.green;
}
if (Input.GetKeyDown(KeyCode.Keypad5)) {
cube.renderer.material.color = Color.magenta;
}
}
function Hit() : boolean {
return Physics.Raycast(transform.position, transform.forward, hit, range, 1);
}

Related

Graphics.DrawMesh has wired offset while scaling in Unity, why?

I'm implementing after image effect currently and I meet a problem with Graphics.DrawMesh. The code shows below
public class AfterImage3DByCombine : MonoBehaviour
{
public class AfterImange
{
public Mesh mesh;
public Material material;
// public Matrix4x4 matrix;
public float duration;
public float time;
}
protected SkinnedMeshRenderer[] skinRenderers;
protected MeshFilter[] filters;
protected int filtersCount = 0;
public bool IncludeMeshFilter = true;
public Material EffectMaterial;
public float Duration = 5;
public float Interval = 0.2f;
public float FadeoutTime = 1;
private float mTime = 5;
private List<AfterImange> mAfterImageList = new List<AfterImange>();
protected virtual void Awake()
{
skinRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
if (IncludeMeshFilter)
{
filters = GetComponentsInChildren<MeshFilter>();
filtersCount = filters.Length;
}
}
//call from another place to have after image effect
public void Play()
{
if (skinRenderers.Length + filtersCount <= 0)
{
return;
}
mTime = Duration;
StartCoroutine(AddAfterImage());
}
IEnumerator AddAfterImage()
{
while (mTime > 0)
{
CreateImage();
yield return new WaitForSeconds(Interval);
mTime -= Interval;
}
yield return null;
}
void CreateImage()
{
CombineInstance[] combineInstances = new CombineInstance[skinRenderers.Length + filtersCount];
int index = 0;
for (int i = 0; i < skinRenderers.Length; i++)
{
var render = skinRenderers[i];
var mesh = new Mesh();
render.BakeMesh(mesh);
combineInstances[index] = new CombineInstance
{
mesh = mesh,
transform = render.gameObject.transform.localToWorldMatrix,
subMeshIndex = 0
};
index++;
}
for (int i = 0; i < filtersCount; i++)
{
var render = filters[i];
var temp = (render.sharedMesh != null) ? render.sharedMesh : render.mesh;
var mesh = (Mesh)Instantiate(temp);
combineInstances[index] = new CombineInstance
{
mesh = mesh,
transform = render.gameObject.transform.localToWorldMatrix,
subMeshIndex = 0
};
index++;
}
Mesh combinedMesh = new Mesh();
combinedMesh.CombineMeshes(combineInstances, true, true);
mAfterImageList.Add(new AfterImange
{
mesh = combinedMesh,
material = new Material(EffectMaterial),
time = FadeoutTime,
duration = FadeoutTime,
});
}
void LateUpdate()
{
bool needRemove = false;
foreach (var image in mAfterImageList)
{
image.time -= Time.deltaTime;
if (image.material.HasProperty("_Color"))
{
Color color = Color.red;
color.a = Mathf.Max(0, image.time / image.duration);
image.material.SetColor("_Color", color);
}
Matrix4x4 mat = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * 2f);
//public static void DrawMesh(Mesh mesh, Matrix4x4 matrix, Material material, int layer, Camera camera, int submeshIndex, MaterialPropertyBlock properties, ShadowCastingMode castShadows);
Graphics.DrawMesh(image.mesh, Matrix4x4.identity, image.material, gameObject.layer, null, 0, null, false);
if (image.time <= 0)
{
needRemove = true;
}
}
if (needRemove)
{
mAfterImageList.RemoveAll(x => x.time <= 0);
}
}
}
Since my prefab has 0.5 times scaling while it's running, then I pass a matrix with two times scaling Matrix4x4 mat = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * 2f); into
Graphics.DrawMesh.
Then, the mesh created by Graphics.DrawMesh isn't in its original position, there is an offset between original mesh and created mesh.
And if I passed Matrix4x4.Identity into Graphics.DrawMesh, the created mesh will have 0.5 times scaling, which looks smaller than original mesh.
Why there is an offset and how could I eliminate the offset without chaning the prefab's scale?

Make 2 Method with One (same parameter)

I think this is beginner stuff, but I still need to find a way to solve this.
I want to make the bool logic reference of the bool logar. The invisiblearrow(), I applied in toggle button in world space Unity thus I want to pass the logar to logic bool.(same bool).
private void invisiblearrow(bool logar) {
if (logar == false) {
GameObject[] arrow = GameObject.FindGameObjectsWithTag("arrow");
foreach(GameObject ar in arrow) {
ar.GetComponent < Renderer > ().enabled = logar;
Debug.Log(logar);
}
}
if (logar == true) {
GameObject[] arrow = GameObject.FindGameObjectsWithTag("arrow");
foreach(GameObject ar in arrow) {
ar.GetComponent < Renderer > ().enabled = logar;
Debug.Log(logar);
}
}
}
public void arrow(float[, ] arrowdata, bool logic) {
for (int x = 0; x < arrowdata.GetLength(0); x++) {
for (int y = 0; y < arrowdata.GetLength(1); y++) {
if (grid[x, y] == 1) {
if (arrowdata[x, y] == 5) {
GameObject referenceArrow = Instantiate(Resources.Load("down")) as GameObject;
float posY = shipvalue.transform.position.y - 9f;
referenceArrow.transform.position = new Vector3(shipvalue.transform.position.x, posY);
referenceArrow.GetComponent < Renderer > ().enabled = logic;
}
if (arrowdata[x, y] == 4) {
GameObject referenceArrow = Instantiate(Resources.Load("top left")) as GameObject;
float posY = shipvalue.transform.position.y - 9f;
referenceArrow.transform.position = new Vector3(shipvalue.transform.position.x, posY);
referenceArrow.GetComponent < Renderer > ().enabled = logic;
}
if (arrowdata[x, y] == 3) {
GameObject referenceArrow = Instantiate(Resources.Load("top right")) as GameObject;
float posY = shipvalue.transform.position.y - 9f;
referenceArrow.transform.position = new Vector3(shipvalue.transform.position.x, posY);
referenceArrow.GetComponent < Renderer > ().enabled = logic;
}
}
}
}
}
You can't because both bools are local bool (at the level of the function only), but you can:
Declare a private bool outside the two function (global), and at the end of invisiblearrow(bool logar) function, assign logar bool value to the new private bool (the new bool = logar), then you can access the new private bool in arrow(float[,] arrowdata, bool logic) function.

Collider triggers firing on launch

I have a "zone", with four borders; north, east, south and west. On these borders, I have 2d colliders, like this :
So, on a zone, I would have four instances of this, for each border. In the script for GridBorderController, I have this :
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == Const.TAG_PLAYER)
{
print("enter " + gridBorderSide.ToString());
/*var pos = new Vector3(20, 20, 0);
var zoneInstance = Instantiate(this, pos, Quaternion.identity, this.transform);
var tileMaker = zoneInstance.transform.GetChild(0);
var terrainDrawer = tileMaker.GetComponent<TerrainDrawer>();
print(terrainDrawer.sprites.Length);*/
}
}
When I launch the game, I create an instance of this zone, and this is what I get in my console :
This is how I start the controller :
void Start()
{
boxCollider2D = GetComponent<BoxCollider2D>();
terrainDrawer = GetComponentInParent<TerrainDrawer>();
collider = GetComponent<Collider2D>();
collider.enabled = false;
var gridRadius = terrainDrawer.gridRadius;
float borderOffset = borderWidth / 2;
switch (gridBorderSide)
{
case GridBorderSide.North:
case GridBorderSide.South:
{
boxCollider2D.size = new Vector2(gridRadius/2 , borderWidth);
if(gridBorderSide == GridBorderSide.North)
{
boxCollider2D.transform.position += new Vector3(0, (gridRadius / 4) - (borderOffset));
}
else
{
boxCollider2D.transform.position -= new Vector3(0, (gridRadius / 4) - (borderOffset));
}
break;
}
case GridBorderSide.East:
case GridBorderSide.West:
{
boxCollider2D.size = new Vector2(borderWidth, gridRadius / 2);
if (gridBorderSide == GridBorderSide.East)
{
boxCollider2D.transform.position += new Vector3((gridRadius / 4) - (borderOffset), 0 );
}
else
{
boxCollider2D.transform.position -= new Vector3((gridRadius / 4) - (borderOffset), 0);
}
break;
}
}
collider.enabled = true;
}
When I walk over the collider with my player, it does fire as well, so I know that part works, but can anyone explain the me why the triggers fire immediately on launch?

Unity3D : How to hide touchscreen keyboard when i select inputfile and inputfield still focus

I've had this problem for a long time. I want to hide touchscreen keyboard when I select inputfile and inputfield still focus. I don't need touchscreen keyboard but I need carretpostion and focus on inputfield(application like calculator).
Thank you everyone for the answer. I solved the problem by custom inputfield. I disable touchscreen keyboard and get carretpostion by OnPointerUp .
code :
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class InputFieldWithOutKeyboard : InputField
{
protected override void Start()
{
keyboardType = (TouchScreenKeyboardType)(-1);
}
public override void OnPointerDown(UnityEngine.EventSystems.PointerEventData eventData)
{
base.OnPointerDown(eventData);
}
public override void OnPointerUp(PointerEventData eventData)
{
Vector2 mPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(textComponent.rectTransform, eventData.position, eventData.pressEventCamera, out mPos);
Vector2 cPos = GetLocalCaretPosition();
int pos = GetCharacterIndexFromPosition(mPos);
Debug.Log("pos = " + pos);
GameObject.FindWithTag("canvas").GetComponent<Calculator>().carretPostion = pos;
GameObject.FindWithTag("canvas").GetComponent<Calculator>().carretVector = mPos;
base.OnPointerUp(eventData);
}
public Vector2 GetLocalCaretPosition()
{
// if (isFocused)
// {
TextGenerator gen = m_TextComponent.cachedTextGenerator;
UICharInfo charInfo = gen.characters[caretPosition];
float x = (charInfo.cursorPos.x + charInfo.charWidth) / m_TextComponent.pixelsPerUnit;
float y = (charInfo.cursorPos.y) / m_TextComponent.pixelsPerUnit;
Debug.Log("x=" + x + "y=" + y);
return new Vector2(x, y);
// }
// else
// return new Vector2(0f, 0f);
}
private int GetCharacterIndexFromPosition(Vector2 pos)
{
TextGenerator gen = m_TextComponent.cachedTextGenerator;
if (gen.lineCount == 0)
return 0;
int line = GetUnclampedCharacterLineFromPosition(pos, gen);
if (line < 0)
return 0;
if (line >= gen.lineCount)
return gen.characterCountVisible;
int startCharIndex = gen.lines[line].startCharIdx;
int endCharIndex = GetLineEndPosition(gen, line);
for (int i = startCharIndex; i < endCharIndex; i++)
{
if (i >= gen.characterCountVisible)
break;
UICharInfo charInfo = gen.characters[i];
Vector2 charPos = charInfo.cursorPos / m_TextComponent.pixelsPerUnit;
float distToCharStart = pos.x - charPos.x;
float distToCharEnd = charPos.x + (charInfo.charWidth / m_TextComponent.pixelsPerUnit) - pos.x;
if (distToCharStart < distToCharEnd)
return i;
}
return endCharIndex;
}
private int GetUnclampedCharacterLineFromPosition(Vector2 pos, TextGenerator generator)
{
// transform y to local scale
float y = pos.y * m_TextComponent.pixelsPerUnit;
float lastBottomY = 0.0f;
for (int i = 0; i < generator.lineCount; ++i)
{
float topY = generator.lines[i].topY;
float bottomY = topY - generator.lines[i].height;
// pos is somewhere in the leading above this line
if (y > topY)
{
// determine which line we're closer to
float leading = topY - lastBottomY;
if (y > topY - 0.5f * leading)
return i - 1;
else
return i;
}
if (y > bottomY)
return i;
lastBottomY = bottomY;
}
// Position is after last line.
return generator.lineCount;
}
private static int GetLineEndPosition(TextGenerator gen, int line)
{
line = Mathf.Max(line, 0);
if (line + 1 < gen.lines.Count)
return gen.lines[line + 1].startCharIdx - 1;
return gen.characterCountVisible;
}
}
You can use something like this
TouchScreenKeyboard keyboard;
void Update()
{
if (keyboard != null)
{
if (Input.deviceOrientation == DeviceOrientation.FaceDown)
keyboard.active = false;
if (Input.deviceOrientation == DeviceOrientation.FaceUp)
keyboard.active = true;
}
}
it will retrieve the TouchScreenKeyboard and after that, you can active or deactive it as you want.

Unity AI need to move a GameObject towards another one by a given distance

I'm currently trying to develop an AI for my game that needs to move every minion towards the enemy minions by a specific distance, what I'm currently doing is calculating the distance between all the enemy minions, after that I'll calculate the angle between the current minion and the closest one, and after that I'll apply the formula:
x = minion.x + cos(angle) * distance;
z = minion.z + sin(angle) * distance;
The problem is that the movement seems random, it doesn't always move towards the enemy but instead, it moves randomly
I'll provide the code below
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyAI : MonoBehaviour {
private float tolerance = 1.2f;
public NavMeshSurface navMesh;
private List<GameObject> board;
private List<Vector3> minionDesiredLocations;
private int currentMinionIndex = 0;
private enum State {
Draw,
Place,
GetBoard,
Move,
MinionMoving
}
private State state = State.Draw;
public GameObject PlaceCard(List<GameObject> hand)
{
//Generate a random integer to see what card to play
int randomIndex = (int) UnityEngine.Random.Range(0, hand.Count - 1);
Debug.Log("AI Generated Index: " + randomIndex);
return hand[randomIndex];
}
private bool MoveMinion(GameObject minion, List<GameObject> enemyMinions)
{
NavMeshAgent minionAgent = minion.GetComponent<NavMeshAgent>();
Card minionCard = minion.transform.Find("Card").GetComponent<Card>();
Vector3 maPosition = minion.transform.position;
//Finding the closest position of the enemy minion
float minDistance = 100.0f;
Vector3 closestMinionPosition = Vector3.negativeInfinity;
foreach (GameObject enemyMinion in enemyMinions)
{
//Calculating distance beetween the enemy AI minion and the enemy
float distance = Vector3.Distance(minion.transform.position, enemyMinion.transform.position);
if (distance <= minDistance)
{
minDistance = distance;
//Attacking the minion is close to the one
if (minDistance <= minionCard.cardRange)
{
float xRange = UnityEngine.Random.Range(-tolerance, tolerance);
float yRange = UnityEngine.Random.Range(-tolerance, tolerance);
closestMinionPosition = enemyMinion.transform.position + new Vector3(xRange, 0, yRange);
minionDesiredLocations[currentMinionIndex] = closestMinionPosition;
minionAgent.SetDestination(closestMinionPosition);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 1.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.SetDestination(hit.position);
return true;
}
}
else
{
//Calculating angle beetween the minion and the target
float angle = GetAngle(minion.transform.position, enemyMinion.transform.position);
float randomDistance = UnityEngine.Random.Range((float)minionCard.cardRange / 2, (float)minionCard.cardRange * 2);
randomDistance = 1.0f;
float x = minion.transform.position.x + (float)Math.Cos(angle) * randomDistance;
float z = minion.transform.position.z + (float)Math.Sin(angle) * randomDistance;
closestMinionPosition = new Vector3(x, 0, z);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 3.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.SetDestination(hit.position);
return true;
}
}
}
}
return false;
}
public bool PerformTurn(GameController gameController)
{
switch (state)
{
case State.Draw:
currentMinionIndex = 0;
gameController.drawCard(1);
state = State.Place;
break;
case State.Place:
//Getting the hand
List<GameObject> hand = gameController.GetHand(1);
//Generate a random integer to see what card to play
int randomIndex = (int)UnityEngine.Random.Range(0, hand.Count - 1);
gameController.PlaceMinion(randomIndex);
state = State.GetBoard;
break;
case State.GetBoard:
board = gameController.GetBoard(1);
minionDesiredLocations = GenerateActualLocations(board);
currentMinionIndex = 0;
state = State.Move;
break;
case State.Move:
//If we have moved all minions
if (currentMinionIndex >= board.Count)
{
Debug.Log("[IA] Passing turn");
state = State.Draw;
gameController.NextPlayer();
return true;
}
else if(MoveMinion(board[currentMinionIndex], gameController.GetBoard(0)))
{
gameController.SetCameraTo(board[currentMinionIndex].transform.position);
MoveMinion(board[currentMinionIndex], gameController.GetBoard(0));
state = State.MinionMoving;
}
break;
case State.MinionMoving:
Vector3 actualMinionPosition = board[currentMinionIndex].transform.position;
Vector3 desiredMinionLocation = minionDesiredLocations[currentMinionIndex];
actualMinionPosition = new Vector3(actualMinionPosition.x, 0, actualMinionPosition.z);
desiredMinionLocation = new Vector3(desiredMinionLocation.x, 0, desiredMinionLocation.z);
if (actualMinionPosition == desiredMinionLocation)
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
//Debug lines
if (Input.GetKey(KeyCode.P))
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
break;
}
//Continue turn proccessing
return false;
}
private List<Vector3> GenerateActualLocations(List<GameObject> board)
{
List<Vector3> l = new List<Vector3>();
foreach (GameObject minion in board)
{
l.Add(minion.transform.position);
}
return l;
}
private float GetAngle(Vector3 minion, Vector3 target)
{
return Vector3.Angle(minion, target);
}
}
Thanks for the help, I've finally found a solution.
What I've done was calling
agent.SetDestination(enemyMinion.transform.position)
After that I've stored the starting position of the agent, and inside of the logic loop, check the distance between the starting position and the actual position, whenever the distance is greater than the distance that the minion can walk, I'll simply stop the NavMeshAgent
Here's the updated code in case someone needs it
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyAI : MonoBehaviour {
private float tolerance = 1.2f;
public NavMeshSurface navMesh;
private List<GameObject> board;
private List<Vector3> minionDesiredLocations;
private Vector3 startMinionLocation;
private int currentMinionIndex = 0;
private enum State {
Draw,
Place,
GetBoard,
Move,
MinionMoving
}
private State state = State.Draw;
public GameObject PlaceCard(List<GameObject> hand)
{
//Generate a random integer to see what card to play
int randomIndex = (int) UnityEngine.Random.Range(0, hand.Count - 1);
Debug.Log("AI Generated Index: " + randomIndex);
return hand[randomIndex];
}
private bool MoveMinion(GameObject minion, List<GameObject> enemyMinions)
{
NavMeshAgent minionAgent = minion.GetComponent<NavMeshAgent>();
Card minionCard = minion.transform.Find("Card").GetComponent<Card>();
Vector3 maPosition = minion.transform.position;
//Finding the closest position of the enemy minion
float minDistance = 100.0f;
Vector3 closestMinionPosition = Vector3.negativeInfinity;
foreach (GameObject enemyMinion in enemyMinions)
{
//Calculating distance beetween the enemy AI minion and the enemy
float distance = Vector3.Distance(minion.transform.position, enemyMinion.transform.position);
if (distance <= minDistance)
{
minDistance = distance;
//Attacking the minion is close to the one
float xRange = UnityEngine.Random.Range(-tolerance, tolerance);
float yRange = UnityEngine.Random.Range(-tolerance, tolerance);
closestMinionPosition = enemyMinion.transform.position + new Vector3(xRange, 0, yRange);
minionDesiredLocations[currentMinionIndex] = closestMinionPosition;
minionAgent.SetDestination(closestMinionPosition);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 1.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.isStopped = false;
minionAgent.SetDestination(hit.position);
startMinionLocation = minion.transform.position;
return true;
}
}
}
return false;
}
public bool PerformTurn(GameController gameController)
{
switch (state)
{
case State.Draw:
currentMinionIndex = 0;
gameController.drawCard(1);
state = State.Place;
break;
case State.Place:
//Getting the hand
List<GameObject> hand = gameController.GetHand(1);
//Generate a random integer to see what card to play
int randomIndex = (int)UnityEngine.Random.Range(0, hand.Count - 1);
gameController.PlaceMinion(randomIndex);
state = State.GetBoard;
break;
case State.GetBoard:
board = gameController.GetBoard(1);
minionDesiredLocations = GenerateActualLocations(board);
currentMinionIndex = 0;
state = State.Move;
break;
case State.Move:
//If we have moved all minions
if (currentMinionIndex >= board.Count)
{
Debug.Log("[IA] Passing turn");
state = State.Draw;
gameController.NextPlayer();
return true;
}
else if(MoveMinion(board[currentMinionIndex], gameController.GetBoard(0)))
{
gameController.SetCameraTo(board[currentMinionIndex].transform.position);
MoveMinion(board[currentMinionIndex], gameController.GetBoard(0));
state = State.MinionMoving;
}
break;
case State.MinionMoving:
Vector3 actualMinionPosition = board[currentMinionIndex].transform.position;
float distance = Vector3.Distance(startMinionLocation, actualMinionPosition);
Card card = board[currentMinionIndex].transform.Find("Card").GetComponent<Card>();
NavMeshAgent agent = board[currentMinionIndex].GetComponent<NavMeshAgent>();
if (distance >= card.cardRange)
{
agent.isStopped = true;
currentMinionIndex++;
state = State.Move;
}
//Debug lines
if (Input.GetKey(KeyCode.P))
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
break;
}
//Continue turn proccessing
return false;
}
private List<Vector3> GenerateActualLocations(List<GameObject> board)
{
List<Vector3> l = new List<Vector3>();
foreach (GameObject minion in board)
{
l.Add(minion.transform.position);
}
return l;
}
private float GetAngle(Vector3 minion, Vector3 target)
{
return Vector3.Angle(minion, target);
}
}