I am currently creating my final project for my coding class, and I have run into a snag in figuring out how to jump. I have used a tutorial video series as reference to my project, here is the link to the jumping episode. https://www.youtube.com/watch?v=05TCTrpGB-4&t=861s
I most likely have a logic error somewhere but every thing looks fine.
Heres my code:
private Rigidbody2D myRigidbody;
[SerializeField]
private float speed;
[SerializeField]
private Transform[] GroundPoints;
[SerializeField]
private float groundRadius;
[SerializeField]
private LayerMask WhatIsGround;
private bool isGrounded;
private bool Jump;
[SerializeField]
private float JumpForce;
// Use this for initialization
void Start () {
myRigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate () {
isGrounded = IsGrounded();
if(isGrounded && Jump)
{
isGrounded = false;
myRigidbody.AddForce(new Vector2(0, JumpForce));
}
float horizontal = Input.GetAxis("Horizontal");
HandleMovement(horizontal);
}
private void HandleInput()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Jump = true;
}
}
//Moving left/right
private void HandleMovement(float horizontal)
{
myRigidbody.velocity = new Vector2(horizontal * speed, myRigidbody.velocity.y);
}
private bool IsGrounded()
{
if(myRigidbody.velocity.y <= 0)
{
foreach (Transform point in GroundPoints)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(point.position, groundRadius, WhatIsGround);
for (int i =0; i < colliders.Length ; i++)
{
if(colliders[i].gameObject != gameObject)
{
return true;
}
}
}
}
return false;
}
The HandleInput was not clarified in FixedUpdate. therefore, the code was not read in the update, making the code "invisible". so adding HandleInput like I added HandleMovement allowed for that code to be read.
Related
Alright so I have a collision script which works as in if I collide a gameobject with another object with the script attached it does register a collision.
The collision script I am using:
private void OnCollisionEnter(Collision collision)
{
Debug.Log("collision registered");
}
However when I try to collided my instantiated prefabs with my object with my script attached a collision does not get registered.
Does anyone know why this is? I think it's to do with with the prefabs being a "Moveable" but I can't quite get to the bottom of the problem.
Script attached to the prefabs:
public class Moveable : MonoBehaviour
{
public float _speedMetersPerSecond = 50f;
public float resistance = 10f;
public float current = 0f;
public List<Moveable> moveables = new List<Moveable>();
private Vector3? _destination;
private Vector3 _startPosition;
private float _totalLerpDuration;
private float _elapsedLerpDuration;
private Action _onCompleteCallback;
public GameObject Electron;
public Transform Lightbulb;
public SliderChange SliderScript;
public VMT2Counter script2;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// THE LIGHTBULB PART IS FOR THE SPAWN POINT SO DO NOT DELETE
Moveable NextOnPath = Instantiate(Electron, Lightbulb.position, Quaternion.identity).GetComponent<Moveable>();
moveables.Add(NextOnPath.GetComponent<Moveable>());
MoverController.instance.targets.Add(NextOnPath.GetComponent<Moveable>());
}
if (_destination.HasValue == false)
return;
if (_elapsedLerpDuration >= _totalLerpDuration && _totalLerpDuration > 0)
return;
_elapsedLerpDuration += Time.deltaTime;
float percent = (_elapsedLerpDuration / _totalLerpDuration);
transform.position = Vector3.Lerp(_startPosition, _destination.Value, percent);
if (_elapsedLerpDuration >= _totalLerpDuration)
_onCompleteCallback?.Invoke();
// resistance = SliderScript.slider.value;
// current = script2.PotentialDifference / resistance;
}
public void MoveTo(Vector3 destination, Action onComplete = null)
{
var distanceToNextWaypoint = Vector3.Distance(transform.position, destination);
_totalLerpDuration = distanceToNextWaypoint / _speedMetersPerSecond;
_startPosition = transform.position;
_destination = destination;
_elapsedLerpDuration = 0f;
_onCompleteCallback = onComplete;
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "Resistor")
{
Debug.Log("lol");
_speedMetersPerSecond = 25f;
}
}
}
Another script which goes hand in hand with the Moveable script but is not attached to the prefab:
public class MoverController : MonoBehaviour
{
public List<Moveable> targets;
[SerializeField] private Moveable target;
private List<Transform> _waypoints;
private int _nextWaypointIndex;
public static MoverController instance;
void Awake()
{
if (instance == null)
{
instance = this;
}
else
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
}
private void OnEnable()
{
MoveToNextWaypoint();
}
private void MoveToNextWaypoint()
{
for (int i = 0; i < targets.Count; i++)
{
if (targets[i] == null) continue;
_waypoints = GetComponentsInChildren<Transform>().ToList();
_waypoints.RemoveAt(0);
var targetWaypointTransform = _waypoints[_nextWaypointIndex];
targets[i].MoveTo(targetWaypointTransform.position, MoveToNextWaypoint);
targets[i].transform.LookAt(_waypoints[_nextWaypointIndex].position);
_nextWaypointIndex++;
if (_nextWaypointIndex >= _waypoints.Count)
_nextWaypointIndex = 0;
}
}
}
[![A picture of the prefab][1]][1]
[1]: https://i.stack.imgur.com/uyuge.png*emphasized text*
Video which shows situation: https://clipchamp.com/watch/MXjnTKl2cqg
The collider is a trigger:
Collider A
Collider B
Event triggered
Collider
Collider
Collision
Collider
Trigger
Trigger
Trigger
Collider
Trigger
Trigger
Trigger
Trigger
To fix this problem, either uncheck the box for it to collide normally, or change your event handler to detect triggers instead of colliders:
private void OnTriggerEnter(Collider other) {
Debug.Log("collision registered");
}
See here for more https://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html :)
It is also worth pointing out that if neither of your objects have rigidbodies on, the event will not fire. If you need it to fire but don't want all of the rigidbody physics, you can add one but tick the isKinematic box.
I'm an absolute beginner in Unity and C# and I'm having some issues inserting a double jump on my Unity 2D Project. My question is: How can I be able to add a double jump on this code?
I tried to follow a lot of tutorials on internet, but I wasn't successful in any of the tutorials. This code I'm using right now is working normally, but I need to add the double jump function on the game.
Here's the code I'm using, I really need some help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rigidbody;
private BoxCollider2D collider;
private SpriteRenderer sprite;
private Animator animator;
[SerializeField] private LayerMask jumpableGround;
private float dirX = 0f;
[SerializeField]private float PlayerMovementSpeed = 7f;
[SerializeField]private float PlayerJumpSpeed = 8f;
private enum MovementState { idle, running, jumping, falling }
// Start is called before the first frame update
private void Start()
{
rigidbody = GetComponent<Rigidbody2D>();
collider = GetComponent<BoxCollider2D>();
sprite = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
}
// Update is called once per frame
private void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rigidbody.velocity = new Vector2(dirX * PlayerMovementSpeed, rigidbody.velocity.y);
if (Input.GetButtonDown("Jump") && IsGrounded())
{
GetComponent<Rigidbody2D>().velocity = new Vector2(0, PlayerJumpSpeed);
}
UpdateAnimationState();
}
private void UpdateAnimationState()
{
MovementState state;
if (dirX > 0f)
{
state = MovementState.running;
sprite.flipX = false;
}
else if (dirX < 0f)
{
state = MovementState.running;
sprite.flipX = true;
}
else
{
state = MovementState.idle;
}
if (rigidbody.velocity.y > .1f)
{
state = MovementState.jumping;
}
else if (rigidbody.velocity.y < -.1f)
{
state = MovementState.falling;
}
animator.SetInteger("state", (int)state);
}
private bool IsGrounded()
{
return Physics2D.BoxCast(collider.bounds.center, collider.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
}
The easy way to make this in your code is adding a counter of jumps, the variable starts in 0 and adds 1 to value on every jump, then you reset de variable when the character in on ground.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rigidbody;
private BoxCollider2D collider;
private SpriteRenderer sprite;
private Animator animator;
[SerializeField] private LayerMask jumpableGround;
private float dirX = 0f;
[SerializeField]private float PlayerMovementSpeed = 7f;
[SerializeField]private float PlayerJumpSpeed = 8f;
private enum MovementState { idle, running, jumping, falling }
// NEW VARIABLE
private int jumpCounter;
// Start is called before the first frame update
private void Start()
{
rigidbody = GetComponent<Rigidbody2D>();
collider = GetComponent<BoxCollider2D>();
sprite = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
jumpCounter = 0;
}
// Update is called once per frame
private void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rigidbody.velocity = new Vector2(dirX * PlayerMovementSpeed, rigidbody.velocity.y);
//THE CONDITION CHANGES
if (Input.GetButtonDown("Jump") && jumpCounter<2)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(0, PlayerJumpSpeed);
jumpCounter++;
}
if(IsGrounded())
{
jumpCounter = 0;
}
enter code here
UpdateAnimationState();
}
private void UpdateAnimationState()
{
MovementState state;
if (dirX > 0f)
{
state = MovementState.running;
sprite.flipX = false;
}
else if (dirX < 0f)
{
state = MovementState.running;
sprite.flipX = true;
}
else
{
state = MovementState.idle;
}
if (rigidbody.velocity.y > .1f)
{
state = MovementState.jumping;
}
else if (rigidbody.velocity.y < -.1f)
{
state = MovementState.falling;
}
animator.SetInteger("state", (int)state);
}
private bool IsGrounded()
{
return Physics2D.BoxCast(collider.bounds.center, collider.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
}
EDIT:
Added a fix to the IsGrounded method.
I've tried 2/3 different ways of removing my gameObject from my List but none are working. When I debug the method the debug log is showing up as it should yet the gameobject still isn't removed from the list.
When my teammates kill an enemy I want the enemy to be removed from the list and then destroyed so I can continue to iterate through the List to find the closest enemy to begin attacking. Because the gameObject's are not being removed I get a null reference and i can loop through my for loop to check.
1st Script: List is created and used in a for loop, removing and destroying the enemy also occurs in here.
public class FriendlyManager : MonoBehaviour
{
public NavMeshAgent navMeshAgent;
public Transform player;
public static FriendlyManager singleton;
public float health;
public float minimumDistance;
public int damage;
public List<GameObject> enemies;
private GameObject enemy;
private GameObject enemyObj;
// animations
[SerializeField] Animator animator;
bool isAttacking;
bool isPatroling;
// attacking
[SerializeField] Transform attackPoint;
[SerializeField] public GameObject projectile;
public float timeBetweenAttacks;
bool alreadyAttacked;
private void Awake()
{
navMeshAgent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
enemyObj = new GameObject();
}
private void Start()
{
singleton = this;
isAttacking = false;
isPatroling = true;
animator.SetBool("isPatroling", true);
}
private void Update()
{
for(int i = 0; i < enemies.Count; i++)
{
if(Vector3.Distance(player.transform.position, enemies[i].transform.position) <= minimumDistance)
{
enemy = enemies[i];
Attacking(enemy);
}
}
}
private void Attacking(GameObject enemy)
{
// stop enemy movement.
navMeshAgent.SetDestination(transform.position);
enemyObj.transform.position = enemy.transform.position;
transform.LookAt(enemyObj.transform);
if (!alreadyAttacked)
{
isAttacking = true;
animator.SetBool("isAttacking", true);
animator.SetBool("isPatroling", false);
Rigidbody rb = Instantiate(projectile, attackPoint.position, Quaternion.identity).GetComponent<Rigidbody>();
rb.AddForce(transform.forward * 32f, ForceMode.Impulse);
alreadyAttacked = true;
Invoke(nameof(ResetAttack), timeBetweenAttacks);
}
}
private void ResetAttack()
{
alreadyAttacked = false;
animator.SetBool("isAttacking", false);
}
public void DestroyEnemy(GameObject enemy)
{
enemies.Remove(enemy);
Debug.Log("AHHHHHHH M GOING CRAZY");
Destroy(gameObject);
}
}
}
2nd Script: Deals with the damage and checks enemy's currentHealth. (I have to post it as an image because for Stack Overflow is being annoying.) ._.
Shouldn't it just be
Destroy(enemy);
and not
Destroy(gameObject);
I am doing a school project in Unity. My team and I decided to make an endless runner 2D game. However, because it is the first time I use C#, I don't know how to make my player's speed accelerate when collide with a game object in Unity. I only know how to destroy the player's health when a collision happens. Please help me! Thank you!
it's quite hard to give answers without seeing any code you've written, but as it's 2D and you've already got the collision damage working, you've probably used an OnCollisionEnter(), well it's very similar: you test if you've collided (which you've already done), then you add force to your player using a rigidbody2d, probably something along the lines of:
public Rigidbody2D rb;
void OnCollisionEnter2D(Collision2D collision)
{
rb.AddForce(direction * force, ForceMode2D.Impulse); // the ForceMode2D is
// optional, it's just so that
// the velocity change is sudden.
}
This should work.
If you have a GameManager that stores the game speed you can also do that too:
private float gameSpeedMultiplier = 0.5f;
void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.CompareTag("Tag of the collided object")
{
GameManager.Instance.gameSpeed += gameSpeedMultiplier;
}
}
public class PlayerContoler : MonoBehaviour
{
public static PlayerContoler instance;
public float moveSpeed;
public Rigidbody2D theRB;
public float jumpForce;
private bool isGrounded;
public Transform GroundCheckPoint;
public LayerMask whatIsGround;
private bool canDoubleJump;
private Animator anim;
private SpriteRenderer theSR;
public float KnockbackLength, KnockbackForce;
private float KnockbackCounter;
public float bonceForce;
public bool stopImput;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
theSR = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
if(!PauseMenu.instance.isPause && !stopImput)
{
if (KnockbackCounter <= 0)
{
theRB.velocity = new Vector2(moveSpeed * Input.GetAxis("Horizontal"), theRB.velocity.y);
isGrounded = Physics2D.OverlapCircle(GroundCheckPoint.position, .2f, whatIsGround);
if (isGrounded)
{
canDoubleJump = true;
}
if (Input.GetButtonDown("Jump"))
{
if (isGrounded)
{
theRB.velocity = new Vector2(theRB.velocity.x, jumpForce);
AudioManager.instance.PlaySFX(10);
}
else
{
if (canDoubleJump)
{
theRB.velocity = new Vector2(theRB.velocity.x, jumpForce);
canDoubleJump = false;
AudioManager.instance.PlaySFX(10);
}
}
}
if (theRB.velocity.x < 0)
{
theSR.flipX = true;
}
else if (theRB.velocity.x > 0)
{
theSR.flipX = false;
}
} else
{
KnockbackCounter -= Time.deltaTime;
if(!theSR.flipX)
{
theRB.velocity = new Vector2(-KnockbackForce, theRB.velocity.y);
} else
{
theRB.velocity = new Vector2(KnockbackForce, theRB.velocity.y);
}
}
}
anim.SetFloat("moveSpeed", Mathf.Abs(theRB.velocity.x));
anim.SetBool("isGrounded", isGrounded);
}
public void Knockback()
{
KnockbackCounter = KnockbackLength;
theRB.velocity = new Vector2(0f, KnockbackForce);
anim.SetTrigger("hurt");
}
}
Hey I am trying to change a float when my player collides with a object. I tried many ways of reference but only got null when trying to debug I came up with this so far. I want to get the gameobject that contains the player script meaning the player and after I want to get the component script tankmovement to change the variable in it.
Getting the null reference error in the powerups script line 79 reset function Tank=GameObject.FindWithTag("Player")
using System.Collections.Generic;
using UnityEngine;
public class PowerUp : MonoBehaviour {
public bool boosting = false;
public GameObject effect;
public AudioSource clip;
public GameObject Tank;
private void Start()
{
Tank = GameObject.Find("Tank(Clone)");
TankMovement script = GetComponent<TankMovement>();
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if (!boosting)
{
clip.Play();
GameObject explosion = Instantiate(effect, transform.position, transform.rotation);
Destroy(explosion, 2);
GetComponent<MeshRenderer>().enabled = false;
GetComponent<Collider>().enabled = false;
Tank.GetComponent<TankMovement>().m_Speed = 20f;
//TankMovement.m_Speed = 20f;
boosting = true;
Debug.Log(boosting);
StartCoroutine(coolDown());
}
}
private IEnumerator coolDown()
{
if (boosting == true)
{
yield return new WaitForSeconds(4);
{
boosting = false;
GetComponent<MeshRenderer>().enabled = true;
GetComponent<Collider>().enabled = true;
Debug.Log(boosting);
// Destroy(gameObject);
}
}
}
void reset()
{
//TankMovement.m_Speed = 12f;
TankMovement collidedMovement = Tank.gameObject.GetComponent<TankMovement>();
collidedMovement.m_Speed = 12f;
//TankMovement1.m_Speed1 = 12f;
}
}
}
Trying to call on my m_Speed float in the player script to boost the speed of my player when he collides with it. How would you get a proper reference since my player is a prefab.
Tank script
using UnityEngine;
public class TankMovement : MonoBehaviour
{
public int m_PlayerNumber = 1;
public float m_Speed = 12f;
public float m_TurnSpeed = 180f;
public AudioSource m_MovementAudio;
public AudioClip m_EngineIdling;
public AudioClip m_EngineDriving;
public float m_PitchRange = 0.2f;
private string m_MovementAxisName;
private string m_TurnAxisName;
private Rigidbody m_Rigidbody;
private float m_MovementInputValue;
private float m_TurnInputValue;
private float m_OriginalPitch;
private void Awake()
{
m_Rigidbody = GetComponent<Rigidbody>();
}
private void OnEnable ()
{
m_Rigidbody.isKinematic = false;
m_MovementInputValue = 0f;
m_TurnInputValue = 0f;
}
private void OnDisable ()
{
m_Rigidbody.isKinematic = true;
}
private void Start()
{
m_MovementAxisName = "Vertical" + m_PlayerNumber;
m_TurnAxisName = "Horizontal" + m_PlayerNumber;
m_OriginalPitch = m_MovementAudio.pitch;
}
private void Update()
{
// Store the player's input and make sure the audio for the engine is playing.
m_MovementInputValue = Input.GetAxis(m_MovementAxisName);
m_TurnInputValue = Input.GetAxis(m_TurnAxisName);
EngineAudio();
}
private void EngineAudio()
{
// Play the correct audio clip based on whether or not the tank is moving and what audio is currently playing.
if (Mathf.Abs(m_MovementInputValue) < 0.1f && Mathf.Abs(m_TurnInputValue) < 0.1f)
{
if (m_MovementAudio.clip == m_EngineDriving)
{
m_MovementAudio.clip = m_EngineIdling;
m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
m_MovementAudio.Play();
}
}
else
{
if (m_MovementAudio.clip == m_EngineIdling)
{
m_MovementAudio.clip = m_EngineDriving;
m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
m_MovementAudio.Play();
}
}
}
private void FixedUpdate()
{
// Move and turn the tank.
Move();
Turn();
}
private void Move()
{
// Adjust the position of the tank based on the player's input.
Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;
m_Rigidbody.MovePosition(m_Rigidbody.position + movement);
}
private void Turn()
{
// Adjust the rotation of the tank based on the player's input.
float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;
Quaternion turnRotation = Quaternion.Euler(0f, turn, 0);
m_Rigidbody.MoveRotation(m_Rigidbody.rotation * turnRotation);
}
}
Since the TankMovement component you need to access is attached to the GameObject that is colliding with the power, you can get the TankMovement component you need to change by using other.gameObject.GetComponent<TankMovement>():
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if (!boosting)
{
// stuff
TankMovement collidedMovement = other.gameObject.GetComponent<TankMovement>();
collidedMovement.m_Speed = 20f;
// more stuff
}
}
}