Unity show pop up if the player doesn't move for 5 seconds - visual-studio

I have a task on Unity 3d that if the player doesn't move for 5 seconds, a pop-up shows on the center of the screen and if the player moves, the pop-up disappears. How can I write the logic for this task please ?
Thanks

Here is code that will check the mouse position of the user and see if it has moved in the last 5 seconds. If it has not, then the popup window will show up. If it's hard to read here with the comments (I kind of think it is) copy and paste this code into Visual Studio so the colors will help distinguish code from comments.
[SerializeField] GameObject popupWindow = null;
float totTime;
float timeBeforePause = 5f;
Vector3 updatedMousePosition;
private void Update()
{
// Add the time delta between frames to the totTime var
totTime += Time.deltaTime;
// Check to see if the current mouse position input is equivalent to updateMousePosition from the previous update
// If they are equivalent, this means that the user hasn't moved the mouse
if (Input.mousePosition == updatedMousePosition)
{
// Since the user hasn't moved the mouse, check to see if the total Time is greater than the timeBeforePause
if (totTime >= timeBeforePause)
{
// Set the popup window to true in order to show the window (instantiate instead it if if doesn't exist already)
popupWindow.SetActive(true);
}
}
// If the user has moved the mouse, set the totTime back to 0 in order to restart the totTime tracking variable
else
{
totTime = 0;
}
// Check to see if the popup window is visible (active)
if (popupWindow.activeSelf == true)
{
// Check to see if the user has pressed the Esc button
if (Input.GetKeyDown(KeyCode.Escape))
{
// Hide the window
popupWindow.SetActive(false);
}
}
// Update the updatedMousePosition before the next frame/update loop executes
updatedMousePosition = Input.mousePosition;
}
If you want to track different user input (key presses) you can use a similar method. Also you will have to implement some sort of button on the popup window that will allow the user to exit out from the popup window once they return. Hope this helps!

Related

How do I initialise AutoScrollPosition to something other than zero?

In a C# Windows Forms app, I have a Form with a Panel with a PictureBox on it. The PictureBox is twice as wide as the Panel and has a graphics drawing in it. On scaling etc. I set AutoScrollPosition to keep the section of interest in the middle of the Panel: no problem. My problem is: when the app starts I want the Panel to show a section in the middle of the drawing, rather than the left hand side.
In the Form constructor I have:
panel1.AutoScroll = true;
panel1.AutoScrollPosition = new Point(100, 0);
textBox1.Text = panel1.AutoScrollPosition.ToString();
But on starting the app, the TextBox shows (0, 0) and the initial scroll position is at the left.
So, for test, I added a button which when pressed also executes:
panel1.AutoScrollPosition = new Point(100, 0);
textBox1.Text = panel1.AutoScrollPosition.ToString();
The TextBox then shows (100, 0) and the panel is scrolled as expected.
I makes no difference whether or not the AutoScrollPosition line is included in the constructor.
What must I do to initialise the scroll position without user interaction?
Finally solved it: you override OnLoad and set AutoScrollPosition in that, e.g.:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
int yScroll = yToCentre - panel1.Height / 2;
panel1.AutoScrollPosition = new Point(0, yScroll);
}

ContextMenuStrip disappears after a quarter second display

Well, I'm back. I solved the ListBox problem by using a ContextMenuStrip — or so I thought!
It comes in perfect, then in a quarter second, two things happen: it disappears, and the TreeNode unselects.
But for that quarter second, it looks perfect!
The way that progresses is, I step through the lines of code on the right of the screenshot, 5 lines, then one more F11, and it appears for a 1/4 second, and the TreeNode UNSELECTS.
But here's another interesting thing:
In Design Mode, I clicked the reference to contextMenuStrip1 in the dialog bar beneath the Form, and it appears in the place I dropped it.
Then a click on the TreeView (white as I suppose you know) and it disappears.
Ah, but then I take the mouse and pull the TreeView over to the right, again click the reference below, again the ContextMenuStrip appears, then I click the TreeView, and AGAIN it disappears!
What am I missing, dear friends? Something to do with the focus?
Much obliged for any help.
Got it! I found that responding to Closing could be stopped for study with a break point. Then poked around in the Properties, and tried a few things. Then ultimately googled and found the answer at
Do not close ContextMenuStrip on selection of certain items. I added AppFocusChange as not a reason to close.
So far, I'm now able to click the members and select them. Progress!
private void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
if (e.CloseReason == ToolStripDropDownCloseReason.AppClicked ||
e.CloseReason == ToolStripDropDownCloseReason.AppFocusChange)
e.Cancel = true;
}
if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
{
for (int i = 0; i < 4; i++)
{
if (contextMenuStrip1.Items[i].Selected == true)
{
bool res = DoChoice(i);
if (res == true) e.Cancel = false;
}
}
}
Then, at DoChoice, I'll invoke the Add or Edit accordingly, and always returna Close to the strip.

Dialog window positioning

I'm creating a small non-modal dialog in TornadoFX like this:
find<Grib>(scope).apply { openModal(block = true,
owner = FX.primaryStage,
stageStyle = StageStyle.UTILITY,
modality = Modality.NONE) }
How do I go about setting (and retrieving) it's window position for later? That is, I have a preferences object for the window location and I want to update it so that the next time the user opens the window, it opens in the same place they last closed it.
I was able to mostly solve my problem by digging through some of the TornadoFX source code.
I added this to my init{} function:
Platform.runLater {
root.scene.window.x = Main.preferences.getDouble(GRIB_WINDOW_X, 400.0)
root.scene.window.y = Main.preferences.getDouble(GRIB_WINDOW_Y, 400.0)
}
And then adding this to my close() function:
Main.preferences.putDouble(GRIB_WINDOW_X, root.scene.window.x)
Main.preferences.putDouble(GRIB_WINDOW_Y, root.scene.window.y)
This "mostly" solves the problem in that it does save/restore the window position, however the window flickers when it is created as it moves from some default position to the newly set position.

How can I get a borderless child window to re-scale to current screen in multi-monitor setup?

My app has a main window which creates and opens an instance of a subclass of a QML Window {} using createObject(). This window has its flags: set to be a borderless window (I've added code so that it can be grabbed and dragged around).
When I attach a monitor to my laptop and set its font scale factor to 125% (or 150%), when I drag my main window over to the second monitor, you can see it suddenly "snap" to the larger size when it reaches the halfway point. Likewise, when I drag it back to my laptop screen it again "snaps" to the smaller size when I get halfway over (this behavior is what I want, so no problems here).
My problem is that when I drag my created borderless window over into the monitor, it keeps the original 100% scale factor and does not "snap" to a larger size. If I drag my main window over to the monitor, it gets larger but the borderless window remains at the smaller scale; only when I grab the borderless window and move it slightly does it suddenly "snap" to the larger scale size. The same thing happens in reverse - if I then drag the borderless window back onto the laptop, it remains at the larger size until I drag the main window back over and then move the borderless window slightly (at which point it suddenly "snaps" to the smaller size).
So it appears that this created Window uses the scale factor of the screen that the parent window window that created it is currently in, even if it is in a different screen itself.
Is this happening because the Window is borderless? (I'm about to test this but my build process is incredibly slow) Or is there any way to set this borderless Window up so that it detects that it is crossing into a new screen and re-scales itself (in the same way that my main window does)?
Update: I just ran a test giving my Window a native titlebar, and with a titlebar the window instantly adopts ("snaps to") the scale factor of whichever screen it happens to be in, just like my main window (and independent of the main window's scale factor).
So is there any way to duplicate this auto-scaling window behavior with a borderless window? Some flag I need to call, or some method(s) I need to call to get the OS to rescale the window?
Update 2: I tried out Felix's SetWindowPos solution. It does move the window, but this does not fix the scaling problem - the behavior of the frameless window is the same and it still does not correctly pick up the scaling factor of the screen it is in.
I am running a test using MoveWindow instead of SetWindowPos to see if that affects anything [edit: MoveWindow does not work, either - same problem]. Then I'm going to try SendMessage or PostMessage along with NoBugz' suggestion of the WM_DPICHANGED message.
Any other suggestions are welcome.
Update 3: I just created a quick C# app (winforms) to see if the same problem occurs with that, and it doesn't - when a borderless form in the C# app is dragged over into the other monitor, it immediately picks up the scale factor change. So it appears this is a Qt problem.
Update 4: See my answer below for a working solution to this problem (if a bit of a hack).
So as far as I understand, your current goal is to move the window via the WIN-API.
You will have to do so via C++. The approach would be:
Pass the QML Window to a C++-Method exposed to QML as a QQuickWindow (The QML window instanciates that type, as seen in the documentation)
Use QWindow::winId to get the native HWND
Call the SetWindowPos WIN-API method to move it
Code sample (C++-part):
// the method
void moveWindow(QQuickWindow *window, int x, int y) {
HWND handle = (HWND)window->winId();
Q_ASSERT(handle);
::SetWindowPos(handle, HWND_TOP,
x, y, 0, 0,
SWP_NOSIZE | SWP_NOZORDER);
}
// assuming "moveWindow" is a member of "MyClass"
qmlEngine->rootContext()->setContextProperty("mover", new MyClass(qmlEngine));
Code sample (QML-part):
// call this method as soon as the drag has finished, with the new positions
mover.moveWindow(idOfWindow, xPos, yPos);
Note: I would recommend you try out calling this only after the drag was finished (and move the window as you do right now until then). If that works, you can try out what happens if you call this during the drag instead of changing the x/y of the window.
I figured out a relatively simple way to fix this problem. Since a frameless window in Qt gets its scaling factor from the window that created it, the trick is to create another window (that has a titlebar but is not visible to the user) and create the frameless window there, and then add code to the frameless window to keep the hidden window positioned underneath it as the user drags it. When the frameless window is dragged into another screen, the hidden window goes with it, picks up the new scale factor (since it has a titlebar) and then the frameless window immediately gets the new screen's scale factor as well.
Here is sample solution code:
// HiddenWindow.qml
Window {
id: hiddenWindow
// note: just making window visible: false does not work.
opacity: 0
visible: true
flags: Qt.Tool | Qt.WindowTitleHint | Qt.WindowTransparentForInput |
Qt.WindowStaysOnTopHint // Qt.Tool keeps this window out of the
// taskbar
function createVisibleWindow() {
var component = Qt.createComponent("VisibleWindow.qml")
if (component.status === Component.Ready) {
var win = component.createObject(hiddenWindow)
return win
}
}
}
// VisibleWindow.qml
Window {
id: visibleWindow
property var creatorWindow: undefined
flags: Qt.FramelessWindowHint
onXChanged: {
creatorWindow.x = x
}
onYChanged: {
creatorWindow.y = y
}
onWidthChanged: {
creatorWindow.width = width
}
onHeightChanged: {
creatorWindow.height = height
}
}
And then to use these classes from your main window QML:
property var hiddenWindow: undefined
property var visibleWindow: undefined
Component.onCompleted: {
var component = Qt.createComponent("HiddenWindow.qml")
if (component.status === Component.Ready) {
hiddenWindow = component.createObject(null)
}
visibleWindow = hiddenWindow.createVisibleWindow()
visibleWindow.creatorWindow = hiddenWindow
visibleWindow.show()
}
You need to resize window when window move to other screen
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onPressed: {
movePos = Qt.point(mouse.x, mouse.y)
isDoubleClicked = false
lastWindowWidth = mainWindow.width
lastWindowHeight = mainWindow.height
}
onPositionChanged: {
if (!isDoubleClicked) {
const delta = Qt.point(mouse.x - movePos.x, mouse.y - movePos.y)
if (mainWindow.visibility !== Window.Maximized) {
mainWindow.x = mainWindow.x + delta.x
mainWindow.y = mainWindow.y + delta.y
mainWindow.width = lastWindowWidth
mainWindow.height = lastWindowHeight
}
}
}
}

wp7 xna touch. I want the user to keep tapping, not hold

Trying to make an xna game, where the user needs to tap to stop a bar going down. The simulation is like what we see in a WWE PS3/xbox game, the give up bar.
Anyway, the way i have done it, serves the purpose. However, if the user holds the touch, touch values keep incrementing.
What I want is, if the user taps it, only 1 point will be scored. And when he taps again, he will get 1 point more. At the moment what is happening is, if the user holds it, it keeps incrementing, kind of like in a keyboard (if u hold a button, keypresses keeps going on).
foreach (TouchLocation location in TouchPanel.GetState())
{
if (location.State == TouchLocationState.Moved)
{
touchPoints++;
break;
}
}
Change from TouchLocationState.Moved to TouchLocationState.Pressed. That should only occur with each new touch.
foreach (TouchLocation location in TouchPanel.GetState())
{
TouchLocation prevLocation;
bool prevLocationAvailable = location.TryGetPreviousLocation(out prevLocation);
if (location.State == TouchLocationState.Pressed && prevLocation.State != TouchLocationState.Pressed)
{
touchPoints++;
break;
}
}
And for the future, if you're doing Keyboard input and want each press of the keyboard to increment the value but to be ignored if the player is holding down the space, you just have to store the previous state of the keyboard. Then you compare if the current keyboard state the key is being pressed and the previous keyboard state the key wasn't pressed.
(didn't actually code in compiler so there could be some code issues with the below)
KeyboardState currentKeyboardState = Keyboard.GetState();
if (currentKeyboardState.IsKeyDown(Keys.Space) && !previousKeyboardState.IsKeyDown(Keys.Space) {
//Do whatever it is you want to do with the press of the space key
}
previousKeyboardState = currentKeyboardState;
This is a snippet of my code of how i got each touch to be a individual value.
The system.diagnostics line is the test that will show you in your output box.
TouchCollection touch = TouchPanel.GetState();
foreach (TouchLocation touchLocation in touch)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
base.InputPointX = touchLocation.Position.X;
base.InputPointY = touchLocation.Position.Y;
System.Diagnostics.Debug.WriteLine("X: " + base.InputPointX + \
", Y: " + base.InputPointY);
base.Update();
return true;
}
}

Resources