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

学习游戏制作记录(boss的制作)

我们想制作一个会随机传送或者释放法术的boss

1.实现boss的随机传送

状态机依旧参考骷髅

修改Enemy_DeathBringer脚本:

 [Header("Teleport Details")]
[SerializeField] private BoxCollider2D arena;//传送的区域
[SerializeField] private Vector2 surroundingCheckSize;//检测附近有无障碍物的半径

 public float chanceToTeleport;//传送的概率
public float defaultChanceToTeleport=25;//默认传送的概率

 #region States
public DeathBringerIdleState idleState;
public DeathBringerBattleState battleState;
public DeathBringerAttackState attackState;
public DeathBringerDeadState deadState;
public DeathBringerSpellCastState spellCastState;
public DeathBringerTeleportState teleportState;
#endregion

  public void FindPosition()
{
FindPositionWithLimit(50); // 最多尝试50次
}

  private void FindPositionWithLimit(int maxAttempts)//寻找位置
{
int attempts = 0;

      while (attempts < maxAttempts)
{
// 生成随机位置
float x = Random.Range(arena.bounds.min.x + 3, arena.bounds.max.x - 3);
float y = Random.Range(arena.bounds.min.y + 3, arena.bounds.max.y - 3);

          transform.position = new Vector3(x, y);
transform.position = new Vector3(transform.position.x,
transform.position.y - GroundBelow().distance + (cd.size.y / 2));

          // 如果位置合适,直接返回
if (GroundBelow() && !SomethingIsAround())
{
return; // 找到合适位置,退出函数
}

          attempts++;
}

  }

  private RaycastHit2D GroundBelow() => Physics2D.Raycast(transform.position, Vector2.down, 100, whatIsground);//离地距离和地面检测
private bool SomethingIsAround() => Physics2D.BoxCast(transform.position, surroundingCheckSize, 0, Vector2.zero, 0, whatIsground);//检测是否在地面里面

  protected override void OnDrawGizmos()
{
base.OnDrawGizmos();

      Gizmos.DrawLine(transform.position, new Vector3(transform.position.x, transform.position.y - GroundBelow().distance));
Gizmos.DrawWireCube(transform.position, surroundingCheckSize);
}

  public bool canTeleport()//是否可以传送
{
if(Random.Range(0,100)<=chanceToTeleport)
{
chanceToTeleport = defaultChanceToTeleport;//每次传送成功恢复默认概率
return true;
}
else
return false;

  }

创建DeathBringerTeleportState脚本:

 public override void Enter()
{
base.Enter();

     enemy.state.MakeInvicibale(true);//进入传送时无敌
}

 public override void Update()
{
base.Update();

     if(triggerCalled)
{
enemyStateMachine.ChangeState(enemy.battleState);//攻击结束跳转到战斗状态追击玩家
}
}
public override void Exit()
{
base.Exit();

     enemy.state.MakeInvicibale(false);//退出时解除无敌
}

修改DeathBringerIdleState脚本:

    public override void Update()
{
base.Update();

        if(Input.GetKeyDown(KeyCode.Alpha5))//仅用于调试按下5使boss开始传送
{
enemyStateMachine.ChangeState(enemy.teleportState);
}
}

修改DeathBringerAttackState脚本:

  public override void Enter()
{
base.Enter();

      enemy.chanceToTeleport += 5;//每次攻击都会增加传送的概率
}

  public override void Exit()
{
base.Exit();

      enemy.lastAttackTime = Time.time;
}

  public override void Update()
{
base.Update();
enemy.SetZeroVelocity();

      if (triggerCalled)
{
if (enemy.canTeleport())//攻击结束后进行一次传送
enemy.enemyStateMachine.ChangeState(enemy.teleportState);
else//否则继续战斗
enemyStateMachine.ChangeState(enemy.battleState);
}
}

创建Enemy_DeathBringerAnimationTrigger脚本:

public class Enemy_DeathBringerAnimationTrigger : Enemy_AnimationTrigger
{
private Enemy_DeathBringer enemyDeathBringer => GetComponentInParent<Enemy_DeathBringer>();

    private void ReLocate() => enemyDeathBringer.FindPosition();//进行传送,绑定在传送消失的最后一帧


    private void MakeInvisible() => enemyDeathBringer.entityFX.MakeTransprent(true);//恢复血条的显示,绑定在传送出现的第一帧

    private void Makevisible() => enemyDeathBringer.entityFX.MakeTransprent(false);//隐藏血条,绑定在传送消失的最后一帧

}

UI_HealthBar脚本:

  private void OnEnable()//使启用和事件绑定同步进行
{
entity.onFlipped += FlipUI;
mystate.onHealthChange += UpdateHealthUI;
}
private void UpdateHealthUI()
{
slider.maxValue = mystate.GetMaxHealth();
slider.value = mystate.currentHealth;
}

  private void OnDisable()
{
if(entity!= null) 
{
entity.onFlipped -= FlipUI;
}
if(mystate!= null)
{
mystate.onHealthChange -= UpdateHealthUI;

      }
}

2.boss的法术实体制作

创建DeathBringerSpell_Controller脚本:

[SerializeField] private Transform check;//法术攻击检查位置
[SerializeField] private Vector2 boxSize;//攻击范围
[SerializeField] private LayerMask WhatIsPlayer;//图层

private CharactorState mystats;//使用法术者的状态

public void SetUpSpell(CharactorState _mystats) => mystats = _mystats;//设置
public void AnimationTrigger()//动画触发器,在法术伤害的动画调用
{
Collider2D[] collider2Ds = Physics2D.OverlapBoxAll(check.position, boxSize, WhatIsPlayer);

    foreach (var hit in collider2Ds)
{
if (hit.GetComponent<Player>() != null)
{
hit.GetComponent<Entity>().SetupKnocbackDir(transform);

            mystats.DoDamage(hit.GetComponent<CharactorState>());

        }
}
}

private void OnDrawGizmos()=>Gizmos.DrawWireCube(check.position, boxSize);


private void SelfDestroy() => Destroy(gameObject);//自毁,法术结束时销毁实体

3.boss施法的实现

Enemy_DeathBringer脚本:

public bool BossFigthBegun;//boss战是否开始

[Header("SpellCast Details")]
[SerializeField] private GameObject spellPrefab;//法术实体的预制体
public float lastTimeCast;//上次释放法术的时间

public int amoutsOfSpells;//法术实体的数量
public float SpellCastCooldown;//不同实体间释放的冷却

[SerializeField] private float SpellCastStateCooldown;//进入施法状态的冷却

 public void CastSpell()//施法并产生实体
{
Player player = PlayerManage.instance.player;

     float xOffest = 0;
if (player.rb.velocity.x != 0)
xOffest = player.facingDir * 3;//预判玩家的位置,在玩家附近生成法术实体


     Vector3 spellPosition = new Vector3(player.transform.position.x + xOffest, player.transform.position.y + 1.5f);

     GameObject newSpell=Instantiate(spellPrefab,spellPosition, Quaternion.identity);//生成
newSpell.GetComponent<DeathBringerSpell_Controller>().SetUpSpell(state);//设置
}

 public bool canDoSpellCast()//是否可以进入施法状态
{
if (Time.time >= lastTimeCast + SpellCastStateCooldown)
{

return true;
}
else return false;
}

DeathBringerTeleportState脚本:

    public override void Update()
{
base.Update();

        if(triggerCalled)
{
if (enemy.canDoSpellCast())//如果可以施法则进入施法状态
enemyStateMachine.ChangeState(enemy.spellCastState);
else 
enemyStateMachine.ChangeState(enemy.battleState);
}
}

创建DeathBringerSpellCastState脚本:

private Enemy_DeathBringer enemy;

private int amountsOfSpell;//法术实体数量
private float SpellTimer;//计时器

public override void Enter()
{
base.Enter();

    amountsOfSpell = enemy.amoutsOfSpells;
SpellTimer =.5f;
}

public override void Update()
{
base.Update();

    SpellTimer -= Time.deltaTime;

    if(canCast())//可以施法则开始产生法术实体
{
enemy.CastSpell();
}
if(amountsOfSpell<=0)//所有法术实体释放完开始传送
{
enemyStateMachine.ChangeState(enemy.teleportState);

    }
}
public override void Exit()
{
base.Exit();

    enemy.lastTimeCast = Time.time;
}
private bool canCast()
{
if(amountsOfSpell>0&&SpellTimer<0)//有且不冷却
{
amountsOfSpell--;
SpellTimer = enemy.SpellCastCooldown;
return true;
}
else
return false;
}

DeathBringerIdleState脚本:

    public override void Update()
{
base.Update();

        if(Vector2.Distance(player.position, enemy.transform.position) < 7)//当玩家接近boss时开始战斗
{
enemy.BossFigthBegun = true;
}


        if(stateTimer<0&&enemy.BossFigthBegun)
enemyStateMachine.ChangeState(enemy.battleState);
}

http://www.dtcms.com/a/414440.html

相关文章:

  • 快速排序(含hoare版本、挖坑版本和前后指针版本)
  • LeetCode:77.买卖股票的最佳时机
  • Apache Airflow:让复杂工作流自动化变得简单优雅
  • 精读《C++20设计模式》——创造型设计模式:原型模式
  • IDEA配置Maven教程
  • OpenLayers地图交互 -- 章节十五:鼠标滚轮缩放交互详解
  • [Python编程] Python3 错误与异常
  • 动态代理 java原生 vs Cglib
  • MQTT协议基础知识速成(智能家居项目)
  • 北京网站建设认知网络推广公司服务内容
  • 爬虫疑难问题解决方案整理
  • 如何制作PDF文件目录?
  • 左右翻网站模版网页美工设计教程
  • 牛客小白月赛121
  • 深入理解目标文件:从ELF格式到链接核心
  • Java系列知识之 ~ Spring 与 Spring Boot 常用注解对比说明
  • 郫县建设局网站wordpress如何运行
  • LeetCode 114.二叉树展开为链表
  • 机器人中的电机与扭矩入门
  • 站长平台如何推广自己的网站怎么做网页版网站
  • 深入理解BFC:解决margin折叠和浮动高度塌陷的利器
  • Spec Kit - 规范驱动开发工具包
  • 具有价值的常州做网站免费进销存软件哪个简单好用
  • creo二次开发seo职位信息
  • Windows 10 环境下 Redis 编译与运行指南
  • 【编号206】房地产统计年鉴2002~2023
  • 某大型广告公司实习感受
  • 【Day 68】Zabbix-自动监控-Web检测-分布式监控
  • 企业网站建设公司公司网站开发客户挖掘
  • 天拓四方集团IOT平台:赋能电气设备制造商数智化转型新引擎