Drawing multiple instances of the same rect instead of moving it - c++

class Pong {
public:
Pong(int speed) {
gSpeed = speed;
gPongBG = SDL_LoadBMP("pongBG.bmp");
gPongBGSurf = gPongBG;
gPongRect.w = 800;
gPongRect.h = 460;
gPongRect.x = 700;
gPongRect.y = 220;
gPongPlayer = SDL_LoadBMP("pongPlayer.bmp");
gPongPlayerRect.h = 50;
gPongPlayerRect.w = 10;
gPongPlayerRect.x = 50;
gPongPlayerRect.y = 0;
}
~Pong() {
}
void drawPong() {
gPongBGSurf = gPongBG;
SDL_BlitSurface(gPongBGSurf, NULL, gScreenSurface, &gPongRect);
SDL_BlitSurface(gPongPlayer, NULL, gPongBGSurf, &gPongPlayerRect);
}
void movePlayer() {
gPongPlayerRect.y++;
}
The following code makes it so the gPongPlayerRect makes multiple copies of itself, rather than moving it as i planned. Later in the code, i update the main window named gWindow, and the surface of the main window is the wScreenSurface. If i blit the player directly onto the Window surface, it moves, so i guess the problem is that the old gPongBGSurf surface stays even tho its updated. How could i eventually fix this? Thanks!

My guess is that you forgot to erase the Pong Surface:
Uint32 black= SDL_MapRGBA(gPongBGSurf->format,0,0,0,255);
SDL_FillRect(gPongBGSurf, NULL, black);
SDL_BlitSurface(gPongPlayer, NULL, gPongBGSurf, &gPongPlayerRect);
SDL_BlitSurface(gPongBGSurf, NULL, gScreenSurface, &gPongRect);
For a full example of a SDL2 game with multiple surfaces blitting on top of each other and then onto a screen surface, you can read the small source code of Rock Dodger CE which is only a single file.

Related

SDL Pong Movement Bug

The problem with my code is that I am making a pong game in SDL 2.0 in c++. I did everything until creating the movement. When the player paddle moves, it leaves behind a trail in the same color as the paddle. I watched some videos on YouTube, but when they do the movement it's nice and clear and for me to fix this but I need to recolor the background every time the player moves, which makes it being all flashy and if I hold the button I don't see the paddle at all.
#include<iostream>
#include<SDL2/SDL.h>
#include<SDL2/SDL_image.h>
#include<windows.h>
#define width 800
#define height 600
using namespace std;
bool run = true;
class Player{
private:
SDL_Window* window = SDL_CreateWindow("Pong!", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE);
SDL_Surface* Screen = SDL_GetWindowSurface(window);
Uint32 screen_color = SDL_MapRGB(Screen->format, 0, 0, 0);
Uint32 In_game_RGB = SDL_MapRGB(Screen->format, 255, 255, 255);
SDL_Rect Pl;
SDL_Rect AI;
SDL_Rect Ball;
SDL_Rect ClearP;
SDL_Rect ClearAI;
public:
Player(){
//Player parameters
Pl.x = 60;Pl.y = 225;Pl.w = 25;Pl.h = 200;
//AI parameters
AI.x = 720;AI.y = 225;AI.w = 25;AI.h = 200;
//Ball parameters
Ball.x = width/2;Ball.y = height/2+10;Ball.w = 25;Ball.h = 25;
//Recoloring parameters
ClearP.x = 0;ClearP.y = 0; ClearP.w = 375;ClearP.h = height;
ClearAI.x = 425;ClearAI.y = 0;ClearAI.w = 375;ClearAI.h = height;
//Make the screen color black
SDL_FillRect(Screen, NULL, screen_color);
}
void scrUpdate(){
SDL_UpdateWindowSurface(window);
}
void drawPlayer(){
SDL_FillRect(Screen, &Pl, In_game_RGB);
}
void drawComputer(){
SDL_FillRect(Screen, &AI, In_game_RGB);
}
void ball(){
SDL_FillRect(Screen, &Ball, In_game_RGB);
}
void Movement(){
if(GetAsyncKeyState(VK_DOWN)){
Pl.y += 2;
SDL_FillRect(Screen,&ClearP,screen_color);
}
if(GetAsyncKeyState(VK_UP)){
SDL_FillRect(Screen,&ClearP,screen_color);
Pl.y -= 2;
}
}
};
void EventCheck(){
SDL_Event event;
if(SDL_PollEvent(&event)){
if(event.type == SDL_QUIT){
run = false;
}
}
}
int main( int argc, char *argv[] )
{
SDL_Init(SDL_INIT_EVERYTHING);
Player Play;
//Player Computer();
while(run){
Play.scrUpdate();
Play.drawPlayer();
Play.drawComputer();
Play.ball();
Play.Movement();
EventCheck();
}
SDL_Quit();
return EXIT_SUCCESS;
}
It would help to show some code or an example of what you have been doing, or a link to one of the videos you have been watching:
Youtube tutorial
but I suggest taking a look at:
screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE); and SDL_Flip(screen) as those have to do with screen buffering and drawing.
Another possibilty is that you are running an outdated version of SDL, or an incompatible one with your current system.
To be able to give a more complete and proper answer, I'd highly suggest adding more information about your code, screenshots of results and your version of SDL and operating system.
Also, you said it was flashy when you hold the paddle. I think it must be that you are performing your logic to move the paddle and you redraw the paddle once it's still. If you are redrawing the entire screen constantly, consider double buffering.

SDL will only draw a black screen when trying to print a picture C++

class Game {
public:
Game(int width, int height) {
gwidth = width;
gheight = height;
}
~Game() {
}
bool initGame() {
bool sucsess = true;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
sucsess = false;
}
//gTetrisSurface = SDL_LoadBMP("TetrisBg.bmp");
gWindow = SDL_CreateWindow("Petris V1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, gwidth, gheight, SDL_WINDOW_SHOWN);
gScreenSurface = SDL_GetWindowSurface(gWindow);
gMainBG = SDL_LoadBMP("test.bmp");
/**if (gMainBG == NULL) {
return false;
}**/
bool running = true;
//SDL_SetWindowFullscreen(gWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
while (running == true) {
SDL_BlitSurface(gMainBG, NULL, gScreenSurface, NULL);
SDL_UpdateWindowSurface( gWindow );
}
return sucsess;
}
protected:
int gwidth, gheight;
SDL_Window* gWindow = NULL;
SDL_Surface* gScreenSurface = NULL;
SDL_Surface* gTetrisSurface = NULL;
SDL_Surface* gPongSurface = NULL;
SDL_Surface* gMainBG = NULL;
};
The thought behind this, is that this should be one huge surface, containing 2 other surfaces for 2 other games. Problem is, it wont seem to draw the BMP that i try to draw on it. Because of this my development got kinda stuck. Anyone see a possible sulotion for this problem? Thanks!
EDIT: I made it so it flushes the events, BUT, i did a bit of debugging, the problem seems to be that the img file returns NULL, why? It should be loaded with a bmp... (No error messages at all..)
From the documentation of SDL2:
https://wiki.libsdl.org/SDL_GetWindowSurface
This surface will be invalidated if the window is resized. After resizing a window this function must be called again to return a valid surface.
You may not combine this with 3D or the rendering API on this window.
My advice is to avoid using the window surface directly.
Instead, you should use a renderer and copy your own main surface to your background texture.
The SDL2 migration guide explains clearly the right way to copy surfaces and textures on the screen, especially the paragraph "If your game wants to do both".
The whole problem was that the BMP file was in the wrong folder.
If anyone have the same problem, the picture should either be in the same directory as the src (when debugging) or the solution (if building).
Hope this might help someone in the future, either way, thanks to those who tried coming up with other possibilites.
(Using visual studio)

Why am I unable to draw to a texture in SDL2?

I've been working on a project in SDL on nights and weekends for the past few months. I'm currently trying to get a menu system working. At the moment, I'm working on drawing text using SDL_TTF. As for my question, I'm seeing some strange behavior when I try to draw some textures to another texture.
The weirdness is that when I draw it, on a destination texture created with SDL_TEXTUREACCESS_TARGET (like it says to do in the docs) draws nothing, but returns no error. However, if I use SDL_TEXTUREACCESS_STATIC or SDL_TEXTUREACCESS_STREAM, it returns an error when I set the render target because of the access attribute, but draws just fine. After doing some digging, I heard some things about a bug in the Intel drivers (I'm on a Macbook with Intel graphics), so I was wondering if this was something I messed up, and how I might fix it. Alternately, if it isn't my fault, I'd still like to know what's going on, and if it would perform differently on different platforms and how I could work around it.
Here's my code, after removing unnecessary parts and :
I create the renderer:
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
Later on, when I go to render onto a canvas:
TTF_Font *fnt = loadFont(fontName.c_str(), fontSize);
In here I parse out some attributes and set them using TTF_SetFontStyle() and the clr for text color.
SDL_Texture *canvas;
canvas = SDL_CreateTexture(rendy, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, contentRect.w, contentRect.h)
SDL_SetRenderTarget(rendy, canvas);
int pos = 0;
for (list<string>::iterator itr = lines.begin(); itr != lines.end(); itr++){
SDL_Surface *temp;
temp = TTF_RenderText_Blended(fnt, src.c_str(), clr);
SDL_Texture *line;
line = SDL_CreateTextureFromSurface(rendy, temp);
int w,h;
SDL_QueryTexture(line, NULL, NULL, &w, &h);
SDL_Rect destR;
//Assume that we're left justified
destR.x = 0;
destR.y = pos;
destR.w = w;
destR.h = h;
SDL_RenderCopy(rendy, line, NULL, &destR);
SDL_DestroyTexture(line);
SDL_FreeSurface(temp);
pos += TTF_FontLineSkip(fnt);
}
//Clean up
SDL_SetRenderTarget(rendy, NULL);
canvas gets returned to the calling function so it can be cached until this text box is modified. That function works by having a texture for the whole box, drawing a background texture onto it, and then drawing this image on top of that, and holding on to the whole thing.
That code looks like this:
(stuff to draw the background, which renders fine)
SDL_Texture *sum = SDL_CreateTexture(rendy, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, globalRect.w, globalRect.h);
SDL_SetTextureBlendMode(sum, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(rendy, sum);
string lPad = getAttribute(EL_LEFT_PADDING);
string tPad = getAttribute(EL_TOP_PADDING);
int paddingL = strtol(lPad.c_str(), NULL, 10);
int paddingT = strtol(tPad.c_str(), NULL, 10);
SDL_Rect destR;
SDL_Rect srcR;
srcR.x = 0;
srcR.y = 0;
srcR.w = globalRect.w; //globalRect is the size size of the whole button
srcR.h = globalRect.h;
destR.x = 0;
destR.y = 0;
destR.w = globalRect.w;
destR.h = globalRect.h;
SDL_RenderCopy(rendy, bgTexture, NULL, &destR);
int maxX = contentRect.w;
fgTexture = getFGImage(rendy); //The call to the previous part
int w, h;
SDL_QueryTexture(fgTexture, NULL, NULL, &w, &h);
int width, height;
getTextSize(&width, &height, maxX);
srcR.x = 0;
srcR.y = 0;
srcR.w = width;
srcR.h = height;
destR.x = paddingL;
destR.y = paddingT;
destR.w = globalRect.w;
destR.h = globalRect.h;
SDL_RenderCopy(rendy, fgTexture, NULL, &destR);
SDL_DestroyTexture(fgTexture);
SDL_DestroyTexture(bgTexture);
return sum;
Sum is returned to another function which does the drawing.
Thanks in advance!
Update
So I've figured out that the reason it only drew when I had the incorrect access setting was that, since the function was returning an error value, the render target was never set to the texture, so it was just drawing on the screen. I've also checked all my textures by writing a function AuditTexture which checks to see that the texture format for a texture is supported by the renderer, prints a string description of the access attribute, and prints the dimensions. I now know that all of their texture formats are supported, the two lines are static, canvas and sum are render targets, and none of them have dimensions of zero.
As it turns out, I had set the render target to be the composite texture, then called my function which set the render target to the text texture before drawing text. Then when I returned from the function, the render target was still the text texture instead of the composite one, so I basically drew the text over itself instead of drawing over the background.
A word to the wise: Don't ever assume something is taken care of for you, especially in c or c++.

C++ DirectX 9.0 Sprite Alpha Blending Not Showing

EDIT: SOLVED
The problem was me using the renderstate functions I needed for alphablending outside of the Sprite->Begin() and Sprite->End() codeblock.
I am creating my own 2D engine within DirectX 9.0. I am using sprites with corresponding spritesheets to draw them. Now the problem is, if I set my blending to D3DSPR_SORT_TEXTURE, I'll be able to see the texture without any problems (including transformation matrices), however if I try and set it to D3DSPR_ALPHABLEND, the sprite won't display. I've tried several things; SetRenderState, change the image format from .png to .tga, add an alpha channel to the image with a black background, used another image used within an example of 2D blending, changed my D3DFMT_ parameter of my D3DManager, etc.
I'm tried searching for an answer here but didn't find any answers related to my question.
Here's some of my code which might be of importance;
D3DManager.cpp
parameters.BackBufferWidth = w; //Change Direct3D renderer size
parameters.BackBufferHeight = h;
parameters.BackBufferFormat = D3DFMT_UNKNOWN; //Colors
parameters.BackBufferCount = 1; //The amount of buffers to use
parameters.MultiSampleType = D3DMULTISAMPLE_NONE; //Anti-aliasing quality
parameters.MultiSampleQuality = 0;
parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
parameters.hDeviceWindow = window; //The window to tie the buffer to
parameters.Windowed = true; //Window mode, true or false
parameters.EnableAutoDepthStencil = NULL;
parameters.Flags = NULL; //Advanced flags
parameters.FullScreen_RefreshRateInHz = 0; //Fullscreen refresh rate, leave at 0 for auto and no risk
parameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE; //How often to redraw
Sprite.cpp
void Sprite::draw(){
D3DXVECTOR2 center2D = D3DXVECTOR2(center.x,center.y);
D3DXMatrixTransformation2D(&matrix,&center2D,NULL,&scale,&center2D,angle,new D3DXVECTOR2(position.x,position.y));
sprite->SetTransform(&matrix);
sprite->Begin(D3DXSPRITE_ALPHABLEND);
if(!extended){
sprite->Draw(texture, NULL, NULL, &position, 0xFFFFFF);
}
else{
doAnimation();
sprite->Draw(texture, &src, &center, new D3DXVECTOR3(0,0,0), color);
}
sprite->End();
}
Main.cpp
//Clear the scene for drawing
void renderScene(){
d3dManager->getDevice().Clear(0,NULL,D3DCLEAR_TARGET,0x161616,1.0f,0); //Clear entire backbuffer
d3dManager->getDevice().BeginScene(); //Prepare scene for drawing
render(); //Render everything
d3dManager->getDevice().EndScene(); //Close off
d3dManager->getDevice().Present(NULL, NULL, NULL, NULL); //Present everything on-screen
}
//Render everything
void render(){
snake->draw();
}
I've got no clue at all. Any help would be appreciated.
The problem was me using the renderstate functions I needed for alphablending outside of the Sprite->Begin() and Sprite->End()
code block.

SDL C Program freezes on sdl_blitsurface

I'm having an issue with a program I'm working on. Occasionally, it will just freeze. No errors or anything.
The game is a multiplayer game where you fly a ship around. Pictures of other players and powerups move in and out of view depending on your location. For the most part, it works great, but under certain circumstances, it locks up.
I've tracked it down to when it BLITs one surface onto another. (SDL_BlitSurface).
If I comment out the single line of code where it blits (SDL_BlitSurface), and replace the graphic with a simple circle, it'll never freeze under any circumstances. But, comment out the circle and replace it with blitting the graphic again, and it'll randomly freeze. The frustrating part is, sometimes it will, sometimes it won't. Sometimes the graphic will sit on screen for a few moments and then freeze, sometimes it'll freeze the moment it shows up. Sometimes, it won't freeze at all. I simply cannot track it down to anything in particular.
I have ample amount of code that checks for NULL surfaces and it doesn't seem to stop it.
I also have it set up to output information about all the graphics to a file (such as width, height, location in memory, x, y, etc) and nothing seems out of the ordinary.
My main questions are, what about surfaces can cause SDL_BlitSurface to freeze? And what other checks can I add for surfaces to make sure it doesn't try to blit bad surfaces?
The code is too long to list, but here is how it works:
class Player
{
Player();
int x;
int y;
int xvel;
int yvel;
SDL_Surface *DrawScreen;
SDL_Surface *ShipPic;
void check_player_dist();
void check_powerup_dist();
void update();
};
class PowerUp
{
int x;
int y;
int type;
SDL_Surface *Powerup_Pic;
};
Player::Player()
{
Apply_Surface(0, 0, PlayerShipPics, ShipPic);
}
Player::Update(Player p[], PowerUp pu[])
{
x += xvel;
y += yvel;
for (int i = 0; i < Num_Players; i++)
{
if (check_on_screen(p[i].x, p[i].y) == true)
{
Apply_Surface(x - p[i].x, y - p[i].y, p[i].ShipPic, DrawScreen);
}
}
for (int i = 0; i < Num_PowerUps; i++)
{
if (check_on_screen(pu[i].x, pu[i].y) == true)
{
Apply_Surface(x - pu[i].x, y - pu[i].y, pu[i].Pic, DrawScreen);
}
}
}
int main()
{
SDL_Surface *Screen;
Player players[4];
PowerUp powerups[200];
Num_Players = 4;
Num_PowerUps = 200;
while (quit == false)
{
for (int i = 0; i < Num_Players; i++)
{
players[i].update(players, powerups);
switch (i)
{
case 0: ScreenX = 0; ScreenY = 0; break;
case 1: ScreenX = ScreenWid / 2; ScreenY = 0; break;
case 2: ScreenX = 0; ScreenY = ScreenHigh / 2; break;
case 3: ScreenX = ScreenWid / 2; ScreenY = ScreenHigh / 2; break;
}
Apply_Surface (ScreenX, ScreenY, players[i].DrawScreen, Screen);
}
if (SDL_Flip(Screen) == -1)
{
return -1;
}
}
}
void Apply_Surface (int x, int y, SDL_Surface* Source, SDL_Surface* Destination, SDL_Rect* Clip)
{
SDL_Rect Offset;
Offset.x = x;
Offset.y = y;
if ((Source != NULL) && (Destination != NULL))
{
SDL_BlitSurface (Source, Clip, Destination, &Offset );
}
}
I've noticed it generally freezes when two or more players are near each other and it tries to draw the same power-up on both of their screens. But again...not always!
Well, I figured out what it was.
I was using the SDL_GFX library along with my game. Many of the images were created using rotozoomSurface(), which is a function of SDL_GFX.
Turns out there's a bug in it where, under certain circumstances that I don't know, it'll create a bad surface that will work "most" of the time, but under the right conditions, will crash. Such as, being placed at a particular x & y coordinate on the screen. (Don't know for sure). The rotated/zoomed images would work about 95% of the time, so it was very difficult to pin point what the issue was.
The work around was, when the image was created, just SDL_BlitSurface() it onto another surface under controlled conditions, such as putting it at coordinates (0, 0). Then, delete the rotated and zoomed surface, and just use the new "safe" surface.
Works great after that.
Hopefully this will help anyone who's using SDL_GFX and cannot figure out why their program is crashing.
Example:
Before:
SDL_Surface *original = SDL_CreateRGBSurface(SDL_SWSURFACE, Ship_Width, Ship_Height, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, ShipsPic, original, &bounds);
SDL_Surface *finished = rotozoomSurface(original, pic_angle, zoom, SMOOTHING_ON);
SDL_FreeSurface(original);
return finished;
After (fixed):
SDL_Surface *original = SDL_CreateRGBSurface(SDL_SWSURFACE, Ship_Width, Ship_Height, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, ShipsPic, original, &bounds);
SDL_Surface *temp = rotozoomSurface(original, pic_angle, zoom, SMOOTHING_ON);
SDL_Surface *finished = SDL_CreateRGBSurface(SDL_SWSURFACE, temp->w, temp->h, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, temp, finished);
SDL_FreeSurface(temp);
SDL_FreeSurface(original);
return finished;
And for what it's worth, the Apply_Surface() function:
void Apply_Surface (int x, int y, SDL_Surface* Source, SDL_Surface* Destination, SDL_Rect* Clip)
{
SDL_Rect Offset;
Offset.x = x;
Offset.y = y;
if ((Source != NULL) && (Destination != NULL))
{
SDL_BlitSurface (Source, Clip, Destination, &Offset );
}
}
There's not really enough information to figure out what exactly is going on. Computers don't like to do things "sometimes," they either do them or not, so it leads me to believe that maybe there's some variable that's doing something it shouldn't.
Just in case, what does your Apply_Surface() function look like? I assume that's where you're doing your actual blitting, and if that's where you're having your problems, that would be useful for those of us trying to figure out your dilemma.