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

文章介绍了如何在一款斩杀怪物游戏中设计攻击判定和得分系统,通过使用大球形进行碰撞检测简化处理,并通过提前计算碰撞时间和攻击距离来判断得分等级,如GREAT、GOOD和OKAY,以此提升游戏的挑战性和趣味性。同时,调整判定时间阈值能控制游戏的难度和平衡性。
摘要由CSDN通过智能技术生成

大部分游戏都鼓励玩家不断挑战更高的得分。虽然也有像角色扮演(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),可以调整游戏高分的难度。这些数值是决定游戏平衡性的重要因素,我们要对照效果调整出最合适的数值。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七七喝椰奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值