Unity 3D射箭游戏

这篇具有很好参考价值的文章主要介绍了Unity 3D射箭游戏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实现功能

 地形:使用地形组件,上面有草、树;
 天空盒:使用天空盒,天空可随时间变化
 固定靶:有一个以上固定的靶标;
 运动靶:有一个以上运动靶标,运动轨迹,速度使用动画控制;
 射击位:地图上应标记若干射击位,仅在射击位附近可以拉弓射击;
 驽弓动画:支持蓄力半拉弓,然后 hold,择机 shoot;
 游走:玩家的驽弓可在地图上游走,不能碰上树和靶标等障碍;
 碰撞与计分:在射击位,射中固定靶+10分,移动靶+20分。

二、代码介绍

2.1总体框架

导入了assets store的三个资源包,分别是天空盒、靶子、弓箭资源包,ArrowController用于射箭碰撞检测控制,BowController用于控制拉弓蓄力及射击,BowMovement用于控制弓箭(摄像头)移动及视角转动,SwitchSky用于控制天空盒随时间变化。

Unity 3D射箭游戏,unity,游戏,游戏引擎

2.2天空盒变化

新建一个空物体挂载SwitchSky,配置mats数组为需要切换的天空盒材质,ChangeTime为天空盒切换时间,这里的三个天空盒Material均为资源包中下载的。

Unity 3D射箭游戏,unity,游戏,游戏引擎

ChangeBox() 是一个公共方法。它在指定的时间间隔内被 InvokeRepeating() 方法重复调用。在这个方法中,它通过改变 currentIndexnextIndex 来更新当前和下一个天空盒的索引,并将 RenderSettings.skybox 设置为 mats 数组中的下一个天空盒材质。

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

public class SwitchSky : MonoBehaviour
{
    public Material[] mats;
    private int currentIndex = 0;
    private int nextIndex = 1;
    public int changeTime; // 更换天空盒子的秒数

    void Start()
    {
        RenderSettings.skybox = mats[currentIndex];
        InvokeRepeating("ChangeBox", 0, changeTime);
    }

    public void ChangeBox()
    {
        currentIndex = nextIndex;
        nextIndex = (nextIndex + 1) % mats.Length;
        RenderSettings.skybox = mats[currentIndex]; // 更换天空盒材质
    }
}

2.3地形配置

导入资源包后将任意Demo拖入对象列表即可获得对应天空盒和地形,根据游戏需要设置地形范围大小,环境中还有草、栅栏、树、石头等,这些物体的预制体中需要添加Collider,选择合适的Collider以保证玩家的驽弓可在地图上游走,不能碰上树和靶标等障碍。

Unity 3D射箭游戏,unity,游戏,游戏引擎Unity 3D射箭游戏,unity,游戏,游戏引擎

Unity 3D射箭游戏,unity,游戏,游戏引擎

2.4固定靶、移动靶

直接拖入资源包中的靶子预制体即可使用,靶子数量根据个人游戏设计添加。

Unity 3D射箭游戏,unity,游戏,游戏引擎

固定靶添加标签staticTarget,移动靶添加标签MovingTarget,地形添加标签Ground.

Unity 3D射箭游戏,unity,游戏,游戏引擎

移动靶分为左右移动和上下移动两种,以上下移动的动画UpDownTarget为例,新建Animation——UpDownTarget,拉到需要做成移动靶的靶子对象上自动建立Animator组件,Animation通过编辑Curves或录制设计上下移动的动画。

Unity 3D射箭游戏,unity,游戏,游戏引擎

2.5射击位

新建两个任意形状对象作为射击区域,这里选择建立两个圆形区域,白色圆形区域附近有两个移动靶,而绿色移动区域均为固定靶,两个射击区对象均添加标签Ground.后续代码实现仅在射击位附近可以拉弓射击。

2.6拉弓动画及拉弓射击控制

弓箭CrossBow的动画控制器CrossbowAni设置如下,Empty到EmptyPull的转移条件为isPulling = Ture,EmptyPull到Shoot的转移条件为Fire = True. 

Unity 3D射箭游戏,unity,游戏,游戏引擎

Unity 3D射箭游戏,unity,游戏,游戏引擎

射击控制由BowController实现,可以检测

1.Isinarea() 方法用于检查玩家是否处于特定区域内。

        检查当前玩家是否位于预设的两个区域中的任意一个内,通过计算玩家位置和两个区域点之间的距离来判断。

如果玩家在指定区域内:

  • 按下空格键时触发开始拉弓动作,设置 isPullingtrue
  • 持续按住空格键记录按键时间,并映射为拉弓的强度 pullStrength
  • 松开空格键时结束拉弓动作。
  • 点击鼠标左键触发射箭动作,通过 Fire() 方法发射箭矢,并根据 pullStrength 来设置箭矢的发射力度。

2.Fire() 方法:

  • firePoint 位置实例化箭矢预制体,并设置箭矢的初始位置和方向。
  • 给箭矢添加了 Rigidbody 组件,并根据 holdForce(拉弓力度)施加力,使箭矢飞行
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

public class BowController : MonoBehaviour
{

    Animator animator;
    bool isPulling = false;
    float pullDuration = 0f;
    public float maxPullDuration = 2f; // 最长拉弓时间
    public float arrowSpeed = 1f; // 箭矢速度
    public GameObject arrowObj;
    float pullStrength;
    public Transform firePoint;
    public Camera maincam;
    void Start()
    {
        // 获取弓上的Animator组件
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        if (Isinarea())
        {
            Debug.Log("在区域内");
            // 当按下空格键时触发状态切换
            if (Input.GetKeyDown(KeyCode.Space))
            {
                pullDuration = 0;
                animator.SetBool("Fire", false);
                animator.SetFloat("Power", 0);
                isPulling = true;
                animator.SetBool("isPulling", true);
                //animator.SetBool("Holding", false);
            }

            // 持续按下空格键时记录按下时间,决定拉弓的强度
            if (isPulling)
            {
                pullDuration += Time.deltaTime;
                // 将按下的时间映射到0到1的范围,作为拉弓强度的参数
                pullStrength = Mathf.Clamp01(pullDuration / maxPullDuration);
                animator.SetFloat("Power", pullStrength);
            }


            if (Input.GetKeyUp(KeyCode.Space))
            {

                isPulling = false;
                //animator.SetBool("Holding", true);
                animator.SetBool("isPulling", false);

            }
            // 当点击鼠标左键时触发射击
            if (Input.GetMouseButtonDown(0))
            {
                animator.SetBool("Fire", true);
                animator.SetFloat("Power", 0);
                // animator.SetBool("Holding", false);
                Fire(pullStrength);
            }
        }
    }
    public void Fire(float holdForce)
    {
        GameObject arrow = Instantiate<GameObject>(Resources.Load<GameObject>("prefabs/Arrow"));
        arrow.AddComponent<ArrowController>();
        ArrowController arrowController = arrow.GetComponent<ArrowController>();
        arrowController.cam = maincam;
        arrow.transform.position = firePoint.transform.position;
        arrow.transform.rotation = Quaternion.LookRotation(this.transform.forward);
        Rigidbody rd = arrow.GetComponent<Rigidbody>();
        if (rd != null)
        {
            rd.AddForce(this.transform.forward * 60 * holdForce);
            Debug.Log(arrow.transform.rotation);
        }
    }
    bool Isinarea()
    {
        Vector3 currentPosition = transform.position;
        Vector3 area1 = new Vector3(-99.12f, 14.86f, 153.65f);
        Vector3 area2 = new Vector3(-93.8506f, 15.3659f, 83.4803f);
        float distance1 = Vector3.Distance(currentPosition, area1); // 计算目标点和玩家位置之间的距离
        float distance2 = Vector3.Distance(currentPosition, area2);
        float radius = 10f; // 圆的半径

        if (distance1 <= radius || distance2 <= radius)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

}

2.7游走控制

1.变量定义:

  • public Transform tourCamera;:用于存储游览相机的 Transform 组件。
  • moveSpeed, rotateSpeed, shiftRate:控制相机移动和旋转的速度参数。
  • minDistance:控制相机与不可穿透表面的最小距离。

2.Update() 方法:

  • GetDirection():检测玩家输入,并获取相机移动的方向。
  • 通过 Physics.Raycast() 方法检查是否离不可穿透表面过近,如果是,消除垂直于不可穿透表面的运动速度分量,以防止相机穿透表面。
  • 限制相机的最大和最小高度。
  • 使用 Translate() 方法移动相机。

3.GetDirection() 方法:

  • 根据玩家输入的键盘按键来设置相机在各个方向上的移动速度,实现弓箭在地图上游走。
  • 通过 Input.GetMouseButton(1) 检测鼠标右键是否按下,如果按下,根据鼠标移动来控制相机的旋转。

4.V3RotateAround() 方法:

  • 用于计算一个 Vector3 绕旋转中心旋转指定角度后所得到的向量。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BowMovement : MonoBehaviour
{
    // 在场景中游览的相机(不要给相机加碰撞器!)
    public Transform tourCamera;
    #region 相机移动参数
    public float moveSpeed = 20.0f;
    public float rotateSpeed = 150.0f;
    public float shiftRate = 2.0f;// 按住Shift加速
    public float minDistance = 0.5f;// 相机离不可穿过的表面的最小距离(小于等于0时可穿透任何表面)
    #endregion
    #region 运动速度和其每个方向的速度分量
    private Vector3 direction = Vector3.zero;
    private Vector3 speedForward;
    private Vector3 speedBack;
    private Vector3 speedLeft;
    private Vector3 speedRight;
    private Vector3 speedUp;
    private Vector3 speedDown;
    #endregion
    void Start()
    {
        if (tourCamera == null) tourCamera = gameObject.transform;

    }
    void Update()
    {
        GetDirection();
        // 检测是否离不可穿透表面过近ss
        RaycastHit hit;
        while (Physics.Raycast(tourCamera.position, direction, out hit, minDistance))
        {
            // 消去垂直于不可穿透表面的运动速度分量
            float angel = Vector3.Angle(direction, hit.normal);
            float magnitude = Vector3.Magnitude(direction) * Mathf.Cos(Mathf.Deg2Rad * (180 - angel));
            direction += hit.normal * magnitude;
        }
        if (tourCamera.localPosition.y > 25.0f)
        {
            tourCamera.localPosition = new Vector3(tourCamera.localPosition.x, 25.0f, tourCamera.localPosition.z);
        }
        if (tourCamera.localPosition.y < 12.0f)
        {
            tourCamera.localPosition = new Vector3(tourCamera.localPosition.x, 12.0f, tourCamera.localPosition.z);
        }
        tourCamera.Translate(direction * moveSpeed * Time.deltaTime, Space.World);
    }
    private void GetDirection()
    {
        #region 加速移动
        if (Input.GetKeyDown(KeyCode.LeftShift)) moveSpeed *= shiftRate;
        if (Input.GetKeyUp(KeyCode.LeftShift)) moveSpeed /= shiftRate;
        #endregion
        #region 键盘移动
        // 复位
        speedForward = Vector3.zero;
        speedBack = Vector3.zero;
        speedLeft = Vector3.zero;
        speedRight = Vector3.zero;
        speedUp = Vector3.zero;
        speedDown = Vector3.zero;
        // 获取按键输入
        if (Input.GetKey(KeyCode.W)) speedForward = tourCamera.forward;
        if (Input.GetKey(KeyCode.S)) speedBack = -tourCamera.forward;
        if (Input.GetKey(KeyCode.A)) speedLeft = -tourCamera.right;
        if (Input.GetKey(KeyCode.D)) speedRight = tourCamera.right;
        if (Input.GetKey(KeyCode.E)) speedUp = Vector3.up;
        if (Input.GetKey(KeyCode.Q)) speedDown = Vector3.down;
        direction = speedForward + speedBack + speedLeft + speedRight + speedUp + speedDown;
        #endregion
        #region 鼠标旋转
        if (Input.GetMouseButton(1))
        {
            // 转相机朝向
            tourCamera.RotateAround(tourCamera.position, Vector3.up, Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime);
            tourCamera.RotateAround(tourCamera.position, tourCamera.right, -Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime);
            // 转运动速度方向
            direction = V3RotateAround(direction, Vector3.up, Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime);
            direction = V3RotateAround(direction, tourCamera.right, -Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime);
        }
        #endregion
    }
    /// <summary>
    /// 计算一个Vector3绕旋转中心旋转指定角度后所得到的向量。
    /// </summary>
    /// <param name="source">旋转前的源Vector3</param>
    /// <param name="axis">旋转轴</param>
    /// <param name="angle">旋转角度</param>
    /// <returns>旋转后得到的新Vector3</returns>
    public Vector3 V3RotateAround(Vector3 source, Vector3 axis, float angle)
    {
        Quaternion q = Quaternion.AngleAxis(angle, axis);// 旋转系数
        return q * source;// 返回目标点
    }

}

2.8碰撞与计分

碰撞逻辑在ArrowController实现,分数改变传递到ui.score变量显示。

1.变量定义:

  • private Rigidbody rb;:箭矢的刚体组件,用于控制箭矢的物理行为。
  • public float Score = 0;:箭矢的得分,可能是在箭矢击中目标时增加的分数。
  • public Camera cam;:用于获取相机以访问 Main 脚本。
  • private Main ui;:对游戏界面的引用,用于更新得分。

2.Start() 方法:

  • 获取箭矢的刚体组件。
  • 获取相机上的 Main 脚本。

3.OnCollisionEnter(Collision collision) 方法:

  • 当箭矢与其他物体碰撞时触发。
  • 如果是 "staticTarget" 标签,分数增加 10 分,箭矢销毁。
  • 如果是 "MovingTarget" 标签,分数增加 20 分,箭矢销毁。
  • 如果是 "Ground" 标签,箭矢直接销毁。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SocialPlatforms.Impl;

public class ArrowController : MonoBehaviour
{
    // Start is called before the first frame update
    private Rigidbody rb;
    public float Score = 0;

    public Camera cam;
    private Main ui;
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        ui = cam.GetComponent<Main>();
    }

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

    }
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("staticTarget"))
        {
            rb.velocity = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
            ui.Score += 10;
            Destroy(gameObject);

        }
        else if (collision.gameObject.CompareTag("MovingTarget"))
        {
            rb.velocity = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
            ui.Score += 20;
            Destroy(gameObject);
        }
        else if (collision.gameObject.CompareTag("Ground"))
        {
            rb.velocity = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
            Destroy(gameObject);
        }

    }
}

Main实现显示分数和游戏提示,挂载在主摄像机Cam_fps(1)上。

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

public class Main : MonoBehaviour
{
    // Start is called before the first frame update
    public float Score = 0;
    void Start()
    {
    }

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

    }
    private void OnGUI()
    {
        GUIStyle style = new GUIStyle();
        style.fontSize = 15;
        style.normal.textColor = Color.white;

        // 定义游戏介绍文本内容
        string introText = "天空10s自动切换\nwasd --移动弓弩\nSpace --蓄力拉弓\n鼠标左键 --射箭\n鼠标右键 --调整角度";

        // 在屏幕左上角绘制游戏介绍文本
        GUI.Label(new Rect(10, 10, 300, 100), introText, style);
        style.fontSize = 24;
        style.normal.textColor = Color.white;
        // 在屏幕右上角显示分数
        GUI.Label(new Rect(Screen.width - 150, 20, 150, 30), "Score: " + Score, style);
    }
}

三、游戏演示

参考博客:unity射箭小游戏-CSDN博客

演示视频:Unity3D射箭小游戏_哔哩哔哩_bilibili

Unity 3D射箭游戏,unity,游戏,游戏引擎文章来源地址https://www.toymoban.com/news/detail-755049.html

到了这里,关于Unity 3D射箭游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • final-期末大作业-制作AR射箭小游戏(Unity AR配置详细教程)

    链接: github仓库 bilibili视频 大作业要求: 制作一款特定技术应用小游戏,并提交技术报告。 内容(请参考以下技术主题,但不限于这些主题): 运用手机拍若干全景图,贴到天空盒或球型天空,做一个简单校园漫游功能。 粒子系统效果制作,必须带一个控制组件,控制粒子

    2024年02月06日
    浏览(34)
  • 【毕业论文】| 基于Unity3D引擎的冒险游戏的设计与实现

    📢博客主页:肩匣与橘 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 肩匣与橘 编写,首发于 CSDN 🙉 📢生活依旧是美好而又温柔的,你也是✨  基于Unity3D引擎的冒险游戏的设计与实现 📢前言 摘要 Abstract 1 绪论 1.1 选题背景 1.2 研究目的及意义 2 开发工具

    2024年02月05日
    浏览(46)
  • SuperMap Hi-Fi 3D SDK for Unity制作游戏引擎材质

    kele     在交通,电力,规划等行业中,有的对象常常具有很强的质感,比如金属质感的 钢轨,电力塔;陶瓷材质的绝缘子;玻璃材质的建筑幕墙等,但常规方式的表现效果 往往差强人意。     游戏引擎(Unity3D)中已有丰富的材质资源库,比如玻璃,金属等材质,这

    2024年02月09日
    浏览(75)
  • 【Unity3D赛车游戏优化篇】【十】汽车粒子特效和引擎咆哮打造极速漂移

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 :Unity游戏demo – 😶‍🌫️版本: Unity2021 😶‍🌫️适合人群:Unity初学者进阶 😶‍🌫️学习目标:3D赛车游戏的基础制作 😶‍🌫️技能

    2024年02月09日
    浏览(45)
  • 3D射箭游戏

    目录 一、游戏介绍 1、游戏要求 2、游戏规则 二、游戏实现 1、地形 2、天空盒 3、固定靶和运动靶 4、射击位 5、弩弓管理 6、游走         7、碰撞与计分 三、游戏视频 四、代码地址 一、游戏介绍 1、游戏要求  基础分:有博客;  1-3分钟视频:视频呈现游戏主要游玩过程

    2024年02月03日
    浏览(22)
  • 十八、Unity游戏引擎入门

    1、下载     首先需要下载Unity Hub,下载网址:https://unity.com/cn。     然后在其中下载Unity编辑器并安装,可选择最新版本。     接着需要选择适合的开发环境,例如Android Studio或Xcode,以便进行手机游戏开发。在安装完Unity后,需要根据项目需求下载对应的模块和插件,例

    2024年02月16日
    浏览(51)
  • Unity、UE、Cocos游戏开发引擎的区别

    Unity、Unreal Engine(UE)和Cocos引擎是三个常用的游戏开发引擎,它们在功能和特性上有一些区别。以下是它们之间的主要区别: 编程语言:Unity使用C#作为主要的编程语言,开发者可以使用C#脚本进行游戏逻辑编写。Unreal Engine主要使用C++作为编程语言,但也支持蓝图系统,允许

    2024年02月22日
    浏览(47)
  • 【Unity】3D跑酷游戏

    finish_all 翻墙:https://www.youtube.com/watch?v=9ZEu_I-ido4list=PLPV2KyIb3jR53Jce9hP7G5xC4O9AgnOuLindex=3 最终成果 2.1 基本场景 1.创建Cube作为跑道 1)记得把位置Reset; 2)改名为ground; 3)改变其参数,x=15,y=1,z=100; 4)调整位置使其从相机同一位置开始。 选中单击f可聚焦。 2.创建Cube作为Pla

    2024年02月04日
    浏览(29)
  • Unity vs Godot :哪个游戏引擎更适合你?

    游戏引擎的选择对开发过程和最终产品质量有着重大影响。近年来,Godot和Unity这两款引擎受到广泛关注。本文将从多个维度对两者进行比较,以期为开发者提供正确的选择建议。 Godot和Unity都有各自的优势,没有绝对的好坏之分。Godot开源免费,上手简单,更适合2D和小型游戏

    2024年01月23日
    浏览(74)
  • Unity3D学习笔记——物理引擎

    1简介 刚体可以为游戏对象赋予物理特性,是游戏对象在物理系统的控制下接受推力和扭力,从而实现现实世界的物理学现象。 2属性 1简介 碰撞器是物理组件的一类,他与刚体一起促使碰撞发生 碰撞体是简单形状,如方块、球形或者胶囊形,在 Unity 3D 中每当一个 GameObjects

    2023年04月12日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包