MIF_E31222586/Assets/Scripts/player.cs

329 lines
10 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class player : MonoBehaviour
{
[Header ("Movement Settings")]
public float speed;
public float jumpscale;
[Header("Ground & Wall Detection")]
public bool isground, iswall;
public float rayLength = 0.3f;
public LayerMask groundLayer;
[Header("Game References")]
public GameObject soal;
public GameObject gameover;
public GameObject finish;
public healthmanager healthmanager;
[Header("Audio")]
public AudioSource jump_audio;
public AudioSource soal_audio;
public AudioSource walk_audio;
public AudioSource fall_audio;
public AudioSource finish_audio;
public AudioSource gameover_audio;
//private references
private Rigidbody2D body;
private SpriteRenderer sprite;
private Animator animator;
private Vector3 safePosition;
private SoalPapanManager soalManager;
private skor_akhir UpdateLevel;
private BoxCollider2D wall_detector;
private checkpoint[] allCheckpoints;
private bool isRespawning = false;
private bool canJump = true;
private bool justRespawned = false;
//water detection
private bool inWater = false;
private float WaterDangerThreshold = -6.5f;
private float respawnYOffset = 0.5f;
void Start()
{
soalManager = soal.GetComponent<SoalPapanManager>();
body = GetComponent<Rigidbody2D>();
sprite = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
//set initial safe position;
safePosition = transform.position;
}
[Obsolete]
void Awake() {
allCheckpoints = GameObject.FindObjectsOfType<checkpoint>();
}
void Update()
{
if (isRespawning) return;
UpdateGroundWallCheck();
if (isground && !canJump && !justRespawned && Mathf.Abs(body.linearVelocity.y) < 0.1f)
{
canJump = true;
Debug.Log("Landed: canJump reset");
}
//handle input
if (Input.GetKey(KeyCode.RightArrow))
{
runright();
}
if (Input.GetKey(KeyCode.LeftArrow))
{
runleft();
}
if (Input.GetKeyUp(KeyCode.RightArrow) || Input.GetKeyUp(KeyCode.LeftArrow))
{
stop();
}
if (Input.GetKeyDown(KeyCode.UpArrow))
{
jump();
}
UpdateAnimation();
UpdateSafePosition();
CheckWaterFall();
Debug.DrawRay(transform.position, Vector2.down * rayLength, Color.red);
}
void UpdateGroundWallCheck()
{
RaycastHit2D hitGround = Physics2D.Raycast(transform.position, Vector2.down, rayLength, groundLayer);
isground = hitGround.collider != null;
iswall = Physics2D.Raycast(transform.position, Vector2.right, 0.3f, groundLayer).collider != null ||
Physics2D.Raycast(transform.position, Vector2.left, 0.3f, groundLayer).collider != null;
}
void UpdateSafePosition() {
//update safe position when player is on solid ground (not water)
if (Mathf.Abs(body.linearVelocity.y) < 0.1f && isground) {
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, 1.5f, groundLayer);
if (hit.collider != null && !hit.collider.CompareTag("Water")) {
safePosition = new Vector3(transform.position.x, hit.point.y + respawnYOffset, transform.position.z);
}
}
}
void CheckWaterFall() {
//check if player has fallen bellow the water danger threshold
if(transform.position.y < WaterDangerThreshold && !inWater) {
inWater = true;
HandleWaterFall();
}
//reset water detection when player is back above threshold
if(transform.position.y >= WaterDangerThreshold) {
inWater = false;
}
}
void HandleWaterFall()
{
//stop player movement
body.linearVelocity = Vector2.zero;
body.gravityScale = 0;
//disable camera flow
Camera.main.GetComponent<camerafollow>().enabled = false;
//reduce health
healthmanager.TakeDamage(1);
Debug.Log("Nyawa tersisa: " + healthmanager.health);
// play fall sound
if (Time.timeScale == 1)
{
fall_audio.Play();
}
// ✅ Ambil checkpoint terdekat
checkpoint nearestCP = FindNearestCheckpoint();
if (nearestCP != null)
{
safePosition = new Vector3(nearestCP.transform.position.x, nearestCP.transform.position.y + respawnYOffset, transform.position.z);
Debug.Log("Respawn ke checkpoint terdekat: " + nearestCP.name);
}
canJump = false;
justRespawned = true;
//check if player is still alive
if (healthmanager.isAlive())
{
StartCoroutine(RespawnRoutine());
}
else
{
StartCoroutine(GameOverRoutine());
}
}
bool IsSoalSedangAktif()
{
return soalManager != null && soalManager.IsSoalAktif();
}
public void runleft() {
sprite.flipX = true;
if (!IsSoalSedangAktif() && !gameover.activeSelf && !finish.activeSelf) {
body.linearVelocity = new Vector2(-speed, body.linearVelocity.y);
}
}
public void runright() {
sprite.flipX = false;
if (!IsSoalSedangAktif() && !gameover.activeSelf && !finish.activeSelf) {
body.linearVelocity = new Vector2(speed, body.linearVelocity.y);
}
}
public void stop() {
if (!IsSoalSedangAktif() && !gameover.activeSelf && !finish.activeSelf) {
body.linearVelocity = new Vector2(0, body.linearVelocity.y);
}
}
public void jump() {
if (justRespawned || !isground || !canJump)
return;
if (!IsSoalSedangAktif() && !gameover.activeSelf && !finish.activeSelf) {
body.linearVelocity = new Vector2(body.linearVelocity.x, jumpscale);
canJump = false;
if (Time.timeScale == 1) jump_audio.Play();
}
}
void UpdateAnimation() {
if(body.linearVelocity.y > 0.01f){
animator.SetInteger("state", 2);
walk_audio.Stop();
} else if(body.linearVelocity.y < -0.01f){
animator.SetInteger("state", 3);
walk_audio.Stop();
} else {
if(Math.Abs(body.linearVelocity.x) > speed/2f){
animator.SetInteger("state", 1);
if(!walk_audio.isPlaying && isground){
if(Time.timeScale == 1){
walk_audio.Play();
}
}
} else {
animator.SetInteger("state", 0);
walk_audio.Stop();
}
}
}
void OnTriggerEnter2D(Collider2D obj)
{
//if player touches water directly
if(obj.CompareTag("Water") && transform.position.y < WaterDangerThreshold && !isRespawning) {
HandleWaterFall();
}
// Jika menyentuh checkpoint
if (obj.CompareTag("Checkpoint")) {
safePosition = new Vector3(obj.transform.position.x, obj.transform.position.y + respawnYOffset, transform.position.z);
Debug.Log("Checkpoint updated at: " + safePosition);
}
//handle question activation
if (obj.CompareTag("pos")){
if (soalManager != null && !soalManager.IsSoalAktif())
{
soalManager.TampilkanSoal();
obj.gameObject.SetActive(false); // disable trigger papan
soal_audio.Play();
}
/*soal.transform.GetChild(obj.transform.GetSiblingIndex()).gameObject.SetActive(true);
obj.gameObject.SetActive(false);
soal_audio.Play();*/
}
//handle finish line
if(obj.CompareTag("Finish")) {
if (soal.GetComponent<SoalPapanManager>().soalterjawab == 5)
{
finish.SetActive(true);
finish_audio.Play();
}
}
}
IEnumerator RespawnRoutine()
{
isRespawning = true;
//yield return new WaitForSeconds(0.3f);
body.gravityScale = 2;
body.linearVelocity = Vector2.zero;
transform.position = safePosition;
Camera.main.GetComponent<camerafollow>().enabled = true;
Camera.main.GetComponent<camerafollow>().player = this.transform;
inWater = false;
yield return new WaitUntil(() =>
{
UpdateGroundWallCheck();
return isground && Mathf.Abs(body.linearVelocity.y) < 0.05f;
});
canJump = true;
yield return new WaitForSeconds(0.2f);
justRespawned = false;
isRespawning = false;
Debug.Log($"Respawn complete. isground: {isground}, canJump: {canJump}");
}
IEnumerator GameOverRoutine(){
yield return new WaitForSeconds(0.3f);
gameover.SetActive(true);
gameover_audio.Play();
Debug.Log("Game Over!");
}
checkpoint FindNearestCheckpoint() {
checkpoint nearest = null;
float minDistance = Mathf.Infinity;
Vector3 pos = transform.position;
foreach (checkpoint cp in allCheckpoints) {
float dist = Vector3.Distance(pos, cp.transform.position);
if (dist < minDistance) {
minDistance = dist;
nearest = cp;
}
}
return nearest;
}
// Visualize the raycasts for debugging
void OnDrawGizmos() {
// Ground check
Gizmos.color = Color.red;
Gizmos.DrawRay(transform.position, Vector2.down * rayLength);
// Jump check
Gizmos.color = Color.blue;
Gizmos.DrawRay(transform.position, Vector2.down * 0.6f);
// Wall checks
Gizmos.color = Color.yellow;
Gizmos.DrawRay(transform.position, Vector2.right * 0.3f);
Gizmos.DrawRay(transform.position, Vector2.left * 0.3f);
}
}