I Have a player which gets childed to a game object when it walks up to a trigger now I want the player's parent to become null again after space is pressed because I'm trying to make a rope system, and it's required for the player to be able to de-attach from the rope
This is the script that's supposed to attach/detach the player from the rope
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AttachToRope : MonoBehaviour
{
public GameObject objectToParentTo;
public GameObject objectWithSwingScript;
// Start is called before the first frame update
private void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.tag == "Rope")
{
transform.parent = objectToParentTo.transform;
objectWithSwingScript.GetComponent<playerscript>().enabled = true;
GetComponent<PlayerController>().enabled = false;
GetComponent<CharacterController>().enabled = false;
GetComponent<Swinging>().enabled = false;
}
}
private void OnTriggerStay(Collider collider)
{
if (Input.GetButtonDown("Jump"))
{
transform.parent = null;
objectWithSwingScript.GetComponent<playerscript>().enabled = false;
GetComponent<PlayerController>().enabled = true;
GetComponent<CharacterController>().enabled = true;
GetComponent<Swinging>().enabled = true;
Debug.Log("Deattached");
}
}
}
What happens when the player enters the trigger is that the scripts that make the player move get disabled and then it gets chilled to the last section of the rope now in ontriggerstay i want it to check if space is pressed and re-enable all the scripts that are required for the player to move (which does not work) but since nothing in there works i tried to debug.log but even that does not work so if anyone knows how to fix this please help me
From the OnTriggerStay documentation: The function is on the physics timer so it won't necessarily run every frame.
Functions on the physics timer (e.g. FixedUpdate()) don't play nicely with Input.GetButtonDown because they don't run every frame. Instead, they run on a fixed timestep, 0.02 seconds by default.
The solution is to put calls to Input.GetButtonDown into Update(). For instance, in this example you could have a boolean member variable isJumpPushed and set it to true in Update() when the jump button is pushed and the player is attached, and then check that value in OnTriggerStay.
--
A note about debugging:
I tried to debug.log but even that does not work
If your Debug.Log isn't showing a log in the console, that still tells you something important. It tells you that code path isn't getting called. That's an important clue for you to figure out what's really going on. To further narrow down the problem, you could move the Debug.Log statement outside the if statement. This would show that it's Input.GetButtonDown that isn't returning true when you think it is.
Related
I am trying to learn the basics of unity collision and I want the movement of the player to stop whenever it touches an obstacle but the movement stops whenever it touches the ground. I tagged the obstacle with a tag called obstacle and left the ground untagged but whenever the player touches the ground it stops all movement. Does anyone know how to fix this? Heres my code: `using UnityEngine;
public class PlayerCollision : MonoBehaviour
{
public Movement playerMovement;
void OnCollisionEnter(Collision collisionInfo)
{
Debug.Log(collisionInfo.collider.tag == "Obstacle");{
playerMovement.enabled = false;
}
}
}
The code you've written stops the movement of the player whenever its collides with something. The code wouldn't even compile because of the "{" at the end.
void OnCollisionEnter(Collision collisionInfo)
{
// returns true or false in the console depending on whether player its colliding with the obstacle
// code won't compile because of the "{" at the end
Debug.Log(collisionInfo.collider.tag == "Obstacle");{
playerMovement.enabled = false;
}
To fix that you can use an if statement and remove the "{" at the end like shown below.
It is also recommended to use CompareTag when working with tags.
void OnCollisionEnter(Collision collisionInfo)
{
if(collisionInfo.collider.CompareTag("Obstacle"))
{
playerMovement.enabled = false;
}
}
When I retrieve an object from a list of created objects and reactivate it, it destroys itself, but only if I have force applied to start it moving. If I never apply force, everything works as intended and I can keep activating the object over and over.
I've tried putting a debug.log in the OnCollision and it isn't colliding with anything.
As said above, if I never initiate speed, the rest works fine.
When speed is applied, the first projectile works, the second destroys itself.
I've tried manually activating them instead of by code. Same result.
Exception: If I manually activate/deactivate objects myself through the inspector, they work if I only have 1 shot in the pool.
The one shot rule doesn't work if I do it through code. It breaks even if I only have one shot.
All the code worked when I wasn't using pooling.
Spawn code:
void CreateBullet(int GunID)
{
GameObject ShotFired = Guns[GunID].GetComponent<Weapon>().FireWeapon();
if (ShotFired == null)
{
ShotFired = Instantiate(Guns[GunID].GetComponent<Weapon>().Projectile,Guns[GunID].gameObject.transform);
Physics.IgnoreCollision(ShotFired.GetComponent<SphereCollider>(), Guns[GunID].GetComponentInParent<CapsuleCollider>());
Guns[GunID].GetComponent<Weapon>().AmmoPool.Add(ShotFired);
}
ShotFired.transform.position = Guns[GunID].transform.position;
ShotFired.transform.rotation = Guns[GunID].transform.rotation;
ShotFired.SetActive(true);
}
Projectile Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
public class Projectile : NetworkBehaviour
{
public float Speed;
public float LifeTime;
public float DamagePower;
public GameObject ExplosionFX;
// Start is called before the first frame update
void Start()
{
GetComponent<Rigidbody>().AddRelativeForce(Vector3.up * Speed, ForceMode.VelocityChange);
StartCoroutine(DeactivateSelf(5.0f));
}
private void OnDestroy()
{
Debug.Log("WHY!");
}
IEnumerator DeactivateSelf(float Sec)
{
yield return new WaitForSeconds(Sec);
Explode();
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.GetComponentInChildren<Vehicle>())
{
collision.gameObject.GetComponentInChildren<Vehicle>().CmdTakeDamage(DamagePower);
}
Explode();
}
void Explode()
{
GameObject ExplosionEvent = Instantiate(ExplosionFX, this.transform.position, Quaternion.identity);
NetworkServer.Spawn(ExplosionEvent);
GetComponent<Rigidbody>().AddRelativeForce(Vector3.zero);
gameObject.SetActive(false);
}
}
Any thoughts welcome. Thanks in advance!
In case anyone else stumbles across this, here's what happened and why assigning a movement speed to the object was what caused the issue.
My projectiles had a 'trailrenderer' on them.
By default 'Autodestruct' is true.
Autodestruct does not destruct the trail, but the game object when the trail disappears. So if you disable anything that had a trail, and activated it through movement, when the object stops moving (say to reposition in an object pool) it will destroy the parent object.
If the object never moves, it never generates a trail, and never needs to be destroyed.
To fix, just uncheck autodestruct.
https://docs.unity3d.com/ScriptReference/TrailRenderer-autodestruct.html
Unity 2019.3.7f1
..
The artist I'm working with has made some animations for some UI stuff using the mecanim system Animator component.
I fire the animation with
Animator.SetTrigger("ParamaterName")
The gameobjects with the animator components, which are being animated, can get disabled by some of my scripts.
This can happen while the animation is playing..
So if the animation starts playing, and lets say the animation has made a button get bigger, then the gameobject gets disabled. When the gameobject is re-enabled (the animation is no longer playing) it is still big..
Is there a way to tell the Animator to go back to normal?
I have tried stuff like this in onEnable and OnDisable in a script on the GameObject
Animator.keepAnimatorControllerStateOnDisable = false
Animator.Play("normalState",0,0f);
Animator.playbackTime = 0f;
Animator.Update(0f);
This mecannim thing just seems like a black box as to how it works. I'm not familiar with it as I've always just used my own library to animate stuff that I've been using for donkeys years.
EDIT:
This was the solution...
private void Start()
{
Animator.keepAnimatorControllerStateOnDisable = true;
}
private void OnDisable()
{
Animator.Play("normalState",0,0f);
}
Make sure your keepAnimatorControllerStateOnDisable isn't set to true. Instead, you should set to false to clear the current state of the Animator controller
Animator.keepAnimatorControllerStateOnDisable = false
This way whenever you disable an object with an Animator, the Animator states and all its parameters go back to default.
Update
From your comments was able to understand the default is to have the button bigger. So, it's actually the other way around (set it to true, instead of false).
As you mention, write the following code
private void Start()
{
Animator.keepAnimatorControllerStateOnDisable = true;
}
private void OnDisable()
{
Animator.Play("normalState",0,0f);
}
I have a player object which has (along with other components and objects) a Rigidbody2D, a Collider2D, a PhotonView, and a script called "PhotonLagCompensationView" attached to it. PhotonLagCompensationView syncs the position and velocity of the attached Rigidbody2D, and applies lag compensation like so:
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
stream.SendNext(rigidBody2D.position);
stream.SendNext(rigidBody2D.velocity);
}
else
{
networkedPosition = (Vector2)stream.ReceiveNext();
networkedVelocity = (Vector2)stream.ReceiveNext();
float lag = Mathf.Abs((float)(PhotonNetwork.Time - info.SentServerTime));
networkedPosition += networkedVelocity * lag;
}
}
void FixedUpdate()
{
if (!photonView.IsMine)
{
rigidBody2D.velocity = networkedVelocity;
rigidBody2D.position = Vector2.Lerp(
rigidBody2D.position, networkedPosition, Time.fixedDeltaTime * interpolateRate);
}
}
The issue is when I try to call Rigidbody2D.AddForce() on that GameObject, the velocity wont even stutter. What blows my mind about this though is that when I call the EXACT SAME FUNCTION on a different script, it works just fine on all players in the room.
The script that is not working is "KnockBackOnTrigger" which is attached to an object which is instantiated over the network by the player. This object has a Collider2D which is a trigger, and a PhotonView. The OnTriggerEnter2D callback is working just fine. It prints "trigger", and I've even Debug.logged the AddForce() parameters, and a TryGetComponent<>() to make sure the Rigidbody is being recognized and it's applying force properly. The script applies force like this:
void OnTriggerEnter2D(Collider2D collider)
{
if(collider.gameObject.layer == 9 && collider.gameObject != PlayerManager.LocalPlayerInstance)
{
Debug.Log("trigger");
collider.gameObject.GetComponent<Rigidbody2D>().AddForce(
new Vector2(this.transform.localScale.x * knockBackForce, 0),ForceMode2D.Impulse);
}
}
Triggers show up, Rigidbody2D shows up, no moveme
The script that is working is a script attached to the "Lava Blocks" Gameobject which is a tilemap object. The tilemap object for the lava blocks has all the tilemap components attached to it (map, renderer, collider) and they work as intended, as well as the script attached to it. The "LavaBlocks" script works like this:
void OnCollisionEnter2D(Collision2D collision)
{ // everything inside this statement will happen to the player when it touches lava.
if (collision.gameObject.layer == 9)
{
collision.gameObject.GetComponent<Rigidbody2D>().AddForce(
Vector2.up * upwardForce, ForceMode2D.Impulse);
}
}
So whenever a player touches one of the Lava tiles' collider, it bounces upward.
Additionally, I've tried setting the velocity of the Rigidbody2D, which did not work either. This is in fact what I originally wanted to do with the script, but I tried AddForce() to see if that would work.
At one point I even tried to just use the player's CharacterController2D.Move() function to just smack the player's position some units to the left/right, and even this did not do anything.
I'm trying to follow the instructions in the unity documents how to use Inverse Kinematics in this page:
Inverse Kinematics
But i don't have the IK Animator Controller when i select Controller for the Animator.
I tried adding the script now. But the hand the right hand is folded to the other side. It's not like it's holding the flash light: The script is attached to the ThirdPersonController. And i dragged to the script in the Inspector to the rightHandObj the EthanRightHand and to the lookObj i dragged the Flashlight.
But the hand seems to be wrong way.
This is the script i'm using now the IKControl:
using UnityEngine;
using System;
using System.Collections;
[RequireComponent(typeof(Animator))]
public class IKControl : MonoBehaviour
{
protected Animator animator;
public bool ikActive = false;
public Transform rightHandObj = null;
public Transform lookObj = null;
void Start()
{
animator = GetComponent<Animator>();
}
//a callback for calculating IK
void OnAnimatorIK()
{
if (animator)
{
//if the IK is active, set the position and rotation directly to the goal.
if (ikActive)
{
// Set the look target position, if one has been assigned
if (lookObj != null)
{
animator.SetLookAtWeight(1);
animator.SetLookAtPosition(lookObj.position);
}
// Set the right hand target position and rotation, if one has been assigned
if (rightHandObj != null)
{
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1);
animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandObj.position);
animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandObj.rotation);
}
}
//if the IK is not active, set the position and rotation of the hand and head back to the original position
else
{
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0);
animator.SetLookAtWeight(0);
}
}
}
}
Add an empty game object to the flashlight and target that instead of the flashlight object itself. Hit play and then fiddle with the placement of the empty object until it is where you want it. Then just turn the flashlight into a prefab, stop play mode and make sure the flashlight in the scene matches the prefab (you can just use revert to do that if needed).
Now it would be doing exactly what you want every time. You could even have multiple prefabs with the empty object positioned differently to allow characters with larger or smaller hands to hold it convincingly.