I am creating a 2d game and i have an enemy and a player. I also have three colliders on an enemy and one on a player. I would want it to be like this - One is for looking if player has stepped in his territory(first, and the biggest collider), if so, he would start chasing him, second one is for attack if the player is in it and the third one is for basic collision against walls and etc. The first two one's have Trigger ON. I've tried to come up with something like this, but wasn't getting anything:
public Collider2D playerFinderSpot;
public Collider2D attackSpot;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.name == "Main char")
{
if (attackSpot.isTrigger)
{
Debug.Log("attack player");
}
if (playerFinderSpot.isTrigger)
{
Debug.Log("catching player");
}
}
}
i added a photo if that helps ->
colliders of my enemy
Thanks in advance.
Related
I am now creating a simple video player in QT.
I created a slider that is connected with Connect to a multimedia player (he is responsible for running the movie back and forth) and I want it to be moved by a mouse click anywhere on the slide and not just by dragging the cursor.
I tried to do this by adding my own method as follows:
class MySlider : public QSlider
{
protected:
void mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
if (orientation() == Qt::Horizontal)
{
setValue(minimum() + (maximum() - minimum()) * (static_cast<float>(event->x()) / static_cast<float>(width())));
}
event->accept();
}
QSlider::mousePressEvent(event);
}
};
This is the way I connected the slide to the player:
connect(player, &QMediaPlayer::durationChanged,pos_slider, &MySlider::setMaximum );
connect(player, &QMediaPlayer::positionChanged,pos_slider, &MySlider::setValue );
connect(pos_slider, &MySlider::sliderMoved, player, &QMediaPlayer::setPosition);
connect(pos_slider, &MySlider::valueChanged ,player, &QMediaPlayer::setPosition );
My problem is that now when the movie is playing, there is lag (the movie hangs for a few seconds every few seconds). In my opinion, because of this addition, I am actually putting a lot more pressure on the player because he has now added events to listen and send.
How can I get the slider moving in a way that will not damage the performance of the player? (Or reduce the performance degradation to a minimum)
thank you
yoko
p.s.
The center of the problem is that I use connect(player, &QMediaPlayer::positionChanged,pos_slider, &MySlider::setValue ); in the media player and also connect(pos_slider, &MySlider::valueChanged ,player, &QMediaPlayer::setPosition ); , this duplication is causing performance problems, but I have no idea how I can get rid of this duplication
As you pointed out yourself, the problem is (probably) due to resonance between QMediaPlayer::position and MySlider::value.
Solution 1:
So, you should avoid changing the QMediaPlayer::position when MySlider::value is updated programmatically, i.e. do not use the following connection:
connect(pos_slider, &MySlider::valueChanged ,player, &QMediaPlayer::setPosition );
Instead, you should use the sliderReleased and sliderMoved signals to update QMediaPlayer::position and call QMediaPlayer::setPosition manually inside mousePressEvent (when appropriate).
Solution 2: (thanks too Karsten Koop)
Create your own slot to update the slider value when QMediaPlayer::position changed to block emitting signals.
connect(player, &QMediaPlayer::positionChanged,pos_slider, &MySlider::updateValueFromMediaPlayer );
void MySlider::updateValueFromMediaPlayer(int pos)
{
blockSignals(true);
setValue(pos);
blockSignals(false);
}
Note that you do not need the following connection in this case:
connect(pos_slider, &MySlider::sliderMoved, player, &QMediaPlayer::setPosition);
I'm developing an application with a menu which contains a list of buttons, when you click one of these buttons, another activity (the same activity with different image for each button) is opened showing an imageview. The problem is that when i click several times in different buttons (opening new images) the app crashes and i'm not able to solve it. Any help? Thanks.
That problem is because your are using a lot of images in your views and never clean the memory, then in one momento your don't have more memory for the new ones.
One form to resolve that problem is cleaning the memory always your destroy and activity.
You can override the next method in your activity for clean the memory.
#Override
public void unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
that method review a view, in your case those views will be your ImageView and ImageButton.
Finally you need call this method in the method onDestroy() (need override that method too).
my QComboBox-derived class lives in a QGraphicsScene at the bottom end of the (visible) screen - but it pops up downwards, thus out of view.
(How) is it possible to force the popup to open above the widget?
I've tried re-implementing showPopup like this:
void MyComboBox::showPopup()
{
QAbstractItemView *popupView = view();
popupView->move(0,-100);
//popupView->window->move(0,-100);
QComboBox::showPopup();
}
The result is, that the content seems to be shifted, but not the underlying popup object.
I think it might be possible to find a solution with styles as indicated in
this article, but I can't find any Styles control that might be helpful here. I am rather new to C++ as well as Qt, so I might be missing something obvious.
I'd appreciate any help on this matter!
Best regards,
Sebastian
With the information found here, I was able to get it done this way:
void SteuerQComboBox::showPopup() {
QComboBox::showPopup();
QWidget *popup = this->findChild<QFrame*>();
popup->move(popup->x(),popup->y()-this->height()-popup->height());
}
Note that it's crucially important to call the base classes "showPopup" first.
Thanks to everybody who was reading my question and thinking about it!
user1319422's solution isn't bad, but it has two problems.
If your platform has GUI animation, the listbox will animate opening downwards, then is moved above the text box.
If you disable combobox animation (or you don't have it), the call to QComboBox::showPopup() still makes the GUI element start to appear on the screen already. So, moving it there would cause it to flicker as it appears in the first place and moves to the next.
So, to address the first problem, I just switched off animation:
void MyComboBox::showPopup()
{
bool oldAnimationEffects = qApp->isEffectEnabled(Qt::UI_AnimateCombo);
qApp->setEffectEnabled(Qt::UI_AnimateCombo, false);
QComboBox::showPopup();
qApp->setEffectEnabled(Qt::UI_AnimateCombo, oldAnimationEffects);
}
Then, for the second problem, I moved the frame in the Show event:
bool MyComboBox::eventFilter(QObject *o, QEvent *e)
{
bool handled = false;
if (e->type() == QEvent::Show)
{
if (o == view())
{
QWidget *frame = findChild<QFrame*>();
//For some reason, the frame's geometry is GLOBAL, not relative to the QComboBox!
frame->move(frame->x(),
mapToGlobal(lineEdit()->geometry().topLeft()).y() - frame->height());
}
}
/*else if other filters here*/
if (!handled)
handled = QComboBox::eventFilter(o, e);
return handled;
}
if you want to force popup to open above only when it is out of view you can do this:
void SteuerQComboBox::showPopup() {
QComboBox::showPopup();
QWidget *popup = this->findChild<QFrame*>();
if((popup->y() + popup->height()) > this->window()->height())
popup->move(popup->x(),popup->y()-this->height()-popup->height());
}
I need some opinions on what is the "ideal" design pattern for a general mouse
interaction.
Here the simplified problem. I have a small 3d program (QT and openGL) and
I use the mouse for interaction. Every interaction is normally not only a
single function call, it is mostly performed by up to 3 function calls (initiate, perform, finalize).
For example, camera rotation: here the initial function call will deliver the current first mouse position,
whereas the performing function calls will update the camera etc.
However, for only a couple of interactions, hardcoding these (inside MousePressEvent, MouseReleaseEvent MouseMoveEvent or MouseWheelEvent etc)
is not a big deal, but if I think about a more advanced program (e.g 20 or more interactions) then a proper design is needed.
Therefore, how would you design such a interactions inside QT.
I hope I made my problem clear enough, otherwise don't bother complain :-)
Thanks
I suggest using polymorphism and the factory method pattern. Here's an example:
In my Qt program I have QGraphicsScenes and QGraphicsItems with mousePressEvent, mouseMoveEvent, and mouseReleaseEvent, which look like this:
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// call factory method, which returns a subclass depending on where click occurred
dragHandler = DragHandler::createDragHandler(event /* and other relevant stuff */);
}
void CustomItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
dragHandler->onMouseMove(event);
}
void CustomItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
dragHandler->onMouseRelease(event);
delete dragHandler;
}
The idea in this particular case is that depending on where I click on CustomItem, mouse pressing, moving, and releasing will have different functionality. For example, if I click on the edge of the item, dragging will resize it, but if I click in the middle of the item, dragging will move it. DragHandler::onMouseMove and DragHandler::onMouseRelease are virtual functions that are reimplemented by subclasses to provide the specific functionality I want depending on where the mouse press occurred. There's no need for DragHandler::onMousePress because that's basically the constructor.
This is of course a rather specific example, and probably not exactly what you want, but it gives you an idea of how you can use polymorphism to clean up your mouse handling.
Qt makes this beautifully simple.
Instead of all the switch mouse_mode: stuff you used to write, simply have each mouse event handler function emit a signal ie. mouseDown/mouseUp/mousePosition and use signals/slots to route those to the appropriate model functions.
Then you can accommodate different uses of the mouse (selecting, rotating, editing etc) by connect/disconnect different SLOTS to the signal sent in the Mouse...Event()
I find Apple's UIGestureRecognizer design quite nice and extendable.
The idea is to decouple the recognition of the gesture (or interaction) and the action that will be triggered.
You need to implement a basic or abstract GestureRecognizer class that is able to recognize a certain interaction or gesture based on events MousePressEvent, MouseReleaseEvent MouseMoveEvent or MouseWheelEvent etc. GestureRecongnizers have a target to report changes periodically.
For example your very basic class would be like: (sorry my poor semi c++ pseudo-code ... recently I don't use it that much)
class Recognizer {
int state; // ex: 0:possible, 1:began, 2:changed, 3:ended/recognized 4:cancelled
protected:
void setTarget(void &theTarget); // or even better a touple, target/method. In this case target is assumed to have a method gestureHandle(Recognizer *r);
virtual void mouserPress() = 0;
virtual void mouserRelease() = 0;
virtual void mouserMove() = 0;
virtual void mouserWheel() = 0;
...
}
And if you want to detect a swipe with the mouse
class SwipeRecognizer : Recognizer {
int direction; // ex: 0:left2right 1:bottom2top 2:...
private:
void mouserPress() {
state = 0; // possible. You don't know yet is the mouse is going to swipe, simple click, long press, etc.
// save some values so you can calculate the direction of the swipe later
target.gestureHandle(this);
};
void mouserMove() {
if (state == 0) {
state = 1; // it was possible now you know the swipe began!
direction = ... // calculate the swipe direction here
} else if (state == 1 || state == 2) {// state is began or changed
state = 2; // changed ... which means is still mouse dragging
// probably you want to make more checks here like you are still swiping in the same direction you started, maybe velocity thresholds, if any of your conditions are not met you should cancel the gesture recognizer by setting its state to 4
}
target.gestureHandler(this);
};
void mouserRelease() {
if (state == 2) { // is swipping
state = 3; // swipe ended
} else {
state = 4; // it was not swiping so simple cancel the tracking
}
target.gestureHandler(this);
};
void mouserWheel() {
// if this method is called then this is definitely not a swipe right?
state = 4; // cancelled
target.gestureHandler(this);
}
Just make sure above methods are called when the events are happening and they should call the target when needed.
This is how the target will look to me:
class Target {
...
void gestureHandler(Recognizer *r) {
if (r->state == 2) {
// Is swipping: move the opengl camera using some parameter your recognizer class brings
} else if (r->state == 3) {
// ended: stop moving the opengl camera
} else if (r->state == 4) {
// Cancelled, maybe restore camera to original position?
}
}
Implementation of UIGestureRecognizer is quite nice and will allow to register several targets /method for the same recognizer and several recognizers to the same view.
UIGestureRecognizers have a delegate object that is used to get information about other gesture recognizers, for example, if two gestures can be detected at the same time, or should one must fail as soon as the other is detected, etc.
Some gesture recognizer will require more overrides than others but the big PRO of this is that their output is the same: a handler method that informs about the current state (and other info).
I think is worth taking a look at it
Hope it helps :)
I am building a complex Flex app, and now I am at the point where navigation becomes a problem. I make use of Viewstacks with a Menu Bar, but I am not sure how to clearly structure this.
Depending on the logged in User and chosen Company by the user, he can see different pages. For now I restricted this hiding the appropriate buttons in the Menu Bar. However, not just the menu bar, but also buttons/links from within the app should be able to navigate to each existing page.
When I am loading up an existing page, it needs some initialization (depending on the context it is loaded from). In addition, when a company is chosen, I need to load the status from the backend, and depending on this status a specific page might be visible.
Are there any guidelines how to tackle more complex navigation/site hierarchies in Flex?
Now I am having all my views in a viewstack in the Application, and refer to it with Application.application.appViews.selectedChild -> but that's obviously not best practice, since it violates encapsulation.
Was thinking of implementing some sort of State Machine, which takes care of all this, but not quite sure it this would make sense, or if there is any better way.
Thanks guys,
Martin
If it's really complex, you might want to consider breaking your application up into modules.
Also, Mate is a great Flex framework for handling complex communication and navigation. Mate's EventMaps help you centralize the communication and logic between components, modules, etc. And, it keeps you away from the dreaded Application.application references.
Even if you don't use a framework like Mate, you can avoid the Application.application references by having components dispatch custom events that bubble up to the top-level of your application. The top level of the application can listen and catch these events and act on them. I've found this to be a much more flexible approach. I avoid Application.application as much as possible!
If you have a complex menu bar that needs to enable / disable a lot of buttons or options based on many different logic conditions, the State pattern is a decent way to handle it. I built an enterprise-level app that had a "Word-like" button bar at the top...and there were so many different conditions that affected the states of the buttons that I had to centralize the logic in one place. At first I didn't use the State pattern and maintaining the code was a difficult chore. One day, I bit the bullet and re-factored all the conditional logic into a StateManager class. It definitely made life easier from there on out.
Again, you might want to consider using Custom Events to broadcast important events to your application. You can make these events bubble up to the Application level. Then, by adding event listeners at the Application level, you can capture and respond to these events and target components or modules from the Application level. This gives you a central location for handling events and "directing traffic". It also prevents the tight-coupling of the Application.application approach. (Which quickly becomes a nightmare as your application grows and scales!)
For example, your StateManager can contain the case statements for deciding which state your application needs to be in. Once the decision about the current state is determined, you would dispatch a custom StateEvent. (Which might have properties like StateEvent.STATE_CHANGED and StateEvent.CURRRENT_STATE) This event can bubble up to the Application level and be caught by a listener. The listener then calls a method to load / change the state.
Does that clarify it for you? If not, perhaps I can spend an hour or two putting together a little sample.
Let me know,
=Bryan=
I can give you the approach I used for some of your sub-questions, the problem of initializing a page at runtime and how to encapsulate navigation.
For page initialization, the issue I came across is that it's not always known once you navigate to a page whether certain elements should be shown, since it not-only depends on overall user permissions, but also permissions against the currently-selected data. And if the information needed to determine this must be loaded from the server, you cannot show the page as-is while loading the information. So we created a control called LoadingPanel, which is a container that can cover content with a loading indicator until additional information has been received. Here's a shortened version of the ActionScript:
[DefaultProperty("children")]
public class LoadingPanel extends ViewStack
{
public function LoadingPanel()
{
this.resizeToContent = false;
super();
}
public function get children():Array { return _children }
public function set children(value:Array):void { _children = value; }
public function get loadingImageStyle():String {
return _loadingImgStyle; }
public function set loadingImageStyle(value:String):void {
_loadingImgStyle = value;
if (_loadingIndic)
_loadingIndic.loadingImageStyle = value;
}
public function showLoadingIndicator():void
{
if (_loadingIndic)
{
super.selectedChild = _loadingIndic;
}
else
{
_pendingLoadingIndic = true;
var me:LoadingPanel = this;
var listener:Function = function(event:Event):void
{
if (me._pendingLoadingIndic)
me.showLoadingIndicator();
}
addEventListener(FlexEvent.CREATION_COMPLETE, listener);
}
}
public function hideLoadingIndicator():void
{
_pendingLoadingIndic = false;
if (_content)
{
super.selectedChild = _content;
}
else
{
var me:LoadingPanel = this;
var listener:Function = function(event:Event):void
{
me.hideLoadingIndicator();
}
addEventListener(FlexEvent.CREATION_COMPLETE, listener);
}
}
public function waitForEvent(target:EventDispatcher, event:String):void
{
_eventCount++;
showLoadingIndicator();
var me:LoadingPanel = this;
target.addEventListener(
event,
function(evt:Event):void
{
me._eventCount--;
if (!me._eventCount)
{
me.hideLoadingIndicator();
}
}
);
}
override public function addChild(child:DisplayObject):DisplayObject
{
var result:DisplayObject = child;
if (_content)
{
result = _content.addChild(child);
invalidateDisplayList();
}
else
{
if (!_children)
{
_children = [];
}
_children.push(child);
}
return result;
}
override protected function createChildren():void
{
super.createChildren();
if (!_content)
{
_content = new Box();
_content.percentWidth = 1.0;
_content.percentHeight = 1.0;
super.addChild(_content);
}
if (!_loadingIndic)
{
_loadingIndic = new LoadingIndicator();
_loadingIndic.percentWidth = 1.0;
_loadingIndic.percentHeight = 1.0;
_loadingIndic.loadingImageStyle = _loadingImgStyle;
super.addChild(_loadingIndic);
}
if (_children)
{
for each (var child:DisplayObject in _children)
{
_content.addChild(child);
}
}
}
private var _loadingImgStyle:String = "loadingIndicatorDark";
private var _loadingIndic:LoadingIndicator = null;
private var _content:Box = null;
private var _children:Array = null;
private var _pendingLoadingIndic:Boolean = false;
private var _eventCount:int = 0;
}
We typically used these by wrapping a LoadingPanel around content then calling the panel's waitForEvent method. Typically, the event we'd wait for is for a web service response to come in. The class also lets you wait on multiple events before it will show its children.
Another recommendation I would make for your project is that you look into deep linking in Flex. Our users appreciated being able to bookmark a resource/location in our complex Flex application as well as being able to hit refresh in their browser and return to the same "page" they were on. But implementing deep linking also helped me out for one of the problems you mentioned; how do you send the UI to a specific page in an encapsulated manner? The way we did it is by raising a bubbling navigation event containing a destination "URL." A top-level navigation "manager" then handled interpreting the URL and "sending" the user to the appropriate area.
Hopefully this will give you some ideas for some of the challenges you face.