y4shiro / uma-card-deck-tools

uma-card-deck-tools.vercel.app
0 stars 0 forks source link

同一キャラのサポカの複数編成を制限する機能実装 #28

Closed y4shiro closed 2 years ago

y4shiro commented 2 years ago

概要

前提条件として、ウマ娘のサポートカードにはキャラクターが最低 1 人以上所属している 殆どのサポカはキャラクター 1 人所属だが、グループカードのみ複数人数が所属している

例: 玉剤に集いし者たち https://gametora.com/ja/umamusume/supports/30067-the-thrones-assemblage このカードのメインキャラはシンボリルドルフだが、カード所属キャラはシンボリルドルフ / トーカイテイオー / ツルマルツヨシの 3 人

サポートカードのデッキ編成では、同一キャラクターを複数枚組み込むことが出来ない制約がある 上で紹介した 玉座に集いし者たち をデッキに組み込んだ場合、カードに所属している3人の他カードをデッキに組むことが出来ない

この Issue では、同一キャラのサポカ編成を制限する機能を実装していく

ToDo

y4shiro commented 2 years ago

現在編成中のキャラ一覧を表す配列を生成

編成中カードを絞り込んで、そこから所属キャラの配列を生成した 正確には配列ではなく Set で、キャラ ID の重複を無くす目的で採用した

// src/features/Support/CardDeck/CardModal/index.tsx
const belongCharaIds = new Set(
  cards
    ?.filter((card) => selectedCards.includes(card.card_id)) // デッキ編成済中カードのみを filter で絞り込み
    .flatMap((card) => card.belong_charactor_ids) // カードに所属する charactor_id の配列を作成
    .sort(),
);
y4shiro commented 2 years ago

現在編成中のキャラ一覧を SelectableCard に Props で渡す

// src/features/Support/CardDeck/CardModal/index.tsx
              {cards.map((card, index) => (
                <GridItem key={index}>
                  <SelectableCard
                    card={card}
                    selectedCards={selectedCards}
                    belongCharaIds={belongCharaIds}
                    imgSize={imgSize}
                  />
                </GridItem>
              ))}
// src/features/Support/CardDeck/CardSlot/SelectableCard/index.tsx
type Props = {
  card: CardType;
  selectedCards: (number | null)[];
  belongCharaIds: Set<number>;
  imgSize: ImgSize;
};

const SelectableCard: React.FC<Props> = ({ card, imgSize, selectedCards, belongCharaIds }) => {
y4shiro commented 2 years ago

選択済みコンポーネントを別コンポーネントに分離

return 文で未選択と選択済みコンポーネントをそれぞれ定義していたが、コードが長くなるので分割した

const AlreadySelectedCard: React.FC<
  Pick<Props, 'card' | 'imgSize'> & { type: 'selected' | 'duplicate' }
> = ({ card, imgSize, type }) => {
  return (
    <Box position='relative'>
      <Box filter='auto' brightness='40%'>
        <Card card={card} imgSize={imgSize} />
      </Box>
      <Box
        position='absolute'
        top='-2%'
        right='0%'
        left='0%'
        margin='auto'
        px={{ base: '2px', md: '6px', lg: '8x' }}
        borderRadius='12px'
        textColor='white'
        background={type === 'selected' ? '#E4436B' : '#E6553E'}
      >
        {type === 'selected' ? (
          <Text fontSize={{ base: '12px', sm: '14px', md: '16px', lg: '20px' }} fontWeight='bold'>
            設定中
          </Text>
        ) : (
          <Text fontSize={{ base: '8px', sm: '12px', md: '16px', lg: '20px' }} fontWeight='bold'>
            !サポ重複
          </Text>
        )}
      </Box>
    </Box>
  );
};
y4shiro commented 2 years ago

編成中キャラカードでも、同じ CardSlot で選択している場合は重複判定から除外する

現在の判定条件だと、既にカードを編成済みの CardSlot から同じキャラの別カードへ変更しようとしても、 既に編成済みの判定が行われて選ぶことが出来ない

同じ CardSlot で表示しているものに限りこの重複判定から除外する

cardDeckSlice に belongCharaIds を追加

cardDeckSlice で編成中のキャラID 一覧である belongCharaIds を保つ必要がある なので state に新たな配列を定義した

// src/features/Support/CardDeck/cardDeckSlice.ts
const initialState: CardSlotType[] = [
  { slotId: 0, cardId: null, belongCharaIds: [] },
  { slotId: 1, cardId: null, belongCharaIds: [] },
  { slotId: 2, cardId: null, belongCharaIds: [] },
  { slotId: 3, cardId: null, belongCharaIds: [] },
  { slotId: 4, cardId: null, belongCharaIds: [] },
  { slotId: 5, cardId: null, belongCharaIds: [] },
];
export const cardDeckSlice = createSlice({
  name: 'cardDeck',
  initialState,
  reducers: {
    changeCard: (state, action: PayloadAction<CardSlotType>) => {
      const { slotId, cardId, belongCharaIds } = action.payload;
      state[slotId] = { slotId, cardId, belongCharaIds };
    },
    removeCard: (state, action: PayloadAction<{ slotId: SlotId }>) => {
      const { slotId } = action.payload;
      state[slotId] = { slotId, cardId: null, belongCharaIds: [] };
    },
  },
});

この変更に伴い、SelectableCard で changeCard を dispatch している箇所を修正した

SelectableCard にて、同じ CardSlot で選択しているカードについては重複判定から除外

  const alreadyDuplicateCard =
    !currentCardSlotCharaIds?.some((charaId) => charaId === card.charactor_id) &&
    belongCharaIds.has(card.charactor_id);
y4shiro commented 2 years ago

特定カードの重複判定がおかしい点を修正

グループサポカのようにカード 1 枚に複数人が所属している物の判定がおかしかったので修正

  const alreadyDuplicateCard =
    !card.belong_charactor_ids.some((charaId) => currentCardSlotCharaIds?.includes(charaId)) &&
    card.belong_charactor_ids.some((charaId) => belongCharaIds.has(charaId));
y4shiro commented 2 years ago

無事マージした