Why is position of my object not changing? - c#

I am currently developing a Unity3D based evolutionary algorithm. The simulation is two-dimensional. A single subject is being depicted as car, being a prefab, consisting of 3 sprites(2 wheels and body), and a CarScript. Each sprite has a proper collider(BoxCollider2D for body and CircleCollider2D for wheels). CarBody also has
two WheelJoint2D. Parameters of those colliders are changed by code.
I want this car to be destroyed, if it stops moving or better - advancing. In the Game window, the car is obviously moving downhill. The problem is, that after checking for transform.position of gameobject, this value seems to be constant. It always shows the position of SpawnPoint. SpawnPoint is empty GameObject with SpawnScript, which fragment is below:
public GameObject carprefab; //Set from editor
public Transform[] spawnPoints; //transform of SpawnPoint, just one element. Set from editor.
private void GenerateCar(Chromosome chromosome)
{
int spawnPointIndex = Random.Range(0, spawnPoints.Length);
var instace = (GameObject)Instantiate(carprefab, spawnPoints[spawnPointIndex].position, spawnPoints[spawnPointIndex].rotation);
instace.SendMessage("SetChromosome", chromosome);
foreach (Transform child in instace.transform)
{ //code omitted for clarity, changes some of parameters based on chromosome.
Instantiated object has a CarScript:
// Update is called once per frame
void Update()
{
if (frames%10 == 0)
CheckForMoving();
frames++;
}
private void CheckForMoving()
{
var pos = gameObject.transform.position; //this is never changing - why?
var diff = pos - startingPosition; //difference between local position and starting position
if (CountLength(diff) >= recordLengthYet)
{
Debug.Log("It is moving!");
recordLengthYet = CountLength(diff);
framesTillLastRecord = 0;
}
else
{
Debug.Log("It is not moving");
if (framesTillLastRecord > 4)
Destroy(gameObject, 0f);
framesTillLastRecord++;
}
}
I tried getting the position by any of the following:
var pos = gameObject.transform.position;
var pos = GameObject.FindGameObjectWithTag("player");
var pos = this.transform.position;
The question is - what did I miss, or why this is not changing? I started learning Unity just recently, and had no previous experience with any similiar software. I also wonder, if it is even the right way to do this.

Few days has passed, nobody had uploaded a proper answer, and I managed to get a workaround. As long as it is really dirty, it seems to work.
I placed a tag on child GameObject, instead of prefab, and I am geting position of this child by
var pos = GameObject.FindGameObjectWithTag("player");
I am not sure, if this is really good answer, but I hope somebody might find it useful someday.

Assuming you are using rigidbodies, you should be overriding FixedUpdate() and not Update() as per Unity doco:
This function is called every fixed framerate frame, if the MonoBehaviour is enabled. FixedUpdate should be used instead of Update when dealing with Rigidbody. For example when adding a force to a rigidbody, you have to apply the force every fixed frame inside FixedUpdate instead of every frame inside Update. - Tell me more...
Replace:
// Update is called once per frame
void Update()
{
if (frames%10 == 0)
CheckForMoving();
frames++;
}
With:
// Update is called once per frame
void FixedUpdate()
{
if (frames%10 == 0)
CheckForMoving();
frames++;
}

Related

How to make Instantiated Game Objects script act separately for every object. Unity2D

I have a script for that Instantiates 2 game object but when something happens to one of them it also happens to the another one even when the conditions are not met for it. How can I make the script act separately for every Game Object?
GO script:
private Transform target;
public float speed = 2f;
private Animator anim;
public float H2Damage = 5f;
private healthBar Hp;
void Start()
{
target = GameObject.FindGameObjectWithTag("enemy").GetComponent<Transform>();
anim = gameObject.GetComponent<Animator>();
Hp = GameObject.FindGameObjectWithTag("enemy").GetComponentInChildren<healthBar>();
}
void Update()
{
target = GameObject.FindGameObjectWithTag("enemy").GetComponent<Transform>();
if (Hp.Died == true)
{
Hp.Died = false;
anim.SetBool("Hero2Attack", false);
anim.SetBool("Hero2Move", true);
}
if (!target || this.anim.GetCurrentAnimatorStateInfo(0).IsName("Hero2ATTACK"))
return;
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
anim.SetBool("Hero2Move", true);
}
private void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.CompareTag("enemy"))
{
anim.SetBool("Hero2Attack", true);
healthBar hp = col.transform.GetComponent<healthBar>();
hp.GiveDamage(H2Damage);
}
}
I believe they act the same way because they are getting the same GetComponentWithTag(), so they will Get the same objects. You also instantiate the animator, which is the exact same one, so they will do the same things. --> If it was as simple as changing the position by 1 meter per second, they would have different behavior (ie. be at different positions) But.... If you instantiate it, the current position is also instantiated, so you are going to have to get the current postion and set it to what you want, so both of these moving boxes aren't at the exact same position. You will have to do something similar here, you are going to want to either (create different scripts for the objects, or set the script values to different things)
TL;DR: You are copying the exact same script with the exact same components, so they will act similarly.
Fix: The only way to fix this is by setting their values after you instantiate them using GetComponent<>()or changing the script you assign them. (or any components for that matter)
Let me know if you have any problems or questions in the comments! :)

Unity - What is OOP - Null Reference Exception

im kind of newbie to unity and object oriented programming. Recently im trying to clone Cube Surfer mobile game. Basic idea from my view is this ;
-When we triggered to collactable cubes which consist script will be duplicated and it will be belong the main cube parent as child object then triggered cube will be destroyed.(After positioning)
-Later this duplicate child objects(cubes) will do the same when they enter trigger area of other collectable cubes(those will be the same prefab but did not yet create a prefab)
Im trying to collect(create a clone of it position and destroy the object) cubes. For first cube, I added some code to my movement script which is below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
public GameObject addup;
Rigidbody rb;
float controlSpeed = 1.25f;
float forwardMovementSpeed = 10f;
private Vector3 axisGet;
float deathTime;
public int collected;
// Start is called before the first frame update
void Start()
{
rb = gameObject.GetComponent<Rigidbody>();
collected = 0;
}
// Update is called once per frame
void FixedUpdate()
{
axisGet = new Vector3(0, 0, Input.GetAxis("Horizontal"));
rb.MovePosition(transform.position + Vector3.left * forwardMovementSpeed * Time.deltaTime + axisGet * controlSpeed * Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
if(other.tag=="add up")
{
gameObject.transform.position += Vector3.up;
var newObject = Instantiate(addup.gameObject, Vector3.zero, Quaternion.identity);
newObject.transform.parent = transform;
newObject.transform.position = gameObject.transform.position + Vector3.down;
Destroy(other.gameObject);
newObject.GetComponent<BoxCollider>().isTrigger = false;
collected++;
}
}
}
WORKED WITHOUT ERROR BUT THEN, I applied the same method to collectable cubes scripts.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UpNdown : MonoBehaviour
{
void Start()
{
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "add up")
{
GameObject parentTransform;//?????????
parentTransform = gameObject.GetComponentInParent<GameObject>(); //get first cube component
parentTransform.transform.position += Vector3.up; //first cube one unit up
GameObject newObject; // ?????????
newObject = Instantiate(other.gameObject, Vector3.zero, Quaternion.identity) as GameObject; //???????????
Debug.Log(newObject);
var collect = parentTransform.GetComponent<Movement>().collected;
if (other != null)
{
Destroy(other.gameObject); //destroy triggered collactable
}
newObject.transform.parent = parentTransform.transform; //setting parent to new cube
newObject.transform.position = parentTransform.transform.position + Vector3.down * (collect + 1); //setting position of new cube
newObject.GetComponent<BoxCollider>().isTrigger = false; //prepare the below cubes(new cubes) for trigger with other collactable cubes
collect++;
}
}
}
And, I had nullexception error in every line in ontriggerenter method then, I changed(added) the lines with question marks. So, I get
ArgumentException: GetComponent requires that the requested component 'GameObject' derives from MonoBehaviour or Component or is an interface.
UnityEngine.GameObject.GetComponentInParent[T] (System.Boolean includeInactive) (at :0)
UnityEngine.GameObject.GetComponentInParent[T] () (at :0)
UpNdown.OnTriggerEnter (UnityEngine.Collider other)
I thought, I understood the OOP instance idea which objects in the scenes are instances scripts has their own value... but i dont understand that while I was operating on a instance why it is null in the memory :((((((((((((( if PC can't access how instantiates the object ?
SORRY I WRITE THIS LONG BUT IM ABOUT THE EDGE AGAIN I DON'T WANT TO QUIT BECAUSE OF FACING THIS PROBLEM AGAIN
TY FOR YOUR ANSWERS, ALREADY APPRECIATED :)
GameObject is no component (it is rather a container of all components attached to it!)
=> you can't get it using GetComponent or GetComponentInParent at all. (Btw Note that GetComponentInParent starts the search on this object itself first before bubling up the hierarchy so either way this isn't what you want to use).
What you want is simply transform.parent to get the Transform component of the parent object of the object this script is attached to (assuming the rest of your code does what it should)
private void OnTriggerEnter(Collider other)
{
// Rather use CompareTag instead of string ==
// The latter silently fails in case of typos making your debugging life miserabel
// it is also slightly less efficient
if (!other.CompareTag("add up")) return;
// Get the parent of this object
var parentTransform = transform.parent;
// Cache this you will need it later see below
var parentMovement = parentTransform.GetComponent<Movement>();
var collect = parentMovement.collected;
parentTransform.position += Vector3.up;
// By using the correct type you want later you can skip GetComponent
var newObjectCollider = Instantiate(other, Vector3.zero, Quaternion.identity);
Debug.Log(newObjectCollider);
Destroy(other.gameObject);
newObjectCollider.transform.parent = parentTransform;
newObjectCollider.transform.position = parentTransform.position + Vector3.down * (collect + 1);
newObjectCollider.isTrigger = false;
// This does absolutely nothing. Numeric values are passed by value and there is no connection
// between your local variable and the component you got it from
//collect++;
// you probably rather want to increase
parentMovement.collected++;
}
Or alternatively since you anyway have a specific component on your parent object you could also do
// Instead directly get this component
var parentMovement = GetComponentInParent<Movement>();
// Then wherever needed access the transform through it
var parentTransform = parentMovement.transform;
...
I'm quite sure though that the other way round it is more efficient since you already know exactly which parent you are searching the component on.
Or - and this would probably be the best option - cache that parent information once right away:
// If possible already reference this vis the Inspector
[SerializeField] private Movement parentMovement;
private Transform parentTransform;
private void Awake ()
{
if(! parentMovement) parentMovement = GetComponentInParent<Movement>();
parentTransform = parentMovement.transform;
}
Ty sir my first code was nearly the same of your first answer but didn't work again at least for error.
private Transform parentTransform;
private void Awake ()
{
if(! parentMovement) parentMovement = GetComponentInParent<Movement>();
parentTransform = parentMovement.transform;
}
But this worked, I guess the problem I need to define instances to class so they don't disappear instantly on the trigger function or direct I need to define them to class.
Anyway, thank you derHugo now need to solve different problems :D

Creating Simple Endless Moving Platform with cubes

Trying to create simple endless moving platform with 3 cubes of scale 70 on z(Player will not move forward, will just move left/right). The RepositionPlatform script is attached to each platform/cube which is responsible for movement and checks the z position of each platform and if it is <= -100.0f, then position is changed to (0,0,200.0f).
Problem is sometimes there is a little gap between the platforms(cubes) or there is a little overlap which I don't want.
Platforms should be placed one after each other without any gap or overlap!!!
Can anyone help find the issue looking at the script or suggest any other better way ?
The script below is attached to 3 platform game objects!!!
public class RepositionPlatform : MonoBehaviour
{
private GameObject platformGO;
[SerializeField]
private float speed;
// Start is called before the first frame update
void Start()
{
platformGO = this.gameObject;
Debug.Log("In RepositionPlatform Start method - "+ platformGO.name);
}
// Update is called once per frame
void Update()
{
Debug.Log("In RepositionPlatform Update Method- " + platformGO.name);
platformGO.transform.Translate(Vector3.back * Time.deltaTime * speed);
Transform platformTransform = platformGO.transform;
if(platformTransform.position.z <= -100.0f)
{
platformTransform.position = new Vector3(0,0,200.0f);
}
}
}
Probably because speed is a floating point value. You should read up on them if you haven't already.
Long story short, you aren't accounting for how far below -100 the value might have gone, you're just resetting it.
If you translate it instead, you will preserve any extra distance beyond -100 that the transform might have gone.
Try this instead:
If (transform.position.z < -100){
transform.Translate(new Vector3(0,0,200));
}
Edit
Should be Z value, not X

Unity Jump function issue

I've been working on this script for the past day. For some reason my character will not jump as long as it's animator is active. I've got into the animation (there is only one) and removed all references to the animation placing a position anywhere and still the issue presides.
I have discovered that I can make my player jump if I use Co-routine which I'm using. However, I'm still new to using them and I can't work out why my player won't fall to the ground once a force has been added to it. And my player only moves up when the button is clicked. Could someone please take a look at my script and tell me what I'm doing wrong?
public float jumpSpeed = 100.0f;
public float jumpHeight = 2.0f;
public AudioClip jumpSound;
private GameObject pos;
private bool moving;
private bool isJumping;
void Start()
{
}
// Update is called once per frame
void Update ()
{
if(Input.GetMouseButtonDown(0))// && !moving)
{
isJumping = true;
StartCoroutine(JumpPlayer(gameObject.transform.localPosition));
}
else
{
isJumping = false;
}
}
IEnumerator JumpPlayer(Vector3 startPos)
{
Vector3 jump = new Vector3(transform.localPosition.x, jumpHeight, transform.localPosition.z);
float t = 0f;
t += Time.deltaTime / jumpSpeed;
rigidbody.AddForce(Vector3.up * jumpSpeed);
//gameObject.transform.localPosition = Vector3.Lerp(startPos, jump, 0.5f);
//isJumping = false;
yield return null;
}
Firstly, your use of coroutine isn't doing anything in particular - because it only does yield return null at the end, it'll run in a single frame and then exit. You could make it a regular void function and you shouldn't see any change in behaviour.
Removing other redundant code and you have just this:
if(Input.GetMouseButtonDown(0))
{
rigidbody.AddForce(Vector3.up * jumpSpeed);
}
This force is added for only a single frame: the frame where the mouse button is pressed down (if you used Input.GetMouseButton instead, you'd see the force applied for multiple frames).
You say "my player only moves up when the button is clicked" but I'm not clear why that's a problem - perhaps you mean that the player should continue to move up for as long as the button is held, in which case you should refer to my previous paragraph.
The most obvious reasons for the player not falling again are related to the RigidBody component: do you have weight & drag set to suitable values? An easy way to test this would be to position your player some distance from the ground at the start of the scene, and ensure that they fall to the ground when you start the scene.
Another reason might be that you're using the default override of .AddForce in an Update cycle. The default behaviour of this method applies force during the FixedUpdate calls, and you might find that using ForceMode.Impulse or ForceMode.VelocityChange gives you the result you're looking for.

Moving Platform works most of the time, but occasionally falls through and/or is jittery

I'm writing a 2D game and I'm trying to get moving platforms to work. After doing some previous investigation, I have it ALMOST working. The idea is to have 2 platform objects with colliders: 1 a visible object, the other an invisible object with isTrigger set (since the player would just go through a trigger). The code for the Moving Platform child (the trigger one) is set here.
using UnityEngine;
using System.Collections;
public class MovingPlatformChild : MonoBehaviour
{
public string parentPlatform = "";
void Start ()
{
transform.parent = GameObject.Find(parentPlatform).transform;
}
// Update is called once per frame
void Update ()
{
}
void OnTriggerEnter(Collider playerObject)
{
Debug.Log ("enter moving platform");
if(playerObject.gameObject.name.Contains("Player"))
{
playerObject.transform.parent = gameObject.transform;
}
}
int i = 0;
void OnTriggerStay(Collider playerObject)
{
Debug.Log ("stay" + i++);
if(playerObject.transform.position.y >= transform.position.y)
{
playerObject.transform.parent = gameObject.transform;
}
else
{
playerObject.transform.parent=null;
}
}
void OnTriggerExit(Collider playerObject)
{
Debug.Log ("EXIT");
if(playerObject.gameObject.name.Contains("Player"))
{
playerObject.transform.parent=null;
}
}
}
The Start() function just makes it a child of the visible platform. This can probably be done right in the Unity editor as well, instead of through code.
The OnTriggerEnter function adds the player object as a child of the trigger platform object, which is a child of the visible platform. So they should all move together.
The OnTriggerStay is an attempt to verify that this remains true only while the player is on the top of the platform. While the player is within the trigger, if the player is on top of the platform, then it remains attached. Otherwise, it's not. This is so that nothing happens on the bottom end.
The OnTriggerExit function just removes the player object as a child when it exits the trigger.
This is somewhat working (but we know somewhat isn't good enough). It works sometimes, but the player will be very jittery. Also, on the way down while standing atop the platform, the TriggerStay function doesn't appear to be called (implying the player is no longer within the trigger). This is observed through my Debug "stay" statement. Finally, sometimes the player will also fall straight through the platform.
What in this code would allow the player to fall through the platform, or be so jittery on the way up? Am I missing something crucial? If you need any more code, please let me know.
Below is the code for the movement of the non-trigger platform (the parent of the trigger platform and in an identical position). I will also share the Player's Update function after that.
void Start ()
{
origY = transform.position.y;
useSpeed = -directionSpeed;
}
// Update is called once per frame
void Update ()
{
if(origY - transform.position.y > distance)
{
useSpeed = directionSpeed; //flip direction
}
else if(origY - transform.position.y < -distance)
{
useSpeed = -directionSpeed; //flip direction
}
transform.Translate(0,useSpeed*Time.deltaTime,0);
}
And now the player code:
void Update()
{
CharacterController controller = GetComponent<CharacterController>();
float rotation = Input.GetAxis("Horizontal");
if(controller.isGrounded)
{
moveDirection.Set(rotation, 0, 0); //moveDirection = new Vector3(rotation, 0, 0);
moveDirection = transform.TransformDirection(moveDirection);
//running code
if(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) //check if shift is held
{ running = true; }
else
{ running = false; }
moveDirection *= running ? runningSpeed : walkingSpeed; //set speed
//jump code
if(Input.GetButtonDown("Jump"))
{
//moveDirection.y = jumpHeight;
jump ();
}
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
EDIT: I've added the specifications for the platforms and player in this imgur album:
http://imgur.com/a/IxgyS
This largely depends on the height of your trigger box, but it's worth looking into. Within your TriggerStay, you've got an IF statement concerning the player y coordinates. If the trigger box is fairly large and the platform's speed fast enough, on the way up and between update ticks the player Y coords could momentarily be smaller than the trigger Y coords. This would lead to him losing the parentage, only to regain it a few ticks later. This might be the cause of the 'jittering'.
The problem I was having included
The moving platform was written using Translate. I rewrote it using a rigidbody and the rigidbody.Move function. This didn't immediately help, but...
I realized the CharacterMotor script (Unity provides this) that I had attached to the player included moving platform support. I set the MovementTransfer value to PermaLocked, and also unchecked the "Use FixedUpdate" box on the script, and it now works 99% of the time. I've had one time where I did a particular behaviour and slipped through, but I can't recreate it.
Hope this helps anyone who might be looking for an answer!

Categories

Resources