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

0 of 13 lessons complete (0%)

App Development

The “Step” Use Case

DTOs

Add the following code to the Objective class:

/// <summary>
/// Increase objective completion status by one step. /// @param id : objective index to be stepped
/// </summary>
public struct StepRequest
{
public int id; }
public struct StepResponse
{
/// <summary>
/// The updated objective.
/// You can choose any custom presentation logic based on step and completion status values. 
/// </summary>
public ObjectivesModel objective; }

Controller

Here we will have to use the Observer Pattern to allow our subject classes involved in the objectives validation process to send a step message to our controller while keeping it as loosely coupled as possible. To do so, we will implement the following class diagram:

Source: Copyright © 2007 Jason S. McDonald – http://www.McDonaldLand.info

Note: you can get a full memento of all the different design patterns here.

We will simply adapt it so that the notification message sends an Objective type as a parameter so we can check in the controller if a corresponding objective is actually running and if so trigger the step use case.

Add the following code to the ObjectivesController class: public class ObjectivesController : MonoBehaviour, IObjectivesObserver {

public void step(int id)


{

Debug.Log(“Stepping objective ” + id);

var request = new Objectives.StepRequest();
 request.id = id;
 interactor.doStep(request);


}
 


// MARK: IObjectivesObserver
 


public void update(Objectives.ObjectiveTypes objectiveType)


{

//foreach objective in fetched list, we increment the

progress and trigger the Step use case if needed
 for (int id = 0; id <

interactor.fetchedObjectives.Length; id++)


{

if (interactor.fetchedObjectives[id].type ==

objectiveType)
 {


step(id);
 }


}
 }


}

Then create a BuzzerObjectiveSubject class and add the following code:

public interface IObjectivesSubject


{

void attach(IObjectivesObserver o);

void detach(IObjectivesObserver o);

void notify(Objectives.ObjectiveTypes objectiveType);


}

public class BuzzerObjectiveSubject : MonoBehaviour, IObjectivesSubject


{

//MARK: Variables


[SerializeField]


private ObjectivesController objectivesObserver = null;


private List<IObjectivesObserver> observers = new List<IObjectivesObserver>();



void OnEnable()


{

//you can specify the objective is observed for example

when the gameObject is enabled


attach(objectivesObserver);
 }



void OnDisable()


{

//you can specify the objective is not observed for

example }


when the gameObject is disabled
 detach(objectivesObserver);
 //MARK: Lifecycle


public void OnBuzzerHit(int index)


{

Objectives.ObjectiveTypes objectiveType;



{


switch (index)


case 0:

objectiveType = Objectives.ObjectiveTypes.Yellow;
 break;


case 1:
objectiveType = Objectives.ObjectiveTypes.Green;

break;
 default:


objectiveType = Objectives.ObjectiveTypes.Blue;


break; }

notify(objectiveType);


}

// MARK: IObjectivesSubject


public void attach(IObjectivesObserver o)


{
observers.Add(o);


 


}

public void detach(IObjectivesObserver o)


{

observers.Remove(o);


}
 


public void notify(Objectives.ObjectiveTypes objectiveType)


{

foreach (var o in observers)


{

o.update(objectiveType);


}
 }


}

Then map the 3 buzzer buttons respectively to BuzzerObjectiveSubject.OnBuzzerHit(0), BuzzerObjectiveSubject.OnBuzzerHit(1) and BuzzerObjectiveSubject.OnBuzzerHit(2) calls.

You can create as many similar objectives subjects as you want based on the above class, just ensure that :
1. You setup the objectivesObserver reference correctly in the inspector
2. You defined and selected the correct objective type in the notify function call

Interactor

Add the following code to the ObjectivesInteractor class:

public interface IObjectivesInteractor {
void doFetch(Objectives.FetchRequest request); void doFlush(Objectives.FlushRequest request); void doStep(Objectives.StepRequest request);
}
public void doStep(Objectives.StepRequest request)
{
var response = new Objectives.StepResponse();

if (fetchedObjectives[request.id].currentStep < fetchedObjectives[request.id].numberOfSteps)
{
fetchedObjectives[request.id].currentStep =
fetchedObjectives[request.id].currentStep + 1; }
ObjectivesWorker.Update(request.id, fetchedSet,
 fetchedObjectives[request.id].currentStep);

response.objective = fetchedObjectives[request.id];

//since we stepped data we fetch objectives again
var fetchRequest = new Objectives.FetchRequest(); fetchRequest.numberOfObjectives = numberOfObjectives; fetchRequest.set = fetchedSet;
doFetch(fetchRequest);

presenter.presentStep(response);
}

Presenter

Add the following code to the ObjectivesPresenter class:

public interface IObjectivesPresenter {
void presentFetch(Objectives.FetchResponse response); void presentFlush(Objectives.FlushResponse response); void presentStep(Objectives.StepResponse response);
}
public void presentStep(Objectives.StepResponse response)
{
if (response.objective.currentStep ==
response.objective.numberOfSteps) {
NotifierPresenter.Instance.PerformInstantaneousRequest(""+ response.objective.title + " : Done !");
} else {
NotifierPresenter.Instance.PerformInstantaneousRequest("" + response.objective.title + " (" + response.objective.currentStep + " / " + response.objective.numberOfSteps + ") ");
} }



fr_FRFrançais