I'm new to Unity and I'm trying to make a drop attack for my character in 2D where if the attack button Z is pressed when the character is jumping, it'll swoop down as a diagonal line like a drop attack. My codes are below,
private Rigidbody2D rb;
private Animator anm;
private Collider2D coll;
private void Movement()
{
float hDir = Input.GetAxis("Horizontal");
if(!anm.GetCurrentAnimatorStateInfo(0).IsTag("attack"))
{
if (hDir < 0)
{
rb.velocity = new Vector2(-speedX, rb.velocity.y);
transform.localScale = new Vector2(-1, 1);
}
else if (hDir > 0)
{
rb.velocity = new Vector2(speedX, rb.velocity.y);
transform.localScale = new Vector2(1, 1);
}
}
else if(anm.GetCurrentAnimatorStateInfo(0).IsTag("attack"))
{
rb.velocity = new Vector2(0, 0);
}
if (Input.GetButtonDown("Jump") && coll.IsTouchingLayers(ground))
{
Jump();
}
}
private void Attack() {
anm.SetTrigger("attack");
if (!coll.IsTouchingLayers(ground)) {
rb.velocity = new Vector2(speedX * Time.deltaTime, rb.velocity.y);
}
}
private void Jump() {
rb.velocity = new Vector2(rb.velocity.x, jumpforce);
state = State.jumping;
}
I think it has something to do at the Attack() function.
Related
I want to code the car's rotation system as I move left and right. I use the following code for this.
float steer = Input.GetAxis("Horizontal");
float finalangel = steer * 45f;
wheelcoll[0].steerAngle = finalangel;
But I want to set it for the phone. When the user touches the screen of the phone and keeps his hand on the screen of the phone, the car goes to the left and stays. When the user removes his hand from the phone, the car returns to its original position. But when doing this process, I want the car to turn in the right direction.
How can I do this?
I tried this too:
[SerializeField] Rigidbody rb;
public Vector3 targetpostion;
public int Speed;
public bool FirstLaneBlueCar;
public bool BlueCar;
public Vector2 Xpos;
public float rotatlerptime;
bool rottrue;
void Start()
{
rottrue = false;
BlueCar = false;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
BlueCar = true;
rottrue = true;
LeftButtonPressed();
}else if (Input.GetMouseButtonUp(0))
{
BlueCar = true;
rottrue = true;
LeftButtonPressed();
}
if (!rottrue)
{
if (transform.position.x <= 4f)
{
Debug.Log(">-.5");
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(0, 0, 0), rotatlerptime * Time.deltaTime);
}
if (transform.position.x >= 3f)
{
Debug.Log(">.5f");
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(0, 0, 0), rotatlerptime * Time.deltaTime);
}
}
}
private void FixedUpdate()
{
transform.Translate(targetpostion, Space.World);
if (BlueCar)
{
if (FirstLaneBlueCar)
{
if (rottrue)
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(0, -60f, 0), rotatlerptime * Time.deltaTime);
Invoke("rot2", .1f);
}
Invoke("left", .1f);
}
else
{
if (rottrue)
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(0, 60f, 0), rotatlerptime * Time.deltaTime);
Invoke("rot2", .1f);
}
Invoke("right", .1f);
}
}
}
public void rot2()
{
rottrue = false;
}
void left()
{
transform.position = Vector3.Lerp(transform.position, new Vector3(-Xpos.y, transform.position.y, transform.position.z), .08f);
}
void right()
{
transform.position = Vector3.Lerp(transform.position, new Vector3(-Xpos.x, transform.position.y, transform.position.z), .08f);
}
public void LeftButtonPressed()
{
if (FirstLaneBlueCar)
{
FirstLaneBlueCar = false;
}
else
{
FirstLaneBlueCar = true;
}
}
You can track the first touch position, and make the respective calculations in the Update method, comparing the previous touch position with the current one.
private void Update()
{
if (Input.touches.Length < 1)
return;
var touch = Input.touches[0];
var deltaPosition = touch.deltaPosition;
// Move the car according to the shift in touch position
}
You can also save the touch ID when the touch has just begun, so you can track the same touch later (user can have multiple fingers on the screen).
Use Touch.fingerId for that.
I have a 2d platformer and there are these enemies with a patrol system as so:
public TextMeshProUGUI m_Object;
public SpriteRenderer sp;
public Transform groundCheck;
bool isFacingRight = true;
RaycastHit2D hit;
private void Update()
{
hit = Physics2D.Raycast(groundCheck.position, -transform.up, 1f, groundLayers);
}
private void FixedUpdate()
{
if(hit.collider != false)
{
if (isFacingRight)
{
rb.velocity = new Vector2(speed, rb.velocity.y);
}
else
{
rb.velocity = new Vector2(-speed, rb.velocity.y);
}
}
else
{
isFacingRight = !isFacingRight;
sp.transform.localScale = new Vector3(-transform.localScale.x, 1f, 1f);
Debug.Log(transform.localScale.x);
float placeholder = sp.transform.localScale.x;
m_Object.transform.localScale = new Vector3(placeholder, 1f, 1f);
Debug.Log(m_Object.transform.localScale.x);
}
}
In the end part I am trying to flip the text so it stays facing the logical way however it is not working since when it hits the edge the text disappears and when it its the other edge the text comes back.
Any Ideas would be appreciated.
I am trying to make a simple pong game where once the player or the enemy scores both of them get repositioned on the field.
I have this script on the enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyBehavior : MonoBehaviour
{
Vector3 ballPosition;
Vector3 paddlePosition;
float movementSpeed = 0.1f;
public Transform target;
public float maxAngle = 35.0f;
private Quaternion baseRotation;
private Quaternion targetRotation;
// Start is called before the first frame update
void Start()
{
baseRotation = transform.rotation;
}
// Update is called once per frame
void Update()
{
ballPosition = GameObject.Find("Ball").transform.position;
paddlePosition = this.transform.position;
if (paddlePosition.z < ballPosition.z)
{
paddlePosition.z += movementSpeed;
}
else if (paddlePosition.z > ballPosition.z)
{
paddlePosition.z -= movementSpeed;
}
transform.position = paddlePosition;
Vector3 look = target.transform.position - transform.position;
look.z = 0;
Quaternion q = Quaternion.LookRotation(look);
if (Quaternion.Angle(q, baseRotation) <= maxAngle)
{
targetRotation = q;
}
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2.0f);
}
}
And then a goal script attached to the goal that looks like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Goal : MonoBehaviour
{
public GameObject Ball;
public GameObject Player;
public GameObject Enemy;
public Text Player2Score;
public Text Player1Score;
int Player2ScoreText = 0;
int Player1ScoreText = 0;
Rigidbody ballrig;
Rigidbody playerrig;
Rigidbody enemyrig;
public ParticleSystem Particles;
float timeLeft = 1.0f;
public bool slowMo = false;
// Start is called before the first frame update
void Start()
{
ballrig = Ball.GetComponent<Rigidbody>();
playerrig = Player.GetComponent<Rigidbody>();
enemyrig = Enemy.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (slowMo == true)
{
timeLeft -= Time.deltaTime;
if (timeLeft < 0)
{
slowMo = false;
timeLeft = 1.0f;
Time.timeScale = 1f;
}
}
}
private void OnTriggerEnter(Collider other)
{
if (other.name == "Ball" && name == "Player_Goal")
{
slowMo = true;
Time.timeScale = 0.5f;
Explode();
Player2ScoreText += 1;
Player2Score.text = ("" + Player2ScoreText);
Ball.transform.position = new Vector3(0f, 4f, 0f);
Player.transform.position = new Vector3(-20f, 2f, 0f);
Enemy.transform.position = new Vector3(20f, 2f, 0f);
ballrig.velocity = Vector3.zero;
ballrig.angularVelocity = Vector3.zero;
playerrig.velocity = Vector3.zero;
playerrig.angularVelocity = Vector3.zero;
enemyrig.velocity = Vector3.zero;
enemyrig.angularVelocity = Vector3.zero;
int whoGetsIt = Random.Range(0, 2);
if (whoGetsIt >= 1)
{
Vector3 Impulse = new Vector3(-10f, 5f, Random.Range(-10f, 10f));
Ball.GetComponent<Rigidbody>().AddForce(Impulse, ForceMode.Impulse);
}
else
{
Vector3 Impulse = new Vector3(10f, 0f, Random.Range(-10f, 10f));
Ball.GetComponent<Rigidbody>().AddForce(Impulse, ForceMode.Impulse);
}
}
else if (other.name == "Ball" && name == "Enemy_Goal")
{
slowMo = true;
Time.timeScale = 0.5f;
Explode();
Player1ScoreText += 1;
Player1Score.text = ("" + Player1ScoreText);
Ball.transform.position = new Vector3(0f, 4f, 0f);
Player.transform.position = new Vector3(-20f, 2f, 0f);
Enemy.transform.position = new Vector3(20f, 2f, 0f);
ballrig.velocity = Vector3.zero;
ballrig.angularVelocity = Vector3.zero;
playerrig.velocity = Vector3.zero;
playerrig.angularVelocity = Vector3.zero;
enemyrig.velocity = Vector3.zero;
enemyrig.angularVelocity = Vector3.zero;
int whoGetsIt = Random.Range(0, 2);
if (whoGetsIt >= 1)
{
Vector3 Impulse = new Vector3(-10f, 5f, Random.Range(-10f, 10f));
Ball.GetComponent<Rigidbody>().AddForce(Impulse, ForceMode.Impulse);
}
else
{
Vector3 Impulse = new Vector3(10f, 0f, Random.Range(-10f, 10f));
Ball.GetComponent<Rigidbody>().AddForce(Impulse, ForceMode.Impulse);
}
}
}
void Explode()
{
Particles.Play();
}
}
Now the ball gets repositioned correctly after someone scores but for some reason the player and the enemy do not.
Is it because they both have code in their update function so that code "overwrights" the repositioned command? And if so how can I get around that?
I can see that your players are using Rigidbody or Rigidbody2D.
Whenever a rigidbody is involved you should not set any position via transform but rather use the according rigidbody methods like MovePosition and MoveRotation or for directly setting them go through Rigibody.position and Rigidbody.rotation e.g.
....
slowMo = true;
Time.timeScale = 0.5f;
Explode();
Player2ScoreText += 1;
Player2Score.text = ("" + Player2ScoreText);
Ball.GetComponent<Rigidbody>().position = new Vector3(0f, 4f, 0f);
Player.GetComponent<Rigidbody>().position = new Vector3(-20f, 2f, 0f);
Enemy.GetComponent<Rigidbody>().position = new Vector3(20f, 2f, 0f);
ballrig.velocity = Vector3.zero;
ballrig.angularVelocity = Vector3.zero;
playerrig.velocity = Vector3.zero;
playerrig.angularVelocity = Vector3.zero;
enemyrig.velocity = Vector3.zero;
enemyrig.angularVelocity = Vector3.zero;
int whoGetsIt = Random.Range(0, 2);
....
And then also in the EnemyBehaviour -> It should be FixedUpdate and look like
public Rigidbody target;
Rigidbody ball;
Rigidbody ownRigidbody;
void Start()
{
baseRotation = transform.rotation;
// Get reference only ONCE and store them1
ball = GameObject.Find("Ball").GetComponent<Rigidbody>();
ownRigidbody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
ballPosition = ball.position;
paddlePosition = ownRigidbody.position;
if (paddlePosition.z < ballPosition.z)
{
paddlePosition.z += movementSpeed;
}
else if (paddlePosition.z > ballPosition.z)
{
paddlePosition.z -= movementSpeed;
}
ownRigidbody.MovePosition(paddlePosition;)
Vector3 look = target.position - ownRigidbody.position;
look.z = 0;
Quaternion q = Quaternion.LookRotation(look);
if (Quaternion.Angle(q, baseRotation) <= maxAngle)
{
targetRotation = q;
}
ownRigidbody.MoveRotation(Quaternion.Slerp(ownRigidbody.rotation, targetRotation, Time.deltaTime * 2.0f));
}
since here you want smooth interpolated position
I'm pretty new to all of this so sorry for rookie mistakes. I'm making a 2D platformer
I am checking for ground via RayCast and right after the player jumps, the jumpCounter resets to 0, so I get a bonus jump. I tried adding a 0.2s timer before it can reset but that caused trouble when jumping multiple times in a row (bunny hopping). Any help?
private void FixedUpdate()
{
GroundCheck();
if (state != State.hurt)
{
Movement();
DoubleJump();
StateMachine();
}
HurtCheck();
anim.SetInteger("state", (int)state);
}
private void Movement()
{
//Input.GetAxis returns a value between -1 up to 1
//Edit> Project Settings> Input> Axis> Horizontal
float hDirection = Input.GetAxisRaw("Horizontal");
//holding down "D" makes the value positive and vice versa
if (hDirection < 0)
{
rb.velocity = new Vector2(-speed, rb.velocity.y);
transform.localScale = new Vector2(-1, 1);
}
else if (hDirection > 0)
{
rb.velocity = new Vector2(speed, rb.velocity.y);
transform.localScale = new Vector2(1, 1);
}
else
{
}
if (Input.GetButtonDown("Jump") && isGrounded == true)
{
Jump();
}
}
private void Jump()
{
rb.velocity = new Vector2(rb.velocity.x, jumpforce);
state = State.jumping;
jumpCount += 1;
}
private void GroundCheck()
{
Debug.DrawRay(transform.position, Vector2.down * hitDistance, Color.green);
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, hitDistance, ground);
if(hit.collider != null)
{
isGrounded = true;
jumpCount = 0;
}
else
{
isGrounded = false;
}
}
private void DoubleJump()
{
if (Input.GetButtonDown("Jump") && isGrounded == false && jumpCount < 2)
{
rb.velocity = new Vector2(rb.velocity.x, jumpforce);
jumpCount += 1;
}
}
Hey Have you made sure your player's layer isn't ground layer or set ground layermask properly or maybe the hitDistance for the raycast is too high it should be very low like 0.1 or less or does jumpCount start from 0 or 1 try and alternate that or maybe have it start from two to lose the extra bonus jump...These would be where I would look, Good luck!
I'm making a 2D platformer in Unity, and made a patrolling enemy with code from a tutorial video. The enemy basically moves randomly to different spots in the scene. But how can I make the sprite turn around?
This is my code so far. I've tried with different approaches, but not getting the expected behavior.
public float speed = 10f;
private float waitTime;
public float startWaitTime = 1f;
public Transform[] moveSpots;
private int randomSpot;
private bool moving = true;
private bool m_FacingRight = true;
void Start()
{
waitTime = startWaitTime;
randomSpot = Random.Range(0, moveSpots.Length);
}
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, speed * Time.deltaTime);
if (Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.2f)
{
//Debug.Log(m_FacingRight);
// if (moving.x > 0 && !m_FacingRight)
// {
// Debug.Log("moving right");
// Flip();
// }
// else if (moving.x < 0 && m_FacingRight)
// {
// Debug.Log("moving left");
// Flip();
// }
if (waitTime <= 0)
{
//moving = true;
randomSpot = Random.Range(0, moveSpots.Length);
waitTime = startWaitTime;
}
else
{
//moving = false;
waitTime -= Time.deltaTime;
}
}
}
//private void Flip()
//{
//m_FacingRight = !m_FacingRight;
//transform.Rotate(0f, 180f, 0f);
//}
**********************************EDIT****************************************
I ended up with this for the enemy script movement
private bool facingRight = true;
private Rigidbody2D rigidBody2D;
private SpriteRenderer spriteRenderer;
public Vector2 speed = new Vector2(10, 0);
public Vector2 direction = new Vector2(1, 0);
private void Awake()
{
rigidBody2D = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.collider.CompareTag("Wall") || collision.collider.CompareTag("Player"))
{
direction = Vector2.Scale(direction, new Vector2(-1, 0));
}
if (!collision.collider.CompareTag("Ground"))
{
if (!facingRight)
{
Flip();
}
else if (facingRight)
{
Flip();
}
}
}
void FixedUpdate()
{
Vector2 movement = new Vector2(speed.x * direction.x, 0);
movement *= Time.deltaTime;
transform.Translate(movement);
}
private void Flip()
{
facingRight = !facingRight;
if (!facingRight)
{
spriteRenderer.flipX = true;
}
else if (facingRight)
{
spriteRenderer.flipX = false;
}
}
Rewrite your Flip function to
private void Flip()
{
m_FacingRight = !m_FacingRight;
GetComponent<SpriteRenderer>().flipX = true;
}
Also, if you're looking for a reference, I made a platformer in Unity that includes enemy patrolling https://github.com/sean244/Braid-Clone
In a sidescroller, an easy way to achieve this is to use SpriteRenderer.flipX.
For instance, if you want to flip X when the velocity is negative:
var sr = GetComponent<SpriteRenderer>();
sr.flipX = velocity.x < 0;