Oculus Go: Picking up/Moving object - c#

I am very new to unity and am building a VR app for Oculus Go. I want to pick and move the object by pointing the ray from the controller on the object and then picking or releasing it by pressing the trigger button. I want the object to stay fixed at the end of the ray's position rather than coming suddenly onto the controller. I have used this script to create a ray and basically allow the controller to pick it up but this script shits the object to the controller's position and as a result I can only move object in a circle(in 360 degrees). It also does not drop the object correctly, as the objects continue to float.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerPointer : MonoBehaviour {
//Returns whatever object is infrount of the controller
private GameObject pointerOver;
[SerializeField]
//Is the object that is currently intractable
private PropBase selectedObject;
//Is the object currently stored in hand, ready to throw.
[SerializeField]
private PickUp inHand;
//This is a refrance to the object we want the pointer to be cast from.
[SerializeField]
public Transform controllerRef;
//This is where we want object we are holding to appear
[SerializeField]
private Transform holdingRef;
//The amount of force we want to throw objects from our hand with.
[SerializeField]
[Range(2,12)]
private float throwForce = 10;
//The script that handles the visuals to show what object is selected
[SerializeField]
private HighlightObject selectVisual;
private LineRenderer line;
void Start () {
line = GetComponent<LineRenderer> ();
}
void Update () {
//If a object is currently being held I don't want to select another
object until it is thrown.
if (inHand == null) {
WorldPointer ();
} else {
line.SetPosition (0, controllerRef.position);
line.SetPosition (1, controllerRef.position);
pointerOver = null;
}
//This function handles how you intract with selected objects
Intract ();
}
//This function handles shooting a raycast into the world from the
controller to see what can be intracted with.
void WorldPointer(){
//We set the line visual to start from the controller.
line.SetPosition (0, controllerRef.position);
RaycastHit hit;
//We reset the pointer so things don't stay selected when we are
pointing at nothing.
pointerOver = null;
//This sends a line from the controller directly ahead of it, it returns
true if it hits something. Using the RaycastHit we can then get information
back.
if (Physics.Raycast (controllerRef.position, controllerRef.forward, out
hit)) {
//Beacuse raycast is true only when it hits anything, we don't need
to check if hit is null
//We set pointerOver to whatever object the raycast hit.
pointerOver = hit.collider.gameObject;
//We set the line visual to stop and the point the raycast hit the
object.
line.SetPosition (1, hit.point);
//Here we check if the object we hit has the PropBase component, or
a child class of its.
if (pointerOver.GetComponent<PropBase> ()) {
//We set the object to be highlighted
selectVisual.NewObject (pointerOver);
} else {
selectVisual.ClearObject ();
}
} else {
//If the raycast hits nothing we set the line visual to stop a
little bit infrount of the controller.
line.SetPosition (1, controllerRef.position + controllerRef.forward
* 10);
selectVisual.ClearObject ();
}
Debug.DrawRay(controllerRef.position , controllerRef.forward *
10,Color.grey);
}
void Intract(){
//We set up the input "OculusTouchpad" in the Input manager
if (Input.GetButtonDown ("Jump") || OVRInput.GetDown
(OVRInput.Button.PrimaryTouchpad)) {
selectVisual.ClearObject ();
//Check if you are holding something you can throw first
if (inHand != null) {
inHand.Release (controllerRef.forward, throwForce);
inHand = null;
//We do this check here to prevent Errors if you have nothing
selected
} else if (selectedObject != null) {
//Check if you can pick up the selected object second
if (selectedObject.GetComponent<PickUp> ()) {
//Beacuse PickUp is a child of PropBase, we can ask InHand
to store selectedObject as PickUp, rather than use GetComponent
inHand = selectedObject as PickUp;
inHand.Store (holdingRef);
//If non of the above were valid then simple call the
trigger function of the selected object
} else {
selectedObject.Trigger ();
}
}
//If you have a object that you need to hold down a button to
intract with
} else if (Input.GetButton ("Jump") && selectedObject != null ||
OVRInput.Get (OVRInput.Button.PrimaryTouchpad) && selectedObject != null) {
selectedObject.Pulse ();
//When you are not pressing down the touchpad button, the selected
object can be updated
} else if (pointerOver != null) {
if (pointerOver.GetComponent<PropBase> ()) {
selectedObject = pointerOver.GetComponent<PropBase> ();
} else {
selectedObject = null;
}
} else {
selectedObject = null;
}
}
}
And i have attached this script to the objects I want to pick:
public class PickUp : PropBase
{
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
public virtual void Store(Transform NewParent)
{
//The following stops the object being effected by physics while it's in
the players hand
rb.isKinematic = true;
//And fixes it to the new parent it is given by the player script to
follow.
transform.parent = NewParent;
//It then resets it's position and rotation to match it's new parent
object
transform.localRotation = Quaternion.identity;
transform.localPosition = Vector3.zero;
}
public virtual void Release(Vector3 ThrowDir, float ThrowForce)
{
//On Release the object is made to be effected by physics again.
rb.isKinematic = false;
//Free itself from following it's parent object
transform.parent = null;
//And applies a burst of force for one frame to propel itself away from
the player.
rb.AddForce(ThrowDir * ThrowForce, ForceMode.Impulse);
}
}
What i'd like to see is have the position of the sphere change according to wherever the end of the ray is cast.
I have also attached this script to the player contoller, which allows it to move to a point by pointing to it and pressing the touchpad button.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClickToMove : MonoBehaviour
{
private Vector3 targetPos; //This Vector3 will store the position where we
click to move.
private bool Moving = false; /*This bool keeps track of whether we are in
the process of moving or not.*/
private GameObject targetInstance;
/*The variables we want to customize. Added info headers to these for the
Unity Editor.*/
[Header("Our Go controller object")]
public GameObject goController;
[Header("Movement Speed")]
public float speed = 1;
[Header("Stop When This Far Away From Target")]
public float haltDistance = 0;
[Header("Optional Target Object")]
public GameObject targetObj;
void Update()
{
MoveToTarget(); /*Here we simply run our MoveToTarget method in the
Update method.*/
//That way we don't clutter up the Update method with too much code.
}
void MoveToTarget() //Here we do the cluttering instead.
{
var ray = new Ray(goController.transform.position,
goController.transform.forward); /*Create a ray going from the goController
position and in the Forward direction of the goController.*/
RaycastHit hitInfo; //Store info about what the ray hits.
Physics.Raycast(ray, out hitInfo, 100);
if (OVRInput.GetUp(OVRInput.Button.PrimaryTouchpad)) /*If we release the
trigger..*/
{
targetPos = hitInfo.point; /*Make our targetPos assume the
positional value of the hit point.*/
if (targetObj) /*If we have specified a Target Object to mark where
we click*/
//If we didn't, then we don't want to try to instantiate it.
{
if (targetInstance) /*If there is already a Target Object in the
scene.*/
{
Destroy(targetInstance); //Destroy it.
}
targetInstance = Instantiate(targetObj, targetPos,
transform.rotation); //Create our Target object at the position we clicked.
}
Moving = true; //And finally we set Moving to True.
}
if (Moving == true) //Since Moving is now true
{
transform.position = Vector3.MoveTowards(transform.position, new
Vector3(targetPos.x, transform.position.y, targetPos.z), speed *
Time.deltaTime); /*Transform our x and z position to move towards the
targetPos.*/
/*Note that our y position is kept at default transform position
since we only want to move along the ground plane.*/
}
if (Vector3.Distance(transform.position, targetPos) <= haltDistance + 1)
/*Check proximity to targetPos. Mainly useful to keep your player from
setting a target position right next to say a building and then end up
clipping through half of it.*/
{
if (targetInstance) //If we created a Target Object..
{
Destroy(targetInstance); //Then we want to destroy it when we
reach it.
}
Moving = false; //Since we have now arrived at our target
//destination.
}
}
}
If anyone could point me in a right direction or help me with this, I would greatly appreciate it!
Thanks in advance.

Okay, with your updated question its now possible to try and answer.
First off - have you tried not resetting your BaseProp localPosition to the controller's?
Try commenting the line that says
transform.localPosition = Vector3.zero;
This wil still orient the object and parent it to the controller but will lock it in a position relative to the moment of parenting.
You currently use "holdingRef" object as a place where the object appears. You may want to use "controllerRef" instead.
To vary distance at which the object appears you can set the object position to:
controllerRef.position+ distance*controllerRef.forward
As this is the direction in which you fire your raycasts. You can get the hit distance by querying hit.distance.
If for any reason that doesn't work out for you, the very point of the raycast hitting the collider is available within HitInfo, so with hit.point you can extract the hit position and position the object relative to that point. Another very useful attribute of hitinfo is .normal, which enables you to get direction at which the hit happened.
You can pass that info along with your Store method.

Related

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

Deleting previous added Component of a GameObject

I have this script where it would add the SelectMove script at runtime when a character was touched by the user.
public GameObject target;
void Start () {
}
// Update is called once per frame
void Update () {
if(Input.touchCount > 0 || Input.GetTouch(0).phase == TouchPhase.Began){
ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Debug.DrawRay(ray.origin,ray.direction * 20,Color.red);
if(Physics.Raycast(ray, out hit,Mathf.Infinity)){
Debug.Log(hit.transform.gameObject.name);
target = hit.transform.gameObject;
//Destroy(hit.transform.gameObject);
selectedPlayer();
}
}
}
void selectedPlayer(){
target.AddComponent(Type.GetType("SelectMove"));
}
In the code above, if the user will click Player A, Player A will move using accelerometer. What I need to do is if I click another character, say Player B, I need Player A to stop moving and it is now Player B's time to move. But I seemed not to get what I want. I tried destroying the script by using Destroy(this) or by this code:
if (target != null)
{
var sphereMesh = target.GetComponent<SelectMove>();
Destroy(sphereMesh);
}
But it is still not working.
If I don't destroy the previous added script, if the user clicks for another character, the previous selected player still moves along with the new one.
Is there another way that I could achieve what I needed to do?
public GameObject target = null;
void Update ()
{
if(Input.touchCount > 0 || Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Debug.DrawRay(ray.origin,ray.direction * 20,Color.red);
RaycastHit hit;
if(Physics.Raycast(ray, out hit,Mathf.Infinity))
{
Debug.Log(hit.transform.gameObject.name);
if(this.target != null){
SelectMove sm = this.target.GetComponent<SelectMove>()
if(sm != null){ sm.enabled = false; }
}
target = hit.transform.gameObject;
//Destroy(hit.transform.gameObject);
selectedPlayer();
}
}
}
void selectedPlayer(){
SelectMove sm = this.target.GetComponent<SelectMove>();
if(sm == null){
target.AddComponent<SelectMove>();
}
sm.enabled = true;
}
The code reuses your base, the new part is that you use the previous selected object to disable the SelectMove script (I assume it is the one moving things). Instead of destroying it, it enables/disables so you save that memory consumption.
I do not think Adding and destroying scripts is the convenient method here.
Try this:
1. Add the SelectMove script to all movable players.
2. Add a public property bool IsMoving = false; to the SelectMove script and make an if statement to move if IsMoving is true.
3. Change selectedPlayer() method to instead change the target player IsMoving to true, and set the previous one (or simply all other players) to false.

Grab and drop object

I'm trying new things and I'm stuck to find a way to drag and drop objects. My player is a square and he have a hand attached. Here is an example:
That red thing in the arm is the "hand", when I press shift it turns green. I made the detection like a ground check. Here is the code:
void Update () {
touch = Physics2D.OverlapCircle(touchDetect.position, 0.01f, objectLayer);
mao1.SetBool("Ligado", ligado);
if (Input.GetKey(KeyCode.LeftShift)) {
ligado = true;
} else {
ligado = false;
}
}
The touchDetect is working fine, because he turns to "true" when touches the box:
My question is: I don't know how to put in the script that I want him to grab the object and drop when I want to. If I need to use Raycast, how would the code looks like?
In order to "grab" an object in unity, simply set the transform.parent of the gameobject you wish to grab, to the transform of the gameobject you wish to grab it with.
For example, in your code you are using Physics2D.OverlapCircle which returns a Collider2D object. You can use that collider to grab on to your gameobject.
Collider2D touch = Physics2D.OverlapCircle(touchDetect.position, 0.01f, objectLayer);
if (Input.GetKey(KeyCode.LeftShift) && touch != null)
{
//grab on to the object
touch.gameObject.transform.parent = this.transform;
//if your box has a rigidbody on it,and you want to take direct control of it
//you will want to set the rigidbody iskinematic to true.
GetComponent<Rigidbody2D>().isKinematic = true;
}
else if( touch != null)
{
//let the object go
touch.gameObject.transform.parent = null;
//if your object has a rigidbody be sure to turn kinematic back to false
GetComponent<Rigidbody2D>().isKinematic = false;
}
Just place a GameObject with SprieRender component attach it to hand tip.
Put this script to that qube and follow what I commented
using UnityEngine;
using System.Collections;
public class collid : MonoBehaviour {
// Use this for initialization
public Sprite mySprite; // Put Here that Qube Sprite
public GameObject Cursorimg; // Put the gameobject here from hierarchy
void Start () {
mySprite = GetComponent<SpriteRenderer>().sprite;
}
// Update is called once per frame
void Update () {
if(Collide conditions) {
Debug.Log(" Collide ");
Cursorimg.GetComponent<SpriteRenderer>().sprite = mySprite;
Cursorimg.GetComponent<SpriteRenderer>().sortingOrder = 3;// U change based on your option
}
if(DropCondition)
{
Debug.Log("Drop");
Cursorimg.GetComponent<SpriteRenderer>().sprite =null;
}
}
If this not works Here is a script that gameobject with Sprite will follow mouse position,
Vector3 pos = Input.mousePosition;
pos.z = Cursorimg.transform.position.z - Camera.main.transform.position.z;
Cursorimg.transform.position = Camera.main.ScreenToWorldPoint(pos);
this code follows in update and Cursorimg is Gameobject
I think This would help you, Let me know further

Can't access variable in different script: Unity C#

Currently I'm making my first video game using unity written in C#, but now I'm facing a trouble and I don't know what to do anymore. First I already made my character move but, I want to put all the attributes in one script, like it's moveSpeed, attackSpeed, etc. but once I access it to another script, my character just stands and do nothing. Here's my code
public class ClickToMove : MonoBehaviour {
public CharacterController controller; // Use to move the player
private Vector3 position; // Store the position at which the player clicked;
public Attributes attribute;
// Animation variables
public AnimationClip idleClip;
public AnimationClip runClip;
// Use this for initialization
void Start () {
position = transform.position; // Set the position to player's current position
}
// Update is called once per frame
void Update () {
// Execute the code below once the player press left click
if(Input.GetMouseButton(0)) {
locatePosition();
}
moveToPosition();
}
// Locate at which the player clicked on the terrain
private void locatePosition() {
RaycastHit hit; // Get information from ray
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // A line in 3D space
// Cast a ray that start from the camera with a distance of 1000
if(Physics.Raycast(ray, out hit, 1000)) {
// Store the position if the casted ray is not pointing to the player or enemy's position
if(hit.collider.tag != "Player" && hit.collider.tag != "Enemy") {
position = new Vector3(hit.point.x, hit.point.y, hit.point.z);
}
}
}
// Move to the located position
private void moveToPosition() {
// Check if the player position and the destination is greater than one
if(Vector3.Distance(transform.position, position) > 1) {
// Subtract the clicked position to the player position
Quaternion newRotation = Quaternion.LookRotation (position - transform.position);
// Disable the rotation from x and z angle
newRotation.x = 0f;
newRotation.z = 0f;
// Rotate the player to a new rotation then move forward
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, Time.deltaTime * attribute.moveSpeed);
controller.SimpleMove(transform.forward * attribute.moveSpeed);
animation.CrossFade(runClip.name);
} else {
animation.CrossFade(idleClip.name);
}
}
}
and here is the script I'm accessing
public class Attributes : MonoBehaviour {
public float moveSpeed;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
I don't know what to do anymore. Any help will be appreciated. Thank you.
There are a couple of things that you need to double check, the first being that you are actually assigning a value to attribute.moveSpeed in the inspector. Otherwise moveSpeed will always be 0 and therefore all of your multiplication operations will result in 0, resulting in no movement at all.
Second, make sure that something is actually being hit by your raycast. You can do this a couple ways, first by printing a message to the console saying that you hit something
// Cast a ray that start from the camera with a distance of 1000
if(Physics.Raycast(ray, out hit, 1000)) {
// Send a debug message to Unity's console
Debug.Log("I hit Something!");
// Store the position if the casted ray is not pointing to the player or enemy's position
if(hit.collider.tag != "Player" && hit.collider.tag != "Enemy") {
position = new Vector3(hit.point.x, hit.point.y, hit.point.z);
}
}
and second by checking that the position variable changed values in the inspector. (Make the position variable public and look at your character's inspector)
Note that you've assigned a value to your attribute variable in the inspector because you're not getting NullReferenceExceptions

Children not following parent

I am making a pokemon clone.
It is a top down tile based rpg.
So I added 4 gameobjects on the player itself. Called up, down, left, right.
I placed them around the player. I use this set up to check if the gameObject up. Is standing on water. If that is true then the player cannot go up. It is my work around for collision. However my children don't want to follow my parent. All I did was I dragged the 4 for gameobjects onto the player, and added this c# script:
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
public LayerMask GroundLayer;
Vector2 startPoint;
Vector2 endPoint;
private float increment;
bool isMoving;
public float speed;
public tk2dTileMap tilemap;
public GameObject up;
public GameObject down;
public GameObject left;
public GameObject right;
void Start()
{
startPoint = transform.position;
endPoint = transform.position;
}
void Update()
{
if (increment <= 1 && isMoving == true)
{
increment += speed / 100;
}
else
{
isMoving = false;
}
if (isMoving)
{
transform.position = Vector2.Lerp(startPoint, endPoint, increment);
}
if (Input.GetKey(KeyCode.UpArrow) && isMoving == false)
{
if (MovementEvents(up) == 0)
{
move(up);
}
}
else if (Input.GetKey(KeyCode.DownArrow) && isMoving == false)
{
if (MovementEvents(down) == 0)
{
move(down);
}
}
else if (Input.GetKey(KeyCode.LeftArrow) && isMoving == false)
{
if (MovementEvents(left) == 0)
{
move(left);
}
}
else if (Input.GetKey(KeyCode.RightArrow) && isMoving == false)
{
if (MovementEvents(right) == 0)
{
move(right);
}
}
}
int MovementEvents(GameObject direction)
{
switch (tilemap.GetTileIdAtPosition(direction.transform.position, 0)) //gettileIdAtPosition returns the id of a tile in this case 0 is grass and 1 is water
{
case 0:
return 0;
default:
return 1;
}
}
void move(GameObject direction)
{
increment = 0;
isMoving = true;
startPoint = transform.position;
endPoint = direction.transform.position;
}
}
I am using 2d toolkit.
I know it is probaly because i am setting them in the wrong way but what am i doing wrong?
You are creating new GameObjects in your script (up, down, etc.) that have no relation to the objects you created in the editor. There are two solutions to this:
1) You need to assign up, down, etc. to the GameObjects you created in the editor. You can do this by editing your Start method to include:
up = GameObject.Find( "up" );
down = GameObject.Find( "down" );
// etc.
Replacing "up" with whatever you named the up GameObject in the editor.
2) Assign up, down, etc. as children to your parent GameObject using
up.transform.parent = parentGameObject.transform;
down.transform.parent = parentGameObject.transform;
// etc.
Note that if you go this route, then the up, down, etc. objects you made in the editor will not be used. You also will need to translate the new objects (after setting their parent) or else they will just sit at (0,0,0) relative to the parent.
Edit in response to the comments
If I am understanding the problem correctly, then it seems you are just making a mistake in how you add the up, down, etc. objects as children in the editor. Simply drag them all onto the parent at the same level:
Then whenever the TestParent object moves, the other objects stay at the same relative position to the parent, and thus move as well. Then if you add the GameObjects to a script like so:
You can move the objects individually (while still being relative to the parent). With the following example script, the parent object moves up (Y+) at one unit a second. The Down object also moves up at an additional one unit per second. This results in the ParentTest, Up, Left, Right maintaining formation, moving one unit per second up, while Down moves at two units per second and slowly moves past them.
using UnityEngine;
using System.Collections;
public class DeleteMe : MonoBehaviour
{
public GameObject Up;
public GameObject Down;
public GameObject Left;
public GameObject Right;
void Start( )
{
}
// Update is called once per frame
void Update( )
{
Move( gameObject );
Move( Down );
}
private void Move( GameObject obj )
{
Vector3 position = obj.transform.position;
position.y += UnityEngine.Time.deltaTime;
obj.transform.position = position;
}
}
A screenshot of them at the start:
Another after some time has elapsed:
Finally note that you do not need to have public GameObjects in the script and then drag-and-drop them onto the script to access children. The same result can be achieved by modifying the script to:
private GameObject Up;
private GameObject Down;
private GameObject Left;
private GameObject Right;
void Start( )
{
Up = transform.Find( "Up" ).gameObject;
Down = transform.Find( "Down" ).gameObject;
Left = transform.Find( "Left" ).gameObject;
Right = transform.Find( "Right" ).gameObject;
}
This prevents the tedious nature of having to drag-and-drop onto the script itself, and also allows you to access children that may be added to the parent dynamically, and thus unable to drag-and-drop.
Hope this has helped!

Categories

Resources