ನೆಟ್‌ವರ್ಕ್ ಲೇಟೆನ್ಸಿ ಪರಿಹಾರ ಅಲ್ಗಾರಿದಮ್‌ನೊಂದಿಗೆ ಮೊಬೈಲ್ ಶೂಟರ್‌ಗಾಗಿ ನಾವು ಬ್ಯಾಲಿಸ್ಟಿಕ್ ಲೆಕ್ಕಾಚಾರಗಳ ಮೆಕ್ಯಾನಿಕ್ಸ್ ಅನ್ನು ಹೇಗೆ ಹೆಚ್ಚಿಸಿದ್ದೇವೆ

ನೆಟ್‌ವರ್ಕ್ ಲೇಟೆನ್ಸಿ ಪರಿಹಾರ ಅಲ್ಗಾರಿದಮ್‌ನೊಂದಿಗೆ ಮೊಬೈಲ್ ಶೂಟರ್‌ಗಾಗಿ ನಾವು ಬ್ಯಾಲಿಸ್ಟಿಕ್ ಲೆಕ್ಕಾಚಾರಗಳ ಮೆಕ್ಯಾನಿಕ್ಸ್ ಅನ್ನು ಹೇಗೆ ಹೆಚ್ಚಿಸಿದ್ದೇವೆ

ಹಾಯ್, ನಾನು ನಿಕಿತಾ ಬ್ರಿಝಾಕ್, ಪಿಕ್ಸೋನಿಕ್‌ನ ಸರ್ವರ್ ಡೆವಲಪರ್. ಇಂದು ನಾನು ಮೊಬೈಲ್ ಮಲ್ಟಿಪ್ಲೇಯರ್‌ನಲ್ಲಿ ವಿಳಂಬವನ್ನು ಸರಿದೂಗಿಸುವ ಬಗ್ಗೆ ಮಾತನಾಡಲು ಬಯಸುತ್ತೇನೆ.

ರಷ್ಯನ್ ಸೇರಿದಂತೆ ಸರ್ವರ್ ಲ್ಯಾಗ್ ಪರಿಹಾರದ ಬಗ್ಗೆ ಅನೇಕ ಲೇಖನಗಳನ್ನು ಬರೆಯಲಾಗಿದೆ. ಇದು ಆಶ್ಚರ್ಯವೇನಿಲ್ಲ, ಏಕೆಂದರೆ 90 ರ ದಶಕದ ಉತ್ತರಾರ್ಧದಿಂದ ಮಲ್ಟಿಪ್ಲೇಯರ್ ಎಫ್ಪಿಎಸ್ ರಚನೆಯಲ್ಲಿ ಈ ತಂತ್ರಜ್ಞಾನವನ್ನು ಸಕ್ರಿಯವಾಗಿ ಬಳಸಲಾಗಿದೆ. ಉದಾಹರಣೆಗೆ, ನೀವು ಕ್ವೇಕ್‌ವರ್ಲ್ಡ್ ಮೋಡ್ ಅನ್ನು ನೆನಪಿಸಿಕೊಳ್ಳಬಹುದು, ಅದನ್ನು ಬಳಸಿದ ಮೊದಲನೆಯದು.

ನಾವು ಅದನ್ನು ನಮ್ಮ ಮೊಬೈಲ್ ಮಲ್ಟಿಪ್ಲೇಯರ್ ಶೂಟರ್ ಡಿನೋ ಸ್ಕ್ವಾಡ್‌ನಲ್ಲಿಯೂ ಬಳಸುತ್ತೇವೆ.

ಈ ಲೇಖನದಲ್ಲಿ, ನನ್ನ ಗುರಿ ಈಗಾಗಲೇ ಸಾವಿರ ಬಾರಿ ಬರೆದದ್ದನ್ನು ಪುನರಾವರ್ತಿಸುವುದು ಅಲ್ಲ, ಆದರೆ ನಮ್ಮ ತಂತ್ರಜ್ಞಾನದ ಸ್ಟಾಕ್ ಮತ್ತು ಪ್ರಮುಖ ಆಟದ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಗಣನೆಗೆ ತೆಗೆದುಕೊಂಡು ನಮ್ಮ ಆಟದಲ್ಲಿ ನಾವು ವಿಳಂಬ ಪರಿಹಾರವನ್ನು ಹೇಗೆ ಅಳವಡಿಸಿದ್ದೇವೆ ಎಂದು ಹೇಳುವುದು.

ನಮ್ಮ ಕಾರ್ಟೆಕ್ಸ್ ಮತ್ತು ತಂತ್ರಜ್ಞಾನದ ಬಗ್ಗೆ ಕೆಲವು ಪದಗಳು.

ಡಿನೋ ಸ್ಕ್ವಾಡ್ ನೆಟ್‌ವರ್ಕ್ ಮೊಬೈಲ್ PvP ಶೂಟರ್ ಆಗಿದೆ. ಆಟಗಾರರು ವಿವಿಧ ಶಸ್ತ್ರಾಸ್ತ್ರಗಳನ್ನು ಹೊಂದಿದ ಡೈನೋಸಾರ್‌ಗಳನ್ನು ನಿಯಂತ್ರಿಸುತ್ತಾರೆ ಮತ್ತು 6v6 ತಂಡಗಳಲ್ಲಿ ಪರಸ್ಪರ ಹೋರಾಡುತ್ತಾರೆ.

ಕ್ಲೈಂಟ್ ಮತ್ತು ಸರ್ವರ್ ಎರಡೂ ಏಕತೆಯನ್ನು ಆಧರಿಸಿವೆ. ವಾಸ್ತುಶೈಲಿಯು ಶೂಟರ್‌ಗಳಿಗೆ ಸಾಕಷ್ಟು ಶ್ರೇಷ್ಠವಾಗಿದೆ: ಸರ್ವರ್ ಸರ್ವಾಧಿಕಾರಿಯಾಗಿದೆ ಮತ್ತು ಕ್ಲೈಂಟ್ ಭವಿಷ್ಯವು ಕ್ಲೈಂಟ್‌ಗಳ ಮೇಲೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ. ಆಟದ ಸಿಮ್ಯುಲೇಶನ್ ಅನ್ನು ಆಂತರಿಕ ಇಸಿಎಸ್ ಬಳಸಿ ಬರೆಯಲಾಗಿದೆ ಮತ್ತು ಸರ್ವರ್ ಮತ್ತು ಕ್ಲೈಂಟ್ ಎರಡರಲ್ಲೂ ಬಳಸಲಾಗುತ್ತದೆ.

ವಿಳಂಬ ಪರಿಹಾರದ ಕುರಿತು ನೀವು ಮೊದಲ ಬಾರಿಗೆ ಕೇಳಿದ್ದರೆ, ಸಮಸ್ಯೆಯ ಕುರಿತು ಸಂಕ್ಷಿಪ್ತ ವಿಹಾರ ಇಲ್ಲಿದೆ.

ಮಲ್ಟಿಪ್ಲೇಯರ್ FPS ಆಟಗಳಲ್ಲಿ, ಪಂದ್ಯವನ್ನು ಸಾಮಾನ್ಯವಾಗಿ ರಿಮೋಟ್ ಸರ್ವರ್‌ನಲ್ಲಿ ಅನುಕರಿಸಲಾಗುತ್ತದೆ. ಆಟಗಾರರು ತಮ್ಮ ಇನ್‌ಪುಟ್ ಅನ್ನು (ಒತ್ತಿದ ಕೀಗಳ ಬಗ್ಗೆ ಮಾಹಿತಿ) ಸರ್ವರ್‌ಗೆ ಕಳುಹಿಸುತ್ತಾರೆ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆಯಾಗಿ ಸರ್ವರ್ ಸ್ವೀಕರಿಸಿದ ಡೇಟಾವನ್ನು ಗಣನೆಗೆ ತೆಗೆದುಕೊಂಡು ನವೀಕರಿಸಿದ ಆಟದ ಸ್ಥಿತಿಯನ್ನು ಕಳುಹಿಸುತ್ತದೆ. ಈ ಸಂವಾದ ಯೋಜನೆಯೊಂದಿಗೆ, ಫಾರ್ವರ್ಡ್ ಕೀಯನ್ನು ಒತ್ತುವ ಮತ್ತು ಪ್ಲೇಯರ್ ಪಾತ್ರವು ಪರದೆಯ ಮೇಲೆ ಚಲಿಸುವ ಕ್ಷಣದ ನಡುವಿನ ವಿಳಂಬವು ಯಾವಾಗಲೂ ಪಿಂಗ್‌ಗಿಂತ ಹೆಚ್ಚಾಗಿರುತ್ತದೆ.

ಸ್ಥಳೀಯ ನೆಟ್‌ವರ್ಕ್‌ಗಳಲ್ಲಿ ಈ ವಿಳಂಬವನ್ನು (ಜನಪ್ರಿಯವಾಗಿ ಇನ್‌ಪುಟ್ ಲ್ಯಾಗ್ ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ) ಗಮನಿಸದೇ ಇರಬಹುದು, ಇಂಟರ್ನೆಟ್ ಮೂಲಕ ಆಡುವಾಗ ಅದು ಪಾತ್ರವನ್ನು ನಿಯಂತ್ರಿಸುವಾಗ "ಐಸ್ ಮೇಲೆ ಸ್ಲೈಡಿಂಗ್" ಎಂಬ ಭಾವನೆಯನ್ನು ಉಂಟುಮಾಡುತ್ತದೆ. ಈ ಸಮಸ್ಯೆಯು ಮೊಬೈಲ್ ನೆಟ್‌ವರ್ಕ್‌ಗಳಿಗೆ ದ್ವಿಗುಣವಾಗಿ ಪ್ರಸ್ತುತವಾಗಿದೆ, ಅಲ್ಲಿ ಆಟಗಾರನ ಪಿಂಗ್ 200 ಎಂಎಸ್ ಆಗಿರುವ ಸಂದರ್ಭವನ್ನು ಇನ್ನೂ ಅತ್ಯುತ್ತಮ ಸಂಪರ್ಕವೆಂದು ಪರಿಗಣಿಸಲಾಗುತ್ತದೆ. ಸಾಮಾನ್ಯವಾಗಿ ಪಿಂಗ್ 350, 500, ಅಥವಾ 1000 ms ಆಗಿರಬಹುದು. ನಂತರ ಇನ್‌ಪುಟ್ ಲ್ಯಾಗ್‌ನೊಂದಿಗೆ ವೇಗದ ಶೂಟರ್ ಅನ್ನು ಆಡಲು ಅಸಾಧ್ಯವಾಗುತ್ತದೆ.

ಈ ಸಮಸ್ಯೆಗೆ ಪರಿಹಾರವೆಂದರೆ ಕ್ಲೈಂಟ್-ಸೈಡ್ ಸಿಮ್ಯುಲೇಶನ್ ಭವಿಷ್ಯ. ಇಲ್ಲಿ ಕ್ಲೈಂಟ್ ಸ್ವತಃ ಆಟಗಾರನ ಪಾತ್ರಕ್ಕೆ ಇನ್ಪುಟ್ ಅನ್ನು ಅನ್ವಯಿಸುತ್ತದೆ, ಸರ್ವರ್ನಿಂದ ಪ್ರತಿಕ್ರಿಯೆಗಾಗಿ ಕಾಯದೆ. ಮತ್ತು ಉತ್ತರವನ್ನು ಸ್ವೀಕರಿಸಿದಾಗ, ಅದು ಫಲಿತಾಂಶಗಳನ್ನು ಸರಳವಾಗಿ ಹೋಲಿಸುತ್ತದೆ ಮತ್ತು ಎದುರಾಳಿಗಳ ಸ್ಥಾನಗಳನ್ನು ನವೀಕರಿಸುತ್ತದೆ. ಈ ಸಂದರ್ಭದಲ್ಲಿ ಕೀಲಿಯನ್ನು ಒತ್ತುವ ಮತ್ತು ಫಲಿತಾಂಶವನ್ನು ಪರದೆಯ ಮೇಲೆ ಪ್ರದರ್ಶಿಸುವ ನಡುವಿನ ವಿಳಂಬವು ಕಡಿಮೆಯಾಗಿದೆ.

ಇಲ್ಲಿ ಸೂಕ್ಷ್ಮ ವ್ಯತ್ಯಾಸವನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ಬಹಳ ಮುಖ್ಯ: ಕ್ಲೈಂಟ್ ಯಾವಾಗಲೂ ತನ್ನ ಕೊನೆಯ ಇನ್ಪುಟ್ ಪ್ರಕಾರ ಸ್ವತಃ ಸೆಳೆಯುತ್ತದೆ, ಮತ್ತು ಶತ್ರುಗಳು - ನೆಟ್ವರ್ಕ್ ವಿಳಂಬದೊಂದಿಗೆ, ಸರ್ವರ್ನಿಂದ ಡೇಟಾದಿಂದ ಹಿಂದಿನ ಸ್ಥಿತಿಯ ಪ್ರಕಾರ. ಅಂದರೆ, ಶತ್ರುಗಳ ಮೇಲೆ ಗುಂಡು ಹಾರಿಸುವಾಗ, ಆಟಗಾರನು ತನಗೆ ಹೋಲಿಸಿದರೆ ಹಿಂದೆ ಅವನನ್ನು ನೋಡುತ್ತಾನೆ. ಕ್ಲೈಂಟ್ ಭವಿಷ್ಯ ಕುರಿತು ಇನ್ನಷ್ಟು ನಾವು ಮೊದಲೇ ಬರೆದಿದ್ದೇವೆ.

ಹೀಗಾಗಿ, ಕ್ಲೈಂಟ್ ಭವಿಷ್ಯವು ಒಂದು ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸುತ್ತದೆ, ಆದರೆ ಇನ್ನೊಂದನ್ನು ಸೃಷ್ಟಿಸುತ್ತದೆ: ಆಟಗಾರನು ಹಿಂದೆ ಶತ್ರು ಇದ್ದ ಸ್ಥಳದಲ್ಲಿ ಶೂಟ್ ಮಾಡಿದರೆ, ಅದೇ ಹಂತದಲ್ಲಿ ಶೂಟ್ ಮಾಡುವಾಗ ಸರ್ವರ್‌ನಲ್ಲಿ, ಶತ್ರು ಇನ್ನು ಮುಂದೆ ಆ ಸ್ಥಳದಲ್ಲಿ ಇರುವುದಿಲ್ಲ. ಸರ್ವರ್ ಲ್ಯಾಗ್ ಪರಿಹಾರವು ಈ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ಆಯುಧವನ್ನು ಹಾರಿಸಿದಾಗ, ಹೊಡೆತದ ಸಮಯದಲ್ಲಿ ಆಟಗಾರನು ಸ್ಥಳೀಯವಾಗಿ ನೋಡಿದ ಆಟದ ಸ್ಥಿತಿಯನ್ನು ಸರ್ವರ್ ಮರುಸ್ಥಾಪಿಸುತ್ತದೆ ಮತ್ತು ಅವನು ನಿಜವಾಗಿಯೂ ಶತ್ರುವನ್ನು ಹೊಡೆಯಬಹುದೇ ಎಂದು ಪರಿಶೀಲಿಸುತ್ತದೆ. ಉತ್ತರವು "ಹೌದು" ಆಗಿದ್ದರೆ, ಆ ಸಮಯದಲ್ಲಿ ಶತ್ರು ಸರ್ವರ್‌ನಲ್ಲಿ ಇಲ್ಲದಿದ್ದರೂ ಸಹ ಹಿಟ್ ಅನ್ನು ಎಣಿಸಲಾಗುತ್ತದೆ.

ಈ ಜ್ಞಾನದಿಂದ ಶಸ್ತ್ರಸಜ್ಜಿತವಾದ ನಾವು ಡಿನೋ ಸ್ಕ್ವಾಡ್‌ನಲ್ಲಿ ಸರ್ವರ್ ಲ್ಯಾಗ್ ಪರಿಹಾರವನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲು ಪ್ರಾರಂಭಿಸಿದ್ದೇವೆ. ಮೊದಲನೆಯದಾಗಿ, ಕ್ಲೈಂಟ್ ಕಂಡದ್ದನ್ನು ಸರ್ವರ್‌ನಲ್ಲಿ ಹೇಗೆ ಮರುಸ್ಥಾಪಿಸುವುದು ಎಂಬುದನ್ನು ನಾವು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಬೇಕಾಗಿತ್ತು? ಮತ್ತು ನಿಖರವಾಗಿ ಏನು ಪುನಃಸ್ಥಾಪಿಸಬೇಕು? ನಮ್ಮ ಆಟದಲ್ಲಿ, ಶಸ್ತ್ರಾಸ್ತ್ರಗಳು ಮತ್ತು ಸಾಮರ್ಥ್ಯಗಳಿಂದ ಹಿಟ್‌ಗಳನ್ನು ರೇಕಾಸ್ಟ್‌ಗಳು ಮತ್ತು ಓವರ್‌ಲೇಗಳ ಮೂಲಕ ಲೆಕ್ಕಹಾಕಲಾಗುತ್ತದೆ - ಅಂದರೆ, ಶತ್ರುಗಳ ಭೌತಿಕ ಕೊಲೈಡರ್‌ಗಳೊಂದಿಗಿನ ಸಂವಹನಗಳ ಮೂಲಕ. ಅಂತೆಯೇ, ಆಟಗಾರನು ಸ್ಥಳೀಯವಾಗಿ "ನೋಡಿದ" ಈ ಕೊಲೈಡರ್‌ಗಳ ಸ್ಥಾನವನ್ನು ನಾವು ಸರ್ವರ್‌ನಲ್ಲಿ ಪುನರುತ್ಪಾದಿಸಬೇಕಾಗಿದೆ. ಆ ಸಮಯದಲ್ಲಿ ನಾವು ಯುನಿಟಿ ಆವೃತ್ತಿ 2018.x ಅನ್ನು ಬಳಸುತ್ತಿದ್ದೆವು. ಭೌತಶಾಸ್ತ್ರದ API ಸ್ಥಿರವಾಗಿದೆ, ಭೌತಿಕ ಪ್ರಪಂಚವು ಒಂದೇ ಪ್ರತಿಯಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ. ಅದರ ಸ್ಥಿತಿಯನ್ನು ಉಳಿಸಲು ಮತ್ತು ನಂತರ ಅದನ್ನು ಪೆಟ್ಟಿಗೆಯಿಂದ ಪುನಃಸ್ಥಾಪಿಸಲು ಯಾವುದೇ ಮಾರ್ಗವಿಲ್ಲ. ಹಾಗಾದರೆ ಏನು ಮಾಡಬೇಕು?

ಪರಿಹಾರವು ಮೇಲ್ಮೈಯಲ್ಲಿದೆ; ಅದರ ಎಲ್ಲಾ ಅಂಶಗಳನ್ನು ಈಗಾಗಲೇ ಇತರ ಸಮಸ್ಯೆಗಳನ್ನು ಪರಿಹರಿಸಲು ನಾವು ಬಳಸಿದ್ದೇವೆ:

  1. ಪ್ರತಿ ಕ್ಲೈಂಟ್‌ಗೆ, ಅವರು ಕೀಗಳನ್ನು ಒತ್ತಿದಾಗ ಅವರು ಯಾವ ಸಮಯದಲ್ಲಿ ಎದುರಾಳಿಗಳನ್ನು ನೋಡಿದರು ಎಂಬುದನ್ನು ನಾವು ತಿಳಿದುಕೊಳ್ಳಬೇಕು. ನಾವು ಈಗಾಗಲೇ ಈ ಮಾಹಿತಿಯನ್ನು ಇನ್‌ಪುಟ್ ಪ್ಯಾಕೇಜ್‌ಗೆ ಬರೆದಿದ್ದೇವೆ ಮತ್ತು ಕ್ಲೈಂಟ್ ಭವಿಷ್ಯವನ್ನು ಸರಿಹೊಂದಿಸಲು ಅದನ್ನು ಬಳಸಿದ್ದೇವೆ.
  2. ನಾವು ಆಟದ ಸ್ಥಿತಿಗಳ ಇತಿಹಾಸವನ್ನು ಸಂಗ್ರಹಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ. ಅದರಲ್ಲಿಯೇ ನಾವು ನಮ್ಮ ವಿರೋಧಿಗಳ ಸ್ಥಾನಗಳನ್ನು (ಮತ್ತು ಆದ್ದರಿಂದ ಅವರ ಘರ್ಷಣೆದಾರರು) ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುತ್ತೇವೆ. ನಾವು ಈಗಾಗಲೇ ಸರ್ವರ್‌ನಲ್ಲಿ ರಾಜ್ಯದ ಇತಿಹಾಸವನ್ನು ಹೊಂದಿದ್ದೇವೆ, ನಾವು ಅದನ್ನು ನಿರ್ಮಿಸಲು ಬಳಸಿದ್ದೇವೆ ಡೆಲ್ಟಾಗಳು. ಸರಿಯಾದ ಸಮಯವನ್ನು ತಿಳಿದಿದ್ದರೆ, ನಾವು ಇತಿಹಾಸದಲ್ಲಿ ಸರಿಯಾದ ಸ್ಥಿತಿಯನ್ನು ಸುಲಭವಾಗಿ ಕಂಡುಕೊಳ್ಳಬಹುದು.
  3. ಈಗ ನಾವು ಇತಿಹಾಸದಿಂದ ಆಟದ ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿದ್ದೇವೆ, ನಾವು ಆಟಗಾರರ ಡೇಟಾವನ್ನು ಭೌತಿಕ ಪ್ರಪಂಚದ ಸ್ಥಿತಿಯೊಂದಿಗೆ ಸಿಂಕ್ರೊನೈಸ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ. ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಕೊಲೈಡರ್‌ಗಳು - ಸರಿಸಿ, ಕಾಣೆಯಾದವುಗಳು - ರಚಿಸಿ, ಅನಗತ್ಯವಾದವುಗಳು - ನಾಶಮಾಡು. ಈ ತರ್ಕವನ್ನು ಈಗಾಗಲೇ ಬರೆಯಲಾಗಿದೆ ಮತ್ತು ಹಲವಾರು ECS ವ್ಯವಸ್ಥೆಗಳನ್ನು ಒಳಗೊಂಡಿದೆ. ಒಂದು ಯೂನಿಟಿ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ ಹಲವಾರು ಆಟದ ಕೊಠಡಿಗಳನ್ನು ಹಿಡಿದಿಡಲು ನಾವು ಇದನ್ನು ಬಳಸಿದ್ದೇವೆ. ಮತ್ತು ಭೌತಿಕ ಪ್ರಪಂಚವು ಪ್ರತಿ ಪ್ರಕ್ರಿಯೆಗೆ ಒಂದಾಗಿರುವುದರಿಂದ, ಅದನ್ನು ಕೊಠಡಿಗಳ ನಡುವೆ ಮರುಬಳಕೆ ಮಾಡಬೇಕಾಗಿತ್ತು. ಸಿಮ್ಯುಲೇಶನ್‌ನ ಪ್ರತಿ ಟಿಕ್‌ಗೆ ಮೊದಲು, ನಾವು ಭೌತಿಕ ಪ್ರಪಂಚದ ಸ್ಥಿತಿಯನ್ನು "ಮರುಹೊಂದಿಸುತ್ತೇವೆ" ಮತ್ತು ಪ್ರಸ್ತುತ ಕೊಠಡಿಯ ಡೇಟಾದೊಂದಿಗೆ ಅದನ್ನು ಮರುಪ್ರಾರಂಭಿಸುತ್ತೇವೆ, ಬುದ್ಧಿವಂತ ಪೂಲಿಂಗ್ ಸಿಸ್ಟಮ್ ಮೂಲಕ ಸಾಧ್ಯವಾದಷ್ಟು ಯೂನಿಟಿ ಆಟದ ವಸ್ತುಗಳನ್ನು ಮರುಬಳಕೆ ಮಾಡಲು ಪ್ರಯತ್ನಿಸುತ್ತೇವೆ. ಹಿಂದಿನಿಂದಲೂ ಆಟದ ಸ್ಥಿತಿಗೆ ಅದೇ ತರ್ಕವನ್ನು ಆಹ್ವಾನಿಸುವುದು ಮಾತ್ರ ಉಳಿದಿದೆ.

ಈ ಎಲ್ಲಾ ಅಂಶಗಳನ್ನು ಒಟ್ಟಿಗೆ ಸೇರಿಸುವ ಮೂಲಕ, ನಾವು ಭೌತಿಕ ಪ್ರಪಂಚದ ಸ್ಥಿತಿಯನ್ನು ಸರಿಯಾದ ಕ್ಷಣಕ್ಕೆ ಹಿಂತಿರುಗಿಸುವ "ಸಮಯ ಯಂತ್ರ"ವನ್ನು ಪಡೆದುಕೊಂಡಿದ್ದೇವೆ. ಕೋಡ್ ಸರಳವಾಗಿದೆ:

public class TimeMachine : ITimeMachine
{
     //История игровых состояний
     private readonly IGameStateHistory _history;

     //Текущее игровое состояние на сервере
     private readonly ExecutableSystem[] _systems;

     //Набор систем, расставляющих коллайдеры в физическом мире 
     //по данным из игрового состояния
     private readonly GameState _presentState;

     public TimeMachine(IGameStateHistory history, GameState presentState, ExecutableSystem[] timeInitSystems)
     {
         _history = history; 
         _presentState = presentState;
         _systems = timeInitSystems;  
     }

     public GameState TravelToTime(int tick)
     {
         var pastState = tick == _presentState.Time ? _presentState : _history.Get(tick);
         foreach (var system in _systems)
         {
             system.Execute(pastState);
         }
         return pastState;
     }
}

ಹೊಡೆತಗಳು ಮತ್ತು ಸಾಮರ್ಥ್ಯಗಳನ್ನು ಸುಲಭವಾಗಿ ಸರಿದೂಗಿಸಲು ಈ ಯಂತ್ರವನ್ನು ಹೇಗೆ ಬಳಸುವುದು ಎಂದು ಲೆಕ್ಕಾಚಾರ ಮಾಡುವುದು ಮಾತ್ರ ಉಳಿದಿದೆ.

ಸರಳವಾದ ಸಂದರ್ಭದಲ್ಲಿ, ಯಂತ್ರಶಾಸ್ತ್ರವು ಒಂದೇ ಹಿಟ್‌ಸ್ಕ್ಯಾನ್ ಅನ್ನು ಆಧರಿಸಿದ್ದಾಗ, ಎಲ್ಲವೂ ಸ್ಪಷ್ಟವಾಗಿದೆ ಎಂದು ತೋರುತ್ತದೆ: ಆಟಗಾರನು ಶೂಟ್ ಮಾಡುವ ಮೊದಲು, ಅವನು ಭೌತಿಕ ಜಗತ್ತನ್ನು ಅಪೇಕ್ಷಿತ ಸ್ಥಿತಿಗೆ ಹಿಂತಿರುಗಿಸಬೇಕು, ರೇಕಾಸ್ಟ್ ಮಾಡಿ, ಹಿಟ್ ಅಥವಾ ಮಿಸ್ ಅನ್ನು ಎಣಿಸಬೇಕು ಮತ್ತು ಜಗತ್ತನ್ನು ಆರಂಭಿಕ ಸ್ಥಿತಿಗೆ ಹಿಂತಿರುಗಿ.

ಆದರೆ ಡಿನೋ ಸ್ಕ್ವಾಡ್‌ನಲ್ಲಿ ಅಂತಹ ಮೆಕ್ಯಾನಿಕ್‌ಗಳು ಬಹಳ ಕಡಿಮೆ! ಆಟದಲ್ಲಿನ ಹೆಚ್ಚಿನ ಆಯುಧಗಳು ಸ್ಪೋಟಕಗಳನ್ನು ರಚಿಸುತ್ತವೆ - ದೀರ್ಘಾವಧಿಯ ಬುಲೆಟ್‌ಗಳು ಹಲವಾರು ಸಿಮ್ಯುಲೇಶನ್ ಉಣ್ಣಿಗಳಿಗಾಗಿ ಹಾರುತ್ತವೆ (ಕೆಲವು ಸಂದರ್ಭಗಳಲ್ಲಿ, ಡಜನ್ಗಟ್ಟಲೆ ಉಣ್ಣಿ). ಅವರೊಂದಿಗೆ ಏನು ಮಾಡಬೇಕು, ಅವರು ಯಾವ ಸಮಯದಲ್ಲಿ ಹಾರಬೇಕು?

В ಪ್ರಾಚೀನ ಲೇಖನ ಹಾಫ್-ಲೈಫ್ ನೆಟ್‌ವರ್ಕ್ ಸ್ಟಾಕ್ ಬಗ್ಗೆ, ವಾಲ್ವ್‌ನ ವ್ಯಕ್ತಿಗಳು ಅದೇ ಪ್ರಶ್ನೆಯನ್ನು ಕೇಳಿದರು, ಮತ್ತು ಅವರ ಉತ್ತರ ಹೀಗಿತ್ತು: ಉತ್ಕ್ಷೇಪಕ ವಿಳಂಬ ಪರಿಹಾರವು ಸಮಸ್ಯಾತ್ಮಕವಾಗಿದೆ ಮತ್ತು ಅದನ್ನು ತಪ್ಪಿಸುವುದು ಉತ್ತಮ.

ನಾವು ಈ ಆಯ್ಕೆಯನ್ನು ಹೊಂದಿಲ್ಲ: ಉತ್ಕ್ಷೇಪಕ-ಆಧಾರಿತ ಶಸ್ತ್ರಾಸ್ತ್ರಗಳು ಆಟದ ವಿನ್ಯಾಸದ ಪ್ರಮುಖ ಲಕ್ಷಣವಾಗಿದೆ. ಆದ್ದರಿಂದ ನಾವು ಏನನ್ನಾದರೂ ತರಬೇಕಾಗಿತ್ತು. ಕೆಲವು ಬುದ್ದಿಮತ್ತೆಯ ನಂತರ, ನಾವು ಎರಡು ಆಯ್ಕೆಗಳನ್ನು ರೂಪಿಸಿದ್ದೇವೆ ಅದು ಕೆಲಸ ಮಾಡುತ್ತದೆ:

1. ನಾವು ಉತ್ಕ್ಷೇಪಕವನ್ನು ರಚಿಸಿದ ಆಟಗಾರನ ಸಮಯಕ್ಕೆ ಟೈ ಮಾಡುತ್ತೇವೆ. ಸರ್ವರ್ ಸಿಮ್ಯುಲೇಶನ್‌ನ ಪ್ರತಿ ಟಿಕ್, ಪ್ರತಿ ಆಟಗಾರನ ಪ್ರತಿ ಬುಲೆಟ್‌ಗೆ, ನಾವು ಭೌತಿಕ ಪ್ರಪಂಚವನ್ನು ಕ್ಲೈಂಟ್ ಸ್ಥಿತಿಗೆ ಹಿಂತಿರುಗಿಸುತ್ತೇವೆ ಮತ್ತು ಅಗತ್ಯ ಲೆಕ್ಕಾಚಾರಗಳನ್ನು ನಿರ್ವಹಿಸುತ್ತೇವೆ. ಈ ವಿಧಾನವು ಸರ್ವರ್‌ನಲ್ಲಿ ವಿತರಿಸಿದ ಲೋಡ್ ಅನ್ನು ಹೊಂದಲು ಮತ್ತು ಸ್ಪೋಟಕಗಳ ಹಾರಾಟದ ಸಮಯವನ್ನು ಊಹಿಸಲು ಸಾಧ್ಯವಾಗಿಸಿತು. ಕ್ಲೈಂಟ್‌ನಲ್ಲಿ ಶತ್ರು ಸ್ಪೋಟಕಗಳು ಸೇರಿದಂತೆ ಎಲ್ಲಾ ಸ್ಪೋಟಕಗಳನ್ನು ನಾವು ಹೊಂದಿರುವುದರಿಂದ ಭವಿಷ್ಯವು ನಮಗೆ ವಿಶೇಷವಾಗಿ ಮುಖ್ಯವಾಗಿದೆ.

ನೆಟ್‌ವರ್ಕ್ ಲೇಟೆನ್ಸಿ ಪರಿಹಾರ ಅಲ್ಗಾರಿದಮ್‌ನೊಂದಿಗೆ ಮೊಬೈಲ್ ಶೂಟರ್‌ಗಾಗಿ ನಾವು ಬ್ಯಾಲಿಸ್ಟಿಕ್ ಲೆಕ್ಕಾಚಾರಗಳ ಮೆಕ್ಯಾನಿಕ್ಸ್ ಅನ್ನು ಹೇಗೆ ಹೆಚ್ಚಿಸಿದ್ದೇವೆ
ಚಿತ್ರದಲ್ಲಿ, ಟಿಕ್ 30 ನಲ್ಲಿರುವ ಆಟಗಾರನು ನಿರೀಕ್ಷೆಯಲ್ಲಿ ಕ್ಷಿಪಣಿಯನ್ನು ಹಾರಿಸುತ್ತಾನೆ: ಶತ್ರು ಯಾವ ದಿಕ್ಕಿನಲ್ಲಿ ಓಡುತ್ತಿದ್ದಾನೆ ಮತ್ತು ಕ್ಷಿಪಣಿಯ ಅಂದಾಜು ವೇಗವನ್ನು ಅವನು ನೋಡುತ್ತಾನೆ. ಸ್ಥಳೀಯವಾಗಿ ಅವನು 33 ನೇ ಟಿಕ್‌ನಲ್ಲಿ ಗುರಿಯನ್ನು ಹೊಡೆಯುವುದನ್ನು ನೋಡುತ್ತಾನೆ. ವಿಳಂಬ ಪರಿಹಾರಕ್ಕೆ ಧನ್ಯವಾದಗಳು, ಇದು ಸರ್ವರ್‌ನಲ್ಲಿಯೂ ಸಹ ಗೋಚರಿಸುತ್ತದೆ

2. ನಾವು ಎಲ್ಲವನ್ನೂ ಮೊದಲ ಆಯ್ಕೆಯಲ್ಲಿರುವಂತೆಯೇ ಮಾಡುತ್ತೇವೆ, ಆದರೆ, ಬುಲೆಟ್ ಸಿಮ್ಯುಲೇಶನ್‌ನ ಒಂದು ಟಿಕ್ ಅನ್ನು ಎಣಿಸಿದ ನಂತರ, ನಾವು ನಿಲ್ಲುವುದಿಲ್ಲ, ಆದರೆ ಅದೇ ಸರ್ವರ್ ಟಿಕ್‌ನಲ್ಲಿ ಅದರ ಹಾರಾಟವನ್ನು ಅನುಕರಿಸುವುದನ್ನು ಮುಂದುವರಿಸುತ್ತೇವೆ, ಪ್ರತಿ ಬಾರಿ ಅದರ ಸಮಯವನ್ನು ಸರ್ವರ್‌ಗೆ ಹತ್ತಿರ ತರುತ್ತೇವೆ. ಒಂದೊಂದಾಗಿ ಟಿಕ್ ಮತ್ತು ಕೊಲೈಡರ್ ಸ್ಥಾನಗಳನ್ನು ನವೀಕರಿಸಲಾಗುತ್ತಿದೆ. ಎರಡು ವಿಷಯಗಳಲ್ಲಿ ಒಂದು ಸಂಭವಿಸುವವರೆಗೆ ನಾವು ಇದನ್ನು ಮಾಡುತ್ತೇವೆ:

  • ಬುಲೆಟ್ ಅವಧಿ ಮೀರಿದೆ. ಇದರರ್ಥ ಲೆಕ್ಕಾಚಾರಗಳು ಮುಗಿದಿವೆ, ನಾವು ಮಿಸ್ ಅಥವಾ ಹಿಟ್ ಅನ್ನು ಎಣಿಸಬಹುದು. ಮತ್ತು ಇದು ಗುಂಡು ಹಾರಿಸಿದ ಅದೇ ಟಿಕ್‌ನಲ್ಲಿದೆ! ನಮಗೆ ಇದು ಪ್ಲಸ್ ಮತ್ತು ಮೈನಸ್ ಎರಡೂ ಆಗಿತ್ತು. ಒಂದು ಪ್ಲಸ್ - ಏಕೆಂದರೆ ಶೂಟಿಂಗ್ ಆಟಗಾರನಿಗೆ ಇದು ಹಿಟ್ ಮತ್ತು ಶತ್ರುಗಳ ಆರೋಗ್ಯದಲ್ಲಿನ ಇಳಿಕೆ ನಡುವಿನ ವಿಳಂಬವನ್ನು ಗಮನಾರ್ಹವಾಗಿ ಕಡಿಮೆ ಮಾಡುತ್ತದೆ. ತೊಂದರೆಯೆಂದರೆ ಎದುರಾಳಿಗಳು ಆಟಗಾರನ ಮೇಲೆ ಗುಂಡು ಹಾರಿಸಿದಾಗ ಅದೇ ಪರಿಣಾಮವನ್ನು ಗಮನಿಸಲಾಯಿತು: ಶತ್ರು, ಅದು ತೋರುತ್ತದೆ, ಕೇವಲ ನಿಧಾನವಾದ ರಾಕೆಟ್ ಅನ್ನು ಹಾರಿಸಲಾಯಿತು ಮತ್ತು ಹಾನಿಯನ್ನು ಈಗಾಗಲೇ ಎಣಿಸಲಾಗಿದೆ.
  • ಬುಲೆಟ್ ಸರ್ವರ್ ಸಮಯವನ್ನು ತಲುಪಿದೆ. ಈ ಸಂದರ್ಭದಲ್ಲಿ, ಅದರ ಸಿಮ್ಯುಲೇಶನ್ ಯಾವುದೇ ವಿಳಂಬ ಪರಿಹಾರವಿಲ್ಲದೆ ಮುಂದಿನ ಸರ್ವರ್ ಟಿಕ್‌ನಲ್ಲಿ ಮುಂದುವರಿಯುತ್ತದೆ. ನಿಧಾನಗತಿಯ ಸ್ಪೋಟಕಗಳಿಗೆ, ಇದು ಮೊದಲ ಆಯ್ಕೆಗೆ ಹೋಲಿಸಿದರೆ ಭೌತಶಾಸ್ತ್ರದ ರೋಲ್‌ಬ್ಯಾಕ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಸೈದ್ಧಾಂತಿಕವಾಗಿ ಕಡಿಮೆ ಮಾಡುತ್ತದೆ. ಅದೇ ಸಮಯದಲ್ಲಿ, ಸಿಮ್ಯುಲೇಶನ್‌ನಲ್ಲಿ ಅಸಮ ಲೋಡ್ ಹೆಚ್ಚಾಯಿತು: ಸರ್ವರ್ ನಿಷ್ಕ್ರಿಯವಾಗಿದೆ, ಅಥವಾ ಒಂದು ಸರ್ವರ್ ಟಿಕ್‌ನಲ್ಲಿ ಅದು ಹಲವಾರು ಬುಲೆಟ್‌ಗಳಿಗೆ ಡಜನ್ ಸಿಮ್ಯುಲೇಶನ್ ಟಿಕ್‌ಗಳನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡುತ್ತಿದೆ.

ನೆಟ್‌ವರ್ಕ್ ಲೇಟೆನ್ಸಿ ಪರಿಹಾರ ಅಲ್ಗಾರಿದಮ್‌ನೊಂದಿಗೆ ಮೊಬೈಲ್ ಶೂಟರ್‌ಗಾಗಿ ನಾವು ಬ್ಯಾಲಿಸ್ಟಿಕ್ ಲೆಕ್ಕಾಚಾರಗಳ ಮೆಕ್ಯಾನಿಕ್ಸ್ ಅನ್ನು ಹೇಗೆ ಹೆಚ್ಚಿಸಿದ್ದೇವೆ
ಹಿಂದಿನ ಚಿತ್ರದಲ್ಲಿನ ಅದೇ ಸನ್ನಿವೇಶ, ಆದರೆ ಎರಡನೇ ಯೋಜನೆಯ ಪ್ರಕಾರ ಲೆಕ್ಕಹಾಕಲಾಗಿದೆ. ಶಾಟ್ ಸಂಭವಿಸಿದ ಅದೇ ಟಿಕ್‌ನಲ್ಲಿ ಕ್ಷಿಪಣಿಯು ಸರ್ವರ್ ಸಮಯದೊಂದಿಗೆ "ಕ್ಯಾಚ್ ಅಪ್" ಆಗಿದೆ ಮತ್ತು ಮುಂದಿನ ಟಿಕ್‌ನಂತೆಯೇ ಹಿಟ್ ಅನ್ನು ಎಣಿಸಬಹುದು. 31 ನೇ ಟಿಕ್‌ನಲ್ಲಿ, ಈ ಸಂದರ್ಭದಲ್ಲಿ, ವಿಳಂಬ ಪರಿಹಾರವನ್ನು ಇನ್ನು ಮುಂದೆ ಅನ್ವಯಿಸಲಾಗುವುದಿಲ್ಲ

ನಮ್ಮ ಅನುಷ್ಠಾನದಲ್ಲಿ, ಈ ಎರಡು ವಿಧಾನಗಳು ಕೋಡ್‌ನ ಕೇವಲ ಒಂದೆರಡು ಸಾಲುಗಳಲ್ಲಿ ಭಿನ್ನವಾಗಿವೆ, ಆದ್ದರಿಂದ ನಾವು ಎರಡನ್ನೂ ರಚಿಸಿದ್ದೇವೆ ಮತ್ತು ದೀರ್ಘಕಾಲದವರೆಗೆ ಅವು ಸಮಾನಾಂತರವಾಗಿ ಅಸ್ತಿತ್ವದಲ್ಲಿವೆ. ಆಯುಧದ ಯಂತ್ರಶಾಸ್ತ್ರ ಮತ್ತು ಗುಂಡಿನ ವೇಗವನ್ನು ಅವಲಂಬಿಸಿ, ನಾವು ಪ್ರತಿ ಡೈನೋಸಾರ್‌ಗೆ ಒಂದು ಅಥವಾ ಇನ್ನೊಂದು ಆಯ್ಕೆಯನ್ನು ಆರಿಸಿದ್ದೇವೆ. "ಇಂತಹ ಸಮಯದಲ್ಲಿ ನೀವು ಶತ್ರುಗಳನ್ನು ಹಲವು ಬಾರಿ ಹೊಡೆದರೆ, ಅಂತಹ ಮತ್ತು ಅಂತಹ ಬೋನಸ್ ಪಡೆಯಿರಿ" ಎಂಬಂತಹ ಯಂತ್ರಶಾಸ್ತ್ರದ ಆಟದಲ್ಲಿ ಕಾಣಿಸಿಕೊಂಡಿರುವುದು ಇಲ್ಲಿ ಮಹತ್ವದ ತಿರುವು. ಆಟಗಾರನು ಶತ್ರುವನ್ನು ಹೊಡೆದ ಸಮಯವು ಪ್ರಮುಖ ಪಾತ್ರವನ್ನು ವಹಿಸಿದ ಯಾವುದೇ ಮೆಕ್ಯಾನಿಕ್ ಎರಡನೇ ವಿಧಾನದೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ನಿರಾಕರಿಸಿತು. ಆದ್ದರಿಂದ ನಾವು ಮೊದಲ ಆಯ್ಕೆಯೊಂದಿಗೆ ಹೋಗುವುದನ್ನು ಕೊನೆಗೊಳಿಸಿದ್ದೇವೆ ಮತ್ತು ಇದು ಈಗ ಎಲ್ಲಾ ಶಸ್ತ್ರಾಸ್ತ್ರಗಳು ಮತ್ತು ಆಟದಲ್ಲಿನ ಎಲ್ಲಾ ಸಕ್ರಿಯ ಸಾಮರ್ಥ್ಯಗಳಿಗೆ ಅನ್ವಯಿಸುತ್ತದೆ.

ಪ್ರತ್ಯೇಕವಾಗಿ, ಕಾರ್ಯಕ್ಷಮತೆಯ ಸಮಸ್ಯೆಯನ್ನು ಹೆಚ್ಚಿಸುವುದು ಯೋಗ್ಯವಾಗಿದೆ. ಇದೆಲ್ಲವೂ ನಿಧಾನವಾಗುತ್ತದೆ ಎಂದು ನೀವು ಭಾವಿಸಿದರೆ, ನಾನು ಉತ್ತರಿಸುತ್ತೇನೆ: ಅದು. ಘರ್ಷಣೆಯನ್ನು ಚಲಿಸುವಲ್ಲಿ ಮತ್ತು ಅವುಗಳನ್ನು ಆನ್ ಮತ್ತು ಆಫ್ ಮಾಡುವಲ್ಲಿ ಏಕತೆ ಸಾಕಷ್ಟು ನಿಧಾನವಾಗಿದೆ. ಡಿನೋ ಸ್ಕ್ವಾಡ್‌ನಲ್ಲಿ, "ಕೆಟ್ಟ" ಸಂದರ್ಭದಲ್ಲಿ, ಹಲವಾರು ನೂರು ಸ್ಪೋಟಕಗಳು ಏಕಕಾಲದಲ್ಲಿ ಯುದ್ಧದಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿರಬಹುದು. ಪ್ರತಿ ಉತ್ಕ್ಷೇಪಕವನ್ನು ಪ್ರತ್ಯೇಕವಾಗಿ ಎಣಿಸಲು ಕೊಲೈಡರ್‌ಗಳನ್ನು ಚಲಿಸುವುದು ಕೈಗೆಟುಕಲಾಗದ ಐಷಾರಾಮಿ. ಆದ್ದರಿಂದ, ಭೌತಶಾಸ್ತ್ರ "ರೋಲ್ಬ್ಯಾಕ್" ಸಂಖ್ಯೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಲು ನಮಗೆ ಸಂಪೂರ್ಣವಾಗಿ ಅಗತ್ಯವಾಗಿತ್ತು. ಇದನ್ನು ಮಾಡಲು, ನಾವು ECS ನಲ್ಲಿ ಪ್ರತ್ಯೇಕ ಘಟಕವನ್ನು ರಚಿಸಿದ್ದೇವೆ ಅದರಲ್ಲಿ ನಾವು ಆಟಗಾರನ ಸಮಯವನ್ನು ದಾಖಲಿಸುತ್ತೇವೆ. ವಿಳಂಬ ಪರಿಹಾರದ ಅಗತ್ಯವಿರುವ ಎಲ್ಲಾ ಘಟಕಗಳಿಗೆ ನಾವು ಅದನ್ನು ಸೇರಿಸಿದ್ದೇವೆ (ಯೋಜನೆಗಳು, ಸಾಮರ್ಥ್ಯಗಳು, ಇತ್ಯಾದಿ.). ನಾವು ಅಂತಹ ಘಟಕಗಳನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಪ್ರಾರಂಭಿಸುವ ಮೊದಲು, ನಾವು ಈ ಸಮಯದಲ್ಲಿ ಅವುಗಳನ್ನು ಕ್ಲಸ್ಟರ್ ಮಾಡುತ್ತೇವೆ ಮತ್ತು ಅವುಗಳನ್ನು ಒಟ್ಟಿಗೆ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುತ್ತೇವೆ, ಪ್ರತಿ ಕ್ಲಸ್ಟರ್‌ಗೆ ಒಮ್ಮೆ ಭೌತಿಕ ಪ್ರಪಂಚವನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತೇವೆ.

ಈ ಹಂತದಲ್ಲಿ ನಾವು ಸಾಮಾನ್ಯವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವ ವ್ಯವಸ್ಥೆಯನ್ನು ಹೊಂದಿದ್ದೇವೆ. ಇದರ ಕೋಡ್ ಸ್ವಲ್ಪ ಸರಳೀಕೃತ ರೂಪದಲ್ಲಿದೆ:

public sealed class LagCompensationSystemGroup : ExecutableSystem
{
     //Машина времени
     private readonly ITimeMachine _timeMachine;

     //Набор систем лагкомпенсации
     private readonly LagCompensationSystem[] _systems;
     
     //Наша реализация кластеризатора
     private readonly TimeTravelMap _travelMap = new TimeTravelMap();

    public LagCompensationSystemGroup(ITimeMachine timeMachine, 
        LagCompensationSystem[] lagCompensationSystems)
     {
         _timeMachine = timeMachine;
         _systems = lagCompensationSystems;
     }

     public override void Execute(GameState gs)
     {
         //На вход кластеризатор принимает текущее игровое состояние,
         //а на выход выдает набор «корзин». В каждой корзине лежат энтити,
         //которым для лагкомпенсации нужно одно и то же время из истории.
         var buckets = _travelMap.RefillBuckets(gs);

         for (int bucketIndex = 0; bucketIndex < buckets.Count; bucketIndex++)
         {
             ProcessBucket(gs, buckets[bucketIndex]);
         }

         //В конце лагкомпенсации мы восстанавливаем физический мир 
         //в исходное состояние
         _timeMachine.TravelToTime(gs.Time);
     }

     private void ProcessBucket(GameState presentState, TimeTravelMap.Bucket bucket)
     {
         //Откатываем время один раз для каждой корзины
         var pastState = _timeMachine.TravelToTime(bucket.Time);

         foreach (var system in _systems)
         {
               system.PastState = pastState;
               system.PresentState = presentState;

               foreach (var entity in bucket)
               {
                   system.Execute(entity);
               }
          }
     }
}

ವಿವರಗಳನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡುವುದು ಮಾತ್ರ ಉಳಿದಿದೆ:

1. ಸಮಯದಲ್ಲಿ ಚಲನೆಯ ಗರಿಷ್ಠ ಅಂತರವನ್ನು ಎಷ್ಟು ಮಿತಿಗೊಳಿಸಬೇಕು ಎಂಬುದನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಿ.

ಕಳಪೆ ಮೊಬೈಲ್ ನೆಟ್‌ವರ್ಕ್‌ಗಳ ಪರಿಸ್ಥಿತಿಗಳಲ್ಲಿ ಆಟವನ್ನು ಸಾಧ್ಯವಾದಷ್ಟು ಪ್ರವೇಶಿಸುವಂತೆ ಮಾಡುವುದು ನಮಗೆ ಮುಖ್ಯವಾಗಿದೆ, ಆದ್ದರಿಂದ ನಾವು ಕಥೆಯನ್ನು 30 ಟಿಕ್‌ಗಳ ಅಂಚುಗಳೊಂದಿಗೆ (20 Hz ಟಿಕ್ ದರದೊಂದಿಗೆ) ಸೀಮಿತಗೊಳಿಸಿದ್ದೇವೆ. ಇದು ಆಟಗಾರರು ಅತಿ ಹೆಚ್ಚು ಪಿಂಗ್‌ಗಳಲ್ಲಿಯೂ ಎದುರಾಳಿಗಳನ್ನು ಹೊಡೆಯಲು ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ.

2. ಯಾವ ವಸ್ತುಗಳನ್ನು ಸಮಯಕ್ಕೆ ಸರಿಸಬಹುದೆಂದು ಮತ್ತು ಯಾವುದು ಸಾಧ್ಯವಿಲ್ಲ ಎಂಬುದನ್ನು ನಿರ್ಧರಿಸಿ.

ನಾವು, ಸಹಜವಾಗಿ, ನಮ್ಮ ವಿರೋಧಿಗಳನ್ನು ಚಲಿಸುತ್ತಿದ್ದೇವೆ. ಆದರೆ ಸ್ಥಾಪಿಸಬಹುದಾದ ಶಕ್ತಿ ಗುರಾಣಿಗಳು, ಉದಾಹರಣೆಗೆ, ಅಲ್ಲ. ಆನ್‌ಲೈನ್ ಶೂಟರ್‌ಗಳಲ್ಲಿ ಸಾಮಾನ್ಯವಾಗಿ ಮಾಡುವಂತೆ ರಕ್ಷಣಾತ್ಮಕ ಸಾಮರ್ಥ್ಯಕ್ಕೆ ಆದ್ಯತೆ ನೀಡುವುದು ಉತ್ತಮ ಎಂದು ನಾವು ನಿರ್ಧರಿಸಿದ್ದೇವೆ. ಆಟಗಾರನು ವರ್ತಮಾನದಲ್ಲಿ ಈಗಾಗಲೇ ಶೀಲ್ಡ್ ಅನ್ನು ಇರಿಸಿದ್ದರೆ, ಹಿಂದಿನಿಂದ ವಿಳಂಬ-ಪರಿಹಾರ ಗುಂಡುಗಳು ಅದರ ಮೂಲಕ ಹಾರಬಾರದು.

3. ಡೈನೋಸಾರ್‌ಗಳ ಸಾಮರ್ಥ್ಯಗಳನ್ನು ಸರಿದೂಗಿಸಲು ಅಗತ್ಯವಿದೆಯೇ ಎಂದು ನಿರ್ಧರಿಸಿ: ಕಚ್ಚುವುದು, ಬಾಲ ಮುಷ್ಕರ, ಇತ್ಯಾದಿ. ನಾವು ಬೇಕಾದುದನ್ನು ನಿರ್ಧರಿಸಿದ್ದೇವೆ ಮತ್ತು ಬುಲೆಟ್‌ಗಳಂತೆಯೇ ಅದೇ ನಿಯಮಗಳ ಪ್ರಕಾರ ಅವುಗಳನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುತ್ತೇವೆ.

4. ಮಂದಗತಿಯ ಪರಿಹಾರವನ್ನು ನಿರ್ವಹಿಸುವ ಆಟಗಾರನ ಕೊಲೈಡರ್‌ಗಳೊಂದಿಗೆ ಏನು ಮಾಡಬೇಕೆಂದು ನಿರ್ಧರಿಸಿ. ಉತ್ತಮ ರೀತಿಯಲ್ಲಿ, ಅವರ ಸ್ಥಾನವು ಹಿಂದಿನದಕ್ಕೆ ಬದಲಾಗಬಾರದು: ಆಟಗಾರನು ಈಗ ಸರ್ವರ್‌ನಲ್ಲಿರುವ ಅದೇ ಸಮಯದಲ್ಲಿ ತನ್ನನ್ನು ನೋಡಬೇಕು. ಆದಾಗ್ಯೂ, ನಾವು ಶೂಟಿಂಗ್ ಪ್ಲೇಯರ್‌ನ ಕೊಲೈಡರ್‌ಗಳನ್ನು ಸಹ ಹಿಂತಿರುಗಿಸುತ್ತೇವೆ ಮತ್ತು ಇದಕ್ಕೆ ಹಲವಾರು ಕಾರಣಗಳಿವೆ.

ಮೊದಲನೆಯದಾಗಿ, ಇದು ಕ್ಲಸ್ಟರಿಂಗ್ ಅನ್ನು ಸುಧಾರಿಸುತ್ತದೆ: ನಿಕಟ ಪಿಂಗ್ಗಳೊಂದಿಗೆ ಎಲ್ಲಾ ಆಟಗಾರರಿಗೆ ನಾವು ಒಂದೇ ಭೌತಿಕ ಸ್ಥಿತಿಯನ್ನು ಬಳಸಬಹುದು.

ಎರಡನೆಯದಾಗಿ, ಎಲ್ಲಾ ರೇಕಾಸ್ಟ್‌ಗಳು ಮತ್ತು ಅತಿಕ್ರಮಣಗಳಲ್ಲಿ ನಾವು ಯಾವಾಗಲೂ ಸಾಮರ್ಥ್ಯಗಳು ಅಥವಾ ಸ್ಪೋಟಕಗಳನ್ನು ಹೊಂದಿರುವ ಆಟಗಾರನ ಕೊಲೈಡರ್‌ಗಳನ್ನು ಹೊರತುಪಡಿಸುತ್ತೇವೆ. ಡಿನೋ ಸ್ಕ್ವಾಡ್‌ನಲ್ಲಿ, ಆಟಗಾರರು ಡೈನೋಸಾರ್‌ಗಳನ್ನು ನಿಯಂತ್ರಿಸುತ್ತಾರೆ, ಇದು ಶೂಟರ್ ಮಾನದಂಡಗಳ ಮೂಲಕ ಪ್ರಮಾಣಿತವಲ್ಲದ ರೇಖಾಗಣಿತವನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಆಟಗಾರನು ಅಸಾಮಾನ್ಯ ಕೋನದಲ್ಲಿ ಗುಂಡು ಹಾರಿಸಿದರೂ ಮತ್ತು ಬುಲೆಟ್‌ನ ಪಥವು ಆಟಗಾರನ ಡೈನೋಸಾರ್ ಕೊಲೈಡರ್ ಮೂಲಕ ಹಾದು ಹೋದರೂ, ಬುಲೆಟ್ ಅದನ್ನು ನಿರ್ಲಕ್ಷಿಸುತ್ತದೆ.

ಮೂರನೆಯದಾಗಿ, ನಾವು ಡೈನೋಸಾರ್‌ನ ಆಯುಧದ ಸ್ಥಾನಗಳನ್ನು ಅಥವಾ ಮಂದಗತಿಯ ಪರಿಹಾರವನ್ನು ಪ್ರಾರಂಭಿಸುವ ಮೊದಲು ಇಸಿಎಸ್‌ನಿಂದ ಡೇಟಾವನ್ನು ಬಳಸಿಕೊಂಡು ಸಾಮರ್ಥ್ಯವನ್ನು ಅನ್ವಯಿಸುವ ಬಿಂದುವನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡುತ್ತೇವೆ.

ಪರಿಣಾಮವಾಗಿ, ಮಂದಗತಿ-ಪರಿಹಾರ ಆಟಗಾರನ ಕೊಲೈಡರ್ಗಳ ನೈಜ ಸ್ಥಾನವು ನಮಗೆ ಮುಖ್ಯವಲ್ಲ, ಆದ್ದರಿಂದ ನಾವು ಹೆಚ್ಚು ಉತ್ಪಾದಕ ಮತ್ತು ಅದೇ ಸಮಯದಲ್ಲಿ ಸರಳವಾದ ಮಾರ್ಗವನ್ನು ತೆಗೆದುಕೊಂಡಿದ್ದೇವೆ.

ನೆಟ್‌ವರ್ಕ್ ಲೇಟೆನ್ಸಿಯನ್ನು ಸರಳವಾಗಿ ತೆಗೆದುಹಾಕಲಾಗುವುದಿಲ್ಲ, ಅದನ್ನು ಮರೆಮಾಚಬಹುದು. ಮಾರುವೇಷದ ಯಾವುದೇ ಇತರ ವಿಧಾನದಂತೆ, ಸರ್ವರ್ ಲ್ಯಾಗ್ ಪರಿಹಾರವು ಅದರ ವಹಿವಾಟುಗಳನ್ನು ಹೊಂದಿದೆ. ಇದು ಶೂಟ್ ಮಾಡಿದ ಆಟಗಾರನ ವೆಚ್ಚದಲ್ಲಿ ಶೂಟಿಂಗ್ ಮಾಡುವ ಆಟಗಾರನ ಗೇಮಿಂಗ್ ಅನುಭವವನ್ನು ಸುಧಾರಿಸುತ್ತದೆ. ಆದಾಗ್ಯೂ, ಡಿನೋ ಸ್ಕ್ವಾಡ್‌ಗೆ, ಇಲ್ಲಿ ಆಯ್ಕೆಯು ಸ್ಪಷ್ಟವಾಗಿತ್ತು.

ಸಹಜವಾಗಿ, ಒಟ್ಟಾರೆಯಾಗಿ ಸರ್ವರ್ ಕೋಡ್‌ನ ಹೆಚ್ಚಿದ ಸಂಕೀರ್ಣತೆಯಿಂದ ಇವೆಲ್ಲವನ್ನೂ ಪಾವತಿಸಬೇಕಾಗಿತ್ತು - ಪ್ರೋಗ್ರಾಮರ್‌ಗಳು ಮತ್ತು ಆಟದ ವಿನ್ಯಾಸಕರಿಗೆ. ಹಿಂದಿನ ಸಿಮ್ಯುಲೇಶನ್ ಸಿಸ್ಟಮ್ಗಳ ಸರಳ ಅನುಕ್ರಮ ಕರೆ ಆಗಿದ್ದರೆ, ವಿಳಂಬ ಪರಿಹಾರದೊಂದಿಗೆ, ನೆಸ್ಟೆಡ್ ಲೂಪ್ಗಳು ಮತ್ತು ಶಾಖೆಗಳು ಅದರಲ್ಲಿ ಕಾಣಿಸಿಕೊಂಡವು. ಕೆಲಸ ಮಾಡಲು ಅನುಕೂಲವಾಗುವಂತೆ ಮಾಡಲು ನಾವು ಸಾಕಷ್ಟು ಶ್ರಮವನ್ನು ವ್ಯಯಿಸಿದ್ದೇವೆ.

2019 ರ ಆವೃತ್ತಿಯಲ್ಲಿ (ಮತ್ತು ಸ್ವಲ್ಪ ಮುಂಚಿತವಾಗಿ), ಯೂನಿಟಿ ಸ್ವತಂತ್ರ ಭೌತಿಕ ದೃಶ್ಯಗಳಿಗೆ ಸಂಪೂರ್ಣ ಬೆಂಬಲವನ್ನು ಸೇರಿಸಿತು. ನವೀಕರಣದ ನಂತರ ನಾವು ಅವುಗಳನ್ನು ಸರ್ವರ್‌ನಲ್ಲಿ ಅಳವಡಿಸಿದ್ದೇವೆ, ಏಕೆಂದರೆ ಎಲ್ಲಾ ಕೊಠಡಿಗಳಿಗೆ ಸಾಮಾನ್ಯವಾದ ಭೌತಿಕ ಪ್ರಪಂಚವನ್ನು ತ್ವರಿತವಾಗಿ ತೊಡೆದುಹಾಕಲು ನಾವು ಬಯಸಿದ್ದೇವೆ.

ನಾವು ಪ್ರತಿ ಆಟದ ಕೋಣೆಗೆ ತನ್ನದೇ ಆದ ಭೌತಿಕ ದೃಶ್ಯವನ್ನು ನೀಡಿದ್ದೇವೆ ಮತ್ತು ಸಿಮ್ಯುಲೇಶನ್ ಅನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡುವ ಮೊದಲು ನೆರೆಯ ಕೋಣೆಯ ಡೇಟಾದಿಂದ ದೃಶ್ಯವನ್ನು "ತೆರವುಗೊಳಿಸುವ" ಅಗತ್ಯವನ್ನು ತೆಗೆದುಹಾಕಿದ್ದೇವೆ. ಮೊದಲನೆಯದಾಗಿ, ಇದು ಉತ್ಪಾದಕತೆಯಲ್ಲಿ ಗಮನಾರ್ಹ ಹೆಚ್ಚಳವನ್ನು ನೀಡಿತು. ಎರಡನೆಯದಾಗಿ, ಹೊಸ ಆಟದ ಅಂಶಗಳನ್ನು ಸೇರಿಸುವಾಗ ಪ್ರೋಗ್ರಾಮರ್ ದೃಶ್ಯ ಕ್ಲೀನಪ್ ಕೋಡ್‌ನಲ್ಲಿ ದೋಷವನ್ನು ಮಾಡಿದರೆ ಉದ್ಭವಿಸಿದ ಸಂಪೂರ್ಣ ವರ್ಗದ ದೋಷಗಳನ್ನು ತೊಡೆದುಹಾಕಲು ಇದು ಸಾಧ್ಯವಾಗಿಸಿತು. ಅಂತಹ ದೋಷಗಳನ್ನು ಡೀಬಗ್ ಮಾಡುವುದು ಕಷ್ಟಕರವಾಗಿತ್ತು, ಮತ್ತು ಅವುಗಳು ಸಾಮಾನ್ಯವಾಗಿ ಒಂದು ಕೋಣೆಯ ದೃಶ್ಯದಲ್ಲಿನ ಭೌತಿಕ ವಸ್ತುಗಳ ಸ್ಥಿತಿಗೆ ಮತ್ತೊಂದು ಕೋಣೆಗೆ "ಹರಿಯುತ್ತವೆ".

ಇದರ ಜೊತೆಗೆ, ಭೌತಿಕ ಪ್ರಪಂಚದ ಇತಿಹಾಸವನ್ನು ಸಂಗ್ರಹಿಸಲು ಭೌತಿಕ ದೃಶ್ಯಗಳನ್ನು ಬಳಸಬಹುದೇ ಎಂಬುದರ ಕುರಿತು ನಾವು ಕೆಲವು ಸಂಶೋಧನೆಗಳನ್ನು ಮಾಡಿದ್ದೇವೆ. ಅಂದರೆ, ಷರತ್ತುಬದ್ಧವಾಗಿ, ಪ್ರತಿ ಕೋಣೆಗೆ ಒಂದು ದೃಶ್ಯವಲ್ಲ, ಆದರೆ 30 ದೃಶ್ಯಗಳನ್ನು ನಿಯೋಜಿಸಿ ಮತ್ತು ಅವುಗಳಲ್ಲಿ ಒಂದು ಚಕ್ರದ ಬಫರ್ ಮಾಡಿ, ಅದರಲ್ಲಿ ಕಥೆಯನ್ನು ಸಂಗ್ರಹಿಸಲು. ಸಾಮಾನ್ಯವಾಗಿ, ಆಯ್ಕೆಯು ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿದೆ, ಆದರೆ ನಾವು ಅದನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲಿಲ್ಲ: ಇದು ಉತ್ಪಾದಕತೆಯಲ್ಲಿ ಯಾವುದೇ ಅಸಾಮಾನ್ಯ ಹೆಚ್ಚಳವನ್ನು ತೋರಿಸಲಿಲ್ಲ, ಆದರೆ ಅಪಾಯಕಾರಿ ಬದಲಾವಣೆಗಳ ಅಗತ್ಯವಿದೆ. ಇಷ್ಟು ದೃಶ್ಯಗಳೊಂದಿಗೆ ದೀರ್ಘಕಾಲ ಕೆಲಸ ಮಾಡುವಾಗ ಸರ್ವರ್ ಹೇಗೆ ವರ್ತಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಲು ಕಷ್ಟವಾಯಿತು. ಆದ್ದರಿಂದ, ನಾವು ನಿಯಮವನ್ನು ಅನುಸರಿಸಿದ್ದೇವೆ: "ಅದು ಮುರಿಯದಿದ್ದರೆ, ಅದನ್ನು ಸರಿಪಡಿಸಬೇಡಿ».

ಮೂಲ: www.habr.com

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ