Svelte 3 рдХреЛ рдПрдХ рдорд╣реАрдиреЗ рдкрд╣рд▓реЗ рдереЛрдбрд╝рд╛ рд░рд┐рд▓реАрдЬ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдЖрдкрд╕реЗ рдорд┐рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдЪреНрдЫрд╛ рдкрд▓, рдореИрдВрдиреЗ рд╕реЛрдЪрд╛, рдФрд░ рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рднрд╛рдЧ рдЧрдпрд╛, рдЬрд┐рд╕рдХрд╛ рд░реВрд╕реА рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рднреА рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред
рдЕрддреАрдд рдХреЛ рдордЬрдмреВрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдПрдХ рдЫреЛрдЯреА рд╕реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдмрдирд╛рдИ рдФрд░ рдкрд░рд┐рдгрд╛рдо рдЖрдкрдХреЗ рд╕рд╛рде рд╕рд╛рдЭрд╛ рдХрд┐рдпрд╛ред рдпрд╣ рдПрдХ-рдЕрдзрд┐рдХ-рдЯреВрдбреВ-рд╕реВрдЪреА рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЧреЗрдо рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдЖрдкрдХреЛ рдХрд╛рд▓реЗ рд╡рд░реНрдЧреЛрдВ рд╕реЗ рд╢реВрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

0. рдЕрдзреАрд░ рдХреЗ рд▓рд┐рдП
рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА
рдПрдХреНрд╕реНрдЯреНрд░рд╛рд╕ рдХреЗ рд╕рд╛рде рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА
рдбреЗрдореЛ
1. рддреИрдпрд╛рд░реА
рд╣рдо рд╡рд┐рдХрд╛рд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреНрд▓реЛрди рдХрд░рддреЗ рд╣реИрдВ
git clone https://github.com/sveltejs/template.git
рдирд┐рд░реНрднрд░рддрд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВред
cd template/ npm i
рд╣рдо рджреЗрд╡ рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред
npm run dev
рд╣рдорд╛рд░реЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИ
http: // рд▓реЛрдХрд▓рд╣реЛрд╕реНрдЯ: 5000 ред рд╕рд░реНрд╡рд░ рдЧрд░реНрдо рдкреБрдирдГ рд▓реЛрдб рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд░рд┐рд╡рд░реНрддрди рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗ рдХреНрдпреЛрдВрдХрд┐ рдкрд░рд┐рд╡рд░реНрддрди рд╕рд╣реЗрдЬреЗ рдЧрдП рд╣реИрдВред
рдпрджрд┐ рдЖрдк рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЛ рдкрд░рд┐рдирд┐рдпреЛрдЬрд┐рдд рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдХреЛрдбреИрдВрдбрдмреЙрдХреНрд╕ рдФрд░ рд╕реНрдЯреИрдХрдмреНрд▓рд┐рдЯреНрдЬрд╝ рд╕реИрдВрдбрдмреЙрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдСрдирд▓рд╛рдЗрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ Svelte рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВред
2. рдЦреЗрд▓ рдХрд╛ рдврд╛рдБрдЪрд╛
Src рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рджреЛ рдлрд╛рдЗрд▓реЗрдВ рд╣реЛрддреА рд╣реИрдВ main.js рдФрд░ App.svelte ред
main.js рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХрд╛ рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБ рд╣реИред рд╡рд┐рдХрд╛рд╕ рдХреЗ рджреМрд░рд╛рди, рд╣рдо рдЗрд╕реЗ рдирд╣реАрдВ рдЫреВрдПрдВрдЧреЗред рдпрд╣рд╛рдВ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдХреЗ рд╢рд░реАрд░ рдореЗрдВ App.svelte рдШрдЯрдХ рдорд╛рдЙрдВрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред
App.svelte svelte рдХрд╛ рдПрдХ рдШрдЯрдХ рд╣реИред рдШрдЯрдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рддреАрди рднрд╛рдЧ рд╣реЛрддреЗ рд╣реИрдВ:
<script> </script> <style> h1 { color: purple; } </style> <h1>Hello {name}!</h1>
рдШрдЯрдХ рд╢реИрд▓рд┐рдпреЛрдВ рдХреЛ рдЕрд▓рдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдирд┐рд░реНрджреЗрд╢ рдХреЗ рд╕рд╛рде рд╡реИрд╢реНрд╡рд┐рдХ рд╢реИрд▓рд┐рдпреЛрдВ рдХреЛ рдЕрд╕рд╛рдЗрди рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ: рд╡реИрд╢реНрд╡рд┐рдХ ()ред рд╢реИрд▓рд┐рдпреЛрдВ рдкрд░ рдЕрдзрд┐рдХ ред
рд╣рдорд╛рд░реЗ рдШрдЯрдХ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдп рд╢реИрд▓рд┐рдпрд╛рдБ рдЬреЛрдбрд╝реЗрдВред
src / App.svelte <script> export let name; </script> <style> :global(html) { height: 100%; } :global(body) { height: 100%; overscroll-behavior: none; user-select: none; margin: 0; background-color: #efefef; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; } </style> <h1>Hello {name}!</h1>
рдЪрд▓рд┐рдП src / Components рдлреЛрд▓реНрдбрд░ рдмрдирд╛рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рд╣рдорд╛рд░реЗ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ рдХреЛ рд╕реНрдЯреЛрд░ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛
рдЗрд╕ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ, рджреЛ рдлрд╝рд╛рдЗрд▓реЗрдВ рдмрдирд╛рдПрдВ рдЬрд┐рд╕рдореЗрдВ рдЦреЗрд▓ рдХрд╛ рдореИрджрд╛рди рдФрд░ рдирд┐рдпрдВрддреНрд░рдг рд╣реЛрдЧрд╛ред
src / рдШрдЯрдХреЛрдВ / GameField.svelte src / Components / Controls.svelte рдШрдЯрдХ рдирд┐рд░реНрджреЗрд╢ рджреНрд╡рд╛рд░рд╛ рдЖрдпрд╛рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
import Controls from "./components/Controls.svelte";
рдПрдХ рдШрдЯрдХ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕ рдорд╛рд░реНрдХрдЕрдк рдореЗрдВ рдШрдЯрдХ рдЯреИрдЧ рдбрд╛рд▓реЗрдВред рдЯреИрдЧреНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдФрд░ рдЬрд╛рдиреЗрдВ ред
<Controls />
рдЕрдм рд╣рдо рдЕрдкрдиреЗ рдШрдЯрдХреЛрдВ рдХреЛ App.svelte рдореЗрдВ рдЖрдпрд╛рдд рдФрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВред
src / App.svelte <script> </script> <style> :global(html) { height: 100%; } :global(body) { height: 100%; overscroll-behavior: none; user-select: none; margin: 0; background-color: #efefef; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; } </style> <Controls /> <GameField />
3. рдирд┐рдпрдВрддреНрд░рдг
Controls.svelte рдШрдЯрдХ рдореЗрдВ рддреАрди рдмрдЯрди рд╣реЛрдВрдЧреЗ: рдмрд╛рдПрдБ рд▓реЗ рдЬрд╛рдПрдБ, рджрд╛рдПрдБ рдЬрд╛рдПрдБ, рдЕрдЧреНрдирд┐ред рдмрдЯрди рдЖрдЗрдХрди svg рддрддреНрд╡ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗред
Src / asssets рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рдПрдВ, рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдЕрдкрдиреЗ svg рдЖрдЗрдХрди рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред
src / рдЖрд╕реНрддрд┐рдпреЛрдВ / Bullet.svelte <svg height="40px" viewBox="0 0 427 427.08344" width="40px"> <path d="m341.652344 38.511719-37.839844 37.839843 46.960938 46.960938 37.839843-37.839844c8.503907-8.527344 15-18.839844 19.019531-30.191406l19.492188-55.28125-55.28125 19.492188c-11.351562 4.019531-21.664062 10.515624-30.191406 19.019531zm0 0" /> <path d="m258.65625 99.078125 69.390625 69.390625 14.425781-33.65625-50.160156-50.160156zm0 0" /> <path d="m.0429688 352.972656 28.2812502-28.285156 74.113281 74.113281-28.28125 28.28125zm0 0" /> <path d="m38.226562 314.789062 208.167969-208.171874 74.113281 74.113281-208.171874 208.171875zm0 0" /> </svg>
src / рдЖрд╕реНрддрд┐рдпреЛрдВ / LeftArrow.svelte <svg width="40px" height="40px" viewBox="0 0 292.359 292.359" transform="translate(-5 0)"> <path d="M222.979,5.424C219.364,1.807,215.08,0,210.132,0c-4.949,0-9.233,1.807-12.848,5.424L69.378,133.331 c-3.615,3.617-5.424,7.898-5.424,12.847c0,4.949,1.809,9.233,5.424,12.847l127.906,127.907c3.614,3.617,7.898,5.428,12.848,5.428 c4.948,0,9.232-1.811,12.847-5.428c3.617-3.614,5.427-7.898,5.427-12.847V18.271C228.405,13.322,226.596,9.042,222.979,5.424z" /> </svg>
src / рдЖрд╕реНрддрд┐рдпреЛрдВ / RightArrow.svelte <svg width="40px" height="40px" viewBox="0 0 292.359 292.359" transform="translate(5 0) rotate(180)"> <path d="M222.979,5.424C219.364,1.807,215.08,0,210.132,0c-4.949,0-9.233,1.807-12.848,5.424L69.378,133.331 c-3.615,3.617-5.424,7.898-5.424,12.847c0,4.949,1.809,9.233,5.424,12.847l127.906,127.907c3.614,3.617,7.898,5.428,12.848,5.428 c4.948,0,9.232-1.811,12.847-5.428c3.617-3.614,5.427-7.898,5.427-12.847V18.271C228.405,13.322,226.596,9.042,222.979,5.424z" /> </svg>
рдмрдЯрди рдШрдЯрдХ src / Components / IconButton.svelte рдЬреЛрдбрд╝реЗрдВ ред
рд╣рдо рдореВрд▓ рдШрдЯрдХ рд╕реЗ рдИрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░реЗрдВрдЧреЗред рдмрдЯрди рдХреЛ рджрдмрд╛рдП рд░рдЦрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рджреЛ рд╣реИрдВрдбрд▓рд░ рдЪрд╛рд╣рд┐рдП: рдХреНрд▓рд┐рдХ рдХреА рд╢реБрд░реБрдЖрдд рдФрд░ рдХреНрд▓рд┐рдХ рдХрд╛ рдЕрдВрддред рд╣рдо рдЪрд░реЛрдВ рдХреА рд╢реБрд░реБрдЖрдд рдФрд░ рд╡рд┐рдореЛрдЪрди рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ рд╣рдо рдХреНрд▓рд┐рдХ рдХреА рд╢реБрд░реБрдЖрдд рдФрд░ рдЕрдВрдд рдХреЗ рд▓рд┐рдП рдИрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░реЗрдВрдЧреЗред рд╣рдореЗрдВ рд╕рдХреНрд░рд┐рдп рдЪрд░ рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧрд╛ рдХрд┐ рдмрдЯрди рджрдмрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред
<script> export let start; export let release; export let active; </script>
рд╣рдо рдЕрдкрдиреЗ рдШрдЯрдХ рдХреЛ рд╕реНрдЯрд╛рдЗрд▓ рдХрд░рддреЗ рд╣реИрдВ
<style> .iconButton { display: flex; align-items: center; justify-content: center; width: 60px; height: 60px; border: 1px solid black; border-radius: 50px; outline: none; background: transparent; } .active { background-color: #bdbdbd; } </style>
рдПрдХ рдмрдЯрди рдПрдХ рдмрдЯрди рддрддреНрд╡ рд╣реИ рдЬрд┐рд╕рдХреЗ рднреАрддрд░ рдореВрд▓ рдШрдЯрдХ рд╕реЗ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рд╕рд╛рдордЧреНрд░реА рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддреА рд╣реИред рдЬрд┐рд╕ рд╕реНрдерд╛рди рдкрд░ рд╣рд╕реНрддрд╛рдВрддрд░рд┐рдд рд╕рд╛рдордЧреНрд░реА рдХреЛ рдорд╛рдЙрдВрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рд╡рд╣ <рд╕реНрд▓реЙрдЯ /> рдЯреИрдЧ рджреНрд╡рд╛рд░рд╛ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред <рд╕реНрд▓реЙрдЯ /> рддрддреНрд╡ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдиреЗрдВ ред
<button> <slot /> </button>
рдИрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рд╕рдВрдХреЗрдд рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ : рдирд┐рд░реНрджреЗрд╢, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкрд░: рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ ред
рд╣рдо рдорд╛рдЙрд╕ рдШрдЯрдирд╛рдУрдВ рдХреЛ рд╕рдВрднрд╛рд▓реЗрдВрдЧреЗ рдФрд░ рдХреНрд▓рд┐рдХреЛрдВ рдХреЛ рд╕реНрдкрд░реНрд╢ рдХрд░реЗрдВрдЧреЗред рдЗрд╡реЗрдВрдЯ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдиреЗрдВ ред
рдпрджрд┐ рдмрдЯрди рджрдмрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рд╕рдХреНрд░рд┐рдп рд╡рд░реНрдЧ рдХреЛ рдШрдЯрдХ рдХреЗ рдЖрдзрд╛рд░ рд╡рд░реНрдЧ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛ред рдЖрдк рдХреНрд▓рд╛рд╕ рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЗ рд╣рд┐рд╕рд╛рдм рд╕реЗ рдХреНрд▓рд╛рд╕ рдЕрд╕рд╛рдЗрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╡рд░реНрдЧреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ
<button on:mousedown={start} on:touchstart={start} on:mouseup={release} on:touchend={release} class={`iconButton ${active ? 'active' : ''}`}> <slot /> </button>
рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдорд╛рд░рд╛ рдШрдЯрдХ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:
src / Components / IconButton.svelte <script> export let start; export let release; export let active; </script> <style> .iconButton { display: flex; align-items: center; justify-content: center; width: 60px; height: 60px; border: 1px solid black; border-radius: 50px; outline: none; background: transparent; } .active { background-color: #bdbdbd; } </style> <button on:mousedown={start} on:touchstart={start} on:mouseup={release} on:touchend={release} class={`iconButton ${active ? 'active' : ''}`}> <slot /> </button>
рдЕрдм рд╣рдо рдЕрдкрдиреЗ рдЖрдЗрдХрди рдФрд░ рдмрдЯрди рддрддреНрд╡ рдХреЛ src / Components / Controls.svelte рдореЗрдВ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд▓реЗрдЖрдЙрдЯ рдмрдирд╛рддреЗ рд╣реИрдВред
src / Components / Controls.svelte <script> </script> <style> .controls { position: fixed; bottom: 0; left: 0; width: 100%; } .container { display: flex; justify-content: space-between; margin: 1rem; } .arrowGroup { display: flex; justify-content: space-between; width: 150px; } </style> <div class="controls"> <div class="container"> <div class="arrowGroup"> <IconButton> <LeftArrow /> </IconButton> <IconButton> <RightArrow /> </IconButton> </div> <IconButton> <Bullet /> </IconButton> </div> </div>
рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП:

4. рдЦреЗрд▓ рдХрд╛ рдореИрджрд╛рди
рдЦреЗрд▓ рдХрд╛ рдореИрджрд╛рди рдПрдХ svg рдШрдЯрдХ рд╣реИ, рдЬрд╣рд╛рдВ рд╣рдо рдЕрдкрдиреЗ рдЦреЗрд▓ рддрддреНрд╡реЛрдВ (рдмрдВрджреВрдХ, рдЧреЛрд▓реЗ, рд╡рд┐рд░реЛрдзрд┐рдпреЛрдВ) рдХреЛ рдЬреЛрдбрд╝реЗрдВрдЧреЗред
рдЕрдкрдбреЗрдЯ src / Components / GameField.svelte рдХреЛрдб
src / рдШрдЯрдХреЛрдВ / GameField.svelte <style> .container { flex-grow: 1; display: flex; flex-direction: column; justify-content: flex-start; max-height: 100%; } </style> <div class="container"> <svg viewBox="0 0 480 800"> </svg> </div>
Src / Components / Cannon.svelte рдЧрди рдмрдирд╛рдПрдБред рдПрдХ рдЖрдпрдд рдХреЗ рд▓рд┐рдП рдЬреЛрд░ рд╕реЗ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреАред
src / Components / Cannon.svelte <style> .cannon { transform-origin: 4px 55px; } </style> <g class="cannon" transform={`translate(236, 700)`}> <rect width="8" height="60" fill="#212121" /> </g>
рдЕрдм рд╣рдо рдЕрдкрдиреА рдмрдВрджреВрдХ рдХреЛ рдЦреЗрд▓ рдореИрджрд╛рди рдкрд░ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВред
src / GameField.svelte <script> </script> <style> .container { flex-grow: 1; display: flex; flex-direction: column; justify-content: flex-start; max-height: 100%; } </style> <div class="container"> <svg viewBox="0 0 480 800"> <Cannon /> </svg> </div>
5. рдЦреЗрд▓ рдЪрдХреНрд░
рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЦреЗрд▓ рдХрд╛ рдореВрд▓ рдврд╛рдВрдЪрд╛ рд╣реИред рдЕрдЧрд▓рд╛ рдХрджрдо рдПрдХ рдЧреЗрдо рд▓реВрдк рдмрдирд╛рдирд╛ рд╣реИ рдЬреЛ рд╣рдорд╛рд░реЗ рддрд░реНрдХ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░реЗрдЧрд╛ред
рдЖрдЗрдП рд╕реНрдЯреЛрд░реЗрдЬ рдмрдирд╛рддреЗ рд╣реИрдВ рдЬрд╣рд╛рдВ рд╣рдорд╛рд░реЗ рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рдЪрд░ рд╕рдорд╛рд╣рд┐рдд рд╣реЛрдВрдЧреЗред рд╣рдореЗрдВ svelte / store рдореЙрдбреНрдпреВрд▓ рд╕реЗ рд▓рд┐рдЦрдиреЗ рдпреЛрдЧреНрдп рдШрдЯрдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рд╕реНрдЯреЛрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдиреЗрдВ ред
рдПрдХ рд╕рд╛рдзрд╛рд░рдг рднрдВрдбрд╛рд░ рдмрдирд╛рдирд╛ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
рдЪрд▓рд┐рдП src / store / folder рдмрдирд╛рддреЗ рд╣реИрдВ, рд╣рдорд╛рд░реЗ рдЧреЗрдо рдХреЗ рд╕рднреА рдЙрддреНрдкрд░рд┐рд╡рд░реНрддрд┐рдд рдорд╛рдиреЛрдВ рдХреЛ рдпрд╣рд╛рдБ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
Src / store / game.js рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдВ рдЬрд┐рд╕рдореЗрдВ рдЧреЗрдо рдХреА рд╕рд╛рдорд╛рдиреНрдп рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рдЪрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗред
src / рд╕реНрдЯреЛрд░ / game.js Src / store / cannon.js рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдВ, рдЬрд┐рд╕рдореЗрдВ рдмрдВрджреВрдХ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рдЪрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗ
Svelte рдЖрдкрдХреЛ рдХрд╕реНрдЯрдо рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдмрдирд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдХрд╛рдо рдХреЗ рддрд░реНрдХ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рдЖрдк рдкрд╛рдареНрдпрдкреБрд╕реНрддрдХ рдореЗрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред рдореИрдВ рдЗрд╕реЗ рдЦреЗрд▓ рдЪрдХреНрд░ рдХреА рдЕрд╡рдзрд╛рд░рдгрд╛ рдореЗрдВ рдЦреВрдмрд╕реВрд░рддреА рд╕реЗ рдлрд┐рдЯ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рдерд╛, рдЗрд╕рд▓рд┐рдП рд╣рдо рдХреЗрд╡рд▓ рднрдВрдбрд╛рд░ рдореЗрдВ рдЪрд░ рдШреЛрд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рд╣рдо src / gameLoop рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдЙрдирдХреЗ рд╕рд╛рде рд╕рднреА рдЬреЛрдбрд╝рддреЛрдбрд╝ рдХрд░реЗрдВрдЧреЗред
рдЧреЗрдо рд▓реВрдк рдХрд╛ рдЕрдиреБрд░реЛрдз requestAnimationFrame рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ ред рдЧреЗрдо рдХреЗ рддрд░реНрдХ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдЗрдирдкреБрдЯ рдХреЛ рдЦрд┐рд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдЦреЗрд▓ рдЪрдХреНрд░ рдХреЗ рдЕрдВрдд рдореЗрдВ, рдпрджрд┐ рдЦреЗрд▓ рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ, рддреЛ рдЕрдЧрд▓реЗ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рдИ рдЧрдИ рд╣реИред рдЧреЗрдо рд▓реВрдк рдореЗрдВ, рд╣рдо рдпрд╣ рдЬрд╛рдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП isPlaying рд╡реИрд░рд┐рдПрдмрд▓ рдХреЗ рдорд╛рди рдХреЛ рдПрдХреНрд╕реЗрд╕ рдХрд░реЗрдВрдЧреЗ рдХрд┐ рдХреНрдпрд╛ рдЧреЗрдо рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ рд╣реИред
рднрдВрдбрд╛рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк рдореВрд▓реНрдп рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рджрд╕реНрдпрддрд╛ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдо рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдШрдЯрдХреЛрдВ рдореЗрдВ рдХрд░реЗрдВрдЧреЗред рдЕрднреА рдХреЗ рд▓рд┐рдП, рд╣рдо рд╡реЗрд░рд┐рдПрдмрд▓ рдХреЗ рдорд╛рди рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдлрдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдорд╛рди рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЪрд░ рдХреА .set () рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред
рдЖрдк .update () рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдХреЗ рдорд╛рди рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ, рд╡рд░реНрддрдорд╛рди рдорд╛рди рдХреЛ рдкрд╣рд▓реЗ рддрд░реНрдХ рдореЗрдВ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА ред рдмрд╛рдХреА рд╕рдм рд╢реБрджреНрдз рдЬреЗрдПрд╕ рд╣реИред
src / gameLoop / gameLoop.js рдЕрдм рд╣рдо рдЕрдкрдиреА рдмрдВрджреВрдХ рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рддрд░реНрдХ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВред
src / gameLoop / cannon.js рдЕрдм рд╣рдорд╛рд░реЗ рдмрдВрджреВрдХ рд░реЛрдЯреЗрд╢рди рд╣реИрдВрдбрд▓рд░ рдХреЛ рдЧреЗрдо рд▓реВрдк рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред
import { rotateCannon } from "./cannon"; export const startGame = () => { isPlaying.set(true); startLoop([rotateCannon]); };
рд╡рд░реНрддрдорд╛рди рдЦреЗрд▓ рдЪрдХреНрд░ рдХреЛрдб:
src / gameLoop / gameLoop.js import { isPlaying } from '../stores/game'; import { get } from 'svelte/store'; import { rotateCannon } from './cannon';
рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рддрд░реНрдХ рд╣реИ рдЬреЛ рдмрдВрджреВрдХ рдХреЛ рдШреБрдорд╛ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рд╣рдордиреЗ рдЕрднреА рддрдХ рдЗрд╕реЗ рдмрдЯрди рдХреЗ рдкреБрд╢ рд╕реЗ рдирд╣реАрдВ рдЬреЛрдбрд╝рд╛ рд╣реИред рдпрд╣ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред рдИрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░реНрд╕ рдХреЛ src / рдШрдЯрдХреЛрдВ / Controls.svelte рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛ред
import { direction } from "../stores/cannon.js";
IconButton рддрддреНрд╡реЛрдВ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рд╣реИрдВрдбрд▓рд░ рдФрд░ рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдХреЛ рдЬреЛрдбрд╝реЗрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕ рдкрд╣рд▓реЗ рд╕реЗ рдмрдирд╛рдИ рдЧрдИ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЗ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдкрд╛рд╕ рдХрд░реЗрдВ, рдЬрд╛рд░реА рдХрд░реЗрдВ рдФрд░ рд╕рдХреНрд░рд┐рдп рдХрд░реЗрдВ , рдЬреИрд╕рд╛ рдХрд┐ рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИред
<IconButton start={setDirectionLeft} release={resetDirection} active={$direction === 'left'}> <LeftArrow /> </IconButton> <IconButton start={setDirectionRight} release={resetDirection} active={$direction === 'right'}> <RightArrow /> </IconButton>
рд╣рдордиреЗ $ рджрд┐рд╢рд╛ рдЪрд░ рдХреЗ рд▓рд┐рдП $ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдпрд╣ рд╕рд┐рдВрдЯреИрдХреНрд╕ рдореВрд▓реНрдп рдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдмрдирд╛рддрд╛ рд╣реИ, рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреА рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрддрд╛ рд╣реИред рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА ред
src / Components / Controls.svelte <script> import IconButton from "./IconButton.svelte"; import LeftArrow from "../assets/LeftArrow.svelte"; import RightArrow from "../assets/RightArrow.svelte"; import Bullet from "../assets/Bullet.svelte"; </script> <style> .controls { position: fixed; bottom: 0; left: 0; width: 100%; } .container { display: flex; justify-content: space-between; margin: 1rem; } .arrowGroup { display: flex; justify-content: space-between; width: 150px; } </style> <div class="controls"> <div class="container"> <div class="arrowGroup"> <IconButton start={setDirectionLeft} release={resetDirection} active={$direction === 'left'}> <LeftArrow /> </IconButton> <IconButton start={setDirectionRight} release={resetDirection} active={$direction === 'right'}> <RightArrow /> </IconButton> </div> <IconButton> <Bullet /> </IconButton> </div> </div>
рдлрд┐рд▓рд╣рд╛рд▓, рдЬрдм рд╣рдорд╛рд░рд╛ рдмрдЯрди рджрдмрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдПрдХ рдЪрдпрди рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдмрдВрджреВрдХ рдЕрднреА рднреА рдирд╣реАрдВ рдШреВрдорддреА рд╣реИред рд╣рдореЗрдВ Cannon.svelte рдШрдЯрдХ рдореЗрдВ рдХреЛрдг рдорд╛рди рдЖрдпрд╛рдд рдХрд░рдиреЗ рдФрд░ рдкрд░рд┐рд╡рд░реНрддрди рдкрд░рд┐рд╡рд░реНрддрди рдирд┐рдпрдореЛрдВ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
src / Components / Cannon.svelte <script> </script> <style> .cannon { transform-origin: 4px 55px; } </style> <g class="cannon" transform={`translate(236, 700) rotate(${$angle})`}> <rect width="8" height="60" fill="#212121" /> </g>
рдпрд╣ App.svelte рдШрдЯрдХ рдореЗрдВ рд╣рдорд╛рд░реЗ рдЧреЗрдо рд▓реВрдк рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╣реБрдЖ рд╣реИред
import { startGame } from "./gameLoop/gameLoop"; startGame();
App.svelte <script> import Controls from "./components/Controls.svelte"; import GameField from "./components/GameField.svelte"; </script> <style> :global(html) { height: 100%; } :global(body) { height: 100%; overscroll-behavior: none; user-select: none; margin: 0; background-color: #efefef; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; } </style> <Controls /> <GameField />
рд╣реБрд░реНрд░реЗ! рд╣рдорд╛рд░реА рдмрдВрджреВрдХ рдЪрд▓рдиреЗ рд▓рдЧреАред

6. рд╢реЙрдЯреНрд╕
рдЕрдм рд╣рдорд╛рд░реА рдмрдВрджреВрдХ рдХреЛ рдЧреЛрд▓реА рдорд╛рд░рдирд╛ рд╕рд┐рдЦрд╛рдПрдВред рд╣рдореЗрдВ рдореВрд▓реНрдпреЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
- рдХреНрдпрд╛ рдЕрдм рдмрдВрджреВрдХ рдХреА рдЧреЛрд▓реА рдЪрд▓рддреА рд╣реИ (рдлрд╛рдпрд░ рдмрдЯрди рджрдмрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ);
- рдЕрдВрддрд┐рдо рд╢реЙрдЯ рдХреЗ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдХреЛ рдЖрдЧ рдХреА рджрд░ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ;
- рдЧреЛрд▓реЗ рдХреА рдРрд░реЗред
рдЗрди рдЪрд░реЛрдВ рдХреЛ рд╣рдорд╛рд░реЗ src / store / cannon.js рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ ред
src / store / cannon.js import { writable } from 'svelte/store'; export const direction = writable(null); export const angle = writable(0);
рдЕрджреНрдпрддрди рдЖрдпрд╛рдд рдФрд░ рдЦреЗрд▓ рддрд░реНрдХ src / gameLoop / cannon.js рдореЗрдВ ред
src / gameLoop / cannon.js import { get } from 'svelte/store';
рдЕрдм рд╣рдо рдЕрдкрдиреЗ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдЧреЗрдорд▓реЛрдк.рдЬреЗрдПрд╕ рдореЗрдВ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЧреЗрдо рд▓реВрдк рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред
import { rotateCannon, shoot, moveBullet, clearBullets } from "./cannon"; export const startGame = () => { isPlaying.set(true); startLoop([rotateCannon, shoot, moveBullet, clearBullets ]); };
src / gameLoop / gameLoop.js import { isPlaying } from '../stores/game'; import { get } from 'svelte/store';
рдЕрдм рд╣рдореЗрдВ рдмрд╕ рдлрд╛рдпрд░ рдмрдЯрди рджрдмрд╛рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рддреИрдпрд╛рд░ рдХрд░рдиреА рд╣реИ рдФрд░ рдЦреЗрд▓ рдореИрджрд╛рди рдкрд░ рдЧреЛрд▓реЗ рдХрд╛ рдкреНрд░рджрд░реНрд╢рди рдЬреЛрдбрд╝рдирд╛ рд╣реИред
рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ src / Components / Controls.svelte ред
рдЕрдм рд╣рдорд╛рд░реЗ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдЕрдЧреНрдирд┐ рдирд┐рдпрдВрддреНрд░рдг рдмрдЯрди рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рд░реЛрдЯреЗрд╢рди рдмрдЯрди рдХреЗ рд╕рд╛рде рдХрд┐рдпрд╛ рдерд╛
<IconButton start={startFire} release={stopFire} active={$isFiring}> <Bullet /> </IconButton>
src / Components / Controls.svelte <script> import IconButton from "./IconButton.svelte"; import LeftArrow from "../assets/LeftArrow.svelte"; import RightArrow from "../assets/RightArrow.svelte"; import Bullet from "../assets/Bullet.svelte"; </script> <style> .controls { position: fixed; bottom: 0; left: 0; width: 100%; } .container { display: flex; justify-content: space-between; margin: 1rem; } .arrowGroup { display: flex; justify-content: space-between; width: 150px; } </style> <div class="controls"> <div class="container"> <div class="arrowGroup"> <IconButton start={setDirectionLeft} release={resetDirection} active={$direction === 'left'}> <LeftArrow /> </IconButton> <IconButton start={setDirectionRight} release={resetDirection} active={$direction === 'right'}> <RightArrow /> </IconButton> </div> <IconButton start={startFire} release={stopFire} active={$isFiring}> <Bullet /> </IconButton> </div> </div>
рдпрд╣ рдЦреЗрд▓ рдХреЗ рдореИрджрд╛рди рдкрд░ рдЧреЛрд▓реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдкреНрд░рдХреНрд╖реЗрдкреНрдп рдШрдЯрдХ рдмрдирд╛рдПрдВ
src / Components / Bullet.svelte <script> </script> <g transform={`translate(${bullet.x}, ${bullet.y}) rotate(${bullet.angle})`}> <rect width="3" height="5" fill="#212121" /> </g>
рдЪреВрдВрдХрд┐ рдЧреЛрд▓реЗ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╕рд░рдгреА рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЙрдиреНрд╣реЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред Svelte рдореЗрдВ рдРрд╕реЗ рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд░реНрджреЗрд╢ рд╣реИред рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА ред
// bulletList, bullet. // id , svelte , . // key React {#each $bulletList as bullet (bullet.id)} <Bullet {bullet}/> {/each}
src/components/GameField.svelte <script> import Cannon from "./Cannon.svelte"; </script> <style> .container { flex-grow: 1; display: flex; flex-direction: column; justify-content: flex-start; max-height: 100%; } </style> <div class="container"> <svg viewBox="0 0 480 800"> {#each $bulletList as bullet (bullet.id)} <Bullet {bullet} /> {/each} <Cannon /> </svg> </div>
.

7.
рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛ред . src/stores/enemy.js .
src/stores/enemy.js import { writable } from "svelte/store";
src/gameLoop/enemy.js
src/gameLoop/enemy.js import { get } from 'svelte/store';
.
src/gameLoop/gameLoop.js import { isPlaying } from '../stores/game'; import { get } from 'svelte/store'; import { rotateCannon, shoot, moveBullet, clearBullets } from './cannon';
src/components/Enemy.js .
src/components/Enemy.js <script> </script> // , . <g transform={`translate(${enemy.x}, ${enemy.y})`} > <rect width="30" height="30" fill="#212121" /> </g>
, Each
src/components/GameField.svelte <script> import Cannon from "./Cannon.svelte"; import Bullet from "./Bullet.svelte"; </script> <style> .container { flex-grow: 1; display: flex; flex-direction: column; justify-content: flex-start; max-height: 100%; } </style> <div class="container"> <svg viewBox="0 0 480 800"> {#each $enemyList as enemy (enemy.id)} <Enemy {enemy} /> {/each} {#each $bulletList as bullet (bullet.id)} <Bullet {bullet} /> {/each} <Cannon /> </svg> </div>
!

8.
, .
. src/gameLoop/game.js . MDN
src/gameLoop/game.js import { get } from 'svelte/store';
.
src/gameLoop/gameLoop.js import { isPlaying } from '../stores/game'; import { get } from 'svelte/store'; import { rotateCannon, shoot, moveBullet, clearBullets } from './cannon';
, .

9.
, ToDo :
github .
рдирд┐рд╖реНрдХрд░реНрд╖
, , React. 60 FPS, Svelte .
Svelte , .