Doom style 3d reduced to 2 directions

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
jinxtengu
Posts: 79
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Doom style 3d reduced to 2 directions

Post by jinxtengu » Tue Jan 22, 2019 6:35 am

Hi, Iv'e been using this 8 direction monks code in some of my games http://www.revengeofthesunfish.com/Monks.zgeproj.
Anyway, I'm wondering how this code can be modified to do two things, firstly so that instead of having 8 directions, it would only use only 2, left and right, that is as viewed from a first person perspective. This is the main thing i'd like to work out. With the monks example, the image file used should be 128x128 rather than 512x128, in the altered version of the code.

The second thing that would be useful is to have variations on the size of the frames, for both the 2 direction and the 8 direction variants. for instance the frames are currently set at 64x128, it would be nice to be able to use frames set at 64x64 or possibly larger or smaller.
I'd really appreciate if anyone could assist me with this. I’ve tried tinkering with the code myself, however the solution eludes me thus far.

User avatar
Ats
Posts: 255
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Doom style 3d reduced to 2 directions

Post by Ats » Tue Jan 22, 2019 12:06 pm

Hi Jinxtengu. I'm not sure what you mean by 2 directions.
If you want to turn 90° with left/right like in Dungeon Master, here's the modified code:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Monks" FrameRateStyle="1" ScreenMode="0" CameraPosition="-3 1.6 -2" CameraRotation="0 -1.5 0" ViewportRatio="3" FileVersion="2">
  <OnLoaded>
    <Group Comment="External">
      <Children>
        <ZExternalLibrary ModuleName="opengl32">
          <Source>
<![CDATA[//

void glEnable(int C){}
void glAlphaFunc(int F, float C){}]]>
          </Source>
        </ZExternalLibrary>
        <ZExpression>
          <Expression>
<![CDATA[//

glEnable(0xBC0); // Enable Alpha Test
glAlphaFunc(0x204,0); // Greater then 0

App.CameraPosition.X = 0;
App.CameraPosition.Y = 1.6;
App.CameraPosition.Z = 0;
App.CameraRotation = 0;]]>
          </Expression>
        </ZExpression>
      </Children>
    </Group>
    <Group Comment="Library">
      <Children>
        <ZLibrary Comment="Standard">
          <Source>
<![CDATA[//

float radius(float X, float Y)
{
  return sqrt(X*X+Y*Y);
}]]>
          </Source>
        </ZLibrary>
      </Children>
    </Group>
    <Group Comment="Monks">
      <Children>
        <Repeat Count="32">
          <OnIteration>
            <SpawnModel Model="Monk"/>
          </OnIteration>
        </Repeat>
      </Children>
    </Group>
  </OnLoaded>
  <OnUpdate>
    <Group Comment="Input">
      <Children>
        <ZExpression Comment="Reset">
          <Expression>
<![CDATA[//

Axis[0] = 0;
Axis[1] = 0;]]>
          </Expression>
        </ZExpression>
        <KeyPress Comment="Right" Keys="&gt;" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[0] += 1;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="Left" Keys="&lt;" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[0] -= 1;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="Up" Keys="^" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[1] += 1;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="Down" Keys="_" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[1] -= 1;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
      </Children>
    </Group>
    <Group Comment="Camera">
      <Children>
        <ZExpression>
          <Expression>
<![CDATA[//

App.CameraRotation.Y += Axis[0]*0.25;

//

if(Axis[1])
{
  float R = App.CameraRotation.Y*PI*2;
  float S = Axis[1]; // * the distance you want to walk

  App.CameraPosition.X += S*sin(R);
  App.CameraPosition.Z -= S*cos(R);
}]]>
          </Expression>
        </ZExpression>
      </Children>
    </Group>
  </OnUpdate>
  <OnRender>
    <Group Comment="Debug">
      <Children>
        <UseMaterial Material="FloorMaterial"/>
        <RenderTransform Scale="32 32 1" Rotate="-0.25 0 0"/>
        <RenderSprite/>
      </Children>
    </Group>
  </OnRender>
  <Content>
    <Group Comment="Input">
      <Children>
        <Array Name="Axis" SizeDim1="2"/>
      </Children>
    </Group>
    <Group Comment="Monk">
      <Children>
        <Model Name="Monk">
          <Definitions>
            <Material Name="MonkMaterial" Shading="1" Light="0" Blend="1">
              <Textures>
                <MaterialTexture Name="MonkTexture" Texture="MonkBitmap" TextureScale="0.125 1 1" TextureX="-0.0625" TextureWrapMode="1" TexCoords="1"/>
              </Textures>
            </Material>
          </Definitions>
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[//

CurrentModel.Position.X = random(0,16);
CurrentModel.Position.Z = random(0,16);

CurrentModel.Rotation.Y = floor(rnd()*4)/4;

//

MonkMaterial.Color = 1-radius(CurrentModel.Position.X,
                              CurrentModel.Position.Z)/16;

MonkMaterial.Color.A = 1;]]>
              </Expression>
            </ZExpression>
          </OnSpawn>
          <OnUpdate>
            <ZExpression>
              <Expression>
<![CDATA[// Number of frames

float F = 8;

//

MonkTransform.Rotate.Y = App.CameraRotation.Y*-1-CurrentModel.Rotation.Y;

//

float A = atan2(CurrentModel.Position.X-App.CameraPosition.X,
                CurrentModel.Position.Z-App.CameraPosition.Z)+
                CurrentModel.Rotation.Y*PI*2;

MonkTexture.TextureX = floor(A/PI/2*F+0.5)/F+0.5/F;]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="MonkMaterial"/>
            <RenderTransform Name="MonkTransform" Rotate="0 3.3088 0"/>
            <RenderMesh Mesh="MonkMesh"/>
          </OnRender>
        </Model>
        <Mesh Name="MonkMesh">
          <Producers>
            <MeshBox Scale="0.5 1 1" Grid2DOnly="255"/>
            <MeshTransform Scale="1.5 1.5 1" Position="0 1.075 0"/>
          </Producers>
        </Mesh>
        <Bitmap Name="MonkBitmap" Width="512" Height="128" Filter="1">
          <Producers>
            <BitmapFromFile Transparency="2" HasAlphaLayer="1" DataWidth="512" DataHeight="128">
              <BitmapFile>
<![CDATA[78DAED9D3F886DC795EE6FD881820E14747083EEEC3438D0850EFAC2243E30C13438E80B134CC3044291118E848341BCC4980906E148387828322879A0C4A0170C281AD0CB9C18349993173874E8B0DF59D5FBABFED5776A9F7B6D66DEADB55D0B36FDE7764B5DB5ABD6B7D6B7FEBD783165CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C99F2FF5FCE3E78F118CFF50767E5D95F9C97475FBFBAB8789CBB3465CA76E4E270AF79E7E389EF5D7F785E3EBEBEBC7ACCBEB653CFC5A2D7F4680FDEFCE822B5DEBB58FEF6F26E0FEFF2CD47AFCAE33A7D0B6738CE68AC91EFF4E2BFE9BDF5CE50FC7F32DF13CA17FFF4FAF1EB9FDE3DFEEED79F3D7EF7EB2F1FBFFDD5178F7FFACDD78FF1FDB2CFC9CE4CBC1B9D07D934AEEBF41ECFCF9EEFCB45B275C6BBD13AB9267ECE75FBDA2712AECBFEE5453D13D931F194CD5F30E2807B71475CC7D5BB01BC1C1E03CF9ED7166B22C6F37E848EFBF3FFFDFEF18FFFF1D5E31F7EFB457942E7E989DFCDF43EE363ACF1B39FDC3D7EFE8F6FCA1A429F7FFFAF9F3CFEEEF0F9573F7FD2ED5B38C7B186783F9FFEDDD5E3973FFDF4F1939B8BC7CF7E7CFD78B7BBFE6FD36BF1DF8DFF6FECADFEBFF1F9566CA9AF3EDE3F3E7C74F1F8A7DFFFEEF10FFFFEDDE30FBFFFA13CDFFEEF6FD3E1BFF45ABC23DE693DB1BEB06D745E8893B41D46B707E26FD57DFFE54F0E76FE01B3DCCFF9FC1FAECB5ABFFD9787C7EF7EF149F95C3640F633BBE6DFFD57F86FFC6FD1E6CFB23705F30EF68B6C1861B9703DCE7E9C8DEFFFE3FBFA7CF3F337C50F6870F2706E7EB7F802F18CBE07C2FB4F7FBC2F7A3A702F9EB81F7EB73FB9BD2AEB8D35FEF0DB6FAB5E8F7566B4E7624DB1D6D06F45871FD6F4C7FFF37D79D7B136D9785BC0ACC0ABB067E2FDC5B90DEC8A75EA9C5F9C1F74C0E5457DCA9D583E777F50DF8B8FF17BBE470FBBC3B9F8E77DC1C8780A861CECC551EC3ED77F6B9C85F625F6281EAD3D9EEBE56CC41E16BFF2FC791F33DA8C718FE3F9E617BF2CEF2CEC986FFED737E55EC4B9213F70BDDC9B621FFCFE9BF2AEC3A6CCA0EFA5BBE2A3F3BAC53658F03F9EB013626D0517DED1B621CE8E600F857FE77FDFC3EDEBA2EFC555559F0FFEBBF86DF982DA2BE74D84F7E113CBAE0ADF42BF37D299B88ABFF9ECC5119F734A07E8EEC75E95BDFBE8A27E0C3C8CF3126B94BD13F722CE57D1B53F1BDFDF29BCEC8767959F8D8FA1D3A4D774368EDEFB7236B2733ACE01321EA0754BF7EB3C5F2FEB8FE71476D00E1E61AFE2BCEABD367FDF82F7F1841ED719D7F7E36EC7F76817C4D7E50EDC3C3DB49562BFF6BB274C0C2C094E6594772E3CEFBDA7C38F347B51EFF9B2467D1DFA2D1EE1BE9EF8DDD8E378B2FA888E017EE7032315F3085B41F6C2171F7F928ADF29B6EBD9131EE8DDC5DD28677BF77CF6E31CEB4ED4E7F0BD786823134F143F8CEFBFCF35DE2DF8EE3A4D8FCE38753F3FEA73F1C2C403FE8CF845DD8DC0C4B02FAE078B03C4DF73A5D8E759DFAFE3598F277485EF81F4637066D20BC28A94F7FEC3B3E65DFA19888736C116F85BE13A6D5DBD539E73DF17EA02C774C6B9434F864E0CFD181FE33E8C8481D78B7EE253F4DAC20BC41ADCEE15CE97F52D18286C0C1B41FA905C60E88211753FB90C3ED7CBFA1A1B60F7BC07FE54FDB76B6D86D89B4C7742EB079F539FD827617EF8343A27F54E2C364FB635EFD7EEC0EEC9E6D5B9A6ED573FDF3DAD39EE8ADEBDFE7BE1038BFF7ADF6B0C1E53E7DDD7EAB66EEFDCEB9CDF2D67BC707FB07D6803C92FE0B918F2EE2FEFA9621DD611FF267BB0729EF879FEDED13DB8C9EB0F0BFFDCF789F31D7C5179A0F74ABC6079F4EFA360DCBBEA3AC7C038D7B15EEA3361A1CE7359FBE14EF15EC9470EACD3FE849E0C3D103A2074C1C86B977D17E75998DEC3FF7884FFE2BF6807F01EC8461855EF17CE0B710CEAB1B21F781CDFA90764170B37A83333DE05FAAED2857B3B2BBC0FBA0BCA29D1DDC9C083D477FFE1593DD7E4B7623D71AF637DF1B9F09F3C80F443E54B6143C4FD1F65ADF1F7F66C7E9E7DC5AECA795EEE37EDFB92F706EC974DE1F722F66BC4F31FEB8F877ABEDA370BF753EFC382FBBC17B2F1B4D6D80FFAC56F2ECF53D800CD1A3F38AB6BD77DD8EF9EB14EEFDDFD1EDD7BDD0DDDFD0C3E8074DB1AFEEBFEEADCEBAC501788FF15FE4B5F0843B3E87B9DE3F28E97F72EFC0E3F30CE847480620085E75EBEC733409CBCBB1C57FF9FD25DF46FE4F7B83D70277B08987FC41127C1FF58AB380F9D09F77BF4543DB06B31DE754016FC970DB8E60B37312E6005F5BEFCFF3BE101EEC068EB17F6ADE5F908FFE3A17E179EC77BE7EFBB2D4CBB70441D289DAF734D7B4E182E9B571CA93E3A0F4E9D489E486765583F5F768DEA5BCECF1ADB47EF8F982F7CD0A335CAEE17F6490F0CCF7574B09FF81F8FD64F5DC6B5C73AB58F3CF3AF2FC7D67BC47F3FD7EEFFD3B6B9435CE87A89F5493704EF41FF487B3434FEDBFAE36FA59DEFBE7C7CCEF35E71FFF6EA2817220BFEF3CE3326447BA0C6C0C1F5687DFA5A77BFEC4F22FC7F17ECD719A8BA7ED103AF6117EECB59B868F05FFA63D4F5F6E25DF2FFDCB68FCF65E79007E3BE5177EA5E8C8A7DC43971385A17B171ED7CC85EA83C89DDFBE1F15FD87FF6A2EA78F2BAC4797D4D9BBFB1757056B2E43EF5EE8173E10D078675D3CE51ACD4F5C5D0EF1F363031D0F13FEE837203EF90F3229D51CEC0ED13C729FCD7C7D1B920FAB8BCD33C073CDBC439ADCD7342B866DD9B4CF7807E4E930F7AFB6CE3702F68F710FF1B3B60702EB4E707F7721A9CD7D059111E3EE9C7677E5C1CD168EB5F5B2FCF803800BDC3F8287BC7B1BFE6481ECE8DF80FDAC5A3EA3EB7F1628D8CDFC82F663DCF515E04783F9D75E24506FFBFDCF94507D22622AF476E58F78058EF1CD916F05F78283E5F793EDC9B52E382F83F39F091753FD7D9C37FF2FFE4C86513E9774AAC6BA97F1107104F867BD0F57D76CFDC5F2FD78FF8FF003D7877D9C6C0E92B66BA07D46FCE91D2E7D7392F6B5CF49F633F6D808C7A8031B19E7FF3801857C1FDC35DB87B795EF15F36C068EB7F9BDEBB860FF800CE87310FC77EDE0372C623FBFFF2EDF8B7F67200750FC87D347AD2F080D898C1FF575DDB51EE133870C5367CCD3D9B383BFE6BED95E3B8355BCF7C02E64F080747CF03EDE53CBBFF2FFF4679B08EFFF17DE5BA683F840BB201463E0BC27AF7FFD5E7409C472FC74136DE9DD5060AFFF964B8073DCE9FF1FE5847CFAE233E64C7FFB59878E3D7200FAEE6FC2D9857FCDF97E74DCDE0883520EFE2F378BEB3E7C879BEBF1EE105E3A643E33FFCD912037879DEC445E51BD33FAA76C3AE3DFF15076F12F0FFE27D3F386BF81E3F079E03C0387F8F13E3D759F1BFF1F16F2E8E74DE1AFEB31E4E777FD4B5AFD5FA68ED7F09FEB306A0C901BBB9183A17446B2BF62F62DCEAE9C31A00E9099EF9B21797AD0E20272E3F2005FE23CED9E376B51ECF79775DE0764036FE7FADBEABB9FB37C7B97F35DE7FF99C3B7D7799C7FF67ECD7EBF81AFF6E79EF6B9C512F477C64FEBFE6EE2C1F65FBD65E5FA803E4FBF6386FEF0E64E0FFAFD0AFF85DF05FDC1FF950E27E36BD770AFFE5F790FFF7277E4675EEF2F94B1C2901FFDFD3F36EFBA88EBFF01BC07F61067D1C7FF8FD91FD5EC63794DF50D60C1ED4D7C5D8FFC3AEFF33A3FB00E441DE850B23E759F38156F0BFE10213E1BFC786BDC6B1FA3735FFB39F13D7F0FF83ADDFEB1D4EE502BABE7BD81DC700794E9CFB1FB2F67FC173D96BC436E936F6415D5DE3AE8D91F7EAE086F6FF973E48BD5E303DFE5FE7BEA7EBEBBD070F3ABCDE5BA9832506AAD6CFED7FEA38E17FAD074990F7BCE6EFB8FFAF9C70E5F690FB938F4C3D2FDB501F755E86C67FE831D93CB5BFF1EED8BF7FD83DF703D0EF90F7F2BCB82DE03F398026DFC7F8306264CD994F16FFA7BE178EF7E27EE401F6A889AB79F09763FA01A77AFFB80DC43A1EF543DAEFAE56E3FFB40F47AD8193EFCBFA5EBDDB5AFF677DCE9BF7CADAF0DB96E76AF2FF07B67B9DFF97BF431EB4E22030ADC7EF64CAF97AD738186B58CADA70FE5DEFD1FFA77F9805FF7BB60FF3DBD53374BFEBE3BFFB813AFBB487478D81D43A1FF8FA95F3B01E21F57E631F7AB8E85C5806FCF7F8FF5ABD13F580D7C1D206F09CA04C7A608FFA78F573F1BA4FE677B0F65FBFA7984006FEDFFBF7D61970C87DE0DAD7F2FF2B2E7E9423FFEF88E3B859EA367D96B7C547BC264C7BC35AB9E1EBFFA1F77C9D1E0F66FE6BF36E6F8EF36268278FAEF7D67258BAB970A80FAD3981CFFE5DCDFFCB86FF6BFCBFF478CD91B3FC97C6FFDF5D35797FD516DC5D0D5FFFC7F8867C79CD3010FE377CAFF77BBB3CAE0BCF52037CCAFF77FFA8B179590FBC12FBC958FF4F5CD8A3DF9BF0BFD7074F4F930B001C1C71FD6FF3FF6907E95DD3A6F3F83F7D63E7FF47B4FD5E9D9F35B6BDF43BFB39B016967AB267E3B0EE2743DF9306FF57788EB51C00D502363D316EDBFAC74CFDFFDE8AFFB073EE6013F4F87FF5BCCCE0F75CAFF5BBC5FA7AF82FDE8B1C3973E3981BC2EF8FCCFFB3FE95F1FF12F7D859EE1BEA40D80B5E364F531797A8FF9FF7FD3DE5F77BAD2FEB3E35F78DF7239BFFDFD4C4A3172EF19FFA9E31F11A2BD98DCB817BAFB35EFF7B9D05E6F612FFBDFFDF1EF9A0A3D781B39E8FF18AA6F61F31418F07F1DDEABE7BCEEBE8E7DEF19FF90EBD78B0C7BFBD16B6672766C67FB7F578CFBDD6B1C9FFBB7DE6FCB2FAFF5C73F58F17FE9FF9BFC17BE87BC279F5FEE1FE8CCEFFB3FEB5C9FF5B721EA523C4FBF81C40C5C0A80BB2CDC2A1EF4BFDEFF9EF5E03CBDC27ADBD9E812435906B7D70D7EA62E8EFC91EF21EF0AE3747BDFBFBDD319EAFC503BDFEDFF7C7675F64C27FE63BEFD9FFDA6CE11A0FB49A60DD79E7BED2F8FF2766421CDDFF8FDA3CAF66FEC7ED55AAD9A7EF82FFD5BED9B5F828CC5B8BFF8F5EFF772AE6213B5FB9219AE54BFC2F73013AB951BDBCB051DF3D737D9ADE37E8E9E0B62FB93FD6C6CB06200790210F96FE7FF7FE776A5F9BD8A7E5C5F5FA828DAE037C165CAD67BB3C6FFA9E788E4B2F0ED0AB1B1CD9FFF77A7FE681785E0FD7D8F4D0432EDCE8F9FFBDFA3F9D55C6FE5917DFCB71ECE5BD3AF73534FEBFC506585B6FCFE6E9C5FE32E8BD5339003E03F0C9FEB938AA7D0C3F58FC7F99157899C3FE5BE37B18CF16CED77E784B9CCCE3FFB1EEE07E19031A3DFFBFE1FA0CFFE5FFEFCD9761BDB0FADE89F7F6BEC759FAFFF13C78CCB317CBEEF5FAEAF5FFC8920BDCD379BD9E38CDFA6E8E67A2388E8E8EFFCCE7E9F5F411FFEFF50E3E0373DFE18486C67FE4FF3BFE6BDDC27ECE007ADDE9F5B1DAF322C1B957FD9F6C1D9F6BE8731C7A364076FC3FE5F7F0DEAB0680775F737EEB9CFB8BA75EB8FB5DAEFABF237D0FFC572F1CFAC26BF8DFCCFFB9CD51FFB707EEB1DEEB14FEFB4C20E27E2FFF2D0B0FE6FAFF68060EFCBA5EADB3EB856CF8CFB9A73D5DC83539F63F801BEBE5888FB45EAF53640DE351FF9F9DF5B5B23AC7B7E17F86F9BFB4E9E37BC2FC5E5F2CCF87E8E17F9618B8FAFF94F93F9DBE17B40DD7F09F3A604BFE3FEB788EF0FFF619EF88FFFBE5AE64C07FE7B4D6EAFF6B6DE8E11E28FE5DF1FFAC8FFF5E0B372A07CE792711DF50BD937A1E1CE5FF59FE87E73CF4E6DFA5F1FF3F38CEFFF1DEF7B5C6C9D6EE3950350F749727FFDF67607A3E9CE7B91CCD45DFB5F5E35E1F3E22FEABBFB5D6C0EFB31F86DEA9F25FEB7C83CECC10F6FD18B9FF8FD6477E4BF9FFDEFFA7C9FDFFE8F49C8B4C7DAF9DFF3FCAFFB4DA67EA35E5F978DD57A6FC3FF7837B7940CEFBD11E10FE337E1CDFDB02FED7B5C1FF67DDA3ECE4D7E88D2B1CE4AC707D6F649F576BF4FC3FCF6F603F17D9363A075BF0FFD90B49BE20F3DB58EFC49887EB85ACF57FBC031E0B602D7093DF8A1A00D690911F1A1203A9E397F77CD7A901E0FBE6CC23C6489D231E9D03EFCD3B936DE373305913D3E3C27B762F9F0CF87FB570D7FEEED9FFAFFA0216033BEAF79168FEDF29FFDF7300A4E7EF2EDB5977256684F9BF651EC01207C882FF6BF5FFF1B1E7FFAB2F906C647DBFCEFCB199B9A3DE03E901F5BF76FFBFE2FFA2C36B4F17EC91E3FF510E40323BD8F3E0DCFF77BB87F84F5D90290EDAE3FFD77ADB1DD977376D1E686F4EFAA8F8CF1E85D2EF9CFD48FCF79987DD79A12BCF885C579D77CF58DEAE9D7B490E602D1FCC793FC7C314FE3FECA15E3E580FFF650F3A079839FFBF17FF74FE9F1818FE8FFCFFEA3FEEAE6ADD5836FF9FBD8D3CB65166FDC0FF5FC37FEF013D72FDBFF84BCEBF90CDEB359DB5C6BB330B884F0F1753D8C14B4F78F2E05EDBE6718F1EE7C15CE82C7AB097F3E3B671CC8563ECD76B5C7B792199F0FFCED62D4C68F2FF161BF81A7652B73E3C49FCDFFB7B3F580DA4E282BD1CD0DE994F8BFF1F1CCFFF75FCF7FA7EE23F6B9DB2F9FF9C01D0CB0574FF5F3A517E5EFCFB95D5FF65F0FF7B7DBFAABF07FC6FFC7FCCCA38E5FF7B4C6854FC27DFAD595FE2BDD51368BF6BFBFEB80E60CD1F6362D9EE41AF072EFB7C553FEFA69DFFA5FA87B53AC091FB3FAFAD7D6D36A6E77EBB5FCC9A50EF8337AABD47FE9FF98BAC91AFFCFF4D1B236F6AFECDDE19190359EFC65C0DD936A10B7AB57F6FC3FF5E0E5016FCD77938AA01B15E87ECF1E1BD3E32D6FF9F9A7DB2C6FF7BFE1FF13FBE57660125F0FF95EBBE07E74B8E47F8DFF4C75B74A0E2FF7157C22EA0CD9005FFE9F372DE1FEBFFF7BB563F781F18E783D9F72653FF3FBF07CCFDAFEB06AFC31A11CF7FEAE58266C2FF35DBD86B1FB4669F89E27CC9C8F17FF27E9C7FB7477E1CCF386304DE2BAC7707D2E0FF47CF711FFA05B201140BE9D5FDF16BEF7F9901FFAF4CF739FE79EE0F7D1DCF7DCA86FF5CEF29FF5FEF53E7A0DA03E891233CCDC0FFBF6DD6ABF2B7C90FB1068A1859F0DFEEBF73E12373209AF54D3DAF77DAD449777C80B53AF86CF740F610FD00E53B0BFF7B9C77CFD7CF560B740AFB7B739ED67ABD3E98AD38FA0C1CC77FF6F651CE9B7A81CBFF677D630FFFC9078FDAFFC2FBDD38FE3B16F4F23F7A67DE3FCF60FBBB2DD4C37FEFFB77EA9E67D379EFD20398F10ED7FF77C815D3DD90CD9811FFC9713E2CBDFFE5FF6B1662FD37D905F67BB40D33E07FC3835DB67D0FE32367B9C9AE53EE3B73E2BAF6C0CD459ABBD0EBFFE5B34EBDBF83F7FCED712269E2FF1F9E3535FF5ED3DFE3FFAB0DB0BB3AC2FFD1FD7FC6C099EB517160C9F9A9F57F8B7FD3CC37363BA7770F865BFBF959D3DF9F9CCD29FC8F9FE9F9FE6B7DB033DCFD5EED5FAF06D07BFD52B7F7E26119F1FF6DF17FE5BD53DFC79920FE7F7EFF49C5916CF82F8E977798B570CC7BF8F37FFE507900B78D99FFA68F29F01F791BDA935867E5BE6F3BF87F22F729DB5DE89D7FFAC0C200C741CF79CCC4FD572CFCE06C758EADCFF5E9D57D3F747AC965E2FF99C7C0FE07D4090F3BEB838FBA811EFE0F9DFF87B937C47F72FF8E098C6DF6B8FF5EFD4F36FC5FAB07F3B54BFF29DE413F2015E7F90EF57FF27B1DFF7F79FFAA9C1BED61C1C703FEC7A3F39205FF99FBEFF82FFB867E5FE022FB80795E8CC78546C77FCE00527F23AD93D8E7316EE73E32E43FBDCD276C724376ED99F7590FBD3820E7A2649C03C6DE7DC206FD9BFC61F7FDB2C5808481CC81F73C17BFDB0FF0FD2B3660CEB7F70A187EEDE74FF12EE978E23FE381F471E8DFF7EC00F78733F2FFE4018E663ADF3CD7FFB2E7397D80ACF8FF36FFFF61B179D9EFDEF1FFDB5F7DF1F8877FFFAEFA0FD9F15F7A403CB8BE176B1476EE775747F5F03E0B6764FC571EA37200EF7026B4CEDAFBEEE6E228FF93D89FB50E966782B8CF3EA9DEF7C4DFB7EF4176FC27CF57FD7FCB016B7ADE65C3FF951A38EF7FD89BFF439F9F397FC480D1D72EDCD37AEAACF30FDADE3FCE71BA6F433D47BD97C9FFF7F9275EFFE776FFA9BB9F49E731E6C3FB2F1DC85AFF589BCE81EC9FF85CF963711FBEFE1FBF7CFC73C1FF8BE1F97F8F71D1BFD51DD69D507C23BE175F0B177B35123C1323E3BFEE366B1CE4E311FFD9EBCD393FDA03EE1767C37FEFEBEEF8EF3D007ABD3FE90F64F1814ECEFD34DFB79703760AF733F0FFACE1E59C53E531F9FC1FF684F139B869F01F7D6F54E3E6FC7FAFFED3F17FEDDC67E4FFD77AFF28C7698DF7EBCD3ECCE4FFEF0D07A9EFA4071AFE7FC1FF2FFEE97559AFCE53ACFFBBFFF955E10032D4FFB3D71B7D00E6F8695FC4FF7FF1F16715FFD9439BF82F5E68F4FA3FF23EECF5E5F82FBF2FDE75AC8D7D6F3DF7CFEDE054B6B0F17EAC09F59E36D401710F180FF41CC02C764F33F77677D5D8768C7D9F9AF9E6E760F419788EFFCEFB79DD87F783E3F9CF82FF0D07B0F8FF5ED3CC997F6BFD1F1CEF150BA73F3C3CFE1BDF71340B16F7E0A1C3F352D767F4FF1D077CEE91C7767BF8AFDF8F9F09EC0F0E20C5FCBF8BFE0C2FCEFAE28CDCB8EB61DFBCBE7D5D3EDE5DB67E21B1D1E7E18EFEDE15EF8B476BAC9FDBDCAF5EEE6BAF2F4836FCE79E9017E37C14AF77E8C5FFB2F940EE0F1FCDFA5D3E773EDC635CFEF323E7400AFBAE961A575FF3C3AEED79C3B95FCEFFF77A418E6EFF3206B05F308EBD8FBABD3056E6E09203703E3C05FE2316C4B997C43FE601F6CE7FD6FABF77C57FADD3F15F36419CA3F8FCCB9F7DFEF8C36FBF4D33FF97B95E6EDF92FF577C23EC9BEB1F5D3F7EF36F5F363E428FFF1F1DFFC5FFB8FF1F6BD4E7B14EEF83C239C7E20465FFC80F60AD4CB6BB20FE8B792135D7CBFA804807300F38F3FC03DA3C8E6DE209D6661F78FEE7C818E0394F3DFCF75CC866B6F1AEDF0BDAF3C032E0BF747AE5FF8D0FDFEF8EF1BFB75EE7C2B3F9FF3E03B3A9FDDFB5F10F7F32E3BFCFF93A85FFD287C27FDD93B099C4FF47CE78863CC852EFBC9C7BE7FF35DB40779EF81F5F878DC39E61CEFF67F0FF7B7A5FF8AFF310EB545DA0E7BA9FAAFFC97A1738F79ADC30F97FDAFBA76CBE4C5CE0A93E5835FF6DD77EBFD70B2583EFFF2EF84FFBCF7B40AFF541C834FFAAD7F3A3E6FF7562FF8C01BE6DE6474AFCB71A80A6B7F309FC8F1AB8EC3AEF5DF0BFCEFFB93CAFF8AF7900AA918F9F0FFCFFDD6FBE4E31FB9DB3CEF68883559BEEA69D0726FE3F3E2FFC3FFAC3F5B060F4F93F05EF963E679CF3A2356A9DAAEDF0FE9EBE46FE7B66FCD7A318A86C40CE78EAE9BEB0877D1658360E903A8067DAF1DF6B9F7BF9E0A3E33F6BE0F7F0735803B0EFF441381507CF8CFFE271D76640ACE1FF29FB3FC3D977FCF79A50BE779FFD2DFCDF82FFEFDC07635F7AAF9A81A3FAFFC048FAFFE12F06FE8FDAFBCAFD7FD77BD4E9ECEFA33E19B1B63827B14ED5C8F35C785E48B6D92F81FF5AA3D6A9D90ECCF365BF7772C07126B610FFF759808A7B2BE7C56D9EF8BEF200B3CC3FEFD9C2C402DE7BE5BF475D0FEFC9A97EF0C3E3FF8281C1EDED77574D4C8B7A9FBD8199134E5BCF6B7E339CFF1EFECBE6EDF5BF72DEA7A7F3BC2F580AFCB71C80A6E7F9EEB8EF6DB3DEFBFCF97F3DDCEFF9FFB136FAFFF27764372AFF2FF8FF8C7DCFF7BBAB23FF9FF7223E1736CAC621FE679C7F7BC4831AFEC7E75E07557BE0DE5C1CE5056E25FFCFFB6249DFB3F641EF97F9FFD9F29F3CEE41DFAF17DF8E7DE8F5BBC838FBA0DB03F0E6E2A8EF31EBE3C5F9F5F86F7E9D02FF2DEF8D9C88DBBF8C7D79DD5FAFDF4956FCE77E1003F571CDEECDD6F7608DFF67FF931EFE731F84FF713694FFA7F8FFE8F37F7AF8EFF5CDE4FD34FF87FE3FF1FFC82E4CE4FF33FFAFE7FF4B0F10D71CFF7BD8973DFF9F7631FDFC5E9C3F73EE5FEF2EF4FA5AD6FE372FCF8F62033D0E78745DC85977FB4EED0F6300DE13652DFE9DE9FC8BF356FC83FEFF7ED7F2C1E4FA4EADDD676167C77FF685EAFAFF3FD946FCBFE70BF76C9E5E1F08F5CA887547EF1FF58C191DFB7A3E00D7A6334FFF3FD6A6BCB853F89F21F78FEBAFB1EE97E7758DCCFF23FF5F675DDF5C34F692EE433C5BF0FF391F4DF66E6FC68B730219F1DFCF426FAE057171AD0EB4878199FC7FAFF53FD50BBA17EFCB52FF4FDC13FE530FB02F4CAFDE91FC3F6B9EB7C4FFD79E50B7AD0DE0FDBEB8DE0C71EF77E181D7F09FDF63AE2CF1B1D4FF2D189161DDB47FF4CE95FFEFF8AFBEFFC2FFD7D60F994F06FF9FF9EEC27FAD51EB14F721CCEFD57A2B16963DFF8F67C2F17F2DDF8DF340B2FAFFAE03F627FAFDF5F25D7D1F32F880BD9A47B7731803101FD2C340E21FEDDF0CB8C73C68D601EFE10B930BEAD57EACD5C365C57FE9449E63B7FB7CE661567DE77ECFDE6A5D18DF602F64AE593562811DD10320CB5E28BF573680CF00900DA0FCFF581FF97FC707E685EAEB0CF84FFF5F6B94FF2F7F90BA9E77DCB131B3FF1F7267F130C7C01ECF9DA9F7DBBBE880B59E6F9C01D6E37D33F9FF6E0334F80F6EAF3EE8FFD8C33EEF059705FF99F7EE7320690379DC437B9091FB383A0796F758E3C178E73A13F57CDF5CA4E875FDD770613DFCAFFE3FEEBECE82FAFF85FFFFE53FEF5370DF5A37E77D08FF3DCF5D6741B90DCAFFF37848AC5DD8AFBCB0D1F7807510C2FFF8185FC73A233F5AF82F6C975DCC3BDF8B8167BC0B5A3BE79EF6FADDB9FFDB9B899C69DDBDDA2FEFEBFB601C383960E2409633C09887E21ADEEBB9D6FCDF3CCF7F5BF3FBD9FB2A1BFEF7EAFF9807A377EE775DEB66FD6BC6B3DFC3FF5E1FCC06FF6F2EDA9CA80DE03FF920E7FA18FBA30D2CFC67EF9F2CB3CF42DFABDF07F19F356EACFF8F750AFF551BA4DAB782F9F7ED7DC870F6C577ABFEBF87FFBDFADE5E1D387DA494F80F7B50F8EF796EA7FAFFA4C57F6081F7BA231FC6FE80BDDCEF2CF56FBAFFDE03A8F679DC59CFDB9B8B6E9E03ED804C6BF71E80EC7925CCAFBDAF7657DDB98FA7727F339EFDB53E58A7F0DFE75F6E01FF7BBDC0E9FF7BDE73C5FF83FF9F25FE45FC8F3545BC8BF8CF7EAFD5FF3FAC2FD6BD86FFAC05CF10FFD7D96FFCFFC31A89FFACFF232FC299075E2396D107A87CC8EDEB660E08759DEB3FCF01232F183A33D3BAD5FF8DB9B0BD7E37CE07F7725EB3F8C09EF3B0D6E3BED7DFD07B61669C7D5DEB1F963E57D716F37F40FFA3533D7FB2735FDEF7E3BA3303C0DFBB66426C29FE7F0AFFE31DD31F903D2CEC8C3D91FF9FC1EFFD4BFC7FE1BF6A1BC247965DAC7E08F4FF792732EC419D05B6E4FF0BFFD5FFAFE87BCE375F309EFD2F64FF649CFD47F9FCFE93CA87A8AF85EA1DF5ACF502DF42EF63EF7BFB36FC3F35FF68740E88FDEE7BF84F5FA7D7EFD8FBE164AD7DF7D9779E03D2CB81F1B88FF660F4BEAF6FF381D8FB4018DFB3F9E8FB911FC8A8F37CFD3DFC17FFDFABFD65FC7FE499F76B768FCFF2D1AC6FEAFD586FE0213F4A47F67A426ACF32F0DDDEFFB7D844CBE78A8DD207E8D53C28DF21BB2D2CFC971EF098B0AFBF87FF59F58038805AF3DDC17FF5FC76DFCFFDC00C1C10F51E7B807BCD77AFD77FAFDF7166FCDF230F8079607AC87957FB1FF73FDBCC8BDE3EB8EFCFD80FF37CA5037A76514ACED37A0030FFA337D3A3F87AF7AF9ABA80C87D0BFCCFB40FBE5EC57BC9FDD3D713BF11338E790E847FDE233FCB3E54FB07F97FF1C43A19071706CAE6F15E9825F673933B16166B663E74EFAE3317780BF14FE7007AB14FAF85F69ABF8C1C486FF66993F787BE779C79E1DC47E6B98FCC7DD33C90FD120F51BF27F5FFE8E57D66CF7B59E3427416E407FA19EFE5C06C05FF69FBF5FABB06D605DE0BF342E77FFDB337A5FF6F86D97F7E071CFFD9FB2FF6226A1AC3B6517FC3E6397C3F7C46F5442E35000B1E66D98307F4FB8AB5C63AE3F9E617BF2C5F7BFEBB782FE900F6C0CD8EFFB166CE7D2216F466DDF56AFF5F2416EF87E9EBA7EDB3D6F32253FE8FEA5FEABC9FDDD551CD97D64DBDDFABFFCB68FFF572DFC22650ADB77080710EE780B3C7FCAA2D84BD20FEF7F27D9C032C1F0F389015FFDDF6AFB32ECCFFD77A85FDC24662E2C3DFED53F53EDFEFDA5A97CFFFF14DC1BFF005BFF8F893F25E7B39307126E2DF35F7203E0A0B33D4FE3567E0F6F0CEFFFE7553CFA2FDF8F4EFDF945C40AD5136A0EBFF2DE4FFC5FBF4BE27AC0D979DEF7581DCB7CCF81F78C87AD85EEC23EE4A0FFF33E63F780D1C679EF772FE7A3D9198179319FF3DEF95359F7CB7E2FF7AF39F339F7DE7FFEB0C00E4F77BED47F87BDFFCDB97B5F74DD6B5EF3BB30F38EBB7AC37FCDC03360AE7030B62CDB207A40332E53E8BFB2E71CF03FE05EE0716D2FF935EF0774F1E2CCE417001613364C37ED941D2FDCCFBF1DE27F1BEA32F5089852CBC07F722BB1F10EF3ED61577BAD87D075B563A5F75E0CAFD2007929DFF7C5AFBEBDAFB8F5C18753FE7216C21FFD17B9FD1FF5FC37F5F6FE633E01C887AFF32F799F82FFE8FF1FF2DDC7B72009C835D731F6EAF8E7ADF080BC367C86EFFF80C60E15E997176585FF1F1177CE32C08E6C7E91C083732D90025EF6BA9FD8A9A779FFFEAFE0E67BEEAF3AF7F7A57F628A31DC83C28AFFD911EA0CF13EB961D1067227B0E8CEE00F560F01E71EE4B5CEB703E940B14EF9A3190A607F82E6FECBFF47A3ED8C0B1EEB59E6FAEF7B752FF5D6D1EC37FD97CB483BCEF3DF3C2326200E3BF0D0770F3FC75D3F713F38F0303BFF8F8B37247E2DCBC482ECE07550E5071AFFB273E38F45EC40ABD2774661B60CFB5870F7CFB94EB1EEFD7731D744F54F7E6BD6032E9C138B791E7AEFED7AA09D29D270FD2CB79772E3C23FE6BEDBAF74DCED7520FA1EF4BCF69DD81FF610BFC21A9ED431B286C41F53CAAB6DFFD93FD1BEB14DFE5FD60B2DB3E75F6CFC1068EF59675DE7FD2ED7F567B5DA2E79DF7BFCF68FBB29E9B7A8EBD2DA4E374063CFF23E31950DD87E702B8FF4F3B576724FC9DC041C5485F6C40540B527B5D6BAD0BE71D368FB84F71029BE0FF165B4F364EE03FFB7E79FD97F4BF720155FFAE7B9309FB2ED003DA39AFDEEC4BE93C7DD4FAD3EA00AC5D3911EC83AD7E47E404382B3153CDE3DB70A0E70B2906223D5075C1E19EE80CA4B6FD0FEFFBEC83170DF7253D10764FAC3572403CD7C79FB003D3F97C3F7ACA7D09BD1EEF37D6FAB675FA23DB37630E58F83FC238AD5F4FBC73BD77ED497C5DD67AD82FF9BC8537BEBCDA04FE870D1CEB0BBB269ED89F381F8A8DC51DE14CC8ADC4FF7A5C90FCC16217FCC371FF33E19E6C00ED4516FC0F5F3FF45E3CB201A803E9F7B01776530F5FEA04F5E4E480C579300656E6839E3D61026D24F54DE11E6D2507B8F738175E735F0F675EF51219718F9C67997BF4E159E5BED4F789E7DDEBA0C9076A4F32D641F12C7BBE0BEBFFA8F7581750734277CF6725D3FAEF169D1FF75C8FFB42BD99109C9DA6FDDB84FFBF7B9E6B5B759D1EE83FE907C587B680FFAEDB1B3E7CD7D60211FF99FF357A1C4CEBE0EC0FCEC30E5B807E9F7A9EF0A976C2616FE2DEBFB93C6F62C29E3B34AAADA7473650AC499FEBCC2B2F403541351FCEF2C332EA3EC77FBD57D9837A5C077A4FE46C75AFBCEFB5F67BC901D0C3DC7F9F81CB5E38BDFEF0996C3DCDB8F63A003E71F68BAEB73E3F9A8B5DB9F20F9F7C43C6CE46F707AABDFF411BFF943EE4F98FB5F31EC84E2CB133C4CA33FBC3DA8FA20381FFC2858A858BED47DE770BFE7F6FE6B9F77AF0FBA1EFD7FB7439DEFBDF77663CBCB679AF3AEBFC396101F1513381E2FD173FF0F044FE9F1EAF871ECD2FA28F2FBCD7C378683CBDFAAE6636D8EEEA280F3AB3FFDFCC44C00C549E19F506CCD8F7C5CF00D7A9F350631E37178D8E27EEF56AE247DF87DAF3E6F090DBE2DD579F73E6C3EBF7580BC29981EA835AE689743884516D803DF480F640EF9F9C1FF3E0981BA0CF3D7732EB5C5CFA81D2F5B537C0720F541F413EB0371B3D1D0FB4F4BBE9CD36EBF5FAF07A8807F80F9E2F309ACDDFC37EEF05C41830B1517581B1B6AF3EDE37FD6F3C5F4ADCC848F941CDAC0B725B8747B9BDCC6BE6DC1FDD8F3A0BD6EA0499139695F7670C48B530BAEF3C1BE284D91F2025F6BF3C3FB26DF4759D11B3F065E4FF951F2ECC543C54F83934F69F9F3577BAE01C621EB46F898DDE239CFD00B597E20418171B15FF2BA7BDE86CF93AB40BC40B698D3AEFCE87311698D52ED67E90FFD3BE282F589CBF9E9A038EBEB8596B4199E3DBEBF1E2F9EE8A83CA06BA5BEC468F17BDEFF3EF731DA5A394D7BE16F7ADF580CBB910CE790E743CAA15F29EE09C0938427E9C7C9EF878F8B27CCE1A965E7D17F19EF73DF4847EC7B98F743C306C7FE97DBE6FF6BBDE2FFE7FAD155C747E261FA7703C97E74D4F23E937FA3FC2F526468E79417137AE169FB17C6FD19971C786F16D2EAFBAD85FE75F239EEBB68FF642EB572C807E70D32F0BDC88F74F1BEE1C20FF299ED007D5CFB13830F3C0EBBA4D1F38779C292EC6D83E6380FA5CF8EFBDBF9AFCB7FB5747392319D6FEB07BE6347BF5EDA1D7C5732BE79FF53E8A81DC2D78A933546724BF67FC6FF2D977ADCD4E7B8E712FF2FFCA8B510C4C7817EBE61CA0DE8CCCE00846AA11638E87EE7C9DE773FFEA289E1518C1AF6B8F889BB6176C998DB0EC493CA39F7DCEBCA36F48DF98F51D3EDF593AD06301597CFFBBCBE75E2E3AC3B1279EFFA0358A176EECE2C54662CFDCE7FFDEC5E370BA1D393EBCD77A6A1EF0D20357769D725F6A2D386624FBCCB4B5DEC9A3C5FF98CFA635EB1E30F7A5E183340FF4F69913202FA6F71F7725F41EE38623EB0162BFCE45E14176CFB951F467E917D12FCE1803780036FA5C378F69F37BD51EB87F55EBA1B95FAC1978DF6740BDED845B75962B7ADB34F9AC1F3CD7C34B5F4827C81ED2BB0E5F903D903C4E42FB50FBF13EDF77CD6BC1BD672E67C1EE9BE7BC2FE9BA863B597420F9609E0DFD7746CE09BCB3380F6357E239B92FAC752D7C0FE221F481F4DF13B73424E701BDCEDA4EE942B7793D1FF4697FD017E2E6E2682E68ECC97E10DE9BB61D7D7FFAB9C443EA75C530D50F9D7500F13D6124EDA5264FAC3C4F5CCB68B650D501C8795BCB03F61CF8E07C342348F691F747ABF830A80E8835F843FC72BDE0F9AEEA892F2C147E66997F299DA573CB9EA6E2F68963EC772B3DCFDEEFD415AC0B7FDF79004D1DF7CDC551DEAEB86F715C9E13A39818D72E5E63AD2760ED07C4FE08CB5EBD577B17F13EF2DCFABB99E3A93ED09E27E6BD319B7E40C07FC68246E6FF65B75E5BAE17671CF9FB8DF3F3DC2FF1A2D19F8A0F8CD80FC1731C59CBEC71106183F7BDD3D73ADBD2F38C1BC5FD607DD410F88F5A26FA6A8C57D207621FA05E0D246B26C82BFA79291CC2E5F97BB7075FA186B7E8B6B3B6CE85F84FBF866B510CACE486DAFC00D54129A6146762D43C008FFB792CC4738164D3179B6777DDE640DC3CD941FB9717CDEC8811751EF93CE9BC1203BE69EB1A94E712EF30BE17779CFA907A5EFE03ED25EA8CF789FFE1FBC7BBF1598695C7330E40BEAEDF0BD97AF271F5B3B29188F9C251D6478E521FEDFC6DF503775795B7D7FC43CE00639E1FEB9F7927D83B30D62AFC1835FF493E2A739FD803DCF930CF8D2057C4CFA9FB46B5793CE62D5DC058EEF562F3EADC07A71B0FE79F08FFC98D688F6473BF6F7FC863FBF473F477D22EF0DEF65EE340DE5B9CB8FA84D2DE8FBD927EA00E781FF9B1BD1E7FAC8168F281973BEBBE4B3CC277C5C0D42744B3834B1F14F44491BFB1DF8D89FF471CD06207683DE56F5F3EA7CD20EE94DC17FBA08C88FFF45188FFF275C8F78BE316F725BECBE302C47FD500E81EE9ECBF4F3D586A72B146F27AB20598CFA3BBADF75CCE78E8CA8F5E34FE3FF3249507C03C3ACFA5F35A80F77DEE95DB221B47733EC5E5D4BCF69BE7FE2FF27765FBEBBFE538C97A10F141A3C6C68509D483A7F0DF63FFEA01A19880CF831D95FFAFB5AC9DFA8F729E81FF8163C27FAD2DEC1BE11B1FF25CCC097BDFF8CF3C3FF5EAA879CB61E3BE3CAF7798334E7596B90EF6FED27F53B9608C95325FC4FB08BD37DF5F3D3D765715C3F69617A1FBAA77EE5C06EBDE693BD137ECD5100DEBFF5B6C4B733EB45EE586ED510778BDE43E6B8F889923EA3AE6B492E3D079574C9FEB89AFC595CB06E2BC1BFAFFCA01601D01F99FF7F99ED5D3C9E7DAD086651F2BE901F5778CE79B9FBF29EBD17BD6EF2AB6C75840EFA12DF45EED21EBF9C3B3CF5C76E1BC7080761DEF8EF200BAFDA0177F4136D1A81C00ED62C52C78560AC7B1F0B7AF2E2C5FF0F0701E8CF74B18D5E6614D33F31C69D387ED1CEB12CE0B0BB456EA8906FF973A28AF857F2FF12EE4A8B38641FA49F84FAE82B69EF7016FE6032FFD11E41F3137CA6300EF9B07F7B83FFD805E0EAC627ADEDF55FEBF6260E2FF624FB57ED989DACB91F1DF6B80E21C88BB61BC83B5A0B26B3C3F8EF6DE6877BEC76B6BB65DC1FD9FBD2918A7F32B3F5F7EBFF7BDA28D1BDF8B9F8DDFD7BFB10EE47DC7FE95A3229E42BE1DE394CC0FE21CA8F8F7EFFFF593F2FCF13FBE2A1FC979AA169AF901D41FCC0F19A53FCE9E3DAE160C88F31E6BFBF65F1EEA1C87C0BC3DEC63AD29F651FB457DC0FB40EE53CF8B4185F85FFDA3974FF85762A487273E0F5BEFECACB599FCFD32676678FCEF707FD2F535A6737BD570D99EDBE2F8CF5C579D8DF7C9FFCBC7A1FFC31840FC6D25B7F5E579E3FB335F97BC9DF73E145724DF608D0B79DFF6A0F7EEF61E7F1EEF8E77471F4FEB20B7C93A40F105CA05911F3122F6FB1DF0DC46D63231379C73E179272A5E1E30F4BB5F7C529EC0C2513900BE73BDB7F8DB43F76B4DB269BCC797FC3F7124F1B3811B3FFCE6F3F2902F920F30C2BB56BD93F2D87BFC3F7BFB8A1F89731CEBFAD3EFBF79FCC36FBF289FBBBD17CF7E3937EC07E47563A3F884AC73B8C6DF1D6BD31A95CFB587CE604C407C90EC2AE1BF62C4B49F47AE8B938FEFFC27FB1AF23C8B4716074E5F8F3531A3D73D91BFA1ED566D5ACE0037FC97EFDCC3FFDA136BA90B621F9CF7B5CECADDA0CFDF5AFE9FEA6069C7B19F077B9FEB1EF0FCFB3E8E341BD9EB1C1A0C440C40E79FFC4ED3FB15DCA9F0DF6BC332CC836CE69DA0DF0173388F627E8B1F24FE4B7722F03E703F30F477BFFEACE8D1F87A440E807EAEEE77BCB7F87B19CB60EE0AFBA0B0074E607FAC359EF08F033B9CF31A85EB61EE3AB929E50832374EFB23BC97FF1FEBECD5F8B11FD4514DC0FD78FE20F3DC638D716EE3A3DE61AC53F58D4D9EE0F2EE59EFC6D81F7160741E9CB97CCCF9F0D818F33B150F61EF0FEF013D6AEEDF1AFED397E77B93FFBFE6E73BFF4FBB4FB6FF08B8A7987F2F07D0F1BF57C34B9F9FE741F7C3F19F719091FAFF780CA057EB41FC678E57AD85F8E8397742F141C5C1E547CA5EC8D017F315EA37C989D1AFAFF98E0BDFA3FBA2B3AEF870604460BF7CC5D88B11E300B47BC4FF290640FF9DB91CBCE33CEFC245FA8E23F67F541E40ED51FAD145834FCA75A76F2C6CD4FA64EBC84720C75F7B01206EC6FEC0A3D6C0846FF4FDAF3E2DEB0BFB4F5C479CE3D2D38179AFC875F2F8AED7FE8D14EF5813CEB1663E53ED6D837C3EBD4BE582D1DEE17D610DE5E8F82F3DA0B534B95EF7AF9A3C5E3EEA13A59F3FF2FDE1338D82FF77D6EB5B58AFFC8F1EFE13F798E7CD3BCFDA19D97ED20D23D6829FB201D8FB56B94F8C85D3FE617E78C50FDA3E496681B80DA4B51FF15D4B2EA0F09F7960D223E48947C47EBFFBD2EDFAFB3D97913C0EEF3F73DDE2E785FDC28D51FD5D3E3AB7B557E7CD455303A8BADFB0EBF45E8B0D70C04AAD8FF7BCF224B13788058EC4FBAFC583E26F2EB1FF5F3D7156E2AF9A3CF7851B539EB8B090FA9039A459EEBFF0ADD6732DF11FF67B643C57B6A2CE3EF5047DDF14BA0FF61CF94CF2BDD2EDFE6F1EFFA4BF3412E72D519F03E7B1D8F7ABD6FFDF230670FFCC01D4B37EDFFAFFE2826A1F78CB1F1CD1E7652F00C6055413100F390DE67D30E74D7E94E787A4EA7D8F99077ABCDF17FBBC571DB79C0DFD77E43F8D8CFDE4009403C05E678177D26B1EBFA63DA4DF899F0FDC28B971076CE42CF051ED1ECEB3A45D2F7DE77C5FBC4FD900F46F9A1CFFFB574DAEE46831FF77898DB0B715B910DA8ADA3BAF6B623E78961E58B401A8B3C87588CF615E5CE4018AEBECC57C33F401D63A23F6A55E9D1EBB89BBC1EF39D67BAE1B73E6463CF78DFFBFDC7BF27E5EFF4FBE83B122E2FF51DDCFFDAB6172FEDE8503D0BC06CEFAD65D27A7D78D6B420F7AEC28DBEC1B7F6A2E88E97AE6CA66B9E76B6BA65FD7D433845E5B745B8FDBE4D39C8DFB57C3C77D34A3DB7B7A707E53AF8F7FAFBEDFFBFEB22F346D8AD1E7E179FD435317BE9C0FD6C68B3322BFC199485B9885CDDA6ECE7A54FD336BE218F7CF34F324E40E739C9A98D5FDABA39C0EFA436B36C0E8F79FF3AD6B6FBF9DCDAFB97FD5EDFBD8C3825A0B75DF62FFE8FDDF89FD8E05E4858801DE0B90F640C1FE84E75F9840DDA61831EB791CE746EE6BFC97F000F2F11803F0A787FFB28F38FB7864DBFFC8EFB9442F00F4F778EA5BF5DCDBBED68163EEA57E8F79448C07B007648633A23926EC7778F8769D0FC81EE73A2F7BF4BF608C6C841E07FF257C31F481CEBAF0DF39318FF364D30BEA8F413DC73CB7537EBFE37F863DE02C30CE3ED21DF75E9E5DBE0F35CED48319F45FCFEF6DF0DF72C3D666C2AC9DFF8CF75D3C18ED43D9FD8C8513FF745E32EB39F570605D8BE7FE69ADECE7CDBA5AD90FAC91C9C4FB84BD5BFA7FED9EFB1E7376977AD9F57822F911DE3334130E78FFEFDEC33C00CD3A568D306B45B3DF87A20B961C40CEBBA37DEB9CFF16788FBBCBF5FE55CEFDF76C820CBE7FCF06509F830770823D4E6F6DBE97DBBCD9CEFFA9D9E7AA69E6DA3DCF8FF67F767F5876CF7EE979EBF51EAC01520E79467B7F8D0BA00D20FD56661B1CD6CAD919EA7BC53999E4C733EAFB3DEA6195177FB1E4C994DE20CB0C8FF85C3962F1EFCC15C8E8FFC9F78F77299FDFE78137735E6FDA3928ACF3DDC23D88B37085F9B7B4F19A1CD99FBD39F20BB2DB3E3D7FCF6BFFF9784FC06CF64FD83C774BEF9FDAC31CF3DDF91CF17CF72D173C62CFB7BFD606502F64F57575ECE7B9AFB9225BB9FF1F9E1DCD82E09D502F48F686DA920DC05C40C540991BC259F7CAA325279C791FF6887F5F2D73B0A41B740FD4FB4ED89879BDC5AEC39A89FDDE23DAFBDC11FBB710EFD7DDD79A7B3363BC464631CFACBE9F63E11EF37F1A7F1778E7B1DF2DD87FFB6546AF708F7D7E8ED6CABADFFB677EE0C506A4CC498F5E284BFCDBE760703F7CCEC1567480CE836C00F67A647CC86DDEADD800B4038EE7585F35F3723907B2CE8DDC3DD9D419D71DFE9E7CE08B972F8ABF1F6B550D607C0CFC2356BEBECCFBCEBDDFE18B25DECF5EE0CC0D69F2A1EE5F353352B670EED9F741F75A73DF691B332EBE95B8C71D723CD9D7495C8FFBC3EE1BBFD890C8062207AC3EDFDE07604BF8AF7A10D549864D245DEF39213E0346F3CDB680815EEBC45CF15E5FB7ACDCEFDBCE82664033DF4DF96FDA07F5C76B7AA81F7E2FEB7B571C3CF05F332CD5DB39EA1BA34FDEFE697DE51975B6EDBBBE63EF7BCB3EC8F175B9FBE8737B34133441AFBB77C67EF438F638EF9A3FB805EC671DA0DE3F3F67BE87F08F79439BC3FF0FCFAADDD7CC0A5FE2C21EF31B79B6C55FB376DD0572FFEC75CA7C5FDA40EAA1B285F35072002ECF9BDE90C47FD6453216B0151B483C40E5366E9E7B68D639C0CBBC03F9419CF79AD5FF1707209EA3F4F259EAFFA32F4EAC37D62FCCCC7AD695D3419B4DFDFEF8D0F7EFF5B7DF92EF7FB7CC7BEAE57AF5E6006F45D7797F47D680D55E58C8EF11168A1BDE1AFEB32780F360D2F13E13602B6BD739D82FFD2F65E7F43820BF2BCA01DCD29D58EB1BE739818EFF5BB101C4FFF1DECB27082C102E6AEE419D259E70FD7BCC82506D5BBC5BF535D6B3D8FB69D7A9F3EDF9FDAAEB78BDE44531C6EF3D5E74E6B770C68BBEDBB5B35D1DEB1B7BE07E5BF8EF73612AEE810FE1FDD73ED5BEA81BD1753D3D20ECD72C04DD09E2E2E8FD3DFE9AF3A01C78CDF6E5AC5F6102FB9EEA3C6C290F30DEBD7A81AA464C7562CC93270F40FCDF4A3E34635ECCF553FD97E6E20436EE313F25230E686DA1E323DE1FEF567D1D350720DE75AC51337FB3E2BFB80EE6BC49E7090339DB86BEFF66B04FD8BFC476C569F7FC7DE73BB7C2FD13E758035373006E9F737DC4F1BABEDB12FEF93C38F93BEE036FCDD773FC930F20FEF7E85E585FC42DED077B02EDC181C9068A473DF3D8277F4BF82FACA74E8C73D0E407DD5ED53C68F5FE67FE4426FD18775EB580C202D901E27B0AFF7F799E1EFF99EBA0FA67D50370B69DF7F8C830DBF62FE5F80AB7BDE4B988BFECF579EB71A05BC37F710135EF179C90C7BE150F8F73B345FC672E04E741D55CC0DBEDE27F48A97D5A662793EF59B38DB3F5FD7EEB19587810F6FA210F220E84BDDE5913987D2F2AF775D9BEFB58BBEE857223140B8839328191D421E9D6BB707DCAFBD7438E4379E259F19FB1FF3DE2B9C27EE5F7ABFE9B75DE5BD17777C8ED953E979FEBB1DEB59CC0EC7BE1F8CFB31DEB53CE8F7324CC87DB1AFE37F6103E67BC9FBDBDB78CFF9A8BCEDE08AC09F019685BB18798132B1DA17C08DD01ED01EBA27B1C40D6FDD0D917FFC519D0B107AA17E60CA8E0000223950798A93E4EFA4FFD9F351359739D65DF685F6413657CB7E4FEC9757A6E8BFBFE5BC1FFDAE764F77C9E39CF9CFECE5A3C602BBABFE878E4FF17FC5F74BDF83FD945C4FE587BDC934DE23F66E490FFEF61DD56F13F7421FB9F30E771AD16662BB910EA0150EA219733C0B573FE0B6D00E98A2DC401F6C80B924F5C6B1D973880F244BD3F749D1F93A81620DE79BC6FF5B92F33B0EF5F353D5F62ADB166E67C647CB70B2F53F31859E7AF7E2F47F88F7B9EDDEF2FBECD92E758F1EDF6AAA9695BEDFD7ABFADBE47BCEF9C8F47DCE7D7DA2BF506DD1AFE4BF7CB7F71FC977D78B7F83E2F362A2507003180A73AC88BC61FF4DE785B3C07E4BABDE7B36242E44C7946B2DB87AC05960DC05AE05ECE94FAE465CD01541F14721F7526C0C2F9AB3620BB0F2C7FAED7E78C39006EE767C7FFC25B2FF8CFFE566EE3367D5F8DEFDC62DD9BEA3E63ED3C1FBCEFE241650B6C0DFF857D4D0F988F2E9AB99F3A3F5BF5FDB50725CF7BE97B4EFBD067A46FCD1616FE334EEA768FD6EDB322690364DF03717CD20B8A116B0E5AC3872D7C88B8D3CC679E359F9E0BAF7CF82DF4FD72CCEBF57FF73AD7CDD4B65A8C8E7BD1CBF7731B688BBA5F58CF795FEEFF2B16AA9EF95BE6BFA50F14FFA62EDC32F72FFFA0990FB8C48574177CEEC916F7803170F9049C7DC299B85B9A81C63B208E4F79E2AC83254EB04F5A6ABB1773DF140795CFAF7917B1DE2DE97CF679E8C5F6B66AE3BB1D403FCFE300B493B6CCFB724F38DF83F6B0F27FA40FB68C819AF5269DA09CE82DAFBB609FE2BFCB9C37D7F3B49BB7BA078A156A2EA47C5FCD44613EA474C69670817D402BFEC3F7975F983D1EDEBDF74BFE2BFB9D84EFBF95351EE97CD477F3D9525F8F77E502680749DF71DEE7D6F783FB223E4C3D3F4AEC1B7763EBFBA0D948DA07E9FFADBF7BF1DFC23AF23D7F2BEF5DB90FD28BE281E80B6CB107A6E33F6783757B416C08FBEBFA6F5F3FF2F9F4C7FBF2FC2DE87C3D5BAE6F7A97F537B9DECBB9E7DEBC983265CB18F8F2FC6FEEFEAFE982BFF5B340BF686BB3AFA64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA942953A64C993265CA9451E4FF01F342A6CA]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
      </Children>
    </Group>
    <Group Comment="Debug">
      <Children>
        <Bitmap Name="SpotBitmap" Width="16" Height="16">
          <Producers>
            <BitmapExpression>
              <Expression>
<![CDATA[//

float O = 0.5-0.5/64;

//

pixel = 1-radius(O-X,O-Y)*2;
pixel.A = 1;]]>
              </Expression>
            </BitmapExpression>
          </Producers>
        </Bitmap>
        <Bitmap Name="FloorBitmap" Width="32" Height="32" Filter="2">
          <Producers>
            <BitmapExpression>
              <Expression>
<![CDATA[//

pixel = frac((floor(X*2)+floor(Y*2))/2);]]>
              </Expression>
            </BitmapExpression>
          </Producers>
        </Bitmap>
        <Material Name="FloorMaterial" Shading="1" Light="0">
          <Textures>
            <MaterialTexture Texture="FloorBitmap" TextureScale="32 32 1" TexCoords="1"/>
            <MaterialTexture Texture="SpotBitmap" TextureX="0.5" TextureY="0.5"/>
          </Textures>
        </Material>
      </Children>
    </Group>
  </Content>
</ZApplication>

First you have to init the camera Position and Rotation, otherwise the game will start with the last parameters in memory.
Then I add a RepeatDelay on the keyPress so you won't jump around like crazy.
And then you turn around using App.CameraRotation.Y += Axis[0]*0.25;
(0.25 is a quarter of a full rotation 1)

I'm not sure I understand your frame size problem. Are you talking about the floor?

jinxtengu
Posts: 79
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Doom style 3d reduced to 2 directions

Post by jinxtengu » Wed Jan 23, 2019 5:09 am

Hey thanks for the reply, Ats.
This isn't exactly what I was aiming at, however it's useful to me none the less. Everybit of code helps.

Perhaps my explanation wasn't very clear so I'll try and break it down.
The monks code makes non player objects display fake angles, loading 8 animation frames for each angle. I am wondering how to modify the monk code for non player objects, so that rather than display 8 directions they display only 2, depending on where they stand in the players field of vision.

The size of frames I was asking about refers to the size of the bitmap that the monks texture uses, since the code is set to display only 64x128 correctly, it would be nice to have other size options.
I hope this helps.

User avatar
Ats
Posts: 255
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Doom style 3d reduced to 2 directions

Post by Ats » Wed Jan 23, 2019 7:40 am

Just replace the monk by the sprite sheet you need inside Content / Group "Monk" / Children / MonkBitmap / Producers / BitmapFromFile
The size of MonkBitmap should follow. In my example it is 64x16 (4 frames)

Then in Monk:Model / OnUpdate / ZExpression, set the number of frames to 4. (float F=4;)
That's it.

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Monks" FrameRateStyle="1" ScreenMode="0" CameraPosition="1 1.6 -11" CameraRotation="0 -0.25 0" ViewportRatio="3" FileVersion="2">
  <OnLoaded>
    <Group Comment="External">
      <Children>
        <ZExternalLibrary ModuleName="opengl32">
          <Source>
<![CDATA[//

void glEnable(int C){}
void glAlphaFunc(int F, float C){}]]>
          </Source>
        </ZExternalLibrary>
        <ZExpression>
          <Expression>
<![CDATA[//

glEnable(0xBC0); // Enable Alpha Test
glAlphaFunc(0x204,0); // Greater then 0

App.CameraPosition.X = 0;
App.CameraPosition.Y = 1.6;
App.CameraPosition.Z = 0;
App.CameraRotation = 0;]]>
          </Expression>
        </ZExpression>
      </Children>
    </Group>
    <Group Comment="Library">
      <Children>
        <ZLibrary Comment="Standard">
          <Source>
<![CDATA[//

float radius(float X, float Y)
{
  return sqrt(X*X+Y*Y);
}]]>
          </Source>
        </ZLibrary>
      </Children>
    </Group>
    <Group Comment="Monks">
      <Children>
        <Repeat Count="32">
          <OnIteration>
            <SpawnModel Model="Monk"/>
          </OnIteration>
        </Repeat>
      </Children>
    </Group>
  </OnLoaded>
  <OnUpdate>
    <Group Comment="Input">
      <Children>
        <ZExpression Comment="Reset">
          <Expression>
<![CDATA[//

Axis[0] = 0;
Axis[1] = 0;]]>
          </Expression>
        </ZExpression>
        <KeyPress Comment="Right" Keys="&gt;" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[0] += 1;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="Left" Keys="&lt;" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[0] -= 1;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="Up" Keys="^" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[1] += 1;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="Down" Keys="_" RepeatDelay="0.2">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[1] -= 1;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
      </Children>
    </Group>
    <Group Comment="Camera">
      <Children>
        <ZExpression>
          <Expression>
<![CDATA[//

App.CameraRotation.Y += Axis[0]*0.25;

//

if(Axis[1])
{
  float R = App.CameraRotation.Y*PI*2;
  float S = Axis[1]; // * the distance you want to walk

  App.CameraPosition.X += S*sin(R);
  App.CameraPosition.Z -= S*cos(R);
}]]>
          </Expression>
        </ZExpression>
      </Children>
    </Group>
  </OnUpdate>
  <OnRender>
    <Group Comment="Debug">
      <Children>
        <UseMaterial Material="FloorMaterial"/>
        <RenderTransform Scale="32 32 1" Rotate="-0.25 0 0"/>
        <RenderSprite/>
      </Children>
    </Group>
  </OnRender>
  <Content>
    <Group Comment="Input">
      <Children>
        <Array Name="Axis" SizeDim1="2"/>
      </Children>
    </Group>
    <Group Comment="Monk">
      <Children>
        <Model Name="Monk">
          <Definitions>
            <Material Name="MonkMaterial" Shading="1" Light="0" Blend="1">
              <Textures>
                <MaterialTexture Name="MonkTexture" Texture="MonkBitmap" TextureScale="0.125 1 1" TextureX="-0.0625" TextureWrapMode="1" TexCoords="1"/>
              </Textures>
            </Material>
          </Definitions>
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[//

CurrentModel.Position.X = random(0,16);
CurrentModel.Position.Z = random(0,16);

CurrentModel.Rotation.Y = floor(rnd()*4)/4;

//

MonkMaterial.Color = 1-radius(CurrentModel.Position.X,
                              CurrentModel.Position.Z)/16;

MonkMaterial.Color.A = 1;]]>
              </Expression>
            </ZExpression>
          </OnSpawn>
          <OnUpdate>
            <ZExpression>
              <Expression>
<![CDATA[// Number of frames

float F = 4;

//

MonkTransform.Rotate.Y = App.CameraRotation.Y*-1-CurrentModel.Rotation.Y;

//

float A = atan2(CurrentModel.Position.X-App.CameraPosition.X,
                CurrentModel.Position.Z-App.CameraPosition.Z)+
                CurrentModel.Rotation.Y*PI*2;

MonkTexture.TextureX = floor(A/PI/2*F+0.5)/F+0.5/F;]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="MonkMaterial"/>
            <RenderTransform Name="MonkTransform" Rotate="0 3.3088 0"/>
            <RenderMesh Mesh="MonkMesh"/>
          </OnRender>
        </Model>
        <Mesh Name="MonkMesh">
          <Producers>
            <MeshBox Scale="0.5 1 1" Grid2DOnly="255"/>
            <MeshTransform Scale="1.5 1.5 1" Position="0 1.075 0"/>
          </Producers>
        </Mesh>
        <Bitmap Name="MonkBitmap" Height="16" Filter="1">
          <Producers>
            <BitmapFromFile Comment="Imported from skeleton.png" Transparency="2" HasAlphaLayer="1" DataWidth="64" DataHeight="16">
              <BitmapFile>
<![CDATA[78DAED97C10942410C442DC0A3479BB3040F9660091660531E2DC1165656181942924D62D08BC2C2479C9DBC249BBF8E3136E3BFD4B5DBEE072FEFB7F3F389BE53DBA5BF3F6E6F3D9E2B7B9C2FD794B6CB7BFA66B5A8A3178356EB08CB37BDAB79E31850377EB662B03E53733A1E5E5A7CD7EDADC5A1F94672C77AF42EF791B58FC5CE758CF057BCAD3DD83FCACFB122879C476B9E74F057BDBBF9D16FC83DCF306B9659FC99FA55BD573D94E167EDCC3D7A703E3347949FE38EF47FC5DBE2E7195239FF5A0D56E75F72646290B38BF9ABE75FF65FB4FE881BFCB28EDEFD87CF1D72C00C2B6FB0E3FC47F5DA1E1C47F41D0C56F41DF763861F7AD471757ED95B5B117EA9E738B2FC60D7CE4084DFD2777B5BF73EB9BEC9EFE97FC11FBD8377CE3F4BDFEDBDCA613477F23D26FF4379F748EFFD979DFF596F6FFEAFBC9F3309064F]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
      </Children>
    </Group>
    <Group Comment="Debug">
      <Children>
        <Bitmap Name="SpotBitmap" Width="16" Height="16">
          <Producers>
            <BitmapExpression>
              <Expression>
<![CDATA[//

float O = 0.5-0.5/64;

//

pixel = 1-radius(O-X,O-Y)*2;
pixel.A = 1;]]>
              </Expression>
            </BitmapExpression>
          </Producers>
        </Bitmap>
        <Bitmap Name="FloorBitmap" Width="32" Height="32" Filter="2">
          <Producers>
            <BitmapExpression>
              <Expression>
<![CDATA[//

pixel = frac((floor(X*2)+floor(Y*2))/2);]]>
              </Expression>
            </BitmapExpression>
          </Producers>
        </Bitmap>
        <Material Name="FloorMaterial" Shading="1" Light="0">
          <Textures>
            <MaterialTexture Texture="FloorBitmap" TextureScale="32 32 1" TexCoords="1"/>
            <MaterialTexture Texture="SpotBitmap" TextureX="0.5" TextureY="0.5"/>
          </Textures>
        </Material>
      </Children>
    </Group>
  </Content>
</ZApplication>

jinxtengu
Posts: 79
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Doom style 3d reduced to 2 directions

Post by jinxtengu » Thu Jan 24, 2019 2:20 am

Thanks Ats, that does seem simple.
Do you know a code that could be used to set a value to 1, if an object is moving to the left (as seen in the players field of vision) and sets the same value to a 2 if the object is moving to the right (again in the players field of vision)?

Also any idea how a flat surface can be made to always face the camera?
Sorry if im asking alot of questions.

User avatar
Ats
Posts: 255
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Doom style 3d reduced to 2 directions

Post by Ats » Thu Jan 24, 2019 4:02 pm

There's a bunch of techniques to see if something is within your field of vision. But if you just move on the X and Z axis and rotate the camera only on its Y axis, I would go with that:

Image
https://math.stackexchange.com/question ... of-a-robot


For the surface always facing the camera, it's called a billboard and it is here: viewtopic.php?f=1&t=943&p=5582&hilit=billboard#p5582

Code: Select all

YourSprite.Rotate.X = -App.CameraRotation.X;
YourSprite.Rotate.Y = -App.CameraRotation.Y;
YourSprite.Rotate.Z = -App.CameraRotation.Z;

User avatar
Kjell
Posts: 1714
Joined: Sat Feb 23, 2008 11:15 pm

Re: Doom style 3d reduced to 2 directions

Post by Kjell » Sat Jan 26, 2019 5:01 pm

Hi jinxtengu,
jinxtengu wrote:
Thu Jan 24, 2019 2:20 am
Do you know a code that could be used to set a value to 1, if an object is moving to the left (as seen in the players field of vision) and sets the same value to a 2 if the object is moving to the right (again in the players field of vision)?
This seems like a rather strange thing to do ... for example, when a model is moving almost straight towards ( or away from ) the camera, strafing slightly to left or right can change already the ( screen-space ) direction of the model. Check out the following screenshots, the red line below the ghost represents the ( world-space ) direction vector.

Image Image

Anyway, here's the example from the screenshots ( use arrow keys to navigate ).

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Pac-Man" CameraPosition="15 0.5 15" CameraRotation="0 -0.125 0" LightPosition="0 1 0" FileVersion="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <Source>
<![CDATA[//

void glAlphaFunc(int func, float val){}
void glCullFace(int mode){}
void glEnable(int cap){}]]>
      </Source>
    </ZExternalLibrary>
    <ZExpression>
      <Expression>
<![CDATA[// Enable alpha test

glAlphaFunc(0x0204, 0);
glEnable(0x0BC0);

// Spawn Ghosts

for(int i=0; i<4; i++)
{
  GhostId = i;
  createModel(Ghost);
}

// Spawn Stage

createModel(Stage);]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <Group Comment="Input">
      <Children>
        <Repeat Name="AxisRepeat" Count="2" WhileExp="//">
          <OnIteration>
            <ZExpression>
              <Expression>
<![CDATA[//

int i = AxisRepeat.Iteration;

//

Axis[i] = 0;

//

AxisPositive.CharCode = i ? 38 : 39;
AxisNegative.CharCode = i ? 40 : 37;]]>
              </Expression>
            </ZExpression>
            <KeyPress Name="AxisPositive" CharCode="38">
              <OnPressed>
                <ZExpression>
                  <Expression>
<![CDATA[//

Axis[AxisRepeat.Iteration]++;]]>
                  </Expression>
                </ZExpression>
              </OnPressed>
            </KeyPress>
            <KeyPress Name="AxisNegative" CharCode="40">
              <OnPressed>
                <ZExpression>
                  <Expression>
<![CDATA[//

Axis[AxisRepeat.Iteration]--;]]>
                  </Expression>
                </ZExpression>
              </OnPressed>
            </KeyPress>
          </OnIteration>
        </Repeat>
      </Children>
    </Group>
    <Group Comment="Camera">
      <Children>
        <ZExpression>
          <Expression>
<![CDATA[// Camera control

float t = App.DeltaTime;

App.CameraRotation.Y += Axis[0]*0.25*t;

float a = App.CameraRotation.Y*PI*2;

App.CameraPosition.X += Axis[1]*4*sin(a)*t;
App.CameraPosition.Z -= Axis[1]*4*cos(a)*t;]]>
          </Expression>
        </ZExpression>
      </Children>
    </Group>
  </OnUpdate>
  <Content>
    <Group Comment="Input">
      <Children>
        <Array Name="Axis" SizeDim1="2"/>
      </Children>
    </Group>
    <Group Comment="Stage">
      <Children>
        <Mesh Name="PipeMesh">
          <Producers>
            <MeshBox Scale="0.5 1 1" YCount="15" Grid2DOnly="255"/>
            <MeshExpression AutoNormals="0">
              <Expression>
<![CDATA[//

float y = V.Y*PI;

//

N.Y = sin(y);
N.Z = cos(y);

V.X = V.X+0.5;
V.Y = N.Y*0.25;
V.Z = N.Z*0.25;]]>
              </Expression>
            </MeshExpression>
          </Producers>
        </Mesh>
        <Mesh Name="ElbowMesh">
          <Producers>
            <MeshBox XCount="3" YCount="15" Grid2DOnly="255"/>
            <MeshExpression AutoNormals="0">
              <Expression>
<![CDATA[//

float x, y, sx, cx, sy, cy;

//

x = (V.X+5)*0.25*PI;
y = V.Y*PI;

sx = sin(x);
cx = cos(x);

sy = sin(y);
cy = cos(y);

//

V.X = sx*(cy+2)*0.25+0.5;
V.Y =     sy   *0.25    ;
V.Z = cx*(cy+2)*0.25+0.5;

N.X = sx*cy;
N.Y =    sy;
N.Z = cx*cy;]]>
              </Expression>
            </MeshExpression>
          </Producers>
        </Mesh>
        <Model Name="Stage">
          <OnRender>
            <UseMaterial Material="StageMaterial"/>
            <RenderSetColor Color="0.1255 0.1255 0.8784 1"/>
            <RenderTransformGroup Translate="0 0.5 0">
              <Children>
                <RenderMesh Mesh="StageMesh"/>
              </Children>
            </RenderTransformGroup>
            <RenderSetColor Color="0.0314 0.0314 0.2196 1"/>
            <RenderTransformGroup Translate="0 -0.5 0">
              <Children>
                <RenderMesh Mesh="StageMesh"/>
              </Children>
            </RenderTransformGroup>
          </OnRender>
        </Model>
        <Array Name="StageData" Type="4" SizeDim1="25" Persistent="255">
          <Values>
<![CDATA[78DA6BE473E673E273E473683DE2CCEAC2E2CAEAE0CCE6C4E6C8E600004A28053B]]>
          </Values>
        </Array>
        <Mesh Name="StageMesh">
          <Producers>
            <ZExpression>
              <Expression>
<![CDATA[// Lookup-table with vector & offset

int[4,4] v;

v[0,0] =  1; v[0,1] =  0; v[0,2] =  0; v[0,3] =  1;
v[1,0] =  0; v[1,1] = -1; v[1,2] =  1; v[1,3] =  2;
v[2,0] = -1; v[2,1] =  0; v[2,2] =  2; v[2,3] =  1;
v[3,0] =  0; v[3,1] =  1; v[3,2] =  1; v[3,3] =  0;

// Generate mesh from binary data ( hi rrTea ;-P )

byte s, a, x, z;

a = 0;

for(int i=0; i<25; i++)
{
  byte value = StageData[i];

  switch(value & 0xC0)
  {
    case 0x00: // Pipe
      s = value & 0x3F;

      StageMeshTransform.Position.X = x+v[a,2]*0.5;
      StageMeshTransform.Position.Z = z+v[a,3]*0.5;
      StageMeshTransform.Scale.X = s;

      @MeshLoad(Mesh: PipeMesh);
      @CallComponent(Component: StageMeshTransform);
      @MeshCombine();

      x += v[a,0]*s;
      z += v[a,1]*s;
      break;

    case 0x40: // Elbow
      a = value & 0x03;

      StageMeshTransform.Position.X = x+0.5;
      StageMeshTransform.Position.Z = z+0.5;
      StageMeshTransform.Rotation.X = value & 0x04 ? 0.5 : 0.0;
      StageMeshTransform.Rotation.Y = a*0.25;
      StageMeshTransform.Scale.X = 1;

      @MeshLoad(Mesh: ElbowMesh);
      @CallComponent(Component: StageMeshTransform);
      @MeshCombine();

      x += v[a,0];
      z += v[a,1];
      break;

    case 0x80: // X
      x = value & 0x3F;
      break;

    case 0xC0: // Z
      z = value & 0x3F;
      break;
  }
}

// Reset MeshTransform component

StageMeshTransform.Position.X = 0;
StageMeshTransform.Position.Z = 0;
StageMeshTransform.Rotation.X = 0;
StageMeshTransform.Rotation.Y = 0;
StageMeshTransform.Scale.X = 1;]]>
              </Expression>
            </ZExpression>
            <MeshTransform Name="StageMeshTransform"/>
          </Producers>
        </Mesh>
        <Material Name="StageMaterial"/>
      </Children>
    </Group>
    <Group Comment="Ghost">
      <Children>
        <Model Name="Ghost" Scale="0.0625 0.0625 0.0625">
          <Definitions>
            <Variable Name="GhostId" Type="4"/>
            <Variable Name="GhostColor" Type="7"/>
            <Variable Name="GhostTime"/>
            <Variable Name="GhostVector" Type="7"/>
          </Definitions>
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[// Set ghost color & initial time

switch(GhostId)
{
  case 0: GhostColor = vector3(1.0, 0.0, 0.0); break;
  case 1: GhostColor = vector3(1.0, 0.7, 0.9); break;
  case 2: GhostColor = vector3(0.0, 1.0, 0.9); break;
  case 3: GhostColor = vector3(1.0, 0.7, 0.3); break;
}

GhostTime = rnd()*4;]]>
              </Expression>
            </ZExpression>
          </OnSpawn>
          <OnUpdate>
            <ZExpression>
              <Expression>
<![CDATA[// Ghost movement

float t = frac(GhostTime);

switch(floor(GhostTime))
{
  case 0:
    Ghost.Position.X = t*10+3;
    Ghost.Position.Z = 3;
    GhostVector = vector3(4, 0, 0);
    break;

  case 1:
    Ghost.Position.X = 13;
    Ghost.Position.Z = t*10+3;
    GhostVector = vector3(0, 0, 4);
    break;

  case 2:
    Ghost.Position.X = (1-t)*10+3;
    Ghost.Position.Z = 13;
    GhostVector = vector3(-4, 0, 0);
    break;

  case 3:
    Ghost.Position.X = 3;
    Ghost.Position.Z = (1-t)*10+3;
    GhostVector = vector3(0, 0, -4);
    break;
}

GhostTime += 0.25*App.DeltaTime;
while(GhostTime >= 4)GhostTime -= 4;

// Always face camera*
// * Using RenderTransform instead of Model.Rotation
//   so the modelView matrix can be retrieved easily.

GhostTransform.Rotate.Y = -App.CameraRotation.Y;

// Animate ghost body

GhostBodyTile.TileIndex = frac(GhostTime*16)*2;]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
          <OnRender>
            <ZExpression>
              <Expression>
<![CDATA[// Calculate modelViewProjection matrix

mat4 mv, p, mvp;

getMatrix(0, mv);
getMatrix(1, p);

mvp = p*mv;

// Calculate screen-space coordinates
// for ghost origin and velocity vector

vec3 o, a, b;

o = vector3(0, 0, 0);

a = transformPoint(mvp, o);
b = transformPoint(mvp, GhostVector);

// Mirror eyes depending on screen-space direction

GhostEyesTile.MirrorHorizontal = a.x/a.z > b.x/b.z;]]>
              </Expression>
            </ZExpression>
            <UseMaterial Material="GhostMaterial"/>
            <Repeat Name="GhostRepeat" Count="2" WhileExp="//">
              <OnIteration>
                <ZExpression>
                  <Expression>
<![CDATA[//

if(GhostRepeat.Iteration)
{
  glCullFace(0x0405);

  GhostBodyColor.Color.R = GhostColor.R;
  GhostBodyColor.Color.G = GhostColor.G;
  GhostBodyColor.Color.B = GhostColor.B;

  GhostEyesColor.Color.R = 1;
  GhostEyesColor.Color.G = 1;
  GhostEyesColor.Color.B = 1;

  GhostTransform.Rotate.Y = 0;
}
else
{
  glCullFace(0x0404);

  GhostBodyColor.Color.R = GhostColor.R*0.25;
  GhostBodyColor.Color.G = GhostColor.G*0.25;
  GhostBodyColor.Color.B = GhostColor.B*0.25;

  GhostEyesColor.Color.R = 0.25;
  GhostEyesColor.Color.G = 0.25;
  GhostEyesColor.Color.B = 0.25;
}]]>
                  </Expression>
                </ZExpression>
                <RenderTransform Name="GhostTransform" Scale="1 -1 1"/>
                <RenderSetColor Name="GhostBodyColor" Color="1 0.7 0.3 1"/>
                <RenderTile Name="GhostBodyTile" TileSet="GhostTileSet" OriginX="8" OriginY="16"/>
                <RenderSetColor Name="GhostEyesColor" Color="1 1 1 1"/>
                <RenderTile Name="GhostEyesTile" TileSet="GhostTileSet" TileIndex="3" OriginX="8" OriginY="16"/>
              </OnIteration>
            </Repeat>
          </OnRender>
        </Model>
        <TileSet Name="GhostTileSet" Bitmap="GhostBitmap" TileWidth="16" TileHeight="16"/>
        <Bitmap Name="GhostBitmap" Height="16" Filter="1">
          <Producers>
            <BitmapFromFile Transparency="1" DataWidth="64" DataHeight="16">
              <BitmapFile>
<![CDATA[78DA636018F2E0FFFFFFC86C3817998D4719412E1DDC0FB1EE3F0C208B234BA189A3E9C2CAA59BFB8901E4A91F75FFA8FBA9E27E4C4182DE24460B7DDC0FE21A8210B2396822D81D0F56834B6418B89F482751A21E6BB94A30A710AF850EEEA75DFAA79BFB07B014A25CFD007A815AEAE9EF0B5AA81F05C80000D79158F3]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Material Name="GhostMaterial" Shading="1" Light="0"/>
      </Children>
    </Group>
  </Content>
</ZApplication>
jinxtengu wrote:
Thu Jan 24, 2019 2:20 am
Also any idea how a flat surface can be made to always face the camera?
As Ats mentioned, simply rotate your model so that's it facing the camera.

K

jinxtengu
Posts: 79
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Doom style 3d reduced to 2 directions

Post by jinxtengu » Sun Jan 27, 2019 3:01 am

Thanks for the replies folks. I actually haven't had time to try this and integrate the code thats been posted, it's been 46 degrees here (Australia, and no air con), and I take things a bit slowly in such heat. I would like to understand the maths if possible, so thanks for the link to the stack exchange page.

To give some context, and I know this sounds like a slightly unusual request, but what im using this for is gibs (splatter) among other things :)
When enemies get shot in my game, they shoot out meat or shrapnel. This meat is only a flat sprite (although it's actually a 3d cube just with 0 z axis), when it looks like it's moving to the left I want the sprite to animate rotating left (which requires this code to recognise how it's moving in realtion to the camera), and when moving to the right well it should rotate right. This effect is much simmilar to the bones in decap attack (if you see one enemy die you will see what I mean)(https://www.youtube.com/watch?v=efwF-zaynxQ). I hope this helps to understand why i need this. It seems like it would be not so hard to do, although I have tried to write my own code, but it hasn't worked so far. Anyway im just looking at the examples posted now. I'll post back when iv'e experimented enough to comment, whether Iv'e gotten things working or not.

also Im using an old version of z-game, so I often have to cull the code that gets posted just so it will run.

User avatar
Kjell
Posts: 1714
Joined: Sat Feb 23, 2008 11:15 pm

Re: Doom style 3d reduced to 2 directions

Post by Kjell » Sun Jan 27, 2019 9:38 pm

Hi jinxtengu,

Thanks for the clear explanation & Decap Attack reference, makes it much easier to give you useful suggestions :wink: In fact, you probably don't need any of the ( slightly ) complicated math used in the Pac-Man example. Setting the bone rotation direction once on spawn is probably enough. Below is a example ( use arrow keys to navigate ).

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Decap" CameraPosition="0 1 16" FileVersion="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <Source>
<![CDATA[//

void glAlphaFunc(int func, float val){}
void glEnable(int cap){}]]>
      </Source>
    </ZExternalLibrary>
    <ZExpression>
      <Expression>
<![CDATA[//

glAlphaFunc(0x0204, 0);
glEnable(0x0BC0);

//

createModel(Grid);

for(int i=0; i<16; i++)
{
  Enemy.Position.X = random(0, 8);
  Enemy.Position.Z = random(0, 8);

  createModel(Enemy);
}]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <Group Comment="Input">
      <Children>
        <Repeat Name="AxisRepeat" Count="2" WhileExp="//">
          <OnIteration>
            <ZExpression>
              <Expression>
<![CDATA[//

int i = AxisRepeat.Iteration;

//

Axis[i] = 0;

//

AxisPositive.CharCode = i ? 38 : 39;
AxisNegative.CharCode = i ? 40 : 37;]]>
              </Expression>
            </ZExpression>
            <KeyPress Name="AxisPositive" CharCode="38">
              <OnPressed>
                <ZExpression>
                  <Expression>
<![CDATA[//

Axis[AxisRepeat.Iteration]++;]]>
                  </Expression>
                </ZExpression>
              </OnPressed>
            </KeyPress>
            <KeyPress Name="AxisNegative" CharCode="40">
              <OnPressed>
                <ZExpression>
                  <Expression>
<![CDATA[//

Axis[AxisRepeat.Iteration]--;]]>
                  </Expression>
                </ZExpression>
              </OnPressed>
            </KeyPress>
          </OnIteration>
        </Repeat>
      </Children>
    </Group>
    <Group Comment="Camera">
      <Children>
        <ZExpression>
          <Expression>
<![CDATA[//

float t = App.DeltaTime;

App.CameraRotation.Y += Axis[0]*0.25*t;

float a = App.CameraRotation.Y*PI*2;

App.CameraPosition.X += Axis[1]*4*sin(a)*t;
App.CameraPosition.Z -= Axis[1]*4*cos(a)*t;]]>
          </Expression>
        </ZExpression>
      </Children>
    </Group>
  </OnUpdate>
  <Content>
    <Group Comment="Input">
      <Children>
        <Array Name="Axis" SizeDim1="2"/>
      </Children>
    </Group>
    <Group Comment="Grid">
      <Children>
        <Model Name="Grid">
          <OnRender>
            <UseMaterial Material="GridMaterial"/>
            <RenderMesh Mesh="GridMesh"/>
          </OnRender>
        </Model>
        <Mesh Name="GridMesh">
          <Producers>
            <MeshBox Grid2DOnly="255"/>
            <MeshExpression AutoNormals="0" HasTexCoords="255">
              <Expression>
<![CDATA[//

V.X =  V.X*16;
V.Z = -V.Y*16;
V.Y =       0;

TexCoord.X = V.X*0.25;
TexCoord.Y = V.Z*0.25;]]>
              </Expression>
            </MeshExpression>
          </Producers>
        </Mesh>
        <Bitmap Name="GridBitmap" Width="2" Height="2" Filter="1">
          <Producers>
            <BitmapExpression>
              <Expression>
<![CDATA[//

if(X+Y != 1)
{
  Pixel.R = 1;
  Pixel.G = 1;
}

Pixel.B = 1;
Pixel.A = 1;]]>
              </Expression>
            </BitmapExpression>
          </Producers>
        </Bitmap>
        <Material Name="GridMaterial" Shading="1" Light="0">
          <Textures>
            <MaterialTexture Texture="GridBitmap" TextureWrapMode="1" TexCoords="1"/>
          </Textures>
        </Material>
      </Children>
    </Group>
    <Group Comment="Bone">
      <Children>
        <Model Name="Bone" Velocity="0 8 0">
          <Definitions>
            <Variable Name="BoneSpin"/>
          </Definitions>
          <OnUpdate>
            <ZExpression>
              <Expression>
<![CDATA[//

if(Bone.Position.Y < -1)
{
  @RemoveModel();
}

//

Bone.Rotation.Y = -App.CameraRotation.Y;
Bone.Velocity.Y -= 16*App.DeltaTime;

//

BoneTransform.Rotate.Z += BoneSpin*App.DeltaTime;]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="BoneMaterial"/>
            <RenderTransform Name="BoneTransform"/>
            <RenderMesh Mesh="BoneMesh"/>
          </OnRender>
        </Model>
        <Mesh Name="BoneMesh">
          <Producers>
            <MeshBox Scale="0.5 0.5 0.5" Grid2DOnly="255"/>
          </Producers>
        </Mesh>
        <Bitmap Name="BoneBitmap" Width="16" Height="16" Filter="1">
          <Producers>
            <BitmapFromFile Transparency="2" HasAlphaLayer="1" DataWidth="16" DataHeight="16">
              <BitmapFile>
<![CDATA[78DAFBFFFF3FC3FF118E810044FC27473D884E4E4C066362CC40570FC22D4D2D700C13C385416A9E3F7E8EA216590C66362E0C5207C3C87E00619819F8304C1FB25E74794218DDAFC8FA08F91FD90C74FDC4863F2EFFD32ABD0C660C005480A10C]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Material Name="BoneMaterial" Shading="1" Light="0">
          <Textures>
            <MaterialTexture Texture="BoneBitmap" TexCoords="1"/>
          </Textures>
        </Material>
      </Children>
    </Group>
    <Group Comment="Enemy">
      <Children>
        <Model Name="Enemy" Scale="1.5 1.5 1.5">
          <Definitions>
            <Variable Name="EnemyTimer"/>
            <Variable Name="EnemyFrame"/>
          </Definitions>
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[//

EnemyFrame = rnd()*2;]]>
              </Expression>
            </ZExpression>
          </OnSpawn>
          <OnUpdate>
            <ZExpression>
              <Expression>
<![CDATA[//

Enemy.Rotation.Y = -App.CameraRotation.Y;

//

EnemyFrame += 15*App.DeltaTime;
while(EnemyFrame >= 2)EnemyFrame -= 2;

//

if(EnemyTimer)
{
  if(EnemyTimer > 9) // If timer has run out, spawn two bones & destroy enemy
  {
    float a = App.CameraRotation.Y*PI*2;

    Bone.Position.X = Enemy.Position.X;
    Bone.Position.Z = Enemy.Position.Z;

    BoneSpin = -2;
    Bone.Velocity.X = 4*cos(a);
    Bone.Velocity.Z = 4*sin(a);
    createModel(Bone);

    BoneSpin = 2;
    Bone.Velocity.X = -4*cos(a);
    Bone.Velocity.Z = -4*sin(a);
    createModel(Bone);

    @RemoveModel();
  }
  else // Update timer
  {
    float c = floor(frac(EnemyTimer)*2);

    EnemyColor.Color.G = c;
    EnemyColor.Color.B = c;

    EnemyTimer += 5*App.DeltaTime;
  }
}
else // Check if enemy is within range of camera, if-so start timer
{
  float x, z, s;

  x = App.CameraPosition.X-Enemy.Position.X;
  z = App.CameraPosition.Z-Enemy.Position.Z;

  if(sqrt(x*x+z*z) < 8)
  {
    EnemyTimer = 1;
  }
}]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="EnemyMaterial"/>
            <RenderSetColor Name="EnemyColor" Color="1 1 1 1"/>
            <RenderNet>
              <RenderVertexExpression>
<![CDATA[//

Vertex.Y += 0.5;
TexCoord.X += floor(EnemyFrame);]]>
              </RenderVertexExpression>
            </RenderNet>
          </OnRender>
        </Model>
        <Bitmap Name="EnemyBitmap" Width="48" Height="24" Filter="1">
          <Producers>
            <BitmapFromFile Transparency="2" HasAlphaLayer="1" DataWidth="48" DataHeight="24">
              <BitmapFile>
<![CDATA[78DAED96610E82300C8577945DC5A3106F62B89947F1478FA10CA976A5EBC6B445134C5E10D67E2D6F831142B887464DBF1036C46F550F1F73E02A6878AB1ACB7230DE83CFF3B4FB3DC7E751E3CEE3CA3D58F0B3B91B405684EA7CD27A9EFC791CF323C8A2AC486A92B1D927677EE689E641C93756475AD36EFC4FC4BCCABC37E4D33AE3657C899FD3EBC59E163E677BF1E1B6CCD1744C2C7EAEF2E36FF051C8E7D756CF588337D67C8BBDD49B0F1D4AFB0DFD8FFBCF6EFC348F1DECBDF93D355ABDF1E2D3752AF1A431CAADB13DF8BDCF5B2BD78BAFD5FC06CB9B5FF283BFBF513CBF1667E1F76AEF3F91EFF3423F526F2DB1F8ED9F6A78F44F7B937AACF94F73916FD9FFBFAFFF4387243D00330441BD]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Material Name="EnemyMaterial" Shading="1" Light="0">
          <Textures>
            <MaterialTexture Name="EnemyTexture" Texture="EnemyBitmap" TextureScale="0.5 1 1" TexCoords="1" Origin="0 0.5 0"/>
          </Textures>
        </Material>
      </Children>
    </Group>
  </Content>
</ZApplication>
K

jinxtengu
Posts: 79
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Doom style 3d reduced to 2 directions

Post by jinxtengu » Mon Jun 10, 2019 8:16 am

Any chance this could be simplified for use under version 1.9.9 of z game editor?

User avatar
Kjell
Posts: 1714
Joined: Sat Feb 23, 2008 11:15 pm

Re: Doom style 3d reduced to 2 directions

Post by Kjell » Mon Jun 10, 2019 1:20 pm

Hi jinxtengu,
jinxtengu wrote:
Mon Jun 10, 2019 8:16 am
Any chance this could be simplified for use under version 1.9.9 of z game editor?
Not sure if "simplified" is the correct word as 1.9.9 lacks a couple of features that actually make things easier, but sure .. here's a version for 1.9.9.

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Decap" CameraPosition="0 1 16">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <Source>
<![CDATA[//

void glAlphaFunc(int func, float val){}
void glEnable(int cap){}]]>
      </Source>
    </ZExternalLibrary>
    <ZExpression>
      <Expression>
<![CDATA[//

glAlphaFunc(0x0204, 0);
glEnable(0x0BC0);]]>
      </Expression>
    </ZExpression>
    <SpawnModel Model="Grid"/>
    <Repeat Count="16">
      <OnIteration>
        <ZExpression>
          <Expression>
<![CDATA[//

Enemy.Position.X = random(0, 8);
Enemy.Position.Z = random(0, 8);]]>
          </Expression>
        </ZExpression>
        <SpawnModel Model="Enemy"/>
      </OnIteration>
    </Repeat>
  </OnLoaded>
  <OnUpdate>
    <Group Comment="Input">
      <Children>
        <Repeat Name="AxisRepeat" Count="2">
          <OnIteration>
            <ZExpression>
              <Expression>
<![CDATA[//

int i = AxisRepeat.Iteration;

//

Axis[i] = 0;

//

AxisPositive.CharCode = i ? 38 : 39;
AxisNegative.CharCode = i ? 40 : 37;]]>
              </Expression>
            </ZExpression>
            <KeyPress Name="AxisPositive">
              <OnPressed>
                <ZExpression>
                  <Expression>
<![CDATA[//

Axis[AxisRepeat.Iteration]++;]]>
                  </Expression>
                </ZExpression>
              </OnPressed>
            </KeyPress>
            <KeyPress Name="AxisNegative">
              <OnPressed>
                <ZExpression>
                  <Expression>
<![CDATA[//

Axis[AxisRepeat.Iteration]--;]]>
                  </Expression>
                </ZExpression>
              </OnPressed>
            </KeyPress>
          </OnIteration>
        </Repeat>
      </Children>
    </Group>
    <Group Comment="Camera">
      <Children>
        <ZExpression>
          <Expression>
<![CDATA[//

float t = App.DeltaTime;

App.CameraRotation.Y += Axis[0]*0.25*t;

float a = App.CameraRotation.Y*PI*2;

App.CameraPosition.X += Axis[1]*4*sin(a)*t;
App.CameraPosition.Z -= Axis[1]*4*cos(a)*t;]]>
          </Expression>
        </ZExpression>
      </Children>
    </Group>
  </OnUpdate>
  <Content>
    <Group Comment="Input">
      <Children>
        <DefineArray Name="Axis" SizeDim1="2"/>
      </Children>
    </Group>
    <Group Comment="Grid">
      <Children>
        <Model Name="Grid">
          <OnRender>
            <UseMaterial Material="GridMaterial"/>
            <RenderMesh Mesh="GridMesh"/>
          </OnRender>
        </Model>
        <Mesh Name="GridMesh">
          <Producers>
            <MeshBox Grid2DOnly="255"/>
            <MeshExpression AutoNormals="0" HasTexCoords="255">
              <Expression>
<![CDATA[//

this.V.X = this.V.X* 16;
this.V.Z = this.V.Y*-16;
this.V.Y =            0;

//

this.TexCoord.X = this.V.X*0.25;
this.TexCoord.Y = this.V.Z*0.25;]]>
              </Expression>
            </MeshExpression>
          </Producers>
        </Mesh>
        <Bitmap Name="GridBitmap" Width="0" Height="0" Filter="1">
          <Producers>
            <BitmapExpression>
              <Expression>
<![CDATA[//

if(floor(this.X*2)+floor(this.Y*2) != 1)
{
  this.Pixel.R = 1;
  this.Pixel.G = 1;
}

this.Pixel.B = 1;
this.Pixel.A = 1;]]>
              </Expression>
            </BitmapExpression>
          </Producers>
        </Bitmap>
        <Material Name="GridMaterial" Shading="1" Light="0">
          <Textures>
            <MaterialTexture Texture="GridBitmap" TextureWrapMode="1" TexCoords="1"/>
          </Textures>
        </Material>
      </Children>
    </Group>
    <Group Comment="Bone">
      <Children>
        <Model Name="Bone" Velocity="0 8 0">
          <Definitions>
            <DefineVariable Name="BoneSpin"/>
          </Definitions>
          <OnRender>
            <UseMaterial Material="BoneMaterial"/>
            <RenderTransform Name="BoneTransform"/>
            <RenderMesh Mesh="BoneMesh"/>
          </OnRender>
          <OnUpdate>
            <Condition>
              <Expression>
<![CDATA[//

return Bone.Position.Y < -1;]]>
              </Expression>
              <OnTrue>
                <RemoveModel/>
              </OnTrue>
            </Condition>
            <ZExpression>
              <Expression>
<![CDATA[//

Bone.Rotation.Y = 0-App.CameraRotation.Y;
Bone.Velocity.Y -= 16*App.DeltaTime;

//

BoneTransform.Rotate.Z += BoneSpin*App.DeltaTime;]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
        </Model>
        <Mesh Name="BoneMesh">
          <Producers>
            <MeshBox Scale="0.5 0.5 0.5" Grid2DOnly="255"/>
          </Producers>
        </Mesh>
        <Bitmap Name="BoneBitmap" Width="0" Height="0" Filter="1">
          <Producers>
            <BitmapFromFile Transparency="2" HasAlphaLayer="1">
              <BitmapFile>
<![CDATA[78DAFBFFFF3FC3FF118E810044FC27473D884E4E4C066362CC40570FC22D4D2D700C13C385416A9E3F7E8EA216590C66362E0C5207C3C87E00619819F8304C1FB25E74794218DDAFC8FA08F91FD90C74FDC4863F2EFFD32ABD0C660C005480A10C]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Material Name="BoneMaterial" Shading="1" Light="0">
          <Textures>
            <MaterialTexture Texture="BoneBitmap" TexCoords="1"/>
          </Textures>
        </Material>
      </Children>
    </Group>
    <Group Comment="Enemy">
      <Children>
        <Model Name="Enemy">
          <Definitions>
            <DefineVariable Name="EnemyTimer"/>
            <DefineVariable Name="EnemyFrame"/>
          </Definitions>
          <OnRender>
            <UseMaterial Material="EnemyMaterial"/>
            <RenderSetColor Name="EnemyColor" Color="1 1 1 1"/>
            <RenderNet>
              <RenderVertexExpression>
<![CDATA[//

this.Vertex.Y += 0.5;

this.TexCoord.X = (this.TexCoord.X+floor(EnemyFrame))*0.375;
this.TexCoord.Y = this.TexCoord.Y*0.75;]]>
              </RenderVertexExpression>
            </RenderNet>
          </OnRender>
          <OnUpdate>
            <ZExpression>
              <Expression>
<![CDATA[//

Enemy.Rotation.Y = 0-App.CameraRotation.Y;

//

EnemyFrame += 15*App.DeltaTime;
while(EnemyFrame >= 2)EnemyFrame -= 2;]]>
              </Expression>
            </ZExpression>
            <Condition>
              <Expression>
<![CDATA[//

return EnemyTimer;]]>
              </Expression>
              <OnTrue>
                <Condition>
                  <Expression>
<![CDATA[//

return EnemyTimer > 9;]]>
                  </Expression>
                  <OnTrue>
                    <ZExpression>
                      <Expression>
<![CDATA[//

Bone.Position.X = Enemy.Position.X;
Bone.Position.Z = Enemy.Position.Z;

//

float a = App.CameraRotation.Y*PI*2;

BoneSpin = -2;
Bone.Velocity.X = 4*cos(a);
Bone.Velocity.Z = 4*sin(a);]]>
                      </Expression>
                    </ZExpression>
                    <SpawnModel Model="Bone"/>
                    <ZExpression>
                      <Expression>
<![CDATA[//

float a = App.CameraRotation.Y*PI*2;

BoneSpin = 2;
Bone.Velocity.X = -4*cos(a);
Bone.Velocity.Z = -4*sin(a);]]>
                      </Expression>
                    </ZExpression>
                    <SpawnModel Model="Bone"/>
                    <RemoveModel/>
                  </OnTrue>
                  <OnFalse>
                    <ZExpression>
                      <Expression>
<![CDATA[//

float c = floor(frac(EnemyTimer)*2);

EnemyColor.Color.G = c;
EnemyColor.Color.B = c;

EnemyTimer += 5*App.DeltaTime;]]>
                      </Expression>
                    </ZExpression>
                  </OnFalse>
                </Condition>
              </OnTrue>
              <OnFalse>
                <ZExpression>
                  <Expression>
<![CDATA[//

float x, z, s;

x = App.CameraPosition.X-Enemy.Position.X;
z = App.CameraPosition.Z-Enemy.Position.Z;

if(sqrt(x*x+z*z) < 8)
{
  EnemyTimer = 1;
}]]>
                  </Expression>
                </ZExpression>
              </OnFalse>
            </Condition>
          </OnUpdate>
          <OnSpawn>
            <ZExpression>
              <Expression>
<![CDATA[//

EnemyFrame = rnd()*2;]]>
              </Expression>
            </ZExpression>
          </OnSpawn>
        </Model>
        <Bitmap Name="EnemyBitmap" Height="1" Filter="1">
          <Producers>
            <BitmapFromFile Transparency="2" HasAlphaLayer="1">
              <BitmapFile>
<![CDATA[78DAED97FD1183200CC51985553A8AD74D7A6EE628FD83315A51D3E6620494C48F36BDFB9D55E1F91E4145E7DCCB15D2FF9C5BD17E2D5BF4639F5AA24EE8189A2FD81FDB96F4C1DEB4F5A5C72035DE773F6E53BE86F38931D0D0971A838126F0F8909D8FD82FF5A7AD5F9D1DAEEF030FF6E29167746EA853C7D75F53BF3A7B490D96EA467C72F7B4A6BE68FE1A48ADF6D297BC07DA47FB81EEE3E38B99267F47E88BBC039ED31CEBB7D10BDD4FFAF3F9FC9AFA52F901F0478FCD9E5185B5D1D61779F709AEE5F6D417A9FD06E27A05FF87F5CBDEFA62F9E33CDCE0AD38BF92FE1163B0B636DAFA92CF01CE0F770EFB2AF1A6AD7FD4F3F06CFA9A6372557DC9F900C7E9FB1BA0FD73EDCE58EFD9DAF586BECF17F270D94ADAC2B77FBCC615F2E36C5CC65CFD715FD03F73FE7FBFFF0DC3300CC3300CE3177803BB07B7D3]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Material Name="EnemyMaterial" Shading="1" Light="0">
          <Textures>
            <MaterialTexture Texture="EnemyBitmap" TexCoords="1"/>
          </Textures>
        </Material>
      </Children>
    </Group>
  </Content>
</ZApplication>
Please don't make me do this again though ... going back to 1.9.9 is rather painful :P

K

User avatar
VilleK
Site Admin
Posts: 2020
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Doom style 3d reduced to 2 directions

Post by VilleK » Mon Jun 10, 2019 2:13 pm

jinxtengu wrote:
Mon Jun 10, 2019 8:16 am
Any chance this could be simplified for use under version 1.9.9 of z game editor?
Is there a specific reason you are using this old version of ZGameEditor?

jinxtengu
Posts: 79
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Doom style 3d reduced to 2 directions

Post by jinxtengu » Tue Jun 11, 2019 5:10 am

VilleK wrote:
Mon Jun 10, 2019 2:13 pm
jinxtengu wrote:
Mon Jun 10, 2019 8:16 am
Any chance this could be simplified for use under version 1.9.9 of z game editor?
Is there a specific reason you are using this old version of ZGameEditor?
I've got a few games I've been working on and I'd like to complete them before upgrading. Iv'e tried upgrading them in the past to new er versions, but they end up very buggy and it would be more hassle fixing them than to just start a new game. I've also gotten kindof used to using the older version and it seems to run faster on the slow laptop that I have access to.

Also Thanks Kjell!!! this is very much appreciated. Sorry for the annoyance :D :D

Post Reply