I'm using cairomm, opencv4, box2d(not revealed in below code) to make physics education video.
My plan is like this.
Many Sobject(Scientific obect) constitute a Scene.
So I decided to use inner-class.(I don't know it's best design, I'm newbie to programming)
My problem is in below.
cv::Mat Surface2Mat(Cairo::RefPtr<Cairo::ImageSurface> surface)
{
cv::Mat Frame(surface->get_height(), surface->get_width(), CV_8UC4, surface->get_data(), surface->get_stride());
cv::cvtColor(Frame, Frame, cv::ColorConversionCodes::COLOR_BGRA2BGR);
return Frame;
}
class Scene
{
private:
int surface_width = 1920;
int surface_height = 1080;
int second = 4;
cv::Size resolution = {surface_width, surface_height};
const int mp4 = cv::VideoWriter::fourcc('a', 'v', 'c', '1');
cv::VideoWriter video;
double FPS;
public:
class Sobject
{
private:
double width;
double height;
double color[3] = {1, 1, 1};
public:
Cairo::RefPtr<Cairo::Context> cr;
Cairo::RefPtr<Cairo::ImageSurface> surface;
Sobject()
{
surface = Cairo::ImageSurface::create(Cairo::Format::FORMAT_ARGB32, 1920, 1080);
cr = Cairo::Context::create(surface);
}
void
set_position(double x = 0, double y = 0)
{
cr->move_to(960, 540);
}
void drawCircle()
{
cr->arc(0, 0, 40, 0.0, 2 * M_PI);
}
};
Scene(int width = 1920, int height = 1080)
{
video.open("Scene.mp4", mp4, FPS = 30, resolution, true);
}
~Scene()
{
video.release();
}
void write()
{
for (int i = 0; i < (FPS * second); i++)
{
video.write(Surface2Mat(surface));
}
}
};
The "video.write(Surface2Mat(surface));" at last makes problem.
How can I access to the surface?
You have not created an instance of Sobject. You can do something like:
class Scene
{
....
public:
class Sobject
{...};
Sobject mSobject; // can have it public or private depending on other requirements
....
void write()
{
for (int i = 0; i < (FPS * second); i++)
{
// now that you have an instance of Sobject, you can use surface from it
video.write(Surface2Mat(mSobject.surface));
}
}
Related
I've started programming just recently and I've learned the basic concepts of classes and objects and how to create them. So I decided to try and create a simple game of breakout with what I've learned so far. I've only created the main movable platform with a for cycle and make it move horizontally with the directional keys so far. I've also created a void so the platform doesn't go over the border of the screen but it doesn't work and I've tried all I could think of. Can someone please tell me what I'm doing wrong?
Game::Game( MainWindow& wnd )
:
wnd( wnd ),
gfx( wnd )
{
}
void Game::Go()
{
gfx.BeginFrame();
UpdateModel();
ComposeFrame();
gfx.EndFrame();
}
void Game::UpdateModel()
{
if (wnd.kbd.KeyIsPressed(VK_RIGHT))
{
platform.vx += 3;
}
if (wnd.kbd.KeyIsPressed(VK_LEFT))
{
platform.vx -= 3;
}
platform.ScreenLimit();
}
void Game::ComposeFrame()
{
for (platform.x = 460; platform.x <= platform.w; platform.x++)
{
for (platform.y = 500; platform.y <= platform.h; platform.y++)
{
gfx.PutPixel(platform.x + platform.vx, platform.y, 255, 255, 255);
}
}
}
and here's the header file and source file of the class I created for the platform:
Platform.h
#pragma once
#include "Graphics.h"
class Platform
{
public:
int x = 460;
int y = 500;
int vx = 0;
int width = 60;
int heigth = 10;
int w = x + width;
int h = y + heigth;
void ScreenLimit();
private:
};
Platform.cpp
#include "Platform.h"
void Platform::ScreenLimit()
{
const int left_base = x;
const int right_base = w;
if (right_base >= Graphics::ScreenWidth)
{
x = (Graphics::ScreenWidth - 6) - width;
}
else if (left_base <= 0)
{
x = 0;
}
}
I have a base class cGameObject which has a virtual update function. I wish to have many derived game objects each with their own specific update function.
I want to add the derived gameobjects to a vector and iterate through them to call each of their update methods.
What is wrong with my iterator?
//In Header file
std::vector <cGameObject*> vGameObjs;
std::vector <cGameObject*>::iterator Iter;
cGameObject *AGameObj;
/In cpp file - add object pointer to vector
AGameObj = new BrickBat(128, 32, (1024 - 128) / 2, 768 - 64, 0);
vGameObjs.push_back(AGameObj);
AGameObj = new BrickBall(64, 512, 384, 1, 1, 0);
vGameObjs.push_back(AGameObj);
//Iterator Crashing??
for (Iter = vGameObjs.begin(); Iter != vGameObjs.end(); ++Iter)
{
//Call Each Objects Update() method here?
}
When I run this, it throws an exception: read access violation. _Mycont was nullptr.
Not sure what to do.
error thrown
Header of Class App Class:
#ifndef _H_AGK_TEMPLATE_
#define _H_AGK_TEMPLATE_
// Link to GDK libraries
#include "AGK.h"
#include "Brickbat.h"
#include "BrickBall.h"
#include "cGameObject.h"
#include <vector>
#define DEVICE_WIDTH 1024
#define DEVICE_HEIGHT 768
#define DEVICE_POS_X 32
#define DEVICE_POS_Y 32
#define FULLSCREEN false
// used to make a more unique folder for the write path
#define COMPANY_NAME "BitMaNip:Play"
// Global values for the app
class app
{
public:
// constructor
app() { memset ( this, 0, sizeof(app)); }
// main app functions - mike to experiment with a derived class for this..
void Begin( void );
int Loop( void );
void End( void );
private:
//Vector of GameObject Pointers;
std::vector <cGameObject*> vGameObjs;
//Iterator of GameObjects
std::vector <cGameObject*>::iterator Iter;
BrickBat *MyBat;
BrickBall *MyBall;
cGameObject *AGameObj;
};
extern app App;
#endif
// Allow us to use the LoadImage function name
#ifdef LoadImage
#undef LoadImage
#endif
cpp file for Header
// Includes
#include "template.h"
#include "cGameObject.h"
#include
// Namespace
using namespace AGK;
app App;
void app::Begin(void)
{
agk::SetVirtualResolution (DEVICE_WIDTH, DEVICE_HEIGHT);
agk::SetClearColor( 151,170,204 ); // light blue
agk::SetSyncRate(60,0);
agk::SetScissor(0,0,0,0);
//Test
/*BrickBall = agk::CreateSprite(0);
agk::SetSpriteSize(BrickBall, 64, 64);
agk::SetSpriteColor(BrickBall, 255, 255, 255, 255);
xPos = (DEVICE_WIDTH - 64) / 2;
yPos = (DEVICE_HEIGHT - 64) / 2;
agk::SetSpritePosition(BrickBall, xPos , yPos );
xDir = 1;
yDir = 1;
iSpeed = 8;*/
MyBat = new BrickBat(128, 32, (1024-128)/2, 768-64, 0);
AGameObj = new BrickBat(128, 32, (1024 - 128) / 2, 768 - 64, 0);
vGameObjs.push_back(AGameObj);
MyBall = new BrickBall(64, 512, 384, 1, 1, 0);
AGameObj = new BrickBall(64, 512, 384, 1, 1, 0);
vGameObjs.push_back(AGameObj);
}
int app::Loop (void)
{
agk::Print( agk::ScreenFPS() );
if (agk::GetRawKeyState(37) == 1)
{
MyBat->MoveLeft();
}
if (agk::GetRawKeyState(39) == 1)
{
MyBat->MoveRight();
}
MyBat->Update();
MyBall->Update();
MyBall->Collided(MyBat->iGetBatID());
for (Iter = vGameObjs.begin(); Iter != vGameObjs.end(); ++Iter)
{
//(*Iter)->Update();
//(*Iter)->Collided(MyBat->iGetBatID());
}
Derived class
include "cGameObject.h"
class BrickBall: public cGameObject
{
private:
bool bHoriDir;
bool bVertDir;
int iSpeed;
bool bPause; //in case game is paused
public:
BrickBall(int iSize, int xPos, int yPos, bool bHori, bool bVert, int ImageID);
virtual void Update() override;
virtual void Collided(int OtherSpriteToCheck) override;
};
agk::Sync();
return 0; // return 1 to close app
}
void app::End (void)
{
}
Base Class:
#pragma once
class cGameObject
{
protected:
bool bInit = false;
int iSprID;
int iImageID;
int iXPos;
int iYPos;
int iAngle;
int iAlpha;
int iWidth;
int iHeight;
int iColour;
//Movement
float fDeltaX;
float fDeltaY;
//Animation
int iAniType; //Type of animation
//0 = No Animation
//1 = Repeating Loop of Frames (All image is animation)
//2 =
int iFrameW; //Width of Animation Frame
int iFrameH; //Height of Animation frame
int iFPS; //Animation Delay
int iNumFrames; //Number of animation frames
int iAniCount; //Frame Counter
public:
// set up default for constructor
cGameObject(int width = 16, int height = 16, int xPos = 0, int yPos = 0, int ImageID = 0);
void SetPosition(int ixPos, int iyPos);
void SetSize(int iWidth, int iHeight);
void SetWidth(int Width);
void SetAngle(int iAngle);
void SetTransparency(int iAlpha);
void SetAnimation(int Type, int FrameW, int FrameH, int FPS, int NumFrames);
virtual void Collided(int OtherSpriteToCheck) {};
virtual void Update() {};
int iGetWidth();
int iGetHeight();
int iGetX();
int iGetY();
int iGetSprID();
~cGameObject();
};
Base Class cpp
#include "cGameObject.h"
#include "agk.h"
void cGameObject::SetAngle(int iAngle)
{
if (bInit == true)
{
if (iAngle > 0 && iAngle < 359)
{
agk::SetSpriteAngle(iSprID, iAngle);
}
}
}
//cGameObject::cGameObject(int width, int height, int xPos, int yPos, const char * szImageFile)
cGameObject::cGameObject(int width, int height, int xPos, int yPos, int ImageID)
{
bInit = true;
iImageID = 0;
/*if (std::strlen(szImageFile) > 0)
{
iImageID = agk::LoadImage(szImageFile);
if (iImageID < 1)
{
bInit = false;
}
}*/
iColour = agk::MakeColor(255, 255, 255);
//init animation code
iAniType = 0; //Type of animation
iFrameW = 64; //Width of Animation Frame
iFrameH = 64; //Height of Animation frame
iFPS = 10; //Animation Delay
iNumFrames = 1; //Number of animation frames
iAniCount = 0; //Frame Counter
iSprID = agk::CreateSprite(iImageID);
if (iSprID < 1)
{
bInit = false;
}
else
{
agk::SetSpriteSize(iSprID, width, height);
agk::SetSpritePosition(iSprID, xPos, yPos);
fDeltaX = 4.0;
fDeltaY = 4.0;
}
}
void cGameObject::SetPosition(int ixPos, int iyPos)
{
if (bInit == true)
{
agk::SetSpritePosition(iSprID, ixPos, iyPos);
}
}
void cGameObject::SetSize(int iWidth, int iHeight)
{
if (bInit == true)
{
if (iWidth > 0 && iWidth < 1024 && iHeight > 0 && iHeight < 1024)
{
agk::SetSpriteSize(iSprID, iWidth, iHeight);
}
}
}
void cGameObject::SetWidth(int Width)
{
if (bInit == true)
{
agk::GetSpriteWidth(Width);
}
}
void cGameObject::SetTransparency(int iAlpha)
{
if (bInit == true)
{
if (iAlpha > 0 && iAlpha < 256)
{
agk::SetSpriteTransparency(iSprID, iAlpha);
}
}
}
void cGameObject::SetAnimation(int Type, int FrameW, int FrameH, int FPS, int NumFrames)
{
//Animation
iAniType = Type;
iFrameW = FrameW; //Width of Animation Frame
iFrameH = FrameH; //Height of Animation frame
iFPS = FPS; //Animation Delay
iNumFrames = NumFrames; //Number of animation frames
iAniCount = 0; //Frame Counter
agk::SetSpriteAnimation(iSprID, iFrameW, iFrameH, iNumFrames);
if (iAniType > 0)
{
agk::PlaySprite(iSprID, iFPS);
}
}
int cGameObject::iGetWidth()
{
if (bInit == true)
{
return agk::GetSpriteWidth(iSprID);
}
else
{
return 0;
}
}
int cGameObject::iGetHeight()
{
if (bInit == true)
{
return agk::GetSpriteHeight(iSprID);
}
else
{
return 0;
}
}
int cGameObject::iGetX()
{
if (bInit == true)
{
return agk::GetSpriteX(iSprID);
}
else
{
return 0;
}
}
int cGameObject::iGetY()
{
if (bInit == true)
{
return agk::GetSpriteY(iSprID);
}
else
{
return 0;
}
}
int cGameObject::iGetSprID()
{
if (bInit == true)
{
return iSprID;
}
else
{
return 0;
}
}
cGameObject::~cGameObject()
{
if (bInit == true)
{
agk::DeleteSprite(iSprID);
}
}
Derived Class Header:
#include "cGameObject.h"
class BrickBall: public cGameObject
{
private:
bool bHoriDir;
bool bVertDir;
int iSpeed;
bool bPause; //in case game is paused
public:
BrickBall(int iSize, int xPos, int yPos, bool bHori, bool bVert, int ImageID);
virtual void Update() override;
virtual void Collided(int OtherSpriteToCheck) override;
};
Derived Class cpp
#include "BrickBall.h"
BrickBall::BrickBall(int Size, int xPos, int yPos, bool bHori, bool bVert, int ImageID):cGameObject(Size, Size, xPos, yPos, ImageID)
{
iWidth = Size;
iHeight = Size;
iXPos = xPos;
iYPos = yPos;
bHoriDir = bHori;
bVertDir = bVert;
/*iSprID = agk::CreateSprite(0);
agk::SetSpriteColor(iSprIdx, 255, 255, 255, 255);
//agk::SetSpriteSize(iSprIdx, iSize, iSize);
agk::SetSpriteSize(iSprIdx, 64, 64);
//agk::SetSpritePosition(iSprIdx, ixPos, iyPos);
agk::SetSpritePosition(iSprIdx, ixPos, iyPos);
bInit = true;*/
iSpeed = 8;
}
void BrickBall::Update()
{
if (bInit==true)// && BatID > 0)
{
//Move Ball
agk::SetSpriteColor(iSprID, 100, 100, 100, 255);
agk::PrintC("BallX:");
agk::Print(iXPos);
if (bHoriDir == 1) //Right
{
iXPos = iXPos + iSpeed;
if (iXPos > 1024 - iWidth)
{
bHoriDir = 0;
}
}
else
{
iXPos = iXPos - iSpeed;
if (iXPos < 0)
{
bHoriDir = 1;
}
}
if (bVertDir == 1) //down
{
iYPos = iYPos + iSpeed;
if (iYPos > 768 - 64)
{
bVertDir = 0;
}
}
else
{
iYPos = iYPos - iSpeed;
if (iYPos < 0)
{
bVertDir = 1;
}
}
agk::SetSpritePosition(iSprID, iXPos, iYPos);
//END Move Ball
//Bat2Ball Collisions
/*if (agk::GetSpriteCollision(iSprID, BatID))
{
//We have collided.
//As Ball is bigger than the gap below the bat must have hit top or sides
//so just flip the vertcal direction
if (bVertDir == 1)
{
bVertDir = 0;
}
}*/
}
}
void BrickBall::Collided(int OtherSpriteToCheck)
{
if (agk::GetSpriteCollision(iSprID, OtherSpriteToCheck))
{
if (bVertDir == 1)
{
bVertDir = 0;
}
}
}
I don't know the cause of your error, but I got this exact error because I had an iterator to a vector, then I updated the vector, then I tried to dereference the iterator (e.g. access *myIterator). I'm new to C++, but it seems that if you alter a collection after getting an iterator for it, your iterator is no longer valid. You need to repoint your iterator to wherever it was.
my problem is that when I want to divide the code into smaller functions it throws me a runtime error: access violation.
Since everything is passed by value I have no idea why such an error would occur. There is nothing to do about memory.
General code:
// main.cpp
#include "stdafx.h"
#include "SFML/Graphics.hpp"
#include "GameEngine.h"
int main()
{
sf::RenderWindow* window = new sf::RenderWindow(sf::VideoMode(200, 200), "SFML works!");
GameEngine game(window);
game.run();
delete window;
return 0;
}
// DrawableVertices.h
#pragma once
#include "SFML\Graphics.hpp"
using namespace sf;
class DrawableVertices : public Drawable, public Transformable
{
VertexArray vertices;
Texture* pTexture;
public:
virtual void draw(RenderTarget& target, RenderStates states) const;
DrawableVertices(VertexArray vertices, Texture* pTexture = nullptr);
DrawableVertices();
Texture* getTexture();
VertexArray* getVertices();
};
// DrawableVertices.cpp
#include "stdafx.h"
#include "DrawableVertices.h"
DrawableVertices::DrawableVertices(sf::VertexArray _vertices, sf::Texture* _pTexture)
{
vertices = _vertices;
pTexture = pTexture;
}
DrawableVertices::DrawableVertices()
{
vertices = sf::VertexArray(sf::Points, 1);
pTexture = nullptr;
}
void DrawableVertices::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
states.texture = pTexture;
target.draw(vertices, states);
}
sf::Texture* DrawableVertices::getTexture() { return pTexture; }
sf::VertexArray* DrawableVertices::getVertices() { return &vertices; }
Working code (all in one function):
//GameEngine.h
#pragma once
#include "DrawableVertices.h"
class GameEngine
{
RenderWindow* pWindow;
public:
GameEngine(RenderWindow* window);
void run();
};
//GameEngine.cpp
#include "stdafx.h"
#include "GameEngine.h"
GameEngine::GameEngine(RenderWindow* window)
{
pWindow = window;
}
void GameEngine::run()
{
const int X_DIFF = 8;
const int PLAYER_Y = 24;
const int PLAYER_X = 48;
VertexArray playerShape(TrianglesStrip, 4);
playerShape[0].position = Vector2f(X_DIFF, 0);
playerShape[0].color = Color(0, 127, 255);
playerShape[1].position = Vector2f(PLAYER_X - X_DIFF, 0);
playerShape[1].color = Color(0, 127, 255);
playerShape[2].position = Vector2f(0, PLAYER_Y);
playerShape[2].color = Color(0, 0, 255);
playerShape[3].position = Vector2f(PLAYER_X, PLAYER_Y);
playerShape[3].color = Color(0, 0, 255);
DrawableVertices player(playerShape);
player.setOrigin(PLAYER_X / 2, PLAYER_Y / 2);
player.setPosition(64, 64);
while (pWindow->isOpen())
{
Event event;
while (pWindow->pollEvent(event))
{
if (event.type == Event::Closed)
pWindow->close();
}
pWindow->clear();
pWindow->draw(player);
pWindow->display();
}
}
Not working code, throwing access violation while drawing player
[ pWindow->draw(player) line ]
//GameEngine.h
#pragma once
#include "DrawableVertices.h"
class GameEngine
{
RenderWindow* pWindow;
DrawableVertices player;
void createPlayer();
public:
GameEngine(RenderWindow* window);
void run();
};
// GameEngine.cpp
#include "stdafx.h"
#include "GameEngine.h"
GameEngine::GameEngine(RenderWindow* window)
{
pWindow = window;
createPlayer();
}
void GameEngine::createPlayer()
{
const int X_DIFF = 8;
const int PLAYER_Y = 24;
const int PLAYER_X = 48;
VertexArray playerShape(TrianglesStrip, 4);
playerShape[0].position = Vector2f(X_DIFF, 0);
playerShape[0].color = Color(0, 127, 255);
playerShape[1].position = Vector2f(PLAYER_X - X_DIFF, 0);
playerShape[1].color = Color(0, 127, 255);
playerShape[2].position = Vector2f(0, PLAYER_Y);
playerShape[2].color = Color(0, 0, 255);
playerShape[3].position = Vector2f(PLAYER_X, PLAYER_Y);
playerShape[3].color = Color(0, 0, 255);
player = DrawableVertices(playerShape);
player.setOrigin(PLAYER_X / 2, PLAYER_Y / 2);
player.setPosition(64, 64);
}
void GameEngine::run()
{
while (pWindow->isOpen())
{
Event event;
while (pWindow->pollEvent(event))
{
if (event.type == Event::Closed)
pWindow->close();
}
pWindow->clear();
pWindow->draw(player);
pWindow->display();
}
}
What's worse when I display all player's information like position etc. inside run() method it shows the proper result. It means that player is initialised properly and it exists like it is supposed to.
Sorry for a lot of code, but wanted to show everything that could be useful. Obviously my whole code is bigger, I just put the part making problems into a separate project.
// Edit
Yeah, debugger says that pTexture member of player has a bad pointer.
image from debugging working and not working code
I suppose that overloading = operator might fix the problem. However, I want to understand how it works that this code works without any problems:
void GameEngine::run()
{
DrawableVertices player = DrawableVertices(playerShape);
// ...
pWindow->draw(player);
}
And packing it into a fuction doesn't:
void GameEngine::createPlayer()
{
// ...
DrawableVertices player = DrawableVertices(playerShape);
}
void GameEngine::run()
{
createPlayer();
// ...
pWindow->draw(player);
}
The error (if I'm not wrong) is very simple
In this constructor
DrawableVertices::DrawableVertices(sf::VertexArray _vertices, sf::Texture* _pTexture)
{
vertices = _vertices;
pTexture = pTexture;
}
you copy pTexture on itself; so pTexture start undefined and remain undefined.
I suppose that your intention was
DrawableVertices::DrawableVertices(sf::VertexArray _vertices, sf::Texture* _pTexture)
{
vertices = _vertices;
pTexture = _pTexture; // _pTexture !
}
p.s.: sorry for my bad English.
I'm attempting to integrate SDL_ttf into a particle generator program that I wrote recently, but I keep getting a runtime error: Access violation reading location 0x00000044.. This occurs when I attempt to blit a text surface to the game screen. I've scanned through my code several times, and had similar issues in the past, but I can't figure out the issue. What's most likely the problem?
The error occurs in Text.h:
#pragma once
#include "System.h"
#include <iostream>
#include <sstream>
class Text {
public:
Text(const char *fontaddress = "times.ttf", int size = 30, const char
*begintext = "0", int x = 0, int y = 0, SDL_Color color = { 255, 255, 255 }) {
font = TTF_OpenFont(fontaddress, size);
drawpos.x = x;
drawpos.y = y;
textcolor = color;
text = TTF_RenderText_Solid(font, begintext, textcolor);
if (!text)
std::cout << "damn" << std::endl;
}
~Text() {
if (text)
SDL_FreeSurface(text);
TTF_CloseFont(font);
}
void SetText(const char *txt);
void SetText(int txt);
void DrawText();
private:
TTF_Font *font;
SDL_Rect drawpos;
SDL_Color textcolor;
SDL_Surface *text;
};
inline void Text::SetText(const char *txt) {
if (text)
SDL_FreeSurface(text);
text = TTF_RenderText_Solid(font, txt, textcolor);
}
inline void Text::SetText(int txt) {
if (text)
SDL_FreeSurface(text);
std::stringstream s;
s << txt;
text = TTF_RenderText_Solid(font, s.str().c_str(), textcolor);
}
inline void Text::DrawText() {
static SDL_Surface *const screen = System::GetInstance().GetScreen();
SDL_BlitSurface(text, NULL, screen, &drawpos);
// ^ This line throws the exception
}
Bar.h:
#pragma once
#include <SDL.h>
#include <iostream>
#include "System.h"
#include "Text.h"
class Bar {
public:
Bar(const int xpos = 0, const int ypos = 0, unsigned width = 0, unsigned height = 0, const Uint32 c = SDL_MapRGB(System::GetInstance().GetScreen()- >format, 0, 0, 0), const char *address = "times.ttf",
int sz = 30, const char *bgtext = "0", SDL_Color co = { 255, 255, 255 }) : max_w(width), color(c), colortext(address, sz, bgtext, xpos - 50, ypos, co) {
bar.x = xpos;
bar.y = ypos;
bar.w = width;
bar.h = height;
modval = max_w / 255;
if (!modval)
modval = 1;
if (max_w < 255) {
std::cerr << "invalid width; below 255" << std::endl;
}
colorval = width / modval;
}
void Modify(int width_modifier);
void Draw();
Uint8 GetColorVal();
private:
SDL_Rect bar;
unsigned max_w;
Uint32 color;
Uint8 modval; // number of pixels (in width) required to advance or decrement the color value by 1
Uint8 colorval; // the color value modified when width is changed. Determined by
// modval. This value will be used by RGBTable class for text (on-screen value display) and particle color creation
Text colortext;
};
//inlined methods
//modifies the width of a bar
inline void Bar::Modify(int width_modifier) {
if (bar.w + width_modifier < 0 || bar.w + width_modifier > max_w)
return;
bar.w += width_modifier;
if (bar.w % modval == 0) {
colorval = bar.w / modval;
colortext.SetText(colorval);
}
}
//draws bar to system screen
inline void Bar::Draw() {
static SDL_Surface *screen = System::GetInstance().GetScreen();
SDL_FillRect(screen, &bar, color);
colortext.DrawText();
}
//returns the 8bit color value represented by the width of a bar
inline Uint8 Bar::GetColorVal() {
return colorval;
}
ColorTable.h:
#pragma once
#include "System.h"
#include "Bar.h"
#include <array>
class ColorTable {
public:
static bool needupdate;
static ColorTable &GetInstance();
void Input();
void Draw();
Uint32 MakeColor();
private:
ColorTable(int top_left_x, int top_left_y, unsigned width, int height, int sepval) {
static SDL_Surface *screen = System::GetInstance().GetScreen();
bars[0] = Bar(top_left_x, top_left_y, width, height, SDL_MapRGB(screen->format, 255, 0, 0));
bars[1] = Bar(top_left_x, top_left_y + height + sepval, width, height, SDL_MapRGB(screen->format, 0, 255, 0));
bars[2] = Bar(top_left_x, top_left_y + (sepval *2) + (height * 2), width, height, SDL_MapRGB(screen->format, 0, 0, 255));
activebar = bars.begin();
}
std::array<Bar, 3> bars;
std::array<Bar, 3>::iterator activebar;
const Uint8 *key = SDL_GetKeyboardState(NULL);
};
inline ColorTable &ColorTable::GetInstance() {
static ColorTable table(750, 620, 510, 50, 10);
return table;
}
inline void ColorTable::Draw() {
bars[0].Draw();
bars[1].Draw();
bars[2].Draw();
}
inline Uint32 ColorTable::MakeColor() {
static SDL_Surface *screen = System::GetInstance().GetScreen();
Uint8 r = bars[0].GetColorVal();
Uint8 g = bars[1].GetColorVal();
Uint8 b = bars[2].GetColorVal();
return SDL_MapRGB(screen->format, r, g, b);
}
Run the application in the debugger and break at the exception. Inspect the call stack. If you're lucky, it will trap at the point in your own code where the exception occurred. If the exception is not in your code module at the trap, click your way up the call stack (down the list presented there) until you reach the portion of your code where you can inspect the arguments of the caller, it's usually easy to spot where it went wrong at that point. 0x44 is suspiciously like ASCII '$', do you have a $ in your txt?
i want to make interpolation for my mini game. There are 2 SDL_Textures, when i click on first and then on second, they positions are swapped, but without move animation.
So how to make animated place swapping for SDL_Textures ?
void MainLoop() {
SDL_Event Event;
float t = 0.0f;
float dt = 0.1f;
float currentTime = 0.0f;
float accumulator = 0.0f;
while (Running)
{
while(SDL_PollEvent(&Event)) {
OnEvent(&Event);
}
const float newTime = SDL_GetTicks();
float frameTime = newTime - currentTime;
const Uint32 maxFrameTime = 1000; // 1 sec per frame is the slowest we allow
if( frameTime > maxFrameTime) {
frameTime = maxFrameTime;
}
currentTime = newTime;
accumulator += frameTime;
while( accumulator >= dt )
{
this->UpdatePositions(); // simulate a "frame" of logic at a different FPS than we simulate a frame of rendering
accumulator -= dt;
t += dt;
}
Render();
}
Main Render method:
void Puzzle::Render() const {
SDL_RenderClear(renderer);
for (int i = 0; i < blocksNum; ++i)
{
Rectangle texRect = normalizeTexCoords(blockRect(blocks[i]));
Rectangle scrRectOrigin = blockRect(i);
DrawRect(scrRectOrigin, i, texRect);
}
SDL_RenderPresent(renderer);
}
void DrawRect(const Rectangle& screenCoords, int textureId, const Rectangle& textureCoord) {
SDL_Texture *texture = blockTexture(blocks[textureId]);
renderTexture(texture, renderer, (int)screenCoords.left, (int)screenCoords.top, (int)blockWidth, (int)blockHeight);
//SDL_DestroyTexture(texture2);
}
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y, int w, int h) {
// Destination rectangle position
SDL_Rect dst;
dst.x = x; dst.y = y; dst.w = w; dst.h = h;
SDL_RenderCopy(ren, tex, NULL, &dst);
}
And in my UpdatePosition method i want to make my SDL_Textures moving, but it still swapping without animation.
void Puzzle::UpdatePositions()
{
if (secondSwappedBlock != -1) {
Rectangle firstRect = blockRect(blocks[firstSwappedBlock]);
firstRect.left += speed * deltaTime;
firstRect.right += speed * deltaTime;
SDL_Texture *texture = blockTexture(blocks[firstSwappedBlock]);
renderTexture(texture, renderer, (int)firstRect.left, (int)firstRect.top, (int)blockWidth, (int)blockHeight);
}
}
void Puzzle::SwapBlocks(const int first, const int second) const
{
if (first != second)
{
const int t = blocks[first];
blocks[first] = blocks[second];
blocks[second] = t;
}
}
Here is a minimal (yet fully working) example:
#include "SDL.h"
#include <assert.h>
/* linear interpolation between {start.x; start.y} and {end.x; end.y} */
static void rect_lerp(SDL_Rect *out, const SDL_Rect *start, const SDL_Rect *end, float f) {
float t = 1.0f - f;
out->x = (float)start->x * t + (float)end->x * f;
out->y = (float)start->y * t + (float)end->y * f;
}
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
SDL_Window *window = SDL_CreateWindow("example",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN);
assert(window);
SDL_Renderer *renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED);
assert(renderer);
int quit = 0;
int animate = 0;
Uint32 animation_start_time;
/* whole animation will play in e.g. one seconds */
const Uint32 animation_time_total = 1000;
SDL_Rect rect0 = {
.x = 0, .y = 0, .w = 128, .h = 128
};
SDL_Rect rect1 = {
.x = 256, .y = 256, .w = 128, .h = 128
};
while(!quit) {
/* time of current frame */
Uint32 tcurrent = SDL_GetTicks();
SDL_Event event;
while(SDL_PollEvent(&event)) {
if(event.type == SDL_KEYUP) {
if(event.key.keysym.sym == SDLK_ESCAPE) {
quit = 1;
break;
} else if(event.key.keysym.sym == SDLK_SPACE) {
animate = 1;
animation_start_time = tcurrent;
}
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_Rect r0 = rect0, r1 = rect1;
/* if not within animation - leave coordinates as they are */
if(animate) {
if(tcurrent > animation_start_time + animation_time_total) {
/* animation ends by now */
/* swap rect0 and rect1 and stop animation */
SDL_Rect t = rect0;
rect0 = rect1;
rect1 = t;
animate = 0;
/* need to update r0 and r1 too */
r0 = rect0;
r1 = rect1;
} else {
/* animation is incomplete - interpolate coordinates */
/* calculate current animation percentage - in range [0; 1] */
float factor = ((float)(tcurrent - animation_start_time)) / animation_time_total;
rect_lerp(&r0, &rect0, &rect1, factor);
rect_lerp(&r1, &rect1, &rect0, factor);
}
}
/* r0 and r1 now have correct coordinates, draw */
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &r0);
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
SDL_RenderDrawRect(renderer, &r1);
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
For sake of simplicity it draws rectangles instead of textures, but that could be easily changed.
As you can see, in that example I'm keeping old coordinates for as long as animation incomplete, and fixating it only when it is fully gone. This easily allows to replay it back and don't have problems with precision; but - if you'll try to press space when animation already playing, it will just restart.
Another way could be updating coordinates on each animation step (may have different update frequency then redraw); in that case, you'll need to keep current coordinates, destination coordinates (the ones that you'll reach once animation is complete) and, probably, start coordinates (to eliminate precision problems).