Skip to content

Commit

Permalink
Refactor player icon jumping animation
Browse files Browse the repository at this point in the history
  • Loading branch information
maximvl committed Dec 15, 2024
1 parent dd99767 commit 26e56e7
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 174 deletions.
48 changes: 48 additions & 0 deletions src/pages/map/components/player/JumpingIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useEffect } from 'react'
import { animated, useSpring } from '@react-spring/web'

type Props = {
image: string
isJumping?: boolean
scale?: number
}

export default function JumpingIcon({ image, isJumping, scale }: Props) {
const [styles, api] = useSpring(() => ({
x: 0,
y: 0,
scale: 1.0,
config: { duration: 1000 },
}))

const scaleValue = scale || 1.0

useEffect(() => {
if (isJumping) {
api.start({
loop: true,
from: { x: 0, y: 0, scale: 1.0 },
to: [
{ x: 0, y: -10, scale: 0.8 },
{ x: 0, y: 0, scale: 1.0 },
],
config: { duration: 500 },
})
} else {
api.stop()
}
}, [isJumping])

return (
<animated.img
src={image}
style={{
...styles,
width: `${40 * scaleValue}px`,
verticalAlign: 'middle',
filter: 'drop-shadow(0px -1px 15px rgba(0,0,0,1.0))',
zIndex: 20,
}}
/>
)
}
146 changes: 37 additions & 109 deletions src/pages/map/components/player/PlayerIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,90 +1,14 @@
import { Box } from '@mui/material'
import { animated, useSpring } from '@react-spring/web'
import { useEffect, useRef, useState } from 'react'
import {
Color,
getPlayerColor,
MoveParams,
Player,
PlayerUrl,
} from 'utils/types'
import PlayerGreen from 'assets/map/PlayerGreen.webp'
import PlayerGreenLight from 'assets/map/PlayerGreenLight.webp'
import PlayerRed from 'assets/map/PlayerRed.webp'
import PlayerBlue from 'assets/map/PlayerBlue.webp'
import PlayerBlueLight from 'assets/map/PlayerBlueLight.webp'
import PlayerBlueDark from 'assets/map/PlayerBlueDark.webp'
import PlayerBrown from 'assets/map/PlayerBrown.webp'
import PlayerPink from 'assets/map/PlayerPink.webp'
import PlayerPinkLight from 'assets/map/PlayerPinkLight.webp'
import PlayerOrange from 'assets/map/PlayerOrange.webp'
import PlayerPurple from 'assets/map/PlayerPurple.webp'
import PlayerYellow from 'assets/map/PlayerYellow.webp'
import PlayerBiege from 'assets/map/PlayerBiege.webp'

import PlayerPurple2 from 'assets/map/PlayerPurple2.webp'
import PlayerPurpleMoving2 from 'assets/map/PlayerPurpleMoving2.gif'

import PlayerYellow2 from 'assets/map/PlayerYellow2.webp'

import PlayerYellow3 from 'assets/map/PlayerYellow3.webp'
import PlayerYellowMoving3 from 'assets/map/PlayerYellowMoving3.gif'

import PlayerBlueLight2 from 'assets/map/PlayerBlueLight2.webp'

import PlayerPurpleMoving from 'assets/map/PlayerPurpleMoving.gif'
import PlayerOrangeMoving from 'assets/map/PlayerOrangeMoving.gif'
import PlayerPinkMoving from 'assets/map/PlayerPinkMoving.gif'
import PlayerPinkLightMoving from 'assets/map/PlayerPinkLightMoving.gif'
import PlayerRedMoving from 'assets/map/PlayerRedMoving.gif'
import PlayerBlueMoving from 'assets/map/PlayerBlueMoving.gif'
import PlayerBlueLightMoving from 'assets/map/PlayerBlueLightMoving.gif'
import PlayerBlueDarkMoving from 'assets/map/PlayerBlueDarkMoving.gif'
import PlayerGreenMoving from 'assets/map/PlayerGreenMoving.gif'
import PlayerGreenLightMoving from 'assets/map/PlayerGreenLightMoving.gif'
import PlayerBrownMoving from 'assets/map/PlayerBrownMoving.gif'
import PlayerBiegeMoving from 'assets/map/PlayerBiegeMoving.gif'
import PlayerYellowMoving from 'assets/map/PlayerYellowMoving.gif'
import { useEffect, useState } from 'react'
import { Color, getPlayerColor, MoveParams, Player } from 'utils/types'

import { cellSize } from '../../types'
import PlayerPopup from './PlayerPopup'
import { getMapCellById, laddersByCell, snakesByCell } from '../utils'
import { playerDisplayName } from 'src/pages/player/components/utils'
import { isUndefined } from 'util'

const playerIcons: { [key in PlayerUrl]: string } = {
lasqa: PlayerBlue,
segall: PlayerGreen,
praden: PlayerBrown,
predan: PlayerBrown,
browjey: PlayerOrange,
uselessmouth: PlayerPink,
roadhouse: PlayerPurple2,
melharucos: PlayerBlueLight2,
maddyson: PlayerYellow3,
vovapain: PlayerRed,
timofey: PlayerGreenLight,
unclebjorn: PlayerPinkLight,
krabick: PlayerBlueDark,
keliq_q: PlayerBiege,
}

const playerMovingIcons: { [key in PlayerUrl]: string } = {
lasqa: PlayerBlueMoving,
segall: PlayerGreenMoving,
praden: PlayerBrownMoving,
predan: PlayerBrownMoving,
browjey: PlayerOrangeMoving,
uselessmouth: PlayerPinkMoving,
roadhouse: PlayerPurpleMoving2,
melharucos: PlayerBlueLightMoving,
maddyson: PlayerYellowMoving3,
vovapain: PlayerRedMoving,
timofey: PlayerGreenLightMoving,
unclebjorn: PlayerPinkLightMoving,
krabick: PlayerBlueDarkMoving,
keliq_q: PlayerBiegeMoving,
}
import JumpingIcon from './JumpingIcon'
import { getPlayerIcon } from './utils'

type Props = {
player: Player
Expand All @@ -109,7 +33,6 @@ export default function PlayerIcon({
const [popupOpen, setPopupOpen] = useState(false)
const [popupAnchor, setPopupAnchor] = useState<HTMLElement | null>(null)
const [container, setContainer] = useState<HTMLDivElement | null>(null)
const iconRef = useRef<HTMLImageElement>(null)

const [animationState, setAnimationState] = useState<
'start' | 'moving' | 'finish' | 'off'
Expand Down Expand Up @@ -173,8 +96,12 @@ export default function PlayerIcon({
: laddersByCell[player.map_position + moves]
const snake = snakesByCell[player.map_position + moves]

const animationsList: Array<{ x?: number; y?: number; duration?: number }> =
[]
const animationsList: Array<{
x?: number
y?: number
duration?: number
scale?: number
}> = []
if (player.map_position === 0) {
// console.log('moving to start', relativeX)
// move to beginning of start area
Expand All @@ -191,6 +118,7 @@ export default function PlayerIcon({

let currentX = animationsList[animationsList.length - 1]?.x || 0
let currentY = animationsList[animationsList.length - 1]?.y || 0
let halfTurn = 0
for (let i = 0; i < Math.abs(moves); i++) {
const nextCell = backward
? getMapCellById(player.map_position - i - 1)
Expand All @@ -207,15 +135,25 @@ export default function PlayerIcon({
switch (nextCell.direction) {
case 'right':
currentX += moveOffset
animationsList.push({ x: currentX })
animationsList.push({
x: currentX,
y: currentY,
})
break
case 'left':
currentX -= moveOffset
animationsList.push({ x: currentX })
animationsList.push({
x: currentX,
y: currentY,
})
break
case 'up':
currentY -= moveOffset
animationsList.push({ y: currentY })
animationsList.push({
y: currentY,
x: currentX,
scale: 1.0,
})
break
}
}
Expand Down Expand Up @@ -261,6 +199,7 @@ export default function PlayerIcon({
await next({
x: nextAnimation.x,
y: nextAnimation.y,
scale: nextAnimation.scale || 1,
config: {
// ...animationConfig,
duration: animationDuration || animationsList[i].duration || 1000,
Expand Down Expand Up @@ -346,6 +285,8 @@ export default function PlayerIcon({
return
}

setAnimationState('moving')

const mapContainerLeft = mapContainer.offsetLeft

const targetX = 392
Expand All @@ -363,7 +304,9 @@ export default function PlayerIcon({
api.start({
from: { x: 0, y: 0 },
to: async (next) => {
await next({ x: deltaX, y: deltaY, scale: 1.5 })
await next({ x: deltaX, y: deltaY })
},
onRest: () => {
onAnimationEnd({ player, moveParams: { steps: 1, skipLadders: false } })
},
config: { duration: 5000 },
Expand Down Expand Up @@ -417,8 +360,6 @@ export default function PlayerIcon({
const positionTop = originTop + relativeY
const positionLeft = originLeft + relativeX

const isStillAnimated = iconRef.current?.src.endsWith('gif')

let finalPositionTop = positionTop
let finalPositionLeft = positionLeft

Expand All @@ -427,7 +368,7 @@ export default function PlayerIcon({
finalPositionLeft = positionLeft - containerWidth / 2
}

if (isMoving || isStillAnimated) {
if (isMoving) {
// adjust height for animation
finalPositionTop = positionTop - 14
}
Expand All @@ -438,11 +379,8 @@ export default function PlayerIcon({
event.stopPropagation()
}

const onlineColor = player.is_online ? Color.green : Color.red
const playerColor = getPlayerColor(player.url_handle)
const playerIcon = isMoving
? playerMovingIcons[player.url_handle] || PlayerBlueLightMoving
: playerIcons[player.url_handle] || PlayerBlueLight
const playerIcon = getPlayerIcon(player.url_handle)

const hideAvatar =
playersOnSamePosition.length > 1 && player.map_position !== 0 && !isMoving
Expand Down Expand Up @@ -476,21 +414,11 @@ export default function PlayerIcon({
ref={updateContiner}
>
{!hideAvatar && (
<img
ref={iconRef}
src={playerIcon}
width={'40px'}
alt=""
style={{
verticalAlign: 'middle',
// boxShadow: 'inset 0px 0px 30px 10px rgba(0, 0, 0, 0.4)',
// boxShadow: `0px 0px 20px 10px rgba(0, 0, 0, 0.8)`,
filter: 'drop-shadow(0px -1px 15px rgba(0,0,0,1.0))',
// boxShadow: '0px 20px 20px rgba(0, 0, 0, 0.5)',
// border: '5px solid white',
borderRadius: '5px',
zIndex: 20,
}}
<JumpingIcon
image={playerIcon}
isJumping={
animationState === 'moving' || animationState === 'start'
}
/>
)}
<p style={{ padding: 0, margin: 0, lineHeight: 1 }}>
Expand Down
73 changes: 8 additions & 65 deletions src/pages/map/components/player/PlayerWinnerIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,10 @@
import { Box } from '@mui/material'
import { animated, useSpring } from '@react-spring/web'
import { useEffect, useRef, useState } from 'react'
import { useEffect, useState } from 'react'
import { Color, getPlayerColor, Player } from 'utils/types'
import PlayerGreen from 'assets/map/PlayerGreen.webp'
import PlayerGreenLight from 'assets/map/PlayerGreenLight.webp'
import PlayerRed from 'assets/map/PlayerRed.webp'
import PlayerBlue from 'assets/map/PlayerBlue.webp'
import PlayerBlueLight from 'assets/map/PlayerBlueLight.webp'
import PlayerBlueDark from 'assets/map/PlayerBlueDark.webp'
import PlayerBrown from 'assets/map/PlayerBrown.webp'
import PlayerPink from 'assets/map/PlayerPink.webp'
import PlayerPinkLight from 'assets/map/PlayerPinkLight.webp'
import PlayerOrange from 'assets/map/PlayerOrange.webp'
import PlayerPurple from 'assets/map/PlayerPurple.webp'

import PlayerPurpleMoving from 'assets/map/PlayerPurpleMoving.gif'
import PlayerOrangeMoving from 'assets/map/PlayerOrangeMoving.gif'
import PlayerPinkMoving from 'assets/map/PlayerPinkMoving.gif'
import PlayerPinkLightMoving from 'assets/map/PlayerPinkLightMoving.gif'
import PlayerRedMoving from 'assets/map/PlayerRedMoving.gif'
import PlayerBlueMoving from 'assets/map/PlayerBlueMoving.gif'
import PlayerBlueLightMoving from 'assets/map/PlayerBlueLightMoving.gif'
import PlayerBlueDarkMoving from 'assets/map/PlayerBlueDarkMoving.gif'
import PlayerGreenMoving from 'assets/map/PlayerGreenMoving.gif'
import PlayerGreenLightMoving from 'assets/map/PlayerGreenLightMoving.gif'
import PlayerBrownMoving from 'assets/map/PlayerBrownMoving.gif'

import { cellSize } from '../../types'
import PlayerPopup from './PlayerPopup'
import { getMapCellById, laddersByCell, snakesByCell } from '../utils'

const playerIcons: { [key: string]: string } = {
lasqa: PlayerBlue,
praden: PlayerBrown,
predan: PlayerBrown,
roadhouse: PlayerPurple,
segall: PlayerOrange,
artur: PlayerRed,
uselessmouth: PlayerPink,
unclobjorn: PlayerBlueDark,
melharucos: PlayerBlueLight,
browjey: PlayerGreen,
f1ashko: PlayerPinkLight,
}

const playerMovingIcons: { [key: string]: string } = {
lasqa: PlayerBlueMoving,
praden: PlayerBrownMoving,
predan: PlayerBrownMoving,
roadhouse: PlayerPurpleMoving,
segall: PlayerOrangeMoving,
artur: PlayerRedMoving,
uselessmouth: PlayerPinkMoving,
unclobjorn: PlayerBlueDarkMoving,
melharucos: PlayerBlueLightMoving,
browjey: PlayerGreenMoving,
f1ashko: PlayerPinkLightMoving,
}
import JumpingIcon from './JumpingIcon'
import { getPlayerIcon } from './utils'

type Props = {
player: Player
Expand All @@ -73,7 +21,6 @@ export default function PlayerWinnerIcon({
}: Props) {
const [popupOpen, setPopupOpen] = useState(false)
const [popupAnchor, setPopupAnchor] = useState<HTMLElement | null>(null)
const iconRef = useRef<HTMLImageElement>(null)
const [container, setContainer] = useState<HTMLDivElement | null>(null)

useEffect(() => {
Expand Down Expand Up @@ -116,9 +63,7 @@ export default function PlayerWinnerIcon({

const onlineColor = player.is_online ? Color.green : Color.red
const playerColor = getPlayerColor(player.url_handle)
const playerIcon = isMoving
? playerMovingIcons[player.url_handle] || PlayerBlueLightMoving
: playerIcons[player.url_handle] || PlayerBlueLight
const playerIcon = getPlayerIcon(player.url_handle)

return (
<Box
Expand All @@ -141,12 +86,10 @@ export default function PlayerWinnerIcon({
style={{ cursor: 'pointer', display: 'block', textAlign: 'center' }}
ref={updateContainer}
>
<img
ref={iconRef}
src={playerIcon}
width={`${40 * coords.scale}px`}
alt=""
style={{ verticalAlign: 'middle' }}
<JumpingIcon
image={playerIcon}
isJumping={isMoving}
scale={coords.scale}
/>
<p
style={{
Expand Down
Loading

0 comments on commit 26e56e7

Please sign in to comment.