与游戏世界交互-作业与练习(5)

1、编写一个简单的鼠标打飞碟(Hit UFO)游戏

游戏内容要求:

1.游戏有 n 个 round,每个 round 都包括10 次 trial;
2.每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
3.每个 trial 的飞碟有随机性,总体难度随 round 上升;
4.鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。

游戏的要求:

  • 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的! 具体实现见参考资源 Singleton 模板类
  • 近可能使用前面 MVC 结构实现人机交互与游戏模型分离

设计过程

这次大部分的代码其实都可以沿用之前的,只需稍作修改就好。(那谁能想到被githubgank了呢
在这里插入图片描述
主要改动的有:IUserAction;FirstController;ClickAction;CCActionManager,以及新增的有关UFO的脚本。
IUserAction:很简单,删除几个没用的接口就好。

public interface IUserAction
{
	// void MoveBoat();
    // void MoveRole(RoleModel roleModel);
    void Restart();

    //void Check();
}

FirstController:FirstController涉及的改动较多,主要是UFO函数的调用,主体还是update,按轮次去产生或放出飞碟。(顺手就把轮次变化实现了,他真不值得再建一个文件

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

public class FirstController : MonoBehaviour, ISceneController, IUserAction {

	private bool isRuning;

	public UFOFactory ufoFactory;
	private int[] roundUFOs;
	private int score;
	private int round;
	private float sendTime;

	int sendCnt;
	// the first scripts
	void Awake () {
		SSDirector director = SSDirector.getInstance ();
		director.setFPS (60);
		director.currentSceneController = this;
		director.currentSceneController.LoadResources ();
		this.gameObject.AddComponent<UserGUI>();
        this.gameObject.AddComponent<CCActionManager>();
		ufoFactory=UFOFactory.getInstance();
		roundUFOs=new int[]{3,5,9,11,15};
		score=round=sendCnt=0;
		sendTime=0;
		sendCnt =0;
	}
	 
	// loading resources for the first scence
	public void LoadResources () {
		isRuning=true;
	}

	public void SendUFO(){
        GameObject ufo=ufoFactory.GetUFO(round);
        ufo.transform.position=new Vector3(-ufo.GetComponent<UFOData>().direction.x * 7, UnityEngine.Random.Range(0f, 8f), 0);
        ufo.SetActive(true);
        this.gameObject.GetComponent<CCActionManager>().Fly(ufo,ufo.GetComponent<UFOData>().speed,ufo.GetComponent<UFOData>().direction);
    }

	public bool GetIsRuning(){
		return isRuning;
	}

	public void JudgeCallback(bool isRuning,int score){
		this.score+=score;
        this.gameObject.GetComponent<UserGUI>().score=this.score;
        this.isRuning=isRuning;
    }

	public void Pause ()
	{
		throw new System.NotImplementedException ();
	}

	public void Resume ()
	{
		throw new System.NotImplementedException ();
	}

	#region IUserAction implementation
	public void Restart ()
	{
		isRuning=true;
		this.gameObject.GetComponent<UserGUI>().gameMessage="";
		this.gameObject.GetComponent<UserGUI>().score=0;
		score=round=sendCnt=0;
		sendTime=0;
		ufoFactory.FreeALL();
	}
	#endregion


	void Start () {

	}
	
	void Update () {

		
			sendTime+=Time.deltaTime;
			if(sendTime>2){
				sendTime=0;
				
				for(int i = 0; i < 5 && sendCnt < roundUFOs[round]; i++){
				  	sendCnt++;	
					SendUFO();
				}
				if(sendCnt == roundUFOs[round]&&round==roundUFOs.Length-1){
					isRuning=false;
					gameObject.GetComponent<UserGUI>().gameMessage = "Time Out!";
				}
				if(sendCnt == roundUFOs[round] && round < roundUFOs.Length - 1){
					sendCnt = 0;
                	round++;
				}
				
			
			}
			
	}

}

UFOFactory:涉及飞碟的生成与回收,它实现ClickAction的DealClick接口,在飞碟触发点击事件之后,它就会获得一定的分数。

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

public class UFOFactory : ClickAction
{
    private static UFOFactory _instance;

    public GameObject UFORed_Prefab;
    public GameObject UFOGreen_Prefab;
    public GameObject UFOBlue_Prefab;
    private List<UFOData> used;
    private List<UFOData> free;
    public FirstController controller;

    private UFOFactory(){
        used=new List<UFOData>();
        free=new List<UFOData>();
        UFORed_Prefab=GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("UFORed"), Vector3.zero, Quaternion.identity);
        UFOGreen_Prefab=GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("UFOGreen"), Vector3.zero, Quaternion.identity);
        UFOBlue_Prefab=GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("UFOBlue"), Vector3.zero, Quaternion.identity);
        UFORed_Prefab.SetActive(false);
        UFOGreen_Prefab.SetActive(false);
        UFOBlue_Prefab.SetActive(false);
        controller=SSDirector.getInstance().currentSceneController as FirstController;
    }

    public static UFOFactory getInstance() {
		if (_instance == null) {
			_instance = new UFOFactory();
		}
		return _instance;
	}

    public GameObject GetUFO(int round){
        GameObject ufo;
        if(free.Count>0){
            ufo=free[0].gameObject;
            free.Remove(free[0]);
        }
        else{
            float kind=UnityEngine.Random.Range(0f,round+1);
            if(kind<0.5f){
                ufo=GameObject.Instantiate<GameObject>(UFOBlue_Prefab, Vector3.zero, Quaternion.identity);
                ufo.AddComponent<UFOData>();
                ufo.AddComponent<BoxCollider>();
                ufo.AddComponent<Click>();
                ufo.GetComponent<UFOData>().score=1;
            }
            else if(kind<2.5f){
                ufo=GameObject.Instantiate<GameObject>(UFOGreen_Prefab, Vector3.zero, Quaternion.identity);
                ufo.AddComponent<UFOData>();
                ufo.AddComponent<BoxCollider>();
                ufo.AddComponent<Click>();
                ufo.GetComponent<UFOData>().score=2;
            }
            else{
                ufo=GameObject.Instantiate<GameObject>(UFORed_Prefab, Vector3.zero, Quaternion.identity);
                ufo.AddComponent<UFOData>();
                ufo.AddComponent<BoxCollider>();
                ufo.AddComponent<Click>();
                ufo.GetComponent<UFOData>().score=3;
            }
            ufo.GetComponent<Click>().setClickAction(this);
        }
        ufo.GetComponent<UFOData>().direction=new Vector3(UnityEngine.Random.Range(-2f,2f),1,0);
        float level=UnityEngine.Random.Range(0f,round);
        if(level<3){
            ufo.GetComponent<UFOData>().speed=2.0f+round/6;
        }
        else if(level<6){
            ufo.GetComponent<UFOData>().speed=4.0f+round/6;
        }
        else{
            ufo.GetComponent<UFOData>().speed=5.0f+round/6;
        }
        level=UnityEngine.Random.Range(0f,round);
        if(level<3){
            ufo.GetComponent<UFOData>().scale=3;
            ufo.GetComponent<BoxCollider>().size=new Vector3(3f,2f,3f);
        }
        else if(level<6){
            ufo.GetComponent<UFOData>().scale=2;
            ufo.GetComponent<BoxCollider>().size=new Vector3(4f,3f,4f);
        }
        else{
            ufo.GetComponent<UFOData>().scale=1;
            ufo.GetComponent<BoxCollider>().size=new Vector3(5f,4f,5f);
        }
        used.Add(ufo.GetComponent<UFOData>());
        return ufo;
    }

    public void FreeUFO(GameObject ufo){
        foreach(UFOData ufoData in used){
            if(ufoData.gameObject.GetInstanceID()==ufo.GetInstanceID()){
                ufo.SetActive(false);
                free.Add(ufoData);
                used.Remove(ufoData);
                break;
            }
        }
    }

    public void FreeALL(){
        foreach(UFOData ufoData in used){
            ufoData.gameObject.SetActive(false);
            free.Add(ufoData);
            used.Remove(ufoData);
        }
        used.Clear();
    }

    public void DealClick(GameObject ufo){
        controller.JudgeCallback(true,ufo.GetComponent<UFOData>().score+(int)ufo.GetComponent<UFOData>().speed-3+ufo.GetComponent<UFOData>().scale-1);
        FreeUFO(ufo);
    }
}

CCFlyAction:这个还是比较关键的部分,控制飞碟的飞行。(不想它白给或者拉高人的血压就多调调

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

public class CCFlyAction : SSAction
{
    float gravity;
    float speed;
    Vector3 direction;
    float time;

    public static CCFlyAction GetSSAction(Vector3 direction, float speed){
        CCFlyAction action = ScriptableObject.CreateInstance<CCFlyAction>();
        action.gravity = 9.8f;
        action.time = 0;
        action.speed = speed;
        action.direction = direction;
        return action;
    }

    public override void Start()
    {
        
    }

    public override void Update(){
        time+=Time.deltaTime;
        transform.Translate(Vector3.down*gravity*time*Time.deltaTime);
        transform.Translate(direction*speed*Time.deltaTime);
        if (this.transform.position.y<-8){
            this.destroy=true;
            this.enable=false;
            this.callback.SSActionEvent(this);
        }
    }
}

CCActionManager只是改改变量,实现好回调函数就差不多了。
最后,改动UserGUI,加个计分板。ok!
UserGUI:

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

public class UserGUI : MonoBehaviour {

	private IUserAction action;
	public string gameMessage;
	public int score;

	void Start () {
		action = SSDirector.getInstance ().currentSceneController as IUserAction;
		score=0;
	}

	void OnGUI() {  
		float width = Screen.width / 8;  
		float height = Screen.height / 13;

		//action.Check();
		GUIStyle style = new GUIStyle();
        style.normal.textColor = Color.red;
        style.fontSize = 30;
		GUIStyle style2 = new GUIStyle();
		style2.normal.textColor = Color.red;
		style2.fontSize = 50;
		GUI.Label(new Rect(340,200,50,200),gameMessage,style2);
		GUI.Label(new Rect(width*5, 0, width, height),"Your Score: ",style);
		GUI.Label(new Rect(width*7, 0, width, height),score.ToString(),style);
		if (GUI.Button(new Rect(0, 0, width, height), "Restart")) {  
			action.Restart();  
		} 

		string paused_title = SSDirector.getInstance ().Paused ? "Resume" : "Pause"; 
		if (GUI.Button(new Rect(width, 0, width, height), paused_title)) { 
			SSDirector.getInstance ().Paused = !SSDirector.getInstance ().Paused;
		} 
	}


}

效果展示视频

在这里插入图片描述
发现可以通过暂停作弊,加个暂停不接受点击应该就好了

2、编写一个简单的自定义 Component (选做)

在这里插入图片描述
用了4个圆柱体,合成飞碟四不像
在这里插入图片描述

  • 将UFOData挂上去就可以附属性了。
  • 当然通过GetComponent的方式也可以修改对相应的属性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值