- Home /
Instantiate Side Affects
Hi all, I am having a problem with instantiate. I have a grapple hook enemy which works perfectly in its original gameobject.
When the player gets in the collider the grapple hook enemy shoots out a grapple hook, then brings the player back to the grapple hook enemy's spikes, which damage then release the player.
What is happening is that when the grapple hook enemy is instantiated - it shoots the grapple hook out - then when it should bring the player back in, it teleports the player to the original (I have the original in the scene because I needed to access things from the inspector that were only in the scene, therefore I could not access them if the grapple hook enemy was a prefab).
Here are the scripts...
GrappleHook Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewGrappleScript : MonoBehaviour
{
public Transform target;
public float speed;
public GameObject playerPlace;
public PlayerMovement move;
public PlayerMovement grappleDrag;
private bool moveToTarget;
private bool trigger;
// Use this for initialization
void Awake()
{
trigger = true;
grappleDrag = GetComponent<PlayerMovement>();
move = GetComponent<PlayerMovement>();
}
void OnTriggerEnter2D(Collider2D other)
{
if(other.CompareTag("Player"))
{
playerPlace.GetComponent<PlayerMovement>().move = false;
moveToTarget = true;
}
}
void Update ()
{
if(trigger == true)
{
if (moveToTarget == true)
{
StartCoroutine(MoveToPoint());
}
}
}
IEnumerator MoveToPoint()
{
float waitTime = 0.04f;
while (true)
{
yield return new WaitForSeconds(0.04f);
float step = speed * waitTime;
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
if (transform.position == target.transform.position)
{
Debug.Log("It Works! :D");
trigger = false;
moveToTarget = false;
Invoke("TriggerYes", 6.0f);
Invoke("GoHome",0.0f);
StartCoroutine(MoveBack(1.5f));
yield break;
}
}
}
IEnumerator MoveBack(float time)
{
yield return new WaitForSeconds(time);
float waitTime = 0.04f;
//small number to make it smooth, 0.04 makes it execute 25 times / sec
while (true)
{
yield return new WaitForSeconds(0.04f);
//use WaitForSecondsRealtime if you want it to be unaffected by timescale
float step = speed * waitTime;
transform.Translate(0, Time.deltaTime, 0, Space.Self);
if (transform.localPosition.y == 0) //add a check here or in the "while" to break out of the loop!
{
Invoke("LetGo", 2.0f);
yield break;
}
}
}
void GoHome()
{
playerPlace.GetComponent<PlayerMovement>().grappleDrag = true;
}
void LetGo()
{
playerPlace.GetComponent<PlayerMovement>().move = true;
playerPlace.GetComponent<PlayerMovement>().grappleDrag = false;
}
void TriggerYes()
{
trigger = true;
CancelInvoke("TriggerYes");
}
}
PlayerMovement Script: using UnityEngine; using System.Collections;
public class PlayerMovement : MonoBehaviour
{
Rigidbody2D rbody;
public float speed;
public bool move = true;
public bool grappleDrag = false;
public Transform grapple;
public LookAtPlayer checkGrappleDrag;
void Start ()
{
move = true;
grappleDrag = false;
rbody = GetComponent<Rigidbody2D> ();
}
void Update ()
{
if(move == true)
{
Vector2 movement_vector = new Vector2 (Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
rbody.MovePosition(rbody.position + movement_vector * speed);
transform.localEulerAngles = new Vector3(0, 0, 0);
}
if(grappleDrag == true)
{
GameObject rotateGrapple = GameObject.Find("RotateGrapple");
LookAtPlayer checkGrappleDrag = rotateGrapple.GetComponent<LookAtPlayer>();
checkGrappleDrag.checkGrappleDrag = true;
Invoke("Drag", 0.0f);
}
if(grappleDrag == false)
{
GameObject rotateGrapple = GameObject.Find("RotateGrapple");
LookAtPlayer checkGrappleDrag = rotateGrapple.GetComponent<LookAtPlayer>();
checkGrappleDrag.checkGrappleDrag = false;
CancelInvoke("Drag");
}
}
void Drag()
{
transform.position = Vector3.MoveTowards(grapple.position, grapple.position, 100);
}
}
EDIT: I made this diagram to make it easier to understand.
Figure 1:
other.gameObject.GetComponent<PlayerMovement>().move = false;
float step = hookSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(target.localPosition, transform.position, step);
Invoke("PullBack", 10.0f);
Figure 2:
eject = false;
playerPlaceholder.GetComponent<PlayerMovement>().grappleDrag = true;
float step = hookSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(gEnemy.localPosition, transform.position, step);
Invoke("LetGo", 10.0f);
Figure 3:
CancelInvoke("PullBack");
Debug.Log("You got released");
playerPlaceholder.GetComponent<PlayerMovement>().move = true;
playerPlaceholder.GetComponent<PlayerMovement>().grappleDrag = false;
Thankyou in advance and any help is appreciated.
What jumps out to me first is that you seem to be starting a large amount of coroutines in Update() and I don't think you want/need to do that. You start a new routine in Update
void Update ()
{
if(trigger == true)
{
if (moveToTarget == true)
{
StartCoroutine($$anonymous$$oveToPoint());
I can't see you resetting those variables before you get to
if (transform.position == target.transform.position)
{
Debug.Log("It Works! :D");
trigger = false;
moveToTarget = false;
in the coroutine, which means that for a those couple of seconds (?) you are starting 30-60 new coroutines per second.
That might not be the reason for the other problem though.
Other than that I can't quite see the whole picture. Is Transform target
marking the place where you want the hook to drag the player? Is that field assigned by dragging the "original" enemy into it in the prefab?
I added a diagram to make it easier for you all to understand.
Coroutines are kind of garbage, use them if you want but they will only complicate your code for no good reason. I've almost completed my 2nd Game, 3rd program with Unity and still never found an actual need for a coroutine, they are just a way to move things outside the Update() function. Sometimes I like to multi-thread a system timer to track certain tasks though. All you really need is a single timer and you can make it do callbacks when needed, but that's another level of complex.
What I am seeing here or not seeing, is that I'm not seeing the field "target" ever being set... where does this get set and when?
EDIT: Unity and a lot of tutorials are full of bad coding practices, it is best to assume that every tutorial you read is doing things the worst way possible. Eventually you will craft your own way of doing things.
Well that is definitely a problem then. How would the script know what the new target is if you never set it upon instantiation?
How would I go about doing that because I searched all over the internet and none of the methods worked for me.
Answer by Piyush_Pandey · May 12, 2017 at 08:10 AM
I just read the whole scenario. Made a sample project out of it. Sorry couldn't edit your script to work {lack of time}. This script is the grapple script like you want. I think you can manage others. Please go through it how its working. I tested it in unity and it works fine. I left your public Transform target as it is because you said you need it somewhere and i didn't wanted to confuse you with my variables.
Prerequisites:
1) A demon as parent {nothing on it}
2) Your grapple as its child. Its having Box collider with onTrigger enabled.
3) Player with collider and rigidbody. Its tag name is Player
{if any problem occurs while understanding my code, just make this sample in unity and test it with these prerequisites please}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewGrappleScript : MonoBehaviour
{
public Transform target;
private Transform demon, grapple_hook,hooked_player;
public float speed;
private float step , waitTime= 0.04f;
private bool hook_player_and_drag_him=false;
void Awake()
{
grapple_hook = transform;
}
void Start()
{
demon = grapple_hook.parent;
step = speed * waitTime;
}
void OnTriggerEnter(Collider obj)
{
if (obj.tag == "Player")
{
hooked_player = obj.transform;
hook_player_and_drag_him = true;
}
}
void Update()
{
if (hook_player_and_drag_him)
Dragger();
}
//this will drag the grapple and the enemy
void Dragger()
{
hooked_player.position = Vector3.MoveTowards(hooked_player.position , demon.position ,step);
grapple_hook.position = Vector3.MoveTowards(grapple_hook.position , demon.position ,step);
if (hooked_player.position == demon.position)
hook_player_and_drag_him = false;//stop the drag
}
}