Animating shapes in SFML? - animation

I just wanted to animate a simple shape (rect for instance). This animation is only about changing the color of the shape whenever you press a determinated key.
I couldn't find any tutorial for this simple purpose, these online tutorials are all about sprite movement and all of that.
I managed to do this color change by creating a class named 'Transition' and a function within it named 'Transition::update()', which simply change the color of a shape created in this class. The code it's quite simple (thought it wasn't necessary to put it here).
The problem is that this animated I created it's not a smooth animation, just change the color at the right moment.
The question is obvious:
How could I give that smoothness to my animation?
(Don't need to put large codes here, just a quick advice that's all)

Basically you need to introduce variables which store the transition of the color and you need to control the time per frame. Let me give you a quick and very basic example, so you get the idea. Forgive me the style ...
#include <SFML/Graphics.hpp>
int main(){
sf::RenderWindow renderWindow(sf::VideoMode(800, 600), "Color Animation");
sf::Clock clock;
sf::Event event;
// Change to start the animation
// Red and blue to store the color transition
// Duration to control animation speed
int change = 0;
int red = 255;
int blue = 0;
float duration = float();
// Set a basic red circle as the starting shape
sf::Color color = sf::Color::Red;
sf::CircleShape circle(150);
circle.setFillColor(color);
while (renderWindow.isOpen()){
// How much time since last loop?
sf::Time dt = clock.restart();
duration += dt.asSeconds();
while (renderWindow.pollEvent(event)){
//Handle events here
if (event.type == sf::Event::EventType::Closed)
renderWindow.close();
//Respond to key pressed events
if (event.type == sf::Event::EventType::KeyPressed){
if (event.key.code == sf::Keyboard::C){
// C key pressed, start animation
change = 1;
}
}
}
// Animation started and animation duration per frame (0.01f) reached
// Change color by 1
if (change == 1 && duration > 0.01f){
red -= 1;
blue += 1;
if (red > 0){
// Reset frame time and set new color for circle
duration = 0;
color = sf::Color(red, 0, blue);
circle.setFillColor(color);
} else {
// Stop animation
change = 0;
}
}
// Clear render window and draw circle
renderWindow.clear(sf::Color::Black);
renderWindow.draw(circle);
renderWindow.display();
}
}

Related

Jumping realistic in Processing with PVectors

I tried to make a jump look realistic, while I watched through the Videos:
The Natur of Code - The Coding Train
I got into PVectors. I strongly recomend watching him. But to get to my question, everything seems to work, exept that it draws the rectangle (my PVector) the way I want.
void keyPressed() {
if (keyCode == UP) {
for (int i = 0; i < 16; i++) {
location.sub(velocity);
velocity.sub(acceleration);
h.display();
background(0);
}
velocity.set(0, 15);
}
}
That's the Code, I expect it to "jump", but nothing realy happens. You can see that the rectangle get's drawn again (on the same spot), but there's no movement. It's definitly an issue with the drawing of the background or something, I don't know what exaclty though.
The nature of your question is unclear. You mentioned issues regarding the background interfering with your rectangle after the UP arrow key is pressed. This is likely because background(0) is called immediately after h.display(). I would remove background(0) from your loop if it's a display issue.
Other than that, there seem to be other issues with the loop itself. When the UP key is pressed, h is affected by acceleration only for 16 frames. To make your object more realistic, gravity (or whatever acceleration you choose) should constantly be acting upon the object.
With that in mind, here's a solution for you.
void keyPressed() {
if (keyCode == UP) {
// Make the character 'jump' upwards when the UP arrow is pressed.
// Setting the velocity should be the only thing happening when the key is pressed.
velocity.set(0, -2);
}
}
void draw() {
// Reset the background each frame so rectangles don't overlap.
background(255);
// Always draw the rectangle AFTER resetting the canvas.
h.display();
// Change the object's location by it's velocity.
location.add(velocity);
// And chance the object's velocity by it's acceleration.
// Since acceleration is the acting force of gravity in this situation, acceleration need not be changed.
velocity.add(acceleration);
// Prevent the rectangle from falling through the bottom of the canvas.
if(location.y > height - 5) location.y = height - 5;
}
// You negleteced to define your variables in your code snippet. Here they are.
PVector location = new PVector(0, 0);
PVector velocity = new PVector(0, 0);
PVector acceleration = new PVector(0, 0.1); // Notice that acceleration's y-value is 0.01. This is so you can see the effect of gravity.
// Define your rectangle object.
Object h = new Object();
class Object {
Object() {} // Constructor.
void display() {
// Draw the rectangle at the x- and y-positions of the location vector.
// The '+ width/2' places it at the center of the screen.
rectMode(CENTER);
rect(location.x + width/2, location.y, 10, 10);
}
}

Why doesn't the RoundRect path with gradient fill produce the correct corners on right side?

I came up with a routine to create a gradient filled rounded rectangle (button), however if I omit the code that writes the outline, the lower-right corner looks square and the upper-right seems to be not quite right either . Why is that?
note: The owner-draw button was created 23x23.
//-------------------------------------------------------------------------
// Purpose: Draw a rounded rectangle for owner-draw button
//
// Input: dis - [i] owner-draw information structure
// undermouse - [i] flag if button is under mouse
//
// Output: na
//
// Notes: This creates a standard grey type rounded rectangle for owner
// drawn buttons.
//
// This routine does not currently use undermouse to change
// gradient
//
void DrawRoundedButtonRectangle(const DRAWITEMSTRUCT& dis, BOOL undermouse)
{
UNREFERENCED_PARAMETER(undermouse);
// save DC before we modify it.
SaveDC(dis.hDC);
// create a path for the round rectangle (right/bottom is RECT format of +1)
BeginPath(dis.hDC);
RoundRect(dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, dis.rcItem.bottom, 6, 6);
EndPath(dis.hDC);
// save DC before changing clipping region
SaveDC(dis.hDC);
// set clipping region to be the path
SelectClipPath(dis.hDC, RGN_COPY);
TRIVERTEX vertices[2];
// setup the starting location and color (light grey)
vertices[0].x = dis.rcItem.left;
vertices[0].y = dis.rcItem.top;
vertices[0].Red = MAKEWORDHL(211, 0);
vertices[0].Green = MAKEWORDHL(211, 0);
vertices[0].Blue = MAKEWORDHL(211, 0);
vertices[0].Alpha = 0xffff;
// setup the ending location and color (grey)
vertices[1].x = dis.rcItem.right; // should this be -1 ?
vertices[1].y = dis.rcItem.bottom; // should this be -1 ?
vertices[1].Red = MAKEWORDHL(150, 0);
vertices[1].Green = MAKEWORDHL(150, 0);
vertices[1].Blue = MAKEWORDHL(150, 0);
vertices[1].Alpha = 0xffff;
// setup index to use for left to right
GRADIENT_RECT r[1];
r[0].UpperLeft = 0;
r[0].LowerRight = 1;
// fill the DC with a vertical gradient
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
// go back to original clipping area
RestoreDC(dis.hDC, -1);
// change the path to be the outline border
if (WidenPath(dis.hDC)) {
// set clipping region to be the path
SelectClipPath(dis.hDC, RGN_COPY);
// create a gradient on the outline
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
}
// put back the DC as we received it
RestoreDC(dis.hDC, -1);
}
The red in the pics show the background.
The bad button is generated when the WidenPath section is removed.
According to your description, I think you may be talking about this situation.
BeginPath(dis.hDC);
// RoundRect(dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, dis.rcItem.bottom, 6, 6);
EndPath(dis.hDC);
Let me first analyze the reason why I got this shape.
When you redraw the button, if the length and width of the redrawn button are smaller than that of the button itself, only a part of the redrawn will occur.
case WM_CREATE:
{
//Button width:230 Button height:230
button = CreateRoundRectButton(hWnd, 500, 200, 230, 230, 30, 30, BTN_ID);
return 0;
}
break;
case WM_DRAWITEM:
{
DRAWITEMSTRUCT dis;
dis.CtlType = ODT_BUTTON;
dis.CtlID = BTN_ID;
dis.hDC = GetDC(button);
dis.rcItem.left = 0;
dis.rcItem.top = 0;
dis.rcItem.right = 200; //Width of redrawing
dis.rcItem.bottom = 200; //Height of redrawing
DrawRoundedButtonRectangle(dis, TRUE);
}
In order to see the effect more clearly, I will widen the width and height.
If I omit the code that writes the outline, It only executes the following code to implement the gradient.
// fill the DC with a vertical gradient
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
If I change the XY coordinates of the redrawing.
Actually, when you disable RoundRect, the only thing that works is GradientFill.
Updated:
The redrawn area is based on rcItem. When you draw a path, it's only the inside area that is considered and the outline is not, so WidenPath then goes on the outline and that gives the true routed rect area.

Drawing image(PGraphics) gives unwanted double image mirrored about x-axis. Processing 3

The code is supposed to fade and copy the window's image to a buffer f, then draw f back onto the window but translated, rotated, and scaled. I am trying to create an effect like a feedback loop when you point a camera plugged into a TV at the TV.
I have tried everything I can think of, logged every variable I could think of, and still it just seems like image(f,0,0) is doing something wrong or unexpected.
What am I missing?
Pic of double image mirror about x-axis:
PGraphics f;
int rect_size;
int midX;
int midY;
void setup(){
size(1000, 1000, P2D);
f = createGraphics(width, height, P2D);
midX = width/2;
midY = height/2;
rect_size = 300;
imageMode(CENTER);
rectMode(CENTER);
smooth();
background(0,0,0);
fill(0,0);
stroke(255,255);
}
void draw(){
fade_and_copy_pixels(f); //fades window pixels and then copies pixels to f
background(0,0,0);//without this the corners dont get repainted.
//transform display window (instead of f)
pushMatrix();
float scaling = 0.90; // x>1 makes image bigger
float rot = 5; //angle in degrees
translate(midX,midY); //makes it so rotations are always around the center
rotate(radians(rot));
scale(scaling);
imageMode(CENTER);
image(f,0,0); //weird double image must have something not working around here
popMatrix();//returns window matrix to normal
int x = mouseX;
int y = mouseY;
rectMode(CENTER);
rect(x,y,rect_size,rect_size);
}
//fades window pixels and then copies pixels to f
void fade_and_copy_pixels(PGraphics f){
loadPixels(); //load windows pixels. dont need because I am only reading pixels?
f.loadPixels(); //loads feedback loops pixels
// Loop through every pixel in window
//it is faster to grab data from pixels[] array, so dont use get and set, use this
for (int i = 0; i < pixels.length; i++) {
//////////////FADE PIXELS in window and COPY to f:///////////////
color p = pixels[i];
//get color values, mask then shift
int r = (p & 0x00FF0000) >> 16;
int g = (p & 0x0000FF00) >> 8;
int b = p & 0x000000FF; //no need for shifting
// reduce value for each color proportional
// between fade_amount between 0-1 for 0 being totallty transparent, and 1 totally none
// min is 0.0039 (when using floor function and 255 as molorModes for colors)
float fade_percent= 0.005; //0.05 = 5%
int r_new = floor(float(r) - (float(r) * fade_percent));
int g_new = floor(float(g) - (float(g) * fade_percent));
int b_new = floor(float(b) - (float(b) * fade_percent));
//maybe later rewrite in a way to save what the difference is and round it differently, like maybe faster at first and slow later,
//round doesn't work because it never first subtracts one to get the ball rolling
//floor has a minimum of always subtracting 1 from each value each time. cant just subtract 1 ever n loops
//keep a list of all the pixel as floats? too much memory?
//ill stick with floor for now
// the lowest percent that will make a difference with floor is 0.0039?... because thats slightly more than 1/255
//shift back and or together
p = 0xFF000000 | (r_new << 16) | (g_new << 8) | b_new; // or-ing all the new hex together back into AARRGGBB
f.pixels[i] = p;
////////pixels now copied
}
f.updatePixels();
}
This is a weird one. But let's start with a simpler MCVE that isolates the problem:
PGraphics f;
void setup() {
size(500, 500, P2D);
f = createGraphics(width, height, P2D);
}
void draw() {
background(0);
rect(mouseX, mouseY, 100, 100);
copyPixels(f);
image(f, 0, 0);
}
void copyPixels(PGraphics f) {
loadPixels();
f.loadPixels();
for (int i = 0; i < pixels.length; i++) {
color p = pixels[i];
f.pixels[i] = p;
}
f.updatePixels();
}
This code exhibits the same problem as your code, without any of the extra logic. I would expect this code to show a rectangle wherever the mouse is, but instead it shows a rectangle at a position reflected over the X axis. If the mouse is on the top of the window, the rectangle is at the bottom of the window, and vice-versa.
I think this is caused by the P2D renderer being OpenGL, which has an inversed Y axis (0 is at the bottom instead of the top). So it seems like when you copy the pixels over, it's going from screen space to OpenGL space... or something. That definitely seems buggy though.
For now, there are two things that seem to fix the problem. First, you could just use the default renderer instead of P2D. That seems to fix the problem.
Or you could get rid of the for loop inside the copyPixels() function and just do f.pixels = pixels; for now. That also seems to fix the problem, but again it feels pretty buggy.
If somebody else (paging George) doesn't come along with a better explanation by tomorrow, I'd file a bug on Processing's GitHub. (I can do that for you if you want.)
Edit: I've filed an issue here, so hopefully we'll hear back from a developer in the next few days.
Edit Two: Looks like a fix has been implemented and should be available in the next release of Processing. If you need it now, you can always build Processing from source.
An easier one, and works like a charm:
add f.beginDraw(); before and f.endDraw(); after using f:
loadPixels(); //load windows pixels. dont need because I am only reading pixels?
f.loadPixels(); //loads feedback loops pixels
// Loop through every pixel in window
//it is faster to grab data from pixels[] array, so dont use get and set, use this
f.beginDraw();
and
f.updatePixels();
f.endDraw();
Processing must know when it's drawing in a buffer and when not.
In this image you can see that works

How to add (not blend) non-looped animation clip to looped animation with Mecanim?

I have a GameObject with Animator and looped animation clip.
This animation changes X coordinate from 0 to 10 and back.
I need to add another animation to the first one that increases GameObject's scale and changes its color to red simultaneously.
After scale and color change GameObject keeps these parameters and continues to move according to the first animation clip.
The only way I managed to work it around is writing a custom script with couroutine:
IEnumerator Animate()
{
float scaleDelta = 0.2f;
float colorDelta = 0.02f;
for (int i = 0; i < 50; i++)
{
spriteRenderer.color = new Color(
spriteRenderer.color.r,
spriteRenderer.color.g - colorDelta,
spriteRenderer.color.b - colorDelta);
transform.localScale = new Vector3(
transform.localScale.x + scaleDelta,
transform.localScale.y + scaleDelta,
transform.localScale.z);
yield return new WaitForSeconds(0.02f);
}
}
This works for linear interpolation, but requires to write additional code and write even more code for non-linear transformations.
How can I achieve the same result with Mecanim?
Sample project link: https://drive.google.com/file/d/0B8QGeF3SuAgTU0JWNGd2RnpUU00/view?usp=sharing

Qt-OpenCV:How to display grayscale images(opencv) in Qt

I have a piece of code here.
This is a camera capture application using OpenCV and Qt(for GUI).
void MainWindow::on_pushButton_clicked()
{
cv::VideoCapture cap(0);
if(!cap.isOpened()) return;
//namedWindow("edges",1);
QVector<QRgb> colorTable;
for (int i = 0; i < 256; i++) colorTable.push_back(qRgb(i, i, i));
QImage img;
img.setColorTable(colorTable);
for(;;)
{
cap >> image;
cvtColor(image, edges, CV_BGR2GRAY);
GaussianBlur(edges, edges, cv::Size(7,7), 1.5, 1.5);
Canny(edges, edges, 0, 30, 3);
//imshow("edges", edges);
if(cv::waitKey(30) >= 0) break;
// change color channel ordering
//cv::cvtColor(image,image,CV_BGR2RGB);
img = QImage((const unsigned char*)(edges.data),
image.cols,image.rows,QImage::Format_Indexed8);
// display on label
ui->label->setPixmap(QPixmap::fromImage(img,Qt::AutoColor));
// resize the label to fit the image
ui->label->resize(ui->label->pixmap()->size());
}
}
Initially "edges" is displayed in red with green background.Then it switches to blue background. This switching is happening randomly.
How can I display white edges in a black background in a stable manner.
In short, add the img.setColorTable(colorTable); just before the // display on labelcomment.
For more details, you create your image and affect the color table at the begining of your code:
QImage img;
img.setColorTable(colorTable);
Then in the infinite loop, you are doing the following:
img = QImage((const unsigned char*)(edges.data), image.cols, image.rows, QImage::Format_Indexed8);
What happens is that you destroy the image created at the begining of your code, the color map for this new image is not set and thus uses the default resulting in a colored output.

Resources