Solved

Direct Draw, Movement problem.

Posted on 2004-09-10
5
591 Views
Last Modified: 2013-12-04
Hi i'm currently programming a small game (similar to radian 2). and have come across a small problem with moving the ship.

1. I can't move the ship North-west while shooting.
2. I can't move the ship south-west while shooting.

The keys i have used for moving are:

Forward    - W
backward  - S
Left          - A
Right        - D
Shoot      - Space.

I can move forward,backward,left,right,north-east & south east without any problems.

I have tried other keys for shoot, e.g. i tried F1 for shoot and the ship moves in all directions with no problems.

Can someone please tell me why i'm having this problem.

Note: If you see any problems with my code, e.g. style or bad programming practises please let me know =)
Also the way i've gotten the ship to shoot is probably pretty crude :) (didn't put much thought into it, Just wanted to check ways in which i could get the ship to shoot).

#include<stdlib.h>
#include<windows.h>
#include<ddraw.h>
#include<stdio.h>
#include<conio.h>

#define WIN32_LEAN_AND_MEAN
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480    
#define BPP 16               //bits per pixel

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

#define DDRAW_INIT_STRUCT(ddstruct) {memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize = sizeof(ddstruct);}

#define _RGB16BIT565(r,g,b) ((b & 31) + ((g & 63) << 5) + ((r & 31) << 11))

#define MAX_BULLET 15

#define LEFT      0x41
#define RIGHT      0x44
#define UP            0x57
#define DOWN      0x53
#define SHOOT      0x20

HWND Global_hWnd;

LPDIRECTDRAW                  Lpdd = NULL;
LPDIRECTDRAW7                  Lpdd7 = NULL;
PALETTEENTRY                  Palette[256];
LPDIRECTDRAWPALETTE            LpddPalette;
DDSURFACEDESC2                  ddsd;
LPDIRECTDRAWSURFACE7      LpddsPrimary;
LPDIRECTDRAWSURFACE7      LpddsBack;
DDPIXELFORMAT                  ddpixel;

void ShootLeftBullet(int,int,int);
void ShootRightBullet(int,int,int);
void ShootMiddleBullet(int,int,int);

int Window_Closed      = 0;

RECT rMovement;
RECT rLeftBullet[16];
RECT rRightBullet[16];
RECT rMiddleBullet[16];

int MovementXposition = 310;
int MovementYposition = 420;
int BulletVelocity        = 5;
int RateOfFire;
int BulletNumber;

LRESULT CALLBACK WinProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
{
      PAINTSTRUCT pS;
      HDC                  hDc;

      switch(Msg)
      {                              
      case WM_CREATE:
                              break;
                                          
      case WM_PAINT:
                              hDc = BeginPaint(hWnd,&pS);

                              EndPaint(hWnd,&pS);
                              break;
      case WM_DESTROY:
                              PostQuitMessage(0);
                              break;                               
      }
      return DefWindowProc(hWnd,Msg,wParam,lParam);
}

int Game_Main(void *parms = NULL, int num_parms = 0)
{
      DDBLTFX ddbltfx;   //Used for the bliter
      
      if(Window_Closed)
            return(0);

      if(KEYDOWN(VK_ESCAPE))
      {
            PostMessage(Global_hWnd,WM_CLOSE,0,0);
            Window_Closed = 1;
      }

      //Lock the back buffer Note: this is done so you can write to the back buffer.
      LpddsBack->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);

      UCHAR *Buffer = (UCHAR*)ddsd.lpSurface;

      DDRAW_INIT_STRUCT(ddbltfx);
      
      if(ddsd.lPitch == WINDOW_WIDTH)
      {
            memset(Buffer,0,640*2*480);
      }
      else
      {
            UCHAR* Buffer2 = Buffer;

            for(int Count = 0; Count<WINDOW_HEIGHT;Count++)
            {
                  memset(Buffer2,0,WINDOW_WIDTH*2);
                  Buffer2+=ddsd.lPitch;
            }
      }

      LpddsBack->Unlock(NULL);

      rMovement.left      = MovementXposition;
      rMovement.right      = MovementXposition+20;
      rMovement.top      = MovementYposition;
      rMovement.bottom= MovementYposition+50;

      ddbltfx.dwFillColor = _RGB16BIT565(255,255,255);
      LpddsBack->Blt(&rMovement,
                              NULL,
                              NULL,
                              DDBLT_COLORFILL | DDBLT_WAIT,
                              &ddbltfx);

      ddbltfx.dwFillColor = _RGB16BIT565(255,0,0);
      for(int count = 0; count<MAX_BULLET;count++)
      {

      LpddsBack->Blt(&rLeftBullet[count],
                              NULL,
                              NULL,
                              DDBLT_COLORFILL | DDBLT_WAIT,
                              &ddbltfx);

      LpddsBack->Blt(&rRightBullet[count],
                              NULL,
                              NULL,
                              DDBLT_COLORFILL | DDBLT_WAIT,
                              &ddbltfx);

      LpddsBack->Blt(&rMiddleBullet[count],
                              NULL,
                              NULL,
                              DDBLT_COLORFILL | DDBLT_WAIT,
                              &ddbltfx);
      }
      
      LpddsPrimary->Flip(NULL,DDFLIP_WAIT);

      if(KEYDOWN(LEFT))
      {
            if(MovementXposition>4)
            {
                  MovementXposition-=4;
            }
      }
      if(KEYDOWN(RIGHT))
      {
            if(MovementXposition<615)
            {
                  MovementXposition+=4;
            }
      }
      if(KEYDOWN(UP))
      {
            if(MovementYposition>2)
            {
                  MovementYposition-=4;
            }
      }
      if(KEYDOWN(DOWN))
      {
            if(MovementYposition<425)
            {
                  MovementYposition+=4;
            }
      }

      if(RateOfFire>=10)
      {
            if(KEYDOWN(SHOOT))
            {
                  ShootLeftBullet(MovementXposition,MovementYposition,BulletNumber);
                  ShootRightBullet(MovementXposition,MovementYposition,BulletNumber);
                  ShootMiddleBullet(MovementXposition,MovementYposition,BulletNumber);

                  RateOfFire=0;
                  if(BulletNumber<MAX_BULLET)
                  {
                        BulletNumber++;
                  }
                  else
                  {
                        BulletNumber=0;
                  }
            }
      }
      
      for(int Count1=0;Count1<MAX_BULLET;Count1++)
      {
            if(rLeftBullet[Count1].top>0)
            {
                  rLeftBullet[Count1].top-=8;
                  rLeftBullet[Count1].bottom-=8;

                  rRightBullet[Count1].top-=8;
                  rRightBullet[Count1].bottom-=8;

                  rMiddleBullet[Count1].top-=8;
                  rMiddleBullet[Count1].bottom-=8;
            }
            else
            {
                  rLeftBullet[Count1].top                  = 0;
                  rLeftBullet[Count1].bottom            = 0;

                  rRightBullet[Count1].top            = 0;
                  rRightBullet[Count1].bottom            = 0;
                  
                  rMiddleBullet[Count1].top            = 0;
                  rMiddleBullet[Count1].bottom      = 0;
            }
      }

      RateOfFire++;

      Sleep(10);

      return(1);
}

void ShootLeftBullet(int Xpos,int Ypos,int BulletNumber)
{
      rLeftBullet[BulletNumber].left            = Xpos;
      rLeftBullet[BulletNumber].right            = Xpos+1;
      rLeftBullet[BulletNumber].top            = Ypos;
      rLeftBullet[BulletNumber].bottom      = Ypos+10;
}

void ShootRightBullet(int Xpos,int Ypos,int BulletNumber)
{
      rRightBullet[BulletNumber].left            = Xpos+19;
      rRightBullet[BulletNumber].right      = Xpos+20;
      rRightBullet[BulletNumber].top            = Ypos;
      rRightBullet[BulletNumber].bottom      = Ypos+10;
}

void ShootMiddleBullet(int Xpos,int Ypos,int BulletNumber)
{
      rMiddleBullet[BulletNumber].left      = Xpos+9;
      rMiddleBullet[BulletNumber].right      = Xpos+11;
      rMiddleBullet[BulletNumber].top            = Ypos;
      rMiddleBullet[BulletNumber].bottom      = Ypos+10;
}

int Game_Init(void *parms = NULL, int num_parms = 0)
{
      srand(GetTickCount());

      ShowCursor(false);

      if(FAILED(DirectDrawCreate(NULL,&Lpdd,NULL)))
      {
            return(0);
      }


      if(FAILED(Lpdd->QueryInterface(IID_IDirectDraw7,(LPVOID*)&Lpdd7)))
      {
            return(0);
      }

      Lpdd->Release();
      Lpdd = NULL;

      if(FAILED(Lpdd7->SetCooperativeLevel(Global_hWnd,
                                   DDSCL_FULLSCREEN |
                                             DDSCL_EXCLUSIVE |
                                             DDSCL_ALLOWREBOOT|
                                             DDSCL_ALLOWMODEX)))/*Note: i don't think that it is required
                                                                            to addd DDSCL_ALLOWMODEX, as this only allows
                                                                              you to use 320*240, & no one uses this....*/
      {
            return(0);
      }

      Lpdd7->SetDisplayMode(WINDOW_WIDTH,WINDOW_HEIGHT,BPP,0,0);

      DDRAW_INIT_STRUCT(ddsd);

      ddsd.dwFlags      = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

      ddsd.dwBackBufferCount = 1;

      ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |DDSCAPS_COMPLEX;

      if(FAILED(Lpdd7->CreateSurface(&ddsd,&LpddsPrimary,NULL)))
      {
            return(0);
      }

      ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;

      LpddsPrimary->GetAttachedSurface(&ddsd.ddsCaps,&LpddsBack);
      
      return(1);
}


int Game_Shutdown(void *parms = NULL, int num_parms = 0)
{
      if(LpddsPrimary)
      {
            LpddsPrimary->Release();
            LpddsPrimary = NULL;
      }

      if(LpddPalette)
      {
            LpddPalette->Release();
            LpddPalette = NULL;
      }

      if(Lpdd7)
      {
            Lpdd7->Release();
            Lpdd7 = NULL;
      }
      return(1);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
      WNDCLASSEX WndClass;
      HWND hWnd;
      MSG Msg;

      WndClass.cbSize                  = sizeof(WNDCLASSEX);
      WndClass.hbrBackground      = (HBRUSH)GetStockObject(BLACK_BRUSH);
      WndClass.hCursor            = LoadCursor(NULL,IDC_ARROW);
      WndClass.hIcon                  = LoadIcon(NULL,IDI_ERROR);
      WndClass.hIconSm            = LoadIcon(NULL,IDI_ERROR);
      WndClass.cbClsExtra            = 0;
      WndClass.cbWndExtra            = 0;
      WndClass.hInstance            = hInstance;
      WndClass.lpszMenuName      = NULL;
      WndClass.lpszClassName      = "Class1";
      WndClass.lpfnWndProc      = WinProc;
      WndClass.style                  = CS_DBLCLKS | CS_VREDRAW |
                                  CS_HREDRAW | CS_OWNDC;

      if(!RegisterClassEx(&WndClass))
      {
            MessageBox(NULL,"Could not Register Class.","Error",MB_OK |MB_ICONERROR);
            return(-1);
      }

      /*This will create the window, and defines window properties*/
      if(!(hWnd = CreateWindowEx(NULL,
                             "Class1",
                                     "Practise Window",
                                     WS_POPUP | WS_VISIBLE,
                             350,
                                     150,
                                     WINDOW_WIDTH,
                                     WINDOW_HEIGHT,
                                     NULL,
                                     NULL,
                                 hInstance,
                                     NULL)))
      {
            MessageBox(NULL,"Could not Create Window.","Error",MB_OK|MB_ICONERROR);
      }

      Global_hWnd = hWnd;

      Game_Init();
      
      while(1)
      {
            if(PeekMessage(&Msg,NULL,0,0,PM_REMOVE))
            {
                  if(Msg.message==WM_QUIT)
                  {      
                        break;
                  }
                  TranslateMessage(&Msg);
                  DispatchMessage(&Msg);      
            }

            Game_Main();

      }
      Game_Shutdown();

      return Msg.wParam;
}







0
Comment
Question by:cpu4ghz
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
5 Comments
 
LVL 17

Accepted Solution

by:
davebytes earned 100 total points
ID: 12047276
Simplest answer: there are certain bits used to store current keyboard state, and you can't always rely on getasync to get you the 'real' state when you have more than two keys held at once -- or at least, my brain is recalling that to be the issue.

Have you tried switching to directinput instead?  Or use WM_KEYZZZ messages, and track the keyboard state yourself.  I believe the higher-level systems all have 'work arounds', though I can't recall offhand.

-d
0
 
LVL 2

Assisted Solution

by:cmreichl
cmreichl earned 100 total points
ID: 12084463
Most games will not continuely poll a state, they create 2 event triggers for each key they are using.

Key up and key down...  This way you use flags to set forward movement to true if the corrisponding key is pressed, and forward movement false when the key up event is processed.  Much more efficient and clean method for handling keyboard events.

-Chris
0
 
LVL 3

Assisted Solution

by:str_ek
str_ek earned 100 total points
ID: 12088824
well if you wanna stick to try GetKeyboardState... it's better than pooling buch of getasyncs, nad you only trace what you want ;)

and bout the blockin... havent tried to compile your code.. yet... 'cos there is one other reason that sort of thing happens, and it's the idea some keabords are build on... internal sturcture has nothing in common with the serial transmision standard, or kb protocl...there is microchip that handles the interfaceing...

in most office style keybord there is tendency to design them with assumption that they are to be used for typing, and typing is pressing only one key at once (most, special keys are considered as separate lines), so they design the layout so that a keay  X generates something like 1001000 (internal signal - remember the interface chip reinterprets it!) and key Y 1011000, so pressed together gives the same feedback like Y only.... you may ask and what if Z and W together gives i.e. C , but it's no prob, cos reduceing direct lines by paring keys is already 1/2 of costs! they dont push it to far, and you may design a codepattern that complays theoty ...

there is one other method of keybord-makeing based on like' coordinates system... you get keys set to 0 ( low voltge for logical 0) , nad colums, nad rows to 1 (high volt.) and to microprocessor directly, and when the key is presed it touches the corsing of one of col/row makeing current to sink directly and forcing a 0 logical state on micreoprocessor input, and from the coordinates it decodest the key and generates special seialport (ie ps2) message
thsi way you need only 2*X^(1/2) (square root) lines to code X keys... it's realy widely spread technology, and makes a little problem when ther are presed multiple keys that uses the same lines,
i.e.
   1   1   0
   |   |   |
-----------  1
   |   |   |
-----------   1
   |   |   |
-----------   0
   |   |   |

may be

  1   1   0
   |   |   |
--X--X----  1
   |   |   |
--X-------   1
   |   |   |
-----------   0
   |   |   |

or

  1   1   0
   |   |   |
--X-------  1
   |   |   |
--X--X----   1
   |   |   |
-----------   0
   |   |   |

or
  1   1   0
   |   |   |
---X--X----  1
   |   |   |
------X----   1
   |   |   |
-----------   0
   |   |   |

etc.....

so ther are combinations that are underminable.... but cos of it adventage (witch is double root of lines needed to code the keys) you can actulay code 256 kays with only 32 lines!!! and the price difference between microcontrolers with 32 and with 256 input lines are huge!

anyway...

chech the high-level fuctions, winapi is treacherus, and lieks to teas people... ;) and if it dosnt help jsut dont worry it's you're keybord :) check another brand and price-level for other pattern of cols and rows ;)
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

What is RenderMan: RenderMan is a not any particular piece of software. RenderMan is an industry standard, defining set of rules that any rendering software should use, to be RenderMan-compliant. Pixar's RenderMan is a flagship implementation of …
Recently, in one of the tech-blogs I usually read, I saw a post about the best-selling video games through history. The first place in the list is for the classic, extremely addictive Tetris. Well, a long time ago, in a galaxy far far away, I was…
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…

615 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question