目标
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)文章来源:https://www.toymoban.com/news/detail-761252.html
视频:unity作业-射箭游戏_哔哩哔哩_bilibili文章来源地址https://www.toymoban.com/news/detail-761252.html
到了这里,关于unity实现射箭游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!