Hi !
Sorry for the delay…
So there is my “Frankencode” : i’m a newbie, and i’m learning everything with this game project. as you could expect, “my” code is a mix of several tutorials, codes found here and there, and some ahem personnal tries… it’s a mess, i’m trying to keep it clean and to simplify. Sorry for that… and some names are in french (i’m french) so tell me if you need an translation/explanation. sorry for that !
Here’s in the inspector, the components for my player :
as you can see there is a several scripts :
- a character controller,
- a script for moving the player
- a script for collisions
and two 2D capsule colliders : one for the top of the body wich is disconnected when the player crouches, and the other it for the low part of the body.
the player (“joueur” in french) as several gameobjects parented :
- Ceiling check
- Ground check
- Nouvelle Position
the first and second are obvious enough i think, the third “nouvellePosition” (=NewPosition) is placed near the feet and is used to “teleport” my player when climbing a ledge. At the very last frame of my climb animation, the gameobjecti is moved from feet to the hands position and then, replace by the idle animation.
i hope i’m clear.
And finally, the 3 scripts i’m using :
using UnityEngine;
using UnityEngine.Events;
public class CharacterController2D : MonoBehaviour
{
[SerializeField] private float m_JumpForce = 3400f; // Amount of force added when the player jumps >> à priori juste pour la hauteur donc ?
[Range(0, 1)] [SerializeField] private float m_CrouchSpeed = .36f; // Amount of maxSpeed applied to crouching movement. 1 = 100%
[Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f; // How much to smooth out the movement
[SerializeField] private bool m_AirControl = false; // Whether or not a player can steer while jumping;
[SerializeField] private LayerMask m_WhatIsGround; // A mask determining what is ground to the character
[SerializeField] private Transform m_GroundCheck; // A position marking where to check if the player is grounded.
[SerializeField] private Transform m_CeilingCheck; // A position marking where to check for ceilings
[SerializeField] private Collider2D m_CrouchDisableCollider; // A collider that will be disabled when crouching
const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded
public static bool m_Grounded; // Whether or not the player is grounded.
const float k_CeilingRadius = .2f; // Radius of the overlap circle to determine if the player can stand up
private Rigidbody2D m_Rigidbody2D;
private bool m_FacingRight = true; // For determining which way the player is currently facing.
private Vector3 m_Velocity = Vector3.zero;
public static bool isWalking;
public static bool isJumping;
public static bool isDead = false;
public static bool isGrabbing; // virer = false si necessaire ?
public static bool isLedging = false; //test
[Header("Events")]
[Space]
public UnityEvent OnLandEvent;
[System.Serializable]
public class BoolEvent : UnityEvent<bool> { }
public BoolEvent OnCrouchEvent;
private bool m_wasCrouching = false;
private void Awake()
{
m_Rigidbody2D = GetComponent<Rigidbody2D>();
if (OnLandEvent == null)
OnLandEvent = new UnityEvent();
if (OnCrouchEvent == null)
OnCrouchEvent = new BoolEvent();
}
private void FixedUpdate()
{
bool wasGrounded = m_Grounded;
m_Grounded = false;
// The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
// This can be done using layers instead but Sample Assets will not overwrite your project settings.
Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
m_Grounded = true;
if (!wasGrounded)
OnLandEvent.Invoke();
}
}
}
public void Move(float move, bool crouch, bool jump)
{
// If crouching, check to see if the character can stand up
if (!crouch)
{
// If the character has a ceiling preventing them from standing up, keep them crouching
if (Physics2D.OverlapCircle(m_CeilingCheck.position, k_CeilingRadius, m_WhatIsGround))
{
crouch = true;
}
}
//only control the player if grounded or airControl is turned on
if (m_Grounded || m_AirControl)
{
// If crouching
if (crouch)
{
if (!m_wasCrouching)
{
m_wasCrouching = true;
OnCrouchEvent.Invoke(true);
}
// Reduce the speed by the crouchSpeed multiplier
move *= m_CrouchSpeed;
// Disable one of the colliders when crouching
if (m_CrouchDisableCollider != null)
m_CrouchDisableCollider.enabled = false;
} else
{
// Enable the collider when not crouching
if (m_CrouchDisableCollider != null)
m_CrouchDisableCollider.enabled = true;
if (m_wasCrouching)
{
m_wasCrouching = false;
OnCrouchEvent.Invoke(false);
}
}
// Move the character by finding the target velocity
Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y);
// And then smoothing it out and applying it to the character
m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing);
// If the input is moving the player right and the player is facing left...
if (move > 0 && !m_FacingRight)
{
// ... flip the player.
Flip();
}
// Otherwise if the input is moving the player left and the player is facing right...
else if (move < 0 && m_FacingRight)
{
// ... flip the player.
Flip();
}
}
// If the player should jump...
if (m_Grounded && jump && !isDead)
{
// Add a vertical force to the player.
m_Grounded = false;
m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));
}
}
private void Flip()
{
// Switch the way the player is labelled as facing.
m_FacingRight = !m_FacingRight;
// Multiply the player's x local scale by -1.
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController2D controller;
public Animator animator;
public float horizontalMove = 0f;
public static float runSpeed = 150f;
bool jump = false;
bool crouch = false;
void Update()
{
// Inputs
// fleches gauche et droite = avancer
horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
animator.SetFloat("Mouvement", Mathf.Abs(horizontalMove));
// Bouton Saut
if (Input.GetButtonDown("Jump"))
{
jump = true;
CharacterController2D.isJumping = true;
animator.SetBool("Saute", true);
}
// Bouton se baisser
if (Input.GetButtonDown("Crouch"))
{
crouch = true;
}
else if (Input.GetButtonUp("Crouch"))
{
crouch = false;
}
// Bouton monter plateforme
if (CharacterController2D.isLedging = true && Input.GetButtonDown("Up"))
{
animator.SetBool("Monte", true);
}
///////// Pour utiliser la Manette PS4 ///////
// Bouton Saut PS4
if (Input.GetButtonDown("PS4_X"))
{
jump = true;
CharacterController2D.isJumping = true;
animator.SetBool("Saute", true);
}
// TEST PS4
if (Input.GetButtonDown("PS4_C"))
{
crouch = true;
}
else if (Input.GetButtonUp("PS4_C"))
{
crouch = false;
}
}
public void OnLanding ()
{
animator.SetBool("Saute", false);
}
public void OnCrouching (bool IsCrouching)
{
animator.SetBool("SeBaisse", IsCrouching);
}
void FixedUpdate()
{
// Déplacer le joueur
// avancer
controller.Move(horizontalMove * Time.fixedDeltaTime, crouch, jump);
CharacterController2D.isGrabbing = false;
jump = false;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Collisions : MonoBehaviour
{
public Collider2D ColliderHaut;
public Collider2D ColliderBas;
public Animator animator;
private float TempsEnLair = 0f;
public float HauteurMortelle = 3f;
public GameObject Joueur;
public Transform NouvellePosition;
private void Update()
{
ChuteMortelle();
}
void ChuteMortelle()
{
CharacterController2D controller = GetComponent<CharacterController2D>();
if (CharacterController2D.m_Grounded)
{
TempsEnLair = 0f;
}
if (!CharacterController2D.m_Grounded)
{
TempsEnLair += Time.deltaTime;
}
if (TempsEnLair >= HauteurMortelle)
{
CharacterController2D.isDead = true;
Debug.Log("Chute Mortelle !");
}
}
void OnCollisionEnter2D(Collision2D collision)
{
/// Pour se suspendre aux plateformes
if (collision.gameObject.tag == "MursGrimpables")
{
CharacterController2D.isGrabbing = true;
animator.SetBool("EnCollisionAvecUnMurGrimpable", true);
//Quand le joueur touche un mur, sa vitesse tombe à 0. Mais pour repartir, il faut que cette valeur ne soit pas gelée. d'ou l'ajout d'une durée avec la methode 'invoke' juste après
PlayerMovement.runSpeed = 0f;
// attend un moment avant de revenir à la valeur définie par le private void plus bas
Invoke("Reset_runSpeed", 0.05f);
}
if (collision.gameObject.tag == "Murs")
{
//Debug.Log("Contact");
animator.SetBool("EnCollisionAvecUnMur", true);
//Quand le joueur touche un mur, sa vitesse tombe à 0. Mais pour repartir, il faut que cette valeur ne soit pas gelée. D'où l'ajout d'une durée avec la methode 'invoke' juste après ->
PlayerMovement.runSpeed = 0f;
// Attend un moment avant de revenir à la valeur définie par le private void plus bas Reset_runSpeed
Invoke("Reset_runSpeed", 0.05f);
}
}
void OnCollisionStay2D(Collision2D collision)
{
if (collision.gameObject.tag == "EauMortelle")
{
PlayerMovement.runSpeed = 0f;
CharacterController2D.isDead = true;
animator.SetBool("MortNoyade", true);
}
if (collision.gameObject.tag == "Sols" && CharacterController2D.isDead)
{
//PlayerMovement.runSpeed = 0f;
//CharacterController2D.isDead = true;
animator.SetBool("ChuteMortelle", true);
}
}
private void Reset_runSpeed()
{
// la valeur à laquelle revenir après le délai 'invoke'
PlayerMovement.runSpeed = 150f;
}
private void MortNoyade()
{
animator.speed = 0f;
PlayerMovement.runSpeed = 0f;
}
private void Monte()
{
CharacterController2D.isLedging = true;
}
private void EstMonte()
{
CharacterController2D.isLedging = false;
CharacterController2D.isJumping = false;
animator.SetBool("Monte", false);
CharacterController2D.m_Grounded = true;
Joueur.transform.position = NouvellePosition.transform.position;
}
void OnCollisionExit2D(Collision2D collision)
{
if (collision.gameObject.tag == "MursGrimpables")
{
CharacterController2D.isGrabbing = false;
animator.SetBool("EnCollisionAvecUnMurGrimpable", false);
}
if (collision.gameObject.tag == "Murs")
{
animator.SetBool("EnCollisionAvecUnMur", false);
}
}
}
Well sorry for the mess.
My intention is to symplify all that, with a better and clearer scripts.
thanks for you patience
(if needed, few translations
- murs = walls
- MursGrimpables = climbing walls
- EnCollisionAvecUnMurGrimpable = Collision with a climbing walls