2025-03-18 22:32:00 +08:00
|
|
|
|
using System;
|
2025-03-17 21:56:02 +08:00
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
2025-03-19 22:03:28 +08:00
|
|
|
|
using Unity.VisualScripting;
|
2025-03-17 21:56:02 +08:00
|
|
|
|
using UnityEngine;
|
2025-03-20 22:28:26 +08:00
|
|
|
|
using UnityEngine.SocialPlatforms.Impl;
|
2025-03-19 22:03:28 +08:00
|
|
|
|
using UnityEngine.UIElements;
|
2025-03-17 21:56:02 +08:00
|
|
|
|
|
|
|
|
|
public class RedGhost : MonoBehaviour
|
|
|
|
|
{
|
2025-03-18 22:32:00 +08:00
|
|
|
|
// ========== ״̬ö<CCAC><C3B6> ==========
|
|
|
|
|
public enum GhostState
|
2025-03-17 21:56:02 +08:00
|
|
|
|
{
|
2025-03-18 22:32:00 +08:00
|
|
|
|
Idle, //<2F><><EFBFBD>ֵĴ<D6B5><C4B4><EFBFBD>
|
|
|
|
|
Start, //<2F>뿪<EFBFBD><EBBFAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
Chase, // <><D7B7>ģʽ
|
|
|
|
|
Frightened, // <20>־<EFBFBD>ģʽ,<2C><><EFBFBD><EFBFBD>
|
|
|
|
|
Die // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
2025-03-17 21:56:02 +08:00
|
|
|
|
}
|
2025-03-18 22:32:00 +08:00
|
|
|
|
public GhostState curstate;//<2F><>ǰö<C7B0><C3B6>
|
2025-03-17 21:56:02 +08:00
|
|
|
|
|
2025-03-18 22:32:00 +08:00
|
|
|
|
[Header("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")]
|
|
|
|
|
public Rigidbody2D rb;
|
|
|
|
|
public Animator anim;
|
|
|
|
|
public GameObject pacMan;//<2F>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
2025-03-20 22:28:26 +08:00
|
|
|
|
private PacMan pacManComponent; //<2F>Զ<EFBFBD><D4B6>˽ű<CBBD>
|
2025-03-18 22:32:00 +08:00
|
|
|
|
public LayerMask obstadeLayer;//ǽ<>IJ㼶
|
2025-03-20 22:28:26 +08:00
|
|
|
|
public Transform GhostRevivePoint;//<2F><><EFBFBD><EFBFBD><EFBFBD>㣬ÿ<E3A3AC><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>
|
|
|
|
|
public Transform GhostStartPoint;//<2F>Ӹ<EFBFBD><D3B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD><EFBFBD>ʼ<CABC><D7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
|
|
|
|
|
public float stateTimer; //<2F><>ʱ<EFBFBD><CAB1>
|
|
|
|
|
public bool isFrightened = false;//<2F>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>֤update<74><65>ִֻ<D6BB><D6B4>һ<EFBFBD><D2BB>
|
|
|
|
|
public float idleDuration;//һ<><D2BB>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
|
|
|
|
public float DieDuration;//<2F><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
|
|
|
|
public float Score = 1000;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD>
|
|
|
|
|
|
2025-03-18 22:32:00 +08:00
|
|
|
|
|
|
|
|
|
[Header("<><D7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><DFBC><EFBFBD><EFBFBD><EFBFBD>")]
|
2025-03-19 22:03:28 +08:00
|
|
|
|
private Vector2 currentDirection; //<2F><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>
|
2025-03-20 22:28:26 +08:00
|
|
|
|
public float speed;//<2F><><EFBFBD><EFBFBD><EFBFBD>ٶ<EFBFBD>
|
|
|
|
|
public float frightenedSpeed;//<2F><><EFBFBD><EFBFBD><EFBFBD>ٶ<EFBFBD>
|
2025-03-19 22:03:28 +08:00
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߲<EFBFBD><DFB2><EFBFBD>
|
|
|
|
|
[Header("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")]
|
|
|
|
|
public float castDistance = 1f; // <20><><EFBFBD><EFBFBD><DFBC>ⳤ<EFBFBD><E2B3A4>
|
|
|
|
|
public float boxWidth = 0.3f; // <20><><EFBFBD>߿<EFBFBD><DFBF><EFBFBD>
|
|
|
|
|
public Color validColor = Color.green; // <20><>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ
|
|
|
|
|
public Color blockedColor = Color.red; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ
|
2025-03-18 22:32:00 +08:00
|
|
|
|
|
2025-03-20 22:28:26 +08:00
|
|
|
|
|
2025-03-18 22:32:00 +08:00
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
{
|
|
|
|
|
rb = GetComponent<Rigidbody2D>();
|
|
|
|
|
// anim = GetComponent<Animator>();
|
|
|
|
|
pacMan = GameObject.Find("PacManPlayer");//<2F>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD>
|
2025-03-20 22:28:26 +08:00
|
|
|
|
pacManComponent = pacMan.GetComponent<PacMan>();
|
2025-03-18 22:32:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
|
{
|
|
|
|
|
switch (curstate)
|
|
|
|
|
{
|
|
|
|
|
case GhostState.Idle:
|
|
|
|
|
Idle();
|
2025-03-20 22:28:26 +08:00
|
|
|
|
break;
|
|
|
|
|
case GhostState.Die:
|
|
|
|
|
Die();
|
2025-03-18 22:32:00 +08:00
|
|
|
|
break;
|
2025-03-20 22:28:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pacManComponent.invincible && curstate == GhostState.Chase && !isFrightened)//δ<>ڿ־<DABF>״̬<D7B4>Ž<EFBFBD><C5BD><EFBFBD>
|
|
|
|
|
{
|
|
|
|
|
Debug.Log("<22><><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD>״̬");
|
|
|
|
|
isFrightened = true;
|
|
|
|
|
curstate = GhostState.Frightened;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FixedUpdate()
|
|
|
|
|
{
|
|
|
|
|
switch (curstate)
|
|
|
|
|
{
|
2025-03-18 22:32:00 +08:00
|
|
|
|
case GhostState.Start:
|
|
|
|
|
GhostStart();
|
|
|
|
|
break;
|
|
|
|
|
case GhostState.Chase:
|
|
|
|
|
Chase();
|
|
|
|
|
break;
|
|
|
|
|
case GhostState.Frightened:
|
|
|
|
|
Frightened();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-20 22:28:26 +08:00
|
|
|
|
private void OnTriggerEnter2D(Collider2D collision)
|
|
|
|
|
{
|
|
|
|
|
if (collision.gameObject == pacMan)
|
|
|
|
|
{
|
|
|
|
|
if (curstate == GhostState.Frightened)
|
|
|
|
|
{
|
|
|
|
|
transform.position = GhostRevivePoint.position;//<2F><><EFBFBD>͵<EFBFBD><CDB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
isFrightened = false;//<2F>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD>false
|
|
|
|
|
rb.velocity = Vector2.zero;//λ<>ò<EFBFBD><C3B2><EFBFBD>
|
|
|
|
|
stateTimer = 0;//<2F><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>
|
|
|
|
|
GameManager.instance.AddScore(Score);//<2F>ӷ<EFBFBD>
|
|
|
|
|
|
|
|
|
|
curstate = GhostState.Die;
|
|
|
|
|
}
|
|
|
|
|
else if (curstate == GhostState.Chase)
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
pacManComponent.die = true;
|
|
|
|
|
// Time.timeScale = 0;//<2F><>Ϸ<EFBFBD><CFB7>ͣ
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-19 22:03:28 +08:00
|
|
|
|
|
2025-03-18 22:32:00 +08:00
|
|
|
|
private void Idle()
|
|
|
|
|
{
|
2025-03-20 22:28:26 +08:00
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
|
|
|
|
|
stateTimer += Time.deltaTime;
|
|
|
|
|
if (stateTimer >= idleDuration)
|
|
|
|
|
{
|
|
|
|
|
stateTimer = 0;
|
|
|
|
|
curstate = GhostState.Start;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// anim.SetBool("Moving", false);
|
2025-03-18 22:32:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void GhostStart()
|
|
|
|
|
{
|
2025-03-20 22:28:26 +08:00
|
|
|
|
// <20><><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD>ƶ<EFBFBD>
|
|
|
|
|
Vector2 direction = ((Vector2)GhostStartPoint.position - rb.position).normalized;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ
|
|
|
|
|
rb.velocity = direction * speed *Time.deltaTime;
|
|
|
|
|
if (Vector2.Distance(transform.position, GhostStartPoint.position) < 0.1f)//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1>һ<EFBFBD><D2BB>ֵ
|
|
|
|
|
{
|
|
|
|
|
transform.position = GhostStartPoint.position;
|
|
|
|
|
curstate = GhostState.Chase;
|
|
|
|
|
}
|
2025-03-18 22:32:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void Chase()
|
2025-03-17 21:56:02 +08:00
|
|
|
|
{
|
2025-03-18 22:32:00 +08:00
|
|
|
|
UpdateMovement(pacMan.transform.position, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Frightened()
|
|
|
|
|
{
|
2025-03-20 22:28:26 +08:00
|
|
|
|
|
|
|
|
|
// ֱ<>Ӷ<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>ǵ<EFBFBD>ʣ<EFBFBD><CAA3><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
|
|
|
|
float remainingTime = pacManComponent.remainingInvincibleTime;
|
|
|
|
|
if (remainingTime <=0)//ʱ<><CAB1><EFBFBD>ۼӴ<DBBC><D3B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD>ʱ<EFBFBD>䣬<EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><D7B7>
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
isFrightened = false;//<2F>ѿ־<D1BF><D6BE><EFBFBD><EFBFBD>л<EFBFBD>Ϊδ<CEAA>־<EFBFBD>
|
|
|
|
|
curstate = GhostState.Chase;
|
|
|
|
|
|
|
|
|
|
// anim.SetBool("Frightened", false);
|
|
|
|
|
// return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpdateMovement(pacMan.transform.position, false);
|
|
|
|
|
//anim.SetBool("Frightened", true);
|
2025-03-18 22:32:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Die()
|
|
|
|
|
{
|
2025-03-20 22:28:26 +08:00
|
|
|
|
|
|
|
|
|
stateTimer += Time.deltaTime;
|
|
|
|
|
if(stateTimer >= DieDuration)
|
|
|
|
|
{
|
|
|
|
|
stateTimer = 0;
|
|
|
|
|
curstate = GhostState.Idle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
2025-03-18 22:32:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-03-19 22:03:28 +08:00
|
|
|
|
|
2025-03-18 22:32:00 +08:00
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD><DFBC><EFBFBD><EFBFBD><D7B7>/<2F><><EFBFBD>ܹ<EFBFBD><DCB9>ã<EFBFBD>
|
|
|
|
|
private void UpdateMovement(Vector2 targetPos, bool isChasing)
|
|
|
|
|
{
|
|
|
|
|
Vector2[] directions = { Vector2.up, Vector2.down, Vector2.left, Vector2.right };
|
|
|
|
|
Vector2 bestDir = Vector2.zero;
|
|
|
|
|
float bestValue = isChasing ? Mathf.Infinity : -Mathf.Infinity;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F3A3ACB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
foreach (Vector2 dir in directions)
|
|
|
|
|
{
|
2025-03-20 22:28:26 +08:00
|
|
|
|
if (dir == -currentDirection) continue; // ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>ǰ<EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ѭ<EFBFBD><D1AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱֹ<D6B9>ӻ<EFBFBD>ͷ
|
2025-03-18 22:32:00 +08:00
|
|
|
|
|
2025-03-19 22:03:28 +08:00
|
|
|
|
// ʹ<><CAB9>BoxCast<73><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
bool isBlocked = Physics2D.BoxCast(transform.position,GetBoxSize(dir),0f,dir,castDistance,obstadeLayer);
|
|
|
|
|
|
|
|
|
|
if (isBlocked) continue;
|
2025-03-18 22:32:00 +08:00
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>㷽<EFBFBD><E3B7BD><EFBFBD><EFBFBD>ֵ
|
|
|
|
|
float distance = Vector2.Distance(rb.position + dir, targetPos);//<2F><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD>ӷ<EFBFBD><D3B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD>ֵ
|
2025-03-20 22:28:26 +08:00
|
|
|
|
float currentValue = distance;//<2F><><EFBFBD><D7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
2025-03-18 22:32:00 +08:00
|
|
|
|
|
|
|
|
|
if ((isChasing && currentValue < bestValue) || (!isChasing && currentValue > bestValue))
|
|
|
|
|
{
|
|
|
|
|
bestValue = currentValue;
|
|
|
|
|
bestDir = dir;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bestDir != Vector2.zero)
|
|
|
|
|
{
|
|
|
|
|
currentDirection = bestDir;
|
2025-03-19 22:03:28 +08:00
|
|
|
|
rb.velocity = currentDirection.normalized * (curstate == GhostState.Frightened ? frightenedSpeed : speed) * Time.deltaTime;
|
2025-03-18 22:32:00 +08:00
|
|
|
|
}
|
2025-03-17 21:56:02 +08:00
|
|
|
|
}
|
2025-03-19 22:03:28 +08:00
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD><EFBFBD>ߺ<EFBFBD><DFBA>ӳߴ<D3B3>
|
|
|
|
|
private Vector2 GetBoxSize(Vector2 direction)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2(
|
2025-03-20 22:28:26 +08:00
|
|
|
|
direction.x = boxWidth,//<2F><><EFBFBD>߳<EFBFBD><DFB3><EFBFBD>
|
2025-03-19 22:03:28 +08:00
|
|
|
|
direction.y = boxWidth
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-20 22:28:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-03-19 22:03:28 +08:00
|
|
|
|
// <20><><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
private void OnDrawGizmos()
|
|
|
|
|
{
|
|
|
|
|
if (!Application.isPlaying) return;
|
|
|
|
|
|
|
|
|
|
foreach (Vector2 dir in new[] { Vector2.up, Vector2.down, Vector2.left, Vector2.right })
|
|
|
|
|
{
|
|
|
|
|
Gizmos.color = Physics2D.BoxCast(transform.position, GetBoxSize(dir), 0f, dir, castDistance, obstadeLayer)
|
|
|
|
|
? blockedColor
|
|
|
|
|
: validColor;
|
|
|
|
|
|
|
|
|
|
DrawBoxCastGizmo(
|
|
|
|
|
transform.position,
|
|
|
|
|
dir,
|
|
|
|
|
GetBoxSize(dir),
|
|
|
|
|
castDistance
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ƺ<EFBFBD><C6BA><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
private void DrawBoxCastGizmo(Vector2 origin, Vector2 direction, Vector2 size, float distance)
|
|
|
|
|
{
|
|
|
|
|
Vector2 endPos = origin + direction * distance;
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD><D5B5>ĺ<EFBFBD><C4BA><EFBFBD>
|
|
|
|
|
Gizmos.DrawWireCube(origin, size);
|
|
|
|
|
Gizmos.DrawWireCube(endPos, size);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
Vector2 perpendicular = new Vector2(-direction.y, direction.x) * size.x / 2;
|
|
|
|
|
Vector2 edge1 = origin + perpendicular;
|
|
|
|
|
Vector2 edge2 = origin - perpendicular;
|
|
|
|
|
Gizmos.DrawLine(edge1, edge1 + direction * distance);
|
|
|
|
|
Gizmos.DrawLine(edge2, edge2 + direction * distance);
|
|
|
|
|
}
|
2025-03-17 21:56:02 +08:00
|
|
|
|
}
|
2025-03-19 22:03:28 +08:00
|
|
|
|
|