diff --git a/front/components/editor/CourtPlayer.tsx b/front/components/editor/CourtPlayer.tsx
index 8f4f659..045d5d0 100644
--- a/front/components/editor/CourtPlayer.tsx
+++ b/front/components/editor/CourtPlayer.tsx
@@ -1,6 +1,5 @@
import {RefObject, useRef} from "react"
import "../../style/player.css"
-import RemoveIcon from "../../assets/icon/remove.svg?react"
import {BallPiece} from "./BallPiece"
import Draggable from "react-draggable"
import {PlayerPiece} from "./PlayerPiece"
@@ -69,11 +68,9 @@ export default function CourtPlayer({
if (e.key == "Delete") onRemove()
}}>
-
- {hasBall && (
onBallDrop(ballPiece.current!.getBoundingClientRect())}>
+ {hasBall && ( onBallDrop(ballPiece.current!.getBoundingClientRect())}
+ position={{x:0, y: 0}}>
diff --git a/front/tactic/Player.ts b/front/tactic/Player.ts
index 553b85e..a025daf 100644
--- a/front/tactic/Player.ts
+++ b/front/tactic/Player.ts
@@ -1,26 +1,26 @@
import { Team } from "./Team"
export interface Player {
- id: string
+ readonly id: string
/**
* the player's team
* */
- team: Team
+ readonly team: Team
/**
* 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)
*/
- bottomRatio: number
+ readonly bottomRatio: number
/**
* 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
}
diff --git a/front/views/Editor.tsx b/front/views/Editor.tsx
index 9032595..100b2d7 100644
--- a/front/views/Editor.tsx
+++ b/front/views/Editor.tsx
@@ -23,6 +23,7 @@ import SavingState, {
} from "../components/editor/SavingState"
import {CourtObject} from "../tactic/CourtObjects";
+import {Simulate} from "react-dom/test-utils";
const ERROR_STYLE: CSSProperties = {
@@ -126,11 +127,12 @@ function EditorView({
const [opponents, setOpponents] = useState(
getRackPlayers(Team.Opponents, content.players),
)
- const [objects, setObjects] = useState([{key: "ball"}])
+
+ const [objects, setObjects] = useState(isBallOnCourt(content) ? [] : [{key: "ball"}])
const courtDivContentRef = useRef(null)
-
+
const canDetach = (bounds: DOMRect) => {
const courtBounds = courtDivContentRef.current!.getBoundingClientRect()
@@ -143,6 +145,8 @@ function EditorView({
)
}
+
+
const onPieceDetach = (ref: HTMLDivElement, element: RackedPlayer) => {
const refBounds = ref.getBoundingClientRect()
const courtBounds = courtDivContentRef.current!.getBoundingClientRect()
@@ -167,7 +171,6 @@ function EditorView({
})
}
-
const onObjectDetach = (ref: HTMLDivElement, rackedObject: RackedCourtObject) => {
const refBounds = ref.getBoundingClientRect()
const courtBounds = courtDivContentRef.current!.getBoundingClientRect()
@@ -176,60 +179,110 @@ function EditorView({
let courtObject: CourtObject
-
switch (rackedObject.key) {
case "ball":
- courtObject = {
- type: "ball",
- rightRatio: x,
- bottomRatio: y
+ 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 = {
+ type: "ball",
+ rightRatio: x,
+ bottomRatio: y
+ }
}
break
+
default:
throw new Error("unknown court object ", rackedObject.key)
}
- setContent((content) =>
- ({
+ setContent((content) => {
+ return ({
...content,
objects: [
...content.objects,
courtObject,
]
})
- )
+ })
}
- const onBallDrop = (ballBounds: DOMRect) => {
- let ballAssigned = false
+ const getPlayerCollided = (bounds: DOMRect, players: Player[]): number | -1 => {
+ for (let i = 0; i < players.length; i++) {
+ const player = players[i]
+ const playerBounds = document.getElementById(player.id)!.getBoundingClientRect()
+ const doesOverlap = !(
+ bounds.top > playerBounds.bottom ||
+ bounds.right < playerBounds.left ||
+ bounds.bottom < playerBounds.top ||
+ bounds.left > playerBounds.right
+ )
+ if(doesOverlap) {
+ return i
+ }
+ }
+ return -1
+ }
- setContent(content => {
- const players = content.players.map(player => {
- if (ballAssigned) {
- return {...player, hasBall: false}
- }
- const playerBounds = document
- .getElementById(player.id)!
- .getBoundingClientRect()
- const doesOverlap = !(
- ballBounds.top > playerBounds.bottom ||
- ballBounds.right < playerBounds.left ||
- ballBounds.bottom < playerBounds.top ||
- ballBounds.left > playerBounds.right
- )
- if (doesOverlap) {
- ballAssigned = true
+
+ 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
+ }
- let objects = content.objects
- if (ballAssigned) {
- const ballPieceIdx = content.objects.findIndex(obj => obj.type === "ball")
- objects = objects.toSpliced(ballPieceIdx, 1)
- }
+ if(content.objects.findIndex(o => o.type == "ball") != -1) {
+ return
+ }
+
+ const courtBounds = courtDivContentRef.current!.getBoundingClientRect()
+ const {x, y} = calculateRatio(refBounds, courtBounds)
+ let courtObject: CourtObject
+
+ 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,
false,
),
+ objects: [
+ ...content.objects,
+ ]
}))
let setter
switch (player.team) {
@@ -333,7 +389,7 @@ function EditorView({
setter = setAllies
}
if (player.hasBall) {
- /// add an instance of RackedBall back to the rack (objects)
+ setObjects([{key: "ball"}])
}
setter((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) {
if (courtObject.key == "ball") {
return