欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

3D游戏编程作业5:简易的鼠标打飞碟

程序员文章站 2022-07-13 08:34:48
...

简单的打飞碟游戏

设计结构

本次采用了MVC结构,在Driect.cs文件中定义了Direct,UserAction,ISceneController三个类,对于

MVC结构的作用是重要的:

代码如下;

Direct.cs

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

public class Direct : System.Object
{
    private static Direct instance;
    public ISceneController currentScene{get;set;}
    public static Direct getInstance(){
        if (instance==null)
            instance=new Direct();
        return instance;
    }

}

public interface ISceneController{
    
}
public interface UserAction{
    void getScore(int n);
    void getLost(int n);

}

Direct类用于管理当前的场记类,做一些传参(用instance指明了现在的场记),还有管理一些重要功能等。

ISceneController提供了每个场记必须要有的函数,这里是空的,ISceneController主要起一个标记作用,这样在其他物体的类里面,就可以通过Direct找到当前的Controller了。

UserAction规定了用户可能会发生的事情,在复杂的情况,可以一个场记,一个Action接口。这里的GetScore是玩家获得得分的事件,Getlost是玩家丢掉分数的事件(没打到飞碟)。

FirstController.cs

场记用于处理在该场景下的一切事务,包括资源的加载,物体的调度,事件的处理等。其他的许多物体类,也都收到FirstController类的管理。

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

public class FirstController : MonoBehaviour,ISceneController,UserAction
{
    // Start is called before the first frame update
    public GameObject[] terrain;
    public UFOController uc;
    public int score;
    public int lost;
    public yesyes[] yes;

    public GUIStyle style;

    public int round;



    void Start()
    {
        Direct.getInstance().currentScene=this;
        loadResources();
        Random.InitState((int)System.DateTime.Now.Ticks);
        uc.StartRound();
        score=0; lost=0;
        round=1;


    }

    // Update is called once per frame
    
    void Update()
    {
        if (round>=4) return;
        uc.UFOUpdate();

        if (uc.isOver()==1){
            round++;
            if (round>=4) 
                return;
            uc.setDifficulty(round);
            uc.StartRound();
        }  

    }

    void OnGUI(){
        if (round>=4){
            style.alignment=TextAnchor.MiddleCenter;
            style.normal.textColor=Color.black;
            style.fontSize=250;
            if (score>lost){
                GUI.Label(new Rect(0,0,Screen.width,Screen.height),"你赢了",style);
            }else{
                GUI.Label(new Rect(0,0,Screen.width,Screen.height),"你输了",style);
            }
        }

        style.alignment=TextAnchor.MiddleLeft;
        style.normal.textColor=Color.black;
        style.fontSize=40;
        GUI.Label(new Rect(0,Screen.height-100,Screen.width,100),"白 1 分      蓝 2 分      红 3 分"+"                                     Score : "+score.ToString()+"       Lost : "+lost.ToString()+"              Round "+round.ToString(),style);
    
        for(int i=1;i<=33;++i){
            if (yes[i].isOn==1){
                if (Time.time-yes[i].stime>=3){
                    yes[i].isOn=0;
                    continue;
                }
                else{
                    if (yes[i].color=="white") style.normal.textColor=Color.gray;
                    if (yes[i].color=="blue") style.normal.textColor=Color.blue;
                    if (yes[i].color=="red") style.normal.textColor=Color.red;

                    GUI.Label(new Rect(yes[i].x,yes[i].y,400,200),"YesYes",style);
                }
            }
        }

    }

    public void loadResources(){
        terrain=new GameObject[4];
        terrain[0]=Instantiate(Resources.Load<GameObject>("Terrain"),new Vector3(0,0,0),Quaternion.identity);
        terrain[1]=Instantiate(terrain[0],new Vector3(-1000,0,0),Quaternion.identity);
        terrain[2]=Instantiate(terrain[0],new Vector3(-1000,0,-1000),Quaternion.identity);
        terrain[3]=Instantiate(terrain[0],new Vector3(0,0,-1000),Quaternion.identity);

        uc=new UFOController();
        yes=new yesyes[34];
        for (int i=0;i<=33;++i){
            yes[i]=new yesyes();
        }
    }

    public void getScore(int n){
        score+=n;

        for (int i=1;i<=33;++i){
            if (yes[i].isOn==0){
                yes[i].isOn=1;
                yes[i].x=Input.mousePosition.x;
                yes[i].y=Screen.height-Input.mousePosition.y;
                yes[i].stime=Time.time;

                if (n==1) yes[i].color="white";
                if (n==2) yes[i].color="blue";
                if (n==3) yes[i].color="red";

                break;
            }
        }
    }

    public void getLost(int n){
        lost+=n;
    }


}


public class yesyes{
    public int isOn;
    public float x,y;
    public float stime;
    public string color;

    public yesyes(){
        isOn=0;
        x=-200;y=-200;
        stime=-100;
        color="white";
    }

    public void over(){
        isOn=0;
    }
}

在FirstController里面首先在Start中确立了自己和Direct类的关系。然后加载自己的资源。

在Update函数中调用UFOController类里的函数UFOUpdate,这个是下一个文件中的类。用于管理所有的UFO,减轻场记的代码负担和混乱度。在Update中还判断了游戏结束的条件。因为游戏分为3个round(关卡),随着round的提高,游戏的难度会变高。在Update函数中要处理这些变化。

FirstController还实现了接口UserAction的函数定义,获取或者失去得分。

说说下面这个yesyes类

作用:在鼠标点击飞碟后,我希望屏幕上能显示出一个与飞碟同颜色的“yesyes”字样来提醒打到了。

参数:记录了每一个yesyes字样的应有颜色,位置,以及是否应该被显示,开始显示的时间是什么。显示时间超过三秒,就不再显示了。这些都在OnGui函数中进行了判断。

效果
3D游戏编程作业5:简易的鼠标打飞碟
打掉的飞碟都变成了yesyes

斯卡文腐蚀+1

UFOController.cs

负责管理UFO的生成,移动,销毁,等所有事物。在此文件中还定义了有关UFO的其他类,记录UFO的信息或者管理UFO的点击事件。

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

public class UFOController :MonoBehaviour
{
    
    public GameObject white,blue,red;
    public UFO[] ufos;
   
    public int diff;

    public float stime;

    private float lastCreateTime;
    public void UFOUpdate(){
        int number=getNumber();
        
        if (Time.time-stime>=9.5f){
            
        }else{
            if (Time.time-lastCreateTime>=1){
                lastCreateTime=Time.time;

                for (int i=1;i<=diff;++i){
                    CreateUFO();
                }
            }
        }

        for(int i=1;i<=33;++i){
            if (ufos[i].obj!=null){
                ufos[i].obj.transform.position=Vector3.MoveTowards(ufos[i].obj.transform.position,ufos[i].target,ufos[i].speed);
                if (ufos[i].obj.transform.position==ufos[i].target || ufos[i].obj.transform.position.y<=4.5){
                    ufos[i].obj.GetComponent<UFOClass>().getOut();
                    number--;
                }
            }
        }
        
    }

    public void StartRound(){
        stime=Time.time;
    }

    public int isOver(){
        if (getNumber()==0 && Time.time-stime>=10){
            return 1;
        }
        return 0;
    }

    public UFOController(){
        white=Resources.Load<GameObject>("whiteUFO");
        blue=Resources.Load<GameObject>("blueUFO");
        red=Resources.Load<GameObject>("redUFO");

        ufos=new UFO[34];
        for (int i=0;i<34;++i){
            ufos[i]=new UFO();
        }
        diff=1;
        stime=-100;
        lastCreateTime=-100;
    }
    public void setDifficulty(int d){
        diff=d;
        
    }


    public int getNumber(){
        int ans=0;
        for (int i=1;i<=33;++i){
            if (ufos[i].obj!=null)
                ans++;
        }
        return ans;
    }

    public void CreateUFO(){
        UFO u=new UFO();
        for (int i=1;i<=33;++i){
            if (ufos[i].obj==null){
                u=ufos[i];
                break;
            }
        }


        u.init(diff);

        int kind;
        kind=Random.Range(0,100);
        if (kind<=33){
            u.obj=Instantiate(white,u.pos,Quaternion.identity);
            u.obj.name="white";
        }
        else if (kind<=66){
            u.obj=Instantiate(blue,u.pos,Quaternion.identity);
            u.obj.name="blue";
        }
        else{
            u.obj=Instantiate(red,u.pos,Quaternion.identity);
            u.obj.name="red";
        }

        u.obj.AddComponent(typeof(UFOClass));
    }
}

public class UFO {
    public float speed;
    public Vector3 target;
    public GameObject obj;
    public Vector3 pos;
   
    public UFO(){

    }

    public void init(int diff){
        Object.Destroy(obj);
        float y=Random.Range(60,120f);
        float x=150;
        if (Random.Range(0,2)==0){
            x=-x;
        }
        pos=new Vector3(x,y,80);

        x=-x;
        y=Random.Range(0f,70f);
        target=new Vector3(x,y,80);
        

        speed=Random.Range(0.04f,0.06f);
        speed=speed*diff;
    }
}


public class UFOClass:MonoBehaviour{
    private UserAction action;

    public UFOClass(){
        action=Direct.getInstance().currentScene as UserAction;
    }

    void OnMouseDown(){
        string s=gameObject.name;
        if (s=="white"){
            action.getScore(1);
        }
        if (s=="blue"){
            action.getScore(2);
        }
        if (s=="red"){
            action.getScore(3);
        }
        Destroy(gameObject);
        
    }

    public void getOut(){
        string s=gameObject.name;
        if (s=="white"){
            action.getLost(1);
        }
        if (s=="blue"){
            action.getLost(2);
        }
        if (s=="red"){
            action.getLost(3);
        }
        Destroy(gameObject);        
    }
}

按照我设计的算法,游戏中最多可能出现33个UFO,所以用一个33的数组就能存放下全部的内容。(不想用链表)

	public UFO[] ufos;

CreateUFO用于创建UFO,根据难度值,对UFO的速度进行调整。
StartRound用于重新开始一个回合
SetDifficulty用于设置难度,一般用在每个回合开始前。
getNumber统计当前UFO的个数。
isOver判断当前回合有没有结束。如果飞碟数为0,并且已经开始了一段时间(防止刚开始就结束),那么此回合就结束了。将有FirstController开启下一回合。
UFOUpdate在FirstController中的Update中被调用,两者的调用是同步进行的。UFOUpdate主要用于管理飞碟的移动,判断创建新飞碟的条件,并且判断飞碟出界或者到达目的地的条件,是这个类的核心。

下面的UFO和UFOClass两个类:

UFO类是为了记录每一个飞碟的信息,比如初始位置,速度,目的地等,还有一个obj作为指针指向飞碟的GameObject。内部inti函数会根据当前的难度进行重新构造,完成了资源的重新利用。

UFOClass主要用于AddComponent函数,给飞碟的GameObject加入组件。该组件用于处理点击事件。里面的action变量是利用MVC结构的特性,从而完成了对场记中玩家事件函数的调用。

代码部分至此介绍完毕。

成果

3D游戏编程作业5:简易的鼠标打飞碟

项目链接

代码链接

项目下载

项目使用方法

下载Asserts.zip解压,用我的Asserts覆盖你项目的Asserts。刷新你的项目,双击UFOScene,点击运行。

相关标签: 游戏 游戏开发