can put the ball on the court if we want

pull/77/head
Vivien DUFOUR 1 year ago
parent bfdde852f6
commit 0cd937cd3b

@ -1,6 +1,5 @@
import {RefObject, useRef} from "react" import {RefObject, useRef} from "react"
import "../../style/player.css" import "../../style/player.css"
import RemoveIcon from "../../assets/icon/remove.svg?react"
import {BallPiece} from "./BallPiece" import {BallPiece} from "./BallPiece"
import Draggable from "react-draggable" import Draggable from "react-draggable"
import {PlayerPiece} from "./PlayerPiece" import {PlayerPiece} from "./PlayerPiece"
@ -69,11 +68,9 @@ export default function CourtPlayer({
if (e.key == "Delete") onRemove() if (e.key == "Delete") onRemove()
}}> }}>
<div className="player-selection-tab"> <div className="player-selection-tab">
<RemoveIcon {hasBall && (<Draggable nodeRef={ballPiece}
className="player-selection-tab-remove" onStop={() => onBallDrop(ballPiece.current!.getBoundingClientRect())}
onClick={onRemove} position={{x:0, y: 0}}>
/>
{hasBall && (<Draggable nodeRef={ballPiece} onStop={() => onBallDrop(ballPiece.current!.getBoundingClientRect())}>
<div ref={ballPiece}> <div ref={ballPiece}>
<BallPiece /> <BallPiece />
</div> </div>

@ -1,26 +1,26 @@
import { Team } from "./Team" import { Team } from "./Team"
export interface Player { export interface Player {
id: string readonly id: string
/** /**
* the player's team * the player's team
* */ * */
team: Team readonly team: Team
/** /**
* player's role * player's role
* */ * */
role: string readonly role: string
/** /**
* Percentage of the player's position to the bottom (0 means top, 1 means bottom, 0.5 means middle) * Percentage of the player's position to the bottom (0 means top, 1 means bottom, 0.5 means middle)
*/ */
bottomRatio: number readonly bottomRatio: number
/** /**
* Percentage of the player's position to the right (0 means left, 1 means right, 0.5 means middle) * Percentage of the player's position to the right (0 means left, 1 means right, 0.5 means middle)
*/ */
rightRatio: number readonly rightRatio: number
hasBall: boolean readonly hasBall: boolean
} }

@ -23,6 +23,7 @@ import SavingState, {
} from "../components/editor/SavingState" } from "../components/editor/SavingState"
import {CourtObject} from "../tactic/CourtObjects"; import {CourtObject} from "../tactic/CourtObjects";
import {Simulate} from "react-dom/test-utils";
const ERROR_STYLE: CSSProperties = { const ERROR_STYLE: CSSProperties = {
@ -126,7 +127,8 @@ function EditorView({
const [opponents, setOpponents] = useState( const [opponents, setOpponents] = useState(
getRackPlayers(Team.Opponents, content.players), getRackPlayers(Team.Opponents, content.players),
) )
const [objects, setObjects] = useState<RackedCourtObject[]>([{key: "ball"}])
const [objects, setObjects] = useState<RackedCourtObject[]>(isBallOnCourt(content) ? [] : [{key: "ball"}])
const courtDivContentRef = useRef<HTMLDivElement>(null) const courtDivContentRef = useRef<HTMLDivElement>(null)
@ -143,6 +145,8 @@ function EditorView({
) )
} }
const onPieceDetach = (ref: HTMLDivElement, element: RackedPlayer) => { const onPieceDetach = (ref: HTMLDivElement, element: RackedPlayer) => {
const refBounds = ref.getBoundingClientRect() const refBounds = ref.getBoundingClientRect()
const courtBounds = courtDivContentRef.current!.getBoundingClientRect() const courtBounds = courtDivContentRef.current!.getBoundingClientRect()
@ -167,7 +171,6 @@ function EditorView({
}) })
} }
const onObjectDetach = (ref: HTMLDivElement, rackedObject: RackedCourtObject) => { const onObjectDetach = (ref: HTMLDivElement, rackedObject: RackedCourtObject) => {
const refBounds = ref.getBoundingClientRect() const refBounds = ref.getBoundingClientRect()
const courtBounds = courtDivContentRef.current!.getBoundingClientRect() const courtBounds = courtDivContentRef.current!.getBoundingClientRect()
@ -176,60 +179,110 @@ function EditorView({
let courtObject: CourtObject let courtObject: CourtObject
switch (rackedObject.key) { switch (rackedObject.key) {
case "ball": case "ball":
const ballObj = content.objects.findIndex(o => o.type == "ball")
const playerCollidedIdx = getPlayerCollided(refBounds, content.players)
if(playerCollidedIdx != -1) {
onBallDropOnPlayer(playerCollidedIdx)
setContent((content) => {
return{
...content,
objects : content.objects.toSpliced(ballObj, 1)
}
})
return
}
else {
courtObject = { courtObject = {
type: "ball", type: "ball",
rightRatio: x, rightRatio: x,
bottomRatio: y bottomRatio: y
} }
}
break break
default: default:
throw new Error("unknown court object ", rackedObject.key) throw new Error("unknown court object ", rackedObject.key)
} }
setContent((content) => setContent((content) => {
({ return ({
...content, ...content,
objects: [ objects: [
...content.objects, ...content.objects,
courtObject, courtObject,
] ]
}) })
) })
} }
const onBallDrop = (ballBounds: DOMRect) => { const getPlayerCollided = (bounds: DOMRect, players: Player[]): number | -1 => {
let ballAssigned = false for (let i = 0; i < players.length; i++) {
const player = players[i]
setContent(content => { const playerBounds = document.getElementById(player.id)!.getBoundingClientRect()
const players = content.players.map(player => {
if (ballAssigned) {
return {...player, hasBall: false}
}
const playerBounds = document
.getElementById(player.id)!
.getBoundingClientRect()
const doesOverlap = !( const doesOverlap = !(
ballBounds.top > playerBounds.bottom || bounds.top > playerBounds.bottom ||
ballBounds.right < playerBounds.left || bounds.right < playerBounds.left ||
ballBounds.bottom < playerBounds.top || bounds.bottom < playerBounds.top ||
ballBounds.left > playerBounds.right bounds.left > playerBounds.right
) )
if(doesOverlap) { if(doesOverlap) {
ballAssigned = true return i
}
}
return -1
}
const onBallDropOnPlayer = (playerCollidedIdx : number) => {
setContent((content) => {
const ballObj = content.objects.findIndex(o => o.type == "ball")
let player = content.players.at(playerCollidedIdx) as Player
return {
...content,
players: content.players.toSpliced(playerCollidedIdx, 1, {...player, hasBall: true}),
objects : content.objects.toSpliced(ballObj, 1)
}
})
}
const onBallDrop = (refBounds: DOMRect) => {
const playerCollidedIdx = getPlayerCollided(refBounds, content.players)
if(playerCollidedIdx != -1) {
setContent((content) => {
return {
...content,
players: content.players.map((player) => ({...player, hasBall: false})),
} }
return { ...player, hasBall: doesOverlap }
}) })
onBallDropOnPlayer(playerCollidedIdx)
return
}
if(content.objects.findIndex(o => o.type == "ball") != -1) {
return
}
let objects = content.objects const courtBounds = courtDivContentRef.current!.getBoundingClientRect()
if (ballAssigned) { const {x, y} = calculateRatio(refBounds, courtBounds)
const ballPieceIdx = content.objects.findIndex(obj => obj.type === "ball") let courtObject: CourtObject
objects = objects.toSpliced(ballPieceIdx, 1)
courtObject = {
type: "ball",
rightRatio: x,
bottomRatio: y
} }
return {...content, objects, players} setContent((content) => {
return {
...content,
players: content.players.map((player) => ({...player, hasBall: false})),
objects: [
...content.objects,
courtObject,
]
}
}) })
} }
@ -323,6 +376,9 @@ function EditorView({
player, player,
false, false,
), ),
objects: [
...content.objects,
]
})) }))
let setter let setter
switch (player.team) { switch (player.team) {
@ -333,7 +389,7 @@ function EditorView({
setter = setAllies setter = setAllies
} }
if (player.hasBall) { if (player.hasBall) {
/// add an instance of RackedBall back to the rack (objects) setObjects([{key: "ball"}])
} }
setter((players) => [ setter((players) => [
...players, ...players,
@ -352,6 +408,13 @@ function EditorView({
) )
} }
function isBallOnCourt(content : TacticContent) {
if(content.players.findIndex(p => p.hasBall) != -1) {
return true
}
return content.objects.findIndex(o => o.type == "ball") != -1
}
function renderCourtObject(courtObject: RackedCourtObject) { function renderCourtObject(courtObject: RackedCourtObject) {
if (courtObject.key == "ball") { if (courtObject.key == "ball") {
return <BallPiece/> return <BallPiece/>

Loading…
Cancel
Save