I'm working on a script for my camera to make objects between itself and the character transparent.
I managed to make it work with RayCast however I don't know how to restablish objects alpha value after they escape the ray.
This is my current code:
private void XRay() {
float characterDistance = Vector3.Distance(transform.position, GameObject.Find("Character").transform.position);
Vector3 fwd = transform.TransformDirection(Vector3.forward);
RaycastHit hit;
if (Physics.Raycast(transform.position, fwd, out hit, characterDistance)) {
// Add transparence
Color color = hit.transform.gameObject.renderer.material.color;
color.a = 0.5f;
hit.transform.gameObject.renderer.material.SetColor("_Color", color);
}
}
This is my final code. Note it only makes transparent one object at a time, but the same implementation can easily be done with RaycastAll and using an array for oldHits.
public class Camara : MonoBehaviour {
RaycastHit oldHit;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void FixedUpdate() {
XRay ();
}
// Hacer a los objetos que interfieran con la vision transparentes
private void XRay() {
float characterDistance = Vector3.Distance(transform.position, GameObject.Find("Character").transform.position);
Vector3 fwd = transform.TransformDirection(Vector3.forward);
RaycastHit hit;
if (Physics.Raycast(transform.position, fwd, out hit, characterDistance)) {
if(oldHit.transform) {
// Add transparence
Color colorA = oldHit.transform.gameObject.renderer.material.color;
colorA.a = 1f;
oldHit.transform.gameObject.renderer.material.SetColor("_Color", colorA);
}
// Add transparence
Color colorB = hit.transform.gameObject.renderer.material.color;
colorB.a = 0.5f;
hit.transform.gameObject.renderer.material.SetColor("_Color", colorB);
// Save hit
oldHit = hit;
}
}
}
I did attach this script to my simple camera following the player. It might help you.
It can actually manage more than one obstructing the view and also you see I pass it a mask which I target with its name instead of checking for the collider name tag. Have fun.
using UnityEngine;
public class followPlayer : MonoBehaviour
{
public Transform player;
public Vector3 offset;
public Transform[] obstructions;
private int oldHitsNumber;
void Start()
{
oldHitsNumber = 0;
}
private void LateUpdate()
{
viewObstructed();
}
void Update()
{
transform.position = player.TransformPoint(offset);
transform.LookAt(player);
}
void viewObstructed()
{
float characterDistance = Vector3.Distance(transform.position, player.transform.position);
int layerNumber = LayerMask.NameToLayer("Walls");
int layerMask = 1 << layerNumber;
RaycastHit[] hits = Physics.RaycastAll(transform.position, player.position - transform.position, characterDistance, layerMask);
if (hits.Length > 0)
{ // Means that some stuff is blocking the view
int newHits = hits.Length - oldHitsNumber;
if (obstructions != null && obstructions.Length > 0 && newHits < 0)
{
// Repaint all the previous obstructions. Because some of the stuff might be not blocking anymore
for (int i = 0; i < obstructions.Length; i++)
{
obstructions[i].gameObject.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
}
}
obstructions = new Transform[hits.Length];
// Hide the current obstructions
for (int i = 0; i < hits.Length; i++)
{
Transform obstruction = hits[i].transform;
obstruction.gameObject.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly;
obstructions[i] = obstruction;
}
oldHitsNumber = hits.Length;
}
else
{ // Mean that no more stuff is blocking the view and sometimes all the stuff is not blocking as the same time
if (obstructions != null && obstructions.Length > 0)
{
for (int i = 0; i < obstructions.Length; i++)
{
obstructions[i].gameObject.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
}
oldHitsNumber = 0;
obstructions = null;
}
}
}
}
Related
2D Top Down style game. I’m trying to figure out how to hit an enemy whenever he enters the range of my attack point and get hit every, say, 3 frames if he is still within my attack point. here's my script.
public Animator animator;
public Transform AttackPoint;
public float attackRange = 0.5f;
public LayerMask enemyLayers;
public int attackDamage = 40;
public float attackRate = 1f;
float nextAttackTime = 0f;
// Update is called once per frame
void Update()
{
if(Time.time >= nextAttackTime)
{
if (Input.GetKeyDown(KeyCode.Space))
{
Attack();
nextAttackTime = Time.time + 1f / attackRate;
}
}
}
void Attack()
{
animator.SetTrigger("Attack");
Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(AttackPoint.position, attackRange, enemyLayers);
foreach(Collider2D enemy in hitEnemies)
{
enemy.GetComponent<Enemy>().TakeDamage(attackDamage);
}
}
void OnDrawGizmosSelected()
{
if (AttackPoint == null)
return;
Gizmos.DrawWireSphere(AttackPoint.position, attackRange);
}
foreach enemys and check distance with you , and attack it.
and you need a Manager to handle all enemys.
List<Transform> enemys = new List<Transform>();
public void Update()
{
for (int i = 0; i < enemys.Count; i++)
{
float distance = Vector3.Distance(enemys[i].position, transform.position);
if (distance < 10)// in range
{
//todo attack
}
}
}
What Whip should look like
I'm trying to create a whip that can extend in any direction the mouse is facing after pressing a certain button. If there are "grabbable" objects in the way such as an enemy or box, it should latch onto those objects and pull them around to collide with other objects for a certain amount of time.
I know that I need the different sprite shots of the whip extending and latching for animation, but I have no idea how to implement this in code and how to get the whip to stop short if it detects a "grabbable" object.
Attach this script to your player, this should get the job done:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Transform player = null;
public float speed = 30f;
public string grabbableTag = "grabbable";
private LineRenderer line = null;
private float timer = 0f;
private bool grabbing = false;
private bool reached = false;
private Vector2 from = Vector2.zero;
private Vector2 to = Vector2.zero;
private Vector2 target = Vector2.zero;
private Transform grabbable = null;
private void Start()
{
player = transform;
line = new GameObject("Line").AddComponent<LineRenderer>();
line.startColor = Color.red;
line.endColor = Color.red;
// Assign a material
line.gameObject.SetActive(false);
reached = false;
grabbing = false;
}
private void Update()
{
if(grabbing)
{
Grabbing();
}
else
{
if (Input.GetMouseButtonDown(0))
{
Grab();
}
}
}
private void Grab()
{
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = Vector3.Distance(player.position, Camera.main.transform.position);
to = Camera.main.ScreenToWorldPoint(mousePosition);
from = player.position;
Vector2 direction = (to - from).normalized;
float distance = Vector2.Distance(from, to);
RaycastHit2D[] hits = Physics2D.RaycastAll(from, direction, distance);
grabbable = null;
for (int i = 0; i < hits.Length; i++)
{
if (hits[i].transform.tag == grabbableTag)
{
grabbable = hits[i].transform;
break;
}
}
if (grabbable != null)
{
distance = Vector2.Distance(player.position, grabbable.position);
to = from + direction * distance;
}
grabbing = true;
reached = false;
target = from;
timer = 0;
line.gameObject.SetActive(true);
line.positionCount = 2;
line.SetPosition(0, from);
line.SetPosition(1, from);
}
private void Grabbing()
{
if (reached)
{
target = Vector2.Lerp(target, from, speed * Time.deltaTime);
if (target == from)
{
GrabDone(grabbable);
grabbing = false;
line.gameObject.SetActive(false);
}
}
else
{
target = Vector2.Lerp(target, to, speed * Time.deltaTime);
if(target == to)
{
reached = true;
}
}
line.SetPosition(1, target);
if (reached && grabbable != null)
{
grabbable.position = target;
}
}
private void GrabDone(Transform grabbed)
{
if(grabbed != null)
{
// Do somthing ...
Destroy(grabbed.gameObject);
}
}
}
I know the title might be misleading after you see what is the problem, but I really don't know how to name this issue.
The first picture shows the problem.
The white line shows the distance between the player and the gameobject called hook. The blue sprite sphere close to the hook is the SpringJoint2D.connectedBody.
They both (the white line and the blue sprite) are working with the same value: hook.transform.position.
Here is the code snippets which I believe are causing problems or at least reveal the most:
SpringJoint2D snippet:
if (Input.GetMouseButtonDown(0))
{
hook = FindClosestObject(radius, "Hook");
if(hook != null)
{
joint.enabled = true;
joint.connectedBody = hook;
joint.connectedAnchor = hook.transform.position;
Debug.Log("Click.");
Debug.Log(hook);
}
}
if (Input.GetMouseButtonUp(0))
{
joint.enabled = false;
joint.connectedBody = null;
}
Debug.DrawLine snippet:
if (hook != null)
{
joint.distance = Vector3.Distance(hook.transform.position, transform.position) / 2;
Debug.DrawLine(transform.position, hook.transform.position);
}
And here is the whole code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerScript : MonoBehaviour
{
public float radius;
private SpringJoint2D joint;
private Rigidbody2D hook = new Rigidbody2D();
// Start is called before the first frame update
void Start()
{
joint = GetComponent<SpringJoint2D>();
}
// Update is called once per frame
void Update()
{
//touch.phase == TouchPhase.Began
if (Input.GetMouseButtonDown(0))
{
hook = FindClosestObject(radius, "Hook");
if(hook != null)
{
joint.enabled = true;
joint.connectedBody = hook;
joint.connectedAnchor = hook.transform.position;
Debug.Log("Click.");
Debug.Log(hook);
}
}
if (Input.GetMouseButtonUp(0))
{
joint.enabled = false;
joint.connectedBody = null;
}
//foreach (Touch touch in Input.touches)
//{
//}
if (hook != null)
{
joint.distance = Vector3.Distance(hook.transform.position, transform.position) / 2;
Debug.DrawLine(transform.position, hook.transform.position);
}
}
private void OnDrawGizmos()
{
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(transform.position, radius);
if (hook != null)
Gizmos.DrawLine(transform.position, hook.transform.position);
}
public Rigidbody2D FindClosestObject(float radius, string tag)
{
GameObject[] gos;
gos = GameObject.FindGameObjectsWithTag(tag);
Rigidbody2D closest = null;
float distance = radius;
Vector3 position = transform.position;
foreach (GameObject go in gos)
{
Vector3 diff = go.transform.position - position;
float curDistance = diff.sqrMagnitude;
if (curDistance < distance)
{
closest = go.GetComponent<Rigidbody2D>();
distance = curDistance;
}
}
return closest;
}
}
Ah, I was just stupid.
There is no need to assign the connectedAnchor if you also asign the connectedRigidbody2D
The connectedAnchor is the offset from the connectedRigidbody2D's position...
I've written the following code making the gun move to the guy's shoulder position when he stops shooting and it does work...BUT ONLY ONCE. After that, it starts not to meet the target even though it's coordinates remain the same. I've tried it with Lerp, SmoothDamp, MoveTowards...still don't get where the problem lies.
P.S. The gun moves to the shoulder when shooting perfectly, it starts happening when the character stops shooting and tries to go back to the Idle pose.
EDIT: Turns out there's also something wrong with rotation...or maybe it's just rotation. I don't even know at this point.
THE VIDEO of what's going on: https://youtu.be/CheQiomYtm8
THE CODE:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnitControl;
public class BlastIKController : MonoBehaviour
{
public WeaponState wpState;
public GameObject weapon;
public GameObject RightShoulder;
public GameObject HumanSpine;
public GameObject WeaponSpawn;
public LayerMask lmask;
public BlastIKHandler ikHandle;
public Material targetMat;
public Material defMat;
public GameObject target;
public GameObject WeaponIdle;
public bool isShooting = false;
//public bool InIdle = true;
LineRenderer ShootLine;
public GameObject WeaponInstance;
Animator anim;
public float speedMove;
public float speedRot;
// Use this for initialization
void Awake()
{
GameObject weaponInst = Instantiate(weapon, WeaponSpawn.transform);
WeaponInstance = weaponInst;
WeaponInstance.transform.localPosition = new Vector3(0, 0, 0);
wpState = weaponInst.GetComponent<WeaponState>();
ikHandle = this.GetComponent<BlastIKHandler>();
ShootLine = this.GetComponent<LineRenderer>();
anim = this.GetComponent<Animator>();
ikHandle.RightShoulder = RightShoulder;
ikHandle.leftHandTarget = wpState.leftHandIdle.transform;
ikHandle.rightHandTarget = wpState.rightHandTarget.transform;
//Позиция оружия
wpState.shoulder.transform.position = ikHandle.WeaponIdlePos.position;
wpState.shoulder.transform.rotation = ikHandle.WeaponIdlePos.rotation;
}
// Update is called once per frame
void Update()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
#region SearchTarget
if (Physics.Raycast(ray, out hit, Mathf.Infinity, lmask))
{
if (hit.collider.gameObject.tag == "Target")
{
ShootLine.positionCount = 2;
ShootLine.SetPosition(0, HumanSpine.transform.position);
ShootLine.SetPosition(1, hit.collider.gameObject.transform.position);
if (Input.GetMouseButton(0))
{
if (target == null)
{
target = hit.collider.gameObject;
MeshRenderer ms = hit.collider.gameObject.GetComponent<MeshRenderer>();
ms.material = targetMat;
ikHandle.targetPos = hit.collider.gameObject;
}
else
{
MeshRenderer ms = target.GetComponent<MeshRenderer>();
ms.material = defMat;
target = hit.collider.gameObject;
ms = target.GetComponent<MeshRenderer>();
ms.material = targetMat;
ikHandle.targetPos = hit.collider.gameObject;
}
}
}
}
#endregion
#region Shooting
Shooting();
if (isShooting)
{
if (target != null)
{
bool isShoot = anim.GetBool("Shoot");
if (!isShoot)
{
StartCoroutine(MoveToShoot(RightShoulder.transform.position));
ikHandle.leftHandTarget = wpState.leftHandTarget.transform;
anim.SetBool("Shoot", true);
//InIdle = false;
}
}
}
else
{
// float stepMove = speedMove * Time.deltaTime;
// wpState.shoulder.transform.position = Vector3.Lerp(wpState.shoulder.transform.position, ikHandle.WeaponIdlePos.position, stepMove);
// //if (!InIdle)
// //{
// // StartCoroutine(MoveToIdle(ikHandle.WeaponIdlePos.position));
//// }
// //InIdle = true;
// //float stepMove = speedMove * Time.deltaTime;
// //while (wpState.shoulder.transform.position != ikHandle.WeaponIdlePos.position)
// //{
// // wpState.shoulder.transform.position = Vector3.Lerp(wpState.shoulder.transform.position, ikHandle.WeaponIdlePos.position, stepMove);
// //}
// ////wpState.shoulder.transform.position = ikHandle.WeaponIdlePos.position;
// ////wpState.shoulder.transform.position = Vector3.MoveTowards(wpState.shoulder.transform.position, ikHandle.WeaponIdlePos.position, stepMove);
// float stepRot = speedRot * Time.deltaTime;
// //while (wpState.shoulder.transform.rotation != ikHandle.WeaponIdlePos.rotation)
// //{
// wpState.shoulder.transform.rotation = Quaternion.Slerp(wpState.shoulder.transform.rotation, ikHandle.WeaponIdlePos.rotation, stepRot);
// //}
// ////wpState.shoulder.transform.rotation = ikHandle.WeaponIdlePos.rotation;
// ikHandle.leftHandTarget = wpState.leftHandIdle.transform;
// anim.SetBool("Shoot", false);
}
#endregion
}
void LateUpdate()
{
if (!isShooting)
{
float stepMove = speedMove * Time.deltaTime;
stepMove += Time.deltaTime / speedMove;
Vector3 velocity = Vector3.zero;
//.shoulder.transform.position = Vector3.Lerp(wpState.shoulder.transform.position, ikHandle.WeaponIdlePos.position, stepMove);
wpState.shoulder.transform.position = Vector3.MoveTowards(wpState.shoulder.transform.position, ikHandle.WeaponIdlePos.position, stepMove);
//wpState.shoulder.transform.position = Vector3.SmoothDamp(wpState.shoulder.transform.position, ikHandle.WeaponIdlePos.position, ref velocity, stepMove);
// wpState.shoulder.transform.position = Vector3.SmoothDamp()
float stepRot = speedRot * Time.deltaTime;
wpState.shoulder.transform.rotation = Quaternion.Slerp(wpState.shoulder.transform.rotation, ikHandle.WeaponIdlePos.rotation, stepRot);
ikHandle.leftHandTarget = wpState.leftHandIdle.transform;
anim.SetBool("Shoot", false);
}
}
void Shooting()
{
if (Input.GetKeyDown(KeyCode.S))
{
isShooting = !isShooting;
}
}
IEnumerator MoveToShoot(Vector3 WPposition)
{
float step = speedMove * Time.deltaTime;
while (wpState.shoulder.transform.position != WPposition)
{
wpState.shoulder.transform.position = Vector3.Lerp(wpState.shoulder.transform.position, WPposition, step);
Vector3 relativeWeaponPos = ikHandle.targetPos.transform.position - wpState.shoulder.transform.position;
Quaternion WeaponRotation = Quaternion.LookRotation(relativeWeaponPos);
wpState.shoulder.transform.rotation = Quaternion.Slerp(wpState.shoulder.transform.rotation, WeaponRotation, step);
yield return null;
}
}
IEnumerator MoveToIdle(Vector3 WPposition)
{
float stepMove = speedMove * Time.deltaTime;
float stepRot = speedRot * Time.deltaTime;
while (wpState.shoulder.transform.position != WPposition)
{
wpState.shoulder.transform.position = Vector3.Lerp(wpState.shoulder.transform.position, WPposition, stepMove);
wpState.shoulder.transform.rotation = Quaternion.Slerp(wpState.shoulder.transform.rotation, ikHandle.WeaponIdlePos.transform.rotation, stepRot);
yield return null;
}
wpState.shoulder.transform.position = Vector3.Lerp(wpState.shoulder.transform.position, ikHandle.WeaponIdlePos.position, stepMove);
}
}
So, it was the following. It turns out that the coroutines got mixed up in Update and they worked at the same time.
So...I removed all coroutines from the code and then moved and rotated using Lerp and sLerp in the update.
There's one thing though, I also had to add a check for both bositions to meet, and after that it starts shooting and only then.
P.S. I can add the code I changed later if you like.
I want to make a jostick that created (Instatiated or whatever) in touch position(Input.getTouch(i).position) and destroyed when user doesn't touch the screen anymore. This is the source code below. Please give me an idea how to do it. Thank you.
using UnityEngine;
using System.Collections;
public class joy : MonoBehaviour
{
public GameObject joystick; //Self explanitory
public GameObject bg; //Background object for the joystick boundaries
public const float deadzone = 0f; //Deadzone for the joystick
public const float radius = 2.0f; //The radius that the joystick thumb is allowed to move from its origin
public Camera cam;
protected Collider joyCol;
protected int lastfingerid = -1; //Used for latching onto the finger
public Vector2 position = Vector2.zero;
void Awake ()
{
joyCol = bg.GetComponent<Collider>();
}
public void Disable ()
{
gameObject.active = false; //Turns off the joystick when called
}
public void ResetJoystick () //Called when the joystick should be moved back to it's original position (relative to parent object)
{
lastfingerid = -1;
joystick.transform.localPosition = Vector3.zero;
}
void Update ()
{
if (Input.touchCount == 0)
{
ResetJoystick (); //I would have figured this would be obvious? :P
}
else
{
for (int i=0; i < Input.touchCount; i++)
{
Touch touch = Input.GetTouch(i);
bool latchFinger = false;
if (touch.phase == TouchPhase.Began) //When you begin the touch, the code here gets called once
{
//Vector3 touchpos = Input.GetTouch(i).position;
//touchpos.z = 0.0f;
//Vector3 createpos = cam.ScreenToWorldPoint(touchpos);
Ray ray = cam.ScreenPointToRay (touch.position); //Creates a ray at the touch spot
RaycastHit hit; //Used for determining if something was hit
//joystick = (GameObject)Instantiate(Resources.Load("Type3/joystick"),createpos, Quaternion.identity);
//bg = (GameObject)Instantiate(Resources.Load("Type3/Bg"),createpos, Quaternion.identity);
if (joyCol.Raycast(ray,out hit,Mathf.Infinity)) //The ray hit something...
{
if (hit.collider == joyCol) //Apparently, that ray hit your joystick
{
latchFinger = true; //This turns on and sets off a chain reaction
}
}
}
if (latchFinger ) //Latch finger being true turns this code on
{
if ((lastfingerid == -1 || lastfingerid != touch.fingerId))
{
lastfingerid = touch.fingerId;
}
}
if (lastfingerid == touch.fingerId) //The real meat of the code
{
Vector3 sTW = cam.ScreenToWorldPoint (new Vector3 (touch.position.x, touch.position.y, 1)); //Transforms the screen touch coordinates into world coordinates to move our joystick
joystick.transform.position = sTW; //Hurr :O
joystick.transform.localPosition = new Vector3(joystick.transform.localPosition.x,joystick.transform.localPosition.y,0);
//float xClamp = Mathf.Clamp (joystick.transform.localPosition.x, xClampMin, xClampMax); //Limit movement to the boundaries
//float yClamp = Mathf.Clamp (joystick.transform.localPosition.y, yClampMin, yClampMax);
/*float distFromCenter = Mathf.Sqrt(joystick.transform.localPosition.x*joystick.transform.localPosition.x + joystick.transform.localPosition.y*joystick.transform.transform.localPosition.y);
float actualPercent = Mathf.Clamp01(distFromCenter/radius);
float percent = Mathf.Clamp01((distFromCenter - deadzone)/(radius - deadzone));
*/
joystick.transform.localPosition = Vector3.ClampMagnitude(joystick.transform.localPosition,radius);
//joystick.transform.localPosition = new Vector3 (xClamp, yClamp, joystick.transform.localPosition.z); //Finally, the joystick moves like it should with everything in place
if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
{
ResetJoystick ();
}
}
Ray touchray = cam.ScreenPointToRay (touch.position); //Creates a ray at the touch spot
//RaycastHit hit; //Used for determining if something was hit
Debug.DrawRay (touchray.origin, touchray.direction * 100, Color.yellow); //Delete this line. It's not important.
}
}
//set our position variables x and y values to the joysticks values but clamped to a percent value instead of world coords
position.x = joystick.transform.localPosition.x/radius;
position.y = joystick.transform.localPosition.y/radius;
if(position.magnitude < deadzone)
{
position.x = 0;
position.y = 0;
}
}
}