Maîtriser le développement d'application mobile Unity 3D: système d'objectifs modulaire

0 of 13 lessons complete (0%)

App Development

The “Fetch” Use Case

The first use case we will have to implement for our application is the Fetch achievements use case.
When some achievements progress popup has to be displayed to the user, the achievements progress must be fetched from some storage place (as your user can quit the application and open it back).

As we are considering a general application, the achievements progress and completion status can be displayed in various forms, popup, stars …


Adding the Use Case DTOs

– First, we design the related data structure or DTO (Data Transfer Object) which will help us providing data independence.


Note: Keep in mind that Clean Architecture relies on two key concepts : Data Independence and Class Independence.

Add the following inner struct to the Objectives struct we defined previously :

/// <summary>

/// Fetch Objectives list

/// </summary>

public struct FetchRequest
 {


public ObjectiveSet set;


public int numberOfObjectives;
 }


public struct FetchResponse


{

/// <summary>

/// Objectives Index

/// </summary>

public int currentIndex;

/// <summary>

/// Objectives to be done

/// </summary>

public ObjectivesModel[] objectives;


}

The fetch request allow the user to choose the set to be fetched and the number of objectives he wants to be fetched.

The response is sent from the interactor to the presenter.
It gives the computed index to the presenter to allow him to display the corresponding objectives title. It also provide the fetched objectives array or an empty array on case of failure.

Editing the Objectives Controller

The Objectives Controller is responsible for being the entry point of the different use cases triggering. It fires them when some user event is detected or on when some MonoBehaviour lifecycle event occurs.

Add the following code to the ObjectivesController class :

using UnityEngine;

using System.Collections;

using System.Collections.Generic;


public class ObjectivesController : MonoBehaviour
 {


public ObjectivesInteractor interactor { private get; set; }



private void OnEnable()


{

//entry point: fetch game wide objectives on enable so we can launch

animation if needed


fetchObjectives(Objectives.ObjectiveSet.Game, 3);
 }



public void fetchObjectives(Objectives.ObjectiveSet set, int

numberOfObjectives = 3)


{

var request = new Objectives.FetchRequest();
 request.set = set;

request.numberOfObjectives = numberOfObjectives;
 interactor.doFetch(request);


} }

Note: The important thing to note here is that we choose to fetch objectives

each time the attached GameObject is enabled, this is a design choice we rely on the fact that our popup is disabled and we need to update its data when the popup is presented and thus enabled.


As our controller is some kind of sensor handling user inputs and game engine events, it inherits from MonoBehaviour.


When the gameObject is enabled, we trigger the Fetch use case with general game objective set (we could have defined this as a property to choose the objective set to fetch). As our UI needs 3 objectives for a given group we ask for 3 objectives to be fetched.

Now lets define the most interesting part, our Interactor !


Editing the Objectives Interactor

Add the following code to the ObjectivesInteractor class :

public interface IObjectivesInteractor {
 void doFetch(Objectives.FetchRequest request); }

public class ObjectivesInteractor : IObjectivesInteractor


{

// MARK: Properties



public IObjectivesPresenter presenter { private get; set; }



private Objectives.ObjectiveSet fetchedSet;

public Objectives.ObjectivesModel[] fetchedObjectives;



private int numberOfObjectives = 3;



// MARK: IObjectivesInteractor



// MARK: Fetch



public void doFetch(Objectives.FetchRequest request)


{

var response = new Objectives.FetchResponse();



 


numberOfObjectives = request.numberOfObjectives;
 fetchedSet = request.set;


this.fetchedObjectives = ObjectivesWorker.Read(numberOfObjectives, fetchedSet);


response.objectives = this.fetchedObjectives;


response.currentIndex = ObjectivesWorker.ReadIndex(fetchedSet);

this.presenter.presentFetch(response); }

}

Editing the Objectives Presenter

Add the following code to the ObjectivesPresenter class :
 


public interface IObjectivesPresenter

{
void presentFetch(Objectives.FetchResponse response);

}

public class ObjectivesPresenter : MonoBehaviour, IObjectivesPresenter {



/// <summary>

/// Quest Names – Standard Name is used on Overflow.
 /// </summary>

private string[] QUEST_SET_NAMES =

{


“Quest 1 : \nThe Beginning !”,
 “Quest 2 : \nA Great Adventure !”,
 “Quest 3 : \nMastering my skills !”,
 “Quest 4 : \nNot the Best yet !”,
 “Quest 5 : \nKeeping focussed !”,
 “Quest 6 : \nThe Best Bomber !”,
 “Quest 7 : \nBomber Master !”,
 “Quest 8 : \nSo Good !”,

“Quest 9 : \nLooking for challenges”


} ;

private const string DEFAULT_QUEST_SET_NAME = “Quest :;Quêe :”;



// MARK: Fetch



public void presentFetch(Objectives.FetchResponse response)


{

Debug.Log(response.objectives.Length + ” Objectives Fetched !”);



var initializationScript = FindObjectOfType<ObjectivesInitialization>();
 var windowView = initializationScript.gameObjectivesTitle;



var pageIndex = response.currentIndex / response.objectives.Length;
 windowView.text = pageIndex < QUEST_SET_NAMES.Length ?


QUEST_SET_NAMES[pageIndex]
 : DEFAULT_QUEST_SET_NAME;



var objectivesViews = initializationScript.objectivesView; for (int i = 0; i < response.objectives.Length; i++)
{

objectivesViews[i].titleLabel.text = response.objectives[i].title;

objectivesViews[i].descriptionLabel.text = response.objectives[i].description;


objectivesViews[i].completionLabel.text = response.objectives[i].currentStep + ” / ” + response.objectives[i].numberOfSteps;

objectivesViews[i].rewardLabel.text = “” + response.objectives[i].reward;


objectivesViews[i].claimButton.interactable = response.objectives[i].currentStep == response.objectives[i].numberOfSteps && ! response.objectives[i].isRewardClaimed;


objectivesViews[i].starImage.sprite = response.objectives[i].currentStep == response.objectives[i].numberOfSteps ? initializationScript.starOn : initializationScript.starOff;


} }

fr_FRFrançais