Functions: break to maintain small size?
Yes! less than 1 page!
 38%  [ 5 ]
No. wasteful.
 61%  [ 8 ]
Total Votes : 13

Im msgs for aid on a new project... Kerm has been very generous in his help but i need more... Im programming a GBA game in C++... this is very simple and uses draw methods similar to the TI devices.

Everything is written in 2D... however, to draw in 3d, one must do a lot of math equations(hence games like Doom for the GBA) i need aid in programming in this language because i have not yet taken trig and wish to learn a bit now... if you want some source code, i would be more than happy to share(got it from a tutorial). There are 3 issues i want to adress about the application before i begin...

1) it is VERY slow... which needs to be sped up
2) i need it in 3rd person view... not 1st
3) i need to integrate sprites into the datastream(easy part)

this may be my project, but i am more than willing to add anyones names/nick who want to be added into a credits section...

this is the code for the game... the include files can be obtained seperately


Code:

//----------------------------------------------------------------
// includes
//----------------------------------------------------------------
#include "gba.h"
#include "keypad.h"
#include "screenmode.h"
#include "trig.h"
//#include "math.h"

//----------------------------------------------------------------
// constants and globals that are constant
//----------------------------------------------------------------
#define SCREENWIDTH   240
#define SCREENHEIGHT   160
#define GRIDWIDTH      64
#define GRIDHEIGHT      64
#define PLAY_LENGTH   (207.85)
#define W         1   // wall
#define O         0   // opening
#define PI         (3.14159)
#define SHORT_LINE      1200   // screenwidth/2 * 10
#define LONG_LINE      1800   // screenwidth/2 * 15
#define true      1
#define false      0

const u16 gPalette[] = { // 0..16                              
   0x7203,   0x7205,   0x7208,   0x720A,   0x720D,   0x720F,   0x7212,   0x7214,
   0x2945,   0x2946,   0x2948,   0x294A,   0x294C,   0x294E,   0x6B5A,   0x56B5,};

//----------------------------------------------------------------
// this is the map feel free to change/englarge/shrink it
//----------------------------------------------------------------
#define MAPWIDTH            16
#define MAPHEIGHT            16

const char fMap[]=
{//     0         5         10        15
  W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W, // 0
  W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,
  W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,
  W,O,O,O,O,O,O,O,O,O,O,W,O,O,O,W,
  W,O,O,O,O,O,W,O,W,O,O,W,O,O,O,W,
  W,O,O,O,O,O,W,O,W,W,O,W,O,O,O,W, // 5
  W,O,O,O,O,O,W,O,W,O,O,W,O,O,O,W,
  W,O,O,O,O,O,W,W,W,O,O,W,O,O,O,W,
  W,O,O,O,O,O,O,W,O,O,O,W,O,O,O,W,
  W,O,O,O,O,O,O,W,W,W,W,W,O,O,O,W,
  W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W, // 10
  W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,
  W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,
  W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,
  W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,
  W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W, // 15
};

//----------------------------------------------------------------
// global variables
//----------------------------------------------------------------

u32 nPlayerX;
u32 nPlayerY;
u32 nPlayerAngle;

int fKeyUp;      //bool fKeyUp=false;
int fKeyDown;   //bool fKeyDown=false;
int fKeyLeft;   //bool fKeyLeft=false;
int fKeyRight;   //bool fKeyRight=false;

u16* FrontBuffer = (u16*)0x6000000;
u16* BackBuffer = (u16*)0x600A000;
u16* videoBuffer;
u16* paletteMem = (u16*)0x5000000;   //PalMemory is 256 16 bit BGR values starting at 0x5000000

//----------------------------------------------------------------
// function prototypes
//----------------------------------------------------------------
void drawBackground(void);  // draw the background (ceiling and floor) basically clears screen.
void renderWalls();  // draw the walls (drawn on top of background)
void WaitForVsync(void);  // waits for the vsync
void updateKeyVars();  // checks KEYS register and updates our four globals bools
void Flip(void);  // switch witch buffer is being displayed
void move(int moveup);  // moves the character back/forward checks for collision
s32 absint(s32 d);  // returns absolute value of int
s32 distAngle(s32 s1, s32 s2);  // return positive distance between to angles

//----------------------------------------------------------------
// main --- gba entry point
//----------------------------------------------------------------

int main(int argc, char* argv[])
{
   char x;
   char changed = 0;

   SetMode(MODE_4 | BG2_ENABLE ); //set mode 4

   for(x = 0; x < 16; x++)   // palette
      paletteMem[x] = gPalette[x];   

   nPlayerX = 96;      // one and half squares in
   nPlayerY = 128;      // two squares down
   nPlayerAngle = 0;   // angled to the right

   Flip();
   drawBackground();
   renderWalls(); // draw to the screen
   Flip();

   while(true)
   {
      // process the movement
      if (fKeyLeft)
      {
         nPlayerAngle += 10;
         if (nPlayerAngle >= 360) nPlayerAngle = 0;
         changed = 1;
      }

      else if (fKeyRight)
      {
         if (nPlayerAngle < 10) nPlayerAngle = 350;
         else nPlayerAngle -= 10;
         changed = 1;
      }

      if (fKeyUp)
      {
         move(1); // checks for collisions before moving
         //nPlayerX += (u32) (10 * tableCOS[nPlayerAngle]);
         //nPlayerY -= (u32) (10 * tableSIN[nPlayerAngle]);
         changed = 1;
      }
      else if (fKeyDown)
      {
         move(0); // checks for collisions before moving
         //nPlayerX -= (u32) (10 * tableCOS[nPlayerAngle]);
         //nPlayerY += (u32) (10 * tableSIN[nPlayerAngle]);
         changed = 1;
      }


      if (changed) // only redraw if they push a key and change the screen
      {
         changed = 0;
         drawBackground(); // draw background
         renderWalls(); // draw to the screen
         WaitForVsync();
         Flip(); // flip it to screen
      }
      updateKeyVars();
   }

   return 0;
}

void move(int moveup) // check for collision detection and move our guy along
{
   double deltaX;
   double deltaY;
   if (moveup)
   {
      deltaX = (tableCOS[nPlayerAngle] * 15);
      deltaY = -1*(tableSIN[nPlayerAngle] * 15);
   }
   else
   {
      deltaX = -1*(tableCOS[nPlayerAngle] * 15);
      deltaY = (tableSIN[nPlayerAngle] * 15);
   }
   
   int newX = (int)(nPlayerX + deltaX + (8 * abs(deltaX) / deltaX));
   int newY = (int)(nPlayerY + deltaY + (8 * abs(deltaY) / deltaY));
   
   if (fMap[(newX/64) + MAPWIDTH * (newY/64)] == O) {
      nPlayerX += (int) deltaX;
      nPlayerY += (int) deltaY;
   } else if (fMap[(newX/64) + MAPWIDTH * (nPlayerY/64)] == O) {
      nPlayerX += (int) deltaX;
   } else if (fMap[(nPlayerX/64) + MAPWIDTH * (newY/64)] == O) {
      nPlayerY += (int) deltaY;
   }
}

void WaitForVsync(void)
{
   //lets get rid of htat inline asm we used in arm
   /*
      __asm
      {
         mov    r0, #0x4000006   //0x4000006 is vertical trace counter; when it hits 160                //160 the vblanc starts
         scanline_wait:             //the vertical blank period has begun. done in asm just
                           //because:)
         ldrh   r1, [r0]
         cmp   r1, #160
         bne    scanline_wait
      }         
   */
   while(REG_VCOUNT<160);
}

void updateKeyVars()
{
   //keypad register is a 16 bit register at 0x40000130;
   //key bits are cleared when a key is pressed. 
   //keys are defined in keypad.h
   fKeyUp = fKeyDown = fKeyLeft = fKeyRight = 0;

   if(!((*KEYS) & KEY_UP))
   {
      fKeyUp = 1;
   }
   if(!((*KEYS) & KEY_DOWN))
   {
      fKeyDown = 1;
   }
   if(!((*KEYS) & KEY_LEFT))
   {
      fKeyLeft=1;
   }
   if(!((*KEYS) & KEY_RIGHT))
   {
      fKeyRight=1;
   }
   /*if(!((*KEYS) & KEY_A))
   {
   }
   if(!((*KEYS) & KEY_B))
   {
   }
   if(!((*KEYS) & KEY_R))
   {
   }
   if(!((*KEYS) & KEY_L))
   {
   }*/
}

// draw the background, which ends up being the ceiling and floor
// the walls are drawn directly on top of this
void drawBackground(void)
{
   u16* destBuffer =videoBuffer;
   u8 loop;
   for (loop = 0; loop < 8; loop++)
   {
      u16 val = (loop << 8) + loop;
      u16* finalAdr=destBuffer+SHORT_LINE;
      while(destBuffer<finalAdr)
         *destBuffer++=val;
   }
   for (loop = 8; loop < 14; loop++)
   {
      u16 val = (loop<<8) + loop;
      u16* finalAdr=destBuffer+LONG_LINE;
      while(destBuffer<finalAdr)
         *destBuffer++=val;
   }
}


// below are two small helper functions used by renderWalls()
s32 absint(s32 d)
{
   if (d < 0) d *= -1;
   return d;
}

s32 distAngle(s32 s1, s32 s2)
{
   s32 temp;
   if (s2 >= s1)
      temp = s2 - s1;
   else
      temp = s1 - s2;
   if (temp > 30) temp -= 360;
   return absint(temp);
}

//----------------------------------------------------
// The coordinate system for this render method
//----------------------------------------------------
//                       90 deg, y--
//                           |
//                           |
//                 QUAD2     |     QUAD1
//                           |
//                           |
//                           |
// x--, 180 deg --------------------------- 0 deg, x++
//                           |
//                           |
//                 QUAD3     |     QUAD4
//                           |
//                           |
//                           |
//                      270 deg, y++
//----------------------------------------------------

// draw the walls
void renderWalls()
{
   u32      loop;      // loop over every fourth line for the screen 0, 4, 8, ... 236
   s16      curAngle;
   s32      gridX;      // grid coordinates for the map
   s32      gridY;      // grid coordinates for the map
   u16*   destBuffer = videoBuffer; // points to where we draw to
   u8      x,y;      //counters to loop through all x and y positions on the screen
   
   //double   radian;      // angle in radians
   double   horzLength; // length to wall along horizontal route
   double   vertLength; // length to wall along vertical route
   double*   minLength;   // pointer which will point to smaller of above two
   u32      lineLength;   // the length of the line we will draw to the screen

   char darkgray = 0;   // draw vertical as darkgray, and horzontal as lightgray

   double   fdistNextX; // the distance between each test coordinate .
   double   fdistNextY;
   int      ndistNextX;
   int      ndistNextY;

   int      horzY;      // the test coordinates of the vertical/horizonatal test
   double  horzX;
   int      vertX;
   double   vertY;

   curAngle = nPlayerAngle + 30;      // start left 30 degrees of playerAngle
   if (curAngle >= 360) curAngle -= 360;

   for (loop = 0; loop < SCREENWIDTH; loop+=4) // 4 = SCREENWIDTH / 64 (TILEHEIGHT)
   {
      // calculate the horizontal distance
      if (curAngle == 0 || curAngle == 180)
      {
         // there is no horizontal wall at this angle
         // so set the distance to something really large
         horzLength = 9999999.00;
      }
      else // check which direction ray is facing (up or down)
      {
         if (curAngle < 180) // facing up
         {
            horzY = (nPlayerY/64) * 64;
            ndistNextY = -64;
            double amountChange = ((s32) (horzY - nPlayerY) ) * tableINVTAN[curAngle];
            if (curAngle < 90 || curAngle > 270) // facing right
            {
               if (amountChange < 0) amountChange *= -1; // shoud be pos
            }
            else
            {
               if (amountChange > 0) amountChange *= -1; // should be neg
            }
            horzX = nPlayerX + amountChange;
            horzY--;
         }
         else // facing down
         {
            horzY = (nPlayerY/64) * 64 + 64;
            ndistNextY = 64;
            double amountChange = ((s32)(horzY - nPlayerY)) * tableINVTAN[curAngle];
            if (curAngle < 90 || curAngle > 270) // facing right
            {
               if (amountChange < 0) amountChange *= -1; // should be pos
            }
            else
            {
               if (amountChange > 0) amountChange *= -1; // should be neg
            }
            horzX = nPlayerX + amountChange;
         }
         fdistNextX = (64.00 * tableINVTAN[curAngle]);
         // at 90/270 the fdistNextX should get very small, should be zero
         if ( (curAngle < 90) || (curAngle>270) )
         {
            if (fdistNextX < 0) fdistNextX *= -1;      // positive distance to next block
         }
         else
         {
            if (fdistNextX > 0) fdistNextX *= -1;      // negative distance to next block
         }

         while (true)
         {
            gridX = (s32)(horzX / 64);
            gridY = (s32)(horzY / 64);
            if (gridX >= MAPWIDTH || gridY >= MAPHEIGHT || gridX < 0 || gridY < 0)
            {
               horzLength = 9999999.00;
               break;
            }
            else if (fMap[gridX+gridY*MAPHEIGHT])
            {
               horzLength = (horzX - nPlayerX) * tableINVCOS[curAngle];
               break;
            }
            horzX += fdistNextX;
            horzY += ndistNextY;
         }
      }
      // caclulate the vertical distance
      if (curAngle == 90 || curAngle == 270)
      {
         // there is no vertical wall at this angle
         // so set the distance to something really large
         vertLength = 9999999.00;
      }
      else // check which direction ray is facing left or right
      {
         if (curAngle < 90 || curAngle > 270) // facing right
         {
            vertX = (nPlayerX/64) * 64 + 64;
            ndistNextX = 64;
            double amountChange = tableTAN[curAngle]*((s32)(vertX-nPlayerX));
            if (curAngle < 180) // facing up
            {
               if (amountChange > 0) amountChange *= -1; // should be neg
            }
            else
            {
               if (amountChange < 0) amountChange *= -1; // should be pos
            }
            vertY = nPlayerY + amountChange;
         }
         else // facing left
         {
            vertX = (nPlayerX/64) * 64;
            ndistNextX = -64;         
            double amountChange = tableTAN[curAngle]*((s32)(vertX-nPlayerX));
            if (curAngle < 180) // facing up
            {
               if (amountChange > 0) amountChange *= -1; // should be neg
            }
            else
            {
               if (amountChange < 0) amountChange *= -1; // should be pos
            }
            vertY = nPlayerY + amountChange;
            vertX--;
         }
         fdistNextY = 64.00 * tableTAN[curAngle];
         if (curAngle < 180)
         {
            if (fdistNextY > 0) fdistNextY *= -1;   // make it negative (y--) for rays facing up
         }
         else
         {
            if (fdistNextY < 0) fdistNextY *= -1;   // make it positive (y++) for rays facing down
         }

         while (true)
         {
            gridX = (s32)(vertX / 64);
            gridY = (s32)(vertY / 64);
            if (gridX >= MAPWIDTH || gridY >= MAPHEIGHT || gridX < 0 || gridY < 0)
            {
               vertLength = 9999999.00;
               break;
            }
            else if (fMap[gridX+gridY*MAPHEIGHT])
            {
               vertLength = (vertY - nPlayerY) * tableINVSIN[curAngle];
               break;
            }
            vertX += ndistNextX;
            vertY += fdistNextY;
         }
      }

      // correct for negative values distance is always an absolute value
      if (vertLength < 0) vertLength *= -1;
      if (horzLength < 0) horzLength *= -1;

      // determine which is smaller
      if (vertLength < horzLength)
      {
         minLength = &vertLength;
         darkgray = 1;
      }
      else
      {
         darkgray = 0;
         minLength = &horzLength;
      }

      // fix the distortion
      (*minLength) = (*minLength) * tableCOS[distAngle(curAngle, nPlayerAngle)];

      // figure out how long line is
      lineLength = absint((s32)((64.00 / *minLength) * PLAY_LENGTH)   );

      // find where to start drawing the line
      int end = (80 - lineLength/2);
      int start;
      if (end < 0)
      {
         end = 160;
         start = 0;
      }
      else
      {
         start = end;
         end += lineLength;
      }

      // draw the line
      u32 where = loop/2 + start*120;
      if (darkgray)
      {
         for(y = start; y<end; y++)  //loop through all y
         {
               destBuffer[where] = 0x0f0f;
               destBuffer[where+1] = 0x0f0f;
               where += 120;
         }
      }
      else
      {
         for(y = start; y<end; y++)  //loop through all y
         {
               destBuffer[where] = 0x0e0e;
               destBuffer[where+1] = 0x0e0e;
               where += 120;
         }
      }

      curAngle -= 1; // change angle one degree to the right
      if (curAngle < 0) curAngle += 360;

   } // end for loop 0..240 by 4

} // end renderWalls

void Flip(void)         // flips between the back/front buffer
{
   if(REG_DISPCNT & BACKBUFFER) //back buffer is the current buffer so we need to switch it to the font buffer
   {
      REG_DISPCNT &= ~BACKBUFFER; //flip active buffer to front buffer by clearing back buffer bit
      videoBuffer = BackBuffer; //now we point our drawing buffer to the back buffer
    }
    else //front buffer is active so switch it to backbuffer
    {
      REG_DISPCNT |= BACKBUFFER; //flip active buffer to back buffer by setting back buffer bit
      videoBuffer = FrontBuffer; //now we point our drawing buffer to the front buffer
   }
}
[/b]
alright, just glancing over it, and a few things jump out

1) true and false are predifined, you do not need those 2 lines, as true will default to 1 and false to 0 automatically

2) the method with which you are moving the player is slow, not to mention your redraw.

This tut is for computer graphics, but a read through of the basics of raycasting and movement and you can probaly convert the code from his custom API to the GBA's one easy enough:

http://www.student.kuleuven.ac.be/~m0216922/CG/raycasting.html

Note: For his code example he free's up CPU time for other tasks - you can ignore this (for example, don't worry about SDL_Delay(5)Wink
That's an awesome article!
Ahhhh!!! You broke the rule of having methods that are longer than 1 page. Break it up into separate methods and I guarantee you will have an easier time.
Shock /me is lost. What be a method?
Methods = functions. They're called methods in Java.
Oh. Razz So why didn't you say "function"? Razz
Jonathan_Pezzino wrote:
Ahhhh!!! You broke the rule of having methods that are longer than 1 page. Break it up into separate methods and I guarantee you will have an easier time.


thats not a rule in C++ Laughing (or even a common guideline) - but it does make it easier
Kllrnohj wrote:
Jonathan_Pezzino wrote:
Ahhhh!!! You broke the rule of having methods that are longer than 1 page. Break it up into separate methods and I guarantee you will have an easier time.


thats not a rule in C++ Laughing (or even a common guideline) - but it does make it easier


Yeah, I've never heard that one before. Sounds like a good idea though!
KermMartian wrote:
Yeah, I've never heard that one before. Sounds like a good idea though!


not so much. If you focus on cutting up a function because of its length and not based on pieces of repeated code, then it makes the program bloated and slower, jumping to function calls when they aren't really needed. Its also reverse-intuitive, as if a function isn't obvious enough to warant a function, and was made based on length, it can rapidly become hard to remember what the hell the function did, and then you have to keep jumping back and forth....

stupid java programmers and their crappy language Evil or Very Mad Rolling Eyes Razz (thats a JOKE jpez Cool - sorta Very Happy )
Laughing Good point though about the function length.
Kllrnohj wrote:
KermMartian wrote:
Yeah, I've never heard that one before. Sounds like a good idea though!


not so much. If you focus on cutting up a function because of its length and not based on pieces of repeated code, then it makes the program bloated and slower, jumping to function calls when they aren't really needed. Its also reverse-intuitive, as if a function isn't obvious enough to warant a function, and was made based on length, it can rapidly become hard to remember what the hell the function did, and then you have to keep jumping back and forth....

stupid java programmers and their crappy language Evil or Very Mad Rolling Eyes Razz (thats a JOKE jpez Cool - sorta Very Happy )
Meh, it's still much much easier to read even if you are cutting it up only based on length. And that IS a common guideline. Razz
Jonathan_Pezzino wrote:
Meh, it's still much much easier to read even if you are cutting it up only based on length. And that IS a common guideline. Razz


functions should do one thing - irrelevent of length Wink
You might want to check this out if you haven't already Komak57:
http://www.devrs.com/gba/
Oh, that looks like a helpful site for what he's working on...
Kllrnohj wrote:
Jonathan_Pezzino wrote:
Meh, it's still much much easier to read even if you are cutting it up only based on length. And that IS a common guideline. Razz


functions should do one thing - irrelevent of length Wink
That's true, but it's a lot easier to wade through code that has short quick functions whose names are descriptive of what they do than long functions that are difficult to interpret.
cf. Poll added to first post.
Bad Idea
Splitting would make the code a little more comprehensible. Then again, if you split it, you'd have to restructure the entire render function and do some variable swapping, which in the end, would slow down your proggy even more. I wouldn't split it.

Exclamation Disregard my vote for yes. I should have picked the code apart before I voted. Of all my years of programming, skimming has never done me any good. lol Yup, this further proves that I am an idiot.
Hehe, don't worry about it, we all skim sometimes. Smile
I'm going through the render function right now: I'm gonna try to rewrite it to speed it up some.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 4
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement