服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - Unity实现3D射箭小游戏

Unity实现3D射箭小游戏

2022-11-15 14:10lihan_96 C#

这篇文章主要为大家详细介绍了Unity实现3D射箭小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

Unity 小游戏:3D射箭,供大家参考,具体内容如下

前两周因为实训太忙,再加上自己对老师所讲的设计模式并不是很理解,所以就没有写博客。这次博客是记录3D射箭游戏的实现过程。

1. 准备资源

我是在网上找的弓与箭的资源,至于靶子,创建五个不同大小的同心圆柱体,如图所示:

Unity实现3D射箭小游戏

需要注意的是,五个圆柱体并不在同一个平面上,这样才能够看清每一环的颜色,并且在检测碰撞时不会出现各种问题。

另外,如果靶子放得离相机太近,就没有射箭的感觉了;离相机太远,好像又看不清靶子了,然后我试着把靶子MaterialShader改为 Sprites/Default ,这样靶子离相机远一点也能看得很清晰。

2. 布置场景

把弓箭作为Main Camera的子物体,这样我们可以在用鼠标控制镜头移动时,使弓箭一直指向屏幕中心,以达到第一人称控制器的效果。

Unity实现3D射箭小游戏

在此项目中,没有选择使用GUI来做UI界面,而是创建了一个Canvas,在这里面添加了一个Image用来显示弓箭的准心,以及四个Text来显示得分、风向、风力、提示等。

Unity实现3D射箭小游戏

3. 编辑脚本

游戏采用MVC架构,大部分功能是自己实现的,也有一小些函数是借鉴大神的。整体上感觉有很多缺陷,但是又不知道怎么修改才好,我也很无奈啊!°(°ˊДˋ°) °

下面是我的UML图:

Unity实现3D射箭小游戏

以下是完整代码:

SSDirector.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class SSDirector : System.Object {
 
    private static SSDirector _instance;
 
    public ISceneCotroller currentScenceCotroller {
        get;
        set;
    }
 
    public bool running {
        get;
        set;
    }
 
    public static SSDirector getInstance() {
        if (_instance == null) {
            _instance = new SSDirector ();
        }
        return _instance;
    }
}

ISceneCotroller.cs

?
1
2
3
4
5
6
7
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public interface ISceneCotroller {
    void LoadResources ();
}

IUserAction.cs

?
1
2
3
4
5
6
7
8
9
10
11
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public interface IUserAction {
    string getMyScore ();
    float getWind ();
    void Openbow ();
    void Draw ();
    void Shoot ();
}

ActionManager.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using System.Collections; 
using System.Collections.Generic; 
using UnityEngine;
 
public class ActionManager : MonoBehaviour {
 
    private float Force = 0f;
    private int maxPower = 2500;
    private float power;
    public Transform arrowSpawn;
    public Transform myArrow;
    public Transform bow;
 
    //播放拉弓动画
    public void Openbow () {
        bow.GetComponent<Animation>().Play("Draw");
        bow.GetComponent<Animation>()["Draw"].speed = 1;
        bow.GetComponent<Animation>()["Draw"].wrapMode = WrapMode.Once;
 
        arrowSpawn.GetComponent<MeshRenderer>().enabled = true;
 
        //重置 power 为 0
        power = 0;
    }
 
    //拉弓,从power为0到power为3000
    public void Draw () {
        if(power < maxPower) {
            power += maxPower * Time.deltaTime;
        }
    }
 
    //射箭
    public void Shoot () {
        float percent = bow.GetComponent<Animation>()["Draw"].time / bow.GetComponent<Animation>()["Draw"].length;
        float shootTime = 1 * percent;
 
        bow.GetComponent<Animation>().Play("Shoot");
        bow.GetComponent<Animation>()["Shoot"].speed = 1;
        bow.GetComponent<Animation>()["Shoot"].time = shootTime;
        bow.GetComponent<Animation>()["Shoot"].wrapMode = WrapMode.Once;
 
        arrowSpawn.GetComponent<MeshRenderer>().enabled = false;
        Transform arrow= Instantiate (myArrow, arrowSpawn.transform.position, transform.rotation);
        arrow.transform.GetComponent<Rigidbody>().AddForce(transform.forward * power);
 
        wind (arrow);
        Force = Random.Range (-100, 100);
    }
 
    //产生风
    private void wind(Transform arrow) {
        arrow.transform.GetComponent<Rigidbody> ().AddForce (new Vector3 (Force, 0, 0), ForceMode.Force);
    }
 
    //返回风
    public float getWindForce() {
        return Force;
    
}

ScoreRecorder.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System.Collections; 
using System.Collections.Generic; 
using UnityEngine;
 
public class ScoreRecorder : MonoBehaviour {
 
    private string Score = "0";
 
    //判断得分
    public void countScore(string type) {
        Score = type;
    }
 
    //返回分数
    public string getScore () {
        return Score;
    }
}

FirstScene.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class FirstScene : MonoBehaviour, ISceneCotroller, IUserAction {
 
    private ActionManager actionManager;
    private ScoreRecorder scoreRecorder;
 
    void Awake () {
        SSDirector director = SSDirector.getInstance ();
        director.currentScenceCotroller = this;
        director.currentScenceCotroller.LoadResources ();
        actionManager = (ActionManager)FindObjectOfType (typeof(ActionManager));
        scoreRecorder = (ScoreRecorder)FindObjectOfType (typeof(ScoreRecorder));
    }
 
    //加载预制物体靶子
    public void LoadResources () {
        Debug.Log ("loading...\n");
        GameObject target = Instantiate<GameObject> (
                                Resources.Load<GameObject> ("Prefabs/target"));
        target.name = "target";
    }
 
    //获得分数
    public string getMyScore () {
        return scoreRecorder.getScore ();
    }
 
    //获得风向和风力
    public float getWind () {
        return actionManager.getWindForce ();
    }
 
    //拉弓
    public void Openbow () {
        actionManager.Openbow ();
    }
 
    //蓄力
    public void Draw () {
        actionManager.Draw ();
    }
 
    //射箭
    public void Shoot () {
        actionManager.Shoot ();
    }
}

UserGUI.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class UserGUI : MonoBehaviour {
 
    private IUserAction userAction;
    private FirstScene scene;
    private Quaternion m_CharacterTargetRot;
 
    public Text Score;
    public Text WindDirection;
    public Text WindForce;
 
    // Use this for initialization
    void Start () {
        userAction = SSDirector.getInstance ().currentScenceCotroller as IUserAction;
    }
 
    void Awake () {
        m_CharacterTargetRot = transform.localRotation;
    }
 
    void Update () {
        //镜头跟随鼠标
        float xRot = Input.GetAxis ("Mouse X") * 3f;
        float yRot = Input.GetAxis ("Mouse Y") * -3f;
        m_CharacterTargetRot *= Quaternion.Euler (yRot, xRot, 0f);
        transform.localRotation = Quaternion.Slerp (transform.localRotation, m_CharacterTargetRot,
            5f * Time.deltaTime);
 
        //按空格键使弓箭瞄准靶心
        if (Input.GetKeyDown (KeyCode.Space)) {
            m_CharacterTargetRot = Quaternion.Euler (0f, 0f, 0f);
            transform.localRotation = Quaternion.Slerp (transform.localRotation, m_CharacterTargetRot,
                5f * Time.deltaTime);
        }
 
        //鼠标左键按下,开始拉弓
        if (Input.GetMouseButtonDown (0)) {
            userAction.Openbow ();
        }
 
        //鼠标左键按住不放,蓄力
        if (Input.GetMouseButton (0)) {
            userAction.Draw ();
        }
 
        //鼠标左键抬起。射箭
        if (Input.GetMouseButtonUp (0)) {
            userAction.Shoot ();
        }
 
        Score.text = "Score : " + userAction.getMyScore ();     //显示上一轮分数
        float force = userAction.getWind ();
        if (force < 0) {
            WindDirection.text = "Wind Direction : <---";       //显示风向
        } else if (force > 0) {
            WindDirection.text = "Wind Direction : --->";
        } else {
            WindDirection.text = "Wind Direction : No";
        }
        WindForce.text = "Wind Force : " + Mathf.Abs (userAction.getWind ()); //显示风力
    }
}

Arrow.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using UnityEngine;
using System.Collections;
 
public class Arrow : MonoBehaviour {
 
    private RaycastHit hit;
 
    void  Update (){
        //检测在移动的箭
        if(GetComponent<Rigidbody>().velocity.magnitude > 0.5f) {
            CheckForHit();
        } else {
            enabled = false;
        }
        if (transform.position.y < -5) {
            Destroy (this.gameObject);      //将掉出地面以下的箭销毁
        }
    }
 
    //检测是否碰撞
    void CheckForHit (){
        float myVelocity = GetComponent<Rigidbody>().velocity.magnitude;
        float raycastLength = myVelocity * 0.03f;
 
        if(Physics.Raycast(transform.position, transform.forward, out hit, raycastLength)) {
            GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;     //使箭停留在靶子上
            transform.position = hit.point;
            transform.parent = hit.transform;
            enabled = false;
        } else {
            Quaternion newRot = transform.rotation;
            newRot.SetLookRotation(GetComponent<Rigidbody>().velocity);
            transform.rotation = newRot;    //箭没中靶,则继续做抛物线运动
        }
    }
}

Target.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Target : MonoBehaviour {
 
    private ScoreRecorder scoreRecorder;
 
    public string score;    //对应靶环的分数
 
    public void Start() {
        scoreRecorder = (ScoreRecorder)FindObjectOfType (typeof(ScoreRecorder));
    }
 
    void OnTriggerEnter(Collider other) {
        if (other.gameObject.tag == "Arrow") {
            scoreRecorder.countScore (score);       //记录分数
        }
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/lihan_96/article/details/69055091

延伸 · 阅读

精彩推荐
  • C#C#语言MVC框架Aspose.Cells控件导出Excel表数据

    C#语言MVC框架Aspose.Cells控件导出Excel表数据

    这篇文章主要为大家详细介绍了C#语言MVC框架Aspose.Cells控件导出Excel表数据,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    筱筱脱脱9382022-03-06
  • C#再来说说我喜欢的 Dotnet 5.0 & C# 9

    再来说说我喜欢的 Dotnet 5.0 & C# 9

    语言方面,最主要的特性,是 Record。这是 C# 9 出来的一个新数据类型。没错,Record 是一个数据类型。...

    老王Plus11642021-09-29
  • C#C#简单爬虫案例分享

    C#简单爬虫案例分享

    这篇文章主要为大家分享了C#简单爬虫案例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Mask-male7082022-01-24
  • C#c# 进程之间的线程同步

    c# 进程之间的线程同步

    这篇文章主要介绍了c# 进程之间的线程同步,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下...

    一只独行的猿12062022-10-13
  • C#C#使用XmlDocument或XDocument创建xml文件

    C#使用XmlDocument或XDocument创建xml文件

    这篇文章主要为大家详细介绍了C#使用XmlDocument或XDocument创建xml文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    在代码的世界里游走12162022-03-02
  • C#详解C#批量插入数据到Sqlserver中的四种方式

    详解C#批量插入数据到Sqlserver中的四种方式

    本文主要讲解一下在Sqlserver中批量插入数据。文中大数据批量插入方式一和方式四尽量避免使用,而方式二和方式三都是非常高效的批量插入数据方式,需...

    邹琼俊7952021-12-14
  • C#C#中Override关键字和New关键字的用法详解

    C#中Override关键字和New关键字的用法详解

    这篇文章主要介绍了C#中Override关键字和New关键字的用法,需要的朋友可以参考下...

    C#教程网11392021-11-09
  • C#C#编程和Visual Studio使用技巧(上)

    C#编程和Visual Studio使用技巧(上)

    C#是一门伟大的编程语言,与C++和Java相比,它的语法更简单,相对来说更好入门。Visual Studio作为.Net平台上最重量级的IDE,也通过不断的更新为开发者带来...

    C#教程网9652021-10-29