My character is animating but still not moving - c#

I am just starting out with unity and am also making a game for a school project. My 2d game character can do the walk animation when I press the "a" and "d" keys and the sprite flips, but it stays in the same position. Below is my PlayerController script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private float speed = 3f;
private Animator anim;
private SpriteRenderer sr;
// Start is called before the first frame update
void Awake()
{
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
Move();
}
void Move()
{
float h = Input.GetAxisRaw("Horizontal");
Vector3 temp = transform.position;
if (h > 0)
{
temp.x += speed * Time.deltaTime;
sr.flipX = true;
anim.SetBool("Walk", true);
}
else if (h < 0)
{
temp.x -= speed * Time.deltaTime;
sr.flipX = false;
anim.SetBool("Walk", true);
}
else if (h == 0)
{
anim.SetBool("Walk", false);
}
}
}

You're setting 'temp' to equal transform.position, but that doesn't mean that transform.position equals 'temp'. Here, the below script should give you what you want
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private float speed = 3f;
private Animator anim;
private SpriteRenderer sr;
void Awake()
{
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
void Update()
{
Move();
}
void Move()
{
float h = Input.GetAxisRaw("Horizontal");
transform.Translate(Vector2.right * (h * speed * Time.deltaTime));
anim.SetBool("Walk", h != 0f);
if (anim.GetBool("Walk"))
Flip(h > 0f);
}
void Flip(bool facingRight)
{
sr.flipX = !facingRight;
}
}

Related

Unity: Why wont my movement return to value 0

Hi im new to programming in C# and i ran into a problem.Eveything is working,only the value wont return to 0 when the button is not pressed,i can change the direction of the movement,but the object wont stop moving...Here is the code!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
private Rigidbody2D rb2D;
private float speed = 1f;
private float moveHorizontal;
void Start()
{
rb2D = GetComponent<Rigidbody2D>();
}
void Update()
{
moveHorizontal = Input.GetAxisRaw("Horizontal");
}
void FixedUpdate()
{
if (moveHorizontal > 0.1f || moveHorizontal < -0.1f)
{
rb2D.AddForce(new Vector2 (moveHorizontal * speed, 0f), ForceMode2D.Impulse);
}
}
}
I see you adding forces, but you never reset the velocity to 0 anywhere
you could do this like e.g.
if(Mathf.Abs(moveHorizontal) > 0.1f)
{
...
}
else
{
var vel = rb2D.velocity;
vel.x = 0;
rb2D.velocity = vel;
}

How to flip character when moving left unity 2D

I am trying to flip my character sprite when moving left in my game, and I have followed multiple tutorials however my sprite does not seem to flip. It is always facing the same way.
Below is my code for my character's movement. I have created a Flip() function and 2 if statements used to call the function. The character can move left, right, up and down (no jumping).
I cannot seem to see where an error would be and why it is not flipping, so any help would be appreciated. thank you.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
private Animator animate;
public float moveSpeed = 6f;
bool facingRight = true;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
animate = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
animate.SetFloat("Speed", Mathf.Abs(movement.x));
if(movement.x < 0 && facingRight)
{
Flip();
}
else if (movement.x > 0 && !facingRight)
{
Flip();
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Flip()
{
Vector3 currentScale = gameObject.transform.localScale;
currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
facingRight = !facingRight;
}
}
Updated code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
private Animator animate;
public float moveSpeed = 6f;
bool facingRight = true;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
animate = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
animate.SetFloat("Speed", Mathf.Abs(movement.x));
if (movement.x < 0 && facingRight)
{
GetComponent<SpriteRenderer>().flipX = true;
}
else if (movement.x > 0 && !facingRight)
{
GetComponent<SpriteRenderer>().flipX = false;
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Flip()
{
Vector3 currentScale = gameObject.transform.localScale;
currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
facingRight = !facingRight;
}
}
Try to set the flipX property of the SpriteRenderer.
GetComponent<SpriteRenderer>().flipX = true;
You have an animator attached to the game object, if the scale value is controlled by the animation clip, you cannot change it. A typical workaround is give the game object an empty parent and change its scale.
Player <---- Change scale here
Model <---- Animator here
transform.Rotate(0f, 180f, 0f); you have to change y while fliping
will work better instead of using currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
This code worked for me
private void Flip()
{
// Rotate the player
if (transform.localEulerAngles.y != 180 && !facingRight)
transform.Rotate(0f, 180f, 0f);
else if(transform.localEulerAngles.y != 0 && facingRight)
transform.Rotate(0f, -180f, 0f);
// player flip point of attck also flip is direction
//transform.Rotate(0f, 180f, 0f);
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
GetComponent<SpriteRenderer>().flipX = true;
isLookingRight = false;
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
GetComponent<SpriteRenderer>().flipX = false;
isLookingRight = true;
}
Going to right
Going to left

Unity 2d : Objects being reinstantiated on scene reload after being destroyed

GOAL
So I'm creating a top down arena battler type game, and I want you to be able to restart the game by pressing R.
PROBLEM
When I press R, the whole scene resets as it should, except all the enemies that were previously instantiated (and then destroyed) are spawned again, all at once.
CODE
This is the enemy spawning code :
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawn : MonoBehaviour
{
private float nextActionTime = 0.0f;
public float period = 5f;
public GameObject enemy;
void Update()
{
if (Time.time > nextActionTime ) {
nextActionTime += period;
GameObject clone = Instantiate(enemy, new Vector3(-1, 3, 0), Quaternion.identity);
clone.tag = "enemy";
}
}
}
This is the player code, responsible for restarting the scene (I have marked what I belive to be the relevantant sections with dashes) :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class PlayerController : MonoBehaviour
{
public Rigidbody2D rb;
public GameObject Shield;
public GameObject ShieldInstance;
public float moveSpeed = 4.3f;
public float sheildSpeed = 5f;
Vector2 movement;
AudioSource woop;
AudioSource waa;
----------------------------
GameObject[] enemies;
----------------------------
bool isDead = false;
void Start() {
woop = GameObject.Find("Main Camera/ShieldSFX").GetComponent<AudioSource>();
waa = GameObject.Find("Main Camera/DefeatSFX").GetComponent<AudioSource>();
}
void Update()
{
--------------------------------------------------------------
enemies = GameObject.FindGameObjectsWithTag("enemy");
--------------------------------------------------------------
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
Vector3 mouseScreen = Input.mousePosition;
Vector3 mouse = Camera.main.ScreenToWorldPoint(mouseScreen);
transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(mouse.y - transform.position.y, mouse.x - transform.position.x) * Mathf.Rad2Deg - 90);
if (Input.GetMouseButtonDown(0))
{
if (ShieldInstance != null || transform.GetChild(0).GetComponent<SpriteRenderer>().enabled == false) { return; }
woop.Play();
ShieldInstance = Instantiate(Shield, transform.position + transform.forward + transform.up, transform.rotation);
ShieldInstance.transform.parent = transform;
}
if (Input.GetMouseButtonUp(0))
{
if (ShieldInstance == null) { return; }
ShieldInstance.transform.parent = null;
ShieldInstance.GetComponent<ShieldController>().LaunchForward(sheildSpeed);
Destroy(ShieldInstance, 2.3f);
}
-------------------------------------------------------------------------------
if (Input.GetKey("r")) {
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
foreach (GameObject one in enemies) {
Destroy(one);
}
}
-------------------------------------------------------------------------------
}
void FixedUpdate() {
if (!isDead) {
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
}
void OnCollisionEnter2D(Collision2D other) {
if (other.gameObject.tag == "enemy") {
waa.Play();
GameObject.Find("Canvas/gameover").GetComponent<Text>().enabled = true;
transform.GetChild(0).GetComponent<SpriteRenderer>().enabled = false;
GetComponent<PolygonCollider2D>().enabled = false;
}
}
}
And this is the enemy code :
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFollow : MonoBehaviour
{
public float moveSpeed;
public ParticleSystem explode;
AudioSource boom;
Vector2 movement;
GameObject player;
Rigidbody2D rb;
SpriteRenderer sr;
PolygonCollider2D pc;
void Start() {
rb = GetComponent<Rigidbody2D>();
sr = transform.GetChild(0).GetComponent<SpriteRenderer>();
pc = GetComponent<PolygonCollider2D>();
player = GameObject.Find("Player");
boom = GameObject.Find("Main Camera/ExplodeSFX").GetComponent<AudioSource>();
}
void Update()
{
Vector2 difference = (player.transform.position - new Vector3(2, .5f, 0)) - transform.position;
if (difference.x > 0) {
movement.x = 1;
} else if (difference.x < 0){
movement.x = -1;
} else {
movement.x = 0;
}
if (difference.y > 0) {
movement.y = 1;
} else if (difference.y < 0){
movement.y = -1;
} else {
movement.y = 0;
}
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void OnCollisionEnter2D(Collision2D other) {
if (other.gameObject.tag == "shield") {
StartCoroutine(ExplodeF());
}
}
private IEnumerator ExplodeF() {
explode.Play();
boom.Play();
sr.enabled = false;
pc.enabled = false;
yield return new WaitForSeconds(explode.main.startLifetime.constantMax);
Destroy(gameObject);
}
}
I would really appreciate any help!
If you want / need more details, just leave a comment :)
The problem is in Time.time, it is time since the start of the application, not since the start of the scene. So if you were in the game 30 secs, Time.time is 30 secs. If you reload the scene it is still 30 secs.
You have to count the time passed since entering the scene. Then it won't respawn all the enemies on scene reload.
When you restart the scene, everything is being destroyed and reset back except for the time.
The problem in your code is in the enemy spawner. Time.time returns the time passed since you started the game (and not since the scene was loaded). So, after the restart the if condition is true and the enemies are spawned.
If you want to count the time (in seconds) since the scene was loaded, what you can do is to add a variable in the enemy spawner class that would count the time
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawn : MonoBehaviour
{
private float nextActionTime = 0.0f;
private float timeSinceStart = 0;
public float period = 5f;
public GameObject enemy;
void Update()
{
if (timeSinceStart > nextActionTime ) {
nextActionTime += period;
GameObject clone = Instantiate(enemy, new Vector3(-1, 3, 0), Quaternion.identity);
clone.tag = "enemy";
}
timeSinceStart += Time.deltaTime;
}
}
See Time.deltaTime

How can I fix jumping in the air?

I'm making a 2D platformer with Unity. I used this tutorial to write this code but changed it a little bit. I want to support both keyboard and gamepad, so I use the new Input System. I've defined three variables called GroundedRememeber, JumpPressedRemember and JumpPressedRememberTime and basically they work like timers and check if the player leaves the ground and then the player can jump when he is near the ground without need to touch it and I want to use it instead of famous "groundCheck". But the problem is that these timers are not working and the player can jump forever even in the air when I press jump button rapidly. Also, as you can see, I added a LayerMask named "groundLayers" for the player to jump only on this type of objects but when I choose "Ground" in the "groundLayers" slot in the Inspector, the player can't jump anymore.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour, PlayerInputActions.IPlayerActions
{
private PlayerInputActions controls;
[SerializeField] LayerMask groundLayers;
private Rigidbody2D rb;
private Animator anim;
private bool facingRight = true;
private Vector2 moveInput;
[SerializeField] private float jumpForce;
float JumpPressedRemember = 0;
[SerializeField] float JumpPressedRememberTime = 0.2f;
float GroundedRemember = 0;
[SerializeField] float GroundedRememberTime = 0.25f;
[SerializeField] float HorizontalAcceleration = 1;
[SerializeField] [Range(0, 1)] float HorizontalDampingBasic = 0.5f;
[SerializeField] [Range(0, 1)] float HorizontalDampingWhenStopping = 0.5f;
[SerializeField] [Range(0, 1)] float HorizontalDampingWhenTurning = 0.5f;
[SerializeField] [Range(0, 1)] float JumpHeight = 0.5f;
private void Awake()
{
controls = new PlayerInputActions();
controls.Player.SetCallbacks(this);
}
void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
void PlayerInputActions.IPlayerActions.OnMove(InputAction.CallbackContext context)
{
moveInput = context.ReadValue<Vector2>();
}
void Jump() {
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Force);
GroundedRemember = 0;
JumpPressedRemember = 0;
}
bool TryJump() {
if (GroundedRemember > 0) {
Jump();
return true;
} else {
JumpPressedRemember = JumpPressedRememberTime;
return false;
}
}
void PlayerInputActions.IPlayerActions.OnJump(InputAction.CallbackContext context)
{
jumpForce = context.ReadValue<float>();
switch (context.phase) {
case InputActionPhase.Performed:
TryJump();
break;
}
}
void FixedUpdate()
{
if(facingRight == false && moveInput.x > 0){
Flip();
}else if (facingRight == true && moveInput.x < 0){
Flip();
}
}
void Flip(){
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
void OnEnable()
{
controls.Enable();
}
void OnDisable()
{
controls.Disable();
}
void Update()
{
Vector2 GroundedBoxCheckPosition = (Vector2)transform.position + new Vector2(0, -0.01f);
Vector2 GroundedBoxCheckScale = (Vector2)transform.localScale + new Vector2(-0.02f, 0);
bool Grounded = Physics2D.OverlapBox(GroundedBoxCheckPosition, transform.localScale, 0, groundLayers);
GroundedRemember -= Time.deltaTime;
if (Grounded)
{
GroundedRemember = GroundedRememberTime;
}
JumpPressedRemember -= Time.deltaTime;
if ((JumpPressedRemember > 0)) {
TryJump();
}
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
float HorizontalVelocity = rb.velocity.x;
HorizontalVelocity += moveInput.x;
if (Mathf.Abs(moveInput.x) < 0.01f)
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingWhenStopping, Time.deltaTime * 10f);
else if (Mathf.Sign(moveInput.x) != Mathf.Sign(HorizontalVelocity))
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingWhenTurning, Time.deltaTime * 10f);
else
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingBasic, Time.deltaTime * 10f);
rb.velocity = new Vector2(HorizontalVelocity, rb.velocity.y);
}
}
If you know how much the player jumps for, then try maybe adding a delay to the next jump
Maybe using the Invoke() function ur just using Coroutines if you know how to use them.
But i would still recommend using a Ground Check since it's practical and just easier and i don't see a reason why you wouldn't use it.

Delay in shoot (Unity and C#)

I am making shooting in Unity, what I want is to make a little delay, for example: to be able to shoot in every 0.5 seconds. Check the script, I want my bullet prefab to appear (instantiate) after 0.5 sec delay.
private Rigidbody2D rb2d;
private float h = 0.0f;
public float Speed;
public Transform firePoint;
public GameObject bulletPrefab;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
h = Input.GetAxisRaw("Horizontal");
if (h != 0.0f)
{
rb2d.velocity = new Vector2(h * Speed, rb2d.velocity.y);
}
if (h == 0.0f)
{
rb2d.velocity = new Vector2(0, rb2d.velocity.y);
}
if (Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
}
void Shoot()
{
Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
}
This should take you in the right direction, of course, this is only one of the ways to do it.
You can change fireDelay to change the rate of fire.
private Rigidbody2D rb2d;
private float h = 0.0f;
public float Speed;
public Transform firePoint;
public GameObject bulletPrefab;
float fireElapsedTime = 0;
public float fireDelay = 0.2f;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
h = Input.GetAxisRaw("Horizontal");
if (h != 0.0f)
{
rb2d.velocity = new Vector2(h * Speed, rb2d.velocity.y);
}
if (h == 0.0f)
{
rb2d.velocity = new Vector2(0, rb2d.velocity.y);
}
fireElapsedTime += Time.deltaTime;
if (Input.GetKeyDown(KeyCode.Space) && fireElapsedTime >= fireDelay)
{
fireElapsedTime = 0;
Shoot();
}
}
void Shoot()
{
Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
}

Categories

Resources