From 8b4877fe48d21d7e789cf52f81c1d6a87b06bcbc Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 7 May 2012 20:38:46 +0000 Subject: [PATCH] added collision engine, more or less stole gameplay from sdl-test7 --- data/font/Magra-Regular.ttf | Bin 0 -> 45536 bytes src/app/Application.cpp | 119 ++++++++++++++++++++ src/app/Application.h | 64 +++++++++++ src/app/Control.h | 29 +++++ src/app/State.h | 35 ++++++ src/app/Timer.cpp | 21 ++++ src/app/Timer.h | 33 ++++++ src/game/Collision.h | 30 +++++ src/game/Entity.cpp | 136 +++++++++++++++++++++++ src/game/Entity.h | 74 +++++++++++++ src/geometry/Ray2D.h | 35 ++++++ src/geometry/Vector2D.h | 177 ++++++++++++++++++++++++++++++ src/geometry/constants.h | 21 ++++ src/pong/Ball.cpp | 35 ++++++ src/pong/Ball.h | 34 ++++++ src/pong/CountingWall.cpp | 37 +++++++ src/pong/CountingWall.h | 40 +++++++ src/pong/Match.cpp | 213 ++++++++++++++++++++++++++++++++++++ src/pong/Match.h | 66 +++++++++++ src/pong/Paddle.cpp | 64 +++++++++++ src/pong/Paddle.h | 44 ++++++++ src/sdl-test8.cpp | 26 +++++ src/sdl/InitSDL.cpp | 27 +++++ src/sdl/InitSDL.h | 29 +++++ src/sdl/InitScreen.cpp | 28 +++++ src/sdl/InitScreen.h | 37 +++++++ src/sdl/InitTTF.cpp | 28 +++++ src/sdl/InitTTF.h | 26 +++++ src/shape/AABB.cpp | 73 ++++++++++++ src/shape/AABB.h | 52 +++++++++ src/shape/Circle.cpp | 110 +++++++++++++++++++ src/shape/Circle.h | 52 +++++++++ src/shape/Shape.h | 53 +++++++++ 33 files changed, 1848 insertions(+) create mode 100644 data/font/Magra-Regular.ttf create mode 100644 src/app/Application.cpp create mode 100644 src/app/Application.h create mode 100644 src/app/Control.h create mode 100644 src/app/State.h create mode 100644 src/app/Timer.cpp create mode 100644 src/app/Timer.h create mode 100644 src/game/Collision.h create mode 100644 src/game/Entity.cpp create mode 100644 src/game/Entity.h create mode 100644 src/geometry/Ray2D.h create mode 100644 src/geometry/Vector2D.h create mode 100644 src/geometry/constants.h create mode 100644 src/pong/Ball.cpp create mode 100644 src/pong/Ball.h create mode 100644 src/pong/CountingWall.cpp create mode 100644 src/pong/CountingWall.h create mode 100644 src/pong/Match.cpp create mode 100644 src/pong/Match.h create mode 100644 src/pong/Paddle.cpp create mode 100644 src/pong/Paddle.h create mode 100644 src/sdl-test8.cpp create mode 100644 src/sdl/InitSDL.cpp create mode 100644 src/sdl/InitSDL.h create mode 100644 src/sdl/InitScreen.cpp create mode 100644 src/sdl/InitScreen.h create mode 100644 src/sdl/InitTTF.cpp create mode 100644 src/sdl/InitTTF.h create mode 100644 src/shape/AABB.cpp create mode 100644 src/shape/AABB.h create mode 100644 src/shape/Circle.cpp create mode 100644 src/shape/Circle.h create mode 100644 src/shape/Shape.h diff --git a/data/font/Magra-Regular.ttf b/data/font/Magra-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6e252b0c249f67a662d1162907033c7d39fcf4fc GIT binary patch literal 45536 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%0D2=EZE8?@~Lw(L22x0fAkTGW`BR#GsSU!5JB zpf;U*>cHiv4)DROlA`W&4^_Es75NP}c6J}~-|^saw&=m*XivtY3h?Q$XZ7}sj;^}E)6b7>T(qz?ugHIrZ}b28@}6!qgLWz=hIk|3Odx5+ zKyn?yWs271`5fMqAhZr*dl*2)fh)c~a0QFX^M9^??~bMc8RF!kfu-4LaA7@ooPdm) zGiyz?VObUcZ~9J0cZz#K_ud~=$^8*tEr6T&3c*b>f(8=?GE}(A$REzm&+Th_V#|G< zqocE1I%+{{HJ+Q!Hv3;qPsxjWkC&*aLnI*aQ2!SyKwZgRl(sjoOvP8elsb z>m_g3(NWDBm2a6hJG-}~BCUMyD@zNO%&%x@T$bWa&5JSf#Typ)X-i$Dx#bp%BPZKj zbo;jE9#6#*Z*g3fF;8DsL4D$fJq7ql1_4FbeKrjA11)7#AnLo4liKW-+qmr-X50Cfqhjrth^!0Hg`UF4XUqL6KK5@StD?mJCpeGId zt81?siHaV$^t;Q?iH=&jdr?%>PX5Sv4>yRO0pWQ(L#HET`IA%QPqeYOCoUoW7;W>|*xP<9`{0<|PCj?D_<%kHGFWn? z@Ns_Pa@P)8ds(30qmUKTVQWT|0hX8(>(88$#f(JDLV@(Hv* z83_fR`HT7OUe-v%oD&p{|4Jd>RLBO&j~GB!4HdrlIGLL}|#OLqLSc_hcZ{?gi( zjI_m`SJ}SrEgDu=m-)}N)um)Ja96-aZM+27jKqVO%jbj+rz{yrPClI+Ki-~f5p?>g)5yk>ho<0)&>_#*!SIUHP4p!N?Lmt!cW@Tx8w&J>AtKv$d_fe&qsFYwXz-v;2+h7ab6#RnVcU*dG925j+a*Xou`Qm5DTI zYKWH!&>gcG3{)C?B4L+Tl7R&(jT?@3*;d7zARpXlAbuz$)i09FWmm?>wWqBcO-wcF z8hiT|<+We_QiDdLW6n(5;JU)@9sLHa-k3YrmT%ZwS+w3=2qA&1Ycz#5L#udFLTr{= z6Yaae(Y3e2qmGU>7p3Qz3&s|#9zT$q>&(_^VpY*cPd}3M`;AvAX^{~X9*CJo`mAX7OOmgWc5_b)H7HGVrsMI1q!ShTgtonoEk zWWR4a_omrfvV2yS_JEc*f*ts;NFUsGr9IIFJQ2@nWY3_F7+9DCmR~R}jiS9_O3ZqV z$7ffwvy1n7w|3=T(dMqtw>ORyt+S0pN0qYsGuCW)u;M~@{dfC!SbWB$@d52)mA>E{ zY!dKe4uByIxCu>gUa?|^-2<^0N_f($Qvc7AW8A+OL@ zZqe!OCWHOr5pPR=QRX$;0hA)g4|?Wkw=M%822>MqVG&qz<# zHKi}`4ryma5Ayg~U(BhGtJWD;Z277~y@|GO>@Q!i*I|RhIyaM~|69cZ+4J=^mWBuP-TgGmT^`B3i8fZfsI=tNl`yk0y5ZxiWRI-8o>$ZP)WM?!t zXvhD}W3_%TM7mdxNj!*qNj|50=^x1%c=68u9Xl4P2Y2jTuu!vT^{7TX%P#Zprsq4^ zceMWH)W(D#GR~ub8Jq=^WPp&SaT;inSo@;y{$%-i(dRC{{kzLHMDt|rXa0X^UwK8# zl0MfyBKnU8kG>txB6bh`lkI`HjL#u}o;`eSfjwnKZeICtY}c}-Th&~TKCfzY*0b)Y zrpgalnbzMgkAw7;t6|fclzj|#AKUF8XXZrzcgDYt=kfjiZ_gTF8)eC)#d6QO?kC-Yj3B~S*JTUYeToq z8?EM+1ff&FCn3Ge{?7V|_VVD4B&3j?6$Tr!B(Tjz`zkD&l$5mg6@gz`Uv_Dub;!?V4rw9A4(_NcG?0bY*C2y2~x;^0@N(0@eo~Yz%QhGI9#{ zYo%h$UFELzq`l=yv%C4TweH%q4EpZ|WtU9c!C&BG!lD<@nT6pkAR~gEpdkk=mq}`? zLvmQvNmxUl^na_Y!`z+IlabZYUG?oJe#UC={F(omJNbh1{1Z1^{PhiN>87Rzb*{Ck z?Sgc>#@F=Noxgh8|BL5-$(#p&;P>Brs|<54Vx&g-OIRl)(^bAd+)PkHX_I)1y=cS&Pma&Bstd*j*3x`Nz1V|lj! zH(uw;co-9D-t(nw#7w;$@HG?F!Uad~?=4;0c+NSWi+A?Kv(F~K`DU_sr{~DGHq5?a zU1Vos@Tx%v{i?^mOUJrC(%#t%PhUPWvJ;>cvbkg;Hb}9%m|;~l+2M>6{tX9M4|y4K zg*(gTeROqhj;F1rCfV)I(i?LAc;WBI_PsX7uJ6BhDco%Pu_ZP!r4|^pmXHA$_vgU|^gIAI3%W|ho&Kc@-x0CI{&I(yI+JW6umiRPA;UvSJ z=7WR@`XE1=XtA>4+?uAsg4vBDvlM?1{|`a2@wW8Lxy30D)1Df)Gbf( zXjO3|i)u?+%SH}D%{Eu|n37rRwOal{tp7%ry8`kI>2F07Yk0b_{g?%{!#-hD!zJ0k zAX3r%RGRfLl9JoJ7Dl8T4Nos>tX^MOZfY4_{Ijbn{}632PEU8iAn6(ZTjOxStcsk< zmet*nO|XL)ubJW93^*`UKUqalicGlm*~?Ijcl};L^9BQIbt_n64Zft^#uK^CNpz< zJgAAz_NETxv}k6ta!>5l@*S4j^|X87IwMg{B4ZIfcQQs5B^fci4Om%#()?K)s!*v8jW{u zd`tZ!ca>c??0><-ynp_9SQBjv4EkH;!|JQ624WVsGoJk^FB^Af@E84qQ!t_Q{cH4{ z0=q*Y5IbePC|;`wAh2hu_jeSV6E=xew6d_Ur=+lBIw))}R#vYmVT4xJaGuZ7W?*A8 z!;=PFybO3$z(gf-QqXZUV1k}Eeq%L5%cSX zJo#?)m_RZt(eYGJ@-A>}+vd1nIJBi5XBE$$U3}I< zp^eEjF2=P3dQ_ZPbs=N&K|U5%Mq%p;^8xzOXM0LbRUY{g<`Fz(wbobAi`HIL0B_rc z{E;Sf^l36kC=MPB$|Gr^;BTLlO&$y#g3|sC0)B&ts|gu_vc39(rme71EG!!=EE^~q zNH!ED8^Q*0(o^2)bIncF7vVp~!6!bUMF~DlyZ}2sZG2>WhKCeJX!827k3QDD!_svA z>)%&y&?R0qVL61pC{U$r0lRJN@dDE6y8dJwjT>LB>d4B zhfH&16`DqIp^Y93Qrvst&4$q2qd^#9xs#-~1&*L6zzpCcU*Fq6&Ap>CI)t~ABhFi5 z`O1B?O6fkv9ly0*JgO4o4!A`@TVLbeG!=~-Tm~D9Skbus_8pG(>m56KMpeoXm1hJW zVA{YKNuHWEM(VGF#`XY7_tsHW=y;TNIPLMs6F3I#z=~F&9Ew0Im?+3S*vQ4~gPFqW z5AXLf@_y^Hg!g-{wte*bx@%YMwdwW7{7@G-Yv@qF_uj0(ZEZM6UU1p}n2GVli}e}C zRRCp}zm#nc<1E`kyr(LS!dZIZik;?0#qtz>RDpAOC&26^3l)DRZ|VWe+uIR6s$wqv zzdMavH9~)wIpGYznhmjZhIns}VEP}9+#iv|FK6sd85_|^8p$F7zJL1REtHqbj>tU* zXv+V=jJ*=elX1EOD>9Sh5Q^iR(K|h5!-(vwJ{C5?GkdNZmDxt8*hgeIu zeYdF9B(>s zd0vjCA$!+>%ZnV@4Ytj{vJJN+runKfX4NL;a29W48y`F#Gi+Ma{m%!F$Bm?n&eq3Q z<#%qluRb@%ZtI+5HkRHX_AuGc99SQMzefjMXF+c>y9jH7EeUlw2l!e9w=>qZ@LdPn z1TrGEc@OBGdBfV2S>Wl~lxba|baMnydu93_4{JEcDkHV63c#z-Q3NWA(9xSg+Ib?Z zs}PcTbh=kwf=yn_hj5gg0Q&5WI*CJab_rq z=0N1e(MzX9Zd@dXZd}Tb{aOy)kmC!IVT&l1{R8CB6>Hc6L78k;AUEM1fUryvIncz( z12H)E!=**Z$weKO+Jbf0HfQ-36z6nhn+i(|hLZW~NBH%t`{oWh664ZyvkUYEZABf6 zvbs|WTJjx+WP6p*mXMg!Jnw?>H#yOsD&W7SSYHcyiAcIY&dD_QwNTofUX|j-wiiC` z*&FV|7Jlsn;mGD|Tszu-KgE$!$xo^!k=zGKCg-5z(?)#n{uFJn^-*1C& z+hBVR?(S#q{omLii-@droK>Wq~!0x#tBf@Yyeh~MgF|_#^?$yAC6{=^^?cdwvShd=*xf@S_ zrw$I5?i|mPAA%(vKVJp>ClU25YM_orcc0L+&_)Qq8LyVxAsf}_>|^2kBTFJlf3R#) z?ZwTel&18I+G6h&|0-=8Yn|6g0au8Pz<6Kf$1#@_GY07ayE?diNQB1} ziG51EM^_lzj}-k8Dx}M6<9#s~CSkM0z&KbVt@$%VgRr^S=N)GX2@%`9fBYN7g-nM9 zl#vV;Edo*yU@rsZ2n$*b1gWs~pq{tR2n#s{#*YPJQ=9>q5+cN?D6kOSrNU3DNVMv2 zh?-n^?QT0GL;-o=)Bgc}NG8apT`o)}NFZzTH<`8iFar6{86gZx2OGZuj505JKd|=f z$eWKKBYZ<7{v^nL9ylYAA+)8h(@H)M;H-H5K+~bnVRX&TtUC-Gc(-j>qeb>j8zm>wII<;mmH?sFw0r0o|inY z`dJFFikh1|+xyfmCtIPW(5mq$dT$@g2M>{BbxuJ4N7PS*XdNt{5dM7#+$U}a3j~G9iOAl2i?%h@USzxY@vIU{<%Kzjkwau}@zV6c59d}~ z=>N2Nb*;fB0_0Rb(thAl)dD{g;+HWJJaD`7(`LTQLG5Zk>dYYCG7oV zr4F(7`%DN156x8C2lscV3ue5h2m7L;i;|yQ=%VB+H&54s{h$jV*Zz zMx-Ulz7mRiZxeCv4zl@8iF=1qBWIAK$3_N0Dxmm8ih=LeWTU${KwzykYE+@)4T*;D zj&9Wyof<m$B-FxMb?in-t9#Z_b3NDWTmynGk;nEO{6`zXHS7rb3 zlxzf69BBN1hEu9#0aNj55*1&(z)e`48K)PXMMw?O$GaF4g1sV*iOIc99T3}cUKMSD z)2QUWojXg1hXrq;+$)#x*`x@sZJ1|BWJFRTh)?byJS%dqHF@6Z`vap0$&6ex{^^#6 zH?H`j3_kc5=$r2laquZZUw{!sE;~Ru;lUIR)JB+=B0ZIx3amiAjekO?v;+(6b>q!gAhmFn=}k)EDl7E7j^vRF)olUXctnme?8 z&HmDvGFcSgF6skPWDc_DWdAiXB=fNQ9aR!h$piW;5jH0L*5tLOEmNK=*jOGEc7Ze4 zSkT~%c7WGK#+KY2s3{eaBD6l}8;g=0PsVw^$dH6!L1$~{Gd|KCcl$YsTT`xgAc*vS>>8k6Ie)7s@2apTgR zV(%2W-r&dC!h14x@0^nDP0|PL+%qP9e>b>q&yf2avTsKPa?Hqn;Xh*BL=JnS$Rugf))Jk1%BZLnYSxDMUVe~ zg|BL0ehszN z!#=}Sj5*em758gij`wA%>o6KOpO-GF*THnH&v~ zoUEha0u$gevm)11b7%MEvLh9+r z%Lnvulks)U_+H=(b!8>#dDUKw16hoyW}u(svqwiOW%*EyRkXG@%$a#P#3>fwi zPT@|2EHyD7^)!y*d&IU-TegsjE~9LFu&4{BExfQx6zWn{v0IR*E!)c>K_LouTHZCP ze1zn0vjd@N*smzr+|%>1$6p3~!3=LsHD{O+bf%T*j5?wi7kxlP3KXB|8FQ>!?1p zz@J>(hII$nZmm+}COgPv`A4({g5_?wv=4xxnk{mWVrey@G)f$CB6jQCM_$_SxN3wa zXMW=UlBtfFRJT1Rd>oX zBVw3>8S9MU_KkAdy6R5cKfWq7d7Wq^Hc*R)bWTx?XL9F}dwf~hW#nGR^Ma#A--S4- zLe7&1wkQ)twhm0@%-1oP1Qw$V$HpKWlQPUC90lUZdt@kBs{G`xPzW#pTK&jFrMfzp6>Kh~UQ+_Q{)s(% z1O)Tvqu z1XZ^%(LELs{2<;*|E2Wfhe+vYkG| zO9Cs8l})KtF}aR^5vghgx*%JJm}jCMy$FgFdHG?J%rjFg}FW~l(+@*lZki^@{>v5 zEQaDzYM#ZP(bo)~$@LIDWm`0t%!+^~h6cHBYrJo4CCx+1jAIDSPpS8zbOd7AJ* z1th<38cXtnKv#h}Co`8j;j*GVzUZ5vBM=YYg43NSJ}RBO)3i6|;dS~9gk^R2m$Ny( z$BOGCN5TKN{<@-@TKAP5ojC$tj?0)pJTdhxVz(U*V^vH zYy7w01Tn%FqoSIK205EHVCRP6RW>@>G|@^jDWz!m*uMg%?@a}TpIvrQv4vf!^MA{= z#FrhL7_Yala_7oMO&weGz_Yrc_%y34zxkF0`F&=L9{vjz!y322E(T!<_Sv9abFxAd zMPn*qM`o%A8d3(w5kRdPjp?BByYnKBP2`hYbe`OAQZ)7(HDJ z7s_>VoTYuklVx&lUD+&`n*zKe*c2?-e<>#&JTFkEGrXW4MH!6zVfDcL(3*PJ3%PLp zt!JeM%IaMis>S4uN;<3fFv1!tVKvKjeoaZBAU?Sl^up3XEf)Qmq zo(gtwGv;#LL?N@0T?rE@BCbS*p_!^DvMnH&3(r(SQDi(EJ98OD$Qya0zR?Nnci?m6 z=S1$keTE801fpE!D7r5@VwIy5@{fyBN3(5ZS<@>Wu_KDFT-1z&?wF@!PMp4KWFT|z zjKw2A4ovA8Ye=&7lXEQN;BDXlri(M+AOOf|(eQ$7bw4d4ZV4){R6ny#)X(%Py-%s1 zDUwrz$*hQHrI1#t{2RHT=7!8%jqrRtpQL45u#|)+Or?r!5}Fw(Z(gymToTh$LZ- z$Sx*iZaXCegc1!*l%hzgT@ykbMqRLEYH=u{d*uSEOo~ODRF@1Z!+~~iQoD?Y(cWC+;(qXTIlt>E@COaqz=RDL zzy}z)Qt0)wz+w;7dp$>4(eymkQ`>-Z*R&+7NWskvtp>#D8iE_$aof z;uX~mu7Ye^cB{evco^_2wh-Q7c4aRD@36!Kt--Ja3v^qqyKeM`8v;oFpx6IPR^R(U zpf;@$FfIjd#U6~H0kZ!pxCK}!QbMgXs-6Zm&p&^%`dd$rQvdDhW`|M%uDJPXxdxn) zH%NJB>)wjHX)WYt?|SdvnB4cwlvuwy7=Q&auI?ZkmN&f{`l5u!NtVSR-~aEA31 zDTs4b&?K#liF7m4x2KPZLM_5a0wsxR^h_VY-94ZWIsWuPxxEN*tI%E;w2xD3k)V76 zMSv9eNQWY=bUJ*BSvwrYptdv}%Amblft6xq(RKt_l?aP4c$WsWqevj%t=Q6)oXs0V z+ob7Chui_7fHJTq3q6F7;jKWWha|l-Ngn~-hef7UZ%U#Q|AovZtfct!|PEYylkUlAw)(xGG=qK_Fk#mWZyztSjRFt|1Bl~AS zp(8mIV}iZ-q|$zbF;TQMwI4Q;B1Kz^FbY*vKtIE@Ah%Ywr%*k5J$P?0I1^zbQ_DKK3}dP`s(RV{qHMXmgYYc!tdJ`$=Veo^TiC?IE7gVMP9F@$jO!*7s6&#mPhAx<2+SdQR*yl4 zA-_vV)o>#8@XFz=UMRXs`EbPtLe}c5q2Go+4?%-a7+QVvBhqMt6*xbXEFM@U#W1WyD^{|X3=iYJa}QHDeIn<;G(9FuK@)B?RzZYc;)j?$8X4?3R- z)jxtT;iMHgHZ`o6I$InFgbEf_zd8`VslfAYSUadls2_ri6SdC5DgbX|Rg?FBm5lH{SJbbd0WE$-~Cv;5l!1`XAw)*-gML%rp3qC-04;0t~m z+BQ&}RkGJgRU4f?%9fzaRhW??SRN}5u(;;JOg0o-(QU1YO~o?>A`-xLp9&6mhFwLHkKirom&a$s*BAK9o=j8PG@)_xo`F*dGqS&gdx zY*Rz3|DEZDm3x$e%Ffcxq@3I$?UMZTw1!veBc!egp8f?t418csGE)#2(|2HQ%t-|T zJo7>;B=BQ%_0C2NyS*yYzjFGq1%j75s^%1&Kn76QPT?Yho&HC0|D6~sR&eY6FCmV7AJjH>93g0!x&0!ys^IqkUL<)6SF1xGs@ab2}p@!qn$}ta$yVK*chWDiC!Lp=udrrbLGoE@PSG+y7k7$e}ndtO3*^IDr*V z2%ktbS`TKX2aZJ`qj#_b0ZO%+z2-pm0nsr@XI@d1fE$!T1g@*(G6Y>?av1_El_?mK zOAu_q&U$N)KDj&#bqSC_E{YKh4TshuXhe~MK2e2${OdT_)4hu&PBjP zCb)W`fETt_nW2mHYi!15;Yl;%pow5ICBe$t&x;##a%1R3p4A6ySSK0F$#+7zohL9S8L%ssg}{Oo>0n79Bz%(5 z957Luo;YY!$?#;Rsp*|a^dz75b#jiUvm%h>$bD_KFPp-SY&y&?{cOE6Fsr^ z$W9d-I3ove$riLJRzA7FYQU&B83}PllPBYfJ^qYF&+*@f+2`{BlU&;#^A^FXr<8o9 z(s`4v;?tTw-wMETI@_oJa0nEbBymmz#X%v`X7ZGXK-f=6ybth*`n24~21T6#rQXXM z0WmlbuPpAV#y!N770)~y49G|_Z^At`-p}SD|5<~3l!)WGitkeP7mEJ!d6{&Nh^G>A zvsioH4YK@qL=pQizxljgdX4`b?Lp%pT!yR6`C&@(BU4mjz+*vN+D`#7tX<~G%sa2I zQhi=VK*?%OZYVCz4QOxeI?7Wdd@Nv_5vNDecbKV#@i6-e59WvCF~Do*73>F)Jwy!% zQZYzke?-wnx#Akcy{H2@Q4>77Zdx5kszMMx*04=~MPT65>p+gr3NHjnyw4jvhey> z2QeShPdO8ckchXzStKXGMXk`#PInp!sYVe`Bw0kxml=;GVP@I&f^o=tH`QB(PHX@( zjG%P?$?<}Xbwp6OJ+sfMDvYdc6J5#r_6e~!PSdxE@lI2={lB8xFcDPkxpHBcDe%(p zBf!f}0>$j52mn(xv=uV|d!M z6eC9gl{nc;+V{UB3?f?8ju#2rb7vS!bO86y0{5w~-xN|U;b|5RMW2;xq~pi{r(C}^ z02zrE(?o;7!zP(-MaZwUvM**rcK4 zHz2zZ0|T!HwTb6XpT93^4^7M8zm*6pl69nwC=0Uw!~#a=qs78!54);jHSkSVlKWIJ z`oy3m&MM zZbGcBT!hN*;enIgp33em&Mzua^*K$pkQgtIV*0x$ zPko~`E5rXO+9zKLLIHw}L%hspA*ZT{o>;Zgi8{NtDP%C2n=|Q*m0wTxmZy6^bW97_ z=mK%#iZUj$oxxibN)O?i*d%2{g>7dc6TstwZi3)gj>Gywp8KgYUoE{`}zW=`NxH7e-Ml+9yj`2t-cGGeLGD&WZ?twxKX(wz(q=z`FL< zmYnvD@Iq2sfR&XiZ5cv(_u=dkr`PQaLVba`!&R6P2K!tzlZ)o4or$Yixflar3LV7^ z?Szgg*bL+sJM`Y4Kt@u|h!=aFlY|~04pYRrrxY$*a+Sq$<3}2&GlnM?7bo08A32Z7 zFNk5$4_U4Ej#sgxR;#~{J*6qgholNgFMr|__Aq}s&~6H}4l8B;(~gP;>4n1ve2KJU z;gl8)eT96;z+YWgWoO^`k=p6he5Ad`V$mcdfDU#-s1Q-A#)#>ofzzyIRu~k4(Lc`n zklqvLeV}?X4O%|uBXGip3}fg$0xxSr4+s$VOpH(bi*4j@(VC)K_-v#9g<9r?-N>EB zUj$vG;4FiA;v59n46vlB@D!rMupBUGXV7JIq@*#)GBmrmF)3@fv(!1SJf9UhthKW? zoRw#-?Kyi>LvQc5dV0St!(~I8D+6aMP+%KQ-k@^`#5wLp<9gS_ng<-n^T%P;Kmo=?D;P`~EuM7=Q)WGFWh zelAo4M{^u4BC%VX3&rj$-dq}ezvcRi*;|)nIZ5H{2;s zhT<{$%9?g}dznc&8A@w&WY@*I>tZxXcj9Cy;KwS}^LsFkT)CDYm4d@bR~QQBHh4?} zmWIzxg>5zV3`V4b-&pFbc2<)(lDN^lJUZ6kFk6ybHH$3K^(h+`7iJ948uQe4^=9xD z9X_>6JvVLLEPK^XL%y~?eYNqw3hL)Q!?XQgwl~&22^z_qc%J=^9~62^5mnyk<`0XH>B>?c=vcsjf;+? z4kWay+7nvMTOO)o;~DPS#*FL+Z)sL-<-=9c*_qYq1#4k0A^J>X`*;)LJ~U)uCtESb zs)425p2(ecGg96vvl#|oX}HTb9Q95VGev2%HJ)~Lv?s2|t&7sSXKDG>{?A!_S(*Ry zSzX0h8ri&trQY-8b1v=115qkW~Qz2GkGy@qGC&lmG6|Ju90_p|svi042xd@a8-kmqFpCc*V_zVfbroESRs-^C9<{4l@M z|DgX!EL+Ihx=;DPV#M@ut})(@@&5>~GRPSx%le1_=pR*w1*>L1s5-m#o{^Dz=y=)Z z=GO4CclF!{zt?ChYlWk@aX_Qm)K<^1j z0u4<8C0vlL?l017DmvGMY<1H@O;QVcvbRys8CA>B6_HGNaSvN{yDp#jiinFp3Oo~+3Rqbw_Y}vp+~&$J8!0P?d+h3(nxd?%@h<|p%wm1q6%yvB<)F~hsAs9AZA&#a|BDIW1Iv_CIZyyQQti-QTydu#4|39B4hKG_k*V`36s0{`ocTS)HC? z-~?^kC%$BU@L7y258DDA>j(K-CFJYxtTzpe_&@%j^_io(Ij_$?puJ&;9e4Rx_Fo0C z@T>)JJ&ZU>SPBfXFf8JqA^Bm;!p=wn_FtEuy?^1h&dj04OMBK<7G<((-JAMo8@p}g ztLM1d9M?5BW>{E#|8*IVgoy{#q0P@RR+4Qcs)+?5ji>?BmPEg59P%07DBx~lZF2{B zM!uXo)p06 zef)Ys{U$ZnIK94PAGWglY~Sr!sIC2h-G3~OU%$M@|H#oI<6btWW--Ag=S95(*bMLj zLZ(vWZk%gDht|Qnhlo|Tvoy*{VPHYY+wEvy^VmpHLu1$Wm(TK;JZo8XYFu27u2@}F z($cu~r=|5Zu1p`oJ^IgSD9Y+PxOJp|5XU!q*7~0aH; z6?iIvF7}~-1$gp71Se0Lh|NnPA>5ZjVmN>xIsEP3VV>MqJi2Q8+pA?PEgq|`onKVf z{{LFL?&vs*GyZ+2)1Gw2UDwBQ$l*+1#rsarI1c~Z!f)?{AOnFZbkg^2QR0m`F`K*wC|g5 zW_M<1XLfEoZvMnGGy4ud`5crKOI^F7d-(}lw+Xw5Eu*LKJtFMl7<4evnWv{B(@e2L z(McufXcfL2J}AG}&B$?AZPrb^d_T7K)$X+HUFU4s@^bj~aJVUm{FMFhp4ngTVwDL> zq<*9HaEO^2S)7b0elbe$X(7h5FWVuGBg{=9Zlnx95n>JgFNQcli*R0pN~ejAj#Wa8 zl|r%oAx_cp(1i++e(7eVDXn^CmKhT5tR~X|O-0T&O(Hs_M=!!56 zw33&G81Hg;cZeHl9`6e=Rxj|gAx_W$zZBvo(qqFRZU){J;uN*To(^%E+OW=A<&|N* zVN;0b(6Yuj_S|u)MAPJvMFlESKsqg?9M*T}__C`F-xIW>57V)yiAxTyc4J<`1NLM% z3x4C^R!di0AFo|sB;!?(Zh&-k8X%K={ChM7HxHkFGH6oz>S#%Q;0m~E0MF)i>=YvM zTtKwOElqn?p%~~3bBpw)ZSC!g^={V*y33yH=?g7q++95meq8X27V8x&DCz^IZ+cT^ zUhg+1OM3WO)ma#zu)eux6ob8vrAaXbS%ZWH%5`=*0)J zrCc2-dp#||RkcVX)|6#9MxX2WhCO9==rW@YDaDZrFd~)ZBP)@Gj*4hOg@`Jl5!3T6 z*U{Ts+St$ zS%4PR4Oes8)?b8;>!OosUak$G+u2oIt@xK2PmP?x(R)&5H@HIyf7fuB+9^|enj&U z%|?VB#O5WvpjpT&!qyw34*zHhqM;tiYJ}zJR4>`=e5<7~V88~_69zv9SL9u9zQTUG zF@?Da)IiyUY0p-h4_QPvQo>aqISR|QK}Ba#Kn-OPzn5sJ2pbY@Rv&c7gNosq!l-O3 zXF5LGXxYh|o*ooUeXyrj&z4L_1@2V=u&l9W`|T~dOe~BmZF9=7Y-7weRm(T@?#@lR z5p?Kb-TOJuDg}OvZ`m!bS7^<4qeQPsjQ^D&?nCnT%0aaLBmDS&c;e9;Ju&V~7}q86 z9NCO{uN2mSW-wkl3Ug|6F@`-B&p*du4EqK=TZ!-KPsB{dNq8cf59PlZ{o%=&TRH{n zdQL^3y$Ej<--bSS2~^%HyNRWE!?+CleyzZXd@He5sRL(sufkjMchS4iV|QXdyEU{H zyMlGoI_xLWgZYe&sGvUd%USfeo6rLe!f1wJQloSxZN@jW@1?DD7M)Go=o}cqopd=} zL7$+T>F0DM?V+pjF5o`8i>{(?(PeZ4{ek{S*U~Mti#|u+!}+_n(ti3g{fYiUchCd$ zJbfN_$1xbqUYPtLnA>yo0)3gjKwqRU(J#=Dzk-u^U!;d%Jin*w>Fe}W`Wou$SM(d& zP1|8y6KK>n8pLfdv2$T|9!#zb9_PT zjxn|Y;6}y~L-=^=-cj^1|O?sIx;0yU8zL+oJ zOZhUsoUh<3c_;7U-Fy{a&DUVl>OJ%*Jw}hy6Z8yyln&CfbSZt7cG3a*Bz=lL&e!o? zz8>d|-@rHGS?sTTGvC7Rm>=Os`7zAI9puLoos&k+bDe~tsMa~=nNy}_ zNRsGu3$9~MBn(AUYjT#CD^HHw=8oi=yc-xf^g=;0SA*KxoPp%DydrCnwh<({!c1@v z6q#vVDic$ZWLGVA(yYNmSD3Y_sMe)YG$l!`s~03ysN>|iS^~*J4W`%OrZs7(!lnxm zCbhmEH&v|T`1&!!ix=T&J%MHCP0f-dVTBU(DE;(=g|rln^=yb)+fy6r38l8zae8AU z=k!FuGfl@foV=COdW~E;Fg06}bZ<1A9bvRyr371&crPT3+i4cK$XE$ zWf+KLoAx4%HlWJjDKe;H`I4jt>)J~Bb=)+RGxL^h8%;q7v>_EekR(1Nsw)uHHLR+u ztg34`l%^a?GpwX3OVT*(Sx%v`EZod+RF+IR$|Z)wS}rS^8m*TsRf*uu5j0_ zj3mh|HM>mC)L^6SIt9NmTXa3A(UtD7bj!lkI+e7BB0Y*&iewdW6&Y5fEJ>oXOXis{ zOr_tfZySD5VYiOcgOLhK`w^xICA3Z7-=6FgY8o?bw~{n!Q0tRvX;81Q-%*Sc(0No8 z8C9MYNt#FVmg$+kh&!7OjS4)P)a6YN|~U-%8(>(7RpqCrC<`ysTqa}AE}Wd^iU+2W=R`QO-Mi4O{as%^_0*bqLs$2Ac;P{3WG}3HysqwLxuh+q2U^af~(=7 z-w>vydaI1oZZ(2XZiwSW*PV!2ws@XnY$S + +namespace app { + +Application::Application(sdl::InitScreen *screen, State *initialState) +: screen(screen) +, states() +, timer() +, last(SDL_GetTicks()) { + assert(screen && "cannot create application without screen"); + assert(initialState && "cannot create application without initial state"); + RealPushState(initialState); +} + +Application::~Application(void) { + PopAllStates(); +} + + +State *Application::CurrentState(void) { + return states.top(); +} + +void Application::ChangeState(State *s) { + RealPopState(); + RealPushState(s); +} + +void Application::PushState(State *s) { + RealPushState(s); +} + +void Application::RealPushState(State *s) { + states.push(s); + s->EnterState(this, screen->Screen()); +} + +void Application::PopState(void) { + RealPopState(); +} + +void Application::RealPopState(void) { + if (states.empty()) return; + states.top()->ExitState(); + delete states.top(); + states.pop(); +} + +void Application::Quit(void) { + PopAllStates(); +} + +void Application::PopAllStates(void) { + while (!states.empty()) { + RealPopState(); + } +} + + +void Application::Run(void) { + while (CurrentState()) { + Loop(); + } +} + +void Application::Loop(void) { + Uint32 now(SDL_GetTicks()); + Uint32 deltaT(now - last); + if (deltaT > 34) deltaT = 34; + + HandleEvents(); + UpdateWorld(deltaT); + Render(); + + last = now; +} + + +void Application::HandleEvents(void) { + if (!CurrentState()) return; + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + PopAllStates(); + break; + default: + CurrentState()->HandleEvent(event); + break; + } + } +} + +void Application::UpdateWorld(Uint32 deltaT) { + if (!CurrentState()) return; + for (Uint32 i(0); i < deltaT; ++i) { + timer.Update(0.001); + CurrentState()->UpdateWorld(timer); + } +} + +void Application::Render(void) { + if (!CurrentState()) return; + CurrentState()->Render(screen->Screen()); + screen->Flip(); +} + +} diff --git a/src/app/Application.h b/src/app/Application.h new file mode 100644 index 0000000..73e6400 --- /dev/null +++ b/src/app/Application.h @@ -0,0 +1,64 @@ +/* + * Application.h + * + * Created on: Apr 8, 2012 + * Author: holy + */ + +#ifndef APP_APPLICATION_H_ +#define APP_APPLICATION_H_ + +#include "Control.h" +#include "Timer.h" +#include "../sdl/InitScreen.h" + +#include +#include + + +namespace app { + +class State; + +class Application +: public Control { + + public: + explicit Application(sdl::InitScreen *screen, State *initialState); + virtual ~Application(void); + private: + Application(const Application &); + Application &operator =(const Application &); + + public: + void Run(void); + void Loop(void); + + public: + virtual void ChangeState(State *); + virtual void PushState(State *); + virtual void PopState(void); + virtual void Quit(void); + + private: + State *CurrentState(void); + void RealPushState(State *); + void RealPopState(void); + void PopAllStates(void); + + private: + void HandleEvents(void); + void UpdateWorld(Uint32 deltaT); + void Render(void); + + private: + sdl::InitScreen *screen; + std::stack states; + Timer timer; + Uint32 last; + +}; + +} + +#endif /* APP_APPLICATION_H_ */ diff --git a/src/app/Control.h b/src/app/Control.h new file mode 100644 index 0000000..b6cd742 --- /dev/null +++ b/src/app/Control.h @@ -0,0 +1,29 @@ +/* + * Control.h + * + * Created on: Apr 19, 2012 + * Author: holy + */ + +#ifndef APP_CONTROL_H_ +#define APP_CONTROL_H_ + +namespace app { + +class State; + +class Control { + + public: + virtual ~Control(void) { }; + + public: + virtual void ChangeState(State *) = 0; + virtual void PushState(State *) = 0; + virtual void PopState(void) = 0; + virtual void Quit(void) = 0; +}; + +} + +#endif /* APP_CONTROL_H_ */ diff --git a/src/app/State.h b/src/app/State.h new file mode 100644 index 0000000..548fc94 --- /dev/null +++ b/src/app/State.h @@ -0,0 +1,35 @@ +/* + * State.h + * + * Created on: Apr 8, 2012 + * Author: holy + */ + +#ifndef APP_APPLICATIONSTATE_H_ +#define APP_APPLICATIONSTATE_H_ + +#include + +namespace app { + +class Control; +class Timer; + +class State { + + public: + virtual ~State(void) { }; + + public: + virtual void EnterState(Control *ctrl, SDL_Surface *screen) = 0; + virtual void ExitState(void) = 0; + + virtual void HandleEvent(const SDL_Event &) = 0; + virtual void UpdateWorld(const Timer &) = 0; + virtual void Render(SDL_Surface *) = 0; + +}; + +} + +#endif /* APP_STATE_H_ */ diff --git a/src/app/Timer.cpp b/src/app/Timer.cpp new file mode 100644 index 0000000..48a5eba --- /dev/null +++ b/src/app/Timer.cpp @@ -0,0 +1,21 @@ +/* + * Timer.cpp + * + * Created on: Apr 25, 2012 + * Author: holy + */ + +#include "Timer.h" + +namespace app { + +void Timer::Update(double dt) { + delta = dt * scale; + elapsed += dt; +} + +double Timer::Elapsed(void) const { + return elapsed * delta; +} + +} /* namespace app */ diff --git a/src/app/Timer.h b/src/app/Timer.h new file mode 100644 index 0000000..997d92c --- /dev/null +++ b/src/app/Timer.h @@ -0,0 +1,33 @@ +/* + * Timer.h + * + * Created on: Apr 25, 2012 + * Author: holy + */ + +#ifndef APP_TIMER_H_ +#define APP_TIMER_H_ + +namespace app { + +class Timer { + + public: + explicit Timer(double scale = 1.0, double initialTime = 0.0) + : scale(scale), elapsed(initialTime), delta(0.0) { }; + + public: + void Update(double dt); + + public: + double DeltaT(void) const { return delta; }; + double Elapsed(void) const; + + private: + double scale, elapsed, delta; + +}; + +} + +#endif /* APP_TIMER_H_ */ diff --git a/src/game/Collision.h b/src/game/Collision.h new file mode 100644 index 0000000..e2ecb01 --- /dev/null +++ b/src/game/Collision.h @@ -0,0 +1,30 @@ +/* + * Collision.h + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#ifndef GAME_COLLISION_H_ +#define GAME_COLLISION_H_ + +#include "Entity.h" + + +namespace game { + +class Collision { + + public: + Collision(Entity *left, Entity *right, const Entity::Ray &normal) : left(left), right(right), normal(normal) { }; + ~Collision(void) { }; + + public: + Entity *left, *right; + Entity::Ray normal; + +}; + +} + +#endif /* GAME_COLLISION_H_ */ diff --git a/src/game/Entity.cpp b/src/game/Entity.cpp new file mode 100644 index 0000000..1c3f785 --- /dev/null +++ b/src/game/Entity.cpp @@ -0,0 +1,136 @@ +/* + * Entity.cpp + * + * Created on: Apr 25, 2012 + * Author: holy + */ + +#include "Entity.h" + +#include "../app/Timer.h" +#include "../geometry/constants.h" + +#include + +using geometry::PI; +using std::numeric_limits; + +namespace game { + + +void Entity::Update(const app::Timer &timer) { + translation += linearVelocity * timer.DeltaT(); + rotation += angularVelocity * timer.DeltaT(); + if (rotation > 2.0 * PI) { + rotation -= 2.0 * PI; + } else if (rotation < -(2.0 * PI)) { + rotation += 2.0 * PI; + } + shape->Translate(linearVelocity * timer.DeltaT()); + shape->Rotate(angularVelocity * timer.DeltaT()); +} + +bool Entity::CheckCollision(const Entity &other, Ray &ray) { + return shape->CheckCollision(*other.shape, ray); +} + + +Entity::Vector Entity::VelocityAt(const Vector &p) const { + if (angularVelocity == 0 || p == translation) return linearVelocity; + + Vector v(linearVelocity); + Vector pRelative(p - translation); + v += pRelative.Rotate90() * angularVelocity; + return v; +} + + +void Entity::Rotate(Scalar d) { + rotation += d; + shape->Rotate(d); +} + +void Entity::Translate(const Vector &d) { + translation += d; + shape->Translate(d); +} + +void Entity::Accelerate(const Vector &dvl, Scalar dva) { + linearVelocity += dvl; + angularVelocity += dva; +} + + +void Entity::CollisionResponse(Entity &a, const Ray &na, Entity &b) { + if (a.mass == numeric_limits::infinity() + && b.mass == numeric_limits::infinity()) { + // special case: collision of two infinitely heavy entities + InfInfCollisionResponse(a, na, b); + return; + } + + const Scalar e(1); + + const Vector va(a.LinearVelocity()); + const Vector vb(b.LinearVelocity()); + const Scalar wa(a.AngularVelocity()); + const Scalar wb(b.AngularVelocity()); + + const Vector vap(a.VelocityAt(na.Origin())); + const Vector vbp(b.VelocityAt(na.Origin())); + const Vector vab = vap - vbp; + + const Vector rap90((na.Origin() - a.Origin()).Rotate90()); + const Vector rbp90((na.Origin() - b.Origin()).Rotate90()); + + const Scalar ia(a.Mass()); + const Scalar ib(b.Mass()); + + const Scalar rap90dotN(rap90.Dot(na.Direction())); + const Scalar rbp90dotN(rbp90.Dot(na.Direction())); + + const Scalar j( + (((-(1 + e)) * vab).Dot(na.Direction())) + / (na.Direction().Dot(na.Direction() * ((1.0 / a.Mass()) + (1.0 / b.Mass()))) + + ((rap90dotN * rap90dotN) / ia) + + ((rbp90dotN * rbp90dotN) / ib) )); + + const Vector va2(va + ((j / a.Mass()) * na.Direction())); + const Vector vb2(vb - ((j / b.Mass()) * na.Direction())); + const Scalar wa2(wa + ((rap90.Dot(j * na.Direction())) / ia)); + const Scalar wb2(wb - ((rbp90.Dot(j * na.Direction())) / ib)); + + a.linearVelocity = va2; + a.angularVelocity = wa2; + b.linearVelocity = vb2; + b.angularVelocity = wb2; +} + +void Entity::InfInfCollisionResponse(Entity &a, const Ray &na, Entity &b) { + // If both elements are standing still or both are moving, move them away + // from each other. Otherwise, move the moving one. + if ((a.linearVelocity == Vector() && b.linearVelocity == Vector()) + || (a.linearVelocity != Vector() && b.linearVelocity != Vector())) { + a.Translate(na.Direction()); + b.Translate(-na.Direction()); + Ray n; + while (a.shape->CheckCollision(*b.shape, n)) { + a.Translate(n.Direction()); + b.Translate(-n.Direction()); + } + } else if (a.linearVelocity == Vector()) { + b.Translate(-na.Direction()); + Ray n; + while (b.shape->CheckCollision(*a.shape, n)) { + b.Translate(n.Direction()); + } + } else { + a.Translate(na.Direction()); + Ray n; + while (a.shape->CheckCollision(*b.shape, n)) { + a.Translate(n.Direction()); + } + } +} + +} diff --git a/src/game/Entity.h b/src/game/Entity.h new file mode 100644 index 0000000..22d46bd --- /dev/null +++ b/src/game/Entity.h @@ -0,0 +1,74 @@ +/* + * Entity.h + * + * Created on: Apr 25, 2012 + * Author: holy + */ + +#ifndef GAME_ENTITY_H_ +#define GAME_ENTITY_H_ + +#include "../shape/Shape.h" + +#include + +namespace app { class Timer; } + + +namespace game { + +class Entity { + + friend std::ostream &operator <<(std::ostream &, const Entity &); + + public: + typedef shape::Shape::Scalar Scalar; + typedef shape::Shape::Vector Vector; + typedef shape::Shape::Ray Ray; + + public: + static void CollisionResponse(Entity &a, const Entity::Ray &na, Entity &b); + + public: + explicit Entity(shape::Shape *s, Scalar mass = 1.0) : shape(s), mass(mass) { }; + virtual ~Entity(void) { }; + + public: + void Update(const app::Timer &); + bool CheckCollision(const Entity &, Ray &); + + public: + virtual void Collide(Entity &other, const Ray &) { }; + virtual void Render(SDL_Surface *dest) const { }; + + public: + const Vector &Origin(void) const { return translation; }; + const Vector &LinearVelocity(void) const { return linearVelocity; }; + Scalar Angle(void) const { return rotation; }; + Scalar AngularVelocity(void) const { return angularVelocity; }; + Vector VelocityAt(const Vector &p) const; + const Scalar Mass(void) const { return mass; }; + + public: + void Rotate(Scalar); + void Translate(const Vector &); + void Accelerate(const Vector &linear, Scalar angular = 0); + + private: + static void InfInfCollisionResponse(Entity &a, const Entity::Ray &na, Entity &b); + + private: + shape::Shape *shape; + Vector translation, linearVelocity; + Scalar rotation, angularVelocity, mass; + +}; + + +inline std::ostream &operator <<(std::ostream &out, const Entity &e) { + return out << *e.shape; +} + +} + +#endif /* GAME_ENTITY_H_ */ diff --git a/src/geometry/Ray2D.h b/src/geometry/Ray2D.h new file mode 100644 index 0000000..408a061 --- /dev/null +++ b/src/geometry/Ray2D.h @@ -0,0 +1,35 @@ +/* + * Ray2D.h + * + * Created on: Apr 25, 2012 + * Author: holy + */ + +#ifndef GEOMETRY_RAY2D_H_ +#define GEOMETRY_RAY2D_H_ + +#include "Vector2D.h" + +namespace geometry { + +template +class Ray2D { + + public: + explicit Ray2D(const Vector2D &directionUnit = Vector2D(), const Vector2D &origin = Vector2D()) + : direction(directionUnit), origin(origin) { }; + + public: + Vector2D &Direction(void) { return direction; }; + Vector2D &Origin(void) { return origin; }; + const Vector2D &Direction(void) const { return direction; }; + const Vector2D &Origin(void) const { return origin; }; + + private: + Vector2D direction, origin; + +}; + +} + +#endif /* GEOMETRY_RAY2D_H_ */ diff --git a/src/geometry/Vector2D.h b/src/geometry/Vector2D.h new file mode 100644 index 0000000..1134b38 --- /dev/null +++ b/src/geometry/Vector2D.h @@ -0,0 +1,177 @@ +/* + * Vector.h + * + * Created on: Apr 23, 2012 + * Author: holy + */ + +#ifndef GEOMETRY_VECTOR2D_H_ +#define GEOMETRY_VECTOR2D_H_ + +#include +#include + + +namespace geometry { + +template +class Vector2D { + + public: + Vector2D(void) : x(), y() { }; + Vector2D(Scalar x, Scalar y) : x(x), y(y) { }; + + public: + Scalar X(void) const { return x; }; + Scalar Y(void) const { return y; }; + + public: + Scalar Dot(const Vector2D &o) const { return (X() * o.X()) + (Y() * o.Y()); }; + Scalar LengthSquared(void) const { return Dot(*this); }; + Scalar Length(void) const { return std::sqrt(LengthSquared()); }; + + public: + Vector2D &Unify(void) { + if (LengthSquared() == Scalar()) return *this; + *this /= Length(); + return *this; + }; + Vector2D Unit(void) const { + if (LengthSquared() == Scalar()) return *this; + return *this / Length(); + }; + Vector2D &Reflect(const Vector2D &normal); + Vector2D &Rotate90(void) { + return *this = Vector2D(-Y(), X()); + }; + Vector2D &Rotate(Scalar by) { + Scalar sine(std::sin(by)), cosine(std::cos(by)); + return *this = Vector2D(X() * cosine - Y() * sine, X() * sine + y * cosine); + }; + + public: + Vector2D &operator +=(const Vector2D &o) { + x += o.X(); + y += o.Y(); + return *this; + }; + Vector2D &operator -=(const Vector2D &o) { + x -= o.X(); + y -= o.Y(); + return *this; + }; + template + Vector2D &operator +=(T s) { x += s; y += s; return *this; }; + template + Vector2D &operator -=(T s) { x -= s; y -= s; return *this; }; + template + Vector2D &operator *=(T s) { x *= s; y *= s; return *this; }; + template + Vector2D &operator /=(T s) { x /= s; y /= s; return *this; }; + + private: + Scalar x, y; + +}; + +template +inline Vector2D &Vector2D::Reflect(const Vector2D &normal) { + Scalar doubleDot(2 * Dot(normal)); + x -= doubleDot * normal.X(); + y -= doubleDot * normal.Y(); + return *this; +}; + + +template +inline bool operator ==(const Vector2D &lhs, const Vector2D &rhs) { + return lhs.X() == rhs.X() && lhs.Y() == rhs.Y(); +}; + +template +inline bool operator !=(const Vector2D &lhs, const Vector2D &rhs) { + return !(lhs == rhs); +}; + +template +inline Vector2D operator +(const Vector2D &v) { + return v; +}; +template +inline Vector2D operator -(const Vector2D &v) { + return Vector2D(-v.X(), -v.Y()); +}; + +template +inline Vector2D operator +(const Vector2D &lhs, const Vector2D &rhs) { + Vector2D temp(lhs); + temp += rhs; + return temp; +}; +template +inline Vector2D operator -(const Vector2D &lhs, const Vector2D &rhs) { + Vector2D temp(lhs); + temp -= rhs; + return temp; +}; + +template +inline Vector2D operator +(const Vector2D &v, SScalar s) { + Vector2D temp(v); + temp += s; + return temp; +}; +template +inline Vector2D operator -(const Vector2D &v, SScalar s) { + Vector2D temp(v); + temp -= s; + return temp; +}; + +template +inline Vector2D operator +(SScalar s, const Vector2D &v) { + Vector2D temp(v); + temp += s; + return temp; +}; +template +inline Vector2D operator -(SScalar s, const Vector2D &v) { + Vector2D temp(v); + temp -= s; + return temp; +}; + +template +inline Vector2D operator *(const Vector2D &v, SScalar s) { + Vector2D temp(v); + temp *= s; + return temp; +}; +template +inline Vector2D operator *(SScalar s, const Vector2D &v) { + Vector2D temp(v); + temp *= s; + return temp; +}; +template +inline Vector2D operator /(const Vector2D &v, SScalar s) { + Vector2D temp(v); + temp /= s; + return temp; +}; +template +inline Vector2D operator /(SScalar s, const Vector2D &v) { + Vector2D temp(v); + temp /= s; + return temp; +}; + + +template +std::ostream &operator <<(std::ostream &out, const Vector2D &v) { + return out << '<' << v.X() << '|' << v.Y() << '>'; +} + +} + +#endif /* GEOMETRY_VECTOR2D_H_ */ diff --git a/src/geometry/constants.h b/src/geometry/constants.h new file mode 100644 index 0000000..a33ea2a --- /dev/null +++ b/src/geometry/constants.h @@ -0,0 +1,21 @@ +/* + * constants.h + * + * Created on: Apr 26, 2012 + * Author: holy + */ + +#ifndef GEOMETRY_CONSTANTS_H_ +#define GEOMETRY_CONSTANTS_H_ + +#include + + +namespace geometry { + +const double PI(std::atan(1.0) * 4.0); + +} + + +#endif /* GEOMETRY_CONSTANTS_H_ */ diff --git a/src/pong/Ball.cpp b/src/pong/Ball.cpp new file mode 100644 index 0000000..97248f3 --- /dev/null +++ b/src/pong/Ball.cpp @@ -0,0 +1,35 @@ +/* + * Ball.cpp + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#include "Ball.h" + +#include "Paddle.h" +#include "../geometry/constants.h" + +#include +#include + +using game::Entity; +using geometry::PI; + + +namespace pong { + +Ball::Ball(Scalar r) +: Entity(&shape, 4 * PI * r * r * r / 3) +, shape(r) { + +} + + +void Ball::Render(SDL_Surface *screen) const { + circleRGBA(screen, shape.Center().X(), shape.Center().Y(), shape.Radius(), 0xFF, 0xFF, 0xFF, 0xFF); + Vector angle(Vector(0, 1).Rotate(Angle()) * shape.Radius() + Origin()); + lineRGBA(screen, shape.Center().X(), shape.Center().Y(), angle.X(), angle.Y(), 0xFF, 0xFF, 0xFF, 0xFF); +} + +} diff --git a/src/pong/Ball.h b/src/pong/Ball.h new file mode 100644 index 0000000..2e54a8c --- /dev/null +++ b/src/pong/Ball.h @@ -0,0 +1,34 @@ +/* + * Ball.h + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#ifndef PONG_BALL_H_ +#define PONG_BALL_H_ + +#include "../game/Entity.h" +#include "../shape/Circle.h" + + +namespace pong { + +class Ball +: public game::Entity { + + public: + explicit Ball(Scalar radius); + virtual ~Ball(void) { }; + + public: + virtual void Render(SDL_Surface *dest) const; + + private: + shape::Circle shape; + +}; + +} + +#endif /* PONG_BALL_H_ */ diff --git a/src/pong/CountingWall.cpp b/src/pong/CountingWall.cpp new file mode 100644 index 0000000..4b044a7 --- /dev/null +++ b/src/pong/CountingWall.cpp @@ -0,0 +1,37 @@ +/* + * CountingWall.cpp + * + * Created on: Apr 17, 2012 + * Author: holy + */ + +#include "CountingWall.h" + +#include + +using game::Entity; + + +namespace pong { + +CountingWall::CountingWall(Scalar width, Scalar height) +: Entity(&shape, std::numeric_limits::infinity()) +, shape(width, height) +, count(0) { + +} + +CountingWall::~CountingWall(void) { + +} + + +void CountingWall::Collide(Entity &, const Ray &) { + ++count; +} + +void CountingWall::Render(SDL_Surface *dest) const { + +} + +} diff --git a/src/pong/CountingWall.h b/src/pong/CountingWall.h new file mode 100644 index 0000000..c14820d --- /dev/null +++ b/src/pong/CountingWall.h @@ -0,0 +1,40 @@ +/* + * CountingWall.h + * + * Created on: Apr 17, 2012 + * Author: holy + */ + +#ifndef PONG_COUNTINGWALL_H_ +#define PONG_COUNTINGWALL_H_ + +#include "../game/Entity.h" +#include "../shape/AABB.h" + +#include + +namespace pong { + +class CountingWall +: public game::Entity { + + public: + CountingWall(Scalar width, Scalar height); + virtual ~CountingWall(void); + + public: + int HitCount(void) { return count; }; + + public: + virtual void Collide(Entity &other, const Ray &); + virtual void Render(SDL_Surface *dest) const; + + private: + shape::AABB shape; + int count; + +}; + +} + +#endif /* PONG_COUNTINGWALL_H_ */ diff --git a/src/pong/Match.cpp b/src/pong/Match.cpp new file mode 100644 index 0000000..5754b36 --- /dev/null +++ b/src/pong/Match.cpp @@ -0,0 +1,213 @@ +/* + * Match.cpp + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#include "Match.h" + +#include "../app/Control.h" + +#include +#include +#include +#include + +using app::Control; +using app::Timer; +using game::Collision; +using game::Entity; +using std::runtime_error; +using std::stringstream; +using std::vector; + + +namespace pong { + +Match::Match(void) +: ctrl(0) +, scoreFont(TTF_OpenFont("data/font/Magra-Regular.ttf", 30)) +, leftScoreText(0) +, rightScoreText(0) +, paddleSpeed(150) +, worldWidth(800) +, worldHeight(480) +, ball(10) +, secondBall(7) +, thirdBall(5) +, leftPaddle(10, 100) +, rightPaddle(10, 100) +, topWall(800, 10) +, bottomWall(800, 10) +, leftWall(10, 480) +, rightWall(10, 480) +, entities() +, collisions() +, updateScore(true) { + + if (!scoreFont) { + throw runtime_error("failed to load score font"); + } + + ball.Translate(Entity::Vector(400, 240)); + ball.Accelerate(Entity::Vector(180, 180)); +// ball.SetMaxVelocity(500.0f); + + secondBall.Translate(Entity::Vector(300, 240)); + secondBall.Accelerate(Entity::Vector(-50, -50), 1); +// secondBall.SetMaxVelocity(600.0f); + + thirdBall.Translate(Entity::Vector(200, 440)); + thirdBall.Accelerate(Entity::Vector(60, 40)); + + leftPaddle.Translate(Entity::Vector(5, 200)); + rightPaddle.Translate(Entity::Vector(795, 280)); + + leftPaddle.SetMovementSpeed(Entity::Vector(0, paddleSpeed)); + rightPaddle.SetMovementSpeed(Entity::Vector(0, paddleSpeed)); + + topWall.Translate(Entity::Vector(400, -5)); + rightWall.Translate(Entity::Vector(805, 240)); + bottomWall.Translate(Entity::Vector(400, 485)); + leftWall.Translate(Entity::Vector(-5, 240)); + + entities.reserve(9); + entities.push_back(&ball); + entities.push_back(&secondBall); + entities.push_back(&thirdBall); + entities.push_back(&leftPaddle); + entities.push_back(&rightPaddle); + entities.push_back(&topWall); + entities.push_back(&bottomWall); + entities.push_back(&leftWall); + entities.push_back(&rightWall); + + collisions.reserve(2 * entities.size()); +} + +Match::~Match(void) { + +} + + +void Match::EnterState(Control *c, SDL_Surface *screen) { + ctrl = c; +} + +void Match::ExitState(void) { + if (scoreFont) { + TTF_CloseFont(scoreFont); + scoreFont = 0; + } +} + +void Match::HandleEvent(const SDL_Event &e) { + if (e.type == SDL_KEYDOWN) { + if (e.key.keysym.sym == SDLK_w) { + leftPaddle.StartMovingUp(); + } else if (e.key.keysym.sym == SDLK_s) { + leftPaddle.StartMovingDown(); + } else if (e.key.keysym.sym == SDLK_UP) { + rightPaddle.StartMovingUp(); + } else if (e.key.keysym.sym == SDLK_DOWN) { + rightPaddle.StartMovingDown(); + } + } else if (e.type == SDL_KEYUP) { + if (e.key.keysym.sym == SDLK_w) { + leftPaddle.StopMovingUp(); + } else if (e.key.keysym.sym == SDLK_s) { + leftPaddle.StopMovingDown(); + } else if (e.key.keysym.sym == SDLK_UP) { + rightPaddle.StopMovingUp(); + } else if (e.key.keysym.sym == SDLK_DOWN) { + rightPaddle.StopMovingDown(); + } else if (e.key.keysym.sym == SDLK_q) { + if (ctrl) ctrl->Quit(); + } + } +} + +void Match::UpdateWorld(const Timer &timer) { + UpdateEntities(timer); + CheckCollisions(timer); + HandleCollisions(timer); +} + +void Match::UpdateEntities(const Timer &timer) { + for (vector::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) { + (*i)->Update(timer); + } +} + +void Match::CheckCollisions(const Timer &timer) { + Entity::Ray normal; + for (vector::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) { + for (vector::const_iterator j(i + 1); j != end; ++j) { + if ((*i)->CheckCollision(**j, normal)) { + collisions.push_back(Collision(*i, *j, normal)); + } + } + } +} + +void Match::HandleCollisions(const Timer &timer) { + for (vector::const_iterator i(collisions.begin()), end(collisions.end()); i != end; ++i) { + Entity::CollisionResponse(*(i->left), i->normal, *(i->right)); + } + // TODO: resolve collisions of static objects + for (vector::const_iterator i(collisions.begin()), end(collisions.end()); i != end; ++i) { + i->left->Collide(*i->right, i->normal); + i->right->Collide(*i->left, i->normal); + } + if (!collisions.empty()) { + updateScore = true; + } + collisions.clear(); +} + + +void Match::Render(SDL_Surface *screen) { + SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0)); + for (vector::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) { + (*i)->Render(screen); + } + RenderHUD(screen); +} + +void Match::RenderHUD(SDL_Surface *screen) { + if (updateScore) { + UpdateScore(screen); + updateScore = false; + } + RenderScore(screen); +} + +void Match::RenderScore(SDL_Surface *screen) { + SDL_Rect dest = { 2, 2, 0, 0 }; + SDL_BlitSurface(leftScoreText, 0, screen, &dest); + + dest.x = screen->w - rightScoreText->w - 2; + SDL_BlitSurface(rightScoreText, 0, screen, &dest); +} + +void Match::UpdateScore(SDL_Surface *screen) { + if (!scoreFont) return; + if (leftScoreText) SDL_FreeSurface(leftScoreText); + if (rightScoreText) SDL_FreeSurface(rightScoreText); + + SDL_Color color; + color.r = 0xFF; + color.g = 0xFF; + color.b = 0xFF; + + stringstream s; + s << rightWall.HitCount(); + leftScoreText = TTF_RenderUTF8_Blended(scoreFont, s.str().c_str(), color); + + s.str(""); + s << leftWall.HitCount(); + rightScoreText = TTF_RenderUTF8_Blended(scoreFont, s.str().c_str(), color); +} + +} diff --git a/src/pong/Match.h b/src/pong/Match.h new file mode 100644 index 0000000..a838ebe --- /dev/null +++ b/src/pong/Match.h @@ -0,0 +1,66 @@ +/* + * Match.h + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#ifndef PONG_MATCH_H_ +#define PONG_MATCH_H_ + +#include "Ball.h" +#include "CountingWall.h" +#include "Paddle.h" +#include "../app/State.h" +#include "../game/Collision.h" +#include "../game/Entity.h" + +#include +#include +#include + + +namespace pong { + +class Match +: public app::State { + + public: + Match(void); + virtual ~Match(void); + + public: + virtual void EnterState(app::Control *ctrl, SDL_Surface *screen); + virtual void ExitState(void); + + virtual void HandleEvent(const SDL_Event &); + virtual void UpdateWorld(const app::Timer &); + virtual void Render(SDL_Surface *); + + private: + void UpdateEntities(const app::Timer &); + void CheckCollisions(const app::Timer &); + void CheckWorldCollisions(const app::Timer &); + void HandleCollisions(const app::Timer &); + void UpdateScore(SDL_Surface *); + void RenderHUD(SDL_Surface *); + void RenderScore(SDL_Surface *); + + private: + app::Control *ctrl; + TTF_Font *scoreFont; + SDL_Surface *leftScoreText, *rightScoreText; + Sint32 paddleSpeed; + Uint32 worldWidth, worldHeight; + Ball ball, secondBall, thirdBall; + Paddle leftPaddle, rightPaddle; + CountingWall topWall, bottomWall, leftWall, rightWall; + std::vector entities; + std::vector collisions; + bool updateScore; + +}; + +} + +#endif /* PONG_MATCH_H_ */ diff --git a/src/pong/Paddle.cpp b/src/pong/Paddle.cpp new file mode 100644 index 0000000..ef922cc --- /dev/null +++ b/src/pong/Paddle.cpp @@ -0,0 +1,64 @@ +/* + * Paddle.cpp + * + * Created on: Apr 10, 2012 + * Author: holy + */ + +#include "Paddle.h" + +#include "Ball.h" + +#include + + +namespace pong { + +Paddle::Paddle(Scalar width, Scalar height) +: Entity(&shape, std::numeric_limits::infinity()) +, shape(width, height) { + +} + + +void Paddle::Collide(Entity &other, const Ray &) { + if (dynamic_cast(&other)) { + Vector distance(other.Origin() - Origin()); + other.Accelerate(distance.Unit() * 5); + } +} + +void Paddle::Render(SDL_Surface *screen) const { + SDL_Rect destRect; + destRect.x = shape.Left(); + destRect.y = shape.Top(); + destRect.w = shape.Width(); + destRect.h = shape.Height(); + SDL_FillRect(screen, &destRect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF)); +} + + +void Paddle::SetMovementSpeed(Vector s) { +// Vector d(s - movementSpeed); + movementSpeed = s; +// Accelerate(d); +} + + +void Paddle::StartMovingUp(void) { + Accelerate(-movementSpeed); +} + +void Paddle::StopMovingUp(void) { + Accelerate(movementSpeed); +} + +void Paddle::StartMovingDown(void) { + Accelerate(movementSpeed); +} + +void Paddle::StopMovingDown(void) { + Accelerate(-movementSpeed); +} + +} diff --git a/src/pong/Paddle.h b/src/pong/Paddle.h new file mode 100644 index 0000000..85da2af --- /dev/null +++ b/src/pong/Paddle.h @@ -0,0 +1,44 @@ +/* + * Paddle.h + * + * Created on: Apr 10, 2012 + * Author: holy + */ + +#ifndef PONG_PADDLE_H_ +#define PONG_PADDLE_H_ + +#include "../game/Entity.h" +#include "../shape/AABB.h" + + +namespace pong { + +class Paddle +: public game::Entity { + + public: + Paddle(Scalar width, Scalar height); + virtual ~Paddle(void) { }; + + public: + virtual void Collide(Entity &other, const Ray &); + virtual void Render(SDL_Surface *dest) const; + + public: + void SetMovementSpeed(Vector); + + void StartMovingUp(void); + void StopMovingUp(void); + void StartMovingDown(void); + void StopMovingDown(void); + + private: + shape::AABB shape; + Vector movementSpeed; + +}; + +} + +#endif /* PONG_PADDLE_H_ */ diff --git a/src/sdl-test8.cpp b/src/sdl-test8.cpp new file mode 100644 index 0000000..ad1e891 --- /dev/null +++ b/src/sdl-test8.cpp @@ -0,0 +1,26 @@ +//============================================================================ +// Name : sdl-test8.cpp +// Author : HolySmoke +// Version : .3 +// Copyright : MINE, ALL MINE! +// Description : Some pong crap supposed to have somewhat realistic physics. +//============================================================================ + +#include "app/Application.h" +#include "pong/Match.h" +#include "sdl/InitScreen.h" +#include "sdl/InitSDL.h" +#include "sdl/InitTTF.h" + +int main(int argc, char *argv[]) { + const int width(800); + const int height(480); + + sdl::InitSDL initSDL; + sdl::InitTTF initTTF; + sdl::InitScreen initScreen(width, height); + + app::Application a(&initScreen, new pong::Match); + a.Run(); + return 0; +} diff --git a/src/sdl/InitSDL.cpp b/src/sdl/InitSDL.cpp new file mode 100644 index 0000000..0f2eacd --- /dev/null +++ b/src/sdl/InitSDL.cpp @@ -0,0 +1,27 @@ +/* + * InitSDL.cpp + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#include "InitSDL.h" + +#include + +using std::runtime_error; + + +namespace sdl { + +InitSDL::InitSDL(Uint32 flags) { + if (SDL_Init(flags) != 0) { + throw runtime_error("failed to initialize SDL"); + } +} + +InitSDL::~InitSDL(void) { + SDL_Quit(); +} + +} diff --git a/src/sdl/InitSDL.h b/src/sdl/InitSDL.h new file mode 100644 index 0000000..016c0b4 --- /dev/null +++ b/src/sdl/InitSDL.h @@ -0,0 +1,29 @@ +/* + * InitSDL.h + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#ifndef SDL_INITSDL_H_ +#define SDL_INITSDL_H_ + +#include + + +namespace sdl { + +class InitSDL { + + public: + explicit InitSDL(Uint32 flags = SDL_INIT_EVERYTHING); + virtual ~InitSDL(void); + private: + InitSDL(const InitSDL &); + InitSDL &operator =(const InitSDL &); + +}; + +} + +#endif /* SDL_INITSDL_H_ */ diff --git a/src/sdl/InitScreen.cpp b/src/sdl/InitScreen.cpp new file mode 100644 index 0000000..c9b275f --- /dev/null +++ b/src/sdl/InitScreen.cpp @@ -0,0 +1,28 @@ +/* + * InitScreen.cpp + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#include "InitScreen.h" + +#include + +using std::runtime_error; + + +namespace sdl { + +InitScreen::InitScreen(int width, int height, int bpp, Sint32 flags) +: screen(SDL_SetVideoMode(width, height, bpp, flags)) { + if (!screen) { + throw runtime_error("failed to open screen"); + } +} + +InitScreen::~InitScreen(void) { + +} + +} diff --git a/src/sdl/InitScreen.h b/src/sdl/InitScreen.h new file mode 100644 index 0000000..ba731da --- /dev/null +++ b/src/sdl/InitScreen.h @@ -0,0 +1,37 @@ +/* + * InitScreen.h + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#ifndef SDL_INITSCREEN_H_ +#define SDL_INITSCREEN_H_ + +#include + +namespace sdl { + +class InitScreen { + + public: + InitScreen(int width, int height, int bpp = 32, Sint32 flags = SDL_HWSURFACE | SDL_DOUBLEBUF); + virtual ~InitScreen(void); + private: + InitScreen(const InitScreen &); + InitScreen &operator =(const InitScreen &); + + public: + SDL_Surface *Screen(void) { return screen; }; + const SDL_Surface *Screen(void) const { return screen; }; + + void Flip(void) { SDL_Flip(screen); }; + + private: + SDL_Surface *screen; + +}; + +} + +#endif /* SDL_INITSCREEN_H_ */ diff --git a/src/sdl/InitTTF.cpp b/src/sdl/InitTTF.cpp new file mode 100644 index 0000000..5818a73 --- /dev/null +++ b/src/sdl/InitTTF.cpp @@ -0,0 +1,28 @@ +/* + * InitTTF.cpp + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#include "InitTTF.h" + +#include +#include + +using std::runtime_error; + + +namespace sdl { + +InitTTF::InitTTF(void) { + if (TTF_Init() != 0) { + throw runtime_error("failed to initialize SDL TTF"); + } +} + +InitTTF::~InitTTF(void) { + TTF_Quit(); +} + +} diff --git a/src/sdl/InitTTF.h b/src/sdl/InitTTF.h new file mode 100644 index 0000000..6f0306c --- /dev/null +++ b/src/sdl/InitTTF.h @@ -0,0 +1,26 @@ +/* + * InitTTF.h + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#ifndef SDL_INITTTF_H_ +#define SDL_INITTTF_H_ + +namespace sdl { + +class InitTTF { + + public: + InitTTF(void); + virtual ~InitTTF(void); + private: + InitTTF(const InitTTF &); + InitTTF &operator =(const InitTTF &); + +}; + +} + +#endif /* SDL_INITTTF_H_ */ diff --git a/src/shape/AABB.cpp b/src/shape/AABB.cpp new file mode 100644 index 0000000..75007ec --- /dev/null +++ b/src/shape/AABB.cpp @@ -0,0 +1,73 @@ +/* + * AABB.cpp + * + * Created on: Apr 30, 2012 + * Author: holy + */ + +#include "AABB.h" + +#include "Circle.h" + +namespace shape { + +void AABB::Translate(const Vector &delta) { + leftTop += delta; + rightBottom += delta; +} + +void AABB::Rotate(Scalar delta) { + +} + + +bool AABB::CheckCollision(const Shape &other, Ray &na) const { + if (other.CheckCollision(*this, na)) { + na.Direction() *= -1; + return true; + } else { + return false; + } +} + +bool AABB::CheckCollision(const AABB &other, Ray &na) const { + if (Bottom() <= other.Top()) return false; + if (other.Bottom() <= Top()) return false; + if (Right() <= other.Left()) return false; + if (other.Right() <= Left()) return false; + + if (Bottom() <= other.Top() || other.Bottom() <= Top()) { + if (Left() < other.Left()) { + na.Origin() = Vector(((Top() + Bottom()) / 2 + (other.Top() + other.Bottom()) / 2) / 2, Right()); + na.Direction() = Vector(-1, 0); + } else { + na.Origin() = Vector(((Top() + Bottom()) / 2 + (other.Top() + other.Bottom()) / 2) / 2, Left()); + na.Direction() = Vector(1, 0); + } + } else { + if (Top() < other.Top()) { + na.Origin() = Vector(Bottom(), ((Left() + Right()) / 2 + (other.Left() + other.Right()) / 2) / 2); + na.Direction() = Vector(0, -1); + } else { + na.Origin() = Vector(Top(), ((Left() + Right()) / 2 + (other.Left() + other.Right()) / 2) / 2); + na.Direction() = Vector(0, 1); + } + } + return true; +} + +bool AABB::CheckCollision(const Circle &other, Ray &na) const { + if (other.CheckCollision(*this, na)) { + na.Direction() *= -1; + return true; + } else { + return false; + } +} + + +std::ostream &AABB::Write(std::ostream &out) const { + return out << "AABB(" << Width() << 'x' << Height() << ", " << Center() << ')'; +} + +} diff --git a/src/shape/AABB.h b/src/shape/AABB.h new file mode 100644 index 0000000..956114a --- /dev/null +++ b/src/shape/AABB.h @@ -0,0 +1,52 @@ +/* + * AABB.h + * + * Created on: Apr 30, 2012 + * Author: holy + */ + +#ifndef SHAPE_AABB_H_ +#define SHAPE_AABB_H_ + +#include "Shape.h" + +namespace shape { + +class AABB +: public Shape { + + public: + AABB(void) { }; + AABB(Scalar width, Scalar height) : leftTop(-width/2, -height/2), rightBottom(width/2, height/2) { }; + virtual ~AABB(void) { }; + + public: + Scalar Left(void) const { return leftTop.X(); }; + Scalar Top(void) const { return leftTop.Y(); }; + Scalar Right(void) const { return rightBottom.X(); }; + Scalar Bottom(void) const { return rightBottom.Y(); }; + + Vector Center(void) const { return leftTop + (rightBottom - leftTop) / 2; }; + Scalar Width(void) const { return Right() - Left(); }; + Scalar Height(void) const { return Bottom() - Top(); }; + + public: + virtual void Translate(const Vector &delta); + virtual void Rotate(Scalar delta); + + public: + virtual bool CheckCollision(const Shape &, Ray &) const; + virtual bool CheckCollision(const AABB &, Ray &) const; + virtual bool CheckCollision(const Circle &, Ray &) const; + + public: + virtual std::ostream &Write(std::ostream &) const; + + private: + Vector leftTop, rightBottom; + +}; + +} + +#endif /* SHAPE_AABB_H_ */ diff --git a/src/shape/Circle.cpp b/src/shape/Circle.cpp new file mode 100644 index 0000000..3549db9 --- /dev/null +++ b/src/shape/Circle.cpp @@ -0,0 +1,110 @@ +/* + * Circle.cpp + * + * Created on: Apr 29, 2012 + * Author: holy + */ + +#include "Circle.h" + +#include "AABB.h" + +namespace shape { + +void Circle::Translate(const Vector &delta) { + center += delta; +} + +void Circle::Rotate(Scalar delta) { + +} + + +bool Circle::CheckCollision(const Shape &other, Ray &na) const { + if (other.CheckCollision(*this, na)) { + na.Direction() *= -1; + return true; + } else { + return false; + } +} + +bool Circle::CheckCollision(const AABB &other, Ray &na) const { + int xZone( + center.X() < other.Left() ? 0 : ( + other.Right() < center.X() ? 2 : 1)); + int yZone( + center.Y() < other.Top() ? 0 : ( + other.Bottom() < center.Y() ? 2 : 1)); + int zone(xZone + 3 * yZone); + + if (zone == 4) { + na.Origin() = center; + na.Direction() = (center - other.Center()).Unit(); + return true; + } + + if (zone % 2) { + if (xZone == 1) { // vertical + if (Bottom() < other.Top()) return false; + if (other.Bottom() < Top()) return false; + + if (Bottom() < other.Bottom()) { + na.Origin() = Vector(center.X(), Bottom()); + na.Direction() = Vector(0, -1); + } else { + na.Origin() = Vector(center.X(), Top()); + na.Direction() = Vector(0, 1); + } + + return true; + } else { + if (Right() < other.Left()) return false; + if (other.Right() < Left()) return false; + + if (Left() < other.Left()) { + na.Origin() = Vector(Left(), center.Y()); + na.Direction() = Vector(-1, 0); + } else { + na.Origin() = Vector(Right(), center.Y()); + na.Direction() = Vector(1, 0); + } + + return true; + } + } else { + Vector near( + yZone ? other.Right() : other.Left(), + xZone ? other.Bottom() : other.Top()); + Vector distance(Center() - near); + Scalar distanceSquared(distance.LengthSquared()); + if (distanceSquared < (Radius() * Radius())) { + na.Origin() = near; + na.Direction() = distance.Unit(); + return true; + } else { + return false; + } + } +} + +bool Circle::CheckCollision(const Circle &other, Ray &na) const { + const Vector distance(center - other.center); + const Scalar distanceSquared(distance.LengthSquared()); + const Scalar radii(radius + other.radius); + + if (distanceSquared < (radii * radii)) { + na.Direction() = distance.Unit(); + na.Origin() = center + (na.Direction() * radius); + return true; + } else { + return false; + } +} + + +std::ostream &Circle::Write(std::ostream &out) const { + return out << "Circle(" << Radius() << ", " << Center() << ')'; +} + +} diff --git a/src/shape/Circle.h b/src/shape/Circle.h new file mode 100644 index 0000000..ff0363d --- /dev/null +++ b/src/shape/Circle.h @@ -0,0 +1,52 @@ +/* + * Circle.h + * + * Created on: Apr 29, 2012 + * Author: holy + */ + +#ifndef SHAPE_CIRCLE_H_ +#define SHAPE_CIRCLE_H_ + +#include "Shape.h" + +namespace shape { + +class Circle +: public Shape { + + public: + Circle(void) { }; + explicit Circle(Scalar r, Vector pos = Vector()) : center(pos), radius(r) { }; + virtual ~Circle(void) { }; + + public: + const Vector &Center(void) const { return center; }; + Scalar Radius(void) const { return radius; }; + + Scalar Left(void) const { return center.X() - radius; }; + Scalar Top(void) const { return center.Y() - radius; }; + Scalar Right(void) const { return center.X() + radius; }; + Scalar Bottom(void) const { return center.Y() + radius; }; + + public: + virtual void Translate(const Vector &delta); + virtual void Rotate(Scalar delta); + + public: + virtual bool CheckCollision(const Shape &, Ray &) const; + virtual bool CheckCollision(const AABB &, Ray &) const; + virtual bool CheckCollision(const Circle &, Ray &) const; + + public: + virtual std::ostream &Write(std::ostream &) const; + + private: + Vector center; + Scalar radius; + +}; + +} + +#endif /* SHAPE_CIRCLE_H_ */ diff --git a/src/shape/Shape.h b/src/shape/Shape.h new file mode 100644 index 0000000..69eedc2 --- /dev/null +++ b/src/shape/Shape.h @@ -0,0 +1,53 @@ +/* + * Shape.h + * + * Created on: Apr 29, 2012 + * Author: holy + */ + +#ifndef SHAPE_SHAPE_H_ +#define SHAPE_SHAPE_H_ + +#include "../geometry/Ray2D.h" +#include "../geometry/Vector2D.h" + +#include + + +namespace shape { + +class AABB; +class Circle; + +class Shape { + + public: + typedef float Scalar; + typedef geometry::Vector2D Vector; + typedef geometry::Ray2D Ray; + + public: + virtual ~Shape(void) { }; + + public: + virtual void Translate(const Vector &delta) = 0; + virtual void Rotate(Scalar delta) = 0; + + public: + virtual bool CheckCollision(const Shape &, Ray &) const = 0; + virtual bool CheckCollision(const AABB &, Ray &) const = 0; + virtual bool CheckCollision(const Circle &, Ray &) const = 0; + + public: + virtual std::ostream &Write(std::ostream &) const = 0; + +}; + + +inline std::ostream &operator <<(std::ostream &out, const Shape &s) { + return s.Write(out); +}; + +} + +#endif /* SHAPE_SHAPE_H_ */ -- 2.39.2