当前位置: 首页 > wzjs >正文

海外网站免费建设百度指数查询手机版app

海外网站免费建设,百度指数查询手机版app,杭州电商公司排名,做班级网站的素材Unity开发2D类银河恶魔城游戏学习笔记 Unity教程(零)Unity和VS的使用相关内容 Unity教程(一)开始学习状态机 Unity教程(二)角色移动的实现 Unity教程(三)角色跳跃的实现 Unity教程&…

Unity开发2D类银河恶魔城游戏学习笔记

Unity教程(零)Unity和VS的使用相关内容
Unity教程(一)开始学习状态机
Unity教程(二)角色移动的实现
Unity教程(三)角色跳跃的实现
Unity教程(四)碰撞检测
Unity教程(五)角色冲刺的实现
Unity教程(六)角色滑墙的实现
Unity教程(七)角色蹬墙跳的实现
Unity教程(八)角色攻击的基本实现
Unity教程(九)角色攻击的改进

Unity教程(十)Tile Palette搭建平台关卡
Unity教程(十一)相机
Unity教程(十二)视差背景

Unity教程(十三)敌人状态机
Unity教程(十四)敌人空闲和移动的实现
Unity教程(十五)敌人战斗状态的实现
Unity教程(十六)敌人攻击状态的实现
Unity教程(十七)敌人战斗状态的完善

Unity教程(十八)战斗系统 攻击逻辑
Unity教程(十九)战斗系统 受击反馈
Unity教程(二十)战斗系统 角色反击

Unity教程(二十一)技能系统 基础部分


如果你更习惯用知乎
Unity开发2D类银河恶魔城游戏学习笔记目录


文章目录

  • Unity开发2D类银河恶魔城游戏学习笔记
  • 前言
  • 一、概述
  • 二、单例模式
  • 三、玩家管理器PlayerManager
  • 三、技能管理器SkillManager
  • 四、Skill基类
  • 五、创建Dash_Skill冲刺技能
  • 总结 完整代码
    • PlayerManager.cs
    • SkillManager.cs
    • Skill.cs
    • Dash_Skill.cs
    • Player.cs
    • SkeletonBattleState.cs
    • SkeletonGroundedState.cs


前言

本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记,如有错误,欢迎指正。

本节实现角色技能系统基础部分。

Udemy课程地址

对应视频:
Concept of a Skill System
Creating Player Manager and Skill Manager
Foundation of Skill System


一、概述

本节开始进入技能系统的实现。

先使用单例模式创建玩家管理器PlayerManager和技能管理器SkillManager用于全局访问。

创建一个技能基类,所有技能都将在此基础上创建。

修改冲刺,将它重写为一个技能。

在这里插入图片描述

二、单例模式

在前面的章节中,许多类中都需要用到player。例如SkeletonBattle中,使用GameObject.Find会在所有对象中遍历查找,效率很低。
在这里插入图片描述
单例模式就可以用来解决这一点,它用来解决频繁创建和销毁全局使用的类实例的问题。
单例模式确保一个类只有一个实例,并提供一个全局访问点来访问该实例。

Unity中单例模式实现方式多种多样,在此处我们使用继承于MonoBehaviour的写法,因为我们需要PlayerManager与Unity的组件系统交互。

单例的写法总结,可以参考以下文章:
Unity单例模式设计和应用
Unity单例模式写法总结
Unity单例有几种写法

unity中最基础的是

public class PlayerManager : MonoBehaviour
{public static PlayerManager instance;private void Awake(){instance = this;}
}

在教程中,为了确保只有一个单例,添加了一些处理:

public class PlayerManager : MonoBehaviour
{public static PlayerManager instance;private void Awake(){if(instance != null)Destroy(instance.gameObject);elseinstance = this;}
}

这样写是为了让运行后多余的PlayerManager被销毁只保留一个。但尝试之后发现由于Awake执行顺序,这导致最后可能无法完全销毁多余的物体。
我做了一些修改,由每次销毁原来的实例改为每次销毁新创建的,这样最后会正常地只剩一个PlayerManager

public class PlayerManager : MonoBehaviour
{public static PlayerManager instance;public Player player;private void Awake(){if (instance != null && instance != this){Destroy(this.gameObject);}else{instance = this;}}
}

三、玩家管理器PlayerManager

在开始之前我们先整理一下相机。
创建一个空项目命名为Camera,把Main Camera和Virtual Camera都挂在下面。
在这里插入图片描述
把实体特效脚本EntityFX拖到Scripts文件夹下
在这里插入图片描述

正式开始PlayerManager的创建。

在这里插入图片描述
使用单例模式创建PlayerManager,在其中添加变量player,这样就可以在全局以类名.instance.成员名的形式访问它了。

//PlayerManager:玩家管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerManager : MonoBehaviour
{public static PlayerManager instance;public Player player;private void Awake(){if (instance != null && instance != this){Destroy(this.gameObject);}else{instance = this;}}
}

替换其他脚本中查询获取player的部分。Ctrl+F搜索vs项目找到需要替换的地方。
SkeletonBattleState和SkeletonGroundedState中

    public override void Enter(){base.Enter();player = PlayerManager.instance.player.transform;}

创建空对象并命名为PlayerManager,将脚本PlayerManager挂载到下面。将目前的玩家对象Player赋予变量。

在这里插入图片描述
在这里我们测试一下,把PlayerManager复制几份并运行。
在这里插入图片描述
多余的PlayerManager会销毁,只剩一个。

三、技能管理器SkillManager

同PlayerManager类似,创建一个SkillManager脚本,再创建一个空物体命名为SkillManager,将脚本挂上去。

SkillManager同样使用单例模式,便于全局访问。

//SkillManager:玩家管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkillManager : MonoBehaviour
{public static SkillManager instance;private void Awake(){if (instance != null && instance != this){Destroy(this.gameObject);}else{instance = this;}}
}

四、Skill基类

我们创建一个Skill基类,所有技能都继承于它。

技能大都有冷却时间,我们把它写到Skill基类里。在基类中添加冷却时间cooldown,然后添加冷却时间计时器cooldownTimer。在Update函数中更新计时器。

    [SerializeField] protected float cooldown;protected float cooldownTimer;protected virtual void Update(){cooldownTimer -= Time.deltaTime;}

我们还需要创建一个CanUseSkill函数判断冷却时间是否结束,技能是否可用。
还需有一个实现技能具体功能的函数UseSkill,在技能可用时,调用UseSkill函数释放技能。

    public virtual bool CanUseSkill(){if(cooldownTimer< 0){UseSkill();cooldownTimer = cooldown;return true;}Debug.Log("Skill is on cooldown");return false;}public virtual void UseSkill(){//技能实现}

这里教程中的逻辑是,只要判断了技能是否可用,在可用时就立即释放并重置计时器。个人认为这里两部分分开写会比较好,但前面章节都是这个逻辑写的,就先按教程中的写吧。

五、创建Dash_Skill冲刺技能

前面的章节中我们已经实现了冲刺状态,现在我们可以把它改成技能。

创建Dash_Skill脚本,它继承自Skill基类,重写UseSkill函数。

//Dash_Skill:冲刺技能
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Dash_Skill : Skill
{public override void UseSkill(){base.UseSkill();}
}

把Dash_Skill脚本挂到SkillManager下

在这里插入图片描述
在SkillManager脚本中创建冲刺技能并赋值。

    public Dash_Skill dash { get; private set; }private void Start(){dash = GetComponent<Dash_Skill>();}

现在可以把冲刺状态实现时的冲刺冷却和计时器删掉修改成调用Dash_Skill了。
在Player的CheckForInput中

    [Header("Dash Info")]public float dashSpeed=25f;public float dashDuration=0.2f;public float dashDir { get; private set; }//检查冲刺输入public void CheckForDashInput(){if (Input.GetKeyDown(KeyCode.LeftShift) && SkillManager.instance.dash.CanUseSkill()){dashDir = Input.GetAxisRaw("Horizontal");if (dashDir == 0)dashDir = facingDir;StateMachine.ChangeState(dashState);}}

给冷却时间重新赋值
在这里插入图片描述
运行查看冲刺是否正常:
在这里插入图片描述

总结 完整代码

PlayerManager.cs

玩家管理器

//PlayerManager:玩家管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerManager : MonoBehaviour
{public static PlayerManager instance;public Player player;private void Awake(){if (instance != null && instance != this){Destroy(this.gameObject);}else{instance = this;}}
}

SkillManager.cs

技能管理器,创建冲刺技能

//SkillManager:玩家管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkillManager : MonoBehaviour
{public static SkillManager instance;public Dash_Skill dash { get; private set; }private void Awake(){if (instance != null && instance != this){Destroy(this.gameObject);}else{instance = this;}}private void Start(){dash = GetComponent<Dash_Skill>();}
}

Skill.cs

技能基类,包含冷却时间和计时器,包含技能是否可用的判定和技能实现

//Skill:技能基类
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;public class Skill : MonoBehaviour
{[SerializeField] protected float cooldown;protected float cooldownTimer;protected virtual void Update(){cooldownTimer -= Time.deltaTime;}public virtual bool CanUseSkill(){if(cooldownTimer< 0){UseSkill();cooldownTimer = cooldown;return true;}Debug.Log("Skill is on cooldown");return false;}public virtual void UseSkill(){//技能实现}
}

Dash_Skill.cs

冲刺技能

//Dash_Skill:冲刺技能
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Dash_Skill : Skill
{public override void UseSkill(){base.UseSkill();}
}

Player.cs

删除冲刺冷却和计时器,修改冲刺条件

//Player:玩家
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Player : Entity
{[Header("Attack details")]public Vector2[] attackMovement;public float counterAttackDuration = 0.2f;public bool isBusy { get; private set; }[Header("Move Info")]public float moveSpeed = 8f;public float jumpForce = 12f;[Header("Dash Info")]public float dashSpeed=25f;public float dashDuration=0.2f;public float dashDir { get; private set; }#region 状态public PlayerStateMachine StateMachine { get; private set; }public PlayerIdleState idleState { get; private set; }public PlayerMoveState moveState { get; private set; }public PlayerJumpState jumpState { get; private set; }public PlayerAirState airState { get; private set; }public PlayerDashState dashState { get; private set; }public PlayerWallSlideState wallSlideState { get; private set; }public PlayerWallJumpState wallJumpState { get; private set; }public PlayerPrimaryAttackState primaryAttack { get; private set; }public PlayerCounterAttackState counterAttack { get; private set; }#endregion//创建对象protected override void Awake(){base.Awake();StateMachine = new PlayerStateMachine();idleState = new PlayerIdleState(StateMachine, this, "Idle");moveState = new PlayerMoveState(StateMachine, this, "Move");jumpState = new PlayerJumpState(StateMachine, this, "Jump");airState = new PlayerAirState(StateMachine, this, "Jump");dashState = new PlayerDashState(StateMachine, this, "Dash");wallSlideState = new PlayerWallSlideState(StateMachine, this, "WallSlide");wallJumpState = new PlayerWallJumpState(StateMachine, this, "Jump");primaryAttack = new PlayerPrimaryAttackState(StateMachine, this, "Attack");counterAttack = new PlayerCounterAttackState(StateMachine, this, "CounterAttack");}// 设置初始状态protected override void Start(){base.Start();StateMachine.Initialize(idleState);}// 更新protected override void Update(){base.Update();StateMachine.currentState.Update();CheckForDashInput();}public IEnumerator BusyFor(float _seconds){isBusy = true;yield return new WaitForSeconds(_seconds);isBusy = false;}//设置触发器public void AnimationTrigger() => StateMachine.currentState.AnimationFinishTrigger();//检查冲刺输入public void CheckForDashInput(){if (Input.GetKeyDown(KeyCode.LeftShift) && SkillManager.instance.dash.CanUseSkill()){dashDir = Input.GetAxisRaw("Horizontal");if (dashDir == 0)dashDir = facingDir;StateMachine.ChangeState(dashState);}}}

SkeletonBattleState.cs

修改查找Player的部分

//SkeletonBattleState:骷髅战斗状态
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonBattleState : EnemyState
{private Transform player;private Enemy_Skeleton enemy;private int moveDir;public SkeletonBattleState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy, string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){this.enemy =_enemy;}public override void Enter(){base.Enter();player = PlayerManager.instance.player.transform;}public override void Exit(){base.Exit();}public override void Update(){base.Update();if (enemy.IsPlayerDetected()){stateTimer = enemy.battleTime;if (enemy.IsPlayerDetected().distance < enemy.attackDistance){if(CanAttack())stateMachine.ChangeState(enemy.attackState);}}else{if(stateTimer <0 || Vector2.Distance(enemy.transform.position,player.transform.position)>10)stateMachine.ChangeState(enemy.idleState);}if(player.position.x > enemy.transform.position.x)moveDir = 1;else if(player.position.x < enemy.transform.position.x)moveDir = -1;enemy.SetVelocity(enemy.moveSpeed * moveDir, rb.velocity.y);}private bool CanAttack(){if (Time.time >= enemy.lastTimeAttacked + enemy.attackCoolDown)return true;return false;}
}

SkeletonGroundedState.cs

修改查找Player的部分

//SkeletonGroundedState:骷髅接地状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonGroundedState : EnemyState
{protected Enemy_Skeleton enemy;protected Transform player;public SkeletonGroundedState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy, string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){this.enemy=_enemy;}public override void Enter(){base.Enter();//获取Player的Transform组件player = PlayerManager.instance.player.transform;}public override void Exit(){base.Exit();}public override void Update(){base.Update();//转换到战斗状态if (enemy.IsPlayerDetected() || Vector2.Distance(enemy.transform.position,player.position) < 2)stateMachine.ChangeState(enemy.battleState);}
}
http://www.dtcms.com/wzjs/125887.html

相关文章:

  • 丹东网站建设公司google排名
  • 运营推广计划怎么写广告优化师工资一般多少
  • 重庆市建设工程造价管理总网站想做seo哪里有培训的
  • 网站维护推广怎么做如何宣传推广
  • 网站建设网站的好处seo的外链平台有哪些
  • 南宁网站建设7make网站推广优化怎么做最好
  • 注册公司网站开发建设营业项目新型网络营销方式
  • 笑话网站源码带wap西安网络优化培训机构公司
  • wordpress和关键词排名优化怎么样
  • dede学校网站模板下载网站推广方式有哪些
  • 大连网站建设设计推广教程
  • 墙纸 html 网站模板seo怎么优化方案
  • 网站开发公司需要那些硬件设备个人免费自助建站网站
  • 外贸网站开发多少钱app推广好做吗
  • 广东企业网站seo报价快速收录网
  • 实惠的网站建设网络运营培训班
  • 企业网站开发研究现状宁波如何做seo排名优化
  • 做网站网络公司新媒体营销六种方式
  • 学校网站建设项目可行性分析报告seo在线外链
  • 广东省示范校建设专题网站seo模拟点击工具
  • 春哥 响应式网站建设淘宝seo是什么意思啊
  • 沈阳市人大网站建设时间网络营销外包推广价格
  • 泗洪网站建设域名注册管理机构
  • asp.net 网站管理工具网站优化的主要内容
  • 优化企业门户网站东营网站建设费用
  • 怎么将网站做成小程序广东百度推广的代理商
  • 句容网站建设跨境电商平台哪个最好最可靠
  • 怎么接做网站私单软文经典案例
  • 信誉好的龙岗网站设计关键词排名点击软件
  • 福州网站建设服务关键词排名推广公司