3Dgame作业6:打飞碟修改版

简单的打飞碟游戏

设计结构

本次采用了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);

}

public interface PAction{
    void addGravity();
    
}

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

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

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

新加内容

PAction接口是新加的,用于物理引擎的操作。在飞碟的管理类中实现addGravity函数给飞碟施加恒定的重力。

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 FixedUpdate(){
        uc.UFOFixedUpdate();
      
    }

    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的函数定义,获取或者失去得分。

新加内容

FixedUpdate函数是新加的,用于物理引擎。FixUpdate函数会在每次运算物理引擎之前先进行运算。也就是在这个函数中,施加力或者改变速度等。可以和物理运算保持同步。

UFOController.cs

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

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

public class UFOController :MonoBehaviour,PAction
{
    
    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 UFOFixedUpdate(){
        addGravity();
    }

    public void addGravity(){
        for(int i=1;i<=33;++i){
            if (ufos[i].obj!=null){
                ufos[i].obj.GetComponent<Rigidbody>().AddForce(new Vector3(0,-10,0));
            }
        }
    }

    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");

        Rigidbody rb=new Rigidbody();

        white.AddComponent<Rigidbody>();
        white.GetComponent<Rigidbody>().detectCollisions=false;
        white.GetComponent<Rigidbody>().useGravity=false;
        white.GetComponent<Rigidbody>().mass=1;
        white.GetComponent<Rigidbody>().drag=0;
        white.GetComponent<Rigidbody>().angularDrag=10;

        blue.AddComponent<Rigidbody>();
        blue.GetComponent<Rigidbody>().detectCollisions=false;
        blue.GetComponent<Rigidbody>().useGravity=false;
        blue.GetComponent<Rigidbody>().mass=1;
        blue.GetComponent<Rigidbody>().drag=0;
        blue.GetComponent<Rigidbody>().angularDrag=10;

        red.AddComponent<Rigidbody>();
        red.GetComponent<Rigidbody>().detectCollisions=false;
        red.GetComponent<Rigidbody>().useGravity=false;
        red.GetComponent<Rigidbody>().mass=1;
        red.GetComponent<Rigidbody>().drag=0;
        red.GetComponent<Rigidbody>().angularDrag=10;

        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.initVelocity(diff);
        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(60f,120f);
        target=new Vector3(x,y,80);
        

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


    }

    public void initVelocity(int diff){
        Vector3 dir=target-pos;
        dir=dir/dir.magnitude;
        obj.GetComponent<Rigidbody>().velocity=dir*diff*50;
    }
}


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结构的特性,从而完成了对场记中玩家事件函数的调用。

代码部分至此介绍完毕。

新加物理引擎部分

UFOFixedUpdate函数。在每次FirstController执行FixedUpdate时,一起执行这里的UFOFixedUpdate函数。在这里主要进行给飞碟加重力的操作:

    public void UFOFixedUpdate(){
        addGravity();
    }
    public void addGravity(){
        for(int i=1;i<=33;++i){
            if (ufos[i].obj!=null){
                ufos[i].obj.GetComponent<Rigidbody>().AddForce(new Vector3(0,-10,0));
            }
        }
    }

另外,新加部分还有为每个飞碟添加刚体属性,并调配参数。

在构造函数里面。

        white.AddComponent<Rigidbody>();
        white.GetComponent<Rigidbody>().detectCollisions=false;
        white.GetComponent<Rigidbody>().useGravity=false;
        white.GetComponent<Rigidbody>().mass=1;
        white.GetComponent<Rigidbody>().drag=0;
        white.GetComponent<Rigidbody>().angularDrag=10;

        blue.AddComponent<Rigidbody>();
        blue.GetComponent<Rigidbody>().detectCollisions=false;
        blue.GetComponent<Rigidbody>().useGravity=false;
        blue.GetComponent<Rigidbody>().mass=1;
        blue.GetComponent<Rigidbody>().drag=0;
        blue.GetComponent<Rigidbody>().angularDrag=10;

        red.AddComponent<Rigidbody>();
        red.GetComponent<Rigidbody>().detectCollisions=false;
        red.GetComponent<Rigidbody>().useGravity=false;
        red.GetComponent<Rigidbody>().mass=1;
        red.GetComponent<Rigidbody>().drag=0;
        red.GetComponent<Rigidbody>().angularDrag=10;

成果

在这里插入图片描述

附加功能

说说下面这个yesyes类

位置: FirstController.cs里面。额外定义的一个类。

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

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

效果
在这里插入图片描述
打掉的飞碟都变成了yesyes

斯卡文腐蚀+1

项目链接

代码链接
项目下载

项目使用方法

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值