Unity大作业-第一人称射箭游戏

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

视频地址:BILIBILI
代码地址:Gitee

一、加载资源包

本项目中使用了Cross BowVegetationSpawnerMilitary TargetFantacy Skybox F REE资源包,均可在Asset Store免费下载。其中Cross Bow提供了弓和箭的预制,VegetationSpawner提供了树的预制,Military Target提供了靶子的预制,Fantacy Skybox F REE提供了天空盒和地形的预制。

二、定义人物

首先创建一个胶囊体作为我们的人物,将摄像头和弓的预制模型挂载在人物上,从而在第一人称视角能看到手持弓箭的场景。注意要调节摄像头的高度,使得视角在一个合适的位置。
Unity大作业-第一人称射箭游戏,游戏编程,unity,课程设计,游戏
Unity大作业-第一人称射箭游戏,游戏编程,unity,课程设计,游戏

三、人物的控制

首先为人物添加一个Character Controller
Unity大作业-第一人称射箭游戏,游戏编程,unity,课程设计,游戏

脚本MouseLook用于控制视角

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

public class MouseLook : MonoBehaviour
{
    // Start is called before the first frame update

    public float mouseSensitivity = 300f;

    public Transform playerBody;

    float xRotation = 0f;

    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
    }

    // Update is called once per frame
    void Update()
    {
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);// limit the angle

        // rotate the camera within Y axis
        transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
        // rotate the player within X axis
        playerBody.Rotate(Vector3.up * mouseX);
    }
}

脚本PlayMovement用以控制人物移动

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;

public class PlayerMovement : MonoBehaviour
{   
    public CharacterController controller;
    public float speed = 12f;
    private float gravity = 9.8f;
    // Start is called before the first frame update

    Vector3 move;
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {   
        
        if(controller.isGrounded){

        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        //Vector3 move = new Vector3(x, 0f, z);// × global movement, we dont want
        move = transform.right * x + transform.forward * z;// move along the local coordinates right and forward

        }
        move.y = move.y - gravity*Time.deltaTime;
        controller.Move(move * speed * Time.deltaTime);
    }
    
}

四、搭建地形

首先创建一个Terrain对象,在上面添加加载树的预制和草的预制,从而形成人物活动的主要区域
Unity大作业-第一人称射箭游戏,游戏编程,unity,课程设计,游戏
再将人物放入Terrain中,此时启动游戏就能以第一视角在地形中走动
Unity大作业-第一人称射箭游戏,游戏编程,unity,课程设计,游戏

五、设置箭的属性

设置箭飞出去的速度、销毁时间。当箭与靶子发生碰撞时,箭会成为靶子的子对象,并且在一定时间后自动销毁。当箭没有射中靶子时,会在一个更短的时间内销毁。

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

public class ArrowFeature : MonoBehaviour
{
    public Vector3 startPos;
    public Vector3 startDir;
    public Transform target;//collider transform
    public float speed;
    public float destoryTime;

    Rigidbody rb;

    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        destoryTime = 10f;
    }

    // Update is called once per frame
    void Update()
    {
        destoryTime -= Time.deltaTime;
        if (destoryTime < 0)
        {
            Destroy(this.transform.gameObject);
        }
    }
    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "target")
        {
            if (!rb.isKinematic)
            {
                rb.isKinematic = true;
                target = collision.gameObject.transform;
                transform.SetParent(target);
            }
            destoryTime = 5f;

        }

    }

}

六、设置靶子的属性

靶子在被箭射中后,会将总体的分数加一,同时在这个靶子的得分也会加一

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

public class TargetController : MonoBehaviour
{
    public int basepoint;//初始分数

    public float aniSpeed = 1f;//动画执行速度
    public int scores;//单个靶点的分数
    // Use this for initialization
    void Start()
    {   
        this.tag = "target";
       
        //初始分数
        scores= 0;
    }

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

    //打到靶子
    private void OnCollisionEnter(Collision collision)
    {

        if (collision.gameObject.tag == "Arrow")
        {
            
            scores += 1;
            //增加游戏总分数
            Singleton<UserGUI>.Instance.AddScore(1);
            
        }
    }

}

七、设置弓的控制器

弓按住左键能进行蓄力,蓄力过程播放动画。在蓄力完成后按下右键进行发射一支箭,箭的初始速度根据蓄力的程度来确定。

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

public class ShootController : MonoBehaviour
{
    float force;// 蓄力力量
    const float maxForce = 1f;  // 最大力量
    const float chargeRate = 0.1f; // 每0.3秒蓄力的量
    Animator animator;//弓动画控制
    float mouseDownTime;// 记录鼠标蓄力时间
    bool isCharging=false;//是否正在蓄力

    bool isFired=true; //是否已经将蓄力的箭发射
    public Slider Powerslider;//蓄力条
    public SpotController currentSpotController;

    public bool readyToShoot = false;//是否可以开始射击,通过检测是否进入射击位置来设置
    public int shootNum = 0;// 剩余设计次数

    // Start is called before the first frame update
    void Start()
    {
        animator = GetComponent<Animator>();
        animator.SetFloat("power", 1f);
    }

    // Update is called once per frame
    void Update()
    {
        if (!readyToShoot)
        {
            Powerslider.gameObject.SetActive(false);
            return;
        }

        //按照鼠标按下的时间蓄力,每0.3秒蓄0.1的力(最多0.5)加到animator的power属性上,并用相应的力射箭
        if (Input.GetMouseButtonDown(0) && isFired) // 0表示鼠标左键
        {   
            isFired = false;
            mouseDownTime = Time.time;  // 记录鼠标按下的时间
            isCharging = true;  // 开始蓄力
            Powerslider.gameObject.SetActive(true);//显示蓄力条
            animator.SetTrigger("start");
        }

        //根据蓄力程度更新弓的动画
        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);
        }

        //鼠标左键弹起,此时进入hold动画
        if(Input.GetMouseButtonUp(0))
        {
            animator.SetTrigger("hold");
            isCharging = false;
        }

        //按下鼠标右键,将弓箭发射出去
        if (Input.GetMouseButtonDown(1) && readyToShoot)
        {   
            isFired = true;
            //isCharging = false;  // 停止蓄力
            animator.SetTrigger("shoot");
            animator.SetFloat("power", force);  // 将蓄力的量加到animator的power属性上
            StartCoroutine(DelayedFireCoroutine(force));//延迟0.5s后射击
            Powerslider.value = 0;//清零蓄力条
            animator.SetFloat("power", 0f);

            //update shootNum
            shootNum--;
            currentSpotController.shootNum--;
            Singleton<UserGUI>.Instance.SetShootNum(shootNum);
            if (shootNum == 0)
            {
                readyToShoot = false;
            }
        }
    }

    //协程:开火
    IEnumerator DelayedFireCoroutine(float f)
    {
        yield return new WaitForSeconds(0.2f);//等待0.2s后
        fire(f);    
    }

    //射击,创建箭的对象并且给其赋予属性
    public void fire(float f)
    {
        GameObject arrow = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Arrow"));
        ArrowFeature arrowFeature = arrow.AddComponent<ArrowFeature>();
        // 使用Find方法通过子对象的名字获取arrow子对象
        Transform originArrowTransform = transform.Find("mark");
        
        arrow.transform.position = originArrowTransform.position;
        arrow.transform.rotation = transform.rotation;

        Rigidbody arrow_db = arrow.GetComponent<Rigidbody>();

        arrowFeature.startPos = arrowFeature.transform.position;
        arrow.tag = "Arrow";
        arrow_db.velocity = transform.forward * 100 * f;
    }
}

八、射击位置

一个射击位置对应着几个靶子

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

public class SpotController : MonoBehaviour
{
    public int shootNum;
    //该射击点位对应的靶
    public TargetController[] targetControllers;

    // Start is called before the first frame update
    void Start()
    {   
        this.tag = "spot";
        shootNum = 5;
    }

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

九、人与射击位置的检测

人在进入射击位置之后才能拉弓、射箭。并且读取射击位置对应的靶子的分数信息,显示在左上角。

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public ShootController CrossBow;// 弓对象
    private bool atSpot = false;// 是否到达射击点
    private SpotController spot;// 射击位controller
    private TargetController[] targetControllers;//target controller

    void Start()
    {
        CrossBow = GetComponentInChildren<ShootController>();

    }

    void Update()
    {
        //如果进入了射击位置
        if (atSpot)
        {   
            //屏幕左上角出现对应提示
            Singleton<UserGUI>.Instance.SetIsAtSpot(true);
            Singleton<UserGUI>.Instance.SetShootNum(spot.shootNum);
            if (targetControllers != null)
            {
                //获取这个射击位置对应靶子的分数信息
                int sumSpotScore = 0;
                foreach (TargetController targetController in targetControllers)
                {
                    sumSpotScore += targetController.scores;
                }
                Singleton<UserGUI>.Instance.SetSpotScore(sumSpotScore);
            }
        }
        else
        {
            Singleton<UserGUI>.Instance.SetIsAtSpot(false);
            Singleton<UserGUI>.Instance.SetShootNum(0);
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        // 与射击点位撞击

        if (collision.gameObject.tag == "spot")
        {
            
            spot = collision.gameObject.GetComponentInChildren<SpotController>();
            atSpot = true;

            if (spot.shootNum > 0)
            {
                CrossBow.GetComponentInChildren<ShootController>().readyToShoot = true;
                CrossBow.GetComponentInChildren<ShootController>().shootNum = spot.shootNum;
                CrossBow.GetComponentInChildren<ShootController>().currentSpotController = spot;
            }

            
            targetControllers = spot.targetControllers; 
            if (targetControllers != null)
            {
                int sumSpotScore = 0;
                foreach (TargetController targetController in targetControllers)
                {
                    sumSpotScore += targetController.scores;
                }
                Singleton<UserGUI>.Instance.SetSpotScore(sumSpotScore);
            }
        }

    }

    private void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.tag == "spot")
        {
            Debug.Log("collideExit with spot");
            CrossBow.GetComponentInChildren<ShootController>().readyToShoot = false;
            atSpot = false;
        }
    }

}


十、天空盒切换

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

public class SkyboxSwitcher : MonoBehaviour
{
    public Material[] skyboxMaterials; // 存储不同天空盒的材质
 
    private int currentSkyboxIndex = 0; // 当前天空盒的索引
 
 
 
    void Start()
 
    {
 
        RenderSettings.skybox = skyboxMaterials[currentSkyboxIndex]; // 初始设置天空盒
 
    }
 
 
 
    void Update()
 
    {
 
        // 检测按下 'P' 键
 
        if (Input.GetKeyDown(KeyCode.P))
 
        {
 
            // 切换到下一个天空盒
 
            SwitchSkybox();
 
        }
 
    }
 
 
 
    void SwitchSkybox()
 
    {
 
        // 增加索引,确保循环切换
 
        currentSkyboxIndex = (currentSkyboxIndex + 1) % skyboxMaterials.Length;
 
 
 
        // 设置新的天空盒材质
 
        RenderSettings.skybox = skyboxMaterials[currentSkyboxIndex];
 
    }

}

十一、提示的GUI

GUI包含了显示当前的分数、显示进入射击位置、显示当前射击位置的得分、显示准星。

Unity大作业-第一人称射箭游戏,游戏编程,unity,课程设计,游戏

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static UnityEngine.EventSystems.EventTrigger;

public enum GameStatus
{
    Playing,
    GameOver,
}

struct Status
{
    public int score;
    public string tip;
    public float tipShowTime;
    public bool atSpot;
    public int shootNum;
    public GameStatus gameStatus;
    public int spotScore;
}

public class UserGUI : MonoBehaviour
{
    private ISceneController currentSceneController;
    private GUIStyle playInfoStyle;
    private Status status;

    public int crosshairSize = 20;//准星线条长度
    public float zoomSpeed = 5f;//滚轮切换视野大小的速度
    public float minFOV = 20f;//最小视野宽
    public float maxFOV = 60f;//最大视野宽

    // Start is called before the first frame update
    void Start()
    {
        Init();
        currentSceneController = Director.GetInstance().CurrentSceneController;

        // set style
        playInfoStyle = new GUIStyle();
        playInfoStyle.normal.textColor = Color.black;
        playInfoStyle.fontSize= 25;

        // init status
        status.shootNum = 0;
        status.score = 0;
        status.tip = string.Empty;
        status.atSpot = false;
        status.gameStatus = GameStatus.Playing;
        status.spotScore = 0;
        status.tipShowTime = 0;
    }

    private void Init()
    {
      
    }

    // Update is called once per frame
    void Update()
    {
        status.tipShowTime -= Time.deltaTime;
    }

    private void OnGUI()
    {
        // show user page
        ShowPage();
    }

    public void SetGameState(GameStatus gameStatus)
    {
        status.gameStatus = gameStatus;
    }

    /*
     set property of status
     */

    public void SetScore(int score)
    {
        status.score = score;
    }

    public void SetSpotScore(int score)
    {
        status.spotScore = score;
    }

    public void AddScore(int score)
    {
        status.score+=score;
    }

    public void SetShootNum(int shootNum)
    {
        status.shootNum = shootNum;
    }
    
    public void SetIsAtSpot(bool isAtSpot)
    {
        status.atSpot = isAtSpot;
    }

    private void ShowPage()
    {
        switch (status.gameStatus)
        {
            case GameStatus.Playing:
                ShowPlayingPage();
                break;
            case GameStatus.GameOver:
                ShowGameoverPage();
                break;
        }
    }

    private void ShowGameoverPage()
    {
        GUI.Label(new Rect(Screen.width / 2 - 40, 60, 60, 100), "游戏结束!", playInfoStyle);
        
    }

    private void ShowPlayingPage()
    {
        
        GUI.Label(new Rect(10, 10, 60, 100), "正在游戏",playInfoStyle);

        if (status.atSpot)
        {
            // Draw the message with the new GUIStyle
            GUI.Label(new Rect(10, 50, 500, 100), "您已到达射击位,剩余射击次数:" + status.shootNum, playInfoStyle);
            GUI.Label(new Rect(10, 90, 500, 100), "您在该靶点的射击分数:" + status.spotScore, playInfoStyle);
        }
        GUI.Label(new Rect(10, 130, 500, 100), "游戏总分数:" + status.score, playInfoStyle);

        
        // show 准星
        float screenWidth = Screen.width;
        float screenHeight = Screen.height;
        float centerX = screenWidth / 2f;
        float centerY = screenHeight / 2f;
        // 设置准星颜色
        GUI.color = Color.red;
        // 绘制准星
        GUI.DrawTexture(new Rect(centerX - crosshairSize / 2f + 15f, centerY + 5f , crosshairSize, 2f), Texture2D.whiteTexture);
        GUI.DrawTexture(new Rect(centerX - 1f + 15f, centerY - crosshairSize / 2f + 5f, 2f, crosshairSize), Texture2D.whiteTexture);
        // 恢复GUI颜色设置
        GUI.color = Color.white;

    }

}



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

public interface ISceneController
{
    void LoadResources();
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;


public class Director : System.Object
{
    static Director _instance;
    // 关联场记实例
    public ISceneController CurrentSceneController { get; set; }
    // 获取当前的场记
    public static Director GetInstance()
    {
        if (_instance == null)
        {
            _instance = new Director();
        }
        return _instance;
    }

    public static void ReloadCurrentScene()
    {
        int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
        SceneManager.LoadScene(currentSceneIndex);
    }
}

十二、蓄力条

蓄力条使用Slider组件,挂载在摄像机上
Unity大作业-第一人称射箭游戏,游戏编程,unity,课程设计,游戏

十三、最终效果

Unity大作业-第一人称射箭游戏,游戏编程,unity,课程设计,游戏文章来源地址https://www.toymoban.com/news/detail-765604.html

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

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

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

相关文章

  • 基于C#+unity的2D跑酷闯关对战冒险游戏设计 课程报告+答辩PPT+源码

    目录 项目说明 1 1.1. 项目目标 1 1.2. 软硬件环境需求 2 1.3. 使用的关键技术 2 需求分析 2 2.1. 系统用例 2 2.2. 业务流程 3 概要设计 4 3.1. 功能模块设计 4 3.2. 核心类图 5 界面设计 5 选题— 2D跑酷闯关对战游戏 选题动机:因为本学期学习的语言主要是C#,而unity主要是与C#语言结合密

    2023年04月08日
    浏览(73)
  • 【0到1学习Unity脚本编程】第一人称视角的角色控制器

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 :【0到1】Unity脚本游戏开发宝典 将摄像机变为胶囊体的子物体,按住 ctrl +shift +F 调整视野。让他变成胶囊体的眼睛 判断要前进时按照哪个

    2024年02月05日
    浏览(32)
  • 【游戏开发实战】Unity手游第一人称视角,双摇杆控制,FPS射击游戏Demo(教程 | 含Demo工程源码)

    一、前言 嗨,大家好,我是新发。 有同学私信我,问我能不能写一篇Unity手游第一人称视角控制的教程, 那么,今天就来做个 Demo 吧~ 注: Demo 工程源码见文章末尾 最终效果如下: 二、实现方案 1、无主之地,第一人称视角 第一人称视角的游戏大家应该不陌生,比如《无主

    2023年04月08日
    浏览(36)
  • 基于C#开发五子棋游戏 大作业 课程设计源码

    基于C#开发五子棋游戏(大作业/课程设计) 开发环境:  Windows操作系统 开发工具: Microsoft Visual Studio 运行效果图:    基于C#开发五子棋游戏(大作业/课程设计) 开发环境:  Windows操作系统 开发工具:Microsoft Visual Studio 基于C#开发五子棋游戏(大作业/课程设计) 开发环境

    2024年02月04日
    浏览(32)
  • 【用unity实现100个游戏之18】从零开始制作一个类CSGO/CS2、CF第一人称FPS射击游戏——基础篇2(附项目源码)

    本节就先实现添加武器,一些射击基本功能实现。 这里我找了一个人的手臂和武器动画素材 https://sketchfab.com/3d-models/cz-scorpion-evo3-a1-ultimate-fps-animations-f2bdfac775344004ad38d0318f0664a4 将他拖入到为摄像机的子集,然后调整到合适位置即可 你会发现手臂有一部分没法正常显示,那是因

    2024年04月10日
    浏览(36)
  • 【用unity实现100个游戏之18】从零开始制作一个类CSGO/CS2、CF第一人称FPS射击游戏——基础篇4(附项目源码,完结)

    免责声明:因为文章附带 源码 ,所以我上锁了,整理不易,但是推荐大家自己手动跟敲代码理解更加深入

    2024年02月04日
    浏览(35)
  • Unity空间与运动(中山大学3D游戏作业3)

    代码仓库:https://github.com/linfn3/3d_game b站视频:https://www.bilibili.com/video/BV1YD4y1r7GR/?vd_source=6d44ed4eff5157be7cd6838983f17b44 物体运动的本质 unity中物体运动的本质是游戏对象的位置和状态变化。 三种方法实现抛物线运动 使用translate方法 将transfrom.position1加上改变向量 position加减实现

    2024年02月03日
    浏览(36)
  • 3D 游戏编程与设计:第3次作业

    姓名:韩宝欣 学号:20331013 代码仓库:https://gitee.com/sse_20331013/3d-game.git 1、简答并用程序验证【建议做】 游戏对象运动的本质是什么? 本质是游戏对象在游戏每一帧的渲染过程中Transform属性在发生变化。这里物体的Transform属性是指Position与Rotation两个属性。 请用三种方法以上

    2024年02月09日
    浏览(21)
  • unity期末作业-两个简单小游戏游戏-躲避障碍和跑酷(附下载链接和gif动态图演示)

    游戏角色为一个小人,天上不时会掉落障碍物,人物撞到了会掉生命值,人物可以左右移动跳跃来躲避,带游戏音效,比较简单!具体情况如下所示: 点我下载源文件和exe导出文件》》》》》》》 角色可以上下左右移动,J发射子弹k跳跃,只有在跳板上才可以跳跃,可以吃能

    2024年02月04日
    浏览(50)
  • Unity和C#游戏编程入门:创建迷宫小球游戏示例

    💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】 🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】 💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 当涉及到Unity和C#游戏编程入门时,以下是一些示例代码,可以帮助初学者更好地理

    2024年02月08日
    浏览(31)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包