unity小游戏——得分高低的判定

简介: unity小游戏——得分高低的判定

大部分游戏都鼓励玩家不断挑战更高的得分。虽然也有像角色扮演(RPG)这类更主张情节而不关注得分的游戏。但现在挑战更高分的游戏正变得越来越多。

这次我们介绍的是一个斩杀怪物的游戏。成功斩杀怪物后,怪物出现的数量会越来越多。玩家要尽可能地持续斩杀怪物,这样才能在游戏结束之前杀掉大量的怪物。反之,玩家一旦失守,怪物的数量就会减少。

当然,我们可以直接把倒下的怪物数量作为玩家的得分,但这里我们可以小小地改进一下,让游戏更有趣 。

假若武士在追赶怪物的过程中一直不攻击,最终将撞上怪物。在接近怪物的过程中,如果太近的话就会失手。玩家要在确保不撞上怪物的前提下尽可能地接近怪物并斩杀,这样游戏的技术难度就增加了。

这次我们设定了一个“靠近斩杀怪物将得到高分”的规则,但如果靠得太近又会导致武士撞上怪物而失手,这样游戏的就变得更加刺激了。

这种“高风险&高回报”的玩法很值得我们一试


一、武士攻击的判定

在讨论如何判断攻击距离的远近之前,我们先说明一下攻击判定的原理。

玩家点击鼠标按键后,武士就会发起攻击。而攻击判定的计算就伴随着攻击行为的整个过程。

在格斗类游戏中,往往需要对玩家的拳脚和所使用的无器质性攻击判定。同样,也需要对被攻击者的每个关节部位进行伤害计算。正因为有了这样精确的碰撞检测,才能够实现诸如“蹲下躲开对方的回旋踢”,“爆头秒杀”等游戏特性。

不过我们这个游戏的碰撞检测并不需要细致到这种程度。由于怪物以很快的速度朝武士靠近,如果要严格按照刀的形状来进行检测,击中难度将大大增加,因此这里我们用一个大的球形来进行碰撞检测,并再播放攻击动作的时候将其放置在武士前面。

攻击的碰撞检测的执行实践,会比攻击动作的播放时间稍微长一些。如果提前按下鼠标按键,怪物九江进入上面所说的碰撞检测的球体中,这就意味着攻击成功。格斗游戏中常常有“预判”的说法。像这种敌人朝着玩家快速扑来的游戏,加入这种机制后会让游戏变得更容易上手。

二、判断在多近的距离斩杀

通过提前进行碰撞检测和演唱检测的时间,就可以应对怪物快速运动的情况。那么,现在让我们回到主题,看看如何才能计算出"武士在多近的距离斩杀了怪物"。

首先可能会想“要计算武士在多近的距离斩杀了怪物,看看怪物和武士之间的距离不就行了吗?”。

如果这样想的话就错了!因为按照我们的设计思路,怪物会从外部撞向五十面前的碰撞检测用的球体,因此攻击成功时武士和怪物的距离必定等于该球体的半径。

下面来重新理解一下“靠近斩杀”这个过程。

攻击判定实在按键被按下的瞬间开始的。在这一瞬间,怪物和武士之间的距离可能痕迹,也可能很远。如果很远,怪物移动到碰撞检测的位置还需要一些时间。相反如果很近,碰撞检测很快就会进行。因此,我们只要计算出从执行碰撞检测(=摁下鼠标按键的瞬间)开始,到实际发生碰撞位置经过的时间,应该就可以计算出是在躲进的距离进行的斩杀了。

我们用PlayerControl.cs来管理攻击判定开始后的时间,下面列出代码

PlayerControl.attack_control方法:

private void  attack_control()
  {
    if(!this.is_playable) {
      return; 
    }
    if(this.attack_timer > 0.0f) {
      // 正在进行攻击判定
      this.attack_timer -= Time.deltaTime;
      // 攻击判定结束检测
      if(this.attack_timer <= 0.0f) {
        // 使碰撞器(攻击成功否)的碰撞判定无效
        //
        attack_collider.SetPowered(false);
      }
    } else {
      this.attack_disable_timer -= Time.deltaTime;
      if(this.attack_disable_timer > 0.0f) {
        // 仍旧不可攻击
      } else {
        this.attack_disable_timer = 0.0f;
        if(this.is_attack_input()) {
          // 使碰撞器(攻击成功与否)的攻击判定有效
          //
          attack_collider.SetPowered(true);
          this.attack_timer         = PlayerControl.ATTACK_TIME;
          this.attack_disable_timer = PlayerControl.ATTACK_DISABLE_TIME;
          // 播放攻击动作
          // 选择下一个播放的动作
          //
          // 因为要在决定“怪物”飞散的方向时知道“上一个攻击动作”
          // 应该在播放前而非在播放后选择动作
          //
          switch(this.attack_motion) {
            default:
            case ATTACK_MOTION.RIGHT: this.attack_motion = ATTACK_MOTION.LEFT;  break;
            case ATTACK_MOTION.LEFT:  this.attack_motion = ATTACK_MOTION.RIGHT; break;
          }
          switch(this.attack_motion) {
            default:
            case ATTACK_MOTION.RIGHT: this.animator.SetTrigger("attack_r"); break;
            case ATTACK_MOTION.LEFT:  this.animator.SetTrigger("attack_l"); break;
          }
          this.attack_voice_audio.PlayOneShot(this.AttackSound[this.attack_sound_index]);
          this.attack_sound_index = (this.attack_sound_index + 1)%this.AttackSound.Length;
          this.sword_audio.PlayOneShot(this.SwordSound);
        }
      }
    }
  }

其中,attack_timer是用来记录攻击判定持续时间的计时器。在按键被按下的瞬间会用一个特定的值对它进行初始化,随着时间减少,当它的值变为0时,则意味着攻击判定执行结束。

attack_timer表示的知识攻击判定的“剩余时间”,为了获得用于判断“在多近的距离斩杀”的“经过实践”,我们还需要一个GetAttackTimer方法:

  // 算出从开始攻击(点击鼠标按键起)经过的时间
  public float  GetAttackTimer()
  {
    return(PlayerControl.ATTACK_TIME - this.attack_timer);
  }

SceneControl.cs的AddDefeatNum方法在武士攻击命中怪物时被执行

SceneControl.AddDefeatNum方法:

public void AddDefeatNum(int num)
  {
    this.oni_group_defeat_num++;
    this.oni_group_complite++;
    this.result.oni_defeat_num += num;
    // 通过点击按钮后结果的时间来决定评价的好坏
    // (点击后到攻击命中的时间短=在非常精确的时刻斩杀了怪物)
    this.attack_time = this.player.GetComponent<PlayerControl>().GetAttackTimer();
    if(this.evaluation == EVALUATION.MISS) {
      // 失败(慢吞吞地运行中)后,只会出现OKAY 
      this.evaluation = EVALUATION.OKAY;
    } else {
      if(this.attack_time < ATTACK_TIME_GREAT) {
        this.evaluation = EVALUATION.GREAT;
      } else if(this.attack_time < ATTACK_TIME_GOOD) {
        this.evaluation = EVALUATION.GOOD;
      } else {
        this.evaluation = EVALUATION.OKAY;
      }
    }
    if(SceneControl.IS_AUTO_ATTACK) {
      this.evaluation = this.evaluation_auto_attack;
    }
    this.result.eval_count[(int)this.evaluation] += num;
    // 计算得分
    float[] score_list = { this.eval_rate_okay, this.eval_rate_good, this.eval_rate_great, 0 };
    this.result.score_max += num * this.eval_rate_great;
    this.result.score += num * score_list[(int)this.evaluation];
    this.result_control.addOniDefeatScore(num);
    this.result_control.addEvaluationScore((int)this.evaluation);
  }

最后,设定用于度量经过时间和得分高低关系的ATTACK_TIME_GREAT和ATTACK_TIME_GOOD的值。如果经过时间小于ATTACK_TIME_GREAT并在足够近的距离内斩杀了怪物则判定为GREAT,若时间比ATTACK_TIME_GOOD短则判定为GOOD,除此之外在原距离斩杀怪物的情况判定为OKEY。每次攻击后都记录下判定的结果,游戏结束后再通过这些结果来决定玩家的总成绩

通过改变用于衡量得分高低的经过时间的阈值(ATTACK_TIME_GREAT和ATTACK_TIME_GOOD),可以调整游戏高分的难度。这些数值是决定游戏平衡性的重要因素,我们要对照效果调整出最合适的数值。


相关文章
|
6月前
|
图形学
【制作100个unity游戏之28】花半天时间用unity复刻童年4399经典小游戏《黄金矿工》(附带项目源码)
【制作100个unity游戏之28】花半天时间用unity复刻童年4399经典小游戏《黄金矿工》(附带项目源码)
220 0
|
图形学
Unity小游戏——迷你拼图
Unity小游戏——迷你拼图
265 1
|
图形学
Unity小游戏——使被砍中的怪物四处飞散
Unity小游戏——使被砍中的怪物四处飞散
|
机器学习/深度学习 算法 图形学
Unity小游戏——无限滚动的背景的改良
Unity小游戏——无限滚动的背景的改良
117 0
|
算法 图形学
Unity小游戏——武士击杀小怪兽(无限滚动的背景)
Unity小游戏——武士击杀小怪兽(无限滚动的背景)
|
7月前
|
图形学
【Unity3D开发小游戏】Unity3D零基础一步一步教你制作跑酷类游戏
【Unity3D开发小游戏】Unity3D零基础一步一步教你制作跑酷类游戏
|
图形学
Unity小游戏——武士和怪物的碰撞检测
Unity小游戏——武士和怪物的碰撞检测
|
图形学
Unity小游戏——怪物出现模式的管理
Unity小游戏——怪物出现模式的管理
132 0
|
图形学
Unity实现2D小游戏
Unity实现2D小游戏FirstGame2D(Sunny Land) 一、游戏说明 本游戏为作者的第一个实验的2D小游戏 实现效果: (1)简单的UI界面以及触发按钮、滑动按钮事件 (2)通过按钮与按键实现场景的切换 (3)通过代码实现动画效果的切换(跳跃、蹲下等) (4)碰撞体以及触发器实现消灭敌人、收集物品、地面检测 (5)相机场景与背景运动差,实现场景与人物的立体效果,达到较好的视觉效果 (6)SoundMananger实现场景音乐的管理
271 0
Unity实现2D小游戏
|
图形学
unity吃豆人小游戏,迷宫实现
unity吃豆人小游戏,迷宫实现