My sprite only flips when it's close to the player - c#

I'm making an enemy in my 2D Unity game, and I was trying to flip the sprite when it faces the opposite direction, the thing is, the sprite would only flip when the player was very close to the enemy. This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMovement : MonoBehaviour
{
public float moveSpeed;
private PlayerMovement player;
public float playerRange;
public LayerMask playerLayer;
public bool playerinRange;
private bool Right = false;
private void Start()
{
player = FindObjectOfType<PlayerMovement>();
}
private void Update()
{
playerinRange = Physics2D.OverlapCircle(transform.position, playerRange, playerLayer);
if (playerinRange)
{
transform.position = Vector3.MoveTowards(transform.position, player.transform.position, moveSpeed * Time.deltaTime);
}
Flip();
}
private void OnDrawGizmosSelected()
{
Gizmos.DrawSphere(transform.position, playerRange);
}
private void Flip()
{
if (transform.position.x > 0 && !Right || transform.position.x < 0 && Right)
{
Right = !Right;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
}

Looking at your code, what's happening is that the direction the enemy is facing is dependent of the position of the enemy in the world (since you are using the x component of transform.position). If your enemy x position is positive, the Right boolean will be true, otherwise it will be false (also the 0 case isn't accounted for).
Since the only thing that can move the enemy in this code snippet is the Vector3.MoveToward when the player is in range, I suspect what's happening is that as your player gets close, the enemy moves and the x position value goes from negative to positive (or the opposite), flipping the sprite.
Now, linking the sprite direction to the enemy's position isn't something you want to do. Instead, you want the enemy to face the direction it is moving toward. This can be done by having a velocity parameter that you use to move your enemy and which will tell you in which direction he is moving (and at which speed) for instance. If you want to keep the move toward, then you need to figure out in which direction it is making you move and flip the sprite accordingly. Here is a code example base on your code:
private void Update()
{
playerinRange = Physics2D.OverlapCircle(transform.position, playerRange, playerLayer);
if (playerinRange)
{
transform.position = Vector3.MoveTowards(transform.position, player.transform.position, moveSpeed * Time.deltaTime);
Flip(player.transform.position.x - transform.position.x);
}
}
private void Flip(float direction)
{
Right = (direction >= 0);
Vector3 theScale = transform.localScale;
theScale.x = Mathf.Abs(theScale.x) * Mathf.Sign(direction);
transform.localScale = theScale;
}

Related

Problems With Collision Detection (OnCollisionEnter2D)

I am starting to make a 2D platformer. I figured out how to make the character jump, but when I tried to add in Collision Detection to make it to where the player can only jump on the ground, it wouldn't work. Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
Vector2 newPosition = new Vector2(0, 7);
float movementSpeed = 5f;
float jumpForce = 10f;
public bool isGrounded;
// Start is called before the first frame update
void Start()
{
GetComponent<Rigidbody2D>().MovePosition(newPosition);
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.A))
{
Vector2 position = this.transform.position;
position.x -= movementSpeed * Time.deltaTime;
this.transform.position = position;
}
if (Input.GetKey(KeyCode.D))
{
Vector2 position = this.transform.position;
position.x += movementSpeed * Time.deltaTime;
this.transform.position = position;
}
if (Input.GetKey(KeyCode.Space) && isGrounded == true)
{
Vector2 position = this.transform.position;
position.y += jumpForce * Time.deltaTime;
this.transform.position = position;
isGrounded = false;
}
}
void OnCollisionEnter2D(Collision2D other)
{
isGrounded = true;
}
}
Sometimes this is problem of the collider that touches the ground. Try to make it higher, lower and try again. I had the same problem once and the solution was just adjusting the collider. Some times the collider is too low, so when you jump it touches the ground again so it becomes true and immediately stops jumping.
No that wont do it. Try adding a Debug.Log(isGrounded) inside OnCollisionEnter2D() so you can see when it happens exactly maybe that will help you. By the way you haven't put any conditions inside the OnCollisionEnter2D() which means anything that enters it's collider will make isGrounded = true; .

With what I should replace dirX for my bullets to shoot right and left

I am doing a 2d game and I want to know how I can make the bullets to shoot right and left . At this moment the bullets go just to the left , even if my player moves right. How I can make them shoot both sides or shoot just when they find an object tagged " enemy "
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class Character : MonoBehaviour
{
Rigidbody2D rb;
float dirX;
[SerializeField]
float moveSpeed = 5f, jumpForce = 400f, bulletSpeed = 500f;
Vector3 localScale;
public Transform barrel;
public Rigidbody2D bullet;
// Use this for initialization
void Start()
{
localScale = transform.localScale;
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
dirX = CrossPlatformInputManager.GetAxis("Horizontal");
if (CrossPlatformInputManager.GetButtonDown("Jump"))
Jump();
if (CrossPlatformInputManager.GetButtonDown("Fire1"))
Fire();
}
void FixedUpdate()
{
rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
}
void Jump()
{
if (rb.velocity.y == 0)
rb.AddForce(Vector2.up * jumpForce);
}
void Fire()
{
var firedBullet = Instantiate(bullet, barrel.position, barrel.rotation);
firedBullet.AddForce(barrel.up * bulletSpeed);
}
}
You're already accounting for the direction of the barrel. You just need to change the direction of the barrel when you move.
One way to do that is to just set that directly:
// Update is called once per frame
void Update()
{
dirX = CrossPlatformInputManager.GetAxis("Horizontal");
if (dirX !=0)
{
barrel.up = Vector3.right * Mathf.Sign(dirX);
}
if (CrossPlatformInputManager.GetButtonDown("Jump"))
Jump();
if (CrossPlatformInputManager.GetButtonDown("Fire1"))
Fire();
}
If the barrel is a child of the player object, then changing the character's rotation so that the barrel's direction points in the correct direction will also work. There's not enough information in the question to know for sure but maybe using Quaternion.LookRotation to set the character's rotation like so would work:
// Update is called once per frame
void Update()
{
dirX = CrossPlatformInputManager.GetAxis("Horizontal");
if (dirX !=0)
{
Vector3 newPlayerForward = Vector3.forward * Mathf.Sign(dirX);
transform.rotation = Quaternion.LookRotation(newPlayerForward, Vector3.up);
}
if (CrossPlatformInputManager.GetButtonDown("Jump"))
Jump();
if (CrossPlatformInputManager.GetButtonDown("Fire1"))
Fire();
}

Animation gets interrupted, but I want the animation to finish

I'm new to coding and I've been playing around with unity and I've encountered a problem.
My problem is, if I move the player and activate the function SkillAttack1, the animation will cancel out and won't complete. Right now, as you see in the code belowif I activate theSkillAttack1`, it works, but still it won't complete the animation. Also, if I'm pressing the "w" button, for example, for 15 seconds the player gets stuck and moves forward. The only way to play the full animation is not moving, but that's not right.
[Animator1][1]
[Animator2][2]
[Animator3][3]
[1]: https://i.stack.imgur.com/BeziY.png
[2]: https://i.stack.imgur.com/310vz.png
[3]: https://i.stack.imgur.com/tOVVu.png
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float velocity = 5;
public float turnSpeed = 10;
Vector2 input;
float angle;
Quaternion targetRotation;
public Transform cam;
public Animator anim;
public bool IsAttacking = false;
void Start()
{
anim = GetComponent<Animator>();
}
void Update()
{
if(Mathf.Abs(input.x) < 0.5 && Mathf.Abs(input.y) < 0.5) return;
CalculateDirection();
Rotate();
Move();
}
void FixedUpdate()
{
if(IsAttacking == false)
{
GetInput();
}
SkillAttack1();
SkillAttack2();
}
/// Input based on Horizontal(a,d) and Vertical (w,s) keys
void GetInput()
{
input.x = Input.GetAxis("Horizontal");
input.y = Input.GetAxis("Vertical");
anim.SetFloat("VelX", input.x);
anim.SetFloat("VelY", input.y);
}
/// Direction relative to the camera rotation
void CalculateDirection()
{
angle = Mathf.Atan2(input.x, input.y);
angle = Mathf.Rad2Deg * angle;
angle += cam.eulerAngles.y;
}
/// Rotate toward the calculated angle
void Rotate()
{
targetRotation = Quaternion.Euler(0, angle, 0);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed
* Time.deltaTime);
}
/// This player only move along its own forward axis
void Move()
{
transform.position += transform.forward * velocity * Time.deltaTime;
}
public void SkillAttack1(){
if(Input.GetKeyDown("1"))
{
IsAttacking = true;
StartCoroutine(OnSkillAttack1());
}
}
public void SkillAttack2()
{
if(Input.GetKeyDown("2"))
{
anim.SetTrigger("SkillAttack2");
}
}
public IEnumerator OnSkillAttack1()
{
anim.SetTrigger("SkillAttack1");
yield return null;
yield return new WaitForSeconds(15.0f);
IsAttacking = false;
}
}
Looks like your animation controller is getting overridden by your movement code, when your player sends some input to walk left or right, it sets the VelX and VelY variables on your animation controller. Without access to your controller I can't tell you exactly why it's interrupting the attack, but it's likely you have an interrupt set up that triggers from "any state" when one of those variables is above 0 and transitions into the "walk" animation your controller has.
You'll need to adjust your animation transitions to handle this potential case, or alternatively, prevent movement code triggering during an attack animation.

Character won't jump in Unity2D but entered the jump statement

I have a little problem with my player control script (C#) in the unity enigne. I worked out the following script with the basic movement of the player. The problem is that the player can enter the jump statement (the debug log printed it out)
Debug Log
but it will not work. The character is still on the ground.
The jump function will be enabled when the player is on the ground (grounded) and did not a double jump.
So my question is are there any "code mistakes" or maybe some configuration problems which I do not see?
Thank you for your help in advance!
using UnityEngine;
using System.Collections;
public class PlayerControl : MonoBehaviour
{
// public variables
public float speed = 3f;
public float jumpHeight = 5f;
// private variables
Vector3 movement;
Animator anim;
Rigidbody2D playerRigidbody;
// variables for the ground check
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool grounded;
private bool doubleJump;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
// Proves if the player is on the ground and activate the double jump function
if (grounded)
{
doubleJump = false;
}
// First line of proving the jump
if (Input.GetMouseButtonDown(0) && grounded)
{
Debug.Log("Jump if entered");
Jump();
}
if (Input.GetMouseButtonDown(0) && !doubleJump && !grounded)
{
Debug.Log("double Jump");
Jump();
doubleJump = true;
}
// Flipping the Player when he runs back
if (Input.GetAxis("Horizontal") < 0)
{
playerRigidbody.transform.localScale = new Vector2(-1.7f, 1.7f);
}
else
{
playerRigidbody.transform.localScale = new Vector2(1.7f, 1.7f);
}
}
void Awake()
{
// References setting up
playerRigidbody = this.GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
void FixedUpdate()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
// simple Movement without a speed control
Move(horizontal, vertical);
Animating(horizontal, vertical);
// Section for ground detection
grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
// Set the parameter for the jump animation false or true
anim.SetBool("Grounded", grounded);
}
void Move(float horizontal, float vertical)
{
movement.Set(horizontal, 0f, vertical);
movement = movement.normalized * speed * Time.deltaTime;
playerRigidbody.MovePosition(transform.position + movement);
}
void Jump()
{
playerRigidbody.AddForce(Vector3.up * jumpHeight);
// playerRigidbody.AddForce(new Vector2(0f, jumpHeight), ForceMode2D.Impulse);
Debug.Log("Jump function");
}
void Animating(float h, float v)
{
bool walking = h != 0f || v != 0f;
anim.SetBool("IsWalking", walking);
}
}
Just guessing here, but maybe Vector3.up does not work for 2D physics? I'm not really into 2D, but you could try
playerRigidbody.AddForce(transform.up * jumpHeight);
instead.
Also, have you tried different values for jumpHeight? 5 might be way to small depending on the mass you set for your rigidbody.
And make sure you haven't restricted any axes in the inspector.
// Note: If you want the object to move in a reliable predictable way but still allow physics interactions, use MovePosition (set the object to kinematic if you want it to be unaffected by physics but still be able to affect other things, and uncheck kinematic if you want both objects to be able to be acted on by physics.
If you want to move your object but let physics handle the finer details, add a force.
playerRigidbody.rigidbody2D.AddForce(Vector3.up * 10 * Time.deltaTime);
use Vector.up, Vector.down, vector.right, Vectore.left along with time.deltaTime to have smooth movement along the frame.

How Do I Shoot a Projectile into the Direction the Player is Facing?

I am creating a 2D side-scroller video game in Unity using c#. I have created the script that makes the player face the direction that the arrow key that was pressed was pointing to (when the right arrow is pressed, the player faces right. When the left arrow is pressed, the player faces left).
However, I cannot figure out how to make the harpoon that the player shoots point in the direction the player is facing. I have found many questions on Stack Overflow asking questions like this, but none of their answers worked for me.
Can anyone please tell me how to make the harpoon the player shoots face the direction the player is facing? Thanks in advance!
Here is my code that I use-
PLAYER SCRIPT
using UnityEngine;
using System.Collections;
public class playerMove : MonoBehaviour {
// All Variables
public float speed = 10;
private Rigidbody2D rigidBody2D;
private GameObject harpoon_00001;
private bool facingRight = true;
void Awake () {
rigidBody2D = GetComponent<Rigidbody2D>();
harpoon_00001 = GameObject.Find("harpoon_00001");
}
void Update () {
if (Input.GetKeyDown(KeyCode.LeftArrow) && !facingRight) {
Flip();
}
if (Input.GetKeyDown(KeyCode.RightArrow) && facingRight) {
Flip();
}
}
void Flip () {
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
void FixedUpdate () {
float xMove = Input.GetAxis("Horizontal");
float yMove = Input.GetAxis("Vertical");
float xSpeed = xMove * speed;
float ySpeed = yMove * speed;
Vector2 newVelocity = new Vector2(xSpeed, ySpeed);
rigidBody2D.velocity = newVelocity;
if (Input.GetKeyDown("space")) {
GetComponent<AudioSource>().Play();
Instantiate(harpoon_00001,transform.position,transform.rotation);
}
}
}
HARPOON SCRIPT
using UnityEngine;
using System.Collections;
public class harpoonScript : MonoBehaviour {
// Public variable
public int speed = 6;
private Rigidbody2D r2d;
// Function called once when the bullet is created
void Start () {
// Get the rigidbody component
r2d = GetComponent<Rigidbody2D>();
// Make the bullet move upward
float ySpeed = 0;
float xSpeed = -8;
Vector2 newVelocity = new Vector2(xSpeed, ySpeed);
r2d.velocity = newVelocity;
}
void Update () {
if (Input.GetKeyDown(KeyCode.LeftArrow)) {
float xSpeed = -8;
}
if (Input.GetKeyDown(KeyCode.RightArrow)) {
float xSpeed = 8;
}
}
void OnTriggerEnter2D(Collider2D other) //hero hits side of enemy
{
Destroy(other.gameObject.GetComponent<Collider2D>()); //Remove collider to avoid audio replaying
other.gameObject.GetComponent<Renderer>().enabled = false; //Make object invisible
Destroy(other.gameObject, 0.626f); //Destroy object when audio is done playing, destroying it before will cause the audio to stop
}
}
You already defining a variable facingRight to know the direction of the the player. You can use that knowledge to control the harpoon.
For example:
// this line creates a new object, which has harpoonScript attached to it.
// In unity editor, you drag and drop this prefab(harpoon_00001) into right place.
// transform.position is used for the starting point of the fire. You can also add +-some_vector3 for better placement
// Quaternion.identity means no rotation.
harpoonScript harpoon = Instantiate(harpoon_00001,transform.position, Quaternion.identity) as harpoonScript;
// Assuming harpoon prefab already facing to right
if (!facingRight) {
// Maybe, not required
harpoon.transform.eulerAngles = new Vector3(0f, 0f, 180f); // Face backward
Vector3 theScale = harpoon.transform.localScale;
theScale.y *= -1;
harpoon.transform.localScale = theScale; // Flip on y axis
}

Categories