Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Ondřej Bazala
PV247
Commits
410071e2
Unverified
Commit
410071e2
authored
Nov 21, 2021
by
Michal Čaniga
Browse files
Finish game mechanics, polish the website
parent
1fee183d
Changes
26
Hide whitespace changes
Inline
Side-by-side
public/ash.png
0 → 100644
View file @
410071e2
25.9 KB
src/App.tsx
View file @
410071e2
...
@@ -32,6 +32,8 @@ import {
...
@@ -32,6 +32,8 @@ import {
import
{
GameInputProvider
}
from
'
./hooks/useGameInput
'
;
import
{
GameInputProvider
}
from
'
./hooks/useGameInput
'
;
import
{
AllUserDataProvider
}
from
'
./hooks/useAllUserData
'
;
import
{
AllUserDataProvider
}
from
'
./hooks/useAllUserData
'
;
import
GamePage
from
'
./pages/Game/GamePage
'
;
import
GamePage
from
'
./pages/Game/GamePage
'
;
import
{
NotFoundPage
}
from
'
./pages/NotFoundPage
'
;
import
{
Forbidden
}
from
'
./pages/Forbidden
'
;
const
TopMenu
=
()
=>
{
const
TopMenu
=
()
=>
{
const
{
user
}
=
useLoggedInUser
();
const
{
user
}
=
useLoggedInUser
();
...
@@ -98,14 +100,23 @@ const AppContent = () => {
...
@@ -98,14 +100,23 @@ const AppContent = () => {
<
Content
style
=
{
{
padding
:
'
0 50px
'
,
height
:
'
95%
'
}
}
>
<
Content
style
=
{
{
padding
:
'
0 50px
'
,
height
:
'
95%
'
}
}
>
<
Switch
>
<
Switch
>
<
Route
path
=
"/"
exact
component
=
{
Home
}
/>
<
Route
path
=
"/"
exact
component
=
{
Home
}
/>
{
isLoggedIn
&&
(
<
Route
path
=
"/store"
exact
component
=
{
isLoggedIn
?
Store
:
Forbidden
}
/>
<>
<
Route
<
Route
path
=
"/store"
exact
component
=
{
Store
}
/>
path
=
"/encyclopedia"
<
Route
path
=
"/encyclopedia"
exact
component
=
{
Encyclopedia
}
/>
exact
<
Route
path
=
"/leaderboard"
exact
component
=
{
Leaderboard
}
/>
component
=
{
isLoggedIn
?
Encyclopedia
:
Forbidden
}
<
Route
path
=
"/game"
exact
component
=
{
GamePage
}
/>
/>
</>
<
Route
)
}
path
=
"/leaderboard"
exact
component
=
{
isLoggedIn
?
Leaderboard
:
Forbidden
}
/>
<
Route
path
=
"/game"
exact
component
=
{
isLoggedIn
?
GamePage
:
Forbidden
}
/>
<
Route
path
=
"*"
component
=
{
NotFoundPage
}
/>
</
Switch
>
</
Switch
>
</
Content
>
</
Content
>
);
);
...
...
src/data/constants.ts
View file @
410071e2
export
const
maxHearts
=
5
;
export
const
maxHearts
=
5
;
export
const
catchReward
=
10
;
export
const
pokemonSampleCount
=
2
;
export
const
pokemonSampleCount
=
2
;
export
const
esh
=
{
export
const
esh
=
{
x
:
0
,
x
:
0
,
...
...
src/data/food.ts
View file @
410071e2
...
@@ -20,6 +20,12 @@ export const food: Food[] = [
...
@@ -20,6 +20,12 @@ export const food: Food[] = [
name
:
'
Chicken Wings
'
,
name
:
'
Chicken Wings
'
,
price
:
471
,
price
:
471
,
restores
:
2
restores
:
2
},
{
id
:
3
,
name
:
'
Chicken Nuggets
'
,
price
:
682
,
restores
:
3
}
}
];
];
...
...
src/hooks/useAllUserData.tsx
View file @
410071e2
...
@@ -10,7 +10,7 @@ export const AllUserDataProvider: FC = ({ children }) => {
...
@@ -10,7 +10,7 @@ export const AllUserDataProvider: FC = ({ children }) => {
useEffect
(()
=>
{
useEffect
(()
=>
{
const
unsubscribe
=
onSnapshot
(
userDataCollection
,
snapshot
=>
{
const
unsubscribe
=
onSnapshot
(
userDataCollection
,
snapshot
=>
{
setAllUserData
(
snapshot
.
docs
.
map
(
doc
=>
doc
.
data
()));
setAllUserData
(
snapshot
.
docs
.
map
(
doc
=>
({
...
doc
.
data
()
,
id
:
doc
.
id
})
));
});
});
return
()
=>
{
return
()
=>
{
unsubscribe
();
unsubscribe
();
...
...
src/hooks/useLoggedInUser.tsx
View file @
410071e2
...
@@ -24,7 +24,10 @@ export const UserProvider: FC = ({ children }) => {
...
@@ -24,7 +24,10 @@ export const UserProvider: FC = ({ children }) => {
if
(
user
===
undefined
)
{
if
(
user
===
undefined
)
{
return
;
return
;
}
}
const
allUserData
=
snapshot
.
docs
.
map
(
doc
=>
doc
.
data
());
const
allUserData
=
snapshot
.
docs
.
map
(
doc
=>
({
...
doc
.
data
(),
id
:
doc
.
id
}));
setUserData
(
allUserData
.
filter
(
ud
=>
ud
.
userId
===
user
.
uid
)[
0
]);
setUserData
(
allUserData
.
filter
(
ud
=>
ud
.
userId
===
user
.
uid
)[
0
]);
});
});
return
()
=>
{
return
()
=>
{
...
...
src/pages/Forbidden.tsx
0 → 100644
View file @
410071e2
import
{
FrownOutlined
}
from
'
@ant-design/icons
'
;
import
{
Result
}
from
'
antd
'
;
import
{
useState
}
from
'
react
'
;
import
{
AuthModal
,
AuthModalType
}
from
'
./Home/AuthModal
'
;
import
{
SignInButton
,
SignUpButton
}
from
'
./Home/Home
'
;
export
const
Forbidden
=
()
=>
{
const
[
isAuthModalVisible
,
setIsAuthModalVisible
]
=
useState
(
false
);
const
[
authModalType
,
setAuthModalType
]
=
useState
<
AuthModalType
>
();
return
(
<
Result
status
=
"403"
title
=
"400"
subTitle
=
{
<
span
>
<
FrownOutlined
style
=
{
{
marginRight
:
3
}
}
/>
Sorry, we don`t know who you are yet
<
FrownOutlined
style
=
{
{
marginLeft
:
3
}
}
/>
</
span
>
}
extra
=
{
<>
<
SignInButton
setAuthModalType
=
{
setAuthModalType
}
setIsAuthModalVisible
=
{
setIsAuthModalVisible
}
/>
<
SignUpButton
setAuthModalType
=
{
setAuthModalType
}
setIsAuthModalVisible
=
{
setIsAuthModalVisible
}
/>
<
AuthModal
type
=
{
authModalType
}
isVisible
=
{
isAuthModalVisible
}
setAuthModalType
=
{
setAuthModalType
}
setIsAuthModalVisible
=
{
setIsAuthModalVisible
}
/>
</>
}
/>
);
};
src/pages/Game/BottomBar.tsx
View file @
410071e2
import
{
TrademarkCircleOutlined
}
from
'
@ant-design/icons
'
;
import
{
Row
,
Col
}
from
'
antd
'
;
import
{
Row
,
Col
}
from
'
antd
'
;
import
{
useMemo
}
from
'
react
'
;
import
{
useMemo
}
from
'
react
'
;
import
{
getUserFood
}
from
'
../../data/food
'
;
import
{
getUserFood
}
from
'
../../data/food
'
;
import
{
getUserPokeballs
}
from
'
../../data/pokeballs
'
;
import
{
getUserPokeballs
}
from
'
../../data/pokeballs
'
;
import
{
useLoggedInUser
}
from
'
../../hooks/useLoggedInUser
'
;
import
{
useLoggedInUser
}
from
'
../../hooks/useLoggedInUser
'
;
import
{
SetPokemonsAlive
,
SetScore
,
SetUserData
}
from
'
../../utils/commonTypes
'
;
import
{
UserData
}
from
'
../../utils/firebase
'
;
import
{
Loading
}
from
'
../../utils/Loading
'
;
import
{
Loading
}
from
'
../../utils/Loading
'
;
import
{
PokemonOnCanvas
}
from
'
../../utils/pokemonFetcher
'
;
import
{
FoodPowerup
}
from
'
./FoodPowerup
'
;
import
{
FoodPowerup
}
from
'
./FoodPowerup
'
;
import
{
Powerup
}
from
'
./Powerup
'
;
import
{
Pokeball
Powerup
}
from
'
./
Pokeball
Powerup
'
;
type
BottomBarProps
=
{
type
BottomBarProps
=
{
style
?:
React
.
CSSProperties
;
style
?:
React
.
CSSProperties
;
setHearts
:
(
hearts
:
number
)
=>
void
;
setHearts
:
(
hearts
:
number
)
=>
void
;
currentHearts
:
number
;
currentHearts
:
number
;
newUserData
:
UserData
;
setScore
:
SetScore
;
setNewUserData
:
SetUserData
;
alivePokemons
:
PokemonOnCanvas
[];
setAlivePokemons
:
SetPokemonsAlive
;
};
};
export
const
BottomBar
=
({
export
const
BottomBar
=
({
style
,
style
,
setHearts
,
setHearts
,
currentHearts
currentHearts
,
newUserData
,
setScore
,
setNewUserData
,
alivePokemons
,
setAlivePokemons
}:
BottomBarProps
)
=>
{
}:
BottomBarProps
)
=>
{
const
{
userData
}
=
useLoggedInUser
();
const
pokeballData
=
useMemo
(
const
pokeballData
=
useMemo
(
()
=>
getUserPokeballs
(
userData
?.
pokeballIds
),
()
=>
getUserPokeballs
(
newUserData
.
pokeballIds
),
[
userData
]
[
newUserData
]
);
const
foodData
=
useMemo
(
()
=>
getUserFood
(
newUserData
.
foodIds
),
[
newUserData
]
);
);
const
foodData
=
useMemo
(()
=>
getUserFood
(
userData
?.
foodIds
),
[
userData
]);
if
(
pokeballData
===
null
||
foodData
===
null
)
{
if
(
pokeballData
===
null
||
foodData
===
null
)
{
return
<
Loading
/>;
return
<
Loading
/>;
...
@@ -43,6 +61,7 @@ export const BottomBar = ({
...
@@ -43,6 +61,7 @@ export const BottomBar = ({
food
=
{
f
}
food
=
{
f
}
setHearts
=
{
setHearts
}
setHearts
=
{
setHearts
}
currentHearts
=
{
currentHearts
}
currentHearts
=
{
currentHearts
}
setNewUserData
=
{
setNewUserData
}
style
=
{
idx
>
1
?
{
marginLeft
:
5
}
:
undefined
}
style
=
{
idx
>
1
?
{
marginLeft
:
5
}
:
undefined
}
/>
/>
))
}
))
}
...
@@ -50,12 +69,13 @@ export const BottomBar = ({
...
@@ -50,12 +69,13 @@ export const BottomBar = ({
</
Col
>
</
Col
>
<
Col
span
=
{
12
}
>
<
Col
span
=
{
12
}
>
{
pokeballData
.
map
((
p
,
idx
,
arr
)
=>
(
{
pokeballData
.
map
((
p
,
idx
,
arr
)
=>
(
<
Powerup
<
Pokeball
Powerup
key
=
{
idx
}
key
=
{
idx
}
icon
=
{
<
TrademarkCircleOutlined
/>
}
alivePokemons
=
{
alivePokemons
}
onClick
=
{
()
=>
{
pokeball
=
{
p
}
console
.
log
(
'
consume pokeball
'
,
p
);
setAlivePokemons
=
{
setAlivePokemons
}
}
}
setNewUserData
=
{
setNewUserData
}
setScore
=
{
setScore
}
style
=
{
idx
!==
arr
.
length
-
1
?
{
marginLeft
:
5
}
:
undefined
}
style
=
{
idx
!==
arr
.
length
-
1
?
{
marginLeft
:
5
}
:
undefined
}
/>
/>
))
}
))
}
...
...
src/pages/Game/Canvas.tsx
View file @
410071e2
...
@@ -13,7 +13,11 @@ type PokemonObjectProps = {
...
@@ -13,7 +13,11 @@ type PokemonObjectProps = {
};
};
const
Esh
=
()
=>
(
const
Esh
=
()
=>
(
<
CanvasObject
className
=
"esh"
{
...
esh
}
style
=
{
{
backgroundColor
:
'
red
'
}
}
/>
<
CanvasObject
className
=
"esh"
{
...
esh
}
style
=
{
{
backgroundImage
:
`url("/ash.png")`
,
backgroundSize
:
'
cover
'
}
}
/>
);
);
const
PokemonObject
=
({
x
,
y
,
name
,
sprite
}:
PokemonObjectProps
)
=>
(
const
PokemonObject
=
({
x
,
y
,
name
,
sprite
}:
PokemonObjectProps
)
=>
(
<
CanvasObject
<
CanvasObject
...
...
src/pages/Game/FoodPowerup.tsx
View file @
410071e2
import
{
RestOutlined
}
from
'
@ant-design/icons
'
;
import
{
RestOutlined
}
from
'
@ant-design/icons
'
;
import
{
Badge
}
from
'
antd
'
;
import
{
maxHearts
}
from
'
../../data/constants
'
;
import
{
maxHearts
}
from
'
../../data/constants
'
;
import
{
Food
}
from
'
../../data/food
'
;
import
{
Food
}
from
'
../../data/food
'
;
import
{
SetUserData
}
from
'
../../utils/commonTypes
'
;
import
{
Powerup
}
from
'
./Powerup
'
;
import
{
Powerup
}
from
'
./Powerup
'
;
...
@@ -10,13 +12,15 @@ type FoodPowerupProps = {
...
@@ -10,13 +12,15 @@ type FoodPowerupProps = {
currentHearts
:
number
;
currentHearts
:
number
;
food
:
Food
;
food
:
Food
;
style
?:
React
.
CSSProperties
;
style
?:
React
.
CSSProperties
;
setNewUserData
:
SetUserData
;
};
};
export
const
FoodPowerup
=
({
export
const
FoodPowerup
=
({
food
,
food
,
setHearts
,
setHearts
,
currentHearts
,
currentHearts
,
style
style
,
setNewUserData
}:
FoodPowerupProps
)
=>
{
}:
FoodPowerupProps
)
=>
{
const
heal
=
(
restores
:
number
)
=>
{
const
heal
=
(
restores
:
number
)
=>
{
const
healingEffect
=
currentHearts
+
restores
;
const
healingEffect
=
currentHearts
+
restores
;
...
@@ -24,12 +28,22 @@ export const FoodPowerup = ({
...
@@ -24,12 +28,22 @@ export const FoodPowerup = ({
};
};
return
(
return
(
<
Powerup
<
Badge
count
=
{
food
.
restores
}
>
icon
=
{
<
RestOutlined
/>
}
<
Powerup
onClick
=
{
()
=>
{
icon
=
{
<
RestOutlined
/>
}
heal
(
food
.
restores
);
onClick
=
{
()
=>
{
}
}
heal
(
food
.
restores
);
style
=
{
style
}
setNewUserData
(
prev
=>
/>
prev
!==
undefined
?
{
...
prev
,
foodIds
:
prev
.
foodIds
.
filter
(
id
=>
id
!==
food
.
id
)
}
:
undefined
);
}
}
style
=
{
style
}
/>
</
Badge
>
);
);
};
};
src/pages/Game/Game.tsx
View file @
410071e2
import
{
useEffect
,
useState
}
from
'
react
'
;
import
{
cloneDeep
,
set
,
union
}
from
'
lodash
'
;
import
{
useEffect
,
useLayoutEffect
,
useState
}
from
'
react
'
;
import
{
catchReward
,
maxHearts
}
from
'
../../data/constants
'
;
import
{
spawnPokemons
}
from
'
../../data/pokemons
'
;
import
{
spawnPokemons
}
from
'
../../data/pokemons
'
;
import
{
useGameInput
}
from
'
../../hooks/useGameInput
'
;
import
{
useGameInput
}
from
'
../../hooks/useGameInput
'
;
import
{
useLoggedInUser
}
from
'
../../hooks/useLoggedInUser
'
;
import
{
SetGamePhase
,
SetPokemonsAlive
,
SetScore
,
SetUserData
}
from
'
../../utils/commonTypes
'
;
import
{
getElementSize
}
from
'
../../utils/dom
'
;
import
{
getElementSize
}
from
'
../../utils/dom
'
;
import
{
UserData
}
from
'
../../utils/firebase
'
;
import
{
updateUserDataInFirebase
,
UserData
}
from
'
../../utils/firebase
'
;
import
{
Loading
}
from
'
../../utils/Loading
'
;
import
{
Loading
}
from
'
../../utils/Loading
'
;
import
{
PokemonOnCanvas
}
from
'
../../utils/pokemonFetcher
'
;
import
{
PokemonOnCanvas
}
from
'
../../utils/pokemonFetcher
'
;
import
{
BottomBar
}
from
'
./BottomBar
'
;
import
{
BottomBar
}
from
'
./BottomBar
'
;
import
{
Canvas
}
from
'
./Canvas
'
;
import
{
Canvas
}
from
'
./Canvas
'
;
import
{
TopBar
}
from
'
./TopBar
'
;
import
{
onEshDeath
,
TopBar
}
from
'
./TopBar
'
;
export
type
GamePhase
=
'
play
'
|
'
prepare
'
|
'
lost
'
;
type
SetHearts
=
React
.
Dispatch
<
React
.
SetStateAction
<
number
>>
;
type
SetInput
=
React
.
Dispatch
<
React
.
SetStateAction
<
string
>>
;
type
GameProps
=
{
type
GameProps
=
{
hearts
:
number
;
setGamePhase
:
SetGamePhase
;
setHearts
:
React
.
Dispatch
<
React
.
SetStateAction
<
number
>>
;
pokemonsAlive
:
PokemonOnCanvas
[];
setPokemonsAlive
:
React
.
Dispatch
<
React
.
SetStateAction
<
PokemonOnCanvas
[]
>>
;
setScore
:
React
.
Dispatch
<
React
.
SetStateAction
<
number
|
undefined
>>
;
setGamePhase
:
React
.
Dispatch
<
React
.
SetStateAction
<
GamePhase
>>
;
score
?:
number
;
userData
?:
UserData
;
};
};
const
Game
=
({
const
onPokemonCatch
=
(
hearts
,
setPokemonsAlive
:
SetPokemonsAlive
,
setHearts
,
setScore
:
SetScore
,
pokemonsAlive
,
setNewUserData
:
SetUserData
,
setPokemonsAlive
,
setInput
:
SetInput
,
setScore
,
input
:
string
,
score
,
catchedIds
:
number
[]
userData
,
)
=>
{
setGamePhase
setPokemonsAlive
(
prevPokemons
=>
prevPokemons
.
filter
(
p
=>
p
.
name
!==
input
));
}:
GameProps
)
=>
{
setScore
(
prev
=>
prev
!==
undefined
?
prev
+
catchedIds
.
length
*
catchReward
:
undefined
);
setNewUserData
(
prev
=>
prev
!==
undefined
?
{
...
prev
,
catchedPokemonIds
:
union
(
prev
.
catchedPokemonIds
,
catchedIds
)
}
:
undefined
);
setInput
(
''
);
};
const
spawnNextWawe
=
(
setPokemonsAlive
:
SetPokemonsAlive
)
=>
{
setPokemonsAlive
(
prev
=>
[...
prev
,
...
spawnPokemons
(
prev
)]);
};
const
movePokemons
=
(
pokemonsAlive
:
PokemonOnCanvas
[],
setPokemonsAlive
:
SetPokemonsAlive
,
setHearts
:
SetHearts
,
colisionBorder
?:
number
)
=>
{
if
(
colisionBorder
!==
undefined
)
{
const
pokemonsBehindBorder
=
pokemonsAlive
.
filter
(
p
=>
p
.
x
<=
colisionBorder
);
setPokemonsAlive
(
p
=>
p
.
filter
(
p
=>
!
pokemonsBehindBorder
.
map
(
pbh
=>
pbh
.
id
).
includes
(
p
.
id
))
);
setHearts
(
hearts
=>
hearts
-
pokemonsBehindBorder
.
length
>
0
?
hearts
-
pokemonsBehindBorder
.
length
:
0
);
}
setPokemonsAlive
(
prevPokemons
=>
prevPokemons
.
map
(
p
=>
({
...
p
,
x
:
p
.
x
-
0.1
}))
);
};
const
Game
=
({
setGamePhase
}:
GameProps
)
=>
{
const
{
userData
}
=
useLoggedInUser
();
const
[
hearts
,
setHearts
]
=
useState
(
maxHearts
);
const
[
score
,
setScore
]
=
useState
<
number
|
undefined
>
();
const
[
seconds
,
setSeconds
]
=
useState
(
0
);
const
[
pokemonsAlive
,
setPokemonsAlive
]
=
useState
<
PokemonOnCanvas
[]
>
(
spawnPokemons
([])
);
const
[
input
,
setInput
]
=
useGameInput
();
const
[
input
,
setInput
]
=
useGameInput
();
const
[
colisionBorder
,
setColisionBorder
]
=
useState
<
number
>
();
const
[
colisionBorder
,
setColisionBorder
]
=
useState
<
number
>
();
const
[
newUserData
,
setNewUserData
]
=
useState
<
UserData
>
();
// check if esh died
// check if esh died
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
hearts
<=
0
)
{
if
(
hearts
<=
0
)
{
setGamePhase
(
'
lost
'
);
onEshDeath
(
setGamePhase
,
userData
!
,
newUserData
!
,
score
!
,
seconds
);
}
}
},
[
hearts
]);
},
[
hearts
,
setGamePhase
,
userData
]);
// find out esh
size
// find out esh
width
useEffect
(()
=>
{
useEffect
(()
=>
{
const
canvasHeight
=
getElementSize
(
'
.canvas
'
)?.
height
;
const
canvasWidth
=
getElementSize
(
'
.canvas
'
)?.
width
;
const
esh
=
getElementSize
(
'
.esh
'
)?.
height
;
const
esh
=
getElementSize
(
'
.esh
'
)?.
width
;
if
(
canvasHeight
!==
undefined
&&
esh
!==
undefined
)
{
if
(
canvasWidth
!==
undefined
&&
esh
!==
undefined
)
{
setColisionBorder
((
esh
/
canvasHeight
)
*
100
);
setColisionBorder
((
esh
/
canvasWidth
)
*
100
);
}
if
(
userData
!==
undefined
)
{
setScore
(
userData
.
actualScore
);
}
}
});
});
// set score after userData loads
// update colision border on window resize
useLayoutEffect
(()
=>
{
const
updateColisionBorder
=
()
=>
{
const
canvasWidth
=
getElementSize
(
'
.canvas
'
)?.
width
;
const
esh
=
getElementSize
(
'
.esh
'
)?.
width
;
const
newCollisionBorder
=
esh
!==
undefined
&&
canvasWidth
!==
undefined
?
(
esh
/
canvasWidth
)
*
100
:
undefined
;
setColisionBorder
(
newCollisionBorder
);
};
window
.
addEventListener
(
'
resize
'
,
updateColisionBorder
);
updateColisionBorder
();
return
()
=>
window
.
removeEventListener
(
'
resize
'
,
updateColisionBorder
);
},
[]);
// set score after userData loads and make copy of the data
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
userData
!==
undefined
)
{
if
(
userData
!==
undefined
)
{
setScore
(
userData
.
actualScore
);
setScore
(
userData
.
actualScore
);
setNewUserData
(
cloneDeep
(
userData
));
}
}
},
[
userData
]);
},
[
userData
,
setScore
,
setNewUserData
]);
// spawn another pokemons after some interval
// spawn another pokemons after some interval
useEffect
(()
=>
{
useEffect
(()
=>
{
const
id
=
setInterval
(()
=>
{
const
id
=
setInterval
(()
=>
{
console
.
log
(
'
now
'
);
spawnNextWawe
(
setPokemonsAlive
);
setPokemonsAlive
(
prev
=>
[...
prev
,
...
spawnPokemons
(
prev
)]);
},
3000
);
},
3000
);
return
()
=>
clearInterval
(
id
);
return
()
=>
clearInterval
(
id
);
},
[]);
},
[]);
//count seconds
useEffect
(()
=>
{
const
id
=
setInterval
(()
=>
{
setSeconds
(
prev
=>
prev
+
1
);
},
1000
);
return
()
=>
clearInterval
(
id
);
},
[]);
// move pokemons
// move pokemons
useEffect
(()
=>
{
useEffect
(()
=>
{
const
id
=
setInterval
(()
=>
{
const
id
=
setInterval
(()
=>
{
if
(
colisionBorder
!==
undefined
)
{
movePokemons
(
pokemonsAlive
,
setPokemonsAlive
,
setHearts
,
colisionBorder
);
const
pokemonsBehindBorder
=
pokemonsAlive
.
filter
(
p
=>
p
.
x
<=
colisionBorder
);
setPokemonsAlive
(
p
=>
p
.
filter
(
p
=>
!
pokemonsBehindBorder
.
map
(
pbh
=>
pbh
.
id
).
includes
(
p
.
id
))
);
setHearts
(
hearts
=>
hearts
-
pokemonsBehindBorder
.
length
>
0
?
hearts
-
pokemonsBehindBorder
.
length
:
0
);
}
setPokemonsAlive
(
prevPokemons
=>
prevPokemons
.
map
(
p
=>
({
...
p
,
x
:
p
.
x
-
0.1
}))
);
},
20
);
},
20
);
return
()
=>
clearInterval
(
id
);
return
()
=>
clearInterval
(
id
);