preface: i am very new to c#, and this is an object grabbing script i have taken from a prefab and edited.
script goal: detect if a game object is in pickup distance. if it is, when the grip trigger is pressed, parent the object to the virtual hand. when the trigger is released, remove the parent relationship. Also, while the object is parented to the controller, if the B button is held, scale the object up, and if the A button is held, scale the object down, and reset the scale upon thumbstick click.
I can see when my controller collides with the game object, but when i press the designated button to parent the object, nothing seems to happen.
I'd really appreciate any help I could get with this script, as there might be a significant amount i'm doing wrong.
I should mention that I don't really need any sort of physics simulations, all i need is the ability to manipulate an object floating in space for viewing purposes.
Thanks in advance!
Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Grabber : MonoBehaviour
{
// Update is called once per frame
void Update()
{
OVRInput.Update();
if ((OVRInput.Get(OVRInput.Axis1D.SecondaryHandTrigger)) > 0.2f && CollidingObject)
{
GrabObject();
}
if ((OVRInput.Get(OVRInput.Axis1D.SecondaryHandTrigger)) < 0.2f && ObjectInHand)
{
ReleaseObject();
}
if (OVRInput.Get(OVRInput.Button.Two) && ObjectInHand)
{
ScaleUp();
}
if (OVRInput.Get(OVRInput.Button.One) && ObjectInHand)
{
ScaleDown();
}
if (OVRInput.Get(OVRInput.Button.SecondaryThumbstick) && ObjectInHand)
{
ScaleReset();
}
}
public GameObject CollidingObject;
public GameObject ObjectInHand;
public void OnTriggerEnter(Collider other)
{
if (other.gameObject.GetComponent<Rigidbody>())
{
CollidingObject = other.gameObject;
}
}
public void OnTriggerExit(Collider other)
{
CollidingObject = null;
}
private void GrabObject()
{
ObjectInHand = CollidingObject;
ObjectInHand.transform.SetParent(this.transform);
ObjectInHand.GetComponent<Rigidbody>().isKinematic = true;
}
private void ReleaseObject()
{
ObjectInHand.GetComponent<Rigidbody>().isKinematic = false;
ObjectInHand.transform.SetParent(null);
ObjectInHand = null;
}
Vector3 scaleChangeUp = new Vector3(0.01f, 0.01f, 0.01f);
Vector3 scaleChangeDown = new Vector3(-0.01f, -0.01f, -0.01f);
public void ScaleUp()
{
ObjectInHand.transform.localScale += scaleChangeUp;
}
public void ScaleDown()
{
ObjectInHand.transform.localScale += scaleChangeDown;
}
private void ScaleReset()
{
ObjectInHand.transform.localScale = Vector3.one;
}
}
Related
I am making Third person multiplayer game with unity and Photon i can't get the Instantiating of players right both players are sometimes instantiating the same avatar or sometimes there camera Mix up. I have used Cinemachine Virtual camera and Cinemachine brain on main camera
My Hierarchy
Player Prefeb:
Cinemachine Virtual Cam:
Cinemachine brain cam:
This is my script that is responsible for intantiating players
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Photon.Pun;
using UnityEngine;
public class PlayerInstantiator : MonoBehaviour
{
PhotonView PV;
bool spawnPoint1 = true;
bool spawnPoint2 = true;
public GameObject player1;
public GameObject player2;
public Transform sp1;
public Transform sp2;
private void Update()
{
Debug.Log(CheckPlayers());
if (CheckPlayers() == 1 && spawnPoint1 == true)
{
spawnPoint1 = false;
SpawnMasterPlayer();
}
else if (CheckPlayers() == 2 && spawnPoint2 == true)
{
// SpawnMasterPlayer();
SpawnPlayer2();
spawnPoint2 = false;
}
}
private void SpawnMasterPlayer()
{
if (PV.IsMine)
{
CreateController(player1.name, sp1);
}
}
private void SpawnPlayer2()
{
if (!PV.IsMine)
{
CreateController(player2.name, sp2);
}
}
private int CheckPlayers()
{
return PhotonNetwork.CurrentRoom.PlayerCount;
}
private void Awake()
{
PV = GetComponent<PhotonView>();
}
void CreateController(string name, Transform sp)
{
PhotonNetwork.Instantiate(name, sp.position, Quaternion.identity);
}
}
It takes two spawn points and players Prefeb all have photon View attached but still i cant figure it out
It should intantiate two differnt Avatars and make their camers function properly
I'm fairly new to programming and right now I'm working on a 2D-Game for Android with Unity. The basic concept right now is that a object moves to the middle of the screen and it needs to "touch" an other object so you can press on a button and the moving object is getting destroyed. After it got destroyed I want another to spawn in and keep that cycle going. There is my problem. I have the (moving) object as a prefab and added it as the public GameObject "RedTriangle". The object is getting spawned in and moves to the center of the screen but it doesn't change the layer of the new objects when I press the button (I guess because its not the same object as the "RedTriangle" object). I really don't know how to change the Layer of new spawned in objects and hope I can get help here. Thanks already for all responses.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Red : MonoBehaviour, IPointerClickHandler
{
public GameObject RedTriangle;
public GameObject FalseTriangle;
public Transform spawnPos;
public float spawnT;
private void Start()
{
GameObject newTriangle = Instantiate(RedTriangle, spawnPos.position, Quaternion.identity);
}
IEnumerator touchCD()
{
while (true)
{
yield return new WaitForSeconds(0.1f);
if (RedTriangle == null)
{
}
else if (RedTriangle != null)
{
Debug.Log("!= null");
RedTriangle.layer = 0;
}
}
}
public void Update()
{
if (RedTriangle == null)
{
spawnT = Random.Range(1, 4);
if (spawnT == 3)
{
GameObject newTriangle = Instantiate(FalseTriangle, spawnPos.position, Quaternion.identity);
}
else
{
GameObject newFalseTriangle = Instantiate(RedTriangle, spawnPos.position, Quaternion.identity);
}
}
}
public void OnPointerClick(PointerEventData eventData)
{
RedTriangle.layer = 7;
Debug.Log("button");
StartCoroutine(touchCD());
}
Assuming you want to change the layer of the object immediately after spawning, just do exactly that. For example:
GameObject newTriangle = Instantiate(FalseTriangle, spawnPos.position, Quaternion.identity);
newTriangle.layer = 0;
If you want to change the current (MonoBehaviour) object's own layer from its own attached component script e.g. when a certain event occurs, you don't need to keep the reference in your own variable as you can just use for example:
gameObject.layer = 0;
I'm trying to keep the player skin, even when reloading the scene, or moving on to a new one. The player object changes every scene.
The player skin is chosen in a pause menu, with three buttons. Each one of those buttons calls a function in the script below. I'm trying to call one of these functions, based on what value the PlayerPrefs int holds, and the function does get called; But throws the error MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it
Below is what i have already tried, but this throws an error on scene reload (death)
i don't know what i'm doing wrong here.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Pausemenu : MonoBehaviour
{
public static bool gameIsPaused = false;
public GameObject pauseMenuUI;
public Material BelgianMat;
public Material Ball2;
public Material Rainbow;
public GameObject Player;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape)) {
if (gameIsPaused) {
Resume();
} else {
Pause();
}
}
}
public void Resume(){
pauseMenuUI.SetActive(false);
Time.timeScale = 1f;
gameIsPaused = false;
}
void Pause() {
pauseMenuUI.SetActive(true);
Time.timeScale = 0f;
gameIsPaused = true;
}
public void LoadMenu() {
Time.timeScale = 1f;
gameIsPaused = false;
SceneManager.LoadScene("Menu");
}
public void QuitGame() {
Debug.Log("Quitting");
Application.Quit();
}
public void ApplyBelgian() {
Player.GetComponent<Renderer>().material = BelgianMat;
PlayerPrefs.SetInt("playerMat", 0);
}
public void ApplyBall2() {
Player.GetComponent<Renderer>().material = Ball2;
Debug.Log("Applied ball two");
PlayerPrefs.SetInt("playerMat", 1);
}
public void ApplyRainbow() {
Player.GetComponent<Renderer>().material = Rainbow;
PlayerPrefs.SetInt("playerMat", 2);
}
void OnEnable()
{
Debug.Log("OnEnable called");
SceneManager.sceneLoaded += OnSceneLoaded;
}
// called second
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
Debug.Log("OnSceneLoaded: " + scene.name);
Debug.Log(mode);
if (PlayerPrefs.GetInt("playerMat") == 0) {
ApplyBelgian();
}
else if (PlayerPrefs.GetInt("playerMat") == 1) {
Debug.Log("gonna apply ball 2");
ApplyBall2();
}
else if (PlayerPrefs.GetInt("playerMat") == 2) {
ApplyRainbow();
}
}
}
I don't know why but it seems like the reference to the Player object may be broken after loading the scene. If this is the case, add a "Player" tag to your Player object and add this to the OnEnable function: Player = GameObject.FindWithTag("Player");
me and my colleagues are creating a 2D sidescroller game in Unity with C#.
The player, is supposed to be able to pick objects (by touching them) and throw them.
Our plan is this:
1) make variables for the objects, their booleans and their rigid bodies.
2) verify if the object is touching the player
3) if it's true, then the object will parent to the player (setting their position to the player's hand).
4) to throw, the code will check if the player has the object (by using a boolean) and then it will unparent and throw by addforce.
The code doesn't have any errors and it works except on the throwing part (the player can grab and ungrab but can't throw).
The player can pick and unpick but not throwing and i don't understand why because the code looks right and the console doesn't show me any errors :/
Have a look to my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public bool ispicked1 = false;
public GameObject pickable1;
public Rigidbody2D pickable1rb;
public GameObject Parent;
public float force;
void Start() {
pickable1rb = GetComponent<Rigidbody2D>();
}
void Update() {
if (ispicked1 == true) {
pickable1.transform.position = Parent.transform.position;
}
else if (ispicked1 == false) {
pickable1.transform.parent = null;
}
if (Input.GetMouseButton(1) && ispicked1 == true) {
ispicked1 = false;
pickable1rb.AddForce(transform.up * force, ForceMode2D.Impulse);
}
}
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.name == "pickable1") {
Debug.Log("Tocou em objecto");
ispicked1 = true;
pickable1.transform.SetParent(Parent.transform);
}
}
}
Side question: i want the player to throw at the direction he's facing, what is the best way to do that? I can only choose between right, left or up :/
UPDATE:
I solved all the problems and i created a side script for the object to be thrown and they are 100% working! Here are the codes:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public bool ispicked1 = false;
public bool ispicked2 = false;
public GameObject pickable1;
public GameObject pickable2;
public GameObject Parent;
public bool isThrown = false;
public ThrowableObject throwableinstance1;
public ThrowableObject throwableinstance2;
public bool isfull = false;
void Start() {
throwableinstance1 = GameObject.Find("pickable1").GetComponent<ThrowableObject>();
throwableinstance2 = GameObject.Find("pickable2").GetComponent<ThrowableObject>();
}
void Update() {
if (ispicked1 == true) {
pickable1.transform.position = Parent.transform.position;
isfull = true;
}
else if (ispicked1 == false) {
pickable1.transform.parent = null;
}
if (ispicked2 == true) {
pickable2.transform.position = Parent.transform.position;
isfull = true;
} else if (ispicked2 == false) {
pickable2.transform.parent = null;
}
if (Input.GetMouseButton(1) && ispicked1 == true) {
ispicked1 = false;
isThrown = true;
throwableinstance1.Throw();
isfull = false;
}
if (Input.GetMouseButton(1) && ispicked2 == true) {
ispicked2 = false;
isThrown = true;
throwableinstance2.Throw();
isfull = false;
}
}
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.name == "pickable1" && isfull == false) {
ispicked1 = true;
pickable1.transform.SetParent(Parent.transform);
}
if (collision.gameObject.name == "pickable2" && isfull == false) {
ispicked2 = true;
pickable2.transform.SetParent(Parent.transform);
}
}
}
Here's the code to throw the pickable object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThrowableObject : MonoBehaviour
{
public Inventory inventoryinstance;
public Rigidbody2D throwablerb;
public Transform Player;
public GameObject PickableObject;
public EnemyHealth1 enemyhealth1instance;
public EnemyHealth2 enemyhealth2instance;
public EnemyHealth3 enemyhealth3instance;
void Start()
{
inventoryinstance = GameObject.Find("Player").GetComponent<Inventory>();
enemyhealth1instance = GameObject.Find("enemy1").GetComponent<EnemyHealth1>();
enemyhealth2instance = GameObject.Find("enemy2").GetComponent<EnemyHealth2>();
enemyhealth3instance = GameObject.Find("enemy3_leper").GetComponent<EnemyHealth3>();
}
public void Throw()
{
if(Player.localScale.x < 1)
{
throwablerb.AddForce(transform.right * -1);
} else if(Player.localScale.x > 0)
{
throwablerb.AddForce(transform.right);
}
}
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.name == "enemy1") {
enemyhealth1instance.GetComponent<EnemyHealth1>().EnemyHealthbar1-= 1;
Destroy(PickableObject);
}
if (collision.gameObject.name == "enemy2") {
enemyhealth2instance.GetComponent<EnemyHealth2>().EnemyHealthbar2-=1;
Destroy(PickableObject);
}
if (collision.gameObject.name == "enemy3_leper") {
enemyhealth3instance.GetComponent<EnemyHealth3>().EnemyHealthbar3-=1;
Destroy(PickableObject);
}
}
private void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.name == "enemy1_hitbox") {
enemyhealth1instance.GetComponent<EnemyHealth1>().EnemyHealthbar1-=1;
Destroy(PickableObject);
}
}
}
While you're answering my question, I'll do some quick code reviewing:
Overall, it feels weird to be keeping track and maintaining "holding & throwing an item" in a class called "Inventory" that has references to a separate object, that is being held & a reference to the player. What is this script? The item, the player or a third party; a separate inventory? (Questions to ask yourself, you don't need to answer them - just think about it 😊)
pickable1
pickable1object
pickable1rb
These variable names makes little sense to me in current context; why not just isPickedUp, object, rb?
if (pickable1 == true) {
pickable1object.transform.position = Playerparent.transform.position;
}
if (pickable1 == false) {
pickable1object.transform.parent = null;
}
pickable1 will not be both true and false, doing 2 ifs are just unnecessary computations. What you're looking for here is an if/else or if/elseif.
Furthermore, if you child it to the player, logically, shouldn't you NOT have to set the position every frame? Else, what's the purpose of childing?
void FixedUpdate() {
if (Input.GetMouseButton(1)) {
// [...]
}
// [...]
}
Logically, you shouldn't be checking for input in the fixed update since inputs are tied to a frame, meaning Update(). In this case, it may accidentally work reliably most of the time because you're not checking if the player CLICKED a button, rather you're checking if player is HOLDING a button. (GetMouseButton vs GetMouseButtonDown). If you were to check for if the player CLICKED a button in the FixedUpdate, it would only work on the few lucky frames where FixedUpdate and Update were running at the exact same time.
Regarding your question: The code looks alright, it's probably not behave in the way you expect. From what I can tell in the code it will...
If player has picked up an item, it will have force added to it if holding down Mouse 1 for as long as player is holding down mouse.
Why nothing is happening may be due to inspector values being off. Debug the values of force and see if the code is triggering at all. Consider moving the parent = null code (or just remove the parenting alltogether).
It could also be that as soon as you push the item outside of the player, it falls down and triggers OnCollisionEnter and is grabbed by the player again.
The problem with your code is that you use transform.up which will just cause it to throw upwards rather than the direction the player is facing. So you can use transform.right for the direction the player is facing. You can use both to create more of an arc.
You'll have some problems with pivoting with the way you have it setup.
What I recommend is to have two transforms which are children of the player to pivot the sprite properly. (You can change the position of the transform in the keyframes of the player's animation)
The code would look something like this:
public class Inventory : MonoBehaviour
{
private bool carryingItem => pickedUpItem == null;
private PickableItem pickedUpItem;
[SerializeField] private Vector2 throwingForce;
[SerializeField] private Transform spawnPosition; //Should be a child of the player gameobject. This will be position of the object
[SerializeField] private Transform handTransform; //Should also be a child of the player gameobject. This needs to be animated for the keyframes that move the hand
void Update()
{
if (carryingItem && Input.GetMouseButtonDown(1))
{
pickedUpItem.transform.SetParent(null);
pickedUpItem.transform.position = spawnPosition.position;
pickedUpItem.GetComponent<Rigidbody2D>().AddForce(transform.right * throwingForce.x + transform.up * throwingForce.y);
pickedUpItem = null;
}
}
private void OnCollisionEnter2D(Collision2D other)
{
var pickable = other.transform.GetComponent<PickableItem>();
if (pickable && pickedUpItem == null) //This kind of depends on the game design because maybe you want to pick it up if you're carrying something already
{
pickedUpItem = pickable;
pickable.transform.SetParent(handTransform);
}
pickable.transform.localPosition.Set(0,0,0);
}
}
You set the picked up item to the parent where you want to be pivoted around.
I'm wrote this script to decrease the players life and move them back to their original point on contact with certain objects, but I'm finding that it will trigger anywhere from 1 to 4 times per collision taking lives from 3 down to -1.
using UnityEngine;
using System.Collections;
public class HitCar : MonoBehaviour
{
public static int lives = 3;
void OnControllerColliderHit(ControllerColliderHit col)
{
if(col.gameObject.name == "utd_car1")
{
Destroy(col.gameObject);
lives--;
if(lives <= 0)
{
Application.LoadLevel("LoseScreen");
}
else
{
var player = GameObject.Find("3rd Person Controller");
player.transform.position = new Vector3(0, 2, -26);
}
}
}
void OnLevelWasLoaded(int level)
{
lives = 3;
}
}
Any way to prevent it from triggering more than once per collision would be greatly appreciated.
OnControllerColliderHit is used when you want to hit something a few times, preferably to move it.
You can switch to this code:
void OnCollisionEnter(Collision col)
{
if(col.gameObject.name == "utd_car1")
{
}
}