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;
}
热门推荐
英国德国时差是多少
古树普洱茶叶:品种、产地、制作工艺、品饮方法及健益处全方位解析
汽车三包政策解读的关键点是什么?
了解新加坡的牙冠安装流程
古人讲究女子无才便是德 古代女子读书为何那么难
动力学原理及其在工程实践中的应用
清流一边让海瑞冲锋陷阵,一边将他家小接到了淳安县,是何用心?
鼻窦炎鼻涕倒流到咽喉怎么治
网购维权全攻略:三个真实案例教你成功捍卫消费权益
如何判断黄金市场的支撑位?这种支撑位的判断对投资决策有什么作用?
腰椎间盘膨出与突出有哪些区别
从零开始设计专属键帽:详细步骤与实用技巧
心肌炎的症状和护理措施
打造高效工作模式:个人时间管理与效率提升指南
黑糖功效与红糖白糖大比较:营养、禁忌及建议食法
“感冒多喝水”可不是给孩子灌水!很多人都理解错了这个“多”字...
专家眼中的“清淡饮食”究竟怎么吃?
名家新芽再联袂,“粤乐长闻”写新篇
股权重组应关注的问题
王蓉:从“小王菲”到“浪姐”,一位70后歌手的音乐历程
北京民航招飞体检流程及要求全解析
医疗补助费的具体用途有哪些?
如何了解原始股的发行信息以进行投资?这种了解途径在投资决策中有何重要性?
霍克海默《理性之蚀》:什么是主观理性和客观理性?
海中金丝雀——白鲸
《守护隐私,拥抱数字未来》
五行:解读中国哲学中的五要素
2025年春节文旅消费火爆:非遗民俗、特色旅游和文创产品成消费新亮点
古代打仗有东征,西征,南征 自南向北为什么叫做北伐
坐月子禁忌注意事项