Hai bisogno di aiuto nella progettazione di un gioco di carte

1

Mi sto insegnando a codificare di nuovo e ho pensato di scrivere un gioco di carte.

Ho bisogno di aiuto con il mio design del codice (sto usando C #)

Per cominciare, lo sto costruendo come applicazione per console, e più tardi lo estenderò in modo che funzioni come un'applicazione web.

La domanda che ho è se gli oggetti Player fanno parte degli oggetti del gioco? oppure gli oggetti Player (che sono essenzialmente client) interagiscono solo con l'oggetto di gioco attraverso le richieste.

Ad esempio se avessi un gioco base in cui dovevo distribuire 4 carte a 4 giocatori e il giocatore con la carta più alta vince. Se due persone ottengono lo stesso livello di carte alto, le carte vengono ridistribuite.

Se i giocatori (clienti) non fanno parte del gioco (server), allora qual è il responsabile del progetto per attivare l'evento e la regola per determinare la carta più alta e poi se ridurla.

I giocatori stessi possono solo essere consapevoli del proprio stato.

Le carte sono assegnate a un giocatore un attributo del giocatore o sono un attributo di un elenco di carte legate all'oggetto di gioco.

Cerca solo alcuni suggerimenti qui sull'approccio alla progettazione.

    
posta Tysondotnet 08.03.2017 - 23:55
fonte

5 risposte

4

whether the Player objects are part of the Game objects ? or do Player objects (which are essentially clients) only interact with the Game Object through requests.

Utilizzare qualsiasi approccio ti lascia con il codice più comprensibile e gestibile. Non dovresti preoccuparti se un giocatore è sul "client" o sul "server". È comune che un server abbia oggetti che rappresentano cose al di fuori del server, ad es. anche un'app web di base avrà un oggetto User .

Are the cards dealt to a player an attribute of the Player or are they an attribute of a List of Cards tied to the Game Object.

Un giocatore può avere un attributo con un tipo di Hand che è una raccolta, ad es.

class Hand
{
    List<Card> _list;
}

class Player
{
    Hand _currentHand;
}

Mantenendo Hand e Player separati, puoi compartimentare la logica per, diciamo, mantenendo il punteggio (che persiste tra le mani) e le carte di conteggio (ad esempio potresti avere un metodo Hand.IsStraightFlush() ).

    
risposta data 09.03.2017 - 00:16
fonte
2

Ci sono due concetti principali da capire

  1. Quando invii i dati via cavo, sono solo dati. nessun metodo o codice
  2. puoi avere più di un oggetto per rappresentare la stessa cosa

Quindi, quando il tuo oggetto di gioco comunica con un oggetto Player, ciò che accade è:

Game -> make new PlayerOnServer objects
Game -> call PlayerOnServer.DealCard(card)
PlayerOnServer -> send card data to client
PlayerOnClient -> receive card data and make a new Card object
PlayerOnClient -> call PlayerOnClient.DisplayCardOnScreen(card)

Quindi qui abbiamo due tipi di oggetti Player. Uno gira sul server e sa come inviare le carte al client e una gira sul client e sa come visualizzare le carte sullo schermo.

L'oggetto Card è solo una rappresentazione dei dati ed è condiviso tra i due programmi.

Potrebbe essere utile pensare a questo in modo non orientato agli oggetti.

Game -> write to client "5OfHearts"
Client -> listen on port Console.Write(incoming data)

il wrapping della scrittura sul client, l'ascolto sulla porta e la scrittura sullo schermo delle chiamate negli oggetti non modifica l'implementazione sottostante. lo nasconde semplicemente dagli strati superiori del codice

    
risposta data 09.03.2017 - 17:28
fonte
0

La tua domanda è abbastanza ampia. Alla fine stai cercando un'architettura fattibile per un tipo di gioco multiplayer basato su server-client. Una risposta completa richiederebbe di disegnare alcuni diagrammi e scrivere un codice scheletrico. Sono sicuro che ci sono alcuni esempi abbastanza dettagliati da qualche parte.

Tuttavia, c'è un aspetto particolare del design che dovresti considerare se la tua applicazione sarà un gioco multiplayer locale o distribuito o altro.

Sembra che tu stia per mescolare il modello e il controllo . Consiglio vivamente di separarli. Il modulo che contiene il modello per il gioco non dovrebbe avere alcuna conoscenza su server o client e così via. Le regole di un gioco di carte non dipendono dal fatto che l'architettura dell'applicazione di gioco sia distribuita o meno. In realtà, non dipendono nemmeno dal fatto che tu scriva un'applicazione per giocare al computer o per simulare il gioco o per altri scopi come tenere traccia e tenere il punteggio di una partita dal vivo.

Quindi, inizierei scrivendo per la prima volta un modello funzionante per il gioco di carte stesso. Fintanto che mantieni il modello separato, non dovrai più pensare a come implementerai un fantastico gioco multiplayer distribuito in seguito.

Il modello di un gioco di carte consiste di pochi elementi: un modello per le carte e possibili gettoni di gioco, un modello per lo stato di gioco e un modello per le regole. Dato che stiamo parlando di un gioco a turni, le regole del gioco riguardano principalmente la definizione di azioni legali e gli effetti che le azioni hanno sullo stato del gioco. Mi aspetto che il modello contenga classi come

  • Card (per le carte)
  • Deck (per un mazzo di carte)
  • GameState (aggregato per lo stato di gioco, preferibilmente serializzabile)
  • PlayerState (per mantenere lo stato di un giocatore, figlio di GameState)
  • TableState (per mantenere lo stato del tavolo da gioco se ce n'è uno; figlio di GameState)
  • Action (per azioni che un giocatore potrebbe prendere)

Il modello di regole dovrebbe consistere in metodi e classi che controllano quale tipo di Action s è disponibile in qualsiasi stato di un gioco e in che modo un Action scelto cambierebbe lo stato del gioco. Il modello di regole dovrebbe offrire metodi come:

  • List<Action> DetermineAvailableActions(GameState gameState)
  • GameState ResolveGameStateAfterAction(GameState initialGameState, Action action)

Un semplice modello di regole potrebbe consistere in una classe ( GameRules ) che implementa i metodi precedenti.

Se scegli di scrivere un GameState mutabile (che non consiglierei) la seconda firma del metodo sarebbe come

  • void ApplyAction(GameState gameState, Action action)

Il modello per il gioco dovrebbe essere assolutamente agnostico sul resto dell'applicazione, sull'ambiente e in particolare sull'interfaccia utente. Lo stesso modello dovrebbe funzionare per un'applicazione di gioco single player locale e per un'applicazione di gioco client-server multiplayer. Dovresti essere in grado di eseguire simulazioni di interi giochi dall'inizio alla fine usando solo il modello e un semplice ciclo di gioco, alcuni logging e un'implementazione minimamente semplice di un'IA o piuttosto un idiota artificiale che seleziona azioni casuali.

Dopo aver scritto e testato il modello stesso del gioco, puoi continuare a scrivere un controller di gioco. Il controller dovrebbe contenere il loop principale reale del gioco. Dovrebbe essere in grado di

  • prendi le impostazioni iniziali del gioco (numero di giocatori, tipi di giocatori, ecc.)
  • inizializza lo stato del gioco secondo le impostazioni date
  • controlla il flusso del gioco e la comunicazione tra i moduli
  • invia messaggi ai giocatori richiamando metodi di alcuni oggetti PlayerController
  • ascolta i messaggi inviati dai giocatori

I dettagli del controller dipendono dall'architettura dell'applicazione di gioco. Il controller dovrebbe conoscere tutti i moduli coinvolti. Tuttavia, se giochi bene le tue carte, puoi usare lo stesso controller per controllare un semplice gioco o simulazione locale e un gioco multiplayer distribuito.

Un ciclo di gioco semplificato potrebbe essere simile a questo:

while (!currentGameState.IsFinished()) {
    activePlayerController = playerControllers.Get(currentGameState.GetActivePlayerId());
    List<Action> availableActions = rules.DetermineAvailableActions(currentGameState);
    activePlayerController.SendPleaseChooseActionMessage(currentGameState, actions);
    Action chosenAction = ReceiveChosenAction();
    currentGameState = rules.ResolveGameStateAfterAction(currentGameState, chosenAction);
    gameStateHistory.Push(currentGameState);
    for (PlayerController c: playerControllers) {
          c.SendGameStateUpdatedMessage(currentGameState, chosenAction);
    }
}

Se non sei un programmatore esperto, ti suggerisco di provare prima a scrivere un semplice gioco locale. Basta mantenere separati il modello, il controller e l'interfaccia utente.

    
risposta data 10.03.2017 - 00:57
fonte
0

Dimentica il design all'avanguardia. Non hai l'esperienza per produrre un disegno utile e non hai requisiti chiari. Se hai avuto l'esperienza, non ti preoccuperai perché sapresti che il design all'avanguardia a livello di classe è una perdita di tempo. Crea un gioco semplice e implementalo nel modo più semplice possibile, iniziando con un singolo metodo in una singola classe. Man mano che il codice cresce, puoi iniziare a estrarre blocchi di codice in metodi separati. Man mano che il numero di metodi cresce, estrai metodi correlati in nuove classi. Non solo questo sarà più divertente, dato che hai quasi immediatamente codice di lavoro, ma la struttura della classe risultante sarà migliore.

    
risposta data 10.03.2017 - 04:01
fonte
0

Tornando alla tua domanda originale; Separerei completamente i giocatori dalla meccanica del gioco.

Il Gioco distribuirà carte a una raccolta di "Posti a sedere" a un tavolo. Quindi confronterà le Carte in ogni 'Posto', decidendo quale 'Posto' ha la mano migliore (o se è un pareggio). Questa è essenzialmente la meccanica del gioco.

Ogni 'Seat' può avere un giocatore collegato ad esso. Se non ha un giocatore collegato, il Gioco non distribuisce le carte a quel "Posto" (a meno che le tue regole non siano diversamente).

Questo ti consente di far uscire un giocatore dal gioco (abbandonare il "posto") e un altro parteciparlo nel nuovo posto "libero".

Le vincite / punti accumulati ecc. saranno trasferiti al "Posto" applicabile al momento in cui ha avuto la mano vincente.

Essenzialmente, il Gioco non si preoccupa dei Giocatori (i loro nomi, fiches, denaro, ecc.) se sono al Tavolo o fuori - si preoccupa solo di ciò che viene fornito ad un "Posto" al Tavolo.

Se il Gioco fornisce punti o gettoni ai vincitori, li fornisce al "Posto".

L'attaccamento / distacco di un giocatore in un "Posto" comporterebbe l'aggiunta di punti o chip al "Posto" per abilitare il gioco (dalla raccolta personale del Giocatore), o la rimozione (verso la raccolta personale del Giocatore) di qualsiasi cosa vinto al tavolo quando se ne vanno.

    
risposta data 28.03.2017 - 19:43
fonte

Leggi altre domande sui tag