From 486a1cd17c3a091493e05ab4f3b23a8c555ce146 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Fri, 10 Mar 2023 09:21:56 -0500 Subject: [PATCH] Keyboard control --- assets/custom_player.png | Bin 0 -> 8622 bytes src/GameEngine.cpp | 2 +- src/McRFPy_API.cpp | 54 +++++++++++++- src/McRFPy_API.h | 4 + src/PythonScene.cpp | 9 +++ src/scripts/TestScene.py | 153 ++++++++++++++++++++++++++++++++++----- 6 files changed, 200 insertions(+), 22 deletions(-) create mode 100644 assets/custom_player.png diff --git a/assets/custom_player.png b/assets/custom_player.png new file mode 100644 index 0000000000000000000000000000000000000000..0a32f4b41719de6351b12005e2b27abb75e6023e GIT binary patch literal 8622 zcmYLubyO7Z_y6K53j(_!AiayIgn&plEF~qOG$JJ}-7GAybP9-oAl)HdA{|moNGRRH zk}kP4eE0qN{qdV~<~(=q%$=F@+}G_$O?5@G`}Fq#005b?lKdO|stEuPz=;U)6lc|C z5dI>>R!&Y+Sx%1G+11I)*4`2TU{63MNGf&18Go9*EqF!^B8g(ZTcZ9@UV*XxzCtm% zU8pY8tLN82tYpej(Rs^;&in7Hx0hGHl?9hE6Zr>z{~^NhLn-oB^**<`gvh_XX5YAG zufTR)^U@h1aB-UDlQrH)83xorl|xe9D$0FElhgf!ljnoAEu+_>Ka#!; z0J7i`X!mZGMdr-KI`@&w9y8r|s#UjD-r(m-SN$F{>%t>G;nx!U_W7TVdd$opEp@q) z)CT1|(4bJH(#i7+n6(T&dT3p*Z5Hc$NE22wJIFU>3ugJKz$Fs`prfXG9Tdu5PS3&m zsSb9u4-xTCFyd>9GX1L$r+fCK4{`%)Zx(b*q;!14PFUAIjq4*KpTD=QGj}7^uy;XB z?oC)xSJ-X@w31S;6sqs1_*F}0WF#!;1NlBraFOLc5YNZ~pU6TJV6BhU=(0~AZW_Az ze%M_*CQy2<7s;@^Oinwjh5OOhENZI~66)im``U>X1b7N#sOqwPJrml5DhiAn8iKRlm(;i9!cYxPdUk2iVE zIsZvmFU5(6;fTwF-fI3Pqf|!f_(%Eb9CBNeu}u%xtYQ|#8$I53<)>b;JBm_;$2&Vv z($0zqbicS8Dj?$FQt~*}=qHD+M;!+RaCjm1A7ty@BJ!lI8Qa`EK5Ml^2az53%38oI zz_6ENM-ol|@Z2RMsH{Aqi)~WxEN|F)ZpNLY{OGg47c%}n2bs3=8|=F zzqMV3g-F$8KWc2-<#Y3~wp=j)AeRR!_Z`d3vQQ2%_2x!4C)AB1?<@Wh%C=e~XJs8V zH$UXE69PY~X^{Dzpqf}jIx?~3wjB6FQy4GE-=b?OsG4DlAG2;8P3Pvu8Z1-3yBE@>` zNgD18RFsr-rt)iuBktD%Z4Zy%^N6kjYJIZ{Z6iWtH%4M#ayRCfOLvIzP|Y~_Bf_WX z(>FI>^^^bw)X+?4Xw2E_9Oluy*Ds?=oA%`g#sMo28j2Pbb@u$aF9!w$8f;-QlUR`65T!ichqR#-vUk{A3X=U4dF{}&2MBWQGGrR(#s(r zbr2L&e;vpLVT8d_Tv;F>QA>onk16k-_y)@O=({Z%II>n33Af>6v#Wt;EQOO9ci{ z>A$KuFnbcR0tj<#BUqBUY7RR6fg8+7lDPA2a4lUV`!kN|pku3Jt);=_`6`O%1p|0t zLB>1#Jh+G8BcDj%4581`AVEQcN$(nJV4zD?P&Bpof+U3t6Ti|H{6&S8MCz*wtD0Hi z3iF=dMgp==;@1bL@S0EdoP=ZHK?mKKfEuUswtWpoxcz(>gOY+A`(%#-kx&sPpXEr! z*+Z;xcv|dQgVIahwWF2>r$ON34-7AOeI9y|w#AsZFFNj+;sF#v(ZCw{dEOabvir4A zG$yk(;$rs0!N~g^O%vbp&n|p9MP6ZdIc9wxd;%yxbXKRi>a%fA|VpfEPK zyf0$wK)mM$W69}v+)aO#SL!MC={!Kr%S*o&p3>`-pc#Q)vtZIxxtv%1vJX$YJ)q4g zrhw8Q>X>pA=g6>0xk=;xq8R9dj)oB~K)O*I`RQmYA#%<*1^TM!4Tt+3I17sG?M-^O z=GascVYk-6lV@e6$H8&_TMD+I&$Iqbrfhcr`)6gEtAV@4*9UrgYI!%uk#Uc3i&+#S zAUj9>Hu58>177BYFBG^UrrV=5(1qVGC;y}Ww^f@*@GOuqheZ4cwWHtPr*9=jh=W{% zLCJ$sQz!vo%r^(P_i3>Mp*7p9;S!*VZPpIF3qU}06f#`+8jt5WkwHAyVF`o!iP!F5 ziic)FQjoe%pe-x@y$aATfM3Yba*^{zpC^ZA#-$QfmnOAMFRC|fHM~tZcHiDpon1xk z+8BEfE#N^V{|Kn@&o42K(H4oI3xLm3k$9gL*GEB0n4nS+aw=Ye zsw1*4iKnIU&b7ux9vS=E3qGv-1^}efiH2x6&TBa*KP0mjbqSop8DI!Hf|9Ad_js2R z8BY5%P&Mn=sC7W)-e|j}8No?ceLBx3@mps>OIG)2k3RJc$`|Ya>W*+`_v+Q1dJ9HWl!o0DysiGYakBk?2 z9>9jUm>Ckr4Yg&m?Y=y3h8ZKN^;&Mao=zNkIsRqvwKRdt^{e^^?hL`V!;oSJM_VzXoS_*|LE%|u;?j_Du)a4V($n} zjH!OFkj8W&p_u?O90^52Hy=Ri-rkIGLpKYM)KLA;hhFMC5QKyDb??@la0;kWZFi;_ z0mSe7Ibq3Z)bExC>GOZE69I!mMQ>AQSEyaGaE`SItAB+1p5(J0nHsS3n}A=Omwz9b z=>+VjVsHB~C>GG*J{)0$2NCqBb{W-m@&9cb&-`;LN^iT;+a6DZ<%&Svp1<2VY8ne0l(0g14B9|sZ{kMkHGW!gvJB>`MTCc z>0H^S_9nXsN05!j3QG<-ej`@4^8yHrrHbA^KTLI|m5V1=_RukNITm8XYuo{b2OoKQ zdbszVs1fp*=c4QGijDT|w{>gj+BVRGs7`1^4A7HLtogjxc-qOXSP{K1BTs&(^el^* z$E;?8OImAyX2Svfv6u6b`z_ejhZ)O1wF9aFPgi&|Pjs|NF^Gy`M#aJ?)i6}{|P<=b-W}Sal3QkaMEv!+Q=M6Uh zimCo+S4}*-sx-wKZ){sf<|xW{7?cG@6x?r@_Ap+5YFO(skYvRHj9wyUdLbp1nbd^+ zA5?7pT-Ts2xM@4U3k$oNfw1`!#@ImZacx^ryu?CvHE&F8EXU6sABU{`?<06yl}X$A z5LYfVZ_)(Lr-)a{tauCFpY?xN{5Fo{No+`Cbqe1o3Y8WsCl(HLt@b#Fl78+WFrI5S zYUREaK3U_vIZky<(CSWfSQ)-wak_rz)Niu~>F#TJFumhk1g?2cE`r!sN7` z32!FCiNrlut3`~rAU{I$UgrS29)Q27TF^QIH|d@$4#qo? zN8V^NrQeXdE!@(W`b-a~sS#K%3iN5)`bmCFNXi25SIvzEw*(kKL>Qa`V>v&7J(v@#)d|YS z;632hIsaBjv+?%NzEfjtvxud%R*>cM}{v#Y{^|{~VS8 zlt;|a5%ZXQ*|hY@=4SjnV39A^Kg0;nNF_*C9pqDP7Kv_)Wt4V#P_0i|rdLii68R2v zmrq^5Et5gwmqWZMAyt&D{!qI9>({(x#p+|=FppJxxAX$wuroOttn+*&byevpv^XeO z-;>=HO2=8PfqBK6nB=nhZ5_pzV*i5n?i|4}dCy>EZ4hX-+`m^W?jPXrSg?7>`X0pn zqN8dXP^LQVaxO+Qh*dsxMpDyK8>0BA$7 z!PB(!>8rufNJAEr>zD=N3(2wvZo1_qImWgO`N00H(oA99r;i*OU@V?K**e$K31L?5 zeJ|OnBv1SYjs>!wG(sMP{(K*z@V~#y8pGq&b4g1K`7DW#d?RzkNFbT>1ZV)Y&hyW% z$sFKw?Ex}P3x~Gxo3mgmd3J@{sbfLL#N{>;Ra6p=x<_!f1Jr>xW6cYXKl>d!mF>{c z5T`(fbxcraHs7m^F^T=NgZ~ACN4lCxeF=wdw~ebDKxu(X+X>rq3E@Gk=qk$IE$_KMhUo1)0`6Qj>_<-_xld7ebja_kH(C9ybD(Tk| zX-SLE1myFJqQg_GWs*U?Yn1m8Xy0WgoCiU)Q1QpC`{QbjLnR$}TXAsCR8Aa^_BX7r zfeCvupXTJU870>4k9pcu%1%w_efovcsXubbZUE_kLHYOsM(A|_m5gVONhI>c~cYG2Ye5)?|(^g*N26><1S8ajTMRx1tMC$h6rII}5I#O6qKfH_} zfOrSQYWj*&hitFi49R6cdxQHYr~2R(FIh_F4F!{wjl6(W(a6~mlB`L zFI{c?FFnnXh>uU^6f>E2JQvM8QW-e%t_P|P0wYhip0cxiU?5+Vw3}IT_lsTtGvoF) zw+fmwW*dJ32fzTk-=q4N1h6Kzbjp(YpNhqMmlp@M=Uw&@U!Ov_JkCWMDASWGYt2l; zff9u5f-yPIQT8V|8DP?wa=EO|vXxx&*^~>Osm2w30YFfKZlL zw;7<&vW2%yMcmdMApkeP>wI>}p>K_1z!Bs)>~j54wF#hwH| zROy~R;WU<&Z6YiK^Dao9AsT0}z3^Wy7u3o8lF-ltYV-ZD?U=>?Vuo$Vnx#ZLD#nfU zZ_9gwLkM~$u*0}hQyt|Z4W=Q)s=TphX)%o-?REWiovcwCN#K%ojT@5at2O7=h-nl#Q6O}S){m%f^+Cw+pr2c3on2jLS zn|hOf4M4!rMX*JiZ39^mZur=7j)&h3Pl(694eo+|mZe_&Y&u9S6`S%QMelxW5mr(I9y>+&f8`#Xtj`Ant_>D)O_ znhgCy-BgR1n9H#5bZDH>{&ZMo;iTbCHC6fq(H3f+6X}qz$pYqDGmODN`O};nNNW(& zNi@mg((86wIT+#|K&hd*B(Yo!Zjt3@t$1zT4ZBYLibMN=i;H*q2Iazek8|dIIU!8F zZPdfG7uV#5T%OC*n|ITysKwJR$*|U7CvGA#N)NaKQu?%ZXr??F7wNyA(;aqtT5j{_ z#Br8~MilU!jC%N5|E!Uh8RyFZiVtdNh5Iw~?xj(en(kFzE;j@L6Sn|}TLq@gLZoB7 z54KcHKyWfIw+V)i1xf9&Po4lL`h32O+`YN2z&ATUNAYZ0X4&6uQwV&@>%9shy4AJqQ+ET4Ixo7O{%$r7q;UL(-Ep~wQzLzN9ltqJ!P7a)Vqd~0S ziLp|ivVhL;b4{bJtgR45IMs5VMxgxgEUEz-GJ6I;1OP}Y1%Hdzo7f>`2zq-O)XlD? z-vo}?fp+~i!jL@26@MU4ntGSHIG@ZBsPFpb@OWOs#U ztF+7Vf=upUDV|k3Dewzv#N_btg{iIl1k|eYc+?Juu{2jFax8v7 z`enBJb}WnJV&H?Cc}CORnLwZiY(6Z9kZ5n>Roox!+p+YxKQ({KW`$cr%Iq-j@lJg| z8e1WMJ7ZnV(L#%dkcj`PMQ4fM#j$O0a!Qrj>_;YX=T*?D!3fWA!=nk69N~8wA%ABV z50a4jr=1SdbaZkX`?_2ojLg5^eN#e}%wu8k+*uzOjI1-@@grRAzV*g_u_cwJ=oK5n`iO~wxpL20 zIq6!j-ekx^4vp29h&&l>H8h##yu_E5WYGSPXd@zxqtEy7T?URpQ>Cu8&?1=?5ViW) z{oh~P9mA<-Nq9W-KV3;{?5gY!EFa~^%_y}Gh=i0uKdDRF5U-x?TQ`?z!_Yv zHgi_5_1=3U!cI$?>!p*yr;B1CI)od3D_-hLGab9W=D^zt8`GICe9c z%!CgYjnGbK7yn#y3EFPbOukZWkO6lLCP;8!=d)SIZ`N#V4G3)xGCjl1V3W1DAo$Gb zaI%RGO`l@aD>mm^Cpx}BpFKryouTwl$+1fpkKwqK3z+#1gasN0y30j@f8Mp9aX2Du z>ft0${+^z;Hq|b0Oi$pH;dCkYCWq`Qsu2#%na)K{@vjB**P(sSF0&#Hs5N5zgc+PLf`e7l}N32;2oeg zH!5TYo+R>m(mN&d*)msy@%m+jNPIZjK+!P6gFg*)$Y>hoX5(3GYbaF57UU)@Y`XY1 zFQNkc7#c_OnUxg+5w~7;-$1RW6o_-213VfGg0O(rh()T2SdoAJ{1;-%b zG6-StjJE`oc@xbIWkUmX#vPJ;m|cwV5)YaIWrr@iFC&gNS_PwMdk_X}KdPWgw*TEe zbbj9U^V=1JH7PaztJcb72+r#oOSJRVnTwfCILQf#DjJ9{$NNLKinDF)FdNw9P1rbc$MNnEMGUh`H(Dc#NJo12h8c-S21&&j2iL?+@sW^!+C&Xr z`Tvps;|Z#v+ipj+3N?5+TMKPBx3{}$N2T6YF`3^+^4ubE$(4Hpi`R!r|06y*49-po zs7>J+5i(9WIt{R@FND;8(T2mEmd92{TDg$D$W7qY=JpHiy@`p5o(grX?Cl=^roa(G zS}1!fbF}J3(9COmszqqwoekw^F5~|?eb2U!X5N+dk_DqN7ZfyPVLU_dJf5*6;!j}8 z$5b-vM@i@@m#{kRE~{LXh9BPR(Feu9Sjk-ZQUC=Q zHZVSEXX5mN2Z@nv)x|98cqAhpz}WBezOFWLCO)kw?e2$v$j-}?y8;YUOJy*P2Tx|M z(3+1)aYzON7>r*&=6lV~$OcF@urTlf zm^oVE3?z}FhFc3&qZxx^GYaZuA<(*e^1N6&>af;vsVB2_F;%`q*5ehs{x41uukdzUHz?c zC}Am1Ev38odhyi5S!J;OV0A~H-R7(;)&}c)heiX|+4DD?WTPtAO1E7@s7)i^Yp%_9 z@7v97)N*^=HC6ipl{|8<-srQ%&oN!(ZX@Db_U~V)*j>zTY~rvB<(5ub3^Ef4+;XSi zgSGDlVm`LS;`?UFKqp;|?>R}vlf>@VQf1&}!AvRGyQCz%u}@<}H5J8r2zcffWO6ku zqiD7fU1ZcJD0i`P;1FKiVH1!E?1u{nSUI1xj$+=N{^x6LH17U}5UrGcLQbeoM=>6~ zpjenb;UIYLUA4T6{*ApnlU_ZB`4`m;sh3Z zDXGIiOU90{lmyT1P8kWe&AaN7A~xPxA&p~PahqEX^ZsW``%Tob#U)qlvqF-O+ynci z$^tfi5!cy^vY(XYMj?&!t&`Po#7L~JYkD5gArCBmR5WBl+x?Kd*cZoNj{IE z?Sq?Q+1D?BRNuB-psX&j|5d6N62I`HkYAS)zfg-9)X2DwH4ec7w?+4{Fi(F z8c6mD*EA5UEaa)EJC~l;0Ci4`zQ7+difQOKi2fEYk<_=7Oac9|XB_7R$4AGaDGfQG zo0^sL1W#I{=g(Aq?l`~yESIowuTvoR(8+OAR9Vo#*bgcq9b2QLsANc^;ncuY@$M2o z3P={ErY#oyM3q#SixJ5-m868nVb=&FCnC0vXm*^l%N2_;;|w5N6PWS)m)D+Ylt>iN z^ws<#U(ubf8W|MZw!KsQjB>?lYS7vHI?Wb6j%71VFR`JqOhgy5*w5b47jxhtVjqOBE z_t+-m)KJfgKuKTH^bo?%4;@B@XgmfxTmGcvUQ7SA^JV%{@4ty3+XIvp)a5H=O@saq Dj8N)} literal 0 HcmV?d00001 diff --git a/src/GameEngine.cpp b/src/GameEngine.cpp index a35700b..74d4b55 100644 --- a/src/GameEngine.cpp +++ b/src/GameEngine.cpp @@ -24,7 +24,7 @@ GameEngine::GameEngine() McRFPy_API::executePyString("from UIMenu import *"); McRFPy_API::executePyString("from Grid import *"); - scenes["py"] = new PythonScene(this, "MusicScene"); + scenes["py"] = new PythonScene(this, "TestScene"); IndexSprite::game = this; diff --git a/src/McRFPy_API.cpp b/src/McRFPy_API.cpp index 560891f..95e3d82 100644 --- a/src/McRFPy_API.cpp +++ b/src/McRFPy_API.cpp @@ -575,12 +575,14 @@ PyObject* McRFPy_API::_listGrids(PyObject*, PyObject*) { auto grid = it->second; auto p = grid->box.getPosition(); auto s = grid->box.getSize(); - PyObject* grid_args = Py_BuildValue("(siiiiiii)", + PyObject* grid_args = Py_BuildValue("(siiiiiiiO)", title.c_str(), (int)grid->grid_x, (int)grid->grid_y, (int)grid->grid_size, - (int)p.x, (int)p.y, (int)s.x, (int)s.y); + (int)p.x, (int)p.y, (int)s.x, (int)s.y, + grid->visible? Py_True: Py_False); - //std::cout << PyUnicode_AsUTF8(PyObject_Repr(grid_args)) << std::endl; + grid->visible ? Py_INCREF(Py_True) : Py_INCREF(Py_False); + std::cout << PyUnicode_AsUTF8(PyObject_Repr(grid_args)) << std::endl; PyObject* gridobj = PyObject_CallObject((PyObject*) grid_type, grid_args); //std::cout << (long)gridobj << std::flush <points[i].tile_overlay = PyLong_AsLong(PyObject_GetAttrString(gpointobj, "tile_overlay")); grid->points[i].uisprite = PyLong_AsLong(PyObject_GetAttrString(gpointobj, "uisprite")); } + + PyObject* entlist = PyObject_GetAttrString(o, "entities"); + //std::cout << PyUnicode_AsUTF8(PyObject_Repr(entlist)) << std::endl; + for (int i = 0; i < grid->entities.size(); i++) { + PyObject* entobj = PyList_GetItem(entlist, i); + //std::cout << PyUnicode_AsUTF8(PyObject_Repr(entobj)) << std::endl; + grid->entities[i]->cGrid->x = PyLong_AsLong(PyObject_GetAttrString(entobj, "x")); + grid->entities[i]->cGrid->y = PyLong_AsLong(PyObject_GetAttrString(entobj, "y")); + grid->entities[i]->cGrid->indexsprite.texture_index = PyLong_AsLong(PyObject_GetAttrString(entobj, "tex_index")); + grid->entities[i]->cGrid->indexsprite.sprite_index = PyLong_AsLong(PyObject_GetAttrString(entobj, "sprite_index")); + } Py_INCREF(Py_None); return Py_None; @@ -964,3 +977,38 @@ PyObject* McRFPy_API::_listEntities(PyObject* self, PyObject* args) { return Py_None; } */ + +void McRFPy_API::player_input(int dx, int dy) { + std::cout << "# entities tagged 'player': " << McRFPy_API::entities.getEntities("player").size() << std::endl; + auto player_entity = McRFPy_API::entities.getEntities("player")[0]; + auto grid = player_entity->cGrid->grid; + std::cout << "Grid pointed to: " << (long)player_entity->cGrid->grid << std::endl; + if (!McRFPy_API::input_mode.compare("computerturn")) { + // no input accepted while computer moving + std::cout << "Can't move while computer is moving." << std::endl; + return; + } + // TODO: selection cursor via keyboard + // else if (!input_mode.compare("selectpoint") {} + // else if (!input_mode.compare("selectentity") {} + + // grid bounds check + if (player_entity->cGrid->x + dx < 0 || + player_entity->cGrid->y + dy < 0 || + player_entity->cGrid->x + dx > grid->grid_x - 1 || + player_entity->cGrid->y + dy > grid->grid_y - 1) { + std::cout << "(" << player_entity->cGrid->x << ", " << player_entity->cGrid->y << + ") + (" << dx << ", " << dy << ") is OOB." << std::endl; + return; + } + std::cout << PyUnicode_AsUTF8(PyObject_Repr(player_entity->cBehavior->object)) << std::endl; + PyObject* move_fn = PyObject_GetAttrString(player_entity->cBehavior->object, "move"); + std::cout << PyUnicode_AsUTF8(PyObject_Repr(move_fn)) << std::endl; + if (move_fn) { + std::cout << "Calling `move`" << std::endl; + PyObject* move_args = Py_BuildValue("(ii)", dx, dy); + PyObject_CallObject((PyObject*) move_fn, move_args); + } else { + std::cout << "player_input called on entity with no `move` method" << std::endl; + } +} diff --git a/src/McRFPy_API.h b/src/McRFPy_API.h index 6effe2a..22befbd 100644 --- a/src/McRFPy_API.h +++ b/src/McRFPy_API.h @@ -106,6 +106,10 @@ public: // turn cycle static int turn_number; static PyObject* _turnNumber(PyObject*, PyObject*); + + // accept keyboard input from scene + static sf::Vector2i cursor_position; + static void player_input(int, int); // Jank Functionality static UIMenu* createMenu(int posx, int posy, int sizex, int sizey); diff --git a/src/PythonScene.cpp b/src/PythonScene.cpp index 315aac5..f90abb3 100644 --- a/src/PythonScene.cpp +++ b/src/PythonScene.cpp @@ -212,6 +212,15 @@ void PythonScene::doAction(std::string name, std::string type) { // try zoom out doZoom(mousepos, -1); } + else if (ACTIONONCE("up")) { McRFPy_API::player_input(+0, -1); } + else if (ACTIONONCE("upright")) { McRFPy_API::player_input(+1, -1); } + else if (ACTIONONCE("right")) { McRFPy_API::player_input(+1, +0); } + else if (ACTIONONCE("downright")) { McRFPy_API::player_input(+1, +1); } + else if (ACTIONONCE("down")) { McRFPy_API::player_input(+0, +1); } + else if (ACTIONONCE("downleft")) { McRFPy_API::player_input(-1, +1); } + else if (ACTIONONCE("left")) { McRFPy_API::player_input(-1, +0); } + else if (ACTIONONCE("upleft")) { McRFPy_API::player_input(-1, -1); } + else if (ACTIONONCE("wait")) { McRFPy_API::player_input(+0, +0); } } void PythonScene::sRender() { diff --git a/src/scripts/TestScene.py b/src/scripts/TestScene.py index b103457..1b20b50 100644 --- a/src/scripts/TestScene.py +++ b/src/scripts/TestScene.py @@ -8,8 +8,90 @@ WHITE = (255, 255, 255) RED, GREEN, BLUE = (255, 0, 0), (0, 255, 0), (0, 0, 255) DARKRED, DARKGREEN, DARKBLUE = (192, 0, 0), (0, 192, 0), (0, 0, 192) +animations_in_progress = 0 + class TestEntity: - pass + def __init__(self, grid, label, tex_index, basesprite, x, y, texture_width=64, walk_frames=5, attack_frames=6): + self.grid = grid + self.basesprite = basesprite + self.texture_width = texture_width + self.walk_frames = walk_frames + self.attack_frames = attack_frames + self.x = x + self.y = y + self.facing_direction = 0 + #print(f"Calling C++ with: {repr((self.grid, label, tex_index, self.basesprite, x, y, self))}") + grids = mcrfpy.listGrids() + for g in grids: + if g.title == self.grid: + self.entity_index = len(g.entities) + mcrfpy.createEntity(self.grid, label, tex_index, self.basesprite, x, y, self) + + def move(self, dx, dy): + # select animation direction + # prefer left or right for diagonals. + if (dx == 0 and dy == 0): + direction = self.facing_direction # TODO, jump straight to computer turn + elif (dx): + direction = 2 if dx == +1 else 3 + else: + direction = 0 if dy == +1 else 1 + self.animate(direction, move=True, animove=(self.x + dx, self.y+dy)) + self.facing_direction = direction + + + def animate(self, direction, attacking=False, move=False, animove=None): + start_sprite = self.basesprite + (self.texture_width * (direction + (4 if attacking else 0))) + animation_frames = [start_sprite + i for i in range((self.attack_frames if attacking else self.walk_frames))] + mcrfpy.createAnimation( + 0.25, # duration, seconds + self.grid, # parent: a UIMenu or Grid key + "entity", # target type: 'menu', 'grid', 'caption', 'button', 'sprite', or 'entity' + self.entity_index, # target id: integer index for menu or grid objs; None for grid/menu + "sprite", # field: 'position', 'size', 'bgcolor', 'textcolor', or 'sprite' + self.animation_done, #callback: callable once animation is complete + False, #loop: repeat indefinitely + animation_frames # values: iterable of frames for 'sprite', lerp target for others + ) + global animations_in_progress + animations_in_progress += 1 + if move: + pos = [self.x, self.y] + if (direction == 0): pos[1] += 1 + elif (direction == 1): pos[1] -= 1 + elif (direction == 2): pos[0] += 1 + elif (direction == 3): pos[0] -= 1 + if not animove: + self.x, self.y = pos + animove = pos + else: + pos = animove + self.x, self.y = animove + #scene.move_entity(self.grid, self.entity_index, pos) + for g in mcrfpy.listGrids(): + if g.title == self.grid: + g.entities[self.entity_index].x = pos[0] + g.entities[self.entity_index].y = pos[1] + mcrfpy.modGrid(g) + if animove: + mcrfpy.createAnimation( + 0.25, # duration, seconds + self.grid, # parent: a UIMenu or Grid key + "entity", # target type: 'menu', 'grid', 'caption', 'button', 'sprite', or 'entity' + self.entity_index, # target id: integer index for menu or grid objs; None for grid/menu + "position", # field: 'position', 'size', 'bgcolor', 'textcolor', or 'sprite' + self.animation_done, #callback: callable once animation is complete + False, #loop: repeat indefinitely + animove # values: iterable of frames for 'sprite', lerp target for others + ) + animations_in_progress += 1 + + + def animation_done(self): + global animations_in_progress + animations_in_progress -= 1 + #print(f"{self} done animating") + # if animations_in_progress == 0: mcrfpy.unlockPlayerInput() class TestScene: def __init__(self, ui_name = "demobox1", grid_name = "demogrid"): @@ -18,24 +100,25 @@ class TestScene: mcrfpy.createTexture("./assets/test_portraits.png", 32, 8, 8) #0 - portraits mcrfpy.createTexture("./assets/alives_other.png", 16, 64, 64) #1 - TinyWorld NPCs mcrfpy.createTexture("./assets/alives_other.png", 32, 32, 32) #2 - TinyWorld NPCs - 2x2 sprite + mcrfpy.createTexture("./assets/custom_player.png", 16, 5, 13) #3 - player self.ui_name = ui_name self.grid_name = grid_name print("Create UI") # Create dialog UI - mcrfpy.createMenu(ui_name, 20, 520, 500, 200) + mcrfpy.createMenu(ui_name, 20, 540, 500, 200) #mcrfpy.createCaption(ui_name, "Hello There", 18, BLACK) mcrfpy.createCaption(ui_name, "", 24, RED) #mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, (0, 0, 0), "clicky", "testaction") - mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKRED, (0, 0, 0), "REPL", "startrepl") - mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKGREEN, (0, 0, 0), "map gen", "gridgen") + mcrfpy.createButton(ui_name, 250, 0, 130, 40, DARKRED, (0, 0, 0), "REPL", "startrepl") + mcrfpy.createButton(ui_name, 250, 0, 130, 40, DARKGREEN, (0, 0, 0), "map gen", "gridgen") #mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKGREEN, (0, 0, 0), "mapL", "gridgen2") #mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, (192, 0, 0), "a_menu", "animtest") #mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKRED, GREEN, "a_spr", "animtest2") - mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, GREEN, "Next sp", "nextsp") - mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, RED, "Prev sp", "prevsp") - mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, RED, "+16 sp", "skipsp") - mcrfpy.createSprite(ui_name, 2, randint(0, 3), 20, 40, 5.0) + mcrfpy.createButton(ui_name, 250, 0, 130, 40, DARKBLUE, GREEN, "Next sp", "nextsp") + mcrfpy.createButton(ui_name, 250, 0, 130, 40, DARKBLUE, RED, "Prev sp", "prevsp") + mcrfpy.createButton(ui_name, 250, 0, 130, 40, DARKBLUE, DARKGREEN, "+16 sp", "skipsp") + mcrfpy.createSprite(ui_name, 1, 0, 20, 40, 3.0) print("Create UI 2") entitymenu = "entitytestmenu" @@ -46,7 +129,7 @@ class TestScene: mcrfpy.createButton(entitymenu, 0, 110, 150, 40, DARKBLUE, BLACK, "Left", "test_left") mcrfpy.createButton(entitymenu, 0, 160, 150, 40, DARKBLUE, BLACK, "Right", "test_right") mcrfpy.createButton(entitymenu, 0, 210, 150, 40, DARKBLUE, BLACK, "Attack", "test_attack") - + mcrfpy.createButton(entitymenu, 0, 210, 150, 40, DARKBLUE, RED, "TE", "testent") print("Make UIs visible") self.menus = mcrfpy.listMenus() self.menus[0].visible = True @@ -54,22 +137,42 @@ class TestScene: self.menus[1].visible = True mcrfpy.modMenu(self.menus[0]) mcrfpy.modMenu(self.menus[1]) + print(mcrfpy.listMenus()) print("Create grid") # create grid (title, gx, gy, gs, x, y, w, h) mcrfpy.createGrid(grid_name, 20, 20, 16, 20, 20, 800, 500) self.grids = mcrfpy.listGrids() + print(self.grids) print("Create entities") - mcrfpy.createEntity("demogrid", "dragon", 2, 545, 10, 10, lambda: None) - mcrfpy.createEntity("demogrid", "tinyenemy", 1, 1538, 3, 6, lambda: None) + #mcrfpy.createEntity("demogrid", "dragon", 2, 545, 10, 10, lambda: None) + #mcrfpy.createEntity("demogrid", "tinyenemy", 1, 1538, 3, 6, lambda: None) + + print("Create fancy entity") + self.tes = [ + TestEntity("demogrid", "classtest", 1, 1538, 5, 7, 64, walk_frames=5, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 1545, 7, 9, 64, walk_frames=5, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 1552, 9, 11, 64, walk_frames=5, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 1566, 11, 13, 64, walk_frames=4, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 1573, 13, 15, 64, walk_frames=4, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 1583, 15, 17, 64, walk_frames=4, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 130, 9, 7, 64, walk_frames=5, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 136, 11, 9, 64, walk_frames=5, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 143, 13, 11, 64, walk_frames=5, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 158, 15, 13, 64, walk_frames=5, attack_frames=6), + TestEntity("demogrid", "classtest", 1, 165, 17, 15, 64, walk_frames=5, attack_frames=6), + TestEntity("demogrid", "player", 3, 20, 17, 3, 5, walk_frames=4, attack_frames=5) + ] + self.grids = mcrfpy.listGrids() self.entity_direction = 0 - mcrfpy.registerPyAction("test_down", lambda: self.animate_entity(0, False)) - mcrfpy.registerPyAction("test_up", lambda: self.animate_entity(1, False)) - mcrfpy.registerPyAction("test_right", lambda: self.animate_entity(2, False)) - mcrfpy.registerPyAction("test_left", lambda: self.animate_entity(3, False)) - mcrfpy.registerPyAction("test_attack", lambda: self.animate_entity(None, True)) + mcrfpy.registerPyAction("test_down", lambda: [te.animate(0, False, True) for te in self.tes]) + mcrfpy.registerPyAction("test_up", lambda: [te.animate(1, False, True) for te in self.tes]) + mcrfpy.registerPyAction("test_right", lambda: [te.animate(2, False, True) for te in self.tes]) + mcrfpy.registerPyAction("test_left", lambda: [te.animate(3, False, True) for te in self.tes]) + mcrfpy.registerPyAction("test_attack", lambda: [te.animate(0, True) for te in self.tes]) + mcrfpy.registerPyAction("testent", lambda: [te.animate(2, True) for te in self.tes]) # Button behavior self.clicks = 0 @@ -115,6 +218,18 @@ class TestScene: orc_animation # values: iterable of frames for 'sprite', lerp target for others ) + #def move_entity(self, targetgrid, entity_index, position): + # for i, g in enumerate(self.grids): + # if g.title == targetgrid: + # g.entities[entity_index].x = position[0] + # g.entities[entity_index].y = position[1] + # #pts = g.points + # g.visible = True + # mcrfpy.modGrid(g) + # self.grids = mcrfpy.listGrids() + # #self.grids[i].points = pts + # return + def changesprite(self, n): self.sprite_index += n @@ -129,12 +244,14 @@ class TestScene: mcrfpy.modMenu(self.menus[0]) def gridgen(self): - print(f"[Python] modifying {len(self.grids[0].points)} grid points") + #print(f"[Python] modifying {len(self.grids[0].points)} grid points") for p in self.grids[0].points: p.color = (randint(0, 255), randint(64, 192), 0) - print("[Python] Modifying:") + #print("[Python] Modifying:") self.grids[0].visible = True mcrfpy.modGrid(self.grids[0]) + print(f"Sent grid: {repr(self.grids[0])}") + print(f"Received grid: {repr(mcrfpy.listGrids()[0])}") def animation_done(self, s): print(f"The `{s}` animation completed.")