Mouse control is lost after using vtk interactor - c++

I'm trying to visualize a vtk unstructuredgrid mesh.
In order to get the coordinate of a point of my mesh I use the vtk interactor.
I'm able to get the point coordinate by selecting the point using OnRightButtonDown() "overrid"
. However, I loose control of my window . means I can not rotate, translate or zoom my mesh.
I tried to do use OnRightButtonDoubleClick() but this doesn't seem to work . Any idea how may I
get the node coordinate using the interactor without affecting the mouse event behavior or how to re-initialize it when the mouse button is Up...
foo
{
...
// vtk visualization
container = new QWidget(ui->graphicsView);
qvtkWidget = new QVTKOpenGLNativeWidget(container);
...
//Create and link the mapper actor and renderer together.
mapper = vtkSmartPointer<vtkDataSetMapper>::New();
actor = vtkSmartPointer<vtkActor>::New();
renderer = vtkSmartPointer<vtkRenderer>::New();
...
// add elements nodes
...
mapper->SetInputData(eleNodeIdsPtr);
actor->SetMapper(mapper);
renderer->AddActor(actor);
// ste up camera
renderer->SetBackground(0.06, 0.2, 0.5);
double pos[3] = { 0, 0.2, 1 };
double focalPoint[3] = { 0, 0, 0 };
double viewUp[3] = { 1, 1, 1 };
renderer->GetActiveCamera()->SetPosition(pos);
renderer->GetActiveCamera()->SetFocalPoint(focalPoint);
renderer->GetActiveCamera()->SetViewUp(viewUp);
renderer->GetActiveCamera()->Zoom(0.5);
//Add render
qvtkWidget->GetRenderWindow()->AddRenderer(renderer);
qvtkWidget->show();
// Select node
renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(qvtkWidget-
>GetRenderWindow());
vtkNew<InteractorStyle2> style;
renderWindowInteractor->SetInteractorStyle(style);
style->eleNodeIdsPtr = eleNodeIdsPtr;
style->xyzGlobalPtr = xyzGlobalPtr;
renderWindowInteractor->Initialize();
}
// Define interaction style
class InteractorStyle2 : public vtkInteractorStyleTrackballActor
{
public:
static InteractorStyle2* New();
vtkTypeMacro(InteractorStyle2, vtkInteractorStyleTrackballActor);
vtkNew<vtkNamedColors> color;
...
void OnLeftButtonDown() //...>>>This doesn't work!!
{
}
void OnLeftButtonDown() override // .. this work but the I can't controle the transformation anymore!!
{
this->PointPicker = vtkSmartPointer<vtkPointPicker>::New();
// Get the selected point
int x = this->Interactor->GetEventPosition()[0];
int y = this->Interactor->GetEventPosition()[1];
this->FindPokedRenderer(x, y);
this->PointPicker->Pick(this->Interactor->GetEventPosition()[0],
this->Interactor->GetEventPosition()[1],
0, // always zero.
this->Interactor->GetRenderWindow()
->GetRenderers()
->GetFirstRenderer());
if (this->PointPicker->GetPointId() >= 0)
{
this->StartPan();
this->SelectedPoint = this->PointPicker->GetPointId();
double p[3];
this->eleNodeIdsPtr->GetPoint(this->SelectedPoint, p);
std::cout << "p: " << p[0] << " " << p[1] << " " << p[2] << std::endl;
}
}
vtkSmartPointer<vtkPointPicker> PointPicker;
vtkIdType SelectedPoint;
vtkSmartPointer<vtkUnstructuredGrid> eleNodeIdsPtr;
vtkSmartPointer< vtkPoints > xyzGlobalPtr;
}
vtkStandardNewMacro(InteractorStyle2);
}

You should call the OnLeftButtonDown (or up) of the parent class, by adding this line at the end of your method impl:
vtkInteractorStyleTrackballActor::OnLeftButtonDown();
A similar example

Related

My kinematic body position and scale are different than the expected position and scale

I'm trying to create a physics system for my "game engine" using Box2D, And when i create a b2_kinematicBody The position is bigger than the expected position and the scale is small than the expected scale.
I tried to change the SetAsBox parameters with SetAsBox(this->transform->scale.x, transform->scale.y) and the same problem
NOTE: For the rendering i'm using SDL2 and the positions are based in the SDL2 positions.
Example of the error
And here is a video of the problem: https://youtu.be/0fMPh8Rk_pY
This is the code of my KinematicBody2D class.
KinematicBody2D.h
class KinematicBody2D : public Component
{
private:
b2BodyDef k_bodydef;
b2Body* k_body;
b2FixtureDef k_fixtureDef;
b2Fixture *k_fixture;
b2World* k_world;
b2PolygonShape polygonShape;
public:
KinematicBody2D();
KinematicBody2D(Scene scene);
void Start() override;
void Loop(float delta) override;
void MovePosition(Vector2 target);
};
KinematicBody2D.cpp (Just the important part)
void KinematicBody2D::Start()
{
this->k_bodydef.type = b2BodyType::b2_kinematicBody;
this->k_bodydef.position = b2Vec2(this->transform->position.x, this->transform->position.y);
this->k_bodydef.angle = Math::Deg2Rad(this->transform->rotation);
this->k_body = this->k_world->CreateBody(&this->k_bodydef);
this->polygonShape.SetAsBox((this->transform->scale.x / 2.0f), (this->transform->scale.y / 2.0f));
this->k_fixtureDef.shape = &this->polygonShape;
this->k_fixture = this->k_body->CreateFixture(&this->k_fixtureDef);
}
void KinematicBody2D::Loop(float delta)
{
this->transform->position.x = this->k_body->GetPosition().x;
this->transform->position.y = this->k_body->GetPosition().y;
this->transform->rotation = Math::Rad2Deg(this->k_body->GetAngle());
this->polygonShape.SetAsBox((this->transform->scale.x / 2.0f), (this->transform->scale.y / 2.0f));
this->transform->scale = Vector2(this->transform->scale.x, this->transform->scale.y);
return;
}
main.cpp (Just the important part)
int main()
{
GameObject playerObj = GameObject("Player");
Scene scene = Scene("Scene", &playerObj);
playerObj.AddComponent<Sprite>("res/Player.png", Vector4(0, 0, 256, 256),
Vector2(64, 64));
playerObj.AddComponent<Rigidbody2D>(scene);
playerObj.AddComponent<Player>(app.GetRawRenderer());
GameObject floor = GameObject("Floor", "Floor");
floor.AddComponent<Sprite>("res/World 1.png");
floor.AddComponent<KinematicBody2D>(scene);
floor.transform.position = Vector2(100, 200);
}

Visual Studio 2017 Exception Unhandled

I'm a novice programmer trying to follow a tuturial on recreating a game on Steam called Timber(I believe). The program was working fine and I had almost completed the tutrial, but I ran into trouble when I added the code:
for (int i = 0 < NUM_BRANCHES; i++;)
{
branches[i].setTexture(textureBranch);
branches[i].setPosition(-2000, -2000);
// Set the sprite's origin to dead center
// We can then spin it around without changing its position
branches[i].setOrigin(220, 20);
}
Visual Studio says: branches[i].setPosition(-2000, -2000); Unhandled exception thrown: write access violation.
this was 0x59AF28. occurred
I'll also post the full code, apologies that it's a bit messy.
#include "stdafx.h"
#include <sstream>
#include <SFML\Graphics.hpp>
using namespace sf;
// Function declaration
void updateBranches(int seed);
const int NUM_BRANCHES = 6;
Sprite branches[NUM_BRANCHES];
// Where is the player/branch?
// Left or right
enum class side{ LEFT, RIGHT, NONE };
side branchPositions[NUM_BRANCHES];
int main()
{
// Creates a video mode object
VideoMode vm(1920, 1080);
// Creates and opens a window for the game
RenderWindow window(vm, "Timber!!!", Style::Fullscreen);
// Create a texture to hold a graphic on the GPU
Texture textureBackground;
// Load a graphic into the texture
textureBackground.loadFromFile("graphics/background.png");
// Create a sprite
Sprite spriteBackground;
// Attach the texture to the sprite
spriteBackground.setTexture(textureBackground);
// Set the spriteBackground to cover the screen
spriteBackground.setPosition(0, 0);
// Make a tree sprite
Texture textureTree;
textureTree.loadFromFile("graphics/tree.png");
Sprite spriteTree;
spriteTree.setTexture(textureTree);
spriteTree.setPosition(810, 0);
// Prepare the bee
Texture textureBee;
textureBee.loadFromFile("graphics/bee.png");
Sprite spriteBee;
spriteBee.setTexture(textureBee);
spriteBee.setPosition(0, 450);
// Is the be currently moving?
bool beeActive = false;
// How fast can the bee fly
float beeSpeed = 0.0f;
// Make 3 cloud sprites from 1 texture
Texture textureCloud;
// Load 1 new texture
textureCloud.loadFromFile("graphics/cloud.png");
// 3 new sprites with the same texture
Sprite spriteCloud1;
Sprite spriteCloud2;
Sprite spriteCloud3;
spriteCloud1.setTexture(textureCloud);
spriteCloud2.setTexture(textureCloud);
spriteCloud3.setTexture(textureCloud);
// Position the clouds off screen
spriteCloud1.setPosition(0, 0);
spriteCloud2.setPosition(0, -150);
spriteCloud3.setPosition(0, -300);
// Are the clouds currently on the screen?
bool cloud1Active = false;
bool cloud2Active = false;
bool cloud3Active = false;
// How fast is each cloud?
float cloud1Speed = 0.1f;
float cloud2Speed = 0.2f;
float cloud3Speed = 0.3f;
// Variables to control time itself
Clock clock;
// Time bar
RectangleShape timeBar;
float timeBarStartWidth = 400;
float timeBarHeight = 80;
timeBar.setSize(Vector2f(timeBarStartWidth, timeBarHeight));
timeBar.setFillColor(Color::Red);
timeBar.setPosition((1920 / 2) - timeBarStartWidth / 2, 980);
Time gameTimeTotal;
float timeRemaining = 6.0f;
float timeBarWidthPerSecond = timeBarStartWidth / timeRemaining;
// Track whether the game is running
bool paused = true;
// Draw some text
int score = 0;
sf::Text messageText;
sf::Text scoreText;
// Font
Font font;
font.loadFromFile("fonts/KOMIKAP_.ttf");
// Set the font of our message
messageText.setFont(font);
scoreText.setFont(font);
// Assign the actual message
messageText.setString("Press Enter to Start!");
scoreText.setString("score = 0");
// Make text really big
messageText.setCharacterSize(75);
scoreText.setCharacterSize(100);
// Choose a color
messageText.setFillColor(Color::White);
scoreText.setFillColor(Color::Black);
// Position the text
FloatRect textRect = messageText.getLocalBounds();
messageText.setOrigin(textRect.left +
textRect.width / 2.0f,
textRect.top +
textRect.height / 2.0f);
messageText.setPosition(1920 / 2.0f, 1080 / 2.0f);
scoreText.setPosition(20, 20);
// Prepare 6 branches
Texture textureBranch;
textureBranch.loadFromFile("graphics/branch.png");
// Set the texture for each branch sprite
for (int i = 0 < NUM_BRANCHES; i++;)
{
branches[i].setTexture(textureBranch);
branches[i].setPosition(-2000, -2000);
// Set the sprite's origin to dead center
// We can then spin it around without changing its position
branches[i].setOrigin(220, 20);
}
while (window.isOpen())
{
/*
**************
Handles the player input
**************
*/
if (Keyboard::isKeyPressed(Keyboard::Escape))
{
window.close();
}
// Start the game
if (Keyboard::isKeyPressed(Keyboard::Return))
{
paused = false;
// Reset the time and the score
score = 0;
timeRemaining = 5;
}
/*
**************
Update the scene
**************
*/
if (!paused)
{
// Measure time
Time dt = clock.restart();
// Subtract from the amount of time remaining
timeRemaining -= dt.asSeconds();
// size up the time bar
timeBar.setSize(Vector2f(timeBarWidthPerSecond *
timeRemaining, timeBarHeight));
if (timeRemaining <= 0.0f)
{
// Pause the game
paused = true;
// Change the message shown to the player
messageText.setString("Out of time");
// Reposition the text base on its new size
FloatRect textRect = messageText.getLocalBounds();
messageText.setOrigin(textRect.left +
textRect.width / 2.0f,
textRect.top +
textRect.height / 2.0f);
messageText.setPosition(1920 / 2.0f, 1080 / 2.0f);
}
// Setup the bee
if (!beeActive)
{
// How fast is the bee
srand((int)time(0) * 10);
beeSpeed = (rand() % 400) + 350;
// How high is the bee
srand((int)time(0) * 10);
float height = (rand() % 650) + 850;
spriteBee.setPosition(1921, height);
beeActive = true;
}
else
// Move the bee
{
spriteBee.setPosition(
spriteBee.getPosition().x -
(beeSpeed * dt.asSeconds()),
spriteBee.getPosition().y);
// Has the bee reached the right hand edge of the screen?
if (spriteBee.getPosition().x < -100)
{
// Set it up ready to be a whole new bee next frame
beeActive = false;
}
}
// Manage the clouds
// Cloud 1
if (!cloud1Active)
{
// How fast is the cloud
srand((int)time(0) * 10);
cloud1Speed = (rand() % 150);
// How high is the cloud
srand((int)time(0) * 10);
float height = (rand() % 200);
spriteCloud1.setPosition(-300, height);
cloud1Active = true;
}
else
{
spriteCloud1.setPosition(
spriteCloud1.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud1.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud1.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud1Active = false;
}
}
// Cloud 2
if (!cloud2Active)
{
// How fast is the cloud
srand((int)time(0) * 20);
cloud2Speed = (rand() % 200);
// How high is the cloud
srand((int)time(0) * 20);
float height = (rand() % 300);
spriteCloud2.setPosition(-200, height);
cloud2Active = true;
}
else
{
spriteCloud2.setPosition(
spriteCloud2.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud2.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud2.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud2Active = false;
}
}
// Cloud 3
if (!cloud3Active)
{
// How fast is the cloud
srand((int)time(0) * 30);
cloud3Speed = (rand() % 250);
// How high is the cloud
srand((int)time(0) * 30);
float height = (rand() % 150);
spriteCloud3.setPosition(-100, height);
cloud3Active = true;
}
else
{
spriteCloud3.setPosition(
spriteCloud3.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud3.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud3.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud3Active = false;
}
}
// Update the score text
std::stringstream ss;
ss << "Score = " << score;
scoreText.setString(ss.str());
// Update the branch sprites
for (int i = 0; i < NUM_BRANCHES; i++)
{
float height = i * 150;
if (branchPositions[i] == side::LEFT)
{
// Move the sprite to the left side
branches[i].setPosition(610, height);
// Flip the sprite around the other way
branches[i].setRotation(180);
}
else if (branchPositions[i] == side::RIGHT)
{
// Move the sprite to the right side
branches[i].setPosition(1330, height);
// Set the sprite rotation to normal
branches[i].setRotation(0);
}
else
{
// Hide the branch
branches[i].setPosition(3000, height);
}
}
} // End if(!paused)
/*
**************
Draw the scene
**************
*/
// Clear everything from the last frame
window.clear();
// Draw our game scene here
window.draw(spriteBackground);
// Draw the clouds
window.draw(spriteCloud1);
window.draw(spriteCloud2);
window.draw(spriteCloud3);
// Draw the branches
for (int i = 0; i < NUM_BRANCHES; i++)
{
window.draw(branches[i]);
}
// Draw the tree
window.draw(spriteTree);
// Draw the insect
window.draw(spriteBee);
// Draw the score
window.draw(scoreText);
//Draw the timebar
window.draw(timeBar);
if (paused)
{
// Draw our message
window.draw(messageText);
}
// Show everyting we just drew
window.display();
}
return 0;
}
// Function definition
void updateBranches(int seed)
{
// Move all the branches down on place
for (int j = NUM_BRANCHES - 1; j > 0; j--)
{
branchPositions[j] = branchPositions[j - 1];
}
// Spawn a new branch at postion 0
// LEFt, RIGHT, NONE
srand((int)time(0) + seed);
int r = (rand() % 5);
switch (r)
{
case 0:
branchPositions[0] = side::LEFT;
break;
case 1:
branchPositions[0] = side::RIGHT;
break;
default:
branchPositions[0] = side::NONE;
break;
}
}
setPosition() requires an sf::Vector2f. So you could fix your code by changing that line to:
branches[i].setPosition(sf::Vector2f(-2000, -2000))

Vtk Qt scene with >50 (moving) actors

I am trying to implement (fairly) simple scene where I have ~50 cubes which are moving in certain directions. The position of the cubes changes 20 times per second.
My first shoot was adding and removing actors from the scene. This approach just doesn't scale. Whole scene lags and user is unable to move the camera.
void draw(vtkRenderer *renderer)
{
renderer->RemoveAllViewProps();
for(const Cube& cube : cubes_)
{
vtkSmartPointer<vtkCubeSource> cube_source = vtkSmartPointer<vtkCubeSource>::New();
cube_source->Update();
cube_source->SetXLength(cube.lengt());
cube_source->SetYLength(cube.width());
cube_source->SetZLength(cube.height());
vtkSmartPointer<vtkPolyDataMapper> poly_mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
poly_mapper->SetInputConnection(cube_source->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(poly_mapper);
actor->SetPosition(cube.x(), cube.y(), cube.z());
renderer->AddActor(actor);
}
}
Second shot is a bit better. I have created "actor pool" where I reuse the actors and hide the ones which are not needed.
Still, moving camera is laggy and the rest of my UI (I have some additional widgets inside Vtk widget) seems to be laggy.
I couldn't find any relevant source for Vtk where scene is "dynamic". All examples preload all scene elements and further work with them. Can anyone tell me what am I doing wrong here?
this my visualization VTK example
.....
vtkSmartPointer<vtkRenderer> m_vtkRenderer;
vtkSmartPointer<MouseInteractor> m_mouseInteractor;
QVector<vtkActor* > m_parcellationActors;
QVector<vtkActor* > m_electrodesActors;
QVector<vtkFollower* > m_textActors;
QVector<vtkActor*> m_vectorFieldsActors;
QVector<vtkActor*> m_streamlinesActors;
......
void VisualizationWidget::create3DViewArea()
{
m_3DViewArea = new QStackedWidget(this);
m_vtkWidget = new QVTKWidget(m_3DViewArea);
m_vtkRenderer = vtkSmartPointer<vtkRenderer>::New();
m_vtkRenderer->SetBackground(0.4, 0.4, 0.4);
this->m_vtkWidget->GetRenderWindow()->AddRenderer(m_vtkRenderer);
m_mouseInteractor = vtkSmartPointer<MouseInteractor>::New();
m_mouseInteractor ->SetDefaultRenderer(m_vtkRenderer);
this->m_vtkWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle( m_mouseInteractor);
connect(m_mouseInteractor, &MouseInteractor::onActorSelected, this, &VisualizationWidget::onActorSelectedSlot);
m_vtkLoadingWidget = new LoadingWidget(m_3DViewArea);
m_vtkLoadingWidget->setIconPath(Icon::s_getTDCSLoadingGif);
m_3DViewArea->addWidget(m_vtkLoadingWidget);
m_3DViewArea->addWidget(m_vtkWidget);
}
void VisualizationWidget::setParcellationActors(QVector<vtkActor*> actors)
{
m_parcellationActors = actors;
for (int i = 0; i < m_parcellationActors.size(); ++i) {
m_vtkRenderer->AddActor(m_parcellationActors.at(i));
}
m_vtkWidget->update();
}
void VisualizationWidget::setElectrodesActors(QVector<vtkActor*> actors)
{
m_electrodesActors = actors;
for (int i = 0; i < m_electrodesActors.size(); ++i) {
m_vtkRenderer->AddActor(m_electrodesActors.at(i));
}
m_vtkWidget->update();
}
void VisualizationWidget::setElectrodesLabelsActors(QVector<vtkFollower*> actors)
{
m_textActors = actors;
for (int i = 0; i < m_textActors.size(); ++i) {
m_textActors.at(i)->SetCamera(m_vtkRenderer->GetActiveCamera());
m_vtkRenderer->AddActor(m_textActors.at(i));
}
m_vtkRenderer->ResetCamera();
m_vtkWidget->update();
}
void VisualizationWidget::setVectorFieldsActors(QVector<vtkActor*> actors)
{
for (int i = 0; i < m_vectorFieldsActors.size(); ++i) {
m_vtkRenderer->RemoveActor(m_vectorFieldsActors.at(i));
}
m_vectorFieldsActors = actors;
for (int i = 0; i < m_vectorFieldsActors.size(); ++i) {
changeActorOpacity(m_vectorFieldsActors[i], double(m_postProcResOpacSliders.at(i)->value()) / m_postProcResOpacSliders.at(i)->maximum());
m_vtkRenderer->AddActor(m_vectorFieldsActors.at(i));
}
m_vtkRenderer->ResetCamera();
m_vtkWidget->update();
}
void VisualizationWidget::setStreamlinesActors(QVector<vtkActor*> actors)
{
for (int i = 0; i < m_streamlinesActors.size(); ++i) {
m_vtkRenderer->RemoveActor(m_streamlinesActors.at(i));
}
m_streamlinesActors = actors;
for (int i = 0; i < m_streamlinesActors.size(); ++i) {
changeActorOpacity(m_streamlinesActors[i], double(m_streamLinesSlider->value()) / m_streamLinesSlider->maximum());
m_vtkRenderer->AddActor(m_streamlinesActors.at(i));
}
m_vtkRenderer->ResetCamera();
m_vtkWidget->update();
}
void VisualizationWidget::changeActorOpacity(vtkActor* actor, double opac)
{
actor->SetVisibility(opac > 0.05);
actor->GetMapper()->Modified();
actor->GetProperty()->SetOpacity(opac);
}
So afther some days of reaserch I managed to hack working solution:
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
// as many points as you like
points->InsertNextPoint(-25, 0, 0);
points->InsertNextPoint(-35, 0, 0);
vtkSmartPointer<vtkFloatArray> scales = vtkSmartPointer<vtkFloatArray>::New();
scales->SetNumberOfComponents(3);
// same as number of points
scales->InsertNextTuple3(1, 1., 8.);
scales->InsertNextTuple3(1., 1., 10.);
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata->SetPoints(points);
polydata->GetPointData()->SetVectors(scales);
vtkSmartPointer<vtkCubeSource> cubeSource = vtkSmartPointer<vtkCubeSource>::New();
vtkSmartPointer<vtkGlyph3D> glyph3D = vtkSmartPointer<vtkGlyph3D>::New();
glyph3D->OrientOff(); // disable orientation
glyph3D->SetScaleModeToScaleByVectorComponents(); // sacle along each axis
glyph3D->SetSourceConnection(cubeSource->GetOutputPort());
glyph3D->SetInputData(polydata);
glyph3D->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(glyph3D->GetOutputPort());
mapper->ScalarVisibilityOff(); // use color from actor
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->GetProperty()->SetColor(0, 1, 0); // this will change color for whole glyph
actor->SetMapper(mapper);
mapper->Update();
vtk_renderer->AddActor(actor);
Code from above will add as many cubes and you want using a single actor! (which was amazing performance boost in my case)
Further, if you want to update positions of the cubes, you just need to do following:
points->Reset();
points->InsertNextPoint(-25, 0, 0);
points->InsertNextPoint(-35, 0, 0);
scales->Reset();
scales->InsertNextTuple3(1, 1., 8.);
scales->InsertNextTuple3(1., 1., 10.);
polydata_->Modified();
// call render
(notice that I am not removing/adding actors to the scene which is another boost)

Cocos2d C++ Score system

So I am working on this game and I want to implement a score system.
This is the first time I am working with Cocos2d.
I tried a couple of things but didn't really had succes.
I would like it if for each enemy that gets removed from the scene a int with the name score would be increased by one.
Do you guys have some suggestions ?
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
using namespace CocosDenshion;
USING_NS_CC;
#define BACKGROUND_MUSIC_SFX "bee.mp3"
#define PEW_PEW_SFX "splatter.mp3"
// These bit masks define the physics categories; monster + projectile with two values to specify no type or all types, I use this to see what objects are allowed to collide
enum class PhysicsCategory {
None = 0,
Monster = (1 << 0), // 1
Projectile = (1 << 1), // 2
All = PhysicsCategory::Monster | PhysicsCategory::Projectile // 3
};
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object, turn psysics on
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setGravity(Vec2(0,0));
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_NONE);
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer child to scene
scene->addChild(layer);
// return scene
return scene;
}
// initialize instance
bool HelloWorld::init()
{
// call the super class’s init method, if succeeds proceed HelloWorldScene‘s setup
if ( !Layer::init() ) {
return false;
}
// get window bounds using game Director singleton.
auto origin = Director::getInstance()->getVisibleOrigin();
auto winSize = Director::getInstance()->getVisibleSize();
// create a DrawNode to draw a green rectangle that fills the screen
auto background = DrawNode::create();
background->drawSolidRect(origin, winSize, Color4F(0.0,0.6,0.0,0.7));
this->addChild(background);
// create the player sprite, position 10% from the left edge of the screen, centered vertically
_player = Sprite::create("player.png");
_player->setPosition(Vec2(winSize.width * 0.1, winSize.height * 0.5));
this->addChild(_player);
// seed the random number generator
srand((unsigned int)time(nullptr));
this->schedule(schedule_selector(HelloWorld::addMonster), 1.5);
auto eventListener = EventListenerTouchOneByOne::create();
eventListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(eventListener, _player);
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);
SimpleAudioEngine::getInstance()->playBackgroundMusic(BACKGROUND_MUSIC_SFX, true);
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
void HelloWorld::addMonster(float dt) {
auto monster = Sprite::create("monster.png");
//Create a PhysicsBody for the sprite, Physics bodies represent the object in Cocos2d physics simulation.
auto monsterSize = monster->getContentSize();
auto physicsBody = PhysicsBody::createBox(Size(monsterSize.width , monsterSize.height),
PhysicsMaterial(0.1f, 1.0f, 0.0f));
//Set the sprite to be dynamic. physics engine will not apply forces to the bear.
physicsBody->setDynamic(true);
// set the category, collision and contact test bit masks:
physicsBody->setCategoryBitmask((int)PhysicsCategory::Monster);
physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
physicsBody->setContactTestBitmask((int)PhysicsCategory::Projectile);
monster->setPhysicsBody(physicsBody);
// create a bear sprite and place it offscreen to the right, random y position
auto monsterContentSize = monster->getContentSize();
auto selfContentSize = this->getContentSize();
int minY = monsterContentSize.height/2;
int maxY = selfContentSize.height - monsterContentSize.height/2;
int rangeY = maxY - minY;
int randomY = (rand() % rangeY) + minY;
monster->setPosition(Vec2(selfContentSize.width + monsterContentSize.width/2, randomY));
this->addChild(monster);
// random duration for bear, each bear will move the same distance across the screen, varying the duration results in bears with random speeds.
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int randomDuration = (rand() % rangeDuration) + minDuration;
// move the bear across the screen.
auto actionMove = MoveTo::create(randomDuration, Vec2(-monsterContentSize.width/2, randomY));
auto actionRemove = RemoveSelf::create();
monster->runAction(Sequence::create(actionMove,actionRemove, nullptr));
}
bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event) {
// 1 - get the _player object
//auto node = unused_event->getCurrentTarget();
// coordinate of the click within the scene’s coordinate system, calculate the offset of this point from the current position. vector math.
Vec2 touchLocation = touch->getLocation();
Vec2 offset = touchLocation - _player->getPosition();
// If offset‘s x value is negative, the player tries to shoot backwards,return without firing.
if (offset.x < 0) {
return true;
}
// Create projectile, add to screen
auto projectile = Sprite::create("projectile.png");
projectile->setPosition(_player->getPosition());
auto projectileSize = projectile->getContentSize();
auto physicsBody = PhysicsBody::createCircle(projectileSize.width/2 );
physicsBody->setDynamic(true);
physicsBody->setCategoryBitmask((int)PhysicsCategory::Projectile);
physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
physicsBody->setContactTestBitmask((int)PhysicsCategory::Monster);
projectile->setPhysicsBody(physicsBody);
this->addChild(projectile);
// call normalize() to convert the offset into a unit vector, which is a vector of length 1. Multiplying that by 1000 that points in the direction of the user’s tap.
offset.normalize();
auto shootAmount = offset * 1000;
// Adding the vector to the projectile’s position gives the target position.
auto realDest = shootAmount + projectile->getPosition();
// move the projectile to the target position, remove after 5 sec.
auto actionMove = MoveTo::create(5.0f, realDest);
auto actionRemove = RemoveSelf::create();
projectile->runAction(Sequence::create(actionMove,actionRemove, nullptr));
SimpleAudioEngine::getInstance()->playEffect(PEW_PEW_SFX);
return true;
}
// PhysicsContact passed to this method is collision, remove at the end
bool HelloWorld::onContactBegan(PhysicsContact &contact) {
auto nodeA = contact.getShapeA()->getBody()->getNode();
auto nodeB = contact.getShapeB()->getBody()->getNode();
nodeA->removeFromParent();
nodeB->removeFromParent();
return true;
}
I'm not sure that I have fully understood your question, but it seems that you want to create a label to show the current score.
Of course you will need a variable to keep track of your score. Let's assume the variable is an integer and it's called m_score.
You will then need to create and add a Label to your scene. In your init() function add:
m_scoreLabel = Label::createWithTTF(std::to_string(m_score), "fonts/Arial.ttf", 36);
this->addChild(m_scoreLabel);
You will need m_scoreLabel to keep a reference to your Label so that you will be able to change its display text later on. Now, whenever you change the score, first update the value of m_score and then to update the text shown by the label call:
m_scoreLabel->setString(std::to_string(m_score));

Stop particle effect libgdx

I have a game that involves lots of collisions and explosions.
Basically, enemy-projectiles are launched from the bottom-right corner of the screen towards the left side. The player can intercept them using his weapon.
I want whenever a "bullet" and a projectile collide, the code will draw pre-made particles at the impact position.
My problem is that in real-time, in collision, the particles are drawn nicely but they never stop. The particles continue to be drawn even after the collision.
Now, I use callback mechanism to inform the renderer a collision took place somewhere, and I pass him the coordinates of the collision(x,y)
Here is my renderer code. I cut some parts from the code, leaving only the relevant ones:
package com.david.gameworld;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.utils.Array;
import com.david.helpers.AssetsLoader;
import com.david.helpers.CollisionAndTouchCallbacks;
public class GameRenderer implements CollisionAndTouchCallbacks.DrawThings{
/* The GameRenderer class. Responsible for all the rendering work and graphics */
public static final float FLOOR_HEIGHT = 100.0f; // Public variable - The floor height
private static final float Pixels_To_Meters = 32.0f; // PTM Ration
public static float screenWidth; // Screen width
public static float screenHeight; // Screen height
public OrthographicCamera camera; // The orthographic camera
private GameWorld world; // The game world object, for rendering
private boolean drawTrajectory;
private boolean drawParticle;
private boolean isDrawnParticle;
private Box2DDebugRenderer debugRenderer; // Debug renderer, to see the positions and sizes of the bodies/fixtures
private SpriteBatch batch; // A sprite batch
private Array<Body> tempBodies; // An array that contains all the bodies of Box2D
private Array<Vector2> collisionPositions;
private float delta;
public GameRenderer(float screenWidth, float screenHeight, GameWorld world) {
this.world = world;
GameRenderer.screenHeight = screenHeight;
GameRenderer.screenWidth = screenWidth;
debugRenderer = new Box2DDebugRenderer();
batch = new SpriteBatch();
camera = new OrthographicCamera();
tempBodies = new Array<Body>();
collisionPositions = new Array<Vector2>();
drawTrajectory = false;
drawParticle = false;
isDrawnParticle = false;
}
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.delta = delta;
// Update the world
world.updateWorld();
batch.setProjectionMatrix(camera.combined);
// Get box2d World bodies
world.getBox2DWorld().getBodies(tempBodies);
// Draw the entire scene
batch.begin();
drawBodiesBox2D();
if(drawTrajectory)
drawTrajectory();
if(drawParticle) {
if(!isDrawnParticle) {
drawParticle();
isDrawnParticle = true;
} else {
if(AssetsLoader.explosion.isComplete()) {
drawParticle = false;
isDrawnParticle = false;
}
}
}
batch.end();
// Debug Renderer for box2d world
}
// If user is aiming, draw the trajectory of the acorn
public void drawTrajectory() {
Gdx.app.log("System Out Println!!!!!!!!!", "Draw projectile");
float t = 0.1f, x = world.getArrayAcorns().peek().getX(), y = world
.getArrayAcorns().peek().getY();
float width = AssetsLoader.orbit.getWidth() / 8 / Pixels_To_Meters;
float height = AssetsLoader.orbit.getHeight() / 8 / Pixels_To_Meters;
float timeSeparation = 0.08f;
for (int i = 0; i < 40; i++) {
x = world.getAcornEquation().getX(t);
y = world.getAcornEquation().getY(t);
batch.draw(AssetsLoader.orbit, x, y, width, height);
t += timeSeparation;
}
}
private void drawBodiesBox2D() {
for (Body body : tempBodies) {
if (body.getUserData() != null
&& body.getUserData() instanceof Sprite) {
Sprite sprite = (Sprite) body.getUserData();
if (!sprite.getTexture().equals(AssetsLoader.ground)) {
sprite.setPosition(body.getPosition().x - sprite.getWidth()
/ 2, body.getPosition().y - sprite.getHeight() / 2);
} else {
sprite.setSize(screenWidth, FLOOR_HEIGHT / Pixels_To_Meters);
}
sprite.setRotation((float) Math.toDegrees(body.getAngle()));
batch.draw(AssetsLoader.catapult_base1, 450 / Pixels_To_Meters,
(FLOOR_HEIGHT - 10) / Pixels_To_Meters,
AssetsLoader.catapult_base1.getWidth()
/ Pixels_To_Meters,
AssetsLoader.catapult_base1.getHeight()
/ Pixels_To_Meters);
sprite.draw(batch);
}
}
}
public void dispose() {
AssetsLoader.dispose();
batch.dispose();
world.dispose();
debugRenderer.dispose();
}
// Update method for the orthographic camera
public void updateCamera(int width, int height) {
camera.setToOrtho(false, width, height);
screenWidth = (float) width;
screenHeight = (float) height;
camera.update();
// Already Meters
}
public OrthographicCamera getCamera() {
return this.camera;
}
private void drawParticle() {
// TODO Auto-generated method stub
AssetsLoader.explosion.setPosition(collisionPositions.first().x,collisionPositions.first().y);
AssetsLoader.explosion.start();
AssetsLoader.explosion.draw(batch,delta);
AssetsLoader.explosion.allowCompletion();
}
#Override
public void signalToTrajectory(boolean flag) {
// TODO Auto-generated method stub
drawTrajectory = flag;
}
#Override
public void signalToParticle(boolean flag, Array<Vector2> positions) {
// TODO Auto-generated method stub
if(flag)
collisionPositions = positions;
drawParticle = flag;
}
}
How can I draw the particle effect once and that's it?
You can use/optimise my particle class, look my post here
To draw the particle effect once and that's it : ( it's in myparticle free method ) :
ParticleEffect effect = new ParticleEffect();
Emitter emitter = effect.getControllers().first().emitter;
if (emitter instanceof RegularEmitter){
RegularEmitter reg = (RegularEmitter) emitter;
reg.setEmissionMode(RegularEmitter.EmissionMode.EnabledUntilCycleEnd);
//reg.durationValue.setLow(10f);
reg.dispose();
}
emitter.dispose();