236 lines
7.4 KiB
C#
236 lines
7.4 KiB
C#
using BrewMonster.Network;
|
|
using CSNetwork;
|
|
using CSNetwork.GPDataType;
|
|
using CSNetwork.C2SCommand;
|
|
using CSNetwork.Protocols;
|
|
using CSNetwork.Protocols.RPCData;
|
|
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using TMPro;
|
|
using UnityEditor.SearchService;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.UI;
|
|
using Scene = UnityEngine.SceneManagement.Scene;
|
|
|
|
public class CECHostPlayer : MonoBehaviour
|
|
{
|
|
[SerializeField] private TextMeshPro txtName;
|
|
[SerializeField] private CharacterController controller;
|
|
|
|
[SerializeField] private Joystick joystick;
|
|
[SerializeField] private Button btnJump;
|
|
[SerializeField] private Button btnRun;
|
|
[SerializeField] private Transform parentModel;
|
|
|
|
PlayerStateMachine playerStateMachine;
|
|
PlayerMoveState moveState;
|
|
CECHostMove m_MoveCtrl;
|
|
|
|
float playerSpeed = 5.0f;
|
|
float jumpHeight = 1.5f;
|
|
float gravityValue = -9.81f;
|
|
StateAnim stateAnim = StateAnim.Idle;
|
|
Vector3 playerVelocity;
|
|
bool isGrounded = false;
|
|
bool isRun = false;
|
|
GameObject modle;
|
|
Vector3 m_vLastSevPos;
|
|
|
|
// ====== Ground cast config ======
|
|
[Header("Ground Cast")]
|
|
[Tooltip("Khoảng thêm ngoài skinWidth để SphereCast xuống (m ngắn)")]
|
|
[SerializeField] private float extraGroundDistance = 0.05f;
|
|
[Tooltip("Bớt bán kính một chút để tránh tự va vào capsule (epsilon)")]
|
|
[SerializeField] private float radiusEpsilon = 0.005f;
|
|
[Tooltip("Layer mặt đất")]
|
|
[SerializeField] private LayerMask groundMask;
|
|
[Tooltip("Layer mặt đất")]
|
|
[SerializeField] private float slopeToleranceDeg = 2f;
|
|
|
|
// cache tùy chọn (không bắt buộc)
|
|
float ccRadius, ccSkin;
|
|
RaycastHit lastGroundHit;
|
|
|
|
private void Awake()
|
|
{
|
|
moveState = new PlayerMoveState(this);
|
|
playerStateMachine = new PlayerStateMachine();
|
|
m_MoveCtrl = new CECHostMove(this);
|
|
|
|
// Cache: không bắt buộc, nhưng gọn tay và ít gọi property lặp.
|
|
if (controller != null)
|
|
{
|
|
ccRadius = controller.radius;
|
|
ccSkin = controller.skinWidth;
|
|
}
|
|
}
|
|
|
|
public void SetModelHostPlayer()
|
|
{
|
|
modle = NPCManager.Instance.GetModelPlayer();
|
|
Scene scene = SceneManager.GetSceneByName("WorldRender");
|
|
SceneManager.MoveGameObjectToScene(modle, scene);
|
|
modle.transform.SetParent(parentModel);
|
|
modle.transform.localPosition = Vector3.zero;
|
|
modle.SetActive(true);
|
|
}
|
|
private void Start()
|
|
{
|
|
playerStateMachine.InitState(moveState);
|
|
// btnJump.onClick.AddListener(HandleJump);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
m_MoveCtrl.Tick((ulong)Time.deltaTime);
|
|
// Nếu có thay đổi runtime, có thể lấy lại mỗi vài giây/Start nếu bạn thích:
|
|
// ccRadius = controller.radius; ccSkin = controller.skinWidth;
|
|
|
|
playerStateMachine.UpdateState();
|
|
}
|
|
|
|
public void HandleMovement()
|
|
{
|
|
// 1) Kiểm tra grounded bằng SphereCast ngắn dựa trên radius + skinWidth
|
|
isGrounded = GroundCheck(out lastGroundHit);
|
|
|
|
// 2) Input tạm thời: giữ nguyên như bạn
|
|
if (UnityEngine.Input.GetKeyDown(KeyCode.LeftShift)) SetStatusRun(true);
|
|
if (UnityEngine.Input.GetKeyUp(KeyCode.LeftShift)) SetStatusRun(false);
|
|
if (UnityEngine.Input.GetKeyDown(KeyCode.Space)) HandleJump();
|
|
|
|
// 3) Trọng lực / sticky
|
|
if (isGrounded && playerVelocity.y < 0f)
|
|
{
|
|
// Đè nhẹ để bám đất (tránh nhấp-nháy)
|
|
playerVelocity.y = -2f;
|
|
}
|
|
else
|
|
{
|
|
playerVelocity.y += gravityValue * Time.deltaTime;
|
|
}
|
|
|
|
// 4) Chuyển động phẳng
|
|
float x = joystick.Horizontal;
|
|
float z = joystick.Vertical;
|
|
|
|
Vector3 move = new Vector3(x, 0, z);
|
|
move = Vector3.ClampMagnitude(move, 1f);
|
|
|
|
if (move != Vector3.zero)
|
|
{
|
|
transform.forward = move;
|
|
Debug.LogWarning("HoangDev :HandleMovement");
|
|
|
|
m_MoveCtrl.SendMoveCmd(transform.position, controller.velocity, (int)MoveMode.GP_MOVE_WALK);
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
Vector3 finalMove = (move * playerSpeed) + (playerVelocity.y * Vector3.up);
|
|
controller.Move(finalMove * Time.deltaTime);
|
|
}
|
|
|
|
private bool GroundCheck(out RaycastHit hit)
|
|
{
|
|
float radius = controller.radius;
|
|
float skin = controller.skinWidth;
|
|
float height = controller.height;
|
|
|
|
// Tâm capsule theo world
|
|
Vector3 cWorld = transform.TransformPoint(controller.center);
|
|
float hemi = Mathf.Max(0f, (height * 0.5f) - radius);
|
|
|
|
// Hai điểm top/bottom của capsule nhân vật (đang đứng)
|
|
Vector3 pTop = cWorld + Vector3.up * hemi;
|
|
Vector3 pBottom = cWorld - Vector3.up * hemi;
|
|
|
|
// Ta tạo một "đoạn capsule ngắn" gần đáy để sweep xuống
|
|
// Nhấc đoạn bắt đầu lên 1 chút để không bắt đầu trong trạng thái giao nhau
|
|
Vector3 startBottom = pBottom + Vector3.up * (skin + 0.01f);
|
|
Vector3 startTop = startBottom + Vector3.up * (radius * 2f - 0.02f); // chiều cao đoạn ngắn ~2*radius
|
|
|
|
float castRadius = Mathf.Max(0f, radius - radiusEpsilon);
|
|
float castDistance = skin + extraGroundDistance; // quãng sweep ngắn
|
|
|
|
bool hitSomething = Physics.CapsuleCast(
|
|
startTop, startBottom, castRadius,
|
|
Vector3.down, out hit, castDistance,
|
|
groundMask, QueryTriggerInteraction.Ignore
|
|
);
|
|
|
|
if (!hitSomething) return false;
|
|
|
|
// Lọc theo slope limit
|
|
float maxSlope = controller.slopeLimit + slopeToleranceDeg;
|
|
float slope = Vector3.Angle(hit.normal, Vector3.up);
|
|
if (slope > maxSlope) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
private void HandleJump()
|
|
{
|
|
if (isGrounded)
|
|
{
|
|
playerVelocity.y = Mathf.Sqrt(jumpHeight * -2f * gravityValue);
|
|
}
|
|
}
|
|
public void ProcessMessage(in ECMSG Msg)
|
|
{
|
|
switch ((int)Msg.dwMsg)
|
|
{
|
|
case int value when value == EC_MsgDef.MSG_HST_CORRECTPOS: OnMsgHstCorrectPos(Msg); break;
|
|
}
|
|
}
|
|
|
|
|
|
public void OnMsgHstCorrectPos(in ECMSG Msg)
|
|
{
|
|
Debug.Log("OnMsgHstCorrectPos");
|
|
cmd_host_correct_pos pCmd = (cmd_host_correct_pos)Msg.dwParam1;
|
|
Debug.LogWarning("pCmd.pos " + pCmd.pos);
|
|
SetPos(pCmd.pos);
|
|
}
|
|
private void SetPos(Vector3 pos)
|
|
{
|
|
transform.position = pos;
|
|
}
|
|
public void SetStatusRun(bool value)
|
|
{
|
|
if (!isGrounded)
|
|
{
|
|
Debug.LogError("Player not in ground");
|
|
return;
|
|
}
|
|
isRun = value;
|
|
}
|
|
public void InitCharacter(cmd_self_info_1 role)
|
|
{
|
|
string roleName = "(Error decoding name)";
|
|
//if (role.name != null && role.name.ByteArray != null)
|
|
//{
|
|
// roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length);
|
|
//}
|
|
Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z);
|
|
if (txtName != null) txtName.text = roleName;
|
|
transform.position = pos;
|
|
SetModelHostPlayer();
|
|
Debug.LogError("Pos Character = " + pos);
|
|
joystick = FindAnyObjectByType<Joystick>();
|
|
}
|
|
}
|
|
|
|
public enum StateAnim
|
|
{
|
|
Idle = 1,
|
|
Walk = 2,
|
|
Run = 3,
|
|
Jump = 4
|
|
}
|