so I have this code :
public class ball_physics : MonoBehaviour
{
public Rigidbody ball;
public open2close claw;
public Vector3 offset;
Rigidbody rb;
private float forceMultiplier = 20;
private bool isShoot;
Vector3 start_position;
public path path;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.Sleep();
start_position = transform.position;
}
void Update()
{
// *************
}
void Shoot(Vector3 Force)
{
if (isShoot)
{
print("isshot false");
return;
}
rb.AddForce(new Vector3(Force.x, Force.y,Force.z)* forceMultiplier);
isShoot = true;
path.Instance.HideLine();
}
private void OnTriggerStay(Collider ball)
{
if (isShoot)
{
return;
}
print("ontriggerstay");
if (claw.isClosed && claw.transform.gameObject.tag == "claw" )
{
print("claw");
//rb.Sleep();
transform.position = claw.rightClaw.transform.position + offset;
Vector3 forceInit = (start_position - transform.position);
path.Instance.UpdateTrajectory(forceInit * forceMultiplier, rb, transform.position);
}
}
private void OnTriggerExit(Collider ball)
{
if (claw.isClosed && claw.transform.gameObject.tag == "claw")
{
rb.WakeUp();
}
if (claw.isClosed == false)
{
Shoot(start_position - transform.position);
}
}
}
So on my other codes I have OnStayTrigger, which basically a clawhand grabs a ball and pulls. But this code is suppose to show a trajectory line and shoot. When I shoot the first time it works. But when I try again, The clawhand can grab the ball but it doesnt show the trajectory line nor shoots it. So im guessing this is the code that needs to be fixed. How can I make OnTriggerStay work all the time. I wouldnt want to change any code because it works perfectly. How can I just keep updating the OnTriggerstay so it can work?
At first glance it appears that You never set isShoot back to false, so it would never fire again because in OnTriggerStay you have it return if isShoot = true.
Related
Im currently on a project where i need to detect if an object is in front of an other, so if it's the case the object can't move, because one is in front of it, and if not the object can move.
So im using here a raycast, and if the ray hit something I turn a bool to true. And in my scene, the ray hits but never turning it to true.
I precise that both of my objects as 2D colliders and my raycast is a 2DRaycast, I previously add to tick "Queries Start in colliders" in physics 2D so my ray won't detect the object where I cast it.
Please save me.
Here is my code :
float rayLength = 1f;
private bool freeze = false;
private bool moving = false;
private bool behindSomeone = false;
Rigidbody2D rb2D;
public GameObject cara_sheet;
public GameObject Monster_view;
public GameObject monster;
void Start()
{
rb2D = GetComponent<Rigidbody2D>();
}
void Update()
{
Movement();
DetectQueuePos();
}
private void Movement()
{
if(freeze || behindSomeone)
{
return;
}
if(Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Move");
moving = true;
//transform.Translate(Vector3.up * Time.deltaTime, Space.World);
}
if(moving)
{
transform.Translate(Vector3.up * Time.deltaTime, Space.World);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (!collision.CompareTag("Bar"))
{
return;
}
StartCoroutine(StartFreeze());
}
public void DetectQueuePos()
{
RaycastHit2D hit = Physics2D.Raycast(this.transform.position, this.transform.position + this.transform.up * rayLength, 2f);
Debug.DrawLine(this.transform.position, this.transform.position + this.transform.up * rayLength, Color.red, 2f);
if (hit.collider != null)
{
print(hit.collider.name);
}
if(hit.collider != null)
{
Debug.Log("Behind true");
//Destroy(hit.transform.gameObject);
behindSomeone = true;
}
}
IEnumerator StartFreeze()
{
yield return new WaitForSeconds(1f);
rb2D.constraints = RigidbodyConstraints2D.FreezeAll;
freeze = true;
moving = false;
cara_sheet.SetActive(true);
Monster_view.SetActive(true);
}
While Debug.DrawLine expects a start position and an end position a Physics2D.Raycast expects a start position and a direction.
You are passing in what you copied from the DrawLine
this.transform.position + this.transform.up * rayLength
which is a position, not a direction (or at least it will a completely useless one)! Your debug line and your raycast might go in completely different directions!
In addition to that you let the line have the length rayLength but in your raycasts you pass in 2f.
It should rather be
Physics2D.Raycast(transform.position, transform.up, rayLength)
I've created a "game" where you can attack enemies with a sword. All damages applies to only one enemy, even if i attack the other one. Also when I destroy the first I get this message
MissingReferenceException: The object of type 'RectTransform' has been destroyed but you are still trying to access it.
How do I fix it?
Here's my code:
Attached to the enemy
public class EnemyHealth : MonoBehaviour
{
private Transform healthBar;
private Transform canvas;
public float maxHealth = 100f;
public float damage = 10f;
float currentHealth;
float barLength;
private void Start()
{
currentHealth = maxHealth;
GameObject gfx = gameObject.transform.Find("GFX").gameObject;
canvas = gfx.transform.Find("Health Bar");
GameObject canv = canvas.gameObject;
healthBar = canv.transform.Find("Green Bar");
barLength = canvas.GetComponent<RectTransform>().rect.width * canvas.localScale.x;
}
public void GetStruck()
{
currentHealth -= damage;
if (currentHealth < 0) currentHealth = 0;
healthBar.localScale = new Vector3(currentHealth / maxHealth, 1f, 1f);
Vector3 p = healthBar.position;
p -= damage / (maxHealth * 2) * barLength * transform.right * -1;
healthBar.position = p;
if(currentHealth == 0)
{
Destroy(gameObject);
}
}
}
And the sword attack
using UnityEngine;
public class SwordAttack : MonoBehaviour
{
public Animator animator;
private EnemyHealth enemyHealth;
private bool isAttacking;
private void Start()
{
enemyHealth = GameObject.FindGameObjectWithTag("Enemy").GetComponent<EnemyHealth>();
}
void Update()
{
if(Input.GetMouseButtonDown(0))
{
isAttacking = true;
animator.Play("swordSwing", -1, 0f);
}
else if(animator.GetCurrentAnimatorStateInfo(0).normalizedTime > 1)
{
isAttacking = false;
}
animator.SetBool("isAttacking", isAttacking);
}
private void OnTriggerEnter(Collider other)
{
if(isAttacking && other.CompareTag("Enemy"))
{
enemyHealth.GetStruck();
}
}
}
private void Start()
{
enemyHealth = GameObject.FindGameObjectWithTag("Enemy").GetComponent<EnemyHealth>();
}
This is your mistake. You are only getting 1 enemy's health at your start method and you are always decreasing from that enemy's health. Instead you can get the hitted enemy's health in your OnTriggerEnter method and apply damage to that enemy.
My problem is that I'm making a game with unity, and what I want to do is when the enemy in my game hits the obstacle, it does x damage every one second.
There's a collider and health script on the "desk" obstacle, and a collider and script for movement and attacking on the enemy.
The enemy stops when colliding with the desk object, and does damage! but, the damage is continuous... I've tried coroutines and Invoke's but all the results are the same; 10 damage per trigger detection, not per second.
Here are the scripts:
Enemy movement and attack:
private Animator anim;
public GameObject Desk;
private DeskHealth deskHealth;
//private bool inQueue = false;
private bool collidingWithDesk;
public float timeAfterStart;
[Range(0,10)]
public float attackSpeedEnemy = 1f;
[Range(10,100)]
public float walkSpeed;
[SerializeField] float damageDealtToDesk = 10f;
void Start () {
anim = GetComponent<Animator>();
deskHealth = GetComponent<DeskHealth>();
collidingWithDesk = false;
}
void Update()
{
if (collidingWithDesk == false)
{
enemyIsWalking();
}
}
void enemyIsWalking()
{
transform.Translate(0, 0, (-walkSpeed * Time.deltaTime));
}
IEnumerator enemyIsAttacking()
{
var deskHealth = Desk.GetComponent<DeskHealth>();
deskHealth.DealDamageToDesk(damageDealtToDesk);
yield return new WaitForSeconds(5f);
}
void OnTriggerStay(Collider otherCollider)
{
if (otherCollider.tag == "Desk")
{
collidingWithDesk = true;
transform.Translate(0, 0, 0);
anim.Play("enemyHit");
StartCoroutine(enemyIsAttacking());
}
}
desk Health:
[SerializeField] float deskHealth;
Animator anim;
public void DealDamageToDesk(float deskDamage)
{
deskHealth -= deskDamage;
if (deskHealth <= 0)
{
print("am ded");
//anim.Play("deskDestroyed");
}
}
For what the doc says "OnTriggerStay is called once per physics update for every Collider other that is touching the trigger." Which mean that your code :
if (otherCollider.tag == "Desk")
{
collidingWithDesk = true;
transform.Translate(0, 0, 0);
anim.Play("enemyHit");
StartCoroutine(enemyIsAttacking());
}
will be called every update then pause for 5 seconds because of yield return new WaitForSeconds(5f); You should use OnColliderEnter or it might be even better to use OnTriggerEnter instead, because this one will be called once. Then change the value inside the WaitForSeconds call to 1 if you want it once per second.
Also as specified by Draco18s your yield wait for nothing.
You should do something like that :
IEnumerator enemyIsAttacking()
{
var deskHealth = Desk.GetComponent<DeskHealth>();
while(collidingWithDesk)
{
deskHealth.DealDamageToDesk(damageDealtToDesk);
yield return new WaitForSeconds(1f);
}
}
void OnTriggerExit(Collider otherCollider)
{
if (otherCollider.tag == "Desk")
{
collidingWithDesk = false;
// rest of your code
}
}
Okay to be basic, I have a 2d top down click to move game with a small problem. You see I created my player to have three heart lives and that after you get hit by an object you lose a heart, once you lose a heart the player automatically re-spawn back to where he started. however I'm having problems with player's movement, as mentioned before to move my player you have to click around (click to move). When I click to a place and I get hit by an object my player does go back to where it started off at (which is what I want) but after it reset back to where it was in the beginning, my player would continue to move until it get to the destination (which is not want I want)
This is my player movement's script:
public class PlayerMovement : MonoBehaviour {
private Animator anim;
public float speed = 15f;
private Vector3 target;
public PlayerMovement playerMovementRef;
private bool touched;
void Start () {
target = transform.position;
anim = GetComponent<Animator> ();
}
void Update () {
if (Input.GetMouseButtonDown (0)) {
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = 10; // distance from the camera
target = Camera.main.ScreenToWorldPoint(mousePosition);
target.z = transform.position.z;
}
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
var movementDirection = (target - transform.position).normalized;
if (movementDirection.x != 0 || movementDirection.y != 0) {
anim.SetBool ("walking", false);
anim.SetFloat("SpeedX", movementDirection.x);
anim.SetFloat("SpeedY", movementDirection.y);
anim.SetBool ("walking", true);
}
}
void FixedUpdate () {
float LastInputX = transform.position.x - target.x;
float LastInputY = transform.position.y - target.y;
if (touched) {
if (LastInputX != 0 || LastInputY != 0) {
anim.SetBool ("walking", true);
if (LastInputX < 0) {
anim.SetFloat ("LastMoveX", 1f);
} else if (LastInputX > 0) {
anim.SetFloat ("LastMoveX", -1f);
} else {
anim.SetFloat ("LastMoveX", 0f);
}
if (LastInputY > 0) {
anim.SetFloat ("LastMoveY", 1f);
} else if (LastInputY < 0) {
anim.SetFloat ("LastMoveY", -1f);
} else {
anim.SetFloat ("LastMoveY", 0f);
}
}
}else{
touched = false;
anim.SetBool ("walking", false);
}
}
}
And this is my Player's health script (this script respawns my player back to where it started after he is hit by an object):
public class PlayerHealth : MonoBehaviour {
//Stats
public int curHealth;
public int maxHealth = 3;
Vector3 startPosition;
void Start ()
{
curHealth = maxHealth;
startPosition = transform.position;
}
void Update ()
{
if (curHealth > maxHealth) {
curHealth = maxHealth;
}
if (curHealth <= 0) {
Die ();
}
}
void Die ()
{
//Restart
Application.LoadLevel (Application.loadedLevel);
}
public void Damage(int dmg)
{
curHealth -= dmg;
Reset();
}
void Reset()
{
transform.position = startPosition;
}
}
So when you first click a location that the player walk towards,
Input.GetMouseButtonDown (0) is true, so inside of the if statement you set mousePosition with the following line:
Vector3 mousePosition = Input.mousePosition;
and then you set the target equal to that with
target = Camera.main.ScreenToWorldPoint(mousePosition);
The problem is that outside of the if statement, but within the update method, you have
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
Where the player's postition is continually changed to move towards the target. This is causing the problem because update() is constantly being called, even after you respawn, and if you don't assign the target a different value, your player will still move towards target, which was set before the player dies.
So put simply, target is only set once when you click a place to move, but your character always moves towards target, even after he respawns. Inside of the Start() method, write something like PlayerMovement.target = startPosition
Keep in mind target will either have to be public or have a public getter and setter in order to be able to access it from your health class.
I'm trying to get a player character in a 2D sidescroller to ignore collisions with specific objects in an array when it does a dash action. But my first attempt isn't working. No errors, it just doesn't work. The character still collides with the specific objects while dashing.
private Collider2D col;
public Collider2D[] dashMasks;
void Awake()
{
col = GetComponent<BoxCollider2D>();
dashMasks = GetComponents<Collider2D>();
}
void Update()
{
if(dashing)
{
foreach(Collider2D mask in dashMasks)
{
Physics2D.IgnoreCollision(col, mask);
}
}
}
Did I do the GetComponenets call incorrectly or did I do the IgnoreCollision incorrectly, or maybe both?
OK. I tested your situation and it's working now.
Unity version is 5.1.2f Personal.
Screenshot of the editor. Cube has 'PlayerController', Rigidbody2D, and BoxCollider2D.
Here is the code. If you press Space bar, you can pass Block sprite. If not press, of course you can't pass.
public class PlayerController : MonoBehaviour {
float speed = 5;
bool dashing = false;
BoxCollider2D coll;
BoxCollider2D blockColl;
void Awake() {
coll = this.transform.GetComponent<BoxCollider2D> ();
blockColl = GameObject.Find ("Block").GetComponent<BoxCollider2D> ();
}
void Update()
{
dashing = Input.GetKey (KeyCode.Space);
Physics2D.IgnoreCollision (coll, blockColl, dashing);
}
void FixedUpdate ()
{
float dirX = Input.GetAxis ("Horizontal");
float dirY = Input.GetAxis ("Vertical");
Vector3 movement = new Vector2 (dirX, dirY);
GetComponent<Rigidbody2D> ().velocity = movement * speed;
}
}
I guess you already set dashMasks in the editor.
So you shouldn't set dashMasks in this script again.
private Collider2D col;
public Collider2D[] dashMasks;
void Awake()
{
col = GetComponent<BoxCollider2D>();
//dashMasks = GetComponents<Collider2D>(); // delete it.
}
void Update()
{
if(dashing)
{
foreach(Collider2D mask in dashMasks)
{
Physics2D.IgnoreCollision(col, mask);
}
}
}