Can't increment integer in Cocos2d-x V 3.0 - c++

I need to increment an integer.I have this code here :
Utils.h :
class Utils{
static HUD* hudLayer();
static Layer* layerWithTag(int tag);
};
Utils.cpp :
HUD* Utils::hudLayer(){
return (HUD*)Utils::layerWithTag(TAG_HUD);
}
Layer* Utils::layerWithTag(int tag)
{
Scene *sc = Director::getInstance()->getRunningScene();
if (sc->getTag() == TAG_GAME_SCENE) {
Layer *layer = (Layer *)sc->getChildByTag(tag);
return layer;
}
return NULL;
}
HUD.h
class HUD : public Layer{
public:
int score1;
Label* scoreLabel1;
virtual bool init();
void didScore();
CREATE_FUNC(HUD);
};
HUD.cpp :
bool HUD::init(){
if(!Layer::init()){return false;}
score1 = 0;
scoreLabel1 = Label::createWithSystemFont(CCString::createWithFormat("Score : %d",score1)->getCString(), “Arial“, 64);
scoreLabel1->setAnchorPoint(Point(0.0f, 1.0f));
scoreLabel1->setPosition(Point(20, Utils::s().height-10));
this->addChild(scoreLabel1);
return true;
}
void HUD::didScore(){
score1+=10; // Error HERE after coming from onTouchBegan (says parentis null)
scoreLabel1->setString(CCString::createWithFormat("Score : %d",score1)->getCString());
}
In GameScene.h now i have this in onTouchBegan method :
bool GameScene::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event)
{
Point location = touch->getLocationInView();
location = Director::getInstance()->convertToGL(location);
if(location.x < 300.0f){
Utils::hudLayer()->didScore();
}
return true;
}
What am i doing wrong here ?
I can increment an integer in V 2.x the same way but not in V 3.0 . WHY ?

In cocos2d-x v3 is a new listener system for events (touches, accelerometr etc.), you need to create listener for getting touches. In GameScene::init you should put something like that
auto listener1 = EventListenerTouchOneByOne::create();
listener1->setSwallowTouches(true);
listener1->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener1, this);
Look at:
http://www.cocos2d-x.org/wiki/EventDispatcher_Mechanism

Related

Passing a TForm as an argument to a function

I have an application with several Forms. Two of them are quite similar, they have features in the form of VCL objects (labels, images, etc...) in common, which I named the same.
I want to have a function in a specific class which can accept one of these two Form as a parameter in order to modify the parameters that they have in common. The solution I came around does not seem to work.
As my application is quite big and complicated, I replicated the problem using a small example.
First, below is an example of my MainForm :
And an example of one subForm (they are all arranged in a similar way)
I have an additionnal class which is used to fill in the Edits on the subForms. The code for this class is the following:
#pragma hdrstop
#include "master_class.h"
#include "sub_Form2.h"
#include "sub_Form3.h"
#include "sub_Form4.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
Master::Master(void)
{
}
Master::~Master(void)
{
}
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm = static_cast<TForm2*>(Form);
TForm3* self = dynamic_cast<TForm3*>(Form);
TForm2* self2 = dynamic_cast<TForm2*>(Form);
if (self != NULL && self2 == NULL) {
TForm3* curForm = static_cast<TForm3*>(Form);
}
else if (self == NULL && self2 != NULL) {
TForm2* curForm = static_cast<TForm2*>(Form);
}
curForm -> Edit1 -> Text = "blablabla_1";
curForm -> Edit2 -> Text = "blablabla_2";
}
And in the MainForm, the code for the "Fill Form2" button is the following:
Master1 -> WriteToForm(Form2);
where Master1 is just an object of the Master class.
This works very well for Form2 :
But for Form3, which is filled up using Master1 -> WriteToForm(Form3), here is what I get, which the same pb than in my real application:
So what should go to the Edit, is misplaced. I think the main pb comes from the fact that I did not create every label, edit, etc... on the same order. I did that on purpose to mimic my real application. To verify this, I created a 3rd subForm, where this time the VCL objects were created in the same order as my first subForm, and this works:
So I would suspect that this comes from the initial cast
TForm2* curForm = static_cast<TForm2*>(Form);
When I pass Form3 as an argument, Form3 is somewhat casted into the "shape" of Form2, which is not defined in the same order. Maybe this could be corrected by modifying directly the DFM file, but it is not a realistic approach for my main app.
I do this initial cast otherwise I get a compilation error saying that curForm is not known at the first line
curForm -> Edit1 -> Text = "blablabla_1";
So, is there a better way to pass the Form as an argument to the WriteToForm function?
Just because two types are similar does not mean they are related. Your code does not work because your two Form classes are not related to each other in any way. You can't just cast one to the other arbitrarily.
To solve this, you have several options:
code for both Form classes separately, eg:
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm2 = dynamic_cast<TForm2*>(Form);
TForm3* curForm3 = dynamic_cast<TForm3*>(Form);
if (curForm2)
{
curForm2->Edit1->Text = _D("blablabla_1");
curForm2->Edit2->Text = _D("blablabla_2");
}
else if (curForm3)
{
curForm3->Edit1->Text = _D("blablabla_1");
curForm3->Edit2->Text = _D("blablabla_2");
}
}
Or:
void WriteToForm(TForm2* Form);
void WriteToForm(TForm3* Form);
...
void Master::WriteToForm(TForm2* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
void Master::WriteToForm(TForm3* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
Make your function use a template (however, be aware of this: Why can templates only be implemented in the header file?):
template<typename T>
void WriteToForm(T* Form);
...
void Master::WriteToForm<T>(T* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
make the two Form classes derive from a common base class or interface, eg:
class TBaseForm : public TForm
{
public:
inline __fastcall TBaseForm(TComponent *Owner) : TForm(Owner) {}
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TBaseForm
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TBaseForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(TBaseForm* Form)
{
Form->SetEdit1(_D("blablabla_1"));
Form->SetEdit2(_D("blablabla_2"));
}
Or:
__interface INTERFACE_UUID("{E900785E-0151-480F-A33A-1F1452A431D2}")
IMyIntf : public IInterface
{
public:
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TForm, public IMyIntf
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(IMyIntf* Intf)
{
Intf->SetEdit1(_D("blablabla_1"));
Intf->SetEdit2(_D("blablabla_2"));
}
use RTTI to access the fields, eg:
#include <System.Rtti.hpp>
void Master::WriteToForm(TForm* Form)
{
TRttiContext Ctx;
TRttiType *FormType = Ctx.GetType(Form->ClassType());
TRttiField *Field = FormType->GetField(_D("Edit1"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_1");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_1")));
}
}
Field = FormType->GetField(_D("Edit2"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_2");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_2")));
}
}
}

Developing graphical user front-end application to communicate with microcontroller system [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I am able to establish communication between my microcontroller system and computer through serial port and TCP/IP, and able to send/ receive data.
I want to develop a graphical front-end application on my PC in which i can view some values/plot some graphs based on the data sent by my microcontroller.
I have some exposure to Visual Studio and MATLAB, and know C/C++ languages.
Which development environment should i use for the front-end development ??
Any tutorials/books/links regarding the same ??
This is actually an appendix to a comment, where I bragged about a small wrapper for charts, for creating XYPlots.
create a winform, rename it to XYPlot.
add a chart, and name it plotChart
add this as code..
now you can plot easily from your code ..
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace Plot
{
public partial class XYPlot : Form
{
#region constructors
public string Title
{
get
{
return this.Text;
}
set
{
this.Text = "XYPlot : " + value;
}
}
//default, used for multiplots
public XYPlot()
{
InitializeComponent();
InitializeChartStyles();
}
private void InitializeChartStyles()
{
plotChart.ChartAreas["ChartArea1"].AxisX.IsMarginVisible = false;
plotChart.ChartAreas["ChartArea1"].AxisX.MajorGrid.Enabled = false;
plotChart.ChartAreas["ChartArea1"].AxisX.MinorGrid.Enabled = false;
plotChart.ChartAreas["ChartArea1"].AxisY.MajorGrid.Enabled = false;
plotChart.ChartAreas["ChartArea1"].AxisY.MinorGrid.Enabled = false;
}
//one-offs, used for simple plots of data
public XYPlot(string name, Series series)
{
InitializeComponent();
InitializeChartStyles();
this.Add(series);
this.Show();
}
public XYPlot(string name, DataPointCollection XYpoints)
{
InitializeComponent();
InitializeChartStyles();
this.Add(name, XYpoints);
this.Show();
}
public XYPlot(string name, List<Tuple<double, double>> XYpoints)
{
InitializeComponent();
InitializeChartStyles();
this.Add(name, XYpoints);
this.Show();
}
public XYPlot(string name, List<double> X, List<double> Y)
{
InitializeComponent();
InitializeChartStyles();
this.Add(name, X, Y);
this.Show();
}
public XYPlot(string name, List<double> Y, double xIncrements = 1.0, double xOffset = 0.0)
{
InitializeComponent();
InitializeChartStyles();
this.Add(name, Y, xIncrements);
this.Show();
}
private void FormPlot_Load(object sender, EventArgs e)
{
Clear();
}
#endregion
#region getNextDefault
private List<Color> usedColors = new List<Color>();
private Color getNextDefaultColor()
{
switch(usedColors.Count)
{
case 1:
return Color.Red;
case 2:
return Color.Green;
case 3:
return Color.Black;
default:
return Color.Blue;
}
}
private Series newDefaultSeries(string Name)
{
var series = new System.Windows.Forms.DataVisualization.Charting.Series
{
Name = Name,
BorderWidth = 2,
Color = getNextDefaultColor(),
IsVisibleInLegend = true,
IsXValueIndexed = false,
ChartType = SeriesChartType.Line
};
usedColors.Add(series.Color);
return series;
}
#endregion
#region public methods
public void Clear()
{
plotChart.Series.Clear();
usedColors.Clear();
}
public Series getSeries(string Name)
{
return plotChart.Series[Name];
}
#region Add
public void Add(string Name, DataPointCollection XYpoints)
{
Series series = newDefaultSeries(Name);
plotChart.Series.Add(series);
//shallow copy
foreach (DataPoint p in XYpoints)
{
series.Points.Add(p);
}
//invalidates the old surfcace, and thus requests a redraw
plotChart.Refresh();
}
public void Add(string Name, List<Tuple<double, double>> XYpoints)
{
Series series = newDefaultSeries(Name);
plotChart.Series.Add(series);
//shallow copy
foreach (Tuple<double, double> XY in XYpoints)
{
series.Points.AddXY(XY.Item1, XY.Item2);
}
//invalidates the old surfcace, and thus requests a redraw
plotChart.Refresh();
}
public void Add(string Name, List<double> X, List<double> Y)
{
Series series = newDefaultSeries(Name);
plotChart.Series.Add(series);
if (X.Count != Y.Count)
throw new Exception("X and Y vectors must be of same length, otherwise I cannot plot them in an XY plot!");
//shallow copy
for (int i = 0; i < X.Count; i++)
{
series.Points.AddXY(X[i], Y[i]);
}
//invalidates the old surfcace, and thus requests a redraw
plotChart.Refresh();
}
public void Add(string Name, List<double> Y, double xIncrements = 1.0, double xOffset = 0.0)
{
Series series = newDefaultSeries(Name);
plotChart.Series.Add(series);
//shallow copy
if (Y != null)
{
for (int i = 0; i < Y.Count; i++)
{
double x = ((double)i) * xIncrements + xOffset;
series.Points.AddXY(x, Y[i]);
}
}
//invalidates the old surface, and thus requests a redraw
plotChart.Refresh();
}
public void Add(System.Windows.Forms.DataVisualization.Charting.Series series)
{
plotChart.Series.Add(series);
plotChart.Refresh();
}
#endregion
#region updateSeries
public void updateSeries(string Name, DataPointCollection XYpoints)
{
try
{
if (plotChart.Series[Name] == null)
Add(Name, XYpoints);
}
catch
{
Add(Name, XYpoints);
}
//shallow copy
foreach (DataPoint p in XYpoints)
{
plotChart.Series[Name].Points.Add(p);
}
//invalidates the old surfcace, and thus requests a redraw
plotChart.Refresh();
}
public void updateSeries(string Name, List<Tuple<double, double>> XYpoints)
{
try
{
if (plotChart.Series[Name] == null)
Add(Name, XYpoints);
}
catch
{
Add(Name, XYpoints);
}
//shallow copy
foreach (Tuple<double, double> XY in XYpoints)
{
plotChart.Series[Name].Points.AddXY(XY.Item1, XY.Item2);
}
//invalidates the old surfcace, and thus requests a redraw
plotChart.Refresh();
}
public void updateSeries(string Name, List<double> X, List<double> Y)
{
try
{
if (plotChart.Series[Name] == null)
Add(Name, X, Y);
}
catch
{
Add(Name, X, Y);
}
plotChart.Series[Name].Points.Clear();
if (X.Count != Y.Count)
throw new Exception("X and Y vectors must be of same length, otherwise I cannot plot them in an XY plot!");
//shallow copy
for (int i = 0; i < X.Count; i++)
{
plotChart.Series[Name].Points.AddXY(X[i], Y[i]);
}
//invalidates the old surface, and thus requests a redraw
plotChart.Refresh();
}
public void updateSeries(string Name, List<double> Y, double xIncrements = 1.0, double xOffset = 0.0)
{
try
{
if (plotChart.Series[Name] == null)
Add(Name, Y, xIncrements, xOffset);
}
catch
{
Add(Name, Y, xIncrements, xOffset);
}
plotChart.Series[Name].Points.Clear();
//shallow copy
if (Y != null)
{
for (int i = 0; i < Y.Count; i++)
{
double x = ((double)i) * xIncrements + xOffset;
plotChart.Series[Name].Points.AddXY(x, Y[i]);
}
}
//invalidates the old surface, and thus requests a redraw
plotChart.Refresh();
}
public void updateSeries(System.Windows.Forms.DataVisualization.Charting.Series series)
{
try
{
if (plotChart.Series[series.Name] == null)
Add(series);
}
catch
{
Add(series);
}
plotChart.Series[series.Name] = series;
plotChart.Refresh();
}
#endregion
#endregion
}
}
As suggested by Joe, i decided to go ahead with Qt.
The following links are useful for installing and getting started with Qt on windows.
Installation:-
https://zahidhasan.wordpress.com/2014/04/29/how-to-install-qt-4-8-mingw-and-qt-creator-on-windows-8-1/
Reference:-
http://www-cs.ccny.cuny.edu/~wolberg/cs221/qt/books/C++-GUI-Programming-with-Qt-4-1st-ed.pdf
Regards,
Abhishek.

How to subclass vtkActor

I wanted to be able to access my underlaying data structure when I pick a vtkActor. A class derived from vtkActor holding a ptr to my data structure seemed the easiest approach.
I get the subclass to compile just fine but the actor does not seem to be added to the renderer.
So, here's my class:
//.h
#include <vtkActor.h>
#include <vtkObjectFactory.h>
class Node;
struct Actor : public vtkActor {
static Actor* New();
vtkTypeMacro(Actor, vtkActor)
Node* holding_node;
};
//.cpp
#include "actor.h"
vtkStandardNewMacro(Actor)
In my rendering step: if I instantiate the actor with a vtkActor everything shows up as expected, picking works, etc...
vtkSmartPointer<vtkActor> sphereActor = vtkSmartPointer<vtkActor>::New();
But no actor is added if I use my Actor class
vtkSmartPointer<Actor> sphereActor = vtkSmartPointer<Actor>::New();
Nothing else changes in the code. Any ideas of what's wrong?
So, it turns out that there are a bunch of functions that need to be overloaded and a couple touches of macro magic to get this to work.
I pasted below the example that's working for me now. It is mostly from the vtkFollower code (a derived class from vtkActor). Hope this helps!
#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkObjectFactory.h>
#include <vtkRenderingCoreModule.h>
#include <vtkProperty.h>
class Node;
class VTKRENDERINGCORE_EXPORT NodeActor : public vtkActor {
public:
vtkTypeMacro(NodeActor, vtkActor);
static NodeActor *New();
virtual void ReleaseGraphicsResources(vtkWindow *window) {
this->Device->ReleaseGraphicsResources(window);
this->Superclass::ReleaseGraphicsResources(window);
}
virtual int RenderOpaqueGeometry(vtkViewport *viewport){
if ( ! this->Mapper ) {
return 0;
}
if (!this->Property) {
this->GetProperty();
}
if (this->GetIsOpaque()) {
vtkRenderer *ren = static_cast<vtkRenderer *>(viewport);
this->Render(ren);
return 1;
}
return 0;
}
virtual int RenderTranslucentPolygonalGeometry(vtkViewport *viewport){
if ( ! this->Mapper ) {
return 0;
}
if (!this->Property) {
this->GetProperty();
}
if (!this->GetIsOpaque()) {
vtkRenderer *ren = static_cast<vtkRenderer *>(viewport);
this->Render(ren);
return 1;
}
return 0;
}
virtual void Render(vtkRenderer *ren){
this->Property->Render(this, ren);
this->Device->SetProperty (this->Property);
this->Property->Render(this, ren);
if (this->BackfaceProperty) {
this->BackfaceProperty->BackfaceRender(this, ren);
this->Device->SetBackfaceProperty(this->BackfaceProperty);
}
if (this->Texture) {
this->Texture->Render(ren);
}
this->ComputeMatrix();
this->Device->SetUserMatrix(this->Matrix);
this->Device->Render(ren,this->Mapper);
}
void ShallowCopy(vtkProp *prop) {
NodeActor *f = NodeActor::SafeDownCast(prop);
this->vtkActor::ShallowCopy(prop);
}
//****************************************//
// my member
//****************************************//
Node* node_i_represent{nullptr};
protected:
vtkActor* Device;
NodeActor() {
this -> Device = vtkActor::New();
}
~NodeActor() {
this -> Device -> Delete();
}
private:
};
vtkStandardNewMacro(NodeActor)

Detect initial collision of two box2d bodies without continuous collision

I have some simple box2d bodies setup with a contact listener like so:
#import "MyContactListener.h"
MyContactListener::MyContactListener() : _contacts() {
}
MyContactListener::~MyContactListener() {
}
void MyContactListener::BeginContact(b2Contact* contact) {
// We need to copy out the data because the b2Contact passed in
// is reused.
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
_contacts.push_back(myContact);
b2Body *A = contact->GetFixtureA()->GetBody();
b2Body *B = contact->GetFixtureA()->GetBody();
NSLog(#"Collision detected!");
PLAYSOUND(COLLISION);
}
void MyContactListener::EndContact(b2Contact* contact) {
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
std::vector<MyContact>::iterator pos;
pos = std::find(_contacts.begin(), _contacts.end(), myContact);
if (pos != _contacts.end()) {
_contacts.erase(pos);
}
}
void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {
}
void MyContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) {
}
And I need to play a sound when two bodies have collided. However this implementation detects continuous collisions so the sound is played when the bodies are touching. My knowledge of box2d and C++ is already very limited, is there a simple way to detect a new collision without detecting continuous collisions?
You have the right basic idea, but it needs some refinement.
In your BeginContact(...) call, you have:
PLAYSOUND(COLLISION);
Instead of playing the sound here, what you should do is enqueue some other system to play the sound for this particular pair. Set the userdata tag of your bodies to the pointer to the class (or some other ID to keep track of entities). Like so:
class EntityContactListener : public ContactListener
{
private:
GameWorld* _gameWorld;
EntityContactListener() {}
typedef struct
{
Entity* entA;
Entity* entB;
} CONTACT_PAIR_T;
vector<CONTACT_PAIR_T> _contactPairs;
public:
virtual ~EntityContactListener() {}
EntityContactListener(GameWorld* gameWorld) :
_gameWorld(gameWorld)
{
_contactPairs.reserve(128);
}
void NotifyCollisions()
{
Message* msg;
MessageManager& mm = GameManager::Instance().GetMessageMgr();
for(uint32 idx = 0; idx < _contactPairs.size(); idx++)
{
Entity* entA = _contactPairs[idx].entA;
Entity* entB = _contactPairs[idx].entB;
//DebugLogCPP("Contact Notification %s<->%s",entA->ToString().c_str(),entB->ToString().c_str());
msg = mm.CreateMessage();
msg->Init(entA->GetID(), entB->GetID(), Message::MESSAGE_COLLISION);
mm.EnqueueMessge(msg, 0);
msg = mm.CreateMessage();
msg->Init(entB->GetID(), entA->GetID(), Message::MESSAGE_COLLISION);
mm.EnqueueMessge(msg, 0);
}
_contactPairs.clear();
}
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{
}
// BEWARE: You may get multiple calls for the same event.
void BeginContact(b2Contact* contact)
{
Entity* entA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData();
Entity* entB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData();
//DebugLogCPP("Begin Contact %s->%s",entA->ToString().c_str(),entB->ToString().c_str());
if(entA->GetGroupID() == entB->GetGroupID())
{ // Can't collide if they are in the same group.
return;
}
assert(entA != NULL);
assert(entB != NULL);
for(uint32 idx = 0; idx < _contactPairs.size(); idx++)
{
if(_contactPairs[idx].entA == entA && _contactPairs[idx].entB == entB)
return;
// Not sure if this is needed...
if(_contactPairs[idx].entA == entB && _contactPairs[idx].entA == entB)
return;
}
CONTACT_PAIR_T pair;
pair.entA = entA;
pair.entB = entB;
_contactPairs.push_back(pair);
}
// BEWARE: You may get multiple calls for the same event.
void EndContact(b2Contact* contact)
{
/*
Entity* entA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData();
Entity* entB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData();
DebugLogCPP("End Contact %s->%s",entA->ToString().c_str(),entB->ToString().c_str());
*/
}
};
The last part of this is to NOT play the sound again for a short time even if a collision occurs. You can do this by creating a stopwatch or counting down from a fixed time on the entity update cycles.
Was this helpful?
First set a timer like this..
[self schedule:#selector(check collision:)];
and in this method
- (void)tick:(ccTime) dt
{
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext())
{
//--------------My contact Listener Start-------------------------
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos)
{
MyContact contact = *pos;
// Here get your sprite and make their fixture and check...
if ((contact.fixtureA == tempballFixture && contact.fixtureB == _mainballFixture) ||
(contact.fixtureA == _mainballFixture && contact.fixtureB == tempballFixture))
{
if(mainDelegate.music_playing == TRUE)
{
[[SimpleAudioEngine sharedEngine] playEffect:#"Rock impact.mp3"];
}
//-------------collision count for update score value--------
}
}

Inherited variables are not reading correctly when using bitwise comparisons

I have a few classes set up for a game, with XMapObject as the base, and XEntity, XEnviron, and XItem inheriting it.
MapObjects have a number of flags, one of them being MAPOBJECT_SOLID. My problem is that XEntity is the only class that correctly detects MAPOBJECT_SOLID. Both Items are Environs are always considered solid by the game, regardless of the flag's state. What is important is that Environs and Item should almost never be solid.
Each class has a very basic preliminary constructor, just initializing all varibles to zero or NULL. During the CreateX() phase, Objects are linked into the map, set into a linked linked list.
Both XItem and XEnviron are a tad sloppy. They are both new, and in the middle or my debugging attempts.
Here are the relevent code samples:
XMapObject:
#define MAPOBJECT_ACTIVE 1
#define MAPOBJECT_RENDER 2
#define MAPOBJECT_SOLID 4
class XMapObject : public XObject
{
public:
Uint8 MapObjectType,Location[2],MapObjectFlags;
XMapObject *NextMapObject,*PrevMapObject;
XMapObject();
void CreateMapObject(Uint8 MapObjectType);
void SpawnMapObject(Uint8 MapObjectLocation[2]);
void RemoveMapObject();
void DeleteMapObject();
void MapObjectSetLocation(Uint8 Y,Uint8 X);
void MapObjectMapLink();
void MapObjectMapUnlink();
};
XMapObject::XMapObject()
{
MapObjectType = 0;
Location[0] = 0;
Location[1] = 1;
NextMapObject = NULL;
PrevMapObject = NULL;
}
void XMapObject::CreateMapObject(Uint8 Type)
{
MapObjectType = Type;
}
void XMapObject::SpawnMapObject(Uint8 MapObjectLocation[2])
{
if(!(MapObjectFlags & MAPOBJECT_ACTIVE)) { MapObjectFlags += MAPOBJECT_ACTIVE; }
Location[0] = MapObjectLocation[0];
Location[1] = MapObjectLocation[1];
MapObjectMapLink();
}
XEntity:
XEntity *StartEntity = NULL,*EndEntity = NULL;
class XEntity : public XMapObject
{
public:
Uint8 Health,EntityFlags;
float Speed,Time;
XEntity *NextEntity,*PrevEntity;
XItem *IventoryList;
XEntity();
void CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2]);
void DeleteEntity();
void EntityLink();
void EntityUnlink();
Uint8 MoveEntity(Uint8 YOffset,Uint8 XOffset);
};
XEntity::XEntity()
{
Health = 0;
Speed = 0;
Time = 1.0;
EntityFlags = 0;
NextEntity = NULL;
PrevEntity = NULL;
IventoryList = NULL;
}
void XEntity::CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2])
{
CreateMapObject(EntityType);
SpawnMapObject(EntityLocation);
if(!(MapObjectFlags & MAPOBJECT_SOLID) { MapObjectFlags += MAPOBJECT_SOLID; }
EntityFlags = ENTITY_CLIPPING;
Time = 1.0;
Speed = 1.0;
EntityLink();
}
void XEntity::EntityLink()
{
if(StartEntity == NULL)
{
StartEntity = this;
PrevEntity = NULL;
NextEntity = NULL;
}
else
{
EndEntity->NextEntity = this;
}
EndEntity = this;
}
XEnviron:
class XEnviron : public XMapObject
{
public:
Uint8 Effect,TimeOut;
void CreateEnviron(Uint8 Type,Uint8 Y,Uint8 X,Uint8 TimeOut);
};
void XEnviron::CreateEnviron(Uint8 EnvironType,Uint8 Y,Uint8 X,Uint8 TimeOut)
{
CreateMapObject(EnvironType);
Location[0] = Y;
Location[1] = X;
SpawnMapObject(Location);
XTile *Tile = GetTile(Y,X);
Tile->Environ = this;
MapObjectFlags = MAPOBJECT_ACTIVE + MAPOBJECT_SOLID;
printf("%i\n",MapObjectFlags);
}
XItem:
class XItem : public XMapObject
{
public:
void CreateItem(Uint8 Type,Uint8 Y,Uint8 X);
};
void XItem::CreateItem(Uint8 Type,Uint8 Y,Uint8 X)
{
CreateMapObject(Type);
Location[0] = Y;
Location[1] = X;
SpawnMapObject(Location);
}
And lastly, the entity move code. Only entities are capable of moving themselves.
Uint8 XEntity::MoveEntity(Uint8 YOffset,Uint8 XOffset)
{
Uint8
NewY = Location[0] + YOffset,
NewX = Location[1] + XOffset;
if((NewY >= 0 && NewY < MAPY) && (NewX >= 0 && NewX < MAPX))
{
XTile *Tile = GetTile(NewY,NewX);
if(Tile->MapList != NULL)
{
XMapObject *MapObject = Tile->MapList;
while(MapObject != NULL)
{
if(MapObject->MapObjectFlags & MAPOBJECT_SOLID)
{
printf("solid\n");
return 0;
}
MapObject = MapObject->NextMapObject;
}
}
if(Tile->Flags & TILE_SOLID && EntityFlags & ENTITY_CLIPPING)
{
return 0;
}
this->MapObjectSetLocation(NewY,NewX);
return 1;
}
return 0;
}
What is wierd, is that the bitwise operator always returns true when the MapObject is an Environ or an Item, but it works correctly for Entities. For debug I am using the printf "Solid", and also a printf containing the value of the flag for both Environs and Items.
Any help is greatly appreciated, as this is a major bug for the small game I am working on. I am also very new at Object Oriented programming, anything tips, suggestions and/or criticism are also welcome.
Your problem appears to be that you never initialize MapObjectFlags in any classes other than XEnviron so, as a basic type, it will have an unspecified value in XItem, XEntity and other XMapObject derived objects. I suggest that, as a member of XMapObject you explicitly initialize it to a known value.
As a rule, it is generally a good idea to ensure that all members of basic type are explicitly initialized in the initializer list of every constructor that you define.
e.g.
XMapObject()
: MapObjectFlags(0)
, // ... other initializers
{
// Other initializations
}
You can't (legally) be calling XEntity::MoveEntity on a MapObject or Environ because they don't have such a method. If you're using static_cast to change your object pointer into an XEntity so you can call MoveEntity on it, then you really have no guarantees about how the bit operation will work. In some implementations, things may appear to work in MoveEntity, but what's actually happening is it's interpreting the other object's memory as an XEntity. When it tries to access the offset where it believes MapObjectFlags exists, it's not actually there and always has that bit set to 1.
I figured out the problem earlier today - It didn't have any relation to OO programming, inheritance, or bitwise; it was a simple scope error.
The problem was in the fact that during my quick test to get an Environ in game, I declared the new variable inside of the control switch sequence, so the next time any control was used, the Environ would act in unpredictable ways.
switch(Event.key.keysym.sym)
{
...
case SDLK_c: { XEnviron Environ; Environ.InitEnviron(...); }
...
}