Initial commit
This commit is contained in:
385
Assets/Scripts/PacMan.cs
Normal file
385
Assets/Scripts/PacMan.cs
Normal file
@@ -0,0 +1,385 @@
|
||||
namespace Marro.PacManUdon
|
||||
{
|
||||
using System;
|
||||
using UdonSharp;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
using VRC.SDK3.Components;
|
||||
|
||||
public class PacMan : GridMover
|
||||
{
|
||||
private GameController gameController;
|
||||
private PlayerInput input;
|
||||
private float defaultSpeed;
|
||||
private float powerPelletSpeed;
|
||||
private float speed;
|
||||
private Vector3 startPosition;
|
||||
private Quaternion startRotation;
|
||||
private Vector3 startScale;
|
||||
private Animator animator;
|
||||
new Renderer renderer;
|
||||
private VRCObjectPool pelletPool;
|
||||
private bool hideUntilUnfrozen;
|
||||
private bool dead;
|
||||
private bool kinematic;
|
||||
|
||||
private bool followingPredefinedPath;
|
||||
private Vector2[] predefinedPath;
|
||||
private int predefinedPathIndex;
|
||||
|
||||
[UdonSynced] private Vector2 syncedPosition;
|
||||
[UdonSynced] private Vector2 targetDirection;
|
||||
[UdonSynced] private Vector2 direction;
|
||||
[UdonSynced] private float freezeSeconds;
|
||||
[UdonSynced] private bool frozen;
|
||||
|
||||
|
||||
public void Initialize(PlayerInput input, VRCObjectPool pelletPool, GameController gameController)
|
||||
{
|
||||
this.gameController = gameController;
|
||||
this.input = input;
|
||||
this.pelletPool = pelletPool;
|
||||
animator = GetComponent<Animator>();
|
||||
renderer = GetComponent<Renderer>();
|
||||
frozen = false;
|
||||
hideUntilUnfrozen = false;
|
||||
startPosition = transform.localPosition;
|
||||
startRotation = transform.localRotation;
|
||||
startScale = transform.localScale;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
// Debug.Log($"{gameObject} Reset!");
|
||||
transform.localPosition = startPosition;
|
||||
transform.localRotation = startRotation;
|
||||
transform.localScale = startScale;
|
||||
direction = Vector2.left;
|
||||
targetDirection = Vector2.left;
|
||||
speed = defaultSpeed;
|
||||
kinematic = false;
|
||||
followingPredefinedPath = false;
|
||||
|
||||
SetDead(false);
|
||||
animator.SetTrigger("Reset");
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
// gameStateManager.statusDisplay.SetDebugText(1, this.targetDirection.ToString());
|
||||
|
||||
if (frozen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (hideUntilUnfrozen)
|
||||
{
|
||||
hideUntilUnfrozen = false;
|
||||
SetVisibility(true);
|
||||
}
|
||||
|
||||
float speed = this.speed;
|
||||
if (freezeSeconds > 0)
|
||||
{
|
||||
float freezePart = freezeSeconds / Time.deltaTime;
|
||||
if (freezePart >= 1)
|
||||
{
|
||||
freezeSeconds -= Time.deltaTime;
|
||||
animator.speed = 0;
|
||||
return;
|
||||
}
|
||||
speed *= 1 - freezePart;
|
||||
animator.speed = 1 - freezePart;
|
||||
freezeSeconds = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
animator.speed = 1;
|
||||
}
|
||||
|
||||
Vector2 position = GetPosition();
|
||||
Vector2 nextPosition = GridMoverTools.GetNextPosition(position, direction, speed); // The position pacman will move to, assuming it doens't get changed
|
||||
|
||||
if (!kinematic)
|
||||
{
|
||||
if (followingPredefinedPath)
|
||||
{
|
||||
nextPosition = ProcessPredefinedPath(position, nextPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextPosition = ProcessNextPosition(position, nextPosition);
|
||||
}
|
||||
}
|
||||
|
||||
SetPosition(nextPosition);
|
||||
}
|
||||
|
||||
private Vector2 ProcessNextPosition(Vector2 position, Vector2 nextPosition)
|
||||
{
|
||||
if (GridMoverTools.CrossesTileCenter(position, nextPosition, direction.x != 0, false) // If pacman is moving horizontally, check if he may cross the center of a tile in that axis
|
||||
&& (targetDirection.x == 0 || GridMoverTools.CheckCollisionInDirection(transform, nextPosition, new Vector2(direction.x, 0))))
|
||||
{ // If the target direction is in the other axis or if we're about to run into a wall
|
||||
nextPosition.x = GridMoverTools.PositionToGrid(nextPosition).x; // Snap pacman to the center of his current tile in this axis
|
||||
SetDirection(new Vector2(0, direction.y));
|
||||
// Debug.Log($"{gameObject} crossed X tile center from {currentPosition}, nextPosition is now {nextPosition} and direction is now {direction}");
|
||||
}
|
||||
|
||||
if (GridMoverTools.CrossesTileCenter(position, nextPosition, false, direction.y != 0) // See comments above but now vertical
|
||||
&& (targetDirection.y == 0 || GridMoverTools.CheckCollisionInDirection(transform, nextPosition, new Vector2(0, direction.y))))
|
||||
{
|
||||
nextPosition.y = GridMoverTools.PositionToGrid(nextPosition).y;
|
||||
SetDirection(new Vector2(direction.x, 0));
|
||||
// Debug.Log($"{gameObject} crossed Y tile center from {currentPosition} with targetDirection {targetDirection}, nextPosition is now {nextPosition} and direction is now {direction}");
|
||||
}
|
||||
|
||||
if (Networking.IsOwner(gameObject))
|
||||
{
|
||||
Vector2 inputDirection = input.GetDirection();
|
||||
if (!inputDirection.Equals(Vector2.zero) && !inputDirection.Equals(targetDirection) // Ignore neutral input or input in our current direction
|
||||
&& (inputDirection.x == 0 || (Math.Round(nextPosition.y, 5) - 0.5) % 1 != 0) && (inputDirection.y == 0 || (Math.Round(nextPosition.x, 5) - 0.5) % 1 != 0) // Target grid position near the edge of a tile may not be correct, ignore inputs near the border
|
||||
&& !GridMoverTools.CheckCollisionInDirection(transform, nextPosition, inputDirection))
|
||||
{ // Check if the requested direction does not have a wall
|
||||
if (inputDirection.x != 0)
|
||||
{ // Move in the requested direction, as well as perpundicular to it to get to the center of the tunnel
|
||||
SetDirection(inputDirection + new Vector2(0, GridMoverTools.PositionToGrid(nextPosition).y - nextPosition.y).normalized);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDirection(inputDirection + new Vector2(GridMoverTools.PositionToGrid(nextPosition).x - nextPosition.x, 0).normalized);
|
||||
}
|
||||
SetTargetDirection(inputDirection); // This is the direction most logic should assume pacman is moving, the actual direction may be different due to cornering
|
||||
}
|
||||
}
|
||||
|
||||
return nextPosition;
|
||||
}
|
||||
|
||||
private Vector2 ProcessPredefinedPath(Vector2 position, Vector2 nextPosition)
|
||||
{
|
||||
if (GridMoverTools.CrossesTileCenter(position, nextPosition, direction.x != 0, direction.y != 0))
|
||||
{
|
||||
// Find the next valid direction which isn't Vector2.zero
|
||||
int nextValidDirectionIndex = predefinedPathIndex;
|
||||
while (predefinedPath[nextValidDirectionIndex] == Vector2.zero)
|
||||
{
|
||||
nextValidDirectionIndex += 1;
|
||||
}
|
||||
if (!GridMoverTools.CheckCollisionInDirection(transform, nextPosition, predefinedPath[nextValidDirectionIndex]))
|
||||
{
|
||||
// If we're at a Vector2.zero, we skip applying the direction and only increment.
|
||||
if (nextValidDirectionIndex == predefinedPathIndex)
|
||||
{
|
||||
SetDirection(predefinedPath[nextValidDirectionIndex]);
|
||||
SetTargetDirection(predefinedPath[nextValidDirectionIndex]);
|
||||
nextPosition = GridMoverTools.PositionToGrid(nextPosition) + direction.normalized * 0.01f;
|
||||
|
||||
// Check if we've reached the end of the path, which includes making sure the path doesn't end on Vector2.zero
|
||||
do
|
||||
{
|
||||
nextValidDirectionIndex += 1;
|
||||
if (nextValidDirectionIndex >= predefinedPath.Length)
|
||||
{
|
||||
followingPredefinedPath = false;
|
||||
break;
|
||||
}
|
||||
} while (predefinedPath[nextValidDirectionIndex] == Vector2.zero);
|
||||
}
|
||||
|
||||
// gameStateManager.statusDisplay.SetDebugText(1, predefinedPathIndex.ToString());
|
||||
|
||||
predefinedPathIndex++;
|
||||
}
|
||||
}
|
||||
return nextPosition;
|
||||
}
|
||||
|
||||
private void UpdateAnimator()
|
||||
{
|
||||
// Debug.Log($"{gameObject} UpdateAnimator with direction {direction}, dead {dead}, frozen {frozen}");
|
||||
if (!gameObject.activeInHierarchy)
|
||||
return;
|
||||
|
||||
animator.SetBool("Dead", dead);
|
||||
if (dead)
|
||||
{
|
||||
animator.speed = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (frozen || direction.Equals(Vector2.zero))
|
||||
{
|
||||
animator.SetFloat("Direction", 0f);
|
||||
animator.speed = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
animator.speed = 1;
|
||||
if (targetDirection.Equals(Vector2.right))
|
||||
{
|
||||
animator.SetFloat("Direction", 0.25f);
|
||||
}
|
||||
else if (targetDirection.Equals(Vector2.left))
|
||||
{
|
||||
animator.SetFloat("Direction", 0.5f);
|
||||
}
|
||||
else if (targetDirection.Equals(Vector2.up))
|
||||
{
|
||||
animator.SetFloat("Direction", 0.75f);
|
||||
}
|
||||
else if (targetDirection.Equals(Vector2.down))
|
||||
{
|
||||
animator.SetFloat("Direction", 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public Vector2 GetTarget(Vector2 gridPosition, Vector2 currentDirection) {
|
||||
// Vector2 nextDirection = input.GetRotatedDirection();
|
||||
// if(!nextDirection.Equals(currentDirection) && !GridMoverTools.CheckCollisionInDirection(transform, gridPosition, nextDirection)) {
|
||||
// return nextDirection;
|
||||
// }
|
||||
// return Vector2.zero;
|
||||
// }
|
||||
|
||||
public void SetDead(bool dead)
|
||||
{
|
||||
this.dead = dead;
|
||||
UpdateAnimator();
|
||||
}
|
||||
|
||||
public void SetFrozen(bool frozen)
|
||||
{
|
||||
this.frozen = frozen;
|
||||
UpdateAnimator();
|
||||
}
|
||||
|
||||
public void HideUntilUnfrozen()
|
||||
{
|
||||
hideUntilUnfrozen = true;
|
||||
SetVisibility(false);
|
||||
}
|
||||
|
||||
public void SetLevel(int level)
|
||||
{
|
||||
// Debug.Log($"{gameObject} SetLevel {level}");
|
||||
defaultSpeed = PacManConstants.GetPacManDefaultSpeedForLevel(level);
|
||||
powerPelletSpeed = PacManConstants.GetPacManPowerPelletSpeedForLevel(level);
|
||||
}
|
||||
|
||||
public void SetPowerPellet(bool powerPellet)
|
||||
{
|
||||
if (powerPellet)
|
||||
{
|
||||
speed = powerPelletSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = defaultSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetActive(bool active)
|
||||
{
|
||||
gameObject.SetActive(active);
|
||||
renderer.enabled = active;
|
||||
if (active)
|
||||
{
|
||||
UpdateAnimator();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetKinematic(bool kinematic)
|
||||
{
|
||||
this.kinematic = kinematic;
|
||||
}
|
||||
|
||||
public void SetPredefinedPath(Vector2[] predefinedPath)
|
||||
{
|
||||
this.predefinedPath = predefinedPath;
|
||||
followingPredefinedPath = true;
|
||||
predefinedPathIndex = 0;
|
||||
}
|
||||
|
||||
void SetVisibility(bool visible)
|
||||
{
|
||||
renderer.enabled = visible;
|
||||
}
|
||||
|
||||
public override Vector2 GetPosition()
|
||||
{
|
||||
return (Vector2)transform.localPosition;
|
||||
}
|
||||
|
||||
public override void SetPosition(Vector2 position)
|
||||
{
|
||||
GridMoverTools.SetPosition(position, transform);
|
||||
}
|
||||
|
||||
public override Vector2 GetDirection()
|
||||
{
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void SetDirection(Vector2 direction)
|
||||
{
|
||||
this.direction = direction;
|
||||
RequestSerialization();
|
||||
UpdateAnimator();
|
||||
}
|
||||
|
||||
public void SetTargetDirection(Vector2 targetDirection)
|
||||
{
|
||||
this.targetDirection = targetDirection;
|
||||
UpdateAnimator();
|
||||
}
|
||||
|
||||
public override void OnPreSerialization()
|
||||
{
|
||||
syncedPosition = GetPosition();
|
||||
}
|
||||
|
||||
public override void OnDeserialization()
|
||||
{
|
||||
SetPosition(syncedPosition);
|
||||
UpdateAnimator();
|
||||
}
|
||||
|
||||
void OnTriggerEnter(Collider other)
|
||||
{
|
||||
Pellet pellet = other.gameObject.GetComponent<Pellet>();
|
||||
if (pellet)
|
||||
{
|
||||
if (Networking.IsOwner(gameObject))
|
||||
{
|
||||
pelletPool.Return(pellet.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
pellet.pelletRenderer.enabled = false;
|
||||
pellet.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (pellet.isPowerPellet)
|
||||
{
|
||||
if (Networking.IsOwner(gameObject)) gameController.GotPowerPellet();
|
||||
freezeSeconds = 0.05f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Networking.IsOwner(gameObject)) gameController.GotPellet();
|
||||
freezeSeconds = 0.0166666666666667f;
|
||||
}
|
||||
|
||||
if (Networking.IsOwner(gameObject)) RequestSerialization();
|
||||
return;
|
||||
}
|
||||
else if (Networking.IsOwner(gameObject) && other.gameObject.GetComponent<BonusFruit>())
|
||||
{
|
||||
gameController.GotFruit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user