OOP: preoccupazioni per la progettazione estensibile basata su interfacce

3

Introduzione al mio problema

Sto provando a progettare un videogioco molto semplice in cui ci sono diversi% di% giocatori (tutti ereditano da Animals ):

  • Animal
  • Cat
  • Dog

Esistono anche alcune azioni eseguibili (solo una per Rabbit ) che possono eseguire come:

  • Animal : fatto solo da Bite (se un animale viene morso, perderà una quantità di vita)
  • Dogs : fatto solo da Kick (se un animale viene calciato non sarà in grado di muoversi per X secondi)
  • Rabbits : fatto solo da Scratch (se un animale si graffia ridurrà il loro movimento di velocità di -50% per Y secondi)

Stavo pensando a un progetto che potrebbe essere estensibile in futuro: avere nuovi animali (o anche nuovi giocatori come alieni / piante / umani), azioni e persino essere in grado di assegnare casualmente un'azione a un giocatore.

La mia soluzione fino ad ora

Interfacce

Prima di tutto, ogni giocatore che vorrebbe giocare, deve implementare l'interfaccia Cats (In questo caso, Playable implementerebbe Animal ):

L'interfaccia riproducibile

interface Playable {
  move(distance: number): void,
  getPosition(): number,
  attack(): void,
  beingBitten(): void,
  beingKicked(): void,
  beingScratched(): void
}

Interfaccia esecutore

Inoltre, ho pensato di avere un'interfaccia chiamata Playable per ogni azione che un giocatore può eseguire su un altro giocatore:

interface Performer {
  perform(enemy: Playable): void
}

Implementazioni

In questo modo, l'implementazione Performer di Rabbit è simile alla seguente:

class Rabbit extends Animal {

  private action: Performer;

  // ... etc ... 

  public attack(enemy: Playable): void {
    action.perform(enemy);
  }

  // ... etc ... 

}

E l'azione performativa .attack() sarebbe simile a questa:

class Kick implements Performer {

  public perform(enemy: Playable): void {
    enemy.beingKicked();
  }

}

Le mie preoccupazioni

In termini di organizzazione ed essere più chiari, stavo pensando che avrei potuto rompere l'interfaccia Kick in tre:

L'interfaccia dell'attacker

Le azioni relative all'attacco andrebbero qui.

interface attack {       attacco (nemico: giocabile): vuoto     }

L'interfaccia Attackable

Le azioni relative all'essere attaccabili andrebbero qui.

interface Attackable {
  beingBitten(): void,
  beingKicked(): void,
  beingScratched(): void
}

L'interfaccia riproducibile

Le azioni relative alla possibilità di spostarsi andrebbero qui.

interface Playable extends Attacker, Attackable {
  move(distance: number): void,
  getPosition(): number
}

Non ho molta esperienza quando si tratta di OOP, quindi ogni volta che finisco per pensare troppo a qualcosa e progettare alternative diverse, ma faccio fatica a decidere quale dovrei scegliere.

Come vedi tutto questo? Ha senso scindere Playable in tre per rendere le cose più chiare?

    
posta charliebrownie 05.03.2017 - 17:48
fonte

2 risposte

1

Raccomando caldamente di astenermi da tutte le tecniche OOP, poiché non fanno un buon lavoro nel modellare il tipo di dati con cui in genere lavori in un gioco.

L'esempio più semplice è qualsiasi punto del tuo gioco in cui dovrai affrontare più di una manciata di "oggetti". Nella soluzione OOP, hai trasmesso l'idea di gestirne ciascuna come idea separata e separata che eredita e / o sovrascrive le proprietà l'una dall'altra. La realtà dei dati è che queste proprietà possono essere espresse come strutture di array e elaborate in modo più efficiente con le estensioni SIMD della tua CPU.

Guarda la presentazione da Mike Acton , architetto senior ai giochi di Insomniac per una spiegazione approfondita del design del gioco testato in battaglia.

Il blog di Casey Muratori su Mollyrocket "Working on the Witness, parte 11" e in avanti ha l'analisi di esperti di un veterano dello sviluppo del gioco sull'errore di provare ad applicare i principi OOP in un sistema di gioco ad alte prestazioni e offre un modo alternativo di pensando alla programmazione dei giochi. Vedi anche tutorial di streaming di Casey, Handmade Hero per una codifica dal vivo in tempo reale di un gioco completamente descritto da zero.

    
risposta data 06.03.2017 - 03:57
fonte
0

Non sono sicuro di quanto ti aiuti, ma la tua domanda mi ricorda questo video, che mi è rimasto in mente:

Composizione sull'ereditarietà

link

L'esempio è in JavaScript, che è molto malleabile, molte lingue non hanno questa flessibilità.

Mi sono appena reso conto che l'hai chiesto quasi un anno fa. Sono curioso su quale percorso hai scelto.

    
risposta data 20.01.2018 - 20:49
fonte