I am working with pygamezero using an editor called MU (this has the pgzero module built in). When the code is executed the top left of the game window spawns from the centre of the screen and, depending on the dimensions provided by the user for height and width and their screen resolution, portions of the window often appears "off screen". I have found a method - using pygame - that evokes full screen, but am wondering if there is a method to set starting x/y coords of the game screen, so that it is not full-screen, but the window spawn position can be controlled.
To control the window position in Pygame Zero (pgzrun) make use of os.environ['SDL_VIDEO_WINDOW_POS'] as shown below. It must happen before the import pgzrun call, otherwise it won't work.
FYI If you're using Thonny--a teaching & learning IDE--you need to disable Pygame Zero mode from the Run menu to control where the window appears. If you don't disable the mode, Thonny will override your choice by implicitly importing (& thus executing) pgzrun.
The following code snippet will place your window at the top-left corner of the screen. You can also make the window go fullscreen in a different way but that doesn't require os.environ.
x = 0
y = 0
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = f'{x},{y}'
import pgzrun
pgzrun.go()
Note: This question has also been (pretty much) answered elsewhere. Because this question and answer specifically relate to Pygame Zero I'm adding this here so anyone looking specifically for a pygame zero solution can find it.
Related
Is there any way to control where pygame creates the game screen? It seems to always create it in the same general area but not in a consistent location.
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = str(position[0]) + "," + str(position[1])
as per http://pygame.org/wiki/FrequentlyAskedQuestions
You can also just center the screen with
import pygame, os
os.environ['SDL_VIDEO_CENTERED'] = '1'
Note that these should be done before you initialize pygame in the main loop. I do it right after I import os for example. And since they are not actually part of pygame, you can probably use it elsewhere, though things like gtk and wxpython provide their own mechanisms.
Positioning of windows is not handled by the client application. It's handled by the Window manager (metacity etc.).
The SDL library on which PyGame is based does have a few environment variables which can be used to give hints to the Window manager. These are hints which the WM may ignore but it's the best you can do.
The comments over here have an example.
Is there any way to control where pygame creates the game screen? It seems to always create it in the same general area but not in a consistent location.
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = str(position[0]) + "," + str(position[1])
as per http://pygame.org/wiki/FrequentlyAskedQuestions
You can also just center the screen with
import pygame, os
os.environ['SDL_VIDEO_CENTERED'] = '1'
Note that these should be done before you initialize pygame in the main loop. I do it right after I import os for example. And since they are not actually part of pygame, you can probably use it elsewhere, though things like gtk and wxpython provide their own mechanisms.
Positioning of windows is not handled by the client application. It's handled by the Window manager (metacity etc.).
The SDL library on which PyGame is based does have a few environment variables which can be used to give hints to the Window manager. These are hints which the WM may ignore but it's the best you can do.
The comments over here have an example.
I have a 3d rendering program that rotates the world around an observer based on the position the mouse is on the screen. The amount in radians that the world is rotated is defined by this line
glob.worldx=-(w.winfo_pointerxy()[0]-xy[0])/250
Where xy[0] is the x coordinate of the center of the screen
This means that the amount that the observers field of view can be rotated is limited by the distance the mouse can go. If I could get the mouse to come back to the center of the screen I could solve this problem. Any ideas?
The good news is that there is a way to do it.
The intermediate news is that it's not well documented.
The bad news is that it only works on some platforms.
The other intermediate news is that you can step outside of Tk on at least some platforms.
The way to do this in Tcl/Tk is by generating a <Motion> event with -warp 1. The documentation on this is sparse, and scattered around a few different pages (start at bind), but the details are described here. Basically, it's just this:
event generate . <Motion> -warp 1 -x 50 -y 50
So, how do you do this from Tkinter?
Well, event_generate isn't documented anywhere, and neither is the <Motion> event, or the warp parameter… but it's pretty simple to figure out if you know how Tk maps to Tkinter:
window.event_generate('<Motion>', warp=True, x=50, y=50)
And this does indeed generate an event, as you can see by binding <Motion>. Here's a simple test program:
from tkinter import *
root = Tk()
def key(event):
root.event_generate('<Motion>', warp=True, x=50, y=50)
def motion(event):
print('motion {}, {}'.format(event.x, event.y))
root.bind('<Key>', key)
root.bind('<Motion>', motion)
root.mainloop()
Run it, click the window to make sure it has focus, move the cursor around, and you'll see it print out something like this:
motion 65, 69
motion 65, 70
motion 65, 71
Then hit a key, and it'll print out this:
motion 50, 50
Which is great… except that it may not actually be able to move your cursor, in which case all this does is trick Tk into thinking the cursor moved.
From skimming various forums, it looks like:
Mac: Does not work.
You must have Tk 8.6.something or later (see issue 2926819). And you probably have 8.5.something.
But it's not hard to go right to the Cocoa API.
Windows: Usually works.
You must have Tk 8.4.something or later. I couldn't find the bug for this, but you can count on 8.4 with any official Windows binary install of Python 2.7 or 3.x+.
You also must not be running a full-screen app (which you generally aren't, with Tk).
On Vista and later, in some cases it won't work. This may have something to do with not owning the desktop session or not being a local console session, or it may have to do with needing Administrator or other privileges.
If it doesn't work, it's easy to go right to the Win32 API.
X11 (most linux, *BSD, etc.): Usually
Your window manager must not have disabled other clients from warping the pointer. Fortunately, that doesn't seem to be a common thing to do.
If you have this problem, there's no way around it.
Other platforms (iOS, Android, etc.): No idea.
For Mac, you want to generate and send an NSMouseMoved event. The easy way to do this is with pyobjc (which is built in if you're using Apple's Python; otherwise you have to install it):
app = Foundation.NSApplication.sharedApplication()
event = Foundation.NSEvent.mouseEventWithType_location_modifierFlags_timestamp_windowNumber_context_eventNumber_clickCount_pressure_(
Foundation.NSMouseMoved, (50, 50), 0, 0,
app.mainWindow().windowNumber(), None, 0, 0, 0.0)
app.sendEvent_(event)
For Windows, you want to call the SetCursorPos API, or generate and send a MOUSEEVENT. The former will not work with, e.g., DirectX games; the latter may not work with remote desktops. For this case, you probably want the former. Either way, the easiest way to do this is to install pywin32, and then it's just:
win32api.SetCursorPos((50, 50))
For anyone interested in moving the cursor to an absolute position on the screen (using #abarnert's tkinter method):
# Moves the mouse to an absolute location on the screen
def move_mouse_to(x, y):
# Create a new temporary root
temp_root = tk.Tk()
# Move it to +0+0 and remove the title bar
temp_root.overrideredirect(True)
# Make sure the window appears on the screen and handles the `overrideredirect`
temp_root.update()
# Generate the event as #abarnert did
temp_root.event_generate("<Motion>", warp=True, x=x, y=y)
# Make sure that tcl handles the event
temp_root.update()
# Destroy the root
temp_root.destroy()
This function shouldn't interfere with other tkinter windows. Please note that this function creates a new window that is refreshed twice so it might be slow and the user might notice the window created.
I am not writing a game but a scientific renderer using Pygame. I'd like the controls to work just like in a first-person shooter, so that a user can navigate using a familiar set of controls.
I have tried to write the code to have the same properties as the 'look' feature in e.g. Skyrim or Half-Life but the mouse doesn't move the cursor - it lets you look around and around, in infinite circles. Clicking should have no effect.
The first attempt for the controls:
(code inside a game loop)
delta_y, delta_x = pygame.mouse.get_rel()
rotation_direction.x = float(delta_x)
rotation_direction.y = float(delta_y)
(don't ask me why, but y and x need to be reversed like this to get the expected look directions; must be something to do with the camera transform implementation, which isn't mine.)
This, however, leads to a cursor sitting on top of the window, and when the cursor gets to the edge of the screen the window stops rotating; i.e. the code is reporting the actual position on the screen.
I tried to 'reset' the mouse position every game loop (and, incidentally, hide the mouse):
pygame.mouse.set_pos([150, 150])
pygame.mouse.set_visible(False)
But this generates a symmetrical 'move back to start' delta in the next loop, meaning that you couldn't 'look' anywhere.
To summarize, I want to:
detect actual mouse motion reported from the device
not move/show any OS cursor
not clip at the 'edge of a screen'
What is the best way to do this, using Pygame or other Python hacks?
http://www.pygame.org/docs/ref/mouse.html :
If the mouse cursor is hidden, and input is grabbed to the current display the mouse will enter a virtual input mode, where the relative movements of the mouse will never be stopped by the borders of the screen. See the functions pygame.mouse.set_visible - hide or show the mouse cursor and pygame.event.set_grab (docs) - control the sharing of input devices with other applications to get this configured.
Try calling pygame.mouse.get_rel() once more immediately after the set_pos call to 'throw away' whatever relative movement the set_pos call has performed.
Since you are using pyOpenGL, try gluLookAt() example: How do I use gluLookAt properly?
I am trying to rebuild the functionality of the desktop's "highlight to select" feature so that I can use it in my own app. When I say "highlight to select" I mean the selection box that shows up if you click and drag on your desktop (native to all main-stream OS).
I've been working for hours trying to recreate it, and simply can't find a way. I've tried PyGTK, Xlib for python, and a couple other weird hacks. All of which have their own problems that won't allow me to move forward.
I generally don't ask for straight up example code without providing some sort of starting point, but in this project I don't even know where to start. How would you do this?
Here's the requirements:
Must draw on the root window (or a transparent layer that "appears" to be the root)
Must return the coordinates of the selection (x, y, height width)
Update: Forgot some details.
I am using Ubuntu 10.10
I have dual monitors (though, I don't think that should matter)
I don't mind downloading any extra libraries that are necessary
I don't know if this is what you're looking for, but what if you created another window in your module, and have your code show it when you release drag? You could fetch the cursor's current position, and have it draw the window there.
This should help you get the mouse position on the root window.
So, your code may look a little like this (this is untested code!) I'm only showing the relevant portions of what goes inside __ init __.
def __init__(self):
...
#Some of your code here.
...
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
#Note that I am creating a popup window separately.
popwin = gtk.Window(gtk.WINDOW_POPUP)
#I am setting "decorated" to False, so it will have no titlebar or window controls.
#Be sure to compensate for this by having another means of closing it.
popwin.set_decorated(False)
def ShowPopup():
#You may need to put additional arguments in above if this is to be an event.
#For sake of example, I'm leaving this open ended.
#Get the cursor position.
rootwin = widget.get_screen().get_root_window()
curx, cury, mods = rootwin.get_pointer()
#Set the popup window position.
popwin.move(curx, cury)
popwin.show()
def HidePopup():
#This is just an example for how to hide the popup when you're done with it.
popwin.hide()
...
#More of your code here.
...
#Of course, here is the code showing your program's main window automatically.
win.show()
A very simplistic approach, but it should give the appearance of what you're wanting.