I am wondering why the right hand side of my split screen isn't in the middle and also why the game goes off of the background, any help would be much appreciated

#include "SDL.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

#pragma comment(lib,"Winmm.lib")


/* ---------------------------------------------------------------------- */
/* Defines/Enumerations                                                   */
/* ---------------------------------------------------------------------- */

#define SPEED 2
#define GAMETIME 30  //inactivity for 30s quits game

/* ---------------------------------------------------------------------- */
/* Type Declarations                                                      */
/* ---------------------------------------------------------------------- */

struct PLAYER
{
  //SDL_Rect pos;
  SDL_Surface *sprite;
  Sint32 dir;
  Sint32 life;
  Sint32 score;
  float by;
  float bx;
  float pos_y;
  float pos_x;
  bool up, right, left, down;
  bool w, s, a, d; 

};

struct BALL
{
  //SDL_Rect pos;
  SDL_Surface *sprite;
  float bx, by;
  float pos_x, pos_y;

};

/* ---------------------------------------------------------------------- */
/* Global Data                                                            */
/* ---------------------------------------------------------------------- */

/// The start time
SDL_Surface *SCREEN;

/// Some Sprites
SDL_Surface *background, *intro, *numbers;

PLAYER playerA, playerB;
BALL ball;

SDL_Joystick *joy0;
Uint32 iTicksLastKey=0;  //inactivity counter
Uint32 TicksElapsed=0; //ticks elapsed since last update
Sint16 iMoveX;
Sint16 iMoveY;
Sint16 iMoveXOld;  //for comparing the last value
Sint16 iMoveYOld;
float ballspeed=85; //ball speed, number of pixels ball travels in one second
SDL_Surface *level;

/* ---------------------------------------------------------------------- */
/* Helper                                                                 */
/* ---------------------------------------------------------------------- */

void go();

/// Handle events
bool handleEvents()
{
  SDL_Event event;
 
    while (SDL_PollEvent(&event))
    {
    switch(event.type)
        {
            case SDL_KEYDOWN:
            {
                switch(event.key.keysym.sym)
                {
                    case SDLK_UP:   { playerB.up = true; break; }
                    case SDLK_DOWN: { playerB.down =  true; break; }
                    case SDLK_LEFT: { playerB.left =  true; break; }
                    case SDLK_RIGHT: { playerB.right =  true; break; }
                    case SDLK_w:    { playerA.w = true; break; }
                    case SDLK_s:    { playerA.s =  true; break; }
                    case SDLK_a:    { playerA.a = true; break; }
                    case SDLK_d:    { playerA.d =  true; break; }
                    case SDLK_SPACE:
                    {
                        if (ball.bx == 0 && ball.by == 0)
                        {
                            go();
                            playerA.life = 3;
                            playerB.life = 3;
                            playerA.score = 0;
                            playerB.score = 0;
                        }
                    }
                    break;
                    case SDLK_ESCAPE: { return false; } // quits
                    default: { break; }
                }
            }
            break;
            case SDL_KEYUP:
            {
                    iTicksLastKey=SDL_GetTicks();  //remember the time of last key release
                    switch(event.key.keysym.sym)
                    {
                    case SDLK_UP:   { playerB.up = false; break; }
                    case SDLK_DOWN: { playerB.down =  false; break; }
                    case SDLK_LEFT: { playerB.left =  false; break; }
                    case SDLK_RIGHT: { playerB.right =  false; break; }
                    case SDLK_w:    { playerA.w = false; break; }
                    case SDLK_s:    { playerA.s =  false; break; }
                    case SDLK_a:    { playerA.a = false; break; }
                    case SDLK_d:    { playerA.d =  false; break; }
                     { playerA.dir = 0; break; }
                    default: { break; }
                    }
            }
            break;
            case SDL_QUIT: { return false; }
            default: { break; }
        }
    }
    return true;
}

/// Draws the score and life status
void overlay()
{
  char buffer[16];
  SDL_Rect dst, src;
  Sint32 i;

  src.y = 0; src.w = 12; src.h = 14;
  dst.y = 0; dst.w = 12; dst.h = 14;

  sprintf(buffer, "%04d", playerA.score);
  for(i=0; buffer[i]; i++)
    {
    src.x = ((Sint32) buffer[i] - (Sint32) '0') * 12;
    dst.x = i * 12;
    SDL_BlitSurface(numbers, &src, SCREEN, &dst);
  }

  sprintf(buffer, "%04d", playerB.score);
  for(i=0; buffer[i]; i++)
    {
    src.x = ((Sint32) buffer[i] - (Sint32) '0') * 12;
    dst.x = 320 - (4-i) * 12;
    SDL_BlitSurface(numbers, &src, SCREEN, &dst);
  }

  dst.y = 0; dst.w = (ball.sprite)->w; dst.h = (ball.sprite)->h;
  for(i=0; i<playerA.life; i++)
    {
    dst.x = 50 + i * (dst.w + 2);
    SDL_BlitSurface(ball.sprite, NULL, SCREEN, &dst);
  }

  for(i=0; i<playerB.life; i++)
    {
    dst.x = 270 - (3-i) * (dst.w + 2);
    SDL_BlitSurface(ball.sprite, NULL, SCREEN, &dst);
  }
}

void go()
{
    ball.bx = 0;
    while (ball.bx == 0) ball.bx = (rand() % 3) - 1;
    ball.by = (rand() % 3) - 1;
ball.bx=1;
ball.by=1;
    (ball.pos_x) = 160-(ball.sprite)->w/2;
    (ball.pos_y) = 120-(ball.sprite)->h/2;
    TicksElapsed=SDL_GetTicks();
}

//rounds a float to an int
int iRound(float f)
{
    return int(f + 0.5);
}

/* ---------------------------------------------------------------------- */
/* Main Program                                                           */
/* ---------------------------------------------------------------------- */
int main(int argc, char *argv[])
{
 
	PlaySound("cirque.wav",NULL,SND_FILENAME|SND_ASYNC | SND_LOOP);

  Sint32 delta;
 
  // --------------------------------------------------
  // SDL initialisation
  // --------------------------------------------------
  if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK) < 0)
    {
    printf("Couldn't initialize SDL: %s\n", SDL_GetError());
    return -1;
  }

  SCREEN = SDL_SetVideoMode(320, 240, 24, SDL_DOUBLEBUF /*|SDL_FULLSCREEN*/);
  if (!SCREEN)
    {
    printf("Couldn't set 320x240, 24bit video mode: %s\n", SDL_GetError());
    return -2;
  }

  SDL_WM_SetCaption("Pony Pong", "Pony Pong");
  SDL_EnableKeyRepeat(10, SDL_DEFAULT_REPEAT_INTERVAL);
  SDL_ShowCursor(0);

  // --------------------------------------------------
  // Game initialisation
  // --------------------------------------------------
 
  srand(12345);
  playerA.sprite = SDL_LoadBMP("player1.bmp");
    SDL_SetColorKey(playerA.sprite, SDL_SRCCOLORKEY, 0x000000);  //makes black transparent
  playerB.sprite = SDL_LoadBMP("player2.bmp");
    SDL_SetColorKey(playerB.sprite, SDL_SRCCOLORKEY, 0x000000);  //makes black transparent
  ball.sprite = SDL_LoadBMP("ball.bmp");
    SDL_SetColorKey(ball.sprite, SDL_SRCCOLORKEY, 0x000000);  //makes black transparent

  background = SDL_LoadBMP("background.bmp");
  level = SDL_LoadBMP("level.bmp");
  intro = SDL_LoadBMP("intro.bmp");
  numbers = SDL_LoadBMP("numbers.bmp");

    //Check for joysticks:
    int num_joy;
    num_joy=SDL_NumJoysticks();
    printf("%d joysticks found\n", num_joy);
    for (int i=0;i<num_joy;i++) { printf("  %s\n", SDL_JoystickName(i)); }

    if (SDL_NumJoysticks()>0) joy0=SDL_JoystickOpen(0);
    if (joy0)
    {
        printf("Opened Joystick 0\n");
        printf("  Name: %s\n", SDL_JoystickName(0));
        printf("  Number of Axes: %d\n", SDL_JoystickNumAxes(joy0));
        printf("  Number of Buttons: %d\n", SDL_JoystickNumButtons(joy0));
        printf("  Number of Balls: %d\n", SDL_JoystickNumBalls(joy0));
    }
    else { printf("Couldn't open Joystick 0\n"); }

  (playerA.pos_x) = 8;
    (playerA.pos_y) = 120-((playerA.sprite)->h/2);
  //(playerA.pos).w = (playerA.sprite)->w;
    //(playerA.pos).h = (playerA.sprite)->h;

  (playerB.pos_x) = 312-((playerB.sprite)->w);
    (playerB.pos_y) = 120-((playerB.sprite)->h/2);
//  (playerB.pos).w = (playerB.sprite)->w;
//    (playerB.pos).h = (playerB.sprite)->h;

  (ball.pos_x) = 160-(ball.sprite)->w/2;
    (ball.pos_y) = 120-(ball.sprite)->h/2;
  //(ball.pos).w = (ball.sprite)->w;
    //(ball.pos).h = (ball.sprite)->h;

  // --------------------------------------------------
  // Game loop
  // --------------------------------------------------
    while (handleEvents())
    {
    // --------------------------------------------------
    // Game logic
    // --------------------------------------------------

        //after 30s of inactivity quit game
        if ((SDL_GetTicks()-iTicksLastKey)>(GAMETIME*1000)) { break; }

        if (((SDL_JoystickGetButton(joy0, 0)) ||  //fire, start game
             (SDL_JoystickGetButton(joy0, 1)) ||
             (SDL_JoystickGetButton(joy0, 2)) ||
             (SDL_JoystickGetButton(joy0, 3)) ||
             (SDL_JoystickGetButton(joy0, 4)) ||
             (SDL_JoystickGetButton(joy0, 5)) ||
             (SDL_JoystickGetButton(joy0, 6)) ||
             (SDL_JoystickGetButton(joy0, 7))) &&
             ((ball.bx==0) && (ball.by==0)))
        {
            iTicksLastKey=SDL_GetTicks();  //remember the time of last key press
            go();
            playerA.life=playerB.life=3;
            playerA.score=playerB.score=0;
        }
           
        int Delta=SDL_GetTicks()-TicksElapsed;

        // Update position of sprites
        if (joy0)  //if joystick connected
        {
            //SDL_JoystickUpdate();
            iMoveXOld=iMoveX;
            iMoveYOld=iMoveY;
            iMoveX=SDL_JoystickGetAxis(joy0, 0);  //move joy 0 axxis 0 (-32768 to 32768)
            iMoveY=SDL_JoystickGetAxis(joy0, 1);  //move joy 0 axxis 1 (-32768 to 32768)
            (playerA.pos_y)=(int)(((((float)iMoveX)/65335)+0.5)*(240-(playerA.sprite)->h));
            (playerB.pos_y)=(int)(((((float)iMoveY)/65335)+0.5)*(240-(playerB.sprite)->h));
            if ((iMoveX!=iMoveXOld) || (iMoveY!=iMoveYOld)) { iTicksLastKey=SDL_GetTicks(); }  //remember the time of last movement
        }
        else  //otherwise keyboard
        {
            if (playerA.dir != 0)
            {
                (playerA.pos_y)+=((Delta*ballspeed)/1000)*playerA.dir;
                if ((playerA.pos_y) >= 240-(playerA.sprite)->h)
                {
                    (playerA.pos_y) = 240-(playerA.sprite)->h;
                }
                else if ((playerA.pos_y) <= 0)
                {
                    (playerA.pos_y) = 0;
                }
            }
            if (playerB.dir != 0)
            {

                (playerB.pos_y)+=((Delta*ballspeed)/1000)*playerB.dir;
                if ((playerB.pos_y) >= 240-(playerB.sprite)->h)
                {
                    (playerB.pos_y) = 240-(playerB.sprite)->h;
                }
                else if ((playerB.pos_y) <= 0)
                {
                    (playerB.pos_y) = 0;
                }
            }
        }

        if (playerB.up == true) {
            (playerB.pos_y)-=((Delta*ballspeed)/1000);
            }
        if (playerB.down == true) {
            (playerB.pos_y)+=((Delta*ballspeed)/1000);
            }
        if (playerB.left == true) {
            (playerB.pos_x)-=((Delta*ballspeed)/1000);
        }
        if (playerB.right == true) {
            (playerB.pos_x)+=((Delta*ballspeed)/1000);
        }
        if (playerB.pos_y > level->h - playerB.sprite->h) {
            playerB.pos_y = level->h - playerB.sprite->h ;
        }
        if (playerB.pos_y < 0) {
            playerB.pos_y = 0;
        }
        if (playerB.pos_x > level->w - playerB.sprite->w) {
            playerB.pos_x = level->w- playerB.sprite->w;
        }
        if (playerB.pos_x < 0) {
            playerB.pos_x = 0;
        }

       
        if (playerA.w == true){

            (playerA.pos_y)-=((Delta*ballspeed)/1000);
            }
        if (playerA.s == true){

            (playerA.pos_y)+=((Delta*ballspeed)/1000);
            }
        if (playerA.a == true){

            (playerA.pos_x)-=((Delta*ballspeed)/1000);
        }
        if (playerA.d == true){

            (playerA.pos_x)+=((Delta*ballspeed)/1000);
        }

        if (playerA.pos_y > level->h - playerA.sprite->h) {
            playerA.pos_y = level->h - playerA.sprite->h ;
        }
        if (playerA.pos_y < 0) {
            playerA.pos_y = 0;
        }
        if (playerA.pos_x > level->w - playerA.sprite->w) {
            playerA.pos_x = level->w- playerA.sprite->w;
        }
        if (playerA.pos_x < 0) {
            playerA.pos_x = 0;
        }

        // Update ball
        //(ball.pos_x) += ball.bx;
        //(ball.pos_y) += ball.by;
        (ball.pos_x)+=((Delta*ballspeed)/1000)*ball.bx;
        (ball.pos_y)+=((Delta*ballspeed)/1000)*ball.by;
        TicksElapsed=SDL_GetTicks();

        // (*) Reflection on top and bottom of screen
        if ((ball.pos_y) <= 0 || (ball.pos_y) >= 240-(ball.sprite)->h)
        {
            ball.by = -ball.by;
        }

        //player A paddle Reflektion:
        delta=(ball.pos_y)-(playerA.pos_y);
        if (((ball.pos_x)<=8+(playerA.sprite)->w) &&  //in reach of the paddle
            ((ball.pos_x)>=8) &&  //not too far left
            (delta>=0) &&  //not above paddle
            (delta<=(playerA.sprite)->h) &&  //not below
            (ball.bx<0))  //ball flies to the left
        {
            if (ball.bx < 0) { ball.bx = 1; } else { ball.bx = -1; }
            //ball.bx *= (2+abs((delta - ((playerA.sprite)->h/2))) / 6);
            //ball.by = (delta - ((playerA.sprite)->h/2)) / 4;
            playerA.score++;
        }
        if ((ball.pos_x)<0)  //left out
        {
            playerA.life--;
            playerB.score += 10;
            if (playerA.life == 0)
            {
                //Restart game:
                ball.bx = 0;
                ball.by = 0;
                (ball.pos_x) = 160-(ball.sprite)->w/2;
                (ball.pos_y) = 120-(ball.sprite)->h/2;
            }
            else { go(); }
        }

        //player B paddle Reflektion:
        delta=(ball.pos_y)-(playerB.pos_y);
        if (((ball.pos_x)+(ball.sprite)->w>=312-(playerB.sprite)->w) &&  //in reach of the paddle
            ((ball.pos_x)+(ball.sprite)->w<=312) &&  //not too far right
            (delta>=0) &&  //not above paddle
            (delta<=(playerB.sprite)->h) &&  //not below
            (ball.bx>0))  //ball flies to the right
        {
            if (ball.bx < 0) { ball.bx = 1; } else { ball.bx = -1; }
            //ball.bx *= (2+abs((delta - ((playerB.sprite)->h/2))) / 6);
            //ball.by = (delta - ((playerB.sprite)->h/2)) / 4;
            playerB.score++;
        }
        if ((ball.pos_x)+(ball.sprite)->w>320)  //right out
        {
            playerB.life--;
            playerA.score += 10;
            if (playerB.life == 0)
            {
                //Restart game:
                ball.bx = 0;
                ball.by = 0;
                (ball.pos_x) = 160-(ball.sprite)->w/2;
                (ball.pos_y) = 120-(ball.sprite)->h/2;
            }
            else go();
        }

    // --------------------------------------------------
    // Draw game screen
    // --------------------------------------------------
        if (ball.bx == 0 && ball.by == 0) { SDL_BlitSurface(intro, NULL, SCREEN, NULL); }
        else                              { SDL_BlitSurface(background, NULL, SCREEN, NULL); }
       
    SDL_Rect halfscreen;
    halfscreen.x=0;
    halfscreen.y=0;
    halfscreen.w=SCREEN->w/2;
    halfscreen.h=SCREEN->h;
   
    SDL_Rect levelrect;//Left hand side screen
    levelrect.x=iRound(playerB.pos_x-SCREEN->w/4);
    levelrect.y=iRound(playerB.pos_y-SCREEN->h/2);
    levelrect.w=SCREEN->w/2;
    levelrect.h=SCREEN->h;
    SDL_BlitSurface(level, &levelrect, SCREEN, &halfscreen);

    halfscreen.x=SCREEN->w/2;

    levelrect.x=iRound(playerA.pos_x-SCREEN->w/4);//right hand side screen
    levelrect.y=iRound(playerA.pos_y-SCREEN->h/2);
    levelrect.w=SCREEN->w*2;
    levelrect.h=SCREEN->h*1;
    SDL_BlitSurface(level, &levelrect, SCREEN, &halfscreen);
   
    overlay();

    SDL_Rect p1;
    p1.x=(SCREEN->w/4-playerA.sprite->w/5);
    p1.y=(SCREEN->h/2-playerA.sprite->h/2);
    p1.w=(playerA.sprite)->w;
    p1.h=(playerA.sprite)->h;
    SDL_BlitSurface(playerA.sprite, NULL, SCREEN, &p1);

    SDL_Rect p2;
    p2.x=(SCREEN->w/2+SCREEN->w/4-playerB.sprite->w/2);
    p2.y=(SCREEN->h/2-playerB.sprite->h/2);
    p2.w=(playerB.sprite)->w;
    p2.h=(playerB.sprite)->h;
    SDL_BlitSurface(playerB.sprite, NULL, SCREEN, &p2);

    SDL_Rect r;
    r.x=iRound(ball.pos_x);
    r.y=iRound(ball.pos_y);
    r.w= (ball.sprite)->w;
    r.h= (ball.sprite)->w;
    SDL_BlitSurface(ball.sprite, NULL, SCREEN, &r);

    SDL_Flip(SCREEN);
  }

  // --------------------------------------------------
  // Clean up
  // --------------------------------------------------
    if ((joy0) && (SDL_JoystickOpened(0))) { SDL_JoystickClose(joy0); }
  SDL_Quit();
  return 0;
}

Dani AI

Generated

Useful follow-up to what posted — the right-side misalignment and the ball sitting off the background are almost always a camera/coordinate transform problem rather than a sprite bug. Each half of the screen needs its own source rectangle (camera) that is the same size as the half-screen, centered on the player, clamped to the level bounds, and then every world object must be drawn relative to that camera. If the source rect size or the mapping from world->screen is wrong you get the exact symptoms shown here.

A compact, robust approach: compute a viewport size equal to the half-screen, center it on the player, clamp it to [0, level_size - viewport_size], and then convert world coordinates into screen coordinates by subtracting the viewport origin and adding the half-screen offset for the right view. Example (variable names chosen to avoid repeating earlier code):

int clamp_int(int v, int lo, int hi) { return (v < lo) ? lo : (v > hi) ? hi : v; }

int vw = screen_w / 2;
int vh = screen_h;

int camX = px + (pw/2) - (vw/2);
int camY = py + (ph/2) - (vh/2);
camX = clamp_int(camX, 0, level_w - vw);
camY = clamp_int(camY, 0, level_h - vh);

Then map objects into each half before blitting:

int destOffsetX = isRightHalf ? (screen_w/2) : 0;
int sx = worldX - camX + destOffsetX;
int sy = worldY - camY;
SDL_Rect dst = { sx, sy, sprite_w, sprite_h };
SDL_BlitSurface(sprite, NULL, screen, &dst);

Checklist of common pitfalls to verify: the source rect width/height must equal the viewport; do not accidentally use twice the width or wrong units; clamp camera coordinates so the source rect never reads outside the level surface; convert every world-positioned object (ball, moving elements) for each viewport — draw the ball into both halves if both players should see it; watch for swapping width/height by mistake when building dst rects; and use consistent rounding to avoid one-pixel shifts. Using the clamp/center pattern above makes the split-screen stable and avoids ad-hoc offset tweaking.

Can you describe what you did to figure it out since you marked the thread as solved?

Dave

In the rect called levelrect i adjusted the width and the height which corected the right hand screen position.

levelrect.x=iRound(playerA.pos_x-SCREEN->w/28);//right hand side screen
    levelrect.y=iRound(playerA.pos_y-SCREEN->h/10);
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.