Unity 3D RPG游戏的设计与实现
创作时间:
作者:
@小白创作中心
Unity 3D RPG游戏的设计与实现
引用
CSDN
1.
https://blog.csdn.net/brown_dd/article/details/136188863
本文将详细介绍Unity 3D RPG游戏中玩家与敌人交互、状态机设计、攻击动画实现以及攻击时滑动功能的代码实现。通过本文,你将了解如何在Unity中实现基本的玩家控制、状态切换、动画触发以及特效播放等核心功能。
实现鼠标点击的交互
public class PlayerInput : MonoBehaviour
{
public float horizontalInput;
public float verticalInput;
public bool mouseDown;
void Update()
{
if (!mouseDown && Time.timeScale != 0) // 游戏运行中,Time.timeScale等于0时,游戏时间会停止更新,此时不应该响应玩家输入
{
mouseDown = Input.GetMouseButtonDown(0);
}
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
}
private void OnDisable()
{
mouseDown = false; // 清除鼠标输入
horizontalInput = 0;
verticalInput = 0;
}
}
状态机的初步设计
private void StateSwitchTo(CharacterState newState)
{
if (isPlayer)
{
playerInput.mouseDown = false; // 清除鼠标输入,因为Enemy是由ai控制的,所以不需要mouseDown
}
// 对于当前状态的处理
switch (currentState)
{
case CharacterState.Normal:
break;
case CharacterState.Attacking:
animator.SetTrigger("Attack");
break;
}
// 对于新状态的处理
switch (newState)
{
case CharacterState.Normal:
break;
case CharacterState.Attacking:
animator.SetTrigger("Attack");
if (isPlayer)
attackStartTime = Time.time; // 记录角色攻击开始时间的时间点
if (!isPlayer)
{
Quaternion newRotition = Quaternion.LookRotation(playerTarget.transform.position - transform.position); // 计算角色的朝向
transform.rotation = newRotition;
}
break;
}
currentState = newState;
Debug.Log("state changed to " + currentState);
}
normal与attacking的状态转换
private void CalculateMove()
{
if (playerInput.mouseDown && cc.isGrounded)
{
StateSwitchTo(CharacterState.Attacking);
return;
}
}
void FixedUpdate()
{
switch (currentState)
{
case CharacterState.Normal:
if (isPlayer)
CalculateMove();
else
CalculateEnemyMove();
break;
case CharacterState.Attacking:
if (isPlayer)
{
moveVelocity = Vector3.zero; // 将移动速度归零,防止前一帧速度对滑动的干扰
if (Time.time < attackStartTime + slideDuration)
{
float passedTime = Time.time - attackStartTime;
float lerpTime = passedTime / slideDuration;
moveVelocity = Vector3.Lerp(transform.forward * slideSpeed, Vector3.zero, lerpTime);
}
}
break;
}
}
攻击状态的设计与实现
玩家攻击
玩家攻击动画的实现:
点击图示位置打开动画控制器:
代码实现:
private void StateSwitchTo(CharacterState newState)
{
if (isPlayer)
{
playerInput.mouseDown = false; // 清除鼠标输入,因为Enemy是由ai控制的,所以不需要mouseDown
}
// 对于当前状态的处理
switch (currentState)
{
case CharacterState.Normal:
break;
case CharacterState.Attacking:
animator.SetTrigger("Attack");
break;
}
// 对于新状态的处理
switch (newState)
{
case CharacterState.Normal:
break;
case CharacterState.Attacking:
animator.SetTrigger("Attack");
if (isPlayer)
attackStartTime = Time.time; // 记录角色攻击开始时间的时间点
if (!isPlayer)
{
Quaternion newRotition = Quaternion.LookRotation(playerTarget.transform.position - transform.position); // 计算角色的朝向
transform.rotation = newRotition;
}
break;
}
currentState = newState;
Debug.Log("state changed to " + currentState);
}
public void AttackAnimationEnds()
{
StateSwitchTo(CharacterState.Normal); // 攻击状态转换为常态
}
玩家攻击特效的实现:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VFX;
public class PlayerVFXManager : MonoBehaviour
{
public VisualEffect visualEffect;
public ParticleSystem particleSystem;
public void UpdateStep(bool state)
{
if (state)
{
visualEffect.Play(); // 播放VFX动画
}
else
{
visualEffect.Stop();
}
}
public void PlayBlade01()
{
particleSystem.Play();
}
}
敌人攻击
敌人攻击动画的实现:
打开敌人的动画控制器后将敌人的攻击动作设计完毕,后续与玩家的设计原理相同。
代码实现:
private void CalculateEnemyMove()
{
if (Vector3.Distance(transform.position, playerTarget.position) > agent.stoppingDistance)
{
agent.SetDestination(playerTarget.position);
animator.SetFloat("Speed", 0.2f);
}
else
{
agent.SetDestination(transform.position);
animator.SetFloat("Speed", 0f);
StateSwitchTo(CharacterState.Attacking); // 靠近玩家时切换为攻击状态
}
}
敌人攻击特效的实现:
代码实现:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VFX;
public class EnemyVFXManager : MonoBehaviour
{
public VisualEffect visualEffect;
public VisualEffect AttackVFX;
public void PlayerAttackAnimation()
{
AttackVFX.Play();
}
public void BurstFootStep()
{
visualEffect.Play();
}
}
实现攻击时滑动的功能
private float attackStartTime;
public float slideDuration = 0.5f;
public float slideSpeed = 0.4f;
switch (newState)
{
case CharacterState.Normal:
break;
case CharacterState.Attacking:
animator.SetTrigger("Attack");
if (isPlayer)
{
attackStartTime = Time.time; // 记录角色攻击开始时间的时间点
moveVelocity = Vector3.zero; // 将移动速度归零,防止前一帧速度对滑动的干扰
if (Time.time < attackStartTime + slideDuration)
{
float passedTime = Time.time - attackStartTime;
float lerpTime = passedTime / slideDuration;
moveVelocity = Vector3.Lerp(transform.forward * slideSpeed, Vector3.zero, lerpTime);
}
}
break;
}
热门推荐
牛肉为何一炖就柴?加这4种香料,牛肉又嫩又滑不塞牙,越炖越香
第十七届集美龙舟赛下周末举行,文体旅一体传承龙舟文化
中意加强文化遗产保护合作,56件流失文物艺术品回归祖国
王者荣耀KPI为什么可以选一样的英雄
中国南北差异大揭秘:气候、饮食、文化大不同!
核磁共振头部平扫能检查什么
探索细胞再生技术,改变人类健康的革命
企业公司治理与股权架构设计指南
电竞鼠标延迟优化秘籍:如何在激烈竞争中占得先机
仿树塔:科技与自然的巧妙融合
打嗝和放屁是怎么回事
鸡蛋、干货存储技巧有哪些?
祁阳市法院观音滩法庭成功调解一起亲兄弟间民间借贷案件
新手方向感差怎么训练?有哪些成功案例?
内存频率对渲染性能的影响及选择指南
Cesium 3D Tiles 简介
最好的生活状态,就在这三句话里
1000块投资可以做什么?小额投资理财小技巧揭秘
新手STM32:HAL库实现流水灯,并利用中断控制(使用STM32cubeMX)
购买需谨慎!日本药妆店的药可不能随便吃!第一类、第二类、第三类药品有何区别?
唐诗代表人物生平简介:韦庄,《全唐诗》录其诗三百一十六首
晨起时身体常有这个表现,可能是脑肿瘤已到访!
摇篮曲的秘密,你知道吗?
【漫话健康】胸闷,胸痛,警惕它……
五灵脂:传统中药材的活血止痛功效
云南保山旅游攻略:自然奇观与民族文化的完美融合
如何守护青少年用网?AI怎样赋能网络安全?专家有话说→
如何做影视品牌营销策划?
时间管理的艺术:帕累托原则的智慧运用
用vpn(虚拟网络)违法,但为什么还有许多人在用?有什么风险?