unity实现射箭游戏

目标

1.第一人称,玩家可以走动和转动视角

2.箭矢有抛物线轨迹,玩家可以通过不同的蓄力时长控制箭射出的速度

3.使用地形,绘制草和树,树具有碰撞体积

4.有静止靶和运动靶,运动靶使用unity的动画系统控制运动轨迹和速度

5.有射击区域,只有在射击区域内才能进行发射

6.在不同区域使用不同天空盒

7.记分,通过射中靶子得分

使用的资源:Standard Assets(使用其中的第一人称移动控制器),Fantasy Skybox FREE(天空盒、地形材质、草材质)、Free trees(树模型)、十字弩(弩和箭)
一、实现玩家走动和转动视角

按如下顺序组织资源,即可实现走动和视角控制,同时使得十字弩跟随镜头移动

二、实现弩蓄力

动画控制器转移顺序如下,其中hold和shoot都是混合树

zero是零蓄力状态的动作,资源中并没有提供。可以将Fill动画复制一份,然后打开编辑,将所有关键帧改为和初始帧相同,这样就是未蓄力的静止动画。在hold->shoot的转移过程添加bool条件“Fire”.

在shoot动画的最后一帧添加动画事件,触发脚本函数Shoot发射箭矢。在empty动画中添加动画事件,调用脚本函数EnterEmpty将Blend参数重置为0.将以下脚本挂载到十字弓上。这样按下右键就可以蓄力,蓄力后按下左键就可以发射。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireControl : MonoBehaviour
{
    private Animator ani;
    public float fulltime;
    public float maxspeed;
    private float holdtime = 0;
    public GameObject prefab; // 预制对象的引用

    // Start is called before the first frame update
    void Start()
    {
        ani = GetComponent<Animator>();
    }

    private void FixedUpdate()
    {
        AnimatorStateInfo stateInfo = ani.GetCurrentAnimatorStateInfo(0);
        if (Input.GetButton("Fire1"))
        {
            ani.SetBool("Fire", true);
        }
        else
        {
            ani.SetBool("Fire", false);
        }
        if(Input.GetButton("Fire2"))
        {
            ani.SetBool("Holding",true);
            if(holdtime < fulltime && ani.GetCurrentAnimatorStateInfo(0).IsName("hold"))
                holdtime += Time.deltaTime;
            ani.SetFloat("Blend", holdtime / fulltime);
        }
        else
        {
            ani.SetBool("Holding", false);
        }
    }
    // Update is called once per frame
    void Update()
    {
    }
    public void EnterEmpty()
    {
        holdtime = 0;
        ani.SetFloat("Blend", 0);
    }
    public void Shoot(string name)
    {
        Debug.Log("Shoot");
        if (name == "shoot")
        {
            SSDirector.getInstance().currentSceneController.Shoot(ani.GetFloat("Blend") * maxspeed);//发射箭矢
        }
    }
}
三、绘制地形、草、树

其中树需要手动为预制件添加组件“Capsule Collider”,以增加碰撞体。

四、制作静止靶和运动靶

静止靶制作为蓝色,运动靶制作为红色

为运动靶添加动画。通过窗口->动画->动画打开动画编辑器。选中运动靶游戏对象->选择添加动画->添加运动靶的位置属性->设置三个关键帧,初始帧坐标为(0,0,0),末尾帧的位置坐标和初始帧相同。然后创建动画控制器,设置如下动画转移:

可以选中targetMove1修改其播放速度。最后将动画控制器添加到靶子上,并勾选“应用根运动”,这样可以将预制件复制到不同位置进行往返运动。

五、设置射击区域

出于游戏性考虑,射击区域应该是玩家可见的,这里将射击区域设计为半透明的蓝色方块:

勾选Box Collider的“是触发器”选项,这样玩家就可以穿过该方块。在该方块上添加脚本,实现   OnTriggerEnter和OnTriggerExit,分别将玩家进入和退出射击区域的事件通知场记对象。场记在玩家进入射击区域时将布尔变量shootArea标记为true,在离开时标记为false。同时在十字弩的动画转移“hold”->shoot中添加额外条件“ShootArea”,将其与shootArea同步,这样就使得玩家不在射击区域时不能触发shoot动画,也就不会射出箭矢。

除了射击区域,我还设计了补给区域。为动画转移Empty->hold添加bool条件HasArrow。进入补给区域时将剩余箭的数量改为10,每次射箭减少1,减为0时将HasArrow改为false,进入补给区时改为true。这样在没有箭矢时也不会播放装填动画。

六、天空盒

使用Fantasy Sky FREE的天空素材。

用一个巨大的正方体触发器覆盖一半的游戏区域。当玩家进入或离开该碰撞体时触发天空切换。切换天空的脚本如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SkyControl : MonoBehaviour
{
    public Material[] mats;
    private static int index = 0;
    public int changeTime;//更换天空盒子的秒数

    public  void ChangeBox()
    {
        Debug.Log("change skybox"+index);
        RenderSettings.skybox = mats[index];
        index++;
        index %= mats.Length;
    }
    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
    }
}

在unity编辑器页面拖入天空盒素材到mats数组,这里只添加两个天空盒素材,使得两个区域和天空盒有固定映射关系。

七、记分

射箭时,将箭的游戏对象命名为“arrow”,在靶子发生碰撞时,检查collision.gameObject的名称是否为“arrow”,若是则通知场记,同时传递当前靶子的分值(脚本的public字段,可以在unity编辑器页面修改)。每个射击区域有各自的得分倍率,在进入区域时也将倍率传递给场记。场记在收到命中事件后,将靶子的分值乘上当前区域的得分倍率,作为此次命中的得分。

代码:3DgameDesign/lab11_Assets at main · xu-yongjia/3DgameDesign (github.com)

视频:unity作业-射箭游戏_哔哩哔哩_bilibili

猜你喜欢

转载自blog.csdn.net/weixin_66458735/article/details/134667679