3D射箭游戏

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

目录

一、游戏介绍

1、游戏要求

2、游戏规则

二、游戏实现

1、地形

2、天空盒

3、固定靶和运动靶

4、射击位

5、弩弓管理

6、游走        

7、碰撞与计分

三、游戏视频

四、代码地址


一、游戏介绍

1、游戏要求
  •  基础分:有博客;
  •  1-3分钟视频:视频呈现游戏主要游玩过程;
  •  地形:使用地形组件,上面有草、树;
  •  天空盒:使用天空盒,天空可随玩家位置 或 时间变化 或 按特定按键切换天空盒;
  •  固定靶:有一个以上固定的靶标;
  •  运动靶:有一个以上运动靶标,运动轨迹,速度使用动画控制;
  •  射击位:地图上应标记若干射击位,仅在射击位附近可以拉弓射击,每个位置有 n 次机会;
  •  驽弓动画:支持蓄力半拉弓,然后 hold,择机 shoot;
  •  游走:玩家的驽弓可在地图上游走,不能碰上树和靶标等障碍;
  •  碰撞与计分:在射击位,射中靶标的相应分数,规则自定;
2、游戏规则

        每个射击位有5次射箭机会,只有在射击位上方才能射箭。当箭射在靶上时,靶心得6分,之后每向外一环得分减少一份,靶子有固定靶和运动靶。射箭时还会根据鼠标点击的时间长短来决定蓄力的大小,从而控制箭射出去的力量。

二、游戏实现

为了实现游戏要求,步骤如下:

1、地形

        在GameObject-3D Object-Terrain上创建地形,然后在Asset Store上下载合适的树资源包,在Unity中导入资源包之后将树和草预制对象放在创建的Terrain上,即可形成想要的地形。

2、天空盒

        为了实现随时间自动切换天空盒,在Asset Store上导入资源包后,在摄像机上添加组件SkyBox Materials,并将想要进行切换的天空盒添加在组件中,然后在使用脚本控制,可以实现没过5秒切换一次天空盒背景,代码如下:

public class changeskybox : MonoBehaviour
{
    public Material[] skyboxMaterials;
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(ChangeSkybox());
    }

    IEnumerator ChangeSkybox()
    {
        while (true)
        {
            // 随机选择一个天空盒子材质
            int index = Random.Range(0, skyboxMaterials.Length);
            RenderSettings.skybox = skyboxMaterials[index];

            // 等待一段时间后再切换天空盒子
            yield return new WaitForSeconds(5);
        }
    }
}
3、固定靶和运动靶

        可以先创建并生成一个靶子的对象,使用不同大小的Cylinder分别作为靶子的不同环,并在上面添加Mesh Collider作为碰撞器,同时添加脚本来为每一环来设置分数

public class TargetData : MonoBehaviour
{
    // 挂载到Target上的每一环,用来返回该环对应的分数。
    public int GetScore()
    {
        string name = this.gameObject.name;
        int score = 7 - (name[0] - '0');
        return score;
    }

}

        将创建的靶子作为预制,然后生成更多靶子。对于运动靶,需要先添加一个Animator,然后在Animation中设置靶子的运动轨迹就可以完成运动靶的设计,同时为了处理箭射中靶子之后的事件,还需要在每个靶子上添加一个触发的脚本。

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

public class TriggerController : MonoBehaviour
{
    int score = 0;
    public int scores = 0;
    void Start()
    {
        scoreController = Singleton<ScoreController>.Instance;
    }
    // 当有箭射中某一环后触发
    void OnCollisionEnter(Collision collider)
    {
        //得到箭
        GameObject arrow = collider.gameObject;
        Rigidbody rb = arrow.GetComponent<Rigidbody>();
        if (arrow == null)
        {
            return;
        }
        if (collider.gameObject.tag == "Arrow")
        {
            arrow.GetComponent<Rigidbody>().isKinematic = true;
            // 分数控制器
            score = this.gameObject.gameObject.GetComponent<TargetData>().GetScore();
            scores += score;
            Debug.Log(this.gameObject.name);
        }
    }
}
4、射击位

同样使用Cylinder来完成射击位的设计,然后需要设置每个射击位的射击次数,添加的脚本代码如下:

public class SpotController : MonoBehaviour
{
    public int shots;
    // Start is called before the first frame update
    void Start()
    {
        shots = 5;
    }
}
5、弩弓管理

在弩和箭上,需要实现的功能如下:

1、对弩弓是否到达射击位进行判断,并且完成射击次数的管理

2、支持蓄力半拉弓,鼠标点击时蓄力,在松开鼠标时箭释放,同时蓄力大小用Slider显示出来

3、防止弩弓被碰撞时飞走

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


public class CrossbowController : MonoBehaviour
{
    public float mouseSensitivity = 100.0f;
    //public Transform playerBody;
    float force;
    const float maxForce = 0.5f;  // 最大力量
    const float chargeRate = 0.1f; // 每0.3秒蓄力的量
    Animator animator;
    float mouseDownTime;
    bool isCharging;
    public Slider Powerslider;
    public int speed;
    public bool ready_to_shoot;
    private bool atSpot = false;
    public SpotController[] spots;
    private SpotController inspot;
    string message;
    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
        animator = GetComponent<Animator>();
        ready_to_shoot = false;
        inspot = null;
        message = "";
    }

    void Update()
    {
        foreach(SpotController s in spots)
        {
            // 获取两个物体在 X 和 Z 轴上的位置
            Vector2 position1 = new Vector2(s.gameObject.transform.position.x, s.gameObject.transform.position.z);
            Vector2 position2 = new Vector2(this.gameObject.transform.position.x, this.gameObject.transform.position.z);

            // 计算在 X 和 Z 轴上的距离
            float distance = Vector2.Distance(position1, position2);   
            if (distance<=0.5)//位于射击位上方
            {
                atSpot = true;
                inspot = s;
                if (s.shots > 0)
                {
                    ready_to_shoot = true;
                }
                else
                {
                    ready_to_shoot = false;
                }
                break;
            }
            else
            {
                atSpot = false;
                //shots = 0;
                inspot = null;
                ready_to_shoot = false;
            }
        }
        
        if (ready_to_shoot)
        {
            //按照鼠标按下的时间蓄力,每0.3秒蓄0.1的力(最多0.5)加到animator的power属性上,并用相应的力射箭
            if (Input.GetMouseButtonDown(0)) // 0表示鼠标左键
            {
                mouseDownTime = Time.time;  // 记录鼠标按下的时间
                isCharging = true;  // 开始蓄力
                Powerslider.gameObject.SetActive(true);
                animator.SetTrigger("pull");
            }

            if (isCharging)
            {
                float holdTime = Time.time - mouseDownTime; // 计算鼠标按下的时间
                force = Mathf.Min(holdTime / 0.3f * chargeRate, maxForce); // 计算蓄力的量,最大为0.5
                Powerslider.value = force / maxForce; // 更新力量条的值
                animator.SetFloat("power", force + 0.5f);
            }

            if (Input.GetMouseButtonUp(0) && isCharging)
            {
                isCharging = false;  // 停止蓄力
                animator.SetTrigger("hold");
                float holdTime = Time.time - mouseDownTime;  // 计算鼠标按下的时间
                force = Mathf.Min(holdTime / 0.3f * chargeRate, maxForce);  // 计算蓄力的量,最大为0.5
                animator.SetFloat("hold_power", force + 0.5f);  // 将蓄力的量加到animator的power属性上
                StartCoroutine(DelayedFireCoroutine(force));
                Powerslider.value = 0;
                animator.SetTrigger("shoot");
                Debug.Log("setrigger");

            }
        }
        else
        {
            return;
        }
    }

    IEnumerator DelayedFireCoroutine(float f)
    {
        Debug.Log("Ready to fire!!");
        yield return new WaitForSeconds(0f);
        fire(f);
        inspot.shots--;
    }

    public void fire(float f)
    {
        // Your existing fire code
        GameObject arrow = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Arrow"));
        ArrowController aw = arrow.AddComponent<ArrowController>();
        // 使用Find方法通过子对象的名字获取子对象
        Transform childTransform1 = transform.Find("弦");
        aw.transform.position = childTransform1.position;
        aw.transform.rotation = Quaternion.LookRotation(this.transform.forward);
        Rigidbody arrow_db = arrow.GetComponent<Rigidbody>();
        arrow.tag = "Arrow";
        arrow_db.AddForce(100 * f * this.transform.forward);

    }

    void OnCollisionEnter(Collision collider)
    {
        this.gameObject.GetComponent<Rigidbody>().isKinematic = true;
    }
    void OnCollisionExit(Collision collision)
    {
        this.gameObject.GetComponent<Rigidbody>().isKinematic = false;
    }
    void OnGUI()
    {
        GUIStyle style = new GUIStyle(GUI.skin.label);
        style.fontSize = 20; // Set the font size to 30
        if (atSpot)
        {
            // Draw the message with the new GUIStyle
            message = "您已到达射击位,剩余射击次数:" + inspot.shots;
        }
        else
        {
            message = "";
        }
        GUI.Label(new Rect(300, 350, 500, 100), message, style);
    }
}
6、游走        

        为了在鼠标移动的时候弩弓能跟着旋转,需要代码如下:

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

public class Rotate : MonoBehaviour
    private float rotationSpeed = 5f;
    public float maxRotationX = 60f; // 上下旋转的最大角度

    private float currentRotationX = 0f; // 当前上下旋转角度
    void Update()
    {
        FollowMouse();
    }
    void FollowMouse()
    {
        // 获取鼠标在水平和垂直方向的移动距离
        float mouseX = Input.GetAxis("Mouse X");
        float mouseY = Input.GetAxis("Mouse Y");

        // 根据鼠标移动距离计算旋转角度
        float rotationX = mouseY * rotationSpeed;
        float rotationY = mouseX * rotationSpeed;

        // 左右旋转围绕 Y 轴
        transform.Rotate(Vector3.up, rotationY, Space.World);
        // 计算上下旋转角度并限制范围
        currentRotationX -= rotationX;
        currentRotationX = Mathf.Clamp(currentRotationX, -maxRotationX, maxRotationX);
        // 应用上下旋转围绕局部 X 轴
        Quaternion targetRotation = Quaternion.Euler(currentRotationX, transform.localEulerAngles.y, transform.localEulerAngles.z);
        transform.localRotation = targetRotation;
    }
}

        为了能够使用键盘实现弩弓位置的改变,从而使弩弓能够到达射击位,代码如下:

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

public class Move : MonoBehaviour
{
    //public float speed = 1f;    // 允许设置速度
    public float moveSpeed = 3.0f;
    public float rotateSpeed = 90f;
    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        transform.localPosition = this.transform.position + this.transform.forward * z * Time.fixedDeltaTime+ this.transform.right * x * Time.fixedDeltaTime;
    }
}
7、碰撞与计分

        为了最后统计总得分,需要将所有靶子上的TriggerController中的得分加在一起,并在页面中显示出来,代码如下:

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

public class UserGUI : MonoBehaviour
{
    int totalScore;
    public TriggerController[] controller;
    // Start is called before the first frame update
    void Start()
    {
        totalScore = 0;
    }
    // Update is called once per frame
    void OnGUI()
    {
        int tScore = 0;
        foreach (var con in controller)
            tScore += con.scores;
        // Create a new GUIStyle
        GUIStyle style = new GUIStyle(GUI.skin.label);
        style.fontSize = 20; // Set the font size to 30
        // Draw the score label with the new GUIStyle
        GUI.Label(new Rect(10, 10, 200, 60), "Score: " + tScore, style);
        totalScore = tScore;
    }
}

三、游戏视频

四、代码地址

射击游戏 · 张菁/3D游戏编程与设计 - 码云 - 开源中国 (gitee.com)文章来源地址https://www.toymoban.com/news/detail-774897.html

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

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

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

相关文章

  • Unity-第一人称射箭游戏

    欢迎来到我们开发的第一人称射箭游戏!本游戏的设计目标是提供一种真实而又有趣的射箭体验。玩家可以在美丽的自然场景中自由移动,尝试不同的射箭技巧,挑战静态和动态的靶标,以获取高分。我们灵感来源于对射箭运动的热爱,希望通过这个游戏,让玩家感受到驽弓

    2024年02月03日
    浏览(40)
  • Unity大作业-第一人称射箭游戏

    视频地址:BILIBILI 代码地址:Gitee 本项目中使用了 Cross Bow 、 VegetationSpawner 、 Military Target 和 Fantacy Skybox F REE 资源包,均可在Asset Store免费下载。其中 Cross Bow 提供了弓和箭的预制, VegetationSpawner 提供了树的预制, Military Target 提供了靶子的预制, Fantacy Skybox F REE 提供了天空

    2024年02月04日
    浏览(43)
  • final-期末大作业-制作AR射箭小游戏(Unity AR配置详细教程)

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

    2024年02月06日
    浏览(52)
  • Unity 3D游戏开发+脚本编程完整指南:制作第一个游戏:3D滚球跑酷

    教程相关资源 Unity 3D游戏开发+脚本编程完整指南(工程文件+PPT).zip 本节利用前面的知识来实现第一个较为完整的小游戏,如 图 1-21 所示。 图1-21 3D滚球跑酷游戏完成效果 1. 功能点分析 游戏中的小球会以恒定速度向前移动,而玩家控制着小球 左右移动来躲避跑道中的黄色障

    2024年02月21日
    浏览(51)
  • Unity 3D脚本编程与游戏开发(2.8)

    5.1.2 矩形变换(Rect Transform)组件         如果选中界⾯上的控件,读者会发现每个物体并不带有基本的Transform组件,取⽽代之的是Rect Transform(矩形变换)组件。其实Rect Transform组件是Transform组件的⼦类,因此并不违反“每个物体必须有且只有⼀个Transform组件”的规定。

    2024年02月03日
    浏览(38)
  • Unity 3D脚本编程与游戏开发(3.4)

    6.2.3 动画的制作步骤         接下来为⾓⾊配上动画,整体思路分以下3个部分。⼀是准备好单个的动画素材,包含站⽴、跑和跳等动作。也就是说,把原始素材中的图⽚串联起来,形成⼏个单独的动画。⼆是⽤Animator把这些单独的动作有机地组合起来,形成⼀张状态转移

    2024年04月26日
    浏览(37)
  • Unity 3D脚本编程与游戏开发(2.2)

    3.2.7 修改物理材质         每个物体都有着不同的摩擦⼒。光滑的冰⾯摩擦⼒很⼩,⽽地毯表⾯的摩擦⼒则很⼤。另外每种材料也有着不同的弹性,橡⽪表⾯的弹性⼤,硬质地⾯的弹性⼩。在Unity中这些现象都符合⽇常的理念。         虽然从原理上讲,物体的摩擦⼒

    2024年02月04日
    浏览(41)
  • Unity 3D脚本编程与游戏开发(3.5)

    6.2.8 总结和拓展         本节利⽤Unity官⽅素材,以有限的篇幅解释了动画状态机的原理,以及动画制作中最基本但最重要的步骤。总的来看,⽬前的动画只做了4种状态——站⽴、⾛、跑和跳跃,还缺少下蹲、下蹲移动和落地缓冲等动作。好在这些动作只是对现有动作的

    2024年04月10日
    浏览(52)
  • Unity 3D脚本编程与游戏开发【3.8】

    6.4.5 动画层         图6-42显⽰了动画层设置窗⼝。在动画状态机⾥可以添加很多层,层之间可以是覆盖关系也可以是叠加关系,当然也可以随时屏蔽⼀些层、启⽤另⼀些层。 每⼀个动画层可以有单独的设置,其选项解释如下。 ①Weight(权重),本层对总体动画效果的影

    2024年04月16日
    浏览(48)
  • Unity 3D脚本编程与游戏开发【3.7】

            在这个⾓⾊控制脚本中,可以看到很多新奇的写法。关键是,为什么要把移动量转化为转⾝量和前进量呢?要理解这个问题,⼀定要多进⾏游戏测试,体会转⾝与输⼊的关系。         当⾓⾊⾯朝前,输⼊朝后时,⾓⾊的前进量为0,转⾝量达到最⼤;⽽当⾓⾊

    2024年04月15日
    浏览(40)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包