Untitled
unknown
plain_text
a year ago
30 kB
5
Indexable
using System.Collections;
using UnityEngine;
using UnityEngine.Tilemaps;
public class PlayerController : MonoBehaviour
{
[Header("Movement Settings")]
public float speed;
public float jump;
public float maxJumpTime;
public float jumpMultiplier;
public LayerMask groundLayer;
public Transform groundCheck;
[Header("Attack Settings")]
public GameObject meleeCheck;
public GameObject projectilePrefab;
public Transform shootPoint;
public float projectileSpeed = 10f;
[Header("Miscellaneous")]
public GameObject fallDetector;
public AudioClip jumpClip;
public AudioClip atkClip;
private CapsuleCollider2D boxCollider2d;
private Rigidbody2D rigidbody2D;
private Animator anim;
private AudioSource audioPlayer;
private SpriteRenderer spriteRenderer;
private bool facingRight = true;
public bool isJumping;
public float currentJumpTime;
public bool grounded = true;
private bool isAttacking = false;
public bool canShoot;
[SerializeField] private GameObject OneWayHitCheck;
private IEnvironmentModifier currentEnvironment;
[SerializeField] private float wallCheckDistance = 0.5f; // Distance for wall detection
[SerializeField] private LayerMask wallLayer; // Layer for walls
private bool isTouchingWall;
private Vector2 slopeNormalPerp;
private float slopeDownAngle;
private float slopeSideAngle;
private float lastSlopeAngle;
public bool canMagicMeat;
[SerializeField]
private PhysicsMaterial2D noFriction;
[SerializeField]
private PhysicsMaterial2D fullFriction;
//slopes
[SerializeField]
private float slopeCheckDistance;
[SerializeField]
private float maxSlopeAngle;
[SerializeField]
private bool isOnSlope;
[SerializeField]
private bool canWalkOnSlope;
//platform
public bool isOnPlatform;
public Rigidbody2D platformRb;
//double jump powerup
public bool canDoubleJump;
public bool ShouldDoubleJump = true;
private Vector2 newVelocity;
private Vector2 newForce;
public bool faceRight = true;
public bool isOnIce = false;
void Awake()
{
boxCollider2d = GetComponent<CapsuleCollider2D>();
rigidbody2D = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
audioPlayer = GetComponent<AudioSource>();
meleeCheck.SetActive(false);
//headCollider = transform.Find("headCheck").GetComponent<BoxCollider2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
if(spriteRenderer.size == new Vector2(-4, 4))
{
faceRight = false;
}
else
{
faceRight = true;
}
}
private void Update()
{
grounded = IsTouchingGround();
isTouchingWall = IsTouchingWall();
HandleAttack();
HandleJump();
}
void FixedUpdate()
{
Debug.Log("Grounded: " + grounded);
if (grounded)
{
SlopeCheck();
}
HandleMovement();
if (currentEnvironment != null)
{
currentEnvironment.ApplyModifier(this);
}
}
private void HandleMovement()
{
float inputHorizontal = Input.GetAxisRaw("Horizontal");
if (currentEnvironment is not WaterModifier)
{
if (isOnIce && grounded) //Ice physics
{
ApplyIceEffects(inputHorizontal);
}
if (grounded && isOnSlope && canWalkOnSlope && !isJumping)
{
HandleSlopeMovement(inputHorizontal);
}
else if (grounded && !isOnSlope && !isJumping && !isTouchingWall)
{
HandleFlatMovement(inputHorizontal);
}
else if (!grounded)
{
rigidbody2D.velocity = new Vector2(inputHorizontal * speed, rigidbody2D.velocity.y);
}
if (!grounded && !isTouchingWall)
{
rigidbody2D.velocity = new Vector2(inputHorizontal * speed, rigidbody2D.velocity.y);
}
}
// Sprite flip logic
if (inputHorizontal > 0 && !facingRight)
{
Flip();
}
else if (inputHorizontal < 0 && facingRight)
{
Flip();
}
anim.SetBool("Run", inputHorizontal != 0);
}
private void ApplyIceEffects(float inputHorizontal)
{
if (!grounded) return; // Skip ice effects if airborne
if (isOnSlope)
{
// Calculate the slope's tangent direction
Vector2 slopeDirection = slopeNormalPerp.normalized;
Debug.Log("slope direction " + slopeDirection);
if (inputHorizontal != 0)
{
// Move along the slope based on input direction
float moveDirection = Mathf.Sign(inputHorizontal); // +1 for right, -1 for left
Vector2 targetVelocity = slopeDirection * (moveDirection * speed);
rigidbody2D.velocity = Vector2.Lerp(rigidbody2D.velocity, targetVelocity, 0.1f);
rigidbody2D.gravityScale = 1;
}
else
{
// Project velocity onto the slope's tangent for consistent sliding
float projectedVelocity = Vector2.Dot(rigidbody2D.velocity, slopeDirection);
Debug.Log("PROJECTED vELOCITY :" + projectedVelocity);
Vector2 slideVelocity = slopeDirection * projectedVelocity;
// Apply deceleration to stop sliding over time
if (Mathf.Abs(projectedVelocity) < 0.1f)
{
rigidbody2D.velocity = Vector2.zero; // Stop sliding completely
rigidbody2D.gravityScale = 0;
}
else
{
Debug.Log("Sliding!" + slideVelocity * 0.95f);
rigidbody2D.velocity = slideVelocity * 0.95f; // Gradual deceleration
rigidbody2D.gravityScale = 1;
}
}
}
else
{
// Flat ground: consistent ice physics
if (inputHorizontal == 0)
{
// Gradual deceleration when idle
if (Mathf.Abs(rigidbody2D.velocity.x) < 0.1f)
{
rigidbody2D.velocity = new Vector2(0, rigidbody2D.velocity.y);
}
else
{
Debug.Log("Sliding!" + new Vector2(
rigidbody2D.velocity.x * 0.98f,
rigidbody2D.velocity.y
));
rigidbody2D.velocity = new Vector2(
rigidbody2D.velocity.x * 0.98f,
rigidbody2D.velocity.y
);
}
}
else
{
// Smooth movement based on input
Vector2 targetVelocity = new Vector2(inputHorizontal * speed, rigidbody2D.velocity.y);
Debug.Log("targetedVelocity: " + targetVelocity);
rigidbody2D.velocity = Vector2.Lerp(rigidbody2D.velocity, targetVelocity, 0.1f);
}
}
}
private void HandleFlatMovement(float inputHorizontal)
{
if (isOnIce)
{
//ApplyIceEffects(inputHorizontal);
}
else
{
rigidbody2D.sharedMaterial = noFriction;
Vector2 newVelocity = new Vector2(
inputHorizontal * speed,
rigidbody2D.velocity.y > 0 ? 0 : rigidbody2D.velocity.y // Prevent upward launch
); // Prevent upward launch
rigidbody2D.velocity = newVelocity;
rigidbody2D.gravityScale = 1;
}
if (inputHorizontal > 0 && !facingRight)
{
Flip();
}
else if (inputHorizontal < 0 && facingRight)
{
Flip();
}
anim.SetBool("Run", inputHorizontal != 0);
}
private void HandleSlopeMovement(float inputHorizontal)
{
if (inputHorizontal == 0)
{
// When stationary
if (isOnIce)
{
ApplyIceEffects(inputHorizontal);
}
if (isOnSlope)
{
// Apply friction to prevent sliding on slopes
rigidbody2D.sharedMaterial = fullFriction;
rigidbody2D.velocity = Vector2.zero;
rigidbody2D.gravityScale = 0; // Disable gravity when stationary on a slope
}
else
{
// Flat ground behavior
rigidbody2D.sharedMaterial = fullFriction;
rigidbody2D.velocity = Vector2.zero;
rigidbody2D.gravityScale = 1; // Enable normal gravity
}
}
else
{
// When moving
rigidbody2D.sharedMaterial = noFriction;
if (isOnSlope && slopeDownAngle > 0)
{
// Align velocity with slope
newVelocity.Set(
speed * slopeNormalPerp.x * -inputHorizontal,
Mathf.Clamp(speed * slopeNormalPerp.y * -inputHorizontal, -5f,0)
);
rigidbody2D.velocity = newVelocity;
rigidbody2D.gravityScale = 1; // Ensure normal gravity during movement
}
else
{
// Flat ground or non-slope movement
newVelocity.Set(speed * inputHorizontal, 0f);
rigidbody2D.velocity = newVelocity;
rigidbody2D.gravityScale = 1;
}
}
}
private void HandleJump()
{
//grounded = IsTouchingGround();
if (currentEnvironment is not WaterModifier)
{
if (Input.GetButtonDown("Jump"))
{
if (grounded)
{
isOnSlope = false;
isOnIce = false;
Debug.Log("Begun Jump");
ShouldDoubleJump = true;
// Jump only when grounded
isJumping = true;
currentJumpTime = 0f;
audioPlayer.PlayOneShot(jumpClip);
}
else if (isTouchingWall && !isJumping)
{
isJumping = true;
currentJumpTime = 0f;
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, jump);
audioPlayer.PlayOneShot(jumpClip);
}
else if (ShouldDoubleJump && canDoubleJump && !isJumping && rigidbody2D.velocity.y > 0)
{
ShouldDoubleJump = false;
isJumping = true;
currentJumpTime = 0f;
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, jump);
audioPlayer.PlayOneShot(jumpClip);
}
if (Input.GetButton("Jump") && isJumping)
{
if (currentJumpTime < maxJumpTime)
{
Debug.Log("Current Jump Time" + currentJumpTime);
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, jump + (currentJumpTime * jumpMultiplier));
currentJumpTime += Time.deltaTime;
}
else
{
Debug.Log("Max Jump Time");
isJumping = false;
}
}
if (Input.GetButtonUp("Jump"))
{
isJumping = false;
Debug.Log("Not Jumping");
}
// Ceiling detection to cancel jump
if (IsTouchingCeiling())
{
Debug.Log("Touched Ceiling");
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, 0); // Cancel vertical velocity
currentJumpTime = maxJumpTime;
isJumping = false; // Stop the jump
}
}
// Hold jump to increase height
if (Input.GetButton("Jump") && isJumping)
{
if (currentJumpTime < maxJumpTime)
{
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, jump + (currentJumpTime * jumpMultiplier));
currentJumpTime += Time.deltaTime;
}
else
{
isJumping = false;
}
}
// Release jump button
if (Input.GetButtonUp("Jump"))
{
isJumping = false;
}
if (!grounded)
{
rigidbody2D.sharedMaterial = noFriction;
rigidbody2D.gravityScale = 1;
}
}
anim.SetBool("grounded", grounded);
}
private bool IsTouchingGround()
{
float yOffset = boxCollider2d.bounds.size.y / 2f;
float xOffset = boxCollider2d.bounds.size.x / 2f;
Vector2 bottomLeft = new Vector2(transform.position.x - xOffset, transform.position.y - yOffset);
Vector2 bottomRight = new Vector2(transform.position.x + xOffset, transform.position.y - yOffset);
float rayLength = 0.1f; // Adjust the ray length as needed
bool notTouchingGround = (!isJumping && (currentJumpTime >= maxJumpTime) && (rigidbody2D.velocity.y > 0));
Vector2 bottomCenter = new Vector2(transform.position.x, transform.position.y - yOffset);
// Perform a box cast straight down from the bottom center of the player
RaycastHit2D[] hits = Physics2D.BoxCastAll(bottomCenter, new Vector2(xOffset * 2, rayLength), 0f, Vector2.down, rayLength, groundLayer);
// Visualize the box cast in the Scene view
Debug.DrawRay(bottomCenter, Vector2.down * rayLength, Color.red);
foreach (var hit in hits)
{
// Return true if the box cast hits the ground
if (hit.collider != null)
{
//Debug.Log(hit.collider.gameObject.tag);
if (hit.collider.gameObject.CompareTag("Ice"))
{
Debug.Log("Is on Ice");
isOnIce = true;
}
else
{
isOnIce = false;
}
// Add a condition to allow jumping through one-way platforms
if (hit.collider.gameObject.layer == 3)
{
// Handle one-way platforms in a Tilemap
if (hit.collider is CompositeCollider2D compositeCollider)
{
Tilemap tilemap = hit.collider.GetComponent<Tilemap>();
if (tilemap != null)
{
// Check tiles under both bottom corners
Vector3Int leftTilePosition = tilemap.WorldToCell(bottomLeft);
Vector3Int rightTilePosition = tilemap.WorldToCell(bottomRight);
TileBase leftTile = tilemap.GetTile(leftTilePosition);
TileBase rightTile = tilemap.GetTile(rightTilePosition);
// Ensure both corners are above tiles
if (leftTile != null && rightTile != null)
{
Vector3 leftTileWorldPosition = tilemap.GetCellCenterWorld(leftTilePosition);
Vector3 rightTileWorldPosition = tilemap.GetCellCenterWorld(rightTilePosition);
// Check for PlatformEffector2D components in the Tilemap
PlatformEffector2D leftEffector = tilemap.GetComponent<PlatformEffector2D>();
PlatformEffector2D rightEffector = tilemap.GetComponent<PlatformEffector2D>();
Debug.Log("Not touching ground: " + notTouchingGround);
// Skip tiles with upward-facing Platform Effectors during upward movement
if (notTouchingGround)
{
if ((leftEffector != null && Mathf.Approximately(leftEffector.rotationalOffset, 0f)) ||
(rightEffector != null && Mathf.Approximately(rightEffector.rotationalOffset, 0f)))
{
Debug.Log("Plateforme");
return false;
}
if ((transform.position.y - boxCollider2d.bounds.size.y) > leftTileWorldPosition.y &&
(transform.position.y - boxCollider2d.bounds.size.y) > rightTileWorldPosition.y)
{
Debug.Log("Sur le sol");
return true;
}
}
else
{
Debug.Log("Pas de sol");
return false;
}
}
}
}
// Handle other one-way platforms or solid ground
else if (hit.collider.TryGetComponent(out PlatformEffector2D effector))
{
if (currentJumpTime >= maxJumpTime &&
(transform.position.y - boxCollider2d.bounds.size.y) > hit.collider.bounds.max.y - 0.01f &&
bottomLeft.y > hit.collider.bounds.max.y - 0.01f &&
bottomRight.y > hit.collider.bounds.max.y - 0.01f)
{
Debug.Log("Plateforme solide");
return true;
}
}
else
{
// Handle solid ground
if (bottomLeft.y > hit.collider.bounds.max.y - 0.01f &&
bottomRight.y > hit.collider.bounds.max.y - 0.01f)
{
Debug.Log("Sol solide");
return true;
}
}
}
anim.SetBool("grounded", hit.collider != null);
// Return true if the box cast hits the ground
return hit.collider != null;
}
}
return false;
}
private void HandleAttack()
{
if (Input.GetButtonDown("Fire2") && !isAttacking)
{
anim.SetTrigger("Attack2");
StartCoroutine(DoAttack());
if (canShoot)
{
ShootProjectile();
}
}
}
IEnumerator DoAttack()
{
isAttacking = true;
meleeCheck.SetActive(true);
audioPlayer.PlayOneShot(atkClip);
yield return new WaitForSeconds(0.3f);
isAttacking = false;
meleeCheck.SetActive(false);
}
private void Flip()
{
facingRight = !facingRight;
Vector3 currentScale = transform.localScale;
currentScale.x *= -1;
transform.localScale = currentScale;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.TryGetComponent<IEnvironmentModifier>(out var modifier))
{
currentEnvironment = modifier;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.TryGetComponent<IEnvironmentModifier>(out var modifier) && modifier == currentEnvironment)
{
currentEnvironment = null;
}
}
private bool IsTouchingCeiling()
{
float yOffset = boxCollider2d.bounds.extents.y;
float xOffset = boxCollider2d.bounds.extents.x;
Vector2 topLeft = new Vector2(transform.position.x - xOffset, transform.position.y + yOffset);
Vector2 topRight = new Vector2(transform.position.x + xOffset, transform.position.y + yOffset);
RaycastHit2D[] hits = Physics2D.BoxCastAll(topLeft, new Vector2(boxCollider2d.bounds.size.x, 0.1f), 0f, Vector2.up, 0.1f, groundLayer);
foreach (var hit in hits)
{
if (hit.collider != null)
{
// Skip upward-facing Platform Effectors during upward movement
if (hit.collider.TryGetComponent(out PlatformEffector2D effector))
{
if (Mathf.Approximately(effector.rotationalOffset, 0f) && rigidbody2D.velocity.y > 0)
{
Debug.Log("Plateforme");
return false ;
}
}
else if (hit.collider is CompositeCollider2D compositeCollider)
{
Tilemap tilemap = hit.collider.GetComponent<Tilemap>();
if (tilemap != null)
{
Vector3Int tilePosition = tilemap.WorldToCell(transform.position + new Vector3(0, yOffset + 0.05f, 0));
TileBase tile = tilemap.GetTile(tilePosition);
if (tile != null)
{
PlatformEffector2D tileEffector = tilemap.GetComponent<PlatformEffector2D>();
// Skip tiles with upward-facing Platform Effectors during upward movement
if (tileEffector != null && Mathf.Approximately(tileEffector.rotationalOffset, 0f) && rigidbody2D.velocity.y > 0)
{
Debug.Log("Plateforme");
continue;
}
Vector3 tileWorldPosition = tilemap.GetCellCenterWorld(tilePosition);
if (transform.position.y < tileWorldPosition.y)
{
Debug.Log("Plafond!");
return true;
}
}
}
}
else
{
// Handle solid objects
if (topLeft.y < hit.collider.bounds.min.y && topRight.y < hit.collider.bounds.min.y)
{
Debug.Log("Plafond Solide!");
return true;
}
}
}
}
return false;
}
private bool IsTouchingWall()
{
// Cast ray to the left and right of the player
Vector2 position = transform.position;
RaycastHit2D wallHitLeft = Physics2D.Raycast(position, Vector2.left, wallCheckDistance, wallLayer);
RaycastHit2D wallHitRight = Physics2D.Raycast(position, Vector2.right, wallCheckDistance, wallLayer);
Debug.DrawRay(position, Vector2.left * wallCheckDistance, Color.red); // Visualize left ray
Debug.DrawRay(position, Vector2.right * wallCheckDistance, Color.red); // Visualize right ray
// Check if the left wall is not an upward-facing Platform Effector
bool wallOnLeft = wallHitLeft.collider != null &&
(!wallHitLeft.collider.TryGetComponent(out PlatformEffector2D effectorLeft) ||
!Mathf.Approximately(effectorLeft.rotationalOffset, 0f));
// Check if the right wall is not an upward-facing Platform Effector
bool wallOnRight = wallHitRight.collider != null &&
(!wallHitRight.collider.TryGetComponent(out PlatformEffector2D effectorRight) ||
!Mathf.Approximately(effectorRight.rotationalOffset, 0f));
Debug.Log("Murs: " + (wallOnLeft || wallOnRight));
return wallOnLeft || wallOnRight;
}
void ShootProjectile()
{
if (projectilePrefab != null && shootPoint != null)
{
// Instantiate the projectile at the shootPoint position and rotation
GameObject newProjectile = Instantiate(projectilePrefab.gameObject, shootPoint.position, shootPoint.rotation);
PlayerProjectle playerProjectle = newProjectile.GetComponent<PlayerProjectle>();
Debug.Log("Tir");
// Calculate the direction of the projectile
Vector2 shootDirection = facingRight ? Vector2.right : Vector2.left;
playerProjectle.facingRight = facingRight ? true : false;
// Access the projectile's Rigidbody2D component
Rigidbody2D projectileRigidbody = playerProjectle.GetComponent<Rigidbody2D>();
if (projectileRigidbody != null)
{
// Apply force to the projectile in the shoot direction
//playerProjectle.maxDistance += Math.Abs(rigidbody2D.velocity.x/2);
projectileRigidbody.velocity = shootDirection * playerProjectle.speed + rigidbody2D.velocity;
Debug.Log("Vitesse projectile:" + projectileRigidbody.velocity);
}
}
}
//Slope methods
private void SlopeCheck()
{
// Position at the player's feet (adjusted to align with bottom edge)
Vector2 checkPos = (Vector2)transform.position - new Vector2(0f, boxCollider2d.bounds.extents.y);
// Perform horizontal and vertical slope checks
SlopeCheckHorizontal(checkPos);
SlopeCheckVertical(checkPos);
if (isOnSlope)
{
Debug.Log("Is on Slope");
rigidbody2D.sharedMaterial = fullFriction;
Debug.Log("SlopeNormalPerp:" + slopeNormalPerp.x + ", " + slopeNormalPerp.y);
}
else
{
Debug.Log("Not on Slope");
}
}
private void SlopeCheckHorizontal(Vector2 checkPos)
{
RaycastHit2D slopeHitFront = Physics2D.Raycast(checkPos, transform.right, slopeCheckDistance*2, groundLayer);
RaycastHit2D slopeHitBack = Physics2D.Raycast(checkPos, -transform.right, slopeCheckDistance*2, groundLayer);
Debug.DrawRay(checkPos, transform.right * slopeCheckDistance, Color.red);
Debug.DrawRay(checkPos, -transform.right * slopeCheckDistance, Color.blue);
if (slopeHitFront || slopeHitBack)
{
slopeSideAngle = slopeHitFront ? Vector2.Angle(slopeHitFront.normal, Vector2.up) : Vector2.Angle(slopeHitBack.normal, Vector2.up);
if (slopeSideAngle <= maxSlopeAngle)
{
Debug.Log("Is On Slope H");
isOnSlope = true;
Debug.Log("slope side angle " + slopeSideAngle);
return;
}
}
else
{
Debug.Log("Is not on slope H");
slopeSideAngle = 0f;
isOnSlope = false;
}
}
private void SlopeCheckVertical(Vector2 checkPos)
{
float colliderWidth = boxCollider2d.bounds.size.x;
int rayCount = 5; // Number of rays to cast
float raySpacing = colliderWidth / (rayCount - 1);
float rayStartOffset = -colliderWidth / 2; // Start at the left of the collider
slopeDownAngle = 0f; // Reset slope angle
isOnSlope = false; // Reset slope state
canWalkOnSlope = false;
for (int i = 0; i < rayCount; i++)
{
// Calculate the position for this ray
Vector2 rayOrigin = checkPos + new Vector2(rayStartOffset + (i * raySpacing), 0);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.down, slopeCheckDistance, groundLayer);
Debug.DrawRay(rayOrigin, Vector2.down * slopeCheckDistance, Color.yellow); // Debug visualization
if (hit)
{
// Calculate the slope angle and perpendicular direction
float currentSlopeAngle = Vector2.Angle(hit.normal, Vector2.up);
// Update slope values if this ray detects a valid slope
if ((currentSlopeAngle>0)&&(currentSlopeAngle <= maxSlopeAngle))
{
slopeNormalPerp = Vector2.Perpendicular(hit.normal).normalized;
slopeDownAngle = currentSlopeAngle;
isOnSlope = true;
canWalkOnSlope = true;
Debug.DrawRay(hit.point, slopeNormalPerp, Color.green); // Slope perpendicular
Debug.DrawRay(hit.point, hit.normal, Color.red); // Slope normal
return; // Stop further checks once a valid slope is found
}
}
}
// If no valid slope is detected
slopeNormalPerp = Vector2.zero;
slopeDownAngle = 0f;
isOnSlope = false;
canWalkOnSlope = false;
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.collider.CompareTag("Ice"))
{
isOnIce = true;
}
}
private void OnCollisionExit2D(Collision2D collision)
{
if (collision.collider.CompareTag("Ice"))
{
isOnIce = false;
}
}
}
Editor is loading...
Leave a Comment