I'm trying to use a raycast in unity that only reflect off of an objects i define but it didn't work with me any help please?
my game is laser reflection so it's not like a shooting game i need the laser to be visible the whole time and i only Need the laser to be reflected off of the mirrors and not the walls, not the floor nor the other objects in the room.
i tried this code.
public class RaycastReflection : MonoBehaviour
{
public int gunDamage = 1;
public float hitForce = 1f;
private Transform goTransform;
private LineRenderer lineRenderer;
private Ray ray;
private RaycastHit hit;
private Vector3 inDirection;
public int nReflections = 2;
private int nPoints;
void Awake()
{
}
void Update()
{
nReflections = Mathf.Clamp(nReflections, 1, nReflections);
ray = new Ray(goTransform.position, goTransform.forward);
nPoints = nReflections;
lineRenderer.SetVertexCount(nPoints);
lineRenderer.SetPosition(0, goTransform.position);
for (int i = 0; i <= nReflections; i++)
{
//If the ray hasn't reflected yet
if (i == 0)
{
//cast the ray 100 units at the specified direction
if (Physics.Raycast(ray.origin, ray.direction, out hit, 100))
{
inDirection = Vector3.Reflect(ray.direction, hit.normal);
ray = new Ray(hit.point, inDirection);
if (nReflections == 1)
{
lineRenderer.SetVertexCount(++nPoints);
}
lineRenderer.SetPosition(i + 1, hit.point);
}
}
else
{
if (Physics.Raycast(ray.origin, ray.direction, out hit, 100))
{
Target health = hit.collider.GetComponent<Target>()
if (health != null)
health.Damage(gunDamage);
if (hit.rigidbody != null)
hit.rigidbody.AddForce(-hit.normal * hitForce);
inDirection = Vector3.Reflect(inDirection, hit.normal);
ray = new Ray(hit.point, inDirection);
lineRenderer.SetVertexCount(++nPoints);
lineRenderer.SetPosition(i + 1, hit.point);
}
}
}
}
}
Related
So I want to make a 2.5d grappling rope that lets the player swing around objects for quicker turning, but the code that I wrote doesn't work. The player just stops all velocity after a short amount of time.
public Transform player;
private float tikTok;
public LayerMask layerMask;
Vector3 tetherPoint;
Transform tetherObject;
Vector3 currentTether;
float tetherLength;
bool isTethered;
Vector3 previousPlayerPosition;
if (Input.GetKey(KeyCode.Space) && Time.time >= tikTok && !isTethered) {
// this part works fine and dandy
Ray ray = new Ray(player.position, player.forward);
if (Physics.Raycast(ray, out RaycastHit hit, float.MaxValue, layerMask)) {
tetherPoint = hit.point;
tetherObject = hit.transform;
currentTether = tetherObject.position;
tetherLength = Vector3.Distance(player.position, tetherPoint);
isTethered = true;
}
} else if (isTethered && Input.GetKey(KeyCode.Space)) {
// this part does not
if (Vector3.Distance(player.position, tetherPoint) > tetherLength) {
player.position -= (Vector3.Distance(player.position, tetherPoint) - tetherLength) * (player.position - tetherPoint).normalized;
print((player.position - previousPlayerPosition).normalized);
player.gameObject.GetComponent<Rigidbody>().velocity = player.gameObject.GetComponent<Rigidbody>().velocity.magnitude * (player.position - previousPlayerPosition).normalized;
}
} else if (isTethered && !Input.GetKey(KeyCode.Space)) {
isTethered = false;
tetherPoint = Vector3.zero;
tetherObject = null;
currentTether = Vector3.zero;
tetherLength = 0;
}
if (tetherObject != null) {
if (currentTether != tetherObject.position) {
tetherPoint += currentTether - tetherObject.position;
currentTether = tetherObject.position;
}
}
previousPlayerPosition = player.position;```
I'm currently working on a tactical RPG and I have the following issue:
When the player is destroyed, he is spawned at a specific position in the grid. However, after being spawned he doesn't move.
I'm using this script to destroy the player and spawn him. It's attached to each player in the game:
using System.Collections.Generic;
using UnityEngine;
public class Jogador : MonoBehaviour
{
[SerializeField] private Mapa mapa;
public Vector2Int GridPosition;
public bool isPlayer = false;
public float Health = 50f;
public GameObject SpawnPoint;
private void Awake()
{
if (!mapa) mapa = FindObjectOfType<Mapa>();
}
// Start is called before the first frame update
void Start()
{
foreach (var tile in mapa.GridMatriz)
{
//tile.jogador = this;
}
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit) && hit.transform == this.transform)
{
mapa.GetComponent<Movimentação>().TurnEnd();
isPlayer = true;
mapa.GetComponent<Movimentação>().TurnStart();
Debug.Log("clicked");
}
}
CheckHealth();
}
public void CheckHealth()// Function to check the player's health
{
if (Health <= 0)
{
Destroy(gameObject);
Instantiate(this, Spawnador.transform.position, Quaternion.identity);
}
}
}
This is the movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Movimentação : MonoBehaviour
{
//player variables
public GameObject player;
public GameObject[] Personagens;
//moving variables
Vector3 targetPosition;
float posY = 1;
public float velocity = 0.2f;
public float movMax = 3;
public bool ismoving = false;
public bool moveEnabled;
public int aux;
//bullet variables
public GameObject projetil;
private GameObject SpawBala;
public float ProjetilVeloc = 500f;
private void Start()
{
//sets the first unit as the active unit at the start of the game
Personagens[0].GetComponent<Jogador>().isPlayer = true;
TurnStart();
}
// Update is called once per frame
void Update()
{
//left mouse button to start movement
if (Input.GetMouseButtonDown(0))
{
//raycast checks and returns an object, if it's a tile, the unit moves
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
ismoving = true;
if (Physics.Raycast(ray, out hit))
{
if (hit.transform.tag == "Tile")
{
//checks if the tile is available based on the max movement of the unit
Tile tileAux = hit.transform.gameObject.GetComponent<Tile>();
Jogador scriptJog = player.GetComponent<Jogador>();
if ((tileAux.TilePostion.x - scriptJog.GridPosition.x) + (tileAux.TilePostion.y - scriptJog.GridPosition.y) >= -movMax && (tileAux.TilePostion.x - scriptJog.GridPosition.x) + (tileAux.TilePostion.y - scriptJog.GridPosition.y) <= movMax)
{
if ((tileAux.TilePostion.x - scriptJog.GridPosition.x) - (tileAux.TilePostion.y - scriptJog.GridPosition.y) >= -movMax && (tileAux.TilePostion.x - scriptJog.GridPosition.x) - (tileAux.TilePostion.y - scriptJog.GridPosition.y) <= movMax)
{
targetPosition = (hit.transform.position);
targetPosition.y = posY;
moveEnabled = true;
}
}
}
}
}
//right click to shoot
if (Input.GetMouseButtonDown(1))
{
//raycast checks and returns an object, if it's a tile, the unit shoots
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
//checks if the tile is available based on the line and column of the unit
Tile tileAux = hit.transform.gameObject.GetComponent<Tile>();
Jogador scriptJog = player.GetComponent<Jogador>();
if (tileAux.TilePostion.x == scriptJog.GridPosition.x || tileAux.TilePostion.y == scriptJog.GridPosition.y)
{
if (tileAux.TilePostion.x > scriptJog.GridPosition.x)
tileAux.TilePostion.x = 5;
else
tileAux.TilePostion.x = 0;
if (tileAux.TilePostion.y > scriptJog.GridPosition.y)
tileAux.TilePostion.y = 5;
else
tileAux.TilePostion.y = 0;
Debug.Log(tileAux.TilePostion.x);
Debug.Log(tileAux.TilePostion.y);
//instantiates the bullet
GameObject tiro = Instantiate(projetil, SpawBala.transform.position, SpawBala.transform.rotation);
Rigidbody BalaRigid = tiro.GetComponent<Rigidbody>();
if (SpawBala.tag == "Bala1")
{
BalaRigid.AddForce(Vector3.forward * ProjetilVeloc);
}
if (SpawBala.tag == "Bala2")
{
BalaRigid.AddForce(Vector3.back * ProjetilVeloc);
}
}
}
}
//player moves until reaches the position
if (player.transform.position != targetPosition)
{
player.transform.position = Vector3.MoveTowards(player.transform.position, targetPosition, velocity);
if (player.transform.position == targetPosition)
ismoving = false;
}
//if player reaches position, it's deselected
if (moveEnabled && !ismoving)
{
player.GetComponent<Jogador>().isPlayer = false;
moveEnabled = false;
}
}
public void TurnStart()
{
//makes the selected unit the active unit
for (int i = 0; i < Personagens.Length; i++)
{
if (Personagens[i].GetComponent<Jogador>().isPlayer == true)
{
player = Personagens[i];
posY = player.transform.position.y;
targetPosition = player.transform.position;
SpawBala = player.transform.GetChild(0).gameObject;
}
}
}
public void TurnEnd()
{
//desactivates all units
for (int i = 0; i < Personagens.Length; i++)
{
Personagens[i].GetComponent<Jogador>().isPlayer = false;
}
}
}
I really don't know what's going on guys.
I decided to develop a game of gomoku, which the principle is very simple : you have to place circle or cross in a map of tile and the goal is to align 5 items. For that i choose to use unity in 2d and i use prefab with tile image to create my map. The problem i encountered is that, in my script GameManager, when i raycast my mouse click position, the click position is not the same as my tile of my board which i generated so i can't place item on my map.
BoardGenerator.cs
public float startX;
public float startY;
public Transform tiles;
public int BOARD_SIZE = 19;
void Start()
{
CreateBoard();
}
void Update()
{
}
void CreateBoard()
{
float tileX = tiles.GetComponent<SpriteRenderer>().bounds.size.x;
float tileY = tiles.GetComponent<SpriteRenderer>().bounds.size.y;
float yCor = Camera.main.ScreenToWorldPoint(new Vector3(0, startY, 0f)).y;
int count = 0;
for (int i = 0; i < BOARD_SIZE; i++)
{
float xCor = Camera.main.ScreenToWorldPoint(new Vector3(startX, 0, 0f)).x;
for (int j = 0; j < BOARD_SIZE; j++)
{
Vector3 tilesPos = new Vector3(xCor, yCor, 0f);
Transform tile = Instantiate(tiles, tilesPos, Quaternion.identity);
tile.gameObject.name = "Tile" + count;
count++;
xCor += tileX;
}
yCor -= tileY;
}
}
GameManager.cs
public int firstPlayer;
private PlayerTurn playerTurn;
public Sprite xSprite;
public Sprite oSprite;
public enum PlayerTurn
{
PLAYER1,
PLAYER2,
BOT
}
void Start()
{
if (firstPlayer == 1)
playerTurn = PlayerTurn.PLAYER1;
else
playerTurn = PlayerTurn.PLAYER2;
}
void Update()
{
Play();
}
void Play()
{
if (Input.GetMouseButtonDown(0))
{
float xCor = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
float yCor = Camera.main.ScreenToWorldPoint(Input.mousePosition).y;
Vector2 origin = new Vector2(xCor, yCor);
RaycastHit2D hit = Physics2D.Raycast(origin, Vector2.zero, 0);
Debug.Log("mouse = " + origin);
Debug.Log("first tile = " + (Vector2)GameObject.Find("Tile0").transform.position);
if (hit.collider != null && hit.transform.gameObject.tag.Equals("Tile"))
{
Debug.Log("hit");
if (this.playerTurn == PlayerTurn.PLAYER1)
{
hit.transform.gameObject.GetComponent<SpriteRenderer>().sprite = xSprite;
hit.transform.tag = "crossTile";
playerTurn = PlayerTurn.PLAYER2;
}
else if (this.playerTurn == PlayerTurn.PLAYER2)
{
hit.transform.gameObject.GetComponent<SpriteRenderer>().sprite = oSprite;
hit.transform.tag = "roundTile";
playerTurn = PlayerTurn.PLAYER1;
}
}
}
}
You can take advantage of a different overload for the Raycast in order to return the object hit, like so:
Ray ray = camera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics2D.Raycast(ray, out hit, rayDist)){
GameObject obj = hit.transform.gameObject;
// Do something with obj
}
In the above example, 'obj' will be the GameObject that was hit by the Raycast, so you can get its position by then referencing:
obj.transform.position
The reason for:
GameObject obj = hit.transform.gameObject;
is that 'hit.gameObject' will return a parent object with a Rigidbody, if there is one. This can lead to a lot of confusion down the track when working with more complex object structures, so it is good practise to grab 'hit.transform.gameObject', which will always return the GameObject that the collider the Raycast hit is attached to.
I am trying to move the y position of a UI element in it's local space by clicking and dragging with the SteamVR controller and a raycast. I am getting what appear to me to be unpredictable results.
I am trying to get the position of the raycast at the start of the drag and move it the distance between where it is and where it was started while dragging.
Here is my code:
if (hit.transform.name == "Content" && scrollSet == false)
{
content = hit.transform;
scrollSet = true;
scrollPos = hit.transform.position ;
}
if (scrollSet == true)
{
if (rController.triggerPressed)
{
y = hit.transform.position.y - scrollPos.y;
content.transform.localPosition = new Vector3(content.transform.localPosition.x, content.localPosition.y + y, content.transform.localPosition.z);
}
else
{
scrollSet = false;
}
}
you can convert the .MovePosition to .MoveTowards. But it still jumped around. It turns out that the code was only executing during the frame in which you right-clicked, so move it out of the if statement.
Here's the entire script placed into the main camera. You always need to have a target selected, so to prevent errors you need to put a gameObject with a rigidbody into "bTarg".
public class ClickTarget : MonoBehaviour {
private GameObject target; private Vector3 destination; private float distance; private Vector3 tTrans;
public GUIText targetDisplay; public float speed; public GameObject bTarg;
void Start () { targetDisplay.text = ""; distance = 0.0f; target = bTarg; }
void Update () { if(Input.GetButtonDown("Fire1")){ Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if(Physics.Raycast(ray, out hit)){ if(hit.collider != null){ if(hit.collider.tag == "Unit"){ target = hit.collider.gameObject; targetDisplay.text = "Unit: " + hit.collider.gameObject.name; destination = target.transform.position; target.rigidbody.freezeRotation = false; } if(hit.collider.tag == "Building"){ target = hit.collider.gameObject; targetDisplay.text = "Building: " + hit.collider.gameObject.name; } } } } }
void FixedUpdate(){ if (Input.GetButtonDown ("Fire2") && target.tag == "Unit" && GUIUtility.hotControl == 0) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if(Physics.Raycast(ray,out hit)){ destination = hit.point; } }
tTrans = target.transform.position;
distance = Vector3.Distance (tTrans, destination);
if(target.tag == "Unit"){
if (distance > .2f) {
target.transform.LookAt (destination);
target.transform.position = Vector3.MoveTowards (target.transform.position, destination, speed);
target.rigidbody.freezeRotation = true;
}
}
} }
I am moving an object that consists of two cubes: left and right. These cubes are randomly generated on the y-axis upwards.
I am able to move them left and right with no problem, however, when I move one of the cubes left or right they all move.
How am I able to only move one of the cubes when touched only left or right rather than all of them? Here is my code below:
Generate cubes code:
public Transform block;
public Transform player;
private float objectSpawnedTo = 5.0f;
public static float distanceBetweenObjects = 5.0f;
private float nextCheck = 0.0f;
private ArrayList objects = new ArrayList();
void Start () {
maintenance(0.0f);
}
void Update () {
float playerX = player.position.y;
if(playerX > nextCheck)
{
maintenance(playerX);
}
}
private void maintenance(float playerX)
{
nextCheck = playerX + 30;
for (int i = objects.Count-1; i >= 0; i--)
{
Transform blck = (Transform)objects[i];
if(blck.position.y < (transform.position.y - 30))
{
Destroy(blck.gameObject);
objects.RemoveAt(i);
}
}
spawnObjects(5);
}
private void spawnObjects(int howMany)
{
float spawnX = objectSpawnedTo;
for(int i = 0; i<howMany; i++)
{
Vector3 pos = new Vector3(-3.5f,spawnX, 0);
//float firstRandom = Random.Range(-6.0f, 1.0f);
Transform blck = (Transform)Instantiate(block, pos, Quaternion.identity);
//blck.localScale+=new Vector3(firstRandom*2,0,0);
objects.Add(blck);
//pos = new Vector3(0,spawnX, 0);
//blck = (Transform)Instantiate(block, pos, Quaternion.identity);
//blck.localScale +=new Vector3((8.6f-firstRandom)*2,0,0);
//objects.Add(blck);
spawnX = spawnX + distanceBetweenObjects;
}
objectSpawnedTo = spawnX;
}
}
Cube-control code:
public float speed = 5;
// Use this for initialization
void Start () {
}
void Update() {
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) {
// Get movement of the finger since last frame
Vector3 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across XY plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
Vector3 boundaryVector = transform.position;
boundaryVector.x = Mathf.Clamp (boundaryVector.x, -5.5f, -2.8f);
transform.position = boundaryVector;
}
}
}
The problem is your cube-control code has no condition in it about which cube is selected : you simply wait for Input.touchCount to be > 0 and then move the cube. So all the cube having this script will move.
I think what you need to do is a raycast to check which cube has been "touched" and then only move it if raycast is successful :
[SerializeField]
private float speed = 0.5f;
private int MAX_TOUCH_COUNT = 5;
private bool[] touched;
protected void Start()
{
touched = new bool[MAX_TOUCH_COUNT];
}
void Update()
{
if (Input.touchCount > 0)
{
for(int i = 0; i < (Input.touchCount <= MAX_TOUCH_COUNT ? Input.touchCount : MAX_TOUCH_COUNT); i++)
{
if(touched[i] && Input.GetTouch(i).phase == TouchPhase.Ended)
{
touched[i] = false;
}
else if (!touched[i] && Input.GetTouch(i).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(i).position);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
if (hitInfo.transform.GetComponentInChildren<*YOUR_CUBE_CONTROL_CLASS_NAME*>() == this)
{
touched[i] = true;
}
}
}
else if (touched[i] && Input.GetTouch(i).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector3 touchDeltaPosition = Input.GetTouch(i).deltaPosition;
// Move object across XY plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
Vector3 boundaryVector = transform.position;
boundaryVector.x = Mathf.Clamp (boundaryVector.x, -5.5f, -2.8f);
transform.position = boundaryVector;
}
}
else
{
touched = false;
}
}
}
Hope this help,