Игрок всегда находится над платформой в воздухе. Как сделать так, чтобы игрок идеально находился на вершине платформы?C#

Место общения программистов C#
Ответить
Anonymous
 Игрок всегда находится над платформой в воздухе. Как сделать так, чтобы игрок идеально находился на вершине платформы?

Сообщение Anonymous »


Изображение

И у игрока, и у деревянной колоды есть коллайдеры.
Изображение

У игрока есть компонент контроллера персонажа для коллайдера.
Изображение

Деревянная колода оснащена коллайдером.
Изображение

Этот скрипт прикреплен к плееру:
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(Animator))]
public class ModernCharacterController : MonoBehaviour
{
[Header("Movement Settings")]
public float walkSpeed = 4f;
public float runSpeed = 8f;

[Header("Vertical (Screen Up/Down) Movement")]
public float verticalMoveSpeed = 3f;

[Header("Jump Settings")]
public float jumpHeight = 2f;
public float gravity = -9.81f;

[Header("Animation Smoothing")]
[Tooltip("How fast the Speed parameter ramps up (higher = snappier)")]
public float speedSmoothRate = 10f;

[Header("2.5D Settings")]
public bool lockZAxis = true;

private CharacterController controller;
private Animator animator;
private float lockedZPosition;
private Vector3 velocity;
private bool isGrounded;
private float currentAnimSpeed; // smoothed value sent to animator

void Start()
{
controller = GetComponent();
animator = GetComponent();
lockedZPosition = transform.position.z;

// Face right (positive X) for side-scroller
transform.rotation = Quaternion.Euler(0, 90, 0);

// Auto-place player on ground
SnapToGround();
}

void SnapToGround()
{
// Temporarily disable the CharacterController so we can set position directly
controller.enabled = false;

RaycastHit hit;
Vector3 rayOrigin = transform.position + Vector3.up * 10f;

if (Physics.Raycast(rayOrigin, Vector3.down, out hit, 50f))
{
transform.position = new Vector3(transform.position.x, hit.point.y, transform.position.z);
Debug.Log($"Snapped to ground at Y: {hit.point.y} (hit: {hit.collider.name})");
}

controller.enabled = true;
}

void Update()
{
HandleMovement();
HandleAnimator();
}

void HandleMovement()
{
// Ground check
isGrounded = controller.isGrounded;

if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}

// Raw input for instant response
float moveXRaw = Input.GetAxisRaw("Horizontal");
float moveYRaw = Input.GetAxisRaw("Vertical");

// Determine if running
bool isRunning = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
float currentMoveSpeed = isRunning ? runSpeed : walkSpeed;

// Build movement vector
Vector3 move = new Vector3(moveXRaw * currentMoveSpeed, 0f, 0f);

// Optional vertical screen movement (W/S)
Vector3 verticalMove = new Vector3(0f, moveYRaw * verticalMoveSpeed, 0f);

// Face horizontal direction
if (moveXRaw > 0.1f)
transform.rotation = Quaternion.Euler(0, 90, 0);
else if (moveXRaw < -0.1f)
transform.rotation = Quaternion.Euler(0, -90, 0);

// Apply horizontal + vertical movement
controller.Move((move + verticalMove) * Time.deltaTime);

// Jump
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
animator.SetTrigger("Jump");
}

// Apply gravity
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);

// Lock Z axis
if (lockZAxis)
{
float zDrift = transform.position.z - lockedZPosition;

if (Mathf.Abs(zDrift) > 0.001f)
{
controller.Move(new Vector3(0f, 0f, -zDrift));
}
}
}

void HandleAnimator()
{
float moveXRaw = Mathf.Abs(Input.GetAxisRaw("Horizontal"));
bool isRunning = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);

// Target speed for blend tree: 0 = idle, 0.5 = walk, 1 = run
float targetAnimSpeed = 0f;

if (moveXRaw > 0.1f)
{
targetAnimSpeed = isRunning ? 1f : 0.5f;
}

// Smooth it so animation transitions look natural
currentAnimSpeed = Mathf.MoveTowards(currentAnimSpeed, targetAnimSpeed, speedSmoothRate * Time.deltaTime);

animator.SetFloat("Speed", currentAnimSpeed);
animator.SetBool("IsGrounded", isGrounded);
}
}

И этот скрипт прикреплен к пустому игровому объекту DockManager:
using System.Collections.Generic;
using UnityEngine;

public class DockManager : MonoBehaviour
{
public GameObject dockPrefab;
public int sideViewSegments = 6;
public int thirdPersonSegments = 24;
public Transform player;

[Header("Segment Settings")]
[Tooltip("Leave 0 to auto-calculate from prefab")]
public float segmentLengthOverride = 0f;

[Header("Auto-calculated")]
[SerializeField] private float segmentLength;

private List segments = new List();
private float lastSpawnX;
private int currentSegmentCount;

void Start()
{
if (segmentLengthOverride > 0f)
{
segmentLength = segmentLengthOverride;
}
else
{
Renderer rend = dockPrefab.GetComponentInChildren();

if (rend != null)
{
GameObject temp = Instantiate(dockPrefab, Vector3.zero, dockPrefab.transform.rotation);
Renderer[] allRenderers = temp.GetComponentsInChildren();
Bounds combinedBounds = allRenderers[0].bounds;

for (int i = 1; i < allRenderers.Length; i++)
{
combinedBounds.Encapsulate(allRenderers.bounds);
}

segmentLength = combinedBounds.size.x;
Debug.Log($"Calculated segment length: {segmentLength}");
Destroy(temp);
}
}

currentSegmentCount = sideViewSegments;
lastSpawnX = 0f;

for (int i = 0; i < currentSegmentCount; i++)
{
SpawnSegment(false);
}
}

void Update()
{
if (segments.Count == 0)
return;

if (player.position.x > segments[0].transform.position.x + segmentLength)
{
RecycleSegment();
}
}

// Call this from SimpleCameraFollow when switching views
public void SetViewMode(bool isThirdPerson)
{
int targetCount = isThirdPerson ? thirdPersonSegments : sideViewSegments;

if (targetCount > currentSegmentCount)
{
// Add more segments ahead
int toAdd = targetCount - currentSegmentCount;

for (int i = 0; i < toAdd; i++)
{
SpawnSegment(true);
}
}
else if (targetCount < currentSegmentCount)
{
// Remove excess segments from the back (farthest ahead)
int toRemove = currentSegmentCount - targetCount;

for (int i = 0; i < toRemove; i++)
{
if (segments.Count > targetCount)
{
GameObject last = segments[segments.Count - 1];
segments.RemoveAt(segments.Count - 1);
Destroy(last);
lastSpawnX -= segmentLength;
}
}
}

currentSegmentCount = targetCount;
}

void SpawnSegment(bool assignColor)
{
GameObject segment = Instantiate(
dockPrefab,
new Vector3(lastSpawnX, 0, 0),
dockPrefab.transform.rotation
);
segments.Add(segment);
if (assignColor)
SetRandomColor(segment);
lastSpawnX += segmentLength;
}

void RecycleSegment()
{
GameObject first = segments[0];
segments.RemoveAt(0);
first.transform.position = new Vector3(lastSpawnX, 0, 0);
SetRandomColor(first);
segments.Add(first);
lastSpawnX += segmentLength;
}

void SetRandomColor(GameObject segment)
{
Renderer renderer = segment.GetComponent();

if (renderer == null)
return;

MaterialPropertyBlock block = new MaterialPropertyBlock();
renderer.GetPropertyBlock(block);
Color randomColor = Random.ColorHSV(0f, 1f, 0.6f, 1f, 0.6f, 1f);
block.SetColor("_BaseColor", randomColor);
block.SetColor("_Color", randomColor);
renderer.SetPropertyBlock(block);
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... ayer-to-be
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»