boardgameio / boardgame.io

State Management and Multiplayer Networking for Turn-Based Games
https://boardgame.io
MIT License
10k stars 706 forks source link

turn based with a timer (maybe take into account in "phases") #54

Closed FateRiddle closed 6 years ago

FateRiddle commented 6 years ago

Not sure if games like roguelikes & stretagy-rpg are part of this library's target cases. If so, there are a key concept that made turn-based game a little bit real time: there is a universal timer, and every action takes time, which result in:

  1. an action may take less or more than "a standard turn", so
  2. player gets to his/her turn faster or take multiple actions if "speed" is high.

The basic model is: there's actually no concept of "a turn" but only your turn. For example, attacking takes you 3 seconds, then your next turn will be reached after 3 seconds. If nobody gets their turn by that time, you get to take another turn right after.

The way I think: you endTurn after every action, but which one is the next player depends a "timer". Notice you are working on "phases", so just pop this idea.

btw, I wrote a Chinese checkers, maybe it can help with showcase or demo. (but the winner condition seems not working, not sure if "vitory" is a feature beyond 0.14)

btw, can there be example for using boardgame.io with react-redux? Only the top level component receive G,moves,ctx as props. It is inevitable when project gets bigger, we'd love to get access to G,moves,ctx for every component.

nicolodavis commented 6 years ago

Hey @FateRiddle. Having a timer is out of scope for this project. It's primarily targeted at online boardgame implementations. I am planning to add some asynchronous play orders (players can take their turn at any time and the round ends after everyone is done), but this is still not timer based.

Your Chinese Checkers implementation looks really good! Happy to link to it from the project's README. Let's figure out why the victory condition is not working, though. Have you tried the Tic-Tac-Toe example that comes with this project? It also uses victory, and it works correctly. There is most likely a bug in your implementation of the winning condition.

vdfdev commented 6 years ago

@FateRiddle pretty cool game! Never heard about it before, so I can't help find bugs in the rules... But I looked at your code and found some spots that might be causing issues:

victory: (G, ctx) => { getWinner(G.zis) return ctx.currentPlayer }, In this part you are always returning ctx.currentPlayer as a winner, you probably want to return getWinner(G.zis) instead. This only works because you don't check for ctx.winner on your components and do not show any message in case ctx.winner is not null. You probably want to do this too.

FateRiddle commented 6 years ago

@Felizardo @nicolodavis I mean to

victory: (G, ctx) =>  { return getWinner(G.zis) },

And I tried console.log getWinner(G.zis), it gives the correct result. But if you enable debug in App.js, and then test

victory: (G, ctx) => { return ctx.currentPlayer },

it should return currentPlayer as winner, but in the debug panel, winner is always null.

Btw, the rule can be found in https://en.wikipedia.org/wiki/Chinese_checkers, and the game I build is a variation called "super chinese checkers" according to wiki(with the difference that a piece may hop over a non-adjacent piece).

nicolodavis commented 6 years ago

Ah, the bug is that you have victory inside the moves section:

moves: {
   victory: {...}
}

It should be like this:

{
  moves: {...},
  victory: {...},
}
nicolodavis commented 6 years ago

Also, about react-redux, I plan to add some sections to the docs about general recipes and patterns. I'll probably add it there.

FateRiddle commented 6 years ago

@nicolodavis Thanks. That's a lame mistake :sweat_smile:

Here's another problem, if I want to restart a game right away: I've updated my demo to position the pieces one move from victory(both side), for easy testing.

I want to implement "restart", so when game finds a winner, you can click restart to reset things back to initial state.

The problem is you can only reset G but not ctx. So info like winner,currentPlayer,turn will not change. Thus in my game, after reset, pieces can't be moved when there's already a winner, and the winner message will also not go away.

I can't think of a solution, any advice?

nicolodavis commented 6 years ago

There is a RESTORE action available in the Reducer store. You can probably use that to reset the state.

FateRiddle commented 6 years ago

@nicolodavis OK, I finally get it done in demo. But it feels so much like a hack(especially the part when you need to specify initial state with log/_id/_initial). Is there a better way?

// Board.js
import { connect } from 'react-redux'

...

<div onClick={this.props.restore} />

...

const mapStateToProps = (state,ownProps) => ownProps

const initialState =  {
  G:{
    activeZi: null,
    zis: [
      [0, 8, '0'],
      [-1, 7, '0'],
      [1, 7, '0'],
       ...
      [1, -5, '1'],
      [3, -5, '1'],
    ],
  },
  ctx:{
    turn: 0,
    currentPlayer: "0",
    numPlayers: 2,
    winner: null
  }
}

const mapDispatchToProps = (dispatch,ownProps) => ({
  restore: () => { 
    dispatch({
      type: 'RESTORE',
      state: {
        ...initialState,
        log:ownProps.log,
        _id:ownProps._id,
        _initial:ownProps._initial
      }
    })
  } 
})

const ConnectedBoard = connect(mapStateToProps, mapDispatchToProps)(Board)

export default ConnectedBoard