From eee12181c755de2db95e2748f1a0984dd4164c81 Mon Sep 17 00:00:00 2001 From: Luxferre Date: Sat, 24 Oct 2026 09:03:38 +0300 Subject: [PATCH] games: responsive game loop with non-blocking input polling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced the blocking select()-based main loop with a proper game loop: - Process ALL pending X11 input (XPending) before every frame — no more missed keypresses from select() blocking for up to a full frame - Render every frame at 30 fps (FRAME_MS = 33 ms) consistently - Frame pacing uses select() with a timeout that wakes immediately on input, so keypresses are processed within milliseconds - Game logic (snake steps, tetris gravity) still runs at its own rate via nextTick, decoupled from render rate This eliminates input lag and missed keypresses in both Snake and Tetris. --- overlay/rootfs/usr/bin/snake | Bin 13672 -> 13672 bytes overlay/rootfs/usr/bin/tetris | Bin 17764 -> 17764 bytes prebuilt/games/usr/bin/snake | Bin 13672 -> 13672 bytes prebuilt/games/usr/bin/tetris | Bin 17764 -> 17764 bytes src/games/snake.cpp | 59 ++++++++++++++++------------------ src/games/tetris.cpp | 59 ++++++++++++++++------------------ 6 files changed, 56 insertions(+), 62 deletions(-) diff --git a/overlay/rootfs/usr/bin/snake b/overlay/rootfs/usr/bin/snake index c8bf935a4116ca9b9192788bc428f43245be120d..5eda79de33fe22c92b27880aaf808f1fced3fc11 100755 GIT binary patch delta 3330 zcmbtXeNa_ zZ`;P+ZI_R>1O7a z-?{IebKbq@o_p_kt{tu&4kaNu6qgj*pNvodhxAoJGtinzK6K)|;(YeetSig8VwGpB zm0~wiP0K$UI9pFRNTTv=h~!A{ma=rDc5-EFZPao%WB&T|)p93iEL2$vv6(?6&z_!W zq$CEOl}%W5Jj-~Inr9OxoLpMEjT)##X^3e&Fu)zi9^ekjN}nvzi2P)flapa0LM8gC z6(>f-FTH8x*>heecRh_TG*UKd$XdCLXH644yL3Wg*mcIq_2=U!A`<8>Bhomz<4Tm; zNSPTzx}Q??3|V=$5sd$=lo*DrNVA{f*}dLqM~1=49Vn0PuB;uhK1+$PT6={Hw_kCi zhs0W*{nDFh$=4{}$T37>8LqKBfTM6+_pR~Buv_CYm0(ja`+6wP_JC)d@?r1{ereX| zl{*Rym9_E{Lsm0WBIVgBZ)NQ|=zbVN@Pqeo<&d>%CrmY4>KElcz60U!+(=tl%dgy3~cuDHX7om|N# zzzcvajTA>y&%)a9>_=WDO#758Fk(1BAFW5;&0ocAlv-2BwOp` zqz^SvswR~A{h*UWn;NNW?jRY@c8y`=hTM9e> zpcC>=$7Hu6b%~F@$C z!ciyp;hVG6_nZy}sbfg!?^;c0E^|8dqE>Y88qjJ>L24T%t0dI&CMS0=1-9Zg@IlXz zy{XV`PcbumwxEC(6!tDE%uM&hLcis{xu7LDc;e^&;htdVFG(R5+y|_UKlfhi;YOU? zBhNJ(I4Tgk^)pNl0h!6Owc`r<9Z0@9ApuFh1-TIL0+FAs&);5=D zo!s2gOgIVTPlEQJ5cB*TN*0`$#uaZ1_DCyO^K8Yq#4i>f_k@YnS-R<4_JCIYxS}1j zb_J3h`3ZkOn>LL@!17wD#bE92IRfKt%R`z5Dt=!l$d3E+n%y3WB*Ch z$zmJTNPWvm?b1np6-qaceHvNDty1r$D z7d?kXW=4sQQ^+5kV;;M+%giK@{hllt>6htr)2Hm=Z<9kIlSD}2#_)kHG`BXpL(dMD z0k`R=2OUKsA@R1oH1b+;Bc-)==&J`_Eoz`h&!^(6t_dFf@cLVoI0w! zB9P%lM69LZDk35P_VYdj`56AyBEi@t^jBx*X zo-svq+Nd~XsWptc%$2}C7o4#tRd>xk>B7={aw=!^>Ea4aBUM$wvp;<-H`GGJzJ-Ww zA3ai=;2|EMXSVbnG{_BG;k1mIdr}zEf|qM2xjWU?HhtURxqE4J-i?aD1n7ksY&C5S zgxejyDm3>My>Tk(u`l~dtL4?dH+??kiLz0xenJ*)xe@!BM;#^XnW9mXTKODpkBE>hWc>H?0IA@n=oJivSK>kOvr9fsg|D3t%6h3vhS^91!6k z{J0z;FQ6$4p-2D)n9oGW0elhoJU|Na4DgEp9Uv5NCj*=Up9jtZ{s*uF@B!d?z*m3_ zz$FBO3qc6((J(+HS-79F7}U%I;lXzeh!Jt~xH)!paN?NcG`irz7h*F*deRU&2{?== zp>+VH7C;md50Zn}>LO0>Hi6DOi z{3E^Gr}-uyH>n*ni@_;F9X#((UsuLud%}8L&SOHX0KYEm=^s zWI@rg!A3!`g1=Vok2nhb?*R?~Ecmgwbi#)l;&umLauMx3`z@Z1dvr;a8}%iCzw6*{ z47e6_Zvvl40XzKL_$0!Ccg8mmyRbVxHH3m5HQ-$wr%Kt(v&&pH77@<09JLa#frMHG zL8+DRI=UlJzr?tp(#t+-P2M41M__Tj$RW}qEYvVIm)43hAG~qX0TD(ntAp$yd)usXu^*sY?O9Q2p+>- z_~nG9#M8Jp;X$GWf1c1l%;617Hkv=0C|`<@4JIT^@?qd}(EbhZ9pE4IVxHCErxH_$Jp5{+Hbwzfdo&2u z!{<=7S_1x!g6z)4l6M?T_5!X}G+QlH=*qy;A#4fxDya4!^)b_WC*K zKf7D=moRMC90*EQB6K+xN3K`~-yo}3bQ3`TT3JJi&PCzPxrvgBM1(5v?p$q<9VB}q Y?#R^y1-@F!EVqgH4}kmCJ^%m! delta 3364 zcmbW4eNagOy=_;BZKrmpgIf7m+pev(u#US$N4L;gSFkp;Rv=)KCnE1@EN{;P?RNj!*)cP} zoOACv_uQ{@?|W~sbg;BuNjdf;rbJ}v0Vdg#y*9KGOO^UPhdzrd(Y0?mK3$hK*vXwK zdbjPXtc^C?(JHE5N}WC$9`at;lOLsn*290apqe&&S(~@@n?euYv_frvme^R33S4Vo z8y#X5I7PsoC2*`Cv;wCIc=%V+tLd&1FampIdl$dm(#7vmtlE&TmjtC#J$yN#qScaz zwv*&&RqEmu0(Z>s;peAQ)@^h(-RCG-FL1d5flCd9Sj*cyymkR8iqv`8Ds3y>%WJ^H^Hl;@jR8iLGOJhv`mHoW3tYMXG>--AIbL3`HT3ed0#Zf$IWNqS zz9}>0rwZID|3bTHQS5c1)W9@y&O0^ZvQH6t*%zx$IjlOg^w#SU^9?E@FkBOM@`e)h zqT^QVAj=R89Ns0{5AJQO#wq zhElx?rkXC??Z4Vat1G0zFfK@=wgn6V_YeOfMj77{L1b)-)Wh$a5pr94Ba*BOucqBF zWp510IlMM8YHu_VgJL7xl6t>t|73G9xWIkjmj`9CUOwOA(su+DpjLw}`fbC|l?t87 zXl-iO8Kwp0H@@^i;q%gjpu7U zeB3ff+lDD4aHW1R+f2264)Z~Q`=`(BmMls!O}*$Dl(L%?_kJ7iDT|MzH6S7 zPO1TOPq&Bf#56qb4OIwSk?*`W42N#2C^E_GjH| zvc%(%#m2t`T1V@NLH2b#0`tUleI?#WZ>29{tC_wz?tR(7F2Z3~-tF!{_m=~6-IsV! z%xm149ol_~mnrsS%iG<&GXEHEMgH$zr2p=P3}6j+^2|8CSG!vVfVKTR#VwBZrS7Hy zFl;yoM6SnNx0svqFzH%-Js1$ufsLx&jQ>BoY-7kElifPF}uY$Rtchag7N}p8Y;U7hx-t}l@ zMulbrnzQDD&ciQGbK+%?RMWkl(yL0u#%yyOT8$G{<1bblD`ZUC`wDRHB(kqlfWhWRBjuCsV-(JUQs+4#LUHw_l3J%wCKFB z%dlx_&TlSy_|GwbstjfVd&?!io{y)YHT4{CbXC*SHsGq<@$i2}53vn1`gHU0e(^*I zod4Rd&w>my$TdgR=%nRAiCkTyZtLZle9OL^ufC3OHw{arTGOQ-G3bQ>FyHPT#d#IZ znOL+J2+kq@uD-k9jG>#ZiT503z1A<@3b;`t@8gc=qsELGTHd?KEO~sv^7Kc>^evM2 zSMfSUB&}Qq?VpYdLJ#6bUPKl!;vX`b0ubf>a=-1F`|a@mZTIB=o)j}N<4@742f4Q_ zwlP6m$k83m$MPmO;QZB3a(l|E>94)gA7h7OrU3iB>xm&s`dD{cUiJu~+a7b$ZMkmy ziAh-?64tZxFZUTC&vyM_LN1C?|7Nz^vH@-=`a(`;S<;l(#6*AT27M%;DFD>#$Z`CT8}IW*6#DIhNA3 z{S=mO9}#`K`60*3Z~Ruf4$Uj)cTy|l3z>-&B2kDO88O52aL5c$hZG>okqah(vq&rQ@Phz9p?n5WA}bLq@&@8U zVv#d5v5ag(c%&YA0;xns(g8N2Jc;rY08|qyK}|K1q=dO)*SsOEaAG_8eS#@G*NA;1 zi^*;*X;Di?Y1WtW>@hy%38JBN_yVSD8+o zB-0W%ht&^K4FdNL*_rs;q*-2Q|0oUMBD&OJ7#aFjqRhrR4Y`__LKTq^m6KXbYE?7B zzr)&N$S0&tmBx&7BZ24a5@NC+a8Lvc;wu3Vfs+j$C>385# zwT+>V+rebKT(uI?s>o`!n)-ljR;N?V#H~)G){u|YDO4``R-GfS4D>n1xr+g!*Q6#a z3{>C{B_z|XD-{Qd0m(SGl02<(Qk|qnlVht3um;@py9@DkDnLGR0ojJkL|%{r6eEM^ zw;#EHyo{dFL>o(1W+sPpCIfVm&6$Q!NWp+9 Zq%l(;I{EcOPNG_lBPrJ(9m=es{tdkN*uDS& diff --git a/overlay/rootfs/usr/bin/tetris b/overlay/rootfs/usr/bin/tetris index ead3fddf35bbf65f1ac6922083ab2c0e3453b188..a1a0738aafbb59fe7ea15a1410314c13bec8bb16 100755 GIT binary patch delta 3908 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 V(FGP`Eu-+`YZinb8qKjW{{e?FK@|W1 diff --git a/prebuilt/games/usr/bin/snake b/prebuilt/games/usr/bin/snake index c8bf935a4116ca9b9192788bc428f43245be120d..5eda79de33fe22c92b27880aaf808f1fced3fc11 100755 GIT binary patch delta 3330 zcmbtXeNa_ zZ`;P+ZI_R>1O7a z-?{IebKbq@o_p_kt{tu&4kaNu6qgj*pNvodhxAoJGtinzK6K)|;(YeetSig8VwGpB zm0~wiP0K$UI9pFRNTTv=h~!A{ma=rDc5-EFZPao%WB&T|)p93iEL2$vv6(?6&z_!W zq$CEOl}%W5Jj-~Inr9OxoLpMEjT)##X^3e&Fu)zi9^ekjN}nvzi2P)flapa0LM8gC z6(>f-FTH8x*>heecRh_TG*UKd$XdCLXH644yL3Wg*mcIq_2=U!A`<8>Bhomz<4Tm; zNSPTzx}Q??3|V=$5sd$=lo*DrNVA{f*}dLqM~1=49Vn0PuB;uhK1+$PT6={Hw_kCi zhs0W*{nDFh$=4{}$T37>8LqKBfTM6+_pR~Buv_CYm0(ja`+6wP_JC)d@?r1{ereX| zl{*Rym9_E{Lsm0WBIVgBZ)NQ|=zbVN@Pqeo<&d>%CrmY4>KElcz60U!+(=tl%dgy3~cuDHX7om|N# zzzcvajTA>y&%)a9>_=WDO#758Fk(1BAFW5;&0ocAlv-2BwOp` zqz^SvswR~A{h*UWn;NNW?jRY@c8y`=hTM9e> zpcC>=$7Hu6b%~F@$C z!ciyp;hVG6_nZy}sbfg!?^;c0E^|8dqE>Y88qjJ>L24T%t0dI&CMS0=1-9Zg@IlXz zy{XV`PcbumwxEC(6!tDE%uM&hLcis{xu7LDc;e^&;htdVFG(R5+y|_UKlfhi;YOU? zBhNJ(I4Tgk^)pNl0h!6Owc`r<9Z0@9ApuFh1-TIL0+FAs&);5=D zo!s2gOgIVTPlEQJ5cB*TN*0`$#uaZ1_DCyO^K8Yq#4i>f_k@YnS-R<4_JCIYxS}1j zb_J3h`3ZkOn>LL@!17wD#bE92IRfKt%R`z5Dt=!l$d3E+n%y3WB*Ch z$zmJTNPWvm?b1np6-qaceHvNDty1r$D z7d?kXW=4sQQ^+5kV;;M+%giK@{hllt>6htr)2Hm=Z<9kIlSD}2#_)kHG`BXpL(dMD z0k`R=2OUKsA@R1oH1b+;Bc-)==&J`_Eoz`h&!^(6t_dFf@cLVoI0w! zB9P%lM69LZDk35P_VYdj`56AyBEi@t^jBx*X zo-svq+Nd~XsWptc%$2}C7o4#tRd>xk>B7={aw=!^>Ea4aBUM$wvp;<-H`GGJzJ-Ww zA3ai=;2|EMXSVbnG{_BG;k1mIdr}zEf|qM2xjWU?HhtURxqE4J-i?aD1n7ksY&C5S zgxejyDm3>My>Tk(u`l~dtL4?dH+??kiLz0xenJ*)xe@!BM;#^XnW9mXTKODpkBE>hWc>H?0IA@n=oJivSK>kOvr9fsg|D3t%6h3vhS^91!6k z{J0z;FQ6$4p-2D)n9oGW0elhoJU|Na4DgEp9Uv5NCj*=Up9jtZ{s*uF@B!d?z*m3_ zz$FBO3qc6((J(+HS-79F7}U%I;lXzeh!Jt~xH)!paN?NcG`irz7h*F*deRU&2{?== zp>+VH7C;md50Zn}>LO0>Hi6DOi z{3E^Gr}-uyH>n*ni@_;F9X#((UsuLud%}8L&SOHX0KYEm=^s zWI@rg!A3!`g1=Vok2nhb?*R?~Ecmgwbi#)l;&umLauMx3`z@Z1dvr;a8}%iCzw6*{ z47e6_Zvvl40XzKL_$0!Ccg8mmyRbVxHH3m5HQ-$wr%Kt(v&&pH77@<09JLa#frMHG zL8+DRI=UlJzr?tp(#t+-P2M41M__Tj$RW}qEYvVIm)43hAG~qX0TD(ntAp$yd)usXu^*sY?O9Q2p+>- z_~nG9#M8Jp;X$GWf1c1l%;617Hkv=0C|`<@4JIT^@?qd}(EbhZ9pE4IVxHCErxH_$Jp5{+Hbwzfdo&2u z!{<=7S_1x!g6z)4l6M?T_5!X}G+QlH=*qy;A#4fxDya4!^)b_WC*K zKf7D=moRMC90*EQB6K+xN3K`~-yo}3bQ3`TT3JJi&PCzPxrvgBM1(5v?p$q<9VB}q Y?#R^y1-@F!EVqgH4}kmCJ^%m! delta 3364 zcmbW4eNagOy=_;BZKrmpgIf7m+pev(u#US$N4L;gSFkp;Rv=)KCnE1@EN{;P?RNj!*)cP} zoOACv_uQ{@?|W~sbg;BuNjdf;rbJ}v0Vdg#y*9KGOO^UPhdzrd(Y0?mK3$hK*vXwK zdbjPXtc^C?(JHE5N}WC$9`at;lOLsn*290apqe&&S(~@@n?euYv_frvme^R33S4Vo z8y#X5I7PsoC2*`Cv;wCIc=%V+tLd&1FampIdl$dm(#7vmtlE&TmjtC#J$yN#qScaz zwv*&&RqEmu0(Z>s;peAQ)@^h(-RCG-FL1d5flCd9Sj*cyymkR8iqv`8Ds3y>%WJ^H^Hl;@jR8iLGOJhv`mHoW3tYMXG>--AIbL3`HT3ed0#Zf$IWNqS zz9}>0rwZID|3bTHQS5c1)W9@y&O0^ZvQH6t*%zx$IjlOg^w#SU^9?E@FkBOM@`e)h zqT^QVAj=R89Ns0{5AJQO#wq zhElx?rkXC??Z4Vat1G0zFfK@=wgn6V_YeOfMj77{L1b)-)Wh$a5pr94Ba*BOucqBF zWp510IlMM8YHu_VgJL7xl6t>t|73G9xWIkjmj`9CUOwOA(su+DpjLw}`fbC|l?t87 zXl-iO8Kwp0H@@^i;q%gjpu7U zeB3ff+lDD4aHW1R+f2264)Z~Q`=`(BmMls!O}*$Dl(L%?_kJ7iDT|MzH6S7 zPO1TOPq&Bf#56qb4OIwSk?*`W42N#2C^E_GjH| zvc%(%#m2t`T1V@NLH2b#0`tUleI?#WZ>29{tC_wz?tR(7F2Z3~-tF!{_m=~6-IsV! z%xm149ol_~mnrsS%iG<&GXEHEMgH$zr2p=P3}6j+^2|8CSG!vVfVKTR#VwBZrS7Hy zFl;yoM6SnNx0svqFzH%-Js1$ufsLx&jQ>BoY-7kElifPF}uY$Rtchag7N}p8Y;U7hx-t}l@ zMulbrnzQDD&ciQGbK+%?RMWkl(yL0u#%yyOT8$G{<1bblD`ZUC`wDRHB(kqlfWhWRBjuCsV-(JUQs+4#LUHw_l3J%wCKFB z%dlx_&TlSy_|GwbstjfVd&?!io{y)YHT4{CbXC*SHsGq<@$i2}53vn1`gHU0e(^*I zod4Rd&w>my$TdgR=%nRAiCkTyZtLZle9OL^ufC3OHw{arTGOQ-G3bQ>FyHPT#d#IZ znOL+J2+kq@uD-k9jG>#ZiT503z1A<@3b;`t@8gc=qsELGTHd?KEO~sv^7Kc>^evM2 zSMfSUB&}Qq?VpYdLJ#6bUPKl!;vX`b0ubf>a=-1F`|a@mZTIB=o)j}N<4@742f4Q_ zwlP6m$k83m$MPmO;QZB3a(l|E>94)gA7h7OrU3iB>xm&s`dD{cUiJu~+a7b$ZMkmy ziAh-?64tZxFZUTC&vyM_LN1C?|7Nz^vH@-=`a(`;S<;l(#6*AT27M%;DFD>#$Z`CT8}IW*6#DIhNA3 z{S=mO9}#`K`60*3Z~Ruf4$Uj)cTy|l3z>-&B2kDO88O52aL5c$hZG>okqah(vq&rQ@Phz9p?n5WA}bLq@&@8U zVv#d5v5ag(c%&YA0;xns(g8N2Jc;rY08|qyK}|K1q=dO)*SsOEaAG_8eS#@G*NA;1 zi^*;*X;Di?Y1WtW>@hy%38JBN_yVSD8+o zB-0W%ht&^K4FdNL*_rs;q*-2Q|0oUMBD&OJ7#aFjqRhrR4Y`__LKTq^m6KXbYE?7B zzr)&N$S0&tmBx&7BZ24a5@NC+a8Lvc;wu3Vfs+j$C>385# zwT+>V+rebKT(uI?s>o`!n)-ljR;N?V#H~)G){u|YDO4``R-GfS4D>n1xr+g!*Q6#a z3{>C{B_z|XD-{Qd0m(SGl02<(Qk|qnlVht3um;@py9@DkDnLGR0ojJkL|%{r6eEM^ zw;#EHyo{dFL>o(1W+sPpCIfVm&6$Q!NWp+9 Zq%l(;I{EcOPNG_lBPrJ(9m=es{tdkN*uDS& diff --git a/prebuilt/games/usr/bin/tetris b/prebuilt/games/usr/bin/tetris index ead3fddf35bbf65f1ac6922083ab2c0e3453b188..a1a0738aafbb59fe7ea15a1410314c13bec8bb16 100755 GIT binary patch delta 3908 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 V(FGP`Eu-+`YZinb8qKjW{{e?FK@|W1 diff --git a/src/games/snake.cpp b/src/games/snake.cpp index 5744a0c..e2fe959 100644 --- a/src/games/snake.cpp +++ b/src/games/snake.cpp @@ -376,45 +376,42 @@ int main() { int xfd = ConnectionNumber(dpy); const unsigned long FRAME_MS = 1000 / 30; // 30 fps rendering - unsigned long lastFrame = now_ms(); + unsigned long frameStart = now_ms(); while (running) { - unsigned long now = now_ms(); - long until = (long)nextTick - (long)now; - if (until < 0) until = 0; - // Never block select longer than one frame so the screen stays smooth - long wait = (until < (long)FRAME_MS) ? until : (long)FRAME_MS; - - struct timeval tv; - tv.tv_sec = wait / 1000; - tv.tv_usec = (wait % 1000) * 1000; - fd_set fds; - FD_ZERO(&fds); - FD_SET(xfd, &fds); - int r = select(xfd + 1, &fds, nullptr, nullptr, &tv); - bool dirty = false; - if (r > 0) { + // Process all pending input immediately (non-blocking) before each frame + while (XPending(dpy)) { XEvent e; - while (XPending(dpy)) { - XNextEvent(dpy, &e); - handle_event(e); - if (!running) break; - dirty = true; - } + XNextEvent(dpy, &e); + handle_event(e); if (!running) break; } - now = now_ms(); - if (running && now >= nextTick) { + if (!running) break; + + unsigned long now = now_ms(); + + // Game logic step at its own rate + if (now >= nextTick) { if (state == PLAYING) step(); - if (state == PLAYING) nextTick = now + speed; - else nextTick = now + 80; // keep loop responsive while paused/over - dirty = true; + nextTick = now + (state == PLAYING ? speed : 80); } - // Render at 60 fps or whenever state changed - if (dirty || now - lastFrame >= FRAME_MS) { - render(); - lastFrame = now; + + // Render every frame + render(); + + // Frame pacing: sleep until next frame, but wake up immediately on input + now = now_ms(); + long sleepMs = (long)FRAME_MS - (long)(now - frameStart); + if (sleepMs > 0) { + struct timeval tv; + tv.tv_sec = sleepMs / 1000; + tv.tv_usec = (sleepMs % 1000) * 1000; + fd_set fds; + FD_ZERO(&fds); + FD_SET(xfd, &fds); + select(xfd + 1, &fds, nullptr, nullptr, &tv); } + frameStart = now_ms(); } XFreeGC(dpy, gc); diff --git a/src/games/tetris.cpp b/src/games/tetris.cpp index d19bfb4..e517099 100644 --- a/src/games/tetris.cpp +++ b/src/games/tetris.cpp @@ -500,45 +500,42 @@ int main() { int xfd = ConnectionNumber(dpy); const unsigned long FRAME_MS = 1000 / 30; // 30 fps rendering - unsigned long lastFrame = now_ms(); + unsigned long frameStart = now_ms(); while (running) { - unsigned long now = now_ms(); - long until = (long)nextTick - (long)now; - if (until < 0) until = 0; - // Never block select longer than one frame so the screen stays smooth - long wait = (until < (long)FRAME_MS) ? until : (long)FRAME_MS; - - struct timeval tv; - tv.tv_sec = wait / 1000; - tv.tv_usec = (wait % 1000) * 1000; - fd_set fds; - FD_ZERO(&fds); - FD_SET(xfd, &fds); - int r = select(xfd + 1, &fds, nullptr, nullptr, &tv); - bool dirty = false; - if (r > 0) { + // Process all pending input immediately (non-blocking) before each frame + while (XPending(dpy)) { XEvent e; - while (XPending(dpy)) { - XNextEvent(dpy, &e); - handle_event(e); - if (!running) break; - dirty = true; - } + XNextEvent(dpy, &e); + handle_event(e); if (!running) break; } - now = now_ms(); - if (running && now >= nextTick) { + if (!running) break; + + unsigned long now = now_ms(); + + // Game logic step at its own rate + if (now >= nextTick) { if (state == PLAYING) step(); - if (state == PLAYING) nextTick = now + speed; - else nextTick = now + 80; - dirty = true; + nextTick = now + (state == PLAYING ? speed : 80); } - // Render at 60 fps or whenever state changed - if (dirty || now - lastFrame >= FRAME_MS) { - render(); - lastFrame = now; + + // Render every frame + render(); + + // Frame pacing: sleep until next frame, but wake up immediately on input + now = now_ms(); + long sleepMs = (long)FRAME_MS - (long)(now - frameStart); + if (sleepMs > 0) { + struct timeval tv; + tv.tv_sec = sleepMs / 1000; + tv.tv_usec = (sleepMs % 1000) * 1000; + fd_set fds; + FD_ZERO(&fds); + FD_SET(xfd, &fds); + select(xfd + 1, &fds, nullptr, nullptr, &tv); } + frameStart = now_ms(); } XFreeGC(dpy, gc);