I'm working on a platformer game, and I instantiate my character after he gets hit by an enemy object. The problem is, my character is instantiating twice. Here's my code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerMove : MonoBehaviour
{
public GameObject player;
private Rigidbody2D rb;
private SpriteRenderer sprite;
private BoxCollider2D coll;
private Animator anim;
public float Speed;
public float JumpForce;
private float dirX = 0f;
private float fJumpPressedRemember = 0f;
private float fJumpPressedRememberTime = 0.2f;
[SerializeField] private LayerMask jumpableGround;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sprite = GetComponent<SpriteRenderer>();
coll = GetComponent<BoxCollider2D>();
}
// Update is called once per frame
void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(dirX * Speed, rb.velocity.y);
fJumpPressedRemember -= Time.deltaTime;
if (Input.GetButtonDown("Jump"))
{
fJumpPressedRemember = fJumpPressedRememberTime;
}
if ((fJumpPressedRemember > 0) && isGrounded())
{
fJumpPressedRemember = 0;
rb.velocity = new Vector2(rb.velocity.x, JumpForce);
}
UpdateAnimation();
}
private bool isGrounded()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
void OnCollisionEnter2D(Collision2D spikeCol)
{
if (spikeCol.gameObject.tag.Equals("DamageDealer") == true)
{
Instantiate(player, new Vector3(-10, 1, 0), Quaternion.identity);
Destroy(player);
}
if (spikeCol.gameObject.tag.Equals("End") == true)
{
SceneManager.LoadScene("Level2", LoadSceneMode.Single);
}
if (spikeCol.gameObject.tag.Equals("End2") == true)
{
SceneManager.LoadScene("Level1", LoadSceneMode.Single);
}
}
private void UpdateAnimation()
{
if (dirX > 0f)
{
anim.SetBool("running", true);
sprite.flipX = false;
}
else if (dirX < 0f)
{
anim.SetBool("running", true);
sprite.flipX = true;
}
else
{
anim.SetBool("running", false);
}
}
}
It's supposed to instantiate once after dying. I don't know what's happening, but it only started after I added animation code, so I think that's the issue. Thanks to anyone who can help!
OnCollisionEnter2D is called twice.
Reasons why this can be described here: Why is OnCollisionEnter getting called twice?
You can add instantiate method double call check, like this:
private bool isInited;
void OnCollisionEnter2D(Collision2D spikeCol)
{
if (spikeCol.gameObject.tag.Equals("DamageDealer") == true)
{
if (isInited)
{
return;
}
isInited = true;
Instantiate(player, new Vector3(-10, 1, 0), Quaternion.identity);
Destroy(player);
}
...
}
Related
Here's my code for player movement. I have set up walking around and I am now Trying to change the sprite animation when walking in different directions. Everything was working fine but when I tried to change the sprite for walking up the sprite gets stuck in a loop and doesn't idle.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public Animator Animator;
[SerializeField] private float speed = 1f;
private Rigidbody2D body;
private Vector2 axisMovement;
// Start is called before the first frame update
void Start()
{
body = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
axisMovement.x = Input.GetAxisRaw("Horizontal");
axisMovement.y = Input.GetAxisRaw("Vertical");
Animator.SetFloat("Speed", Mathf.Abs(axisMovement.x));
if (Input.GetKey(KeyCode.W))
{
Animator.SetBool("isforward", true);
}
if (Input.GetKey(KeyCode.A))
{
Animator.SetBool("isforward", false);
}
if (Input.GetKey(KeyCode.S))
{
Animator.SetBool("isforward", false);
}
if (Input.GetKey(KeyCode.D))
{
Animator.SetBool("isforward", false);
}
}
private void FixedUpdate()
{
Move();
}
private void Move()
{
body.velocity = axisMovement.normalized * speed;
CheckForFlipping();
}
private void CheckForFlipping()
{
bool movingLeft = axisMovement.x < 0;
bool movingRight = axisMovement.x > 0;
if (movingLeft)
{
transform.localScale = new Vector3(-1f, transform.localScale.y);
}
if (movingRight)
{
transform.localScale = new Vector3(1f, transform.localScale.y);
}
}
}
I also tried doing Animator.SetFloat("Speed", Mathf.Abs(axisMovement.x)); but switch it with axisMovement.y but that stops all the animations moving left and right stop working. 😢
I've figured it out. here's the updated code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public Animator Animator;
[SerializeField] private float speed = 1f;
private Rigidbody2D body;
private Vector2 axisMovement;
// Start is called before the first frame update
void Start()
{
body = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
axisMovement.x = Input.GetAxisRaw("Horizontal");
axisMovement.y = Input.GetAxisRaw("Vertical");
Animator.SetFloat("Speed", Mathf.Abs(axisMovement.x + axisMovement.y));
if (Input.GetKey(KeyCode.W))
{
Animator.SetBool("isforward", true);
} else {
Animator.SetBool("isforward", false);
}
// if (Input.GetKey(KeyCode.A))
// {
// Animator.SetBool("isforward", false);
// }
// if (Input.GetKey(KeyCode.S))
// {
// Animator.SetBool("isforward", false);
// }
// if (Input.GetKey(KeyCode.D))
// {
// Animator.SetBool("isforward", false);
// }
}
private void FixedUpdate()
{
Move();
}
private void Move()
{
body.velocity = axisMovement.normalized * speed;
CheckForFlipping();
}
private void CheckForFlipping()
{
bool movingLeft = axisMovement.x < 0;
bool movingRight = axisMovement.x > 0;
if (movingLeft)
{
transform.localScale = new Vector3(-1f, transform.localScale.y);
}
if (movingRight)
{
transform.localScale = new Vector3(1f, transform.localScale.y);
}
}
}
I am new to the world of programming and game design, I have followed a few tutorials, and now I am making my first own project. I am working with unity and c# and I already have a working player movement script, but I wanna add double jump to it, how can I do that?
I have tried following a few tutorials but none of them seem to work for me.
I have tried to add double jump now, but I am getting a lot of syntax errors, how can I fix that?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rb;
private BoxCollider2D coll;
[SerializeField] private float moveSpeed = 7f;
[SerializeField] private float jumpForce = 14f;
[SerializeField] private LayerMask jumpableGround;
// Start is called before the first frame update
private void Start()
{
rb = GetComponent<Rigidbody2D>();
coll = GetComponent<BoxCollider2D>();
}
// Update is called once per frame
private void Update()
{
float dirX = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
if (Input.GetButtonDown("Jump") && IsGrounded())
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
}
private bool IsGrounded()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
private bool hasDoubleJumped = false;
if (Input.GetButtonDown("Jump") && IsGrounded())
{
hasDoubleJumped = false
rb.velocity = new Vector2(RenderBuffer.velocity.x, jumpForce);
}
else if (Input.GetButtonDown("Jump") && !hasDoubleJumped)
{
hasDoubleJumped = true;
rb.velocity = new Vector2(RenderBuffer.velocity.x, jumpForce);
}
}
You could create a boolean like bool hasDoubleJumped and add the following code to the Update:
if (Input.GetButtonDown("Jump") && IsGrounded())
{
hasDoubleJumped = False
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
else if (Input.GetButtonDown("Jump") && !hasDoubleJumped)
{
hasDoubleJumped = True
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
You would need to add the variable at the top, so for example like that:
private Rigidbody2D rb;
private BoxCollider2D coll;
private bool hasDoubleJumped = False;
Some other tipps: The title of your question is not very good. It doesn't really matter that you write your code in Visual Studio (VS). A better title would have been something like How can I add a double jump to my Unity game in C# or something similar.
EDIT
The following code should work, though I can't say with certainty, I didn't test it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rb;
private BoxCollider2D coll;
private bool hasDoubleJumped = False;
[SerializeField] private float moveSpeed = 7f;
[SerializeField] private float jumpForce = 14f;
[SerializeField] private LayerMask jumpableGround;
// Start is called before the first frame update
private void Start()
{
rb = GetComponent<Rigidbody2D>();
coll = GetComponent<BoxCollider2D>();
}
// Update is called once per frame
private void Update()
{
float dirX = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
if (Input.GetButtonDown("Jump") && IsGrounded())
{
hasDoubleJumped = False
rb.velocity = new Vector2(RenderBuffer.velocity.x, jumpForce);
}
else if (Input.GetButtonDown("Jump") && !hasDoubleJumped)
{
hasDoubleJumped = True;
rb.velocity = new Vector2(RenderBuffer.velocity.x, jumpForce);
}
}
private bool IsGrounded()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
}
The text in this image pretty much explains everything.
This is the code that creates the rays. You may ignore Debug.DrawRay().
RaycastHit hitInfo;
RaycastHit wall;
RaycastHit backFace;
if(Physics.Raycast(barrelEnd.transform.position, barrelEnd.transform.forward, out hitInfo)) {
Debug.DrawRay(barrelEnd.transform.position, barrelEnd.transform.forward*5, Color.green, 5f, false);
Instantiate(rayOneHit, hitInfo.point, Quaternion.identity);
Enemy target = hitInfo.transform.GetComponent<Enemy>();
if(target != null) {
if(Physics.Raycast(hitInfo.point, barrelEnd.transform.forward, out wall)) {
Debug.DrawRay(hitInfo.point, (hitInfo.point - barrelEnd.transform.position)*2, Color.blue, 5f, false);
Instantiate(rayTwoHit, wall.point, Quaternion.identity);
if(Physics.Raycast(wall.point, ((hitInfo.point - wall.point)/Vector3.Distance(hitInfo.point,wall.point)), out backFace)) {
Debug.DrawRay(wall.point, (hitInfo.point - wall.point)*10, Color.red, 5f, false);
Vector3 hitLocation = new Vector3(backFace.point.x, backFace.point.y, backFace.point.z);
Instantiate(hitPoint, hitLocation, Quaternion.identity);
}
}
target.dealDamage(damage);
}
lineRenderer.SetPosition(0, aim.transform.position);
lineRenderer.SetPosition(1, hitInfo.point);
}
This is all inside of a function Shoot() which is called as follows:
void Update() {
if(Input.GetButtonDown("Fire1")) {
Shoot();
}
}
Full code if needed:
using System.Collections;
using UnityEngine;
public class Shooting : MonoBehaviour {
[SerializeField] Transform aim;
[SerializeField] LineRenderer lineRenderer;
public float damage = 30f;
public Transform barrelEnd;
public Transform crosshair;
public Light muzzleFlash;
public Object hitPoint;
public Object rayOneHit;
public Object rayTwoHit;
public LayerMask enemyLayer;
//public Light muzzleFlashSelf;
// public GameObject projectile;
public float force = 100f;
void Start() {
Cursor.visible = false;
muzzleFlash.enabled = false;
//muzzleFlashSelf.enabled = false;
}
void Update() {
if(Input.GetButtonDown("Fire1")) {
Shoot();
}
}
void Shoot() {
RaycastHit hitInfo;
RaycastHit wall;
RaycastHit backFace;
StartCoroutine(DrawLine());
StartCoroutine(Flash());
if(Physics.Raycast(barrelEnd.transform.position, barrelEnd.transform.forward, out hitInfo)) {
Debug.DrawRay(barrelEnd.transform.position, barrelEnd.transform.forward*5, Color.green, 5f, false);
Instantiate(rayOneHit, hitInfo.point, Quaternion.identity);
Enemy target = hitInfo.transform.GetComponent<Enemy>();
if(target != null) {
if(Physics.Raycast(hitInfo.point, barrelEnd.transform.forward, out wall)) {
Debug.DrawRay(hitInfo.point, (hitInfo.point - barrelEnd.transform.position)*2, Color.blue, 5f, false);
Instantiate(rayTwoHit, wall.point, Quaternion.identity);
if(Physics.Raycast(wall.point, ((hitInfo.point - wall.point)/Vector3.Distance(hitInfo.point,wall.point)), out backFace)) {
Debug.DrawRay(wall.point, (hitInfo.point - wall.point)*10, Color.red, 5f, false);
Vector3 hitLocation = new Vector3(backFace.point.x, backFace.point.y, backFace.point.z);
Instantiate(hitPoint, hitLocation, Quaternion.identity);
}
}
target.dealDamage(damage);
}
lineRenderer.SetPosition(0, aim.transform.position);
lineRenderer.SetPosition(1, hitInfo.point);
}
}
IEnumerator DrawLine() {
lineRenderer.enabled = true;
float t = 0;
float time = 0.01f;
Vector3 orig = lineRenderer.GetPosition(0);
Vector3 orig2 = lineRenderer.GetPosition(1);
lineRenderer.SetPosition(1, orig);
for (; t < time; t += Time.deltaTime) {
yield return null;
}
lineRenderer.SetPosition(1, orig2);
lineRenderer.enabled = false;
}
IEnumerator Flash() {
float t = 0;
float time = 0.1f;
muzzleFlash.enabled = true;
//muzzleFlashSelf.enabled = true;
for (; t < time; t += Time.deltaTime) {
yield return null;
}
muzzleFlash.enabled = false;
//muzzleFlashSelf.enabled = false;
}
}
I've tried to start the 2nd raycast slightly further inside of the enemy, because I thought maybe it is hitting the very edge of the collider but this changed nothing. I've also tried to use ~enemyMask to exclude the enemy, but this just made the second ray not fire at all.
When creating the game, I came across the problem that after adding animation to the player's code in the play mode, he stopped moving.
I did everything as usual, went into the animator, made an animation, and then set up and added everything necessary to the code in the animator, but after that the player stopped moving although before that everything was fine.
Help me, I hope it's not difficult.
Here is the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[Header("Controlled player")]
public Rigidbody2D rb;
[Header("Tinctures of movement")]
public float PSpeed = 1f;
public float jumpForce = 1f;
[Header("Variable Reduction parameters")]
public float LowingPSPeed;
public float FormedPSpeed;
[Header("Traffic Statuses")]
public bool Move;
public bool Jump;
[Header("")]
[Header("Checking the ground under the player")]
public bool OnGround;
private bool doJump = false;
private bool GOright = false;
private bool GOleft = false;
[Header("Ground Check Settings")]
private float groundRadius = 0.3f;
public Transform groundCheck;
public LayerMask groundMask;
private Animator anim;
void Math()
{
FormedPSpeed = PSpeed / LowingPSPeed;
}
void Start()
{
anim = GetComponent<Animator>();
}
void Update()
{
Math();
if (Input.GetKeyDown(KeyCode.Space))
{
doJump = true;
}
if (Input.GetKey("d"))
{
GOright = true;
}else
{
GOright = false;
}
if (Input.GetKey("a"))
{
GOleft = true;
}
else
{
GOleft = false;
}
}
void FixedUpdate()
{
OnGround = Physics2D.OverlapCircle(groundCheck.position, groundRadius, groundMask);
if (GOright && Move)
{
transform.position += new Vector3(FormedPSpeed, 0, 0);
GetComponent<SpriteRenderer>().flipX = false;
}
if (GOleft && Move)
{
transform.position += new Vector3(-(FormedPSpeed), 0, 0);
GetComponent<SpriteRenderer>().flipX = true;
}
if (doJump && Jump && OnGround)
{
rb.AddForce(new Vector2(0, (jumpForce * 10)));
anim.SetTrigger("takeOf");
doJump = false;
}
if (OnGround)
{
anim.SetBool("isJump", false);
}else
{
anim.SetBool("isJump", true);
}
if (!GOleft && !GOright)
{
anim.SetBool("isRun", false);
}else
{
anim.SetBool("isRun", true);
}
}
I don't understand why this is happening
I made a script for moving an object to the position indicated by the mouse click. If I don't choose to click to another location to move towards, I would like to stop my object if it reaches the previously mentioned position. However, the object doesn't stop when reaching the position and it continues moving.
Here is the code I wrote. I would be grateful if somebody knows how to fix this issue.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed;
private Vector3 targetPos;
private Rigidbody2D rb;
private bool isMoving;
private Vector2 direction;
public float changeDirCooldown;
private float changeCool;
private bool canChangeDir;
void Start()
{
rb = GetComponent<Rigidbody2D>();
changeCool=changeDirCooldown;
canChangeDir =true;
}
void Update()
{
if (Input.GetMouseButton(0) && canChangeDir)
{
changeDirCooldown = changeCool;
SetTargetPosition();
}
if (changeDirCooldown<=0)
{
canChangeDir = true;
}
else
{
changeDirCooldown -= Time.deltaTime;
}
}
private void FixedUpdate()
{
if (isMoving)
{
Move();
}
if (this.transform.position == this.targetPos)
{
isMoving = false;
rb.velocity = Vector2.zero;
}
}
private void SetTargetPosition()
{
targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
targetPos.z = transform.position.z;
direction = targetPos - this.transform.position;
direction = direction.normalized;
isMoving = true;
}
private void Move()
{
rb.velocity = direction * moveSpeed;
canChangeDir = false;
}
}
It's probabily a problem with float number tolerance. This line
this.transform.position == this.targetPos
will almost never result to true, so instead you should do something like this:
Mathf.Abs(this.transform.position.x - this.targetPos.x) < float.Epsilon &&
Mathf.Abs(this.transform.position.y - this.targetPos.y) < float.Epsilon