3d游戏作业2

3D游戏作业2

一.简答题

1.解释游戏对象(GameObjects)和资源(Assets)的区别与联系。

unity对资源和游戏对象的解释如下

资源:可以在游戏或项目中使用的任何媒体或数据。资源可能来自 Unity 外部创建的文件,例如 3D 模型、音频文件、图像。还可以在 Unity 中创建一些资源类型,例如 Animator Controller、混音器 (Audio Mixer) 或渲染纹理 (Render Texture)。

游戏对象:Unity 场景中的基础对象,可以表示角色、道具、风景、摄像机、路径点等。游戏对象的功能由附加到游戏对象的组件来定义。

从中我们可以总结出两者的区别和联系是:游戏对象是游戏里的独立单位,可以由多个资源构成,比如上述游戏对象里举例的风景就由3D模型,图像等资源构成。而资源可以说是构成游戏对象的模板,而且可以被多个游戏对象使用,比如游戏里的不同人物可能是在同一个3D模型上做修改所形成的。

2.下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)

资源的目录组织结构如下,其中一般包括字体,材料,模型,场景等文件夹,而各种资源就分类存在这些文件夹里

游戏对象树包含了当前场景中所有游戏对象,且是树状结构,即父节点会分出子节点,子节点又有新的子节点,层层构成了对象树。

3.编写一个代码,使用debug 语句来验证MonoBehaviour基本行为或事件触发的条件

  • 基本行为包括Awake() Start() Update() FixedUpdate() LateUpdate()

  • 常用事件包括OnGUI() OnDisable() OnEnable()

首先执行一遍代码

由图可以看出,Start()和Awake()和OnEnable()只执行了一次,而FixedUpdate(),Update(),LateUpdate(),OnGUI(),一直在执行,其中FixedUpdate()执行的次数较少,而Update()和LateUpdate()执行的次数较多,OnGUI()执行的次数最多。查询官网对相关事件的解释,可以知道这些行为和事件触发的条件。

start()awake():这两个行为有一些相似之处,容易混淆,比如他们都只调用一次且都在update()调用之前。但是他们却是不同的,awake()是在对象初始化后就立即调用,而start()只保证在update()之前调用,一般都在awake()之后调用,并且如果在awake()调用之后立即将enable设置为false,禁止update(),那么start()不会被调用。

OnEnable:在激活状态下(即awake()调用之后)对象启用后调用,与start()和awake()的区别是对象被取消激活并重新激活后,start()和awake()不会再次被调用,而OnEnable()会被再次调用。下图是重新激活后的显示。

 Update()LateUpdate():这两个基本行为都是每帧都调用,lateupdate()在update()完全执行完成之后调用,lateupdate() 的常见用途是跟随第三人称摄像机。如果在updape()内让角色移动和转向,可以在lateupdate()中执行所有摄像机移动和旋转计算。这样可以确保角色在摄像机跟踪其位置之前已完全移动。

OnGui():该函数每帧都会调用多次以响应GUI事件。

Fixedupdate():具有物理系统的频率,每个固定帧率帧调用该函数。

Ondisable():行为被禁用或处于非活动状态时,调用此函数。

4.查找脚本手册,了解 GameObject,Transform,Component对象

  • 分别翻译官方对三个对象的描述(description)

Gameobject:Base class for all entities in Unity Scenes.1

GameObject:unity界面中所有实体类的基类

Transform:Position, rotation and scale of an object.2

Transfrom:用于存放游戏物体的位置,旋转角度,缩放。

Component:Base class for everything attached to GameObjects.3

Component:附加到GameObjects的所有内容的基类。

  • 描述下图中table对象(实体)的属性、table的Transform的属性、table的部件

第一个勾选框表示该对象是否存在scene中,如果取消勾选在scene中该对象就会消失;右边的文本框是对象的名字,再右边是将对象设置为静态与否,如果打钩,对象就在游戏过程中不会移动。下边的tag可以设置是否给对象添加标签,layer可以给对象设置涂层,prefab是预制,可以给对象预制。overrides是覆盖。

 transform中有三个属性,Position是对象的位置,Rotation是旋转角度,Scale是对象的大小。

table的部件有如下四个。

 

资源预设(Prefabs)与对象克隆(Clone)

  • 预设(prefabs)有什么好处

    预制就是将一个通用的游戏对象设置为预制体,好处是能够以这个通用的游戏对象为类模板,在其基础上做一些修改和拓展,从而不断得到新的对象,能够节省许多重复创建对象和设置属性的时间,大大提升了工作效率。

  • 预设与对象克隆(clone or copy or Instantiate of Unity Object)关系?

    预设本身不需要有实例化的游戏对象,而克隆需要复制实例化的游戏对象。而且如果要集中修改通过将预设实例化创建出来的对象,只需要修改预设就能全都修改,方便批量修改。而如果要修改克隆出来的对象只能一个一个修改。

  • 制作table预制,写一段代码将table预制资源实例化成游戏对象

GameObject,Transform,Component对象三者的关系如下

二 计算器

运行效果:

代码如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
​
public class cccal : MonoBehaviour {
    public GUIStyle buttonstyle;
    string str="";
    void OnGUI(){
        //创建GUI
        GUI.Box(new Rect (Screen.width/2-100,Screen.height/2-160, 235, 50), str); 
        
        if (GUI.Button (new Rect (Screen.width/2-100,Screen.height/2-45,55,55), "1")) {
            str += "1";
        }
        if (GUI.Button (new Rect (Screen.width/2-40,Screen.height/2-45,55,55), "2")) {
            str += "2";
        }
        if (GUI.Button (new Rect (Screen.width/2+20,Screen.height/2-45,55,55), "3")) {
            str += "3";
        }
        if (GUI.Button (new Rect (Screen.width/2-100,Screen.height/2+10,55,55), "4")) {
            str += "4";
        }
        if (GUI.Button (new Rect (Screen.width/2-40,Screen.height/2+10,55,55), "5")) {
            str += "5";
        }
        if (GUI.Button (new Rect (Screen.width/2+20,Screen.height/2+10,55,55), "6")) {
            str += "6";
        }
        if (GUI.Button (new Rect (Screen.width/2-100,Screen.height/2+65,55,55), "7")) {
            str += "7";
        }
        if (GUI.Button (new Rect (Screen.width/2-40,Screen.height/2+65,55,55), "8")) {
            str += "8";
        }
        if (GUI.Button (new Rect (Screen.width/2+20,Screen.height/2+65,55,55), "9")) {
            str += "9";
        }
        if (GUI.Button (new Rect (Screen.width/2+80, Screen.height/2+10 , 55, 55), "C")) {
            str ="";
        }
        if (GUI.Button (new Rect (Screen.width/2-100,Screen.height/2+120,115,55), "0")) {
            str +="0";
        }
        if (GUI.Button (new Rect (Screen.width/2+20,Screen.height/2+120,55,55), ".")) {
            str +=".";
        }
        if (GUI.Button (new Rect (Screen.width/2-100,Screen.height/2-100,55,55), "+")) {
            str +="+";
        }
        if (GUI.Button (new Rect (Screen.width/2-40,Screen.height/2-100,55,55), "-")) {
            str +="-";
        }
        if (GUI.Button (new Rect (Screen.width/2+20,Screen.height/2-100,55,55), "x")) {
            str +="*";
        }
        if (GUI.Button (new Rect (Screen.width/2+80,Screen.height/2-100,55,55), "/")) {
            str +="/";
        }
        if (GUI.Button (new Rect (Screen.width/2+80, Screen.height/2-45 , 55, 55), "back")) {
            if (str.Length > 0)
                str = str.Remove(str.Length-1,1) ;
        }
        if (GUI.Button (new Rect (Screen.width/2+80,Screen.height/2+65,55,115), "=")) {
            mycocluator c = new mycocluator ();
            str = c.calculate(str);
        }
    }
    public class mycocluator{
        float[] num = new float[100];
        int top1 = -1;//用于记录num中使用到的个数
        Stack<double> num2=new Stack<double>();
        Stack<char> cal2=new Stack<char>();
        char[] cal = new char[100];
        int top2 = -1;//用于记录cal中使用到的个数
        bool flag=false;//用于标记第一个数字是否为负数
        public string calculate(string s) {
            int i = 0;
            if(i==0 && s[i]=='-')
            {
                flag=true;
                i++;
            }
            //先遍历一遍字符串,找出其中的计算符
            while (i < s.Length) {
                switch (s [i]) {
                case '+':
                    cal [top2 + 1] = '+'; 
                    top2++;
                    break;
                case '-':
                    cal [top2 + 1] = '-'; 
                    top2++;
                    break;
                case '*':
                    cal [top2 + 1] = '*'; 
                    top2++;
                    break;
                case '/':
                    cal [top2 + 1] = '/'; 
                    top2++;
                    break;
                }
                int j = 0;
                //用于记录当前遍历到的数字
                string tmpnum = "";
                //找出字符串中的数字
                
                while (((i+j) < s.Length) && (s [i + j] == '.' || (s [i + j] <= '9' && s [i + j] >= '0'))) {
                    tmpnum += s [i + j];
                    j++;
                }
                if (j != 0) {
                    float temp = float.Parse (tmpnum);
                    top1++;   
                    if(top1==0 && flag==true)
                    {
                        num [top1] = 0-temp;
                    }
                    else
                    {
                        num [top1] = temp;
                    }
                    i += j;
                } 
                else {
                    i++;
                }
            }
        //开始计算,如果遇到*或者/就先计算出乘积或商再入栈。
        int l=0;
        num2.Push(num[0]);
        for(int k=1;k<=top1;k++)
        {
            if(cal[l]=='*')
            {
                double tmp=num2.Peek();
                num2.Pop();
                double tmp2=num[k];
                
                num2.Push(tmp*tmp2);
            }
            if(cal[l]=='/')
            {
                double tmp=num2.Peek();
                num2.Pop();
                double tmp2=num[k];
                
                num2.Push(tmp/tmp2);
            }
            else if(cal[l]=='+'||cal[l]=='-')
            {
                cal2.Push(cal[l]);
                num2.Push(num[k]);
            }
            l++;
        }
        //由于栈是反向的,所以可能出现1-3-3被当成1-(3-3)的情况,所以将栈倒置
        ArrayList nnum=new ArrayList();
        ArrayList ccal=new ArrayList();
        while(num2.Count>0)
        {
            nnum.Add(num2.Peek());
            num2.Pop();
        }
        while(cal2.Count>0)
        {
            ccal.Add(cal2.Peek());
            cal2.Pop();
        }
        for(int k=0;k<nnum.Count;k++)
        {
            num2.Push((double)nnum[k]);
        }
        for(int k=0;k<ccal.Count;k++)
        {
            cal2.Push((char)ccal[k]);
         } 
         //对只剩下+和-的进行栈计算
        while(num2.Count>1)
        {
            double a=num2.Peek();
            num2.Pop();
            double b=num2.Peek();
            num2.Pop();
            char c=cal2.Peek();
            cal2.Pop();
            if(c=='+')
            {
                double d=a+b;
                num2.Push(d);
            }
            if(c=='-')
            {
                double d=a-b;
                num2.Push(d);
            }
        }
            flag=false;
            return num2.Peek().ToString();
        }
    }
​
​
    // Use this for initialization
    void Start () {
​
    }
​
    // Update is called once per frame
    void Update () {
​
    }
​
​
}
​
​

[1]  Unity - Scripting API: GameObject

[2]  Unity - Scripting API: Transform

[3]  Unity - Scripting API: Component

猜你喜欢

转载自blog.csdn.net/weixin_52801288/article/details/127164629