Recent

Author Topic: Easy animate  (Read 8371 times)

aradeonas

  • Hero Member
  • *****
  • Posts: 824
Easy animate
« on: October 24, 2014, 01:15:02 am »
Hi,
Is there any easy way to make a shape several moves?
for example I have a rectangle and I want first move it 100px to right and  then 100px to down and  ... .
Yes I can do it with timer but I want to know is there an easy way in BGRABitmap to make these animate easier like a list of moves?

aradeonas

  • Hero Member
  • *****
  • Posts: 824
Re: Easy animate
« Reply #1 on: October 24, 2014, 05:54:38 pm »
If there is not a way,I will be glad if any one share idea with me.

Roland57

  • Sr. Member
  • ****
  • Posts: 421
    • msegui.net
Re: Easy animate
« Reply #2 on: October 24, 2014, 06:28:02 pm »
Hello, your question is too wide (I believe). I don't understand why you speak of BGRABitmap. Maybe you could post a piece of what you have done, to help us to see your problem.

I made an animated chessboard based on WinGraph unit. (To move a piece, click on the piece and then click on the square you wish to move it to.) Is it something like that ?



My projects are on Gitlab and on Codeberg.

aradeonas

  • Hero Member
  • *****
  • Posts: 824
Re: Easy animate
« Reply #3 on: October 24, 2014, 07:02:40 pm »
Quote
I don't understand why you speak of BGRABitmap
I don't understand too,I think because i wanted to paint it with BGRABitmap,but I can done it with anything.
Quote
Maybe you could post a piece of what you have done
For now I just change x and y for moving, but I think about animating like Adobe AfterEffect but simpler.
for example:
Code: [Select]
var
  c: integer;
  x1, y1, x2, y2, rx, ry, sx1, sy1, sx2, sy2, ex1, ey1, ex2, ey2, srx, sry, erx, ery: integer;
   col: TBGRAPixel;
begin
  col := BGRA(200,0,0,200);

  ctx.clearRect(0, 0, ClientWidth, ClientHeight);

  c := round([b]Value[/b]);

  sx1 := 100;
  sy1 := 100;
  sx2 := 100 + 40;
  sy2 := 100 + 40;

  ex1 := 100;
  ey1 := 100;
  ex2 := 100 + 200;
  ey2 := 100 + 400;

  srx := 100;
  sry := 100;
  erx := 10;
  ery := 10;

  x1 := sx1 + (ex1 - sx1) * c div 100;
  y1 := sy1 + (ey1 - sy1) * c div 100;
  x2 := sx2 + (ex2 - sx2) * c div 100;
  y2 := sx2 + (ey2 - sx2) * c div 100;
  rx := srx + (erx - srx) * c div 100;
  ry := sry + (ery - sry) * c div 100;


  bmp.FillRoundRectAntialias(x1, y1, x2, y2, rx, ry, col, [rrDefault]);

  bmp.Draw(Canvas, 0, 0, True);   
Value is percent of progress.
In this example in a progress I change a circle to a rounded rectangle but in this way I have to write code for each change.
If there is a way to makes frames and in each frame  do something its really simpler.
I want to ask about ideas before start.

circular

  • Hero Member
  • *****
  • Posts: 4195
    • Personal webpage
Re: Easy animate
« Reply #4 on: October 24, 2014, 07:47:09 pm »
Hi, there are no specific functions in BGRABitmap to do that. What you can do is to use a Timer and TBGRAVirtualScreen. You can put for example 15 ms for the timer and in the timer event, process the time interval and call InvalidateBitmap function of TBGRAVirtualScreen.

To know how much time has elapsed, you can compute the difference between the current date and the previous date:
Code: [Select]
procedure Timer1Timer(...)
var newTime: TDateTime;
begin
  Timer1.Enabled := false;
  newTime := Now;
  elapsedMs += (newTime - previousTime)*24*60*60*1000; //where elapsedMs is a global variable of type Double
  previousTime := newTime;
  ProcessTimeInterval;
  BGRAVirtualScreen1.RedrawBitmap;
  Timer1.Enabled := true; //by turning off and on again the timer, it ensures the same delay
end;

In the procedure ProcessTimeInterval, you need to determine the position in time. You can for example compute a number of ticks:
Code: [Select]
procedure ProcessTimeInterval;
const timeGrain = 15; //ms
var elapsedTicks: integer;
begin
  if (elapsedMs < 0) or (elapsedMs > 1000) then elapsedMs := 0; //ignore if the time has been changed
  elapsedTicks := trunc(elapsedMs/timeGrain);
  elapsedMs -= elapsedTicks*timeGrain;

  //move everything according to the value of elapsedTicks or add the value to a totalElapsedTicks value
end;

In the RedrawBitmap event of the virtual screen, you need to draw objects according to their new positions.

In order to have a series of movements, you can for example consider that if the total number of elapsed ticks is between 0 and 49, the object is in its first position (or trajectory), then between 50 and 99 in its second position, etc.
Conscience is the debugger of the mind

aradeonas

  • Hero Member
  • *****
  • Posts: 824
Re: Easy animate
« Reply #5 on: October 24, 2014, 08:04:20 pm »
Hi,
Thank you,I use your help in my code but do you have an idea about managing frames?
for example in frame 1 there is an circle an in frame 10 there is a rectangle so how we can make these between frames (2..9) automatically without making frame by frame?
and can you explain to me what is the TBGRAVirtualScreen usage and compare it with simple draw on the form?
(I searched about it but I cant found any thing.)
I hope my explain is clear.
« Last Edit: October 24, 2014, 08:47:32 pm by aradeonas »

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Easy animate
« Reply #6 on: October 24, 2014, 11:27:06 pm »
You can use some kind of state variable in TTimer. For example

Code: [Select]
type
  TForm1 = class...

  private
    animState: integer;
  end;
...
procedure Timer1Timer():
  animState:=(animState+1) mod 9;
  case animState of
    0: DrawCircle;
    8: DrawRectangle;
    else DrawSomethingElse;
  end;

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Re: Easy animate
« Reply #7 on: October 25, 2014, 12:26:14 am »
Men I see what you want to make. Like in Adobe Flash, the interpolations are automatic.

See attached source. It requires BGRABitmap AND BGRA-Controls installed (search them in the wiki).

On this example: a rectangle that is animated into a circle and vice versa.

Edit: Where I say 'Frame: ' and 'CurrentFrame' must be 'Tick' and 'CurrentTick' as circular explained. The real 'CurrentFrame' is the 'TimerCount'.

Code: [Select]
  private
    RX, RY, RWidth, RHeight, RLeft, RTop, RSpeed: integer;
    Increment: boolean;
    TimerCount: integer;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
begin
  { This draw the rounded rectangle }
  Bitmap.RoundRectAntialias(RLeft, RTop, RLeft + RWidth, RTop + RHeight,
    RX, RY, BGRABlack, 0, BGRABlack);
end;

procedure TForm1.BGRAVirtualScreen1Resize(Sender: TObject);
begin
  { Change size of rectangle }
  {RWidth := BGRAVirtualScreen1.Width;
  RHeight := BGRAVirtualScreen1.Height;}
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //DoubleBuffered := True; // avoid flickering
  //BGRAVirtualScreen1.DoubleBuffered := True; // avoid flickering

  RX := 0; // rounding x
  RY := 0; // rounding y

  RLeft := 0; // position x
  RTop := 0; // position y

  RWidth := 170; // width of the rectangle
  RHeight := 170; // height of the rectangle

  RSpeed := 2; // speed (in pixels)

  Increment := True; // switch

  TimerCount := 0;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
const
  FrameStep = 15;
var
  CurrentFrame: integer;
begin
  { Frames }
  Inc(TimerCount);
  CurrentFrame := TimerCount div FrameStep;
  Self.Caption := 'Frame: ' + IntToStr(CurrentFrame);

  { This switch Increment when it is a circle }
  if (RX >= RWidth div 2) or (RY >= RHeight div 2) then
    Increment := False
  { This switch Increment when it is a rectangle }
  else if (RX <= 1) or (RY <= 1) then
  begin
    RX := 1; // must be 1 to be visible
    RY := 1; // must be 1 to be visible
    Increment := True;
  end;

  { It will continue until frame 10 }
  if CurrentFrame <= 10 then
    { Change the options }
    if Increment then
    begin
      { Rounding }
      Inc(RX, RSpeed);
      Inc(RY, RSpeed);
      { Position }
      Inc(RLeft, RSpeed);
      Inc(RTop, RSPeed);
    end
    else
    begin
      { Rounding }
      Dec(RX, RSpeed);
      Dec(RY, RSpeed);
      { Position }
      Dec(RLeft, RSpeed);
      Dec(RTop, RSpeed);
    end;

  { Redraw }
  BGRAVirtualScreen1.RedrawBitmap;
end; 
« Last Edit: October 25, 2014, 04:19:15 am by 007 »

aradeonas

  • Hero Member
  • *****
  • Posts: 824
Re: Easy animate
« Reply #8 on: October 25, 2014, 08:38:32 am »
Yes!
@User137,@007 thank you for example,its really good.But a problem is hear that what can we do when we want change shape to for example triangle or  ...?

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Easy animate
« Reply #9 on: October 25, 2014, 02:50:52 pm »
You need to be much more specific than that, we don't know what to tell you yet. Change shape to triangle, from what? Once or repeatedly? How many frames does the transition take? Does it keep the formed shape or immediately start changing to other shape, then what shape? How many shapes are there in the whole animation and are they perhaps in random order?

There is other way to this animation, to blend 2 images from 1 to other by changing their alpha value. It's not so good on geometry but you can even blend a cat image into dog.

As for how to geometrically morph rectangle into circle, it's as 007 said, using rounded rectangle. To morph rectangle into triangle, you just move any of the 2 same side corners together. It's mathematical term is interpolation, look it up. It's easy to combine to the animState i showed.
« Last Edit: October 25, 2014, 02:56:59 pm by User137 »

aradeonas

  • Hero Member
  • *****
  • Posts: 824
Re: Easy animate
« Reply #10 on: October 25, 2014, 03:47:37 pm »
Yes you are right.I try to make a demo but I want to change any shape to any shape without any fading and just change size of shapes.
Excuse me because of my poor English,because that I cant explain clear for you.

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Re: Easy animate
« Reply #11 on: October 25, 2014, 04:20:45 pm »
There is no way, you must do the programming.

aradeonas

  • Hero Member
  • *****
  • Posts: 824
Re: Easy animate
« Reply #12 on: October 25, 2014, 04:32:30 pm »
Yes you are right and I am going to,Thank you for help for now and when I do something I will share it.

aradeonas

  • Hero Member
  • *****
  • Posts: 824
Re: Easy animate
« Reply #13 on: October 25, 2014, 10:34:01 pm »
Here you are:

Code: [Select]
procedure TForm1.Timer1Timer(Sender: TObject);
var
  col: TBGRAPixel;
  r, w: integer;
begin
  Tik+=1;
  if Tik>100 then Timer1.Enabled:=False;

  col := BGRA(200, 0, 0, 200);
  r := max(round(Tik) * 100 div 100, 25);
  w :=max(round(Tik / 2), 40);

  BMP1.FillRect(0, 0, 200, 200, clWhite);
  BMP1.FillRoundRectAntialias(75, 75, 125, 125, 100, 100, col, [rrDefault]);


  BMP2.FillRect(0, 0, 200, 200, clWhite);
  BMP2.FillRoundRectAntialias(100 - r, 100 - r, 100 + r, 100 + r, 100, 100, col, [rrDefault]);

  Mask.FillRect(0, 0, 200, 200, clBlack);
  Mask.FillRoundRectAntialias(100 - w, 100 - w, 100 + w, 100 + w, 20, 20, BGRAWhite, [rrDefault]);


  BMP3.FillRect(0, 0, 200, 200, clWhite);
  BMP2.ApplyMask(Mask);
  BMP3.PutImage(0, 0, BMP2, dmDrawWithTransparency);

  BMP1.Draw(Canvas, 50, 50, True);
  BMP2.Draw(Canvas, 300, 50, True);
  Mask.Draw(Canvas, 550, 50, True);
  BMP3.Draw(Canvas, 800, 50, True);
end;   
I made a mask of second shape and then grow first one in center of it.
It can be allot better but what is your opinion?
(See attachment)
« Last Edit: October 25, 2014, 11:03:08 pm by aradeonas »

 

TinyPortal © 2005-2018