Cocos2d-x 4.0 Lens3D and Waves3D Animations - c++

I used below code to make water like animation for background image
auto background = Sprite::create(TEX_MM_BG);
background->setPosition(Vec2(SW*0.5f, SH*0.5f));
auto nodeGrid = NodeGrid::create();
nodeGrid->addChild(background);
this->addChild(nodeGrid, 0);
ActionInterval* lens = Lens3D::create(10, Size(32, 24), Vec2(100, 180), 150);
ActionInterval* waves = Waves3D::create(10, Size(15, 10), 18, 15);
nodeGrid->runAction(RepeatForever::create(Sequence::create(waves,lens, NULL)));
Animation look is good. But it stops 10 seconds then play 10 seconds then again stops 10 seconds...it repeats. How to avoid stoping in middle ?

It doesn't stop it is applying waves effect followed by lens effect. While applying lens effect the animation of waves stops.
Correct way to code this will be to use a Spawn:
ActionInterval* lens = Lens3D::create(10, Size(32, 24), Vec2(100, 180), 150);
ActionInterval* waves = Waves3D::create(10, Size(15, 10), 18, 15);
// Spawn will run both effects at the same time.
auto lensWaveSpawn = Spawn::createWithTwoActions(lens, waves);
auto seq = Sequence::create(lensWaveSpawn, nullptr);
nodeGrid->runAction(RepeatForever::create(seq));

Related

Problem with drawing a clock with Direct2D

I am trying to draw a clock with Direct2D. The program correctly gets the current time, however the error is when Direct2D draws the clock, since it seems that the clock is out of date with the current time. To get the current time, use the GetLocalTime() function and then map the values to transform them to an angle, so that they can be drawn. How could I fix it?
...
renderTarget->BeginDraw();
renderTarget->Clear(ColorF(ColorF::Black));
GetLocalTime(&sysTime);
wstring text = L"Hour: " + to_wstring(sysTime.wHour)
+ L"\nMinute: " + to_wstring(sysTime.wMinute)
+ L"\nSecond: " + to_wstring(sysTime.wSecond);
brush->SetColor(ColorF(ColorF::White));
renderTarget->DrawTextW(text.c_str(), text.length(), textFormat, textRect, brush);
D2D1_POINT_2F centerPoint = Point2F(320, 240);
FLOAT hourAngle = map(sysTime.wHour%12, 0, 12, 0, 360);
FLOAT minuteAngle = map(sysTime.wMinute, 0, 60, 0, 360);
FLOAT secondAngle = map(sysTime.wSecond, 0, 60, 0, 360);
brush->SetColor(ColorF(ColorF::DeepPink));
renderTarget->DrawEllipse(D2D1::Ellipse(centerPoint, 150, 150), brush, 5);
renderTarget->SetTransform(Matrix3x2F::Rotation(secondAngle, centerPoint));
brush->SetColor(ColorF(ColorF::Blue));
renderTarget->DrawLine(centerPoint,Point2F(centerPoint.x,centerPoint.y + 150*0.9), brush, 10,lineStrokeStyle);
renderTarget->SetTransform(Matrix3x2F::Rotation(minuteAngle, centerPoint));
brush->SetColor(ColorF(ColorF::White));
renderTarget->DrawLine(centerPoint,Point2F(centerPoint.x,centerPoint.y + 150*0.7), brush, 10, lineStrokeStyle);
renderTarget->SetTransform(Matrix3x2F::Rotation(hourAngle, centerPoint));
brush->SetColor(ColorF(ColorF::GreenYellow));
renderTarget->DrawLine(centerPoint, Point2F(centerPoint.x,centerPoint.y + 150*0.5), brush, 10,lineStrokeStyle);
renderTarget->SetTransform(Matrix3x2F::Identity());
HRESULT hrErr = renderTarget->EndDraw();
if (hrErr != S_OK) {
MessageBox(hWnd, L"Direct2D Error", L"Direct2D Error", MB_OK | MB_ICONERROR);
SafeRelease(&brush);
SafeRelease(&renderTarget);
SafeRelease(&factory);
}
...
Yes, you can use GetLocalTime to get the current local date and time. The problem may be in mapping the time to an angle.
But these can be solved, because there are very detailed examples in MSDN.
Instead of calculating the coordinates for the lines, we can calculate the angle and then apply a rotation transform. The following code shows a function that draws one clock hand. The fAngle parameter gives the angle of the hand, in degrees.
void Scene::DrawClockHand(float fHandLength, float fAngle, float fStrokeWidth)
{
m_pRenderTarget->SetTransform(
D2D1::Matrix3x2F::Rotation(fAngle, m_ellipse.point)
);
// endPoint defines one end of the hand.
D2D_POINT_2F endPoint = D2D1::Point2F(
m_ellipse.point.x,
m_ellipse.point.y - (m_ellipse.radiusY * fHandLength)
);
// Draw a line from the center of the ellipse to endPoint.
m_pRenderTarget->DrawLine(
m_ellipse.point, endPoint, m_pStroke, fStrokeWidth);
}
This code draws a vertical line, starting from the center of the clock face and ending at the point endPoint. The line is rotated around the center of the ellipse by applying a rotation transform. The center point for the rotation is the center of ellipse that forms the clock face.
void Scene::RenderScene()
{
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue));
m_pRenderTarget->FillEllipse(m_ellipse, m_pFill);
m_pRenderTarget->DrawEllipse(m_ellipse, m_pStroke);
// Draw hands
SYSTEMTIME time;
GetLocalTime(&time);
// 60 minutes = 30 degrees, 1 minute = 0.5 degree
const float fHourAngle = (360.0f / 12) * (time.wHour) + (time.wMinute * 0.5f);
const float fMinuteAngle =(360.0f / 60) * (time.wMinute);
DrawClockHand(0.6f, fHourAngle, 6);
DrawClockHand(0.85f, fMinuteAngle, 4);
// Restore the identity transformation.
m_pRenderTarget->SetTransform( D2D1::Matrix3x2F::Identity() );
}
Refer: Drawing Clock Hands
Debug:
The whole code sample:
Direct2D Clock Sample

Cairo Fill with Transparency

I'm new to Cairo, trying to create text with transparent color and stroke. stroke color's transparency works but text fill color transparency transparency_value doesn't work.
If i reduce transparency_value , text color just gets darker(black) and increasing transparency_value makes text color brighter (green in my case)
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480);
cairo_t* cairo = cairo_create(surface);
cairo_set_font_face(cairo, myfont_face);
cairo_set_font_size(cairo, 25);
cairo_text_extents_t extents;
cairo_text_extents(cairo, "Hello World", &extents);
cairo_move_to(cairo, 200, 200);
cairo_text_path(cairo, "Hello World");
double transparency_value = 0.5;
cairo_set_source_rgba(cairo, 0,1,0,transparency_value ); //transparency doesn't work
//cairo_fill(cairo); //this didn't make a difference
cairo_fill_preserve(cairo);
cairo_set_source_rgba(cairo, 0.56, 0.76, 0.96, 0.5); //transparency works
cairo_set_line_width(cairo, 1.5);
cairo_stroke(cairo);
Could it be that you are drawing your text outside of the surface? In the following example I added a call to cairo_move_to(cr, 200, 200) and now I get the following result. (This is written in Lua and uses https://github.com/pavouk/lgi to call into cairo; comments indicate things that I changed compared to your version)
local cairo = require("lgi").cairo
local surface = cairo.ImageSurface.create(cairo.Format.ARGB32, 640, 480)
local cr = cairo.Context(surface)
local myfont_face = cr:get_font_face() -- I have to get this from somewhere
cr:move_to(200, 200) -- I added this line to make something appear
cr:set_font_face(myfont_face)
cr:set_font_size(25)
cr:text_path("Hello World")
local transparency_value = 0.5
cr:set_source_rgba(0, 1, 0, transparency_value)
-- cr:fill()
cr:fill_preserve()
cr:set_source_rgba(0.65, 0.76, 0.96, 0.5)
cr:set_line_width(5) -- changed from 1.5 to 5 to make it more prominent
cr:stroke()
surface:write_to_png("/tmp/out.png")
Edit: And this is the result when I change transparency_value to 0.1. Clearly, the result is different and transparency works correctly (when zooming in, you still see some faint green in the middle).

Improve performance custom progress bar animation

I am looking to have a customized progress bar whose progress changes via a custom animation. I will have quite a number of instances of this widget and all of them should run smoothly and fast.
My first attempt was to use a regular QProgressBar, customize it by using a stylesheet and then using QPropertyAnimation to animate the change in status.
This works fine but is extremely slow. Say, I start my animation at a value of 0% and go up to 50% and want this to be accomplished during a duration of 500 msec. It is not smooth at all, but there are three clearly distinguishable steps. If I drop the stylesheet, it will work smoothly enough.
Well, what seems to work fine is using a derived class of QProgressBar, it is much faster than using stylesheets, although I have to custom-adjust the width and height:
void ColorBar::paintEvent(QPaintEvent *pe)
{
QRect region = pe->rect();
QPainter painter(this);
QColor borderColor;
borderColor.setNamedColor("#a0a0a0");
QColor lightColor = QColor(255, 255, 255);
QColor darkColor = QColor(225, 225, 225);
int barHeight = static_cast<int>(height() * 1. / 4. + 0.5);
QRect drawRect(0, static_cast<int>(height() / 2. - barHeight / 2. + 0.5), width() * .9 * value() / maximum(), barHeight);
QLinearGradient g(drawRect.topLeft(), drawRect.bottomLeft());
g.setColorAt(0., lightColor);
g.setColorAt(1., darkColor);
painter.setPen(QPen(borderColor));
painter.setBrush(QBrush(g));
painter.drawRect(drawRect);
}
Animating this bar is then straightforward and fast:
QPropertyAnimation* x = new QPropertyAnimation(percentageBar, "value");
x->setStartValue(percentageBar->value());
x->setEndValue(newValue);
x->setDuration(500);
x->start();
Still open for feedback or better solutions!

cocos2dx action error: liquid, wave3d and lens3d

Now I'm following article http://www.cocos2d-x.org/wiki/Effects. Examples of the link make errors.
Tested cocos2d-x version is cocos2d-x 3.2beta0.
My code:
auto bgimage = Sprite::create("top.png");
bgimage->setPosition(visibleSize / 2);
// create a Lens3D action
ActionInterval* lens = Lens3D::create(10, Size(32, 24), Vec2(100, 180), 150);
// create a Waved3D action
ActionInterval* waves = Waves3D::create(10, Size(15, 10), 18, 15);
// create a sequence an repeat it forever
bgimage->runAction(RepeatForever::create(Sequence::create(waves, lens, NULL)));
this->addChild(bgimage);
result logs:
Assert failed: GridActions can only used on NodeGrid
Assertion failed!
File: CCActionGrid.cpp
Line: 84
What did I mistake? even I remove liquid action line, wave3d and lens3d also show me same error.
The assertion is clear. You must use NodeGrid if you want use GridActions like Lens3D or Waves3D. If you want use this action, create NodeGride, add your sprite to them, and run action on NodeGrid.
auto bgimage = Sprite::create("top.png");
bgimage->setPosition(visibleSize / 2);
// create a Lens3D action
ActionInterval* lens = Lens3D::create(10, Size(32, 24), Vec2(100, 180), 150);
// create a Waved3D action
ActionInterval* waves = Waves3D::create(10, Size(15, 10), 18, 15);
// create a sequence an repeat it forever
auto nodeGrid = NodeGrid::create();
nodeGrid->addChild(bgimage);
nodeGrid->runAction(RepeatForever::create(Sequence::create(waves, lens, NULL)));
this->addChild(nodeGrid);

How to rotate text for drawText?

I would like to rotate the text 45 degrees?
QFont font;
font.setPixelSize(12);
//grid
for(int i = 0; i < 10; i++){
painter->drawLine(100, 100 + i * 800/9, 900, 100 + i * 800/9);
str = QString::number((double)9 - i, 'd', 1);
painter->setFont(font);
painter->drawText(75, 100 + i * 800/9 - 6, 40, 40, 1, str);
}
Insert painter->rotate(45); before painter->drawText(75, 100 + i * 800/9 - 6, 40, 40, 1, str); and painter->rotate(-45); after (to restore the rotation angle of the coordinate system):
painter->rotate(45);
painter->drawText(75, 100 + i * 800/9 - 6, 40, 40, 1, str);
painter->rotate(-45);
Depending on if you mean 45 degrees clockwise or anti-clockwise you may need to negate the rotation angles.
After you rotate the coordinate system, everything you paint will be painted rotated until you restore the painter. A convenient way of saving and restoring the state of the painter is using QPainter::save() and QPainter::restore().
painter->save(); // saves current painter state
// painter->rotate(45); clockwise rotation
// painter->rotate(-45); counter clockwise rotation
painter->restore(); // restores painter state
In order to rotate your text (and any other drawable object) drawn by painter just call
painter->rotate(yourAngle);
before
painter->drawText();
If you wish to return to previous state call rotate again.
painter->rotate(-yourAngle);
Why making such a simple task so complicated?!!!
void CustomLabel::paintEvent(QPaintEvent* e)
{
QPainter painter(this);
painter.translate(m_rect.center());
painter.rotate(m_rotation);
painter.translate(-m_rect.center());
painter.drawText(m_rect, Qt::AlignHCenter | Qt::AlignVCenter, m_text);
QWidget::paintEvent(e);
}
any time the container of CustomLabel changes it size you can set the m_rect or use the this->rect() itself.