3

I'm currently writing a game in swift and I'm trying to make use of protocols to define things such as Chapters and Levels etc.

So a chapter might have the following structure:

   protocol Chapter {
       var title:String {get}
       var levels:[Level] {get}
       var choices:[OptionSetType]
   }

Each Chapter is composed of multiple levels and each level can only be accessed if certain 'choices' have been met.

To accomplish this I will track those choices and use a bit mask to see if conditions have been met. However the choices can be different for each Chapter but I want to build my game mechanics so they don't have to worry about working out which Chapter the user is actually on.

The idea being that each level has a 'Points' value and I just work out if the Points value contains the relevant choices bit mask.

So for 'Level' I tried to define a protocol such as

   protocol Level {
    var text:String {get}
    var score:OptionSetType {get} // this is what determines if a level can be shown if the right chapter 'choices' have been set
   }

which gives an error of

 Protocol 'OptionSetType' can only be used as a generic constraint because it has Self or associated type requirements

Now each chapter will in theory have it's own set of options, but I'm wondering how I can make this generic enough so that I can almost code the engine around this, rather than coding to each specific chapter. Which is why I thought I'd create the protocols. The trouble is how can I do the bit masking work when I will need to define set OptionSetType values and can't say the properties will be of a type of OptionSetType. Hope that makes sense?

TommyBs
  • 9,354
  • 4
  • 34
  • 65

1 Answers1

1

[In Swift 3, OptionSetType is now OptionSet.] Your error occurs because OptionSet is a protocol and can't be used directly (it 'has Self or ... requirements).

Your design would likely benefit by creating abstractions for Choice and Score - just as you created an abstraction for Level. Then, if you choose to implement Score as an OptionSet, the 'self requirement' will be met. Like such:

struct Score : OptionSet { ... }
struct Choice : OptionSet { ... }

and then:

protocol Chapter {
  var title:String {get}
  var levels:[Level] {get}
  var choices:[Choice]
}

protocol Level {
  var text:String {get}
  var score:Score {get}
}
GoZoner
  • 67,920
  • 20
  • 95
  • 145
  • Will this work for the fact that choices should be different for each chapter? I'd have to declare all the options up front. Whereas it would be more like every chapter has choices but chapter 1 might have Chapter1Choices which implements Choice. So I know they all meet the same interface but the values would be different across each chapter. Well the names would be different but the values would all be bits e.g 1,2,4,8 etc – TommyBs Jul 22 '16 at 18:26
  • It may be that `OptionSet` is not a good choice as one normally adds a bunch of `static let` declarations for the options. If you can't enumerate them or if you can't find a set that applies to all Chapters, then maybe you need a different abstraction. – GoZoner Jul 22 '16 at 22:09
  • Hmmm, I think you're right, maybe i should just think of them as Boolean flags and specify them that way in a Dictionary. Then each level can specify what needs to be 'true'. Though it would have been nice to use the 'score' as an id so the player could 'jump around' the levels, but I guess I could achieve something similar by looping through all the options and checking what's set. Just would be a bit slower is all – TommyBs Jul 23 '16 at 02:18