There is a strange behavior when my spaceship fires off some missiles to destroy an enemy. Under certain circumstances, the missiles "jump" and fly away.
This seems to happen when the nearest enemy is destroyed by one missile and all others have no target any more. Then they "jump" and fly away (off the screen).
I still don't know the cause of this problem.
void Start () {
rb = this.GetComponent<Rigidbody2D>();
nearestEnemy = FindClosestTarget("EnemyShipTag");
}
Getting the closest target (enemy)
GameObject FindClosestTarget(string _target) {
enemies = GameObject.FindGameObjectsWithTag(_target);
closest = null;
distance = Mathf.Infinity;
_position = this.transform.position;
foreach (GameObject enemy in enemies) {
diff = enemy.transform.position - _position;
curDistance = diff.sqrMagnitude;
if (curDistance < distance) {
closest = enemy;
distance = curDistance;
}
}
return closest;
}
Calculate movement to nearest enemy if nearestEnemy is not null
void FixedUpdate () {
if (nearestEnemy != null) {//is enemy available?
Vector2 enemyTarget = nearestEnemy.transform.position;
Vector2 direction = (Vector2)enemyTarget - rb.position;
direction.Normalize ();
float rotateAmount = Vector3.Cross (direction, transform.up).z;
rb.angularVelocity = -rotateAmount * rotateSpeed;
float speed = 6f;
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, nearestEnemy.transform.position, step);
} else {
//rocket shall fly straight ahead if there's no target
rb.velocity = transform.up * speed;
}
These functions are part of the EnemyControl.cs-script
void OnTriggerEnter2D (Collider2D col) {//this function will trigger when there is a collision of our game objects
//detect collision of the enemy ship with the player ship, or with a player's bullet
if ((col.tag == "PlayerShipTag") || (col.tag == "MissileUpgradeTag")) {
EnemyDestroyed ();
}
void EnemyDestroyed () {
Destroy (gameObject);//Destroy the enemy ship
dead = true;
PlayerControl.enemiesDestroyed++;
}
Related
So, Hey guys I am new to unity. I have a small doubt. I have a player who is a child of the topcube in a 3 stackcube placed upon eachother.
These cubes have a target position to move once the user clicks on them.
Like imagine there are 3 points in my world. POINT A with location coordinates as(0,0,1),POINT B with (0,0,2),POINT C with (0,0,3) and the 3 stack cube is place on (0,0,0) with the player attached as a child to topcube in that 3stackcube.
All these points(A,B,C) has a script called targetpoint with a variable bool isFilled(default as false) in them which becomes true when one of the cube reaches to its target position.
Further im checking whenever the cubes reaches their target position make isFilled true and check to see if there is a child attached if yes get the animator of the child and trigger jump animation. The jump animation is an inplace animation.
So I want to programmatically move my character +1 towards the direction he is facing (if he is facing z move + 1 in z, if x move +1 in x like this)when the cube he is attached reached its target position while also playing jump animation.
I did a code. it doesnt seem to be working. And sorry for huge paragraphs. Im totally new to coding and asking doubts. Any help will be helpful thanks.
[SerializeField] public List<targetpoint> waypoints;
[SerializeField] float moveSpeed = 2f;
[SerializeField] AudioClip[] surferSounds;
[SerializeField] GameObject particleToPlay;
int waypointIndex = 0;
float t;
//Cached Reference
AudioSource audioSource;
//State
public bool move = false;
void Start()
{
transform.position = this.transform.position;
t = 0f;
}
void FixedUpdate()
{
if (move == true)
{
MoveTarget();
}
}
void MoveTarget()
{
//Time.timeScale = 0.1f;
if (waypointIndex <= waypoints.Count - 1)
{
var targetPosition = waypoints[waypointIndex].transform.position;
transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
if (transform.position == targetPosition)
{
//Debug.Log(t);
if (waypoints[waypointIndex].isFilled == false)
{
waypoints[waypointIndex].isFilled = true;
AudioClip clip = surferSounds[UnityEngine.Random.Range(0, surferSounds.Length)];
var storeToDestroy = Instantiate(particleToPlay, targetPosition, Quaternion.identity);
Destroy(storeToDestroy , 5f);
audioSource.PlayOneShot(clip);
move = false;
}
else if(waypoints[waypointIndex].isFilled == true)
{
waypointIndex++;
targetPosition = waypoints[waypointIndex].transform.position;
transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
}
if (this.gameObject.transform.childCount > 0)
{
var storeChild = gameObject.transform.GetChild(1).gameObject;
StartCoroutine(GravityAndJump(storeChild,storeChild.transform.position+1*transform.forward,1f));
}
else
{
return;
}
}
}
}
IEnumerator GravityAndJump(GameObject child, Vector3 newPosition , float time)
{
var elapsedTime = 0f;
var startingPosition = child.transform.position;
while(elapsedTime < time)
{
child.GetComponent<Animator>().SetTrigger("shouldJump?");
child.transform.position = Vector3.Lerp(startingPosition, newPosition, (elapsedTime / time));
elapsedTime += Time.deltaTime;
yield return null;
}
//storeChild.GetComponent<Animator>().SetFloat("JumpSpeed", 1f);
//yield return new WaitForSeconds(1f);
//gameObject.GetComponentInChildren<Rigidbody>().useGravity = true;
}
}
So I want to programmatically move my character +1 towards the direction he is facing (if he is facing z move + 1 in z, if x move +1 in x like this)
You can get the forward direction for a GameObject using with transform.forward you can use this to calculate target position in front of the GameObject.
Set target position some distance in front of the transform
targetPosition = transform.position + (transform.forward * distance);
Move towards target position at some speed.
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * followSpeed);
Determining arrival to targetPosition
When it comes to determining if transform has arrive to target destination you should measure the distance instead of comparing that the vectors are the same.
So replace this:
if (transform.position == targetPosition){}
With something like this:
if(Vector3.Distance(transform.position, targetPosition) < .001f){
transform.position = targetPosition;
}
Unless you strictly set two vectors to same values it's likely that they will never be considered equal due to how floating point numbers work.
I have a cloud which has a polygon collider 2d attached. Also, I have a player that has a box collider 2d attached. When the player lands on the cloud, at some point during the movement, something is stopping him. He is animating but he does not move.
Below is the image of my colliders:
When I start running the game, he moves left and right. So I figured it is not a code issue. At a point, he is stuck at the above position and he cannot move right but he can move left. I guess the polygon collider is stopping him from free movement. When I go back, he is walking and when the reaches the above position, he cannot move forward.
Is there any workaround for this?
Below is my code:
public class Player : MonoBehaviour
{
public float speed = 7f;
public float maxVelocity = 8f;
private Rigidbody2D rb;
private Animator anim;
void Awake()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void FixedUpdate()
{
MovePlayerUsingKeyboard();
}
public void MovePlayerUsingKeyboard()
{
float forceX = 0f;
float velocity = Mathf.Abs(rb.velocity.x);
Debug.Log("Player Velocity : " + velocity);
float direction = Input.GetAxis("Horizontal");
if (direction < 0)
{
if (maxVelocity > velocity)
{
anim.SetBool("Walk", true);
forceX = -speed;
}
//Changing the direction the player faces
Vector3 temp = transform.localScale;
temp.x = -1.3f;
transform.localScale = temp;
}
else if (direction > 0)
{
if (maxVelocity > velocity)
{
anim.SetBool("Walk", true);
forceX = speed;
}
Vector3 temp = transform.localScale;
temp.x = 1.3f;
transform.localScale = temp;
}
else
{
anim.SetBool("Walk", false);
}
rb.AddForce(new Vector2(forceX, 0));
}
}
I think it is because that the collider of your character is stuck at the bumpy part of the cloud's polygon collider.
A solution is to change the character's collider to semi-capsule collider or capsule collider so that the character can walk smoothly on some rough surfaces.
I'm trying to write a script for my enemy movements. Here is my code:
public class EnemiesMovement : MonoBehaviour
{
private bool isFacingRight = false;
public float speed = 10f;
private float startPoint;
private float endPoint;
public float unitMovement = 2f;
private Rigidbody2D enemy;
private Animator anim;
bool moveRight;
// Start is called before the first frame update
void Start()
{
enemy = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
startPoint = enemy.position.x;
endPoint = startPoint + unitMovement;
}
// Update is called once per frame
void Update()
{
if (enemy.position.x >= endPoint)
moveRight = false;
if (enemy.position.x <= startPoint)
moveRight = true;
if (moveRight)
{
enemy.velocity = new Vector2(-transform.localScale.x, 0) * speed;
if (!isFacingRight)
Flip();
}
if (!moveRight)
{
enemy.velocity = new Vector2(transform.localScale.x, 0) * speed;
if (isFacingRight)
Flip();
}
}
void Flip()
{
isFacingRight = !isFacingRight;
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
}
}
The movement of the enemy is right, but after the enemy flips its sprites, it doesn't change the direction of its movement. Basically, it continues to the right, even though its sprite has turned left. Can someone show me how I can fix this?
My enemy spite has a positive scale facing to the left.
Velocity is affected by the scale property.
So if you change the scale negative, everything on this GameObject flips, it's not necessary to change the velocity direction.
Are you getting bewildered? You can try another method to flip the sprite.
GetComponent<SpriteRenderer>().flipX = true;
This only flips the sprite renderer, other things are working as normal in its world space.
Another suggests as Unity documented it's better to change Rigidbody's property in the FixedUpdate.
I'm making a 2D game with two sides, left and right, so the player can only move to the left or right or jump. I made an AI as the enemy. The AI is working fine. He can go to the player to kill him.
The problem is the enemy can't rotate or face the player when he goes to kill him. I want the AI to look at the player. When the player is to the left of the enemy, the enemy should rotate to the left to look at the player. I searched many websites and I didn't get any correct solution. This is my enemy script:
public class enemy : MonoBehaviour
{
public float speed;
private Animator animvar;
private Transform target;
public GameObject effect;
public float distance;
private bool movingRight = true;
public Transform groundedDetection;
public float moveInput;
public bool facingRight = true;
void Start()
{
animvar = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Player").transform;
}
// Update is called once per frame
void Update()
{
if (Vector3.Distance(target.position, transform.position) < 20)
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
else
{
transform.Translate(Vector2.right * speed * Time.deltaTime);
}
RaycastHit2D groundInfo = Physics2D.Raycast(groundedDetection.position, Vector2.down, distance);
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag.Equals("danger"))
{
Instantiate(effect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
if (col.gameObject.tag.Equals("Player"))
{
Instantiate(effect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
}
The game is 2D, left, right, with jump using Unity3D.
You need a function that would flip your sprite, you can do that by changing the scale of the transform, and keep a boolean to check where it's facing
bool facingRight;, so something like this
void Flip(){
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
facingRight = !facingRight;
}
and in your Update check if it needs to be flipped or not
if (Vector3.Distance(target.position,transform.position)<20)
{
transform.position=Vector2.MoveTowards(transform.position, target.position,speed*Time.deltaTime);
if(target.position.x > transform.position.x && !facingRight) //if the target is to the right of enemy and the enemy is not facing right
Flip();
if(target.position.x < transform.position.x && facingRight)
Flip();
}
Its simple enough, just get the Player x position and compare to Enemy's x position, then flip the enemy sprite accordingly
This is my Update() method in my Enemy script. This handles enemy movement and changing direction the sprite is facing:
if (moveRight )
{
transform.Translate(2 * Time.deltaTime * moveSpeed, 0, 0);
transform.localScale = new Vector2(6, 6); //6,6 is just a size that suits my sprite
}
else if (!moveRight)
{
transform.Translate(-2 * Time.deltaTime * moveSpeed, 0, 0);
transform.localScale = new Vector2(-6, 6);
}
This is my enemy Attack() method , I compare the Player X position to Enemy X position. If Player X is less( to the left of the Enemy), I flip the Enemy sprite to negative
if (transform.position.x > Player.position.x)
{
transform.localScale = new Vector2(-6, 6);
}
else if (transform.position.x < Player.position.x)
{
transform.localScale = new Vector2(6, 6);
}
So here's the problem in video form
https://pbs.twimg.com/tweet_video/CPsvjgbWoAACKCp.mp4
When not moving the ship the shield moves around just fine, but when you start moving it can only drag behind you and move a little bit, which is just no good at all. I can't figure out what I've done wrong here!
public class ShieldMovement : MonoBehaviour {
public Transform target; //player shield is attaced to
public float circSpeed = 0.1f; // Speed Shield moves around ship
private Vector3 direction = Vector3.up;
private float distance = 0.8f; // distance from player so it doesn't clip
private float deadzone = 0.15f;
private float separation;
private bool canMove = true;
private Vector3 shipPos;
private Rigidbody2D tRB;
private Rigidbody2D rb;
// Use this for initialization
void Start ()
{
tRB = target.GetComponent<Rigidbody2D>();
rb = GetComponent<Rigidbody2D>();
}
void OnCollisionEnter2D (Collision2D other)
{
canMove = false;
}
void OnCollisionStay2d(Collision2D other)
{
canMove = false;
}
void OnCollisionExit2D (Collision2D other)
{
canMove = true;
}
// Update is called once per frame
void Update () {
float rh = Input.GetAxisRaw("rightH");
float rv = Input.GetAxisRaw("rightV");
shipPos = target.position;
separation = Mathf.Abs((transform.position - shipPos).magnitude);
if(Mathf.Abs(rh) > deadzone || Mathf.Abs(rv) > deadzone)
{
Vector3 targetDir = new Vector3(rh, rv, 0.0f);
direction = Vector3.Slerp(transform.position-shipPos, targetDir, circSpeed);
}
Ray ray = new Ray(shipPos, direction); // cast ray in direction of point on circle shield is to go
if(canMove)
{
transform.position = ray.GetPoint(distance); //move shield to the ray as far as the distance
}
if(separation != distance) //If the shield get torn away from the ship
{
transform.position = ray.GetPoint(distance); //move shield to the ray as far as the distance
}
float angleY = transform.position.y - shipPos.y;
float angleX = -(transform.position.x - shipPos.x);
float angle = Mathf.Atan2 (angleY, angleX) * Mathf.Rad2Deg-90; //Get angle
if(Mathf.Abs(rh) > deadzone || Mathf.Abs(rv) > deadzone)
{
transform.rotation = Quaternion.AngleAxis(angle,Vector3.forward*-1); // keep shield facing outwards in respect to player
}
}
void FixedUpdate ()
{
if(!canMove)
{
tRB.velocity = new Vector2(0.0f, 0.0f);
rb.velocity = new Vector2(0.0f, 0.0f);
}
}
Thanks a million for any help :)
You need to move the shield along with the ship. You can do this by adding the ship velocity to the shield.
Something like:
shipPos = target.position;
transform.position += shipVelocity;
separation = Mathf.Abs((transform.position - shipPos).magnitude);
Or make the shield a child object of the ship.
OK, so all I needed to do was to make the shield a child AND get rid of the conditional statement around the transform.rotation so it wouldn't inherit the parent rotation and ruin the shield. It's the little things!