UNITY 2D C#
I have a Canvas object.
My Canvas is image (ARROW) that indicates target (STAR).
When a STAR hit the PLAYER,it is destroyed.
Unfortunately, I can not turn off the ARROW and (when STAR respawn) turn on it again, because after appearing ARROW indicates the previous target.
That's why I must to destroy the canvas.
I added a script to the STAR :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyTest : MonoBehaviour {
public SpawnStar other;
public GameObject Spawner;
public GameObject ToDestroy;
void Awake (){
GameObject Spawner = GameObject.Find ("Spawner");
other = Spawner.GetComponent<SpawnStar>();
}
void OnCollisionEnter2D (Collision2D coll){
if (coll.gameObject.tag == "Player") {
Destroy (gameObject);
Debug.Log("DestroyedStar");
GameObject ToDestroy = GameObject.Find ("Window_QuestPointer");
Destroy (ToDestroy);
Debug.Log("DestroyedOptionOne");
other.Start ();
}
}
}
I added a script to the CANVAS:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using CodeMonkey.Utils;
public class Window_QuestPointer : MonoBehaviour {
[SerializeField] private Camera uiCamera;
public SpawnStar other;
public GameObject Spawner;
private Vector3 targetPosition;
private RectTransform pointerRectTransform;
void Awake (){
GameObject Spawner = GameObject.Find ("Spawner");
other = Spawner.GetComponent<SpawnStar>();
other.Start ();
}
private void Start ()
{
targetPosition = GameObject.FindWithTag("Star").transform.position;
pointerRectTransform = transform.Find ("Pointer").GetComponent<RectTransform> ();
}
private void Update (){
Vector3 toPosition = targetPosition;
Vector3 fromPosition = Camera.main.transform.position;
fromPosition.z = 0f;
Vector3 dir = (toPosition - fromPosition).normalized;
float angle = UtilsClass.GetAngleFromVectorFloat(dir);
pointerRectTransform.localEulerAngles = new Vector3 (0, 0, angle);
float borderSize = 40f;
Vector3 targetPositionScreenPoint = Camera.main.WorldToScreenPoint (targetPosition);
bool isOffscreen = targetPositionScreenPoint.x <= borderSize || targetPositionScreenPoint.x >= Screen.width - borderSize || targetPositionScreenPoint.y <= borderSize || targetPositionScreenPoint.y >= Screen.height - borderSize;
Debug.Log (isOffscreen + " " + targetPositionScreenPoint);
if(isOffscreen){
Vector3 cappedTargetScreenPosition = targetPositionScreenPoint;
cappedTargetScreenPosition.x = Mathf.Clamp (cappedTargetScreenPosition.x, borderSize, Screen.width - borderSize);
cappedTargetScreenPosition.y = Mathf.Clamp (cappedTargetScreenPosition.y, borderSize, Screen.height - borderSize);
Vector3 pointerWorldPosition = uiCamera.ScreenToWorldPoint (cappedTargetScreenPosition);
pointerRectTransform.position = pointerWorldPosition;
pointerRectTransform.localPosition = new Vector3 (pointerRectTransform.localPosition.x, pointerRectTransform.localPosition.y, 0f);
}
else{
Vector3 pointerWorldPosition = uiCamera.ScreenToWorldPoint (targetPositionScreenPoint);
pointerRectTransform.position = pointerWorldPosition;
pointerRectTransform.localPosition = new Vector3 (pointerRectTransform.localPosition.x, pointerRectTransform.localPosition.y, 0f);
}
}
}
I added a script to the SPAWNER object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnStar : MonoBehaviour {
private int waveNumber = 0;
public int enemiesAmount = 0;
public GameObject star;
public GameObject option;
public Camera cam;
public GameObject objectToEnable;
// Use this for initialization
public void Start () {
StartCoroutine (StarEnable());
cam = Camera.main;
enemiesAmount = 0;
objectToEnable.SetActive (false);
}
// Update is called once per frame
public IEnumerator StarEnable () {
yield return new WaitForSeconds (10f);
float height = cam.orthographicSize + 1; // now they spawn just outside
float width = cam.orthographicSize * cam.aspect + 1;
if (enemiesAmount==0) {
Instantiate(star, new Vector3(cam.transform.position.x + Random.Range(-width, width),3,cam.transform.position.z+height+Random.Range(10,30)),Quaternion.identity);
enemiesAmount++;
Instantiate (option, transform.position, transform.rotation);
objectToEnable.SetActive (true);
}
}
}
In addition, the ARROW must respawn in the screen and the STAR off the screen.
you shouldn't destroy a canvas or any GameObject during runtime, answering your question, when you Instantiate the canvas prefab, set the renderer camera with
canvas.worldCamera, but you can, instead of destroying your canvas, create a container inside of it put all the GameObjects inside of this GameObject container, and activate and deactivate it when needed.
If you have one camera U can attach simple script which finds Canvas commonent and attach camera to it in Start() for example:
public class AttachCamera: MonoBehavour
{
private void Start()
{
gameObject.GetComponent<Canvas>().worldCamera = Camera.main;
}
}
If there are more than one camera U have to remember attached camera and set it mannualy after Canvas was spawned.
Can you please show your code that is responsible for destroying the Canvas?
I would use another GameObject that handles this gameplay logic.
First, I would use cameraObj.SetActive(false); to disable the camera, and not destroy it. Destroying and Creating objects can cause memory issues sometimes, and it's just not good practice unless absolutely necessary.
Then, use a Coroutine and WaitForSeconds() or something to that effect to wait, and then call cameraObj.SetActive(true) to re-enable your Camera's main GameObject.
Related
OK, I have a particle which is prefabed as it appears on the left of the image below.
The left side is the result of the projectile code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Collider2D))]
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(SpriteRenderer))]
public class Projectile : MonoBehaviour
{
[SerializeField] float velocity;
[SerializeField] float acceleration;
new Collider2D collider;
Rigidbody2D rb;
SpriteRenderer sr;
[SerializeField] LayerMask targetLayer;
[SerializeField] float lifetime;
[SerializeField] float damage;
[SerializeField] ParticleSystem HitEffect;
public event Action<Projectile,Collider2D> OnHit;
public Color Color
{
get
{
return sr.color;
}
set
{
sr.color = value;
}
}
// Start is called before the first frame update
void Start()
{
collider = GetComponent<Collider2D>();
rb = GetComponent<Rigidbody2D>();
sr = GetComponent<SpriteRenderer>();
collider.isTrigger = false;
}
// Update is called once per frame
void Update()
{
lifetime -= Time.deltaTime;
if (lifetime <=0)
{
Destroy(this.gameObject);
}
}
public void SetTargetMask(LayerMask _mask)
{
targetLayer = _mask;
}
public void SetDamage(float amount)
{
this.damage = amount;
}
protected virtual void OnCollisionEnter2D(Collision2D other)
{
var _hitEffect = Instantiate(HitEffect.gameObject, transform).GetComponent<ParticleSystem>();
if (!_hitEffect.isPlaying) _hitEffect.Play();
rb.velocity = Vector2.zero;
collider.isTrigger = true;
sr.enabled = false;
Damageable othersDamage;
other.gameObject.TryGetComponent<Damageable>(out othersDamage);
//Debug.Log("dmg not null: " + (othersDamage != null) + "; presumed layer:" + other.gameObject.layer + "; actual layer:" + targetLayer.value);
if (othersDamage != null && other.gameObject.layer == targetLayer.value)
{
OnHit?.Invoke(this,other.collider);
othersDamage.HandleDamage(damage);
}
Destroy(this.gameObject,HitEffect.main.duration);
}
}
So, the idea is to have the particle as it appears on the left at each contact point, play, and vanish.
Instead, I have a non-animated particle that floats off after hitting the target.
What am I missing to get to play the single explosion at point, and how to get the sub particle to play properly.
What am I missing to get to play the single explosion at point
Either stop the rigidbody completely:
rb.angularVelocity = Vector2.zero;
rb.velocity = Vector2.zero;
Alternately, unparent the hit effect from the projectile, and destroy it after a delay
_hitEffect.transform.SetParent(null);
Destroy(_hitEffect.gameObject,afterDelay);
I have made a car scene in Unity. I have one Rigidbody (car) and its childgameobject. I made a script to move that childgameobject with sliders while Rigidbody is moving. The childgameobject moves fine with the slider but when my Rigidbody moves, the child GameObject remains in the same position and doesn't move with Rigidbody. Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ChildMove : MonoBehaviour
{
public Slider MySliderx;
public Slider MySlidery;
public Slider MySliderz;
public Transform Cam;
public float temp;
private float CamInitialY = 0f;
private float CamInitialX = 0f;
private float CamInitialZ = 0f;
// Use this for initialization
void Start () {
CamInitialY = Cam.transform.position.y;
CamInitialX = Cam.transform.position.x;
CamInitialZ = Cam.transform.position.z;
}
// Update is called once per frame
void Update () {
Cam.transform.position = new Vector3 (Cam.position.x, CamInitialY + MySliderx.value , Cam.position.z);
Cam.transform.position = new Vector3 (CamInitialX + MySlidery.value, Cam.position.y, Cam.position.z);
Cam.transform.position = new Vector3 (Cam.position.x, Cam.position.y, CamInitialZ + MySliderz.value);
}
}
Fixed by changing position to localposition.
I'm a Unity novice and I'm creating a small 2D shooting game on a school project and I already managed to have a functional shooting system in the main character that even bounces off some objects using Unity Physics.
I now wanted to integrate an aim line that will predict the trajectory of the bullet, including the bounces on objects (bubble-shooter style).
I found a script that uses Raycast and Line Renderer and it supposedly does this and I tried to integrate it into my gun script but although it does not give any error, it simply does not show anything when I test the game. I do not know if the problem is in the settings that I put in the Line Renderer Component or it is in the Script.
Could someone help me understand where my error is and point the right way?
My goal is:
My Line Renderer Component Definitions:
My Weapon Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class Weapon : MonoBehaviour
{
[Range(1, 5)]
[SerializeField] private int _maxIterations = 3;
[SerializeField] private float _maxDistance = 10f;
public int _count;
public LineRenderer _line;
public Transform Firepoint;
public GameObject BulletPrefab;
public GameObject FirePrefab;
void Start()
{
_line = GetComponent<LineRenderer>();
}
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Shoot();
}
_count = 0;
_line.SetVertexCount(1);
_line.SetPosition(0, transform.position);
_line.enabled = RayCast(new Ray(transform.position, transform.forward));
}
void Shoot()
{
//shooting logic
var destroyBullet = Instantiate(BulletPrefab, Firepoint.position, Firepoint.rotation);
Destroy(destroyBullet, 10f);
var destroyFire = Instantiate(FirePrefab, Firepoint.position, Firepoint.rotation);
Destroy(destroyFire, 0.3f);
}
private bool RayCast(Ray ray)
{
RaycastHit hit;
if (Physics.Raycast(ray, out hit, _maxDistance) && _count <= _maxIterations - 1)
{
_count++;
var reflectAngle = Vector3.Reflect(ray.direction, hit.normal);
_line.SetVertexCount(_count + 1);
_line.SetPosition(_count, hit.point);
RayCast(new Ray(hit.point, reflectAngle));
return true;
}
_line.SetVertexCount(_count + 2);
_line.SetPosition(_count + 1, ray.GetPoint(_maxDistance));
return false;
}
}
Unity has two physics engines one for 2D and one for 3D. The script you provided relies on the 3D physics engine and won't work for 2D colliders. I edited your script to function with 2D colliders.
Either way make sure that all your game objects use the same physics system. Also the original script only shows the line renderer if it hits something. Best of luck!
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class Weapon : MonoBehaviour
{
[Range(1, 5)]
[SerializeField] private int _maxIterations = 3;
[SerializeField] private float _maxDistance = 10f;
public int _count;
public LineRenderer _line;
public Transform Firepoint;
public GameObject BulletPrefab;
public GameObject FirePrefab;
private void Start()
{
_line = GetComponent<LineRenderer>();
}
// Update is called once per frame
private void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Shoot();
}
_count = 0;
_line.SetVertexCount(1);
_line.SetPosition(0, transform.position);
_line.enabled = true;
RayCast(transform.position, transform.up);
}
private void Shoot()
{
//shooting logic
var destroyBullet = Instantiate(BulletPrefab, Firepoint.position, Firepoint.rotation);
Destroy(destroyBullet, 10f);
var destroyFire = Instantiate(FirePrefab, Firepoint.position, Firepoint.rotation);
Destroy(destroyFire, 0.3f);
}
private bool RayCast(Vector2 position, Vector2 direction)
{
RaycastHit2D hit = Physics2D.Raycast(position, direction, _maxDistance);
if (hit && _count <= _maxIterations - 1)
{
_count++;
var reflectAngle = Vector2.Reflect(direction, hit.normal);
_line.SetVertexCount(_count + 1);
_line.SetPosition(_count, hit.point);
RayCast(hit.point + reflectAngle, reflectAngle);
return true;
}
if (hit == false)
{
_line.SetVertexCount(_count + 2);
_line.SetPosition(_count + 1, position + direction * _maxDistance);
}
return false;
}
}
Well, I changed on the physics material of the bullet, the Friction to 0 and Bounciness to 1. Also on the rigidbody2D the linear drag, angular drag and gravity scale all to 0. Although it is not a perfect rebound it was very close to what I intend for the game. Thank you! Check it out: Game Gif
Only negative thing is that my bullet is not turning in the direction of the movement after the rebound. I tried to use transform.LookAt but didn`t work. This is my bullet script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float speed = 20f;
public Rigidbody2D myRigidbody;
// Start is called before the first frame update
void Start()
{
this.myRigidbody = this.GetComponent<Rigidbody2D>();
this.myRigidbody.velocity = transform.right * speed;
transform.LookAt(transform.position + this.myRigidbody.velocity);
}
}
But now i have this error: Error CS0034 Operator '+' is ambiguous on operands of type 'Vector3' and 'Vector2'
There are 2 GameObjects; a platform and a ball.
The ball is controlled via a custom controller, and the platform moves via an animation.
Components
platform
+ rigidbody
+ box collider
ball
+ rigidbody
+ sphere collider
When the ball comes in contact with the platform, the ball should stop its current velocity and attain the velocity of the platform it is in contact with. However currently, the ball just falls straight through the platform as if there is no colliders attached.
Code of Player:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
public Text winText;
public float speed;
public Text countText;
public GameObject light;
public GameObject player;
private Rigidbody rb;
private int count;
private int a = 0;
private int b = 0;
private int c = 0;
void Start ()
{
rb = GetComponent<Rigidbody>();
count = 0;
SetCountText ();
winText.text = "";
}
void FixedUpdate()
{
if (player.transform.position.y < -15) {
transform.position = new Vector3(a, b, c);
}
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.AddForce (movement * speed );
}
void OnTriggerEnter (Collider other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive (false);
count = count + 1;
SetCountText ();
}
if (other.gameObject.CompareTag ("Check point"))
{
other.gameObject.SetActive (false);
light.gameObject.SetActive (false);
a = 0;
b = -10;
c = 96;
}
}
void SetCountText ()
{
countText.text = "Score: " + count.ToString();
if (count >= 8)
{
winText.text = "You Win!";
}
}
}
You said you are using a custom controller. Please make sure that you are not using Transform() to change the ball's position manually and move your ball as this defies the physics laws in unity. Instead use Rigidbody.MovePosition().
More at Unity docs
Make sure you have all those game objects in same Z axis.
Throw a debug.log() message in your OnCollisionEnter2D() method to see if they are actually colliding.
Could you also check for the type of Colliders you are using.
More Details about Collision in unity :
https://docs.unity3d.com/Manual/CollidersOverview.html
Also if it a custom controller make sure that something is not changing the position of ball to go below the platform.
Fast moving objects need the dynamic ContinuousDynamic or Continuous mode to work reliable
Make sure both rigidbodies are kinetic and the colliders are not triggers. Thats what really worked for me.
i have a turret,as a game object when a enemy enters it's collison box,the turret starts firing towards it,the logic is when the enemy exits the collider,it should stop its firing ,and other problem is that when again an enemy enters the collison box i.e the second enemy,it gives me an exception ,"MissingReferenceException :the object of type 'transform' has been destroyed but you are still trying to access it.Your script should eihter be check if it is null or you should not destroy it",but i am checking if the list in not null in my code.here is my code
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class TurretScript : MonoBehaviour {
public float shotInterval = 0.2f; // interval between shots
public GameObject bulletPrefab; // drag the bullet prefab here
public float bulletSpeed;
private float shootTime = 0.0f;
private List<Transform> targets;
private Transform selectedTarget;
private Transform myTransform;
private Transform bulletSpawn;
void Start(){
targets = new List<Transform>();
selectedTarget = null;
myTransform = transform;
bulletSpawn = transform.Find ("bulletSpawn"); // only works if bulletSpawn is a turret child!
}
void OnTriggerEnter2D(Collider2D other){
if (other.tag == "enemy"){ // only enemies are added to the target list!
targets.Add(other.transform);
}
}
void OnTriggerExit2D(Collider2D other){
if (other.tag == "enemy"){
targets.Remove(other.transform);
Debug.Log("gone out");
}
}
void TargetEnemy(){
if (selectedTarget == null){ // if target destroyed or not selected yet...
SortTargetsByDistance(); // select the closest one
if (targets.Count > 0) selectedTarget = targets[0];
}
}
void SortTargetsByDistance(){
targets.Sort(delegate(Transform t1, Transform t2){
return Vector3.Distance(t1.position, myTransform.position).CompareTo(Vector3.Distance(t2.position, myTransform.position));
});
}
void Update(){
TargetEnemy(); // update the selected target and look at it
if (selectedTarget)
{
// if there's any target in the range...
Vector3 dir = selectedTarget.position - transform.position;
float angle = Mathf.Atan2(dir.y,dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);// aim at it
if (Time.time >= shootTime){// if it's time to shoot...
// shoot in the target direction
Vector3 lookPos = new Vector3(bulletSpawn.position.x,bulletSpawn.position.y,0);
lookPos = lookPos - transform.position;
float ang = Mathf.Atan2(lookPos.y,lookPos.x)*Mathf.Rad2Deg;
GameObject b1 = Instantiate(bulletPrefab,new Vector3(transform.position.x,transform.position.y,5),transform.rotation)as GameObject;
b1.rigidbody2D.velocity = new Vector3(Mathf.Cos(ang*Mathf.Deg2Rad),Mathf.Sin(ang*Mathf.Deg2Rad),0)*bulletSpeed;
shootTime = Time.time + shotInterval; // set time for next shot
}
}
}
}
here is my enemy script
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class EnemyScript : MonoBehaviour {
public Transform target;
public float speed = 2f;
public int Health;
public float GetHealth()
{
return Health;
}
void Update ()
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
void TakeDamage(int damage){
Health -= damage;
if (Health <= 0)
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D otherCollider)
{
PlayerControl shot = otherCollider.gameObject.GetComponent<PlayerControl>();
if (shot != null)
{
SpecialEffectsHelper.Instance.Explosion(transform.position);
Destroy(shot.gameObject);
}
}
}
you need to check if the selected target is the target leaving the collider. You remove the target from the targets list but the selectedTarget var is still populated.
For the null ref exception. Are you using Destroy() to kill the target? Destroy() doesn't cause an OnTriggerExit() or OnCollisionExit() event call, the object is just gone.
edit: you can get around the lack of a call by adding an OnDestroy() function to the dying object that sets it's position to something well outside the level/view of the player. This way the target leaves the collider and then disappears rather than just disappearing in place.