I am struggling to program keypresses within Irrlicht.
I have created an eventreciever as such:
class MyEventReceiver : public IEventReceiver
{
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == irr::EET_KEY_INPUT_EVENT)
{
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
{
if (event.EventType == irr::EET_KEY_INPUT_EVENT&&!event.KeyInput.PressedDown)
switch(event.KeyInput.Key)
{
case KEY_KEY_1:
case KEY_KEY_2:
case KEY_KEY_3:
}
return true;
}
}
return false;
}
virtual bool IsKeyDown(EKEY_CODE keyCode) const
{
return KeyIsDown[keyCode];
}
MyEventReceiver()
{
memset(KeyIsDown, false, sizeof(KeyIsDown));
}
private:
bool KeyIsDown[KEY_KEY_CODES_COUNT];
};
This all seems to be working as such. However, within "while(device->run())" I have implemented:
if(receiver.IsKeyDown(irr::KEY_KEY_1))
{
}
to which I get an error for my reciever "identifier reciever is undefined". On all examples I see, I see this reciever variable with no declarations and they claim it works. What am I doing wrong?
I am building on the example project "LoadIrrFile" (#15).
The plan is to implement a weapon switch for keys 1-3. I should be able to get the code in once I have the keypress initialised.
I am using the snippet I found here: http://irrlicht.sourceforge.net/forum//viewtopic.php?p=143082
Here is a full code segment if more info is required: http://pastie.org/pastes/8620301/text
The snippet there is only a patch. receiver is not declared in your main(). Have a look at the "complete" example at http://irrlicht.sourceforge.net/docu/example004.html. Your code lacks something along (from the example in the link above):
MyEventReceiver receiver; // declare it
IrrlichtDevice* device = createDevice(driverType,
core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver); // use it here
Related
This is my code, and its working fine.
However I would like to remove the file by variable xmlfilepath which I have mentioned in the OnInitDialog()
BOOL CTestDlg::OnInitDialog()
{
CString xmlfilepath = _T("C:\\Project\\Test\\test.xml");
Navigate(xmlfilepath);
return TRUE;
}
void CTestDlg::OnClose()
{
CDHtmlDialog::OnClose();
remove("C:\\Project\\Test\\test.xml");
}
You probably want something like this:
class CTestDlg : public CDialog
{
...
CString m_xmlfilepath; // << put this somewhere in the definition
// of CTestDlg
...
}
BOOL CTestDlg::OnInitDialog()
{
m_xmlfilepath = _T("C:\\Project\\Test\\test.xml");
Navigate(m_xmlfilepath);
return TRUE;
}
void CTestDlg::OnClose()
{
CDHtmlDialog::OnClose();
remove(m_xmlfilepath);
}
This is really basic C++ knowledge. I suggest you learn the basics of C++ prior to experimenting with MFC.
I've used the command pattern quite extensively, and it works well. However, what's usually not discussed is where the instances of the Commands are created.
The following examples illustrate this issue: A Document has a function setText() that sets the text:
class Document {
public:
void setText(const std::string text) {
if (commandManager()->isActive()) {
// called by SetTextCommand
m_text = text;
} else {
// called somewhere in the application
commandManager()->addAndExecute(new SetTextCommand(this, text));
}
}
std::string text() const { return m_text; }
CommandManager * commandManager() const { return m_commandManager; }
private:
std::string m_text;
CommandManager * m_commandManager;
}
Here, the SetTextCommand would execute document->setText(text) like this:
class SetTextCommand : public Command {
public:
SetTextCommand(Document * doc, const std::string & text)
: Command(), m_doc(doc), m_oldText(doc->text()), m_text(text)
{}
void redo() override {
m_doc->setText(m_text);
}
void undo() override {
m_doc->setText(m_oldText, false);
}
}
The SetTextCommand is processed by the CommandManager like this:
CommandManager::addAndExecute(Command * command) {
m_doc->commandManager()->setActive(true); // THIS IS THE TRICK
command->redo();
m_doc->commandManager()->setActive(false); // THIS IS THE TRICK
m_stack->push_back(command);
}
The trick here is, that when running redo(), CommandManager::isActive() is set to true. Hence, Document::setText() will set m_text.
Obviously, all Document setter functions must follow the if (commandManager()->isActive()) { ... } else { ... } paradigm. This is, because the Commands themselves are created in the setter functions.
Question is now: Is this a good way to implement the command pattern? Or are there far cleaner solutions for creating the Commands while at the same time having a nice API?
Please be verbose with your answers.
I think it'd be pretty ugly to have to replicate the if (commandManager()->isActive()) everywhere... probably nicer to have setText always do the SetTextCommand path, and create a new setTextImmediate method which SetTextCommand can use.
I have an event handler as such,
__event void MouseMoved(int MousePosX, int MousePosY);
and it is raised via
__raise MouseMoved(MousePosX, MousePosY);
This works perfectly fine after using __hook to add a function to the event; however, if I raise the even though any functions bound to the event I get a runtime error. Is there a way to check for the event being empty before raising it?
C++ '11 does not have native events. Neither does C++ '14.
What this looks like to me is a feature specific to Microsoft Visual C++ - maybe Microsoft's Unified Event Model? If that's the case, raising an event that has no subscribers should not cause an error according to their docs:
To fire an event, simply call the method declared as an event in the event source class. If handlers have been hooked to the event, the handlers will be called.
On the other hand, .NET requires you to check events for being null before raising them and those keywords you're using also work in a managed C++ project, so if you created a managed application, it may very well be that you need to do something like
if(MouseMoved != nullptr) {
__raise MouseMoved(MousePosX, MousePosY);
}
If you want to write portable C++ that works on other compilers and/or platforms, I can recommend libsigc++ or JL Signal.
I opted for just defining my own event object which holds a list of function pointers that can be invoked in order. If functions much the same as events and eventhandlers in C#.
struct EventArg
{
public:
EventArg(){}
~EventArg(){}
static EventArg Empty()
{
EventArg empty;
return empty;
}
};
template <typename T>
class EventHandler
{
public:
EventHandler(void(T::*functionHandle)(void*, EventArg), T* receiver)
{
this->functionHandle = functionHandle;
this->receiver = receiver;
}
virtual void Call(void* sender, EventArg e)
{
(receiver->*functionHandle)(sender, e);
}
private:
void (T::*functionHandle)(void*, EventArg);
T* receiver;
};
class Event
{
private:
std::vector<EventHandlerBase*> EventHandlers;
public:
void Raise(void* sender, EventArgT e)
{
for (auto item = EventHandlers.begin(); item != EventHandlers.end(); item++)
(*item)->Call(sender, e);
}
void Add(EventHandler* functionHandle)
{
EventHandlers.push_back(functionHandle);
}
void Remove(EventHandler* functionHandle)
{
for (auto item = EventHandlers.begin(); item != EventHandlers.end(); item++)
{
if ((*item) == functionHandle)
{
EventHandlers.erase(item);
return;
}
}
}
}
I'm writing an xml parser and I need to add objects to a class generically, switching on the actual type of the object. Problem is, I'd like to keep to an interface which is simply addElement(BaseClass*) then place the object correctly.
void E_TableType::addElement(Element *e)
{
QString label = e->getName();
if (label == "state") {
state = qobject_cast<E_TableEvent*>(e);
}
else if (label == "showPaytable") {
showPaytable = qobject_cast<E_VisibleType*>(e);
}
else if (label == "sessionTip") {
sessionTip = qobject_cast<E_SessionTip*>(e);
}
else if (label == "logoffmedia") {
logoffMedia = qobject_cast<E_UrlType*>(e);
}
else {
this->errorMessage(e);
}
}
This is the calling class, an object factory. myElement is an instance of E_TableType.
F_TableTypeFactory::F_TableTypeFactory()
{
this->myElement = myTable = 0;
}
void F_TableTypeFactory::start(QString qname)
{
this->myElement = myTable = new E_TableType(qname);
}
void F_TableTypeFactory::fill(const QString& string)
{
// don't fill complex types.
}
void F_TableTypeFactory::addChild(Element* child)
{
myTable->addElement(child);
}
Element* F_TableTypeFactory::finish()
{
return myElement;
}
void F_TableTypeFactory::addAttributes(const QXmlAttributes &attribs) {
QString tName = attribs.value(QString("id"));
myTable->setTableName(tName);
}
Have you considered using polymorphism here? If a common interface can be implemented by each of your concrete classes then all of this code goes away and things become simple and easy to change in the future. For example:
class Camera {
public:
virtual void Init() = 0;
virtual void TakeSnapshot() = 0;
}
class KodakCamera : Camera {
public:
void Init() { /* initialize a Kodak camera */ };
void TakeSnapshot() { std::cout << "Kodak snapshot"; }
}
class SonyCamera : Camera {
public:
void Init() { /* initialize a Sony camera */ };
void TakeSnapshot() { std::cout << "Sony snapshot"; }
}
So, let's assume we have a system which contains a hardware device, in this case, a camera. Each device requires different logic to take a picture, but the code has to support a system with any supported camera, so we don't want switch statements littered throughout our code. So, we have created an abstract class Camera.
Each concrete class (i.e., SonyCamera, KodakCamera) implementation will incluse different headers, link to different libraries, etc., but they all share a common interface; we just have to decide which one to create up front. So...
std::unique_ptr<Camera> InitCamera(CameraType type) {
std::unique_ptr<Camera> ret;
Camera *cam;
switch(type) {
case Kodak:
cam = new KodakCamera();
break;
case Sony:
cam = new SonyCamera();
break;
default:
// throw an error, whatever
return;
}
ret.reset(cam);
ret->Init();
return ret;
}
int main(...) {
// get system camera type
std::unique_ptr<Camera> cam = InitCamera(cameraType);
// now we can call cam->TakeSnapshot
// and know that the correct version will be called.
}
So now we have a concrete instance that implements Camera. We can call TakeSnapshot without checking for the correct type anywhere in code because it doesn't matter; we know the correct version for the correct hardware will be called. Hope this helped.
Per your comment below:
I've been trying to use polymorphism, but I think the elements differ too much. For example, E_SessionTip has an amount and status element where E_Url just has a url. I could unify this under a property system but then I lose all the nice typing entirely. If you know of a way this can work though, I'm open to suggestions.
I would propose passing the responsibility for writing the XML data to your types which share a common interface. For example, instead of something like this:
void WriteXml(Entity *entity) {
switch(/* type of entity */) {
// get data from entity depending
// on its type and format
}
// write data to XML
}
Do something like this:
class SomeEntity : EntityBase {
public:
void WriteToXml(XmlStream &stream) {
// write xml to the data stream.
// the entity knows how to do this,
// you don't have to worry about what data
// there is to be written from the outside
}
private:
// your internal data
}
void WriteXml(Entity *entity) {
XmlStream str = GetStream();
entity->WriteToXml(stream);
}
Does that work for you? I've done exactly this before and it worked for me. Let me know.
Double-dispatch may be of interest. The table (in your case) would call a virtual method of the base element, which in turns calls back into the table. This second call is made with the dynamic type of the object, so the appropriate overloaded method is found in the Table class.
#include <iostream>
class Table; //forward declare
class BaseElement
{
public:
virtual void addTo(Table* t);
};
class DerivedElement1 : public BaseElement
{
virtual void addTo(Table* t);
};
class DerivedElement2 : public BaseElement
{
virtual void addTo(Table* t);
};
class Table
{
public:
void addElement(BaseElement* e){ e->addTo(this); }
void addSpecific(DerivedElement1* e){ std::cout<<"D1"; }
void addSpecific(DerivedElement2* e){ std::cout<<"D2"; }
void addSpecific(BaseElement* e){ std::cout<<"B"; }
};
void BaseElement::addTo(Table* t){ t->addSpecific(this); }
void DerivedElement1::addTo(Table* t){ t->addSpecific(this); }
void DerivedElement2::addTo(Table* t){ t->addSpecific(this); }
int main()
{
Table t;
DerivedElement1 d1;
DerivedElement2 d2;
BaseElement b;
t.addElement(&d1);
t.addElement(&d2);
t.addElement(&b);
}
output: D1D2B
Have a Look at the Visitor Pattern, it might help you
I'm getting an unhandled exception reading location 0x00000008 (reading NULL value) on the noted line below, relevant methods leading up to the error are included (continued below examples):
Event Methods:
Event::Event(Event::EVENTTYPE type) : eventType(type) { }
KeyEvent Methods:
class KeyboardKeyEvent : public Event {
public:
//...
int GetKey() const;
protected:
//...
};
int KeyboardKeyEvent::GetKey() const {
return this->_scancode; //Errors out here. "this" returns 0x000000
}
KeyboardKeyEvent::KeyboardKeyEvent(int key, Event::EVENTTYPE type) : Event(type), _scancode(key) { }
KeyDownEvent Methods:
KeyboardKeyDownEvent::KeyboardKeyDownEvent(int scancode) : KeyboardKeyEvent(scancode, Event::KEYBOARD_KEYDOWN) { }
Event Handler Methods:
bool EventHandler::EnqueueEvent(Event* event) {
if(event == NULL) return false;
try {
this->_eventQueue.push(event);
} catch (...) {
return false;
}
return true;
}
Event* EventHandler::DequeueEvent() {
if(this->_eventQueue.empty() == false) {
Event* result = new Event(*this->_eventQueue.front());
delete this->_eventQueue.front();
this->_eventQueue.pop();
return result;
}
return NULL;
}
Main Loop Sequence:
if(_eh->HasEvents()) {
Event* nxtEvent = _eh->DequeueEvent();
switch(nxtEvent->GetType()) {
case Event::KEYBOARD_KEYDOWN:
allegro_message("You pressed the %d key!", dynamic_cast<KeyboardKeyDownEvent*>(nxtEvent)->GetKey());
break;
default:
/* DO NOTHING */;
}
delete nxtEvent;
nxtEvent = NULL;
}
I know this is a slicing problem I just don't see why it's happening or how to fix it (Actually, now that I think about it, it's probably a "Can not convert to requested type" error). All throughout when I step through the program _scancode is the appropriate value, but the second the line dynamic_cast<KeyboardKeyDownEvent*>(nxtEvent)->GetKey() runs it throws the error. Double casting as dynamic_cast<KeyboardKeyDownEvent*>(dynamic_cast<KeyboardKeyEvent*>(nxtEvent))->GetKey() fails with the same error as well.
EDIT:
After some tweaking, this variant works perfectly:
if(_eh->HasEvents()) {
switch(_eh->PeekEvent()->GetType()) {
case Event::KEYBOARD_KEYDOWN:
allegro_message("You pressed the %s key!", scancode_to_name(dynamic_cast<KeyboardKeyDownEvent*>(_eh->PeekEvent())->GetKey()));
break;
case Event::MOUSE_BUTTONDOWN:{
Mouse::BUTTONS btn = dynamic_cast<MouseButtonDownEvent*>(_eh->PeekEvent())->GetButton();
if(btn == Mouse::BUTTON2) {
allegro_message("You pressed the %d button!", dynamic_cast<MouseButtonDownEvent*>(_eh->PeekEvent())->GetButton());
}
}
break;
default:
/* DO NOTHING */;
}
}
One solution to avoid slicing is to make the destructor of base class virtual, so in your case you can make ~Event() virtual:
class Event
{
public:
//...
virtual ~Event() {}
};
By the way, I'm wondering why you do the following:
//YOUR CODE : its causing the problem!
Event* EventHandler::DequeueEvent() {
if(this->_eventQueue.empty() == false) {
Event* result = new Event(*this->_eventQueue.front()); // WHY?
delete this->_eventQueue.front(); //WHY?
this->_eventQueue.pop();
return result;
}
return NULL;
}
Why don't you simply do this:
//Use it. Because it should not cause that probem
Event* EventHandler::DequeueEvent() {
if(this->_eventQueue.empty() == false) {
Event* result = this->_eventQueue.front();
this->_eventQueue.pop();
return result;
}
return NULL;
}
In Event* EventHandler::DequeueEvent() you have line
Event* result = new Event(*this->_eventQueue.front()); Here the slicing occurs.
You can do the following:
class Event {
public:
virtual Event* clone() {
// create a new instance and copy all the fields
}
}
Then override clone() in derived classes, e.g.
class KeyboardKeyEvent :public Event {
public:
...
virtual KeyboardKeyEvent* clone(); // note - it returns different type
}
Then change Event* EventHandler::DequeueEvent() :
Event* result = (*this->_eventQueue.front()).clone();
Your DequeueEvent method will always return an Event object, not any of the sub-classes that you are expecting.
Event* result = new Event(*this->_eventQueue.front());
Your Dequeue event should either return the actual reference it is caching, or your base Event class need to provide some sort of virtual copy operation that will provide a real clone.
Why are you copying the Event when you remove it from the queue? That's what is doing the slicing, since you're constructing the base class. Instead, return the pointer that was on the queue to the user.
As noted above, Event should have a virtual ~Event(), so that the recipient of the event can delete it properly. Otherwise, the concrete class destructor will not be properly run.
Event* EventHandler::DequeueEvent() {
if(this->_eventQueue.empty() == false) {
Event* result = this->_eventQueue.front();
this->_eventQueue.pop();
return result;
}
return NULL;
}