Moving a sprite when mouse is pressed in Python - python

I'm making a Pong clone for learning purposes, and need to get the ball moving from the middle of the screen (it's sent there when it goes past a paddle) when the mouse is pressed. I've tried the following code, but it does nothing, so I probably don't understand the syntax. Try to keep it as simple as possible please, and explain it, I'd rather not have 50 lines of code for this (I want to understand everything I'm using here). I think this is all the relevant code, sorry if it isn't. Thanks.
def middle(self):
"""Restart the ball in the centre, waiting for mouse click. """
# puts ball stationary in the middle of the screen
self.x = games.screen.width/2
self.y = games.screen.height/2
self.dy = 0
self.dx = 0
# moves the ball if mouse is pressed
if games.mouse.is_pressed(1):
self.dx = -3

It's impossible to know exactly what's happening based on that code fragment, but it looks like you are using the wrong function to detect whether or not the mouse button is pressed.
Screen.is_pressed from the games module wraps pygame.key.get_pressed, which only detects the state of keyboard keys, not mouse buttons. You probably want the function Screen.mouse_buttons, which wraps pygame.mouse.get_pressed. You could use it within a loop like this (I'll pretend you have an instance of games.Screen called 'screen'):
left, middle, right = screen.mouse_buttons()
# value will be True if button is pressed
if left:
self.dx = -3

I am looking at the same issue as a beginner Python coder - Games.py (revision 1.7) includes several is_pressed methods in various classes, including both keyboard and mouse.
class Mouse(object):
#other stuff then
def is_pressed(self, button_number):
return pygame.mouse.get_pressed()[button_number] == 1
since pygame is a compiled module (I have 1.9.1) referring to the documentation rather than source code, I find here that there is a pygame.mouse.get_pressed():
the will get the state of the mouse buttons
get_pressed() -> (button1, button2, button3)
So I think the issue is the use of this in (y)our code rather than the use of the wrong function.....
OK GOT THIS TO WORK - MY FIX:
class myClass(games.Sprite):
def update(self):
if games.mouse.is_pressed(0)==1:
self.x=games.mouse.x
self.y=games.mouse.y
invoking the in Main() causes the selected sprite to move to the mouse location. HTH

Related

How to move from one screen to another, with any input from the user, in pygame? [duplicate]

I'm making a little game and I want to make another window separately from my main one.
I have the the main game in a main window, and I want to open a new window and do a little animation when the user does something.
In my example code below, when the user presses "a" I want it to open a new window and blit to there.
Here I set up the two windows: (I know this doesnt work, its what I'm asking how to do)
SCREEN_X = 400
SCREEN_Y = 400
BSCREEN_X = 240
BSCREEN_Y = 160
BATTLE_SCENE = pygame.display.set_mode((BSCREEN_X, BSCREEN_Y))
SCREEN = pygame.display.set_mode((SCREEN_X, SCREEN_Y))
and then the program:
def run_ani ():
#Do animation, blitting to BATTLE_SCENE
return
def main_game():
ending=False
while ending==False:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT: ending=True
if event.type == KEYDOWN: # key down or up?
if event.key == K_ESCAPE:
ending=True # Time to leave
print("Stopped Early by user")
elif event.key == K_a:
run_ani()
#Normal screen motion, blitting to SCREEN
if ending: pygame.quit()
return
So far what this does is draws the main screen, then when A is pressed, it stops drawing the main screen animations, but still draws the other animations on the main screen and draws in the top left corner.
I'm pretty sure it does this because I am setting BATTLE_SCENE to be smaller than the main screen, thus when blitting to BATTLE_SCENE it blits to the area I created (240x160) in the top corner of the main screen.
However I want BATTLE_SCENE to be a seperate window, so that when I press 'a' it will pop up, do its thing, then close or at least go behind the main screen.
How to do this? Is it even possible?
Do you really need multiple windows? I mean, do you really need them?
If yes, then you should probably use pyglet/cocos2d instead.
To have multiple windows in pygame, you need multiple processes (one for each window). While this is doable, it's not worth the efford. You'll need IPC to exchange data between the windows, and I guess your code will become error-prone and ugly.
Go with pyglet when you need more than one window.
The better solution is probably to divide your game into scenes. Create multiple scenes so that each one represent one stage of the game, something like MenuScene, MainScene, BattleScene, GameOverScene, OptionScene etc.
Then let each of those scenes handle input/drawing of that very part of the game.
MenuScene handles drawing and input etc. of the game's menu
MainScene handles drawing and input etc. of the running game
BattleScene handles drawing and input etc. of whatever you do in run_ani
In your mainloop, just pass control over to the current scene by implementing the methods draw(), handle_event(), and update().
Some example code to get the idea:
scenes = {'Main': MainScene(),
'Battle': BattleScene()} #etc
scene = scenes['Main']
class MainScene():
...
def handle_event(self, event):
if event.type == KEYUP:
if event.key == K_a:
scene = scenes['Battle']
...
class BattleScene():
...
def draw(self):
# draw your animation
def update(self):
# if animation is over:
scene = scenes['Main']
...
def main_game():
ending=False
While Not ending:
clock.tick(30)
for event in pygame.event.get():
scene.handle_event(event)
scene.update()
scene.draw()
This is an easy way to cleanly seperate the game logic and allow context switching.
======================================Edit=========================================
Actually it won't work. Apperantly pygame only supports one display screen, and when you initialize another, it will close the first. You will stay with two varibles, which in fact are the same surface. You can have instead the game increasing the window size and playing the battle scene on the side of it, to do this, you can call the pygame.display.set_mode() again with different values. The varible which references the display screen will still be usable, as it change its reference to the new one. After the scene is over you can decrease the window back the same way.
==================================================================================
What basically happens is you run a loop, and each iteration of it is rendering and displaying a new frame.
When you call a function inside a loop, it doesn't continue to run until you finish running the function.
One way to solve this problen is just keep calling the function that updates the battle scene in the main loop.
Another way is by using threading. Threading is basically running multiple scripts ("Threads") in the same time.
Luckily, python already implemented this for us with the threading module.
It's too long for me to explain the module here, but you can learn it here. It might be a little complex if you haven't use threads before, but after some time it will be easier.
And If you want to learn more about threading you can go here.
Specificly here, you can have two threads, one for each loop/window, and run them in the same time.
Hope I helped you!
Yes, that is possible. SDL2 is able to open multiple windows. In the example folder you can take a look at "video.py".
https://github.com/pygame/pygame/blob/main/examples/video.py
"This example requires pygame 2 and SDL2. _sdl2 is experimental and will change."

trying to draw over sprite or change picture pyglet

I am trying to learn pyglet and practice some python coding with a questionnaire thing, but I am unable to find a way to make the background picture be removed or drawn on top of or something for 10 seconds. I am new and am lacking in a lot of the knowledge I would need, thank you for helping!
import pyglet
from pyglet.window import Window
from pyglet.window import key
from pyglet import image
import time
card1 = False
cat_image = pyglet.image.load("cat.png")
dog_image = pyglet.image.load("dog.png")
image = pyglet.image.load("backg.png")
background_sprite = pyglet.sprite.Sprite(image)
cat = pyglet.sprite.Sprite(cat_image)
dog = pyglet.sprite.Sprite(dog_image)
window = pyglet.window.Window(638, 404, "Life")
mouse_pos_x = 0
mouse_pos_y = 0
catmeme = pyglet.image.load("catmeme.png")
sprite_catmeme = pyglet.sprite.Sprite(catmeme)
#window.event
def on_draw():
window.clear()
background_sprite.draw()
card_draw1(63, 192, 385, 192)
def card1():
while time.time() < (time.time() + 10):
window.clear()
sprite_catmeme.draw()
#window.event
def card_draw1(x1, y1, x2, y2):
cat.set_position(x1, y1)
dog.set_position(x2, y2)
cat.draw()
dog.draw()
def card_draw2():
pass
#window.event
def on_mouse_press(x, y, button, modifiers):
if x > cat.x and x < (cat.x + cat.width):
if y > cat.y and y < (cat.y + cat.height):
card1()
game = True
while game:
on_draw()
pyglet.app.run()
There's a few flaws in the order and in which you do things.
I will try my best to describe them and give you a piece of code that might work better for what your need is.
I also think your description of the problem is a bit of an XY Problem which is quite common when asking for help on complex matters where you think you're close to a solution, so you're asking for help on the solution you've come up with and not the problem.
I'm assuming you want to show a "Splash screen" for 10 seconds, which happens to be your background? And then present the cat.png and dog.png ontop of it, correct?
If that's the case, here's where you probably need to change things in order for it to work:
The draw() function
It doesn't really update the screen much, it simply adds things to the graphical memory. What updates the screen is you or something telling the graphics library that you're done adding things to the screen and it's time to update everything you've .draw()'n. So the last thing you need in the loop would be window.flip() in order for the things you've drawn to actually show.
Your things might show if you try to wiggle the window around, it should trigger a re-draw of the scene because of how the internal mechanics of pyglet work..
If you don't call .flip() - odds are probable that the redraw() call will never occur - which again, is a internal mechanism of Pyglet/GL that tells the graphics card that something has been updated, we're done updating and it's time to redraw the scene.
a scene
This is the word most commonly used for what the user is seeing.
I'll probably throw this around a lot in my text, so it's good to know that this is what the user is seeing, not what you've .draw()'n or what's been deleted, it's the last current rendering of the graphics card to the monitor.
But because of how graphical buffers work we've might have removed or added content to the memory without actually drawing it yet. Keep this in mind.
The pyglet.app.run() call
This is a never ending loop in itself, so having that in a while game: loop doesn't really make sense because .run() will "hang" your entire application, any code you want to execute needs to be in def on_draw or an event that is generated from within the graphical code itself.
To better understand this, have a look at my code, i've pasted it around a couple of times here on SO over the years and it's a basic model of two custom classes that inherits the behavior of Pyglet but lets you design your own classes to behave slightly differently.
And most of the functionality is under on_??? functions, which is almost always a function used to catch Events. Pyglet has a lot of these built in, and we're going to override them with our own (but the names must be the same)
import pyglet
from pyglet.gl import *
key = pyglet.window.key
class CustomSprite(pyglet.sprite.Sprite):
def __init__(self, texture_file, x=0, y=0):
## Must load the texture as a image resource before initializing class:Sprite()
self.texture = pyglet.image.load(texture_file)
super(CustomSprite, self).__init__(self.texture)
self.x = x
self.y = y
def _draw(self):
self.draw()
class MainScreen(pyglet.window.Window):
def __init__ (self):
super(MainScreen, self).__init__(800, 600, fullscreen = False)
self.x, self.y = 0, 0
self.bg = CustomSprite('bg.jpg')
self.sprites = {}
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE: # [ESC]
self.alive = 0
elif symbol == key.C:
print('Rendering cat')
self.sprites['cat'] = CustomSprite('cat.png', x=10, y=10)
elif symbol == key.D:
self.sprites['dog'] = CustomSprite('dog.png', x=100, y=100)
def render(self):
self.clear()
self.bg.draw()
for sprite_name, sprite_obj in self.sprites.items():
sprite_obj._draw()
self.flip()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
x = MainScreen()
x.run()
Now, this code is kept simple on purpose, the full code I usually paste on SO can be found at Torxed/PygletGui, the gui.py is where most of this comes from and it's the main loop.
What I do here is simply replace the Decorators by using "actual" functions inside a class. The class itself inherits the functions from a traditional pyglet.window.Window, and as soon as you name the functions the same as the inherited onces, you replace the core functionality of Window() with whatever you decide.. In this case, i mimic the same functions but add a few of my own.
on_key_press
One such example is on_key_press(), which normally just contain a pass call and does nothing, here, we check if key.C is pressed, and if so - we add a item to self.sprites.. self.sprites just so happen to be in our render() loop, anything in there will be rendered ontop of a background.
Here's the pictures I used:
(named bg.jpg, cat.png, dog.png - note the different file endings)
class:CustomSprite
CustomSprite is a very simple class designed to make your life easier at this point, nothing else. It's very limited in functionality but the little it do is awesome.
It's soul purpose is to take a file name, load it as an image and you can treat the object like a traditional pyglet.sprite.Sprite, meaning you can move it around and manipulate it in many ways.
It saves a few lines of code having to load all the images you need and as you can see in gui_classes_generic.py you can add a heap of functions that's "invisible" and normally not readily availbale to a normal sprite class.
I use this a bunch! But the code gets complicated real fast so I kept this post simple on purpose.
the flip function
Even in my class, I still need to use flip() in order to update the contents of the screen. This is because .clear() clears the window as you would expect, that also triggers a redraw of the scene.
bg.draw() might in some cases trigger a redraw if the data is big enough or if something else happens, for instance you move the window.
but calling .flip() will tell the GL backend to force a redraw.
Further optimizations
There's a thing called batched rendering, basically the graphic card is designed to take enormous ammounts of data and render it in one go, so calling .draw() on several items will only clog the CPU before the GPU even gets a chance to shine. Read more about Batched rendering and graphics! It will save you a lot of frame rates.
Another thing is to keep as little functionality as possible in the render() loop and use the event triggers as your main source of coding style.
Pyglet does a good job of being fast, especially if you only do things on event driven tasks.
Try to avoid timers, but if you really do need to use time for things, such as removing cat.png after a certain ammount of time, use the clock/time event to call a function that removes the cat. Do not try to use your own t = time() style of code unless you know where you're putting it and why. There's a good timer, I rarely use it.. But you should if you're starting off.
This has been one hell of a wall of text, I hope it educated you some what in the life of graphics and stuff. Keep going, it's a hurdle to get into this kind of stuff but it's quite rewarding once you've mastered it (I still haven't) :)

Turtle in python- Trying to get the turtle to move to the mouse click position and print its coordinates

I'm trying to get the mouse position through Python turtle. Everything works except that I cannot get the turtle to jump to the position of the mouse click.
import turtle
def startmap(): #the next methods pertain to drawing the map
screen.bgcolor("#101010")
screen.title("Welcome, Commadore.")
screen.setup(1000,600,1,-1)
screen.setworldcoordinates(0,600,1000,0)
drawcontinents() #draws a bunch of stuff, works as it should but not really important to the question
turtle.pu()
turtle.onclick(turtle.goto)
print(turtle.xcor(),turtle.ycor())
screen.listen()
As I understand, the line that says 'turtle.onclick(turtle.goto)' should send the turtle to wherever I click the mouse, but it does not. The print line is a test, but it only ever returns the position that I sent the turtle last, nominally (0, 650) although this does not have major significance.
I tried looking up tutorials and in the pydoc, but so far I have not been able to write this successfully.
I appreciate your help. Thank you.
Edit: I need the turtle to go to the click position(done) but I also need it to print the coordinates.
You are looking for onscreenclick(). It is a method of TurtleScreen. The onclick() method of a Turtle refers to mouse clicks on the turtle itself. Confusingly, the onclick() method of TurtleScreen is the same thing as its onscreenclick() method.
24.5.4.3. Using screen events¶
turtle.onclick(fun, btn=1, add=None)
turtle.onscreenclick(fun, btn=1, add=None)¶
Parameters:
fun – a function with two arguments which will be called with the coordinates of the clicked point on the canvas
num – number of the mouse-button, defaults to 1 (left mouse button)
add – True or False – if True, a new binding will be added, otherwise it will replace a former binding
Bind fun to mouse-click events on this screen. If fun is None, existing bindings are removed.
Example for a TurtleScreen instance named screen and a Turtle instance named turtle:
>>> screen.onclick(turtle.goto) # Subsequently clicking into the TurtleScreen will
>>> # make the turtle move to the clicked point.
>>> screen.onclick(None) # remove event binding again
Note: This TurtleScreen method is available as a global function only under the name onscreenclick. The global function onclick is another one derived from the Turtle method onclick.
Cutting to the quick...
So, just invoke the method of screen and not turtle. It is as simple as changing it to:
screen.onscreenclick(turtle.goto)
If you had typed turtle.onclick(lambda x, y: fd(100)) (or something like that) you would probably have seen the turtle move forward when you clicked on it. With goto as the fun argument, you would see the turtle go to... its own location.
Printing every time you move
If you want to print every time you move, you should define your own function which will do that as well as tell the turtle to go somewhere. I think this will work because turtle is a singleton.
def gotoandprint(x, y):
gotoresult = turtle.goto(x, y)
print(turtle.xcor(), turtle.ycor())
return gotoresult
screen.onscreenclick(gotoandprint)
If turtle.goto() returns None (I wouldn't know), then you can actually do this:
screen.onscreenclick(lambda x, y: turtle.goto(x, y) or print(turtle.xcor(), turtle.ycor())
Let me know if this works. I don't have tk on my computer so I can't test this.

A way to animate transition with Python, Gtk and Cairo?

people
I have seen some tutorials showing how to create animations with PyGtk, the best one being this:
https://cairographics.org/cookbook/animationrotation/
This tutorial uses gobject.timeout_add() to set some clock to constantly refresh the animation.
What I wanted to do, instead, is to create FINITE animations, which I could trigger by clicking in some button or checkbox or anything.
For example, I could have a Window with a Button and a DrawingArea with a ball drawn.
When I click the button, the ball would go up and down, and stop. If I click the button again, the ball repeats the move.
In another scenario, the ball could be on the left of the screen. When I toggle a CheckBox, the ball goes (not instantly, but rather moves in a transition) to the right. If I uncheck, the ball comes back to its original position.
I am not planning to use anything else than pure Cairo/Gtk (no Clutter, no OpenGL, no PyGame), because I feel that it should be possible, and I want to go on studying Gtk to do some (future) GUI tricks with simple one-file scripts.
Since the question is about a broader problem, I think it is not needed to add code, but I could edit this question to put some code if anyone feels it would be better.
Thanks for reading and for any help! And Cairo/Gtk is great!
EDIT: after the precise explanation from Jeremy Flores, I came out with this code, which is useless (the ball goes to the right each time the button is clicked, untill falling off the window), but contains the elements upon which to build more creative and useful stuff. If anyone (including Jeremy) has anything to say about this code, specially about removing unnecessary parts, I would very gladly like to hear. Thanks!
#!/usr/bin/env python
import gtk, gobject
from math import pi
class Canvas(gtk.DrawingArea):
def __init__(self):
super(Canvas, self).__init__()
self.connect("expose_event", self.expose)
self.set_size_request(400,400)
self.x = 20
self.y = 20
self.counter = 0
def movealittle(self):
self.x += 1
self.counter += 1
self.queue_draw()
if self.counter <= 20:
return True
elif self.counter > 20:
self.counter = 0
return False
def expose(self, widget, event):
cr = widget.window.cairo_create()
rect = self.get_allocation()
w = rect.width
h = rect.height
cr.arc(self.x, self.y, 10, 0, 2*pi)
cr.fill()
def runanimation(widget):
gobject.timeout_add(5, canvas.movealittle)
print "runanimation call"
button = gtk.Button("Move")
button.connect("clicked", runanimation)
window = gtk.Window()
canvas = Canvas()
panel = gtk.VBox()
window.add(panel)
panel.pack_start(canvas)
panel.pack_start(button)
window.set_position(gtk.WIN_POS_CENTER)
window.show_all()
gtk.main()
gobject.timeout_add() can be used for finite animations. The callback you set up will keep being called until it returns False, at which point your method won't be called again.
For example, if you want a ball to be animated for 5 seconds, you would be responsible for determining how long the animation has been going, and then once it has passed 5 seconds, your method would return False to end the animation. When you want the animation to start again, simply re-register the callback with timeout_add and reset your time counter.
See: http://www.pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--timeout-add for more information.

Pygame: Sprite changing due to direction of movement

I've just started learning how to use pygame yesterday. I was read this one book that was super helpful and followed all its tutorials and examples and stuff. I wanted to try making a really simple side scroller/platforming game but the book sorta jumped pretty fast into 3D modeling with out instructing how to make changing sprites for movement of up down left and right and how to cycle through animating images.
I've spent all today trying to get a sprite to display and be able to move around with up down left and right. But because of the simple script it uses a static image and refuses to change.
Can anyone give me some knowledge on how to change the sprites. Or send me to a tutorial that does?
Every reference and person experimenting with it ha always been using generated shapes so I'm never able to work with them.
Any help is very appreciated.
Added: before figuring out how to place complex animations in my scene I'd like to know how I can make my 'player' change to unmoving images in regards to my pressing up down left or right. maybe diagonal if people know its something really complicated.
Add: This is what I've put together so far. http://animania1.ca/ShowFriends/dev/dirmove.rar would there be a possibility of making the direction/action set the column of the action and have the little column setting code also make it cycle down in a loop to do the animation? (or would that be a gross miss use of efficiency?)
Here is a dumb example which alernates between two first images of the spritesheet when you press left/right:
import pygame
quit = False
pygame.init()
display = pygame.display.set_mode((640,480))
sprite_sheet = pygame.image.load('sprite.bmp').convert()
# by default, display the first sprite
image_number = 0
while quit == False:
event = pygame.event.poll()
no_more_events = True if event == pygame.NOEVENT else False
# handle events (update game state)
while no_more_events == False:
if event.type == pygame.QUIT:
quit = True
break
elif event.type == pygame.NOEVENT:
no_more_events = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
image_number = 0
elif event.key == pygame.K_RIGHT:
image_number = 1
event = pygame.event.poll()
if quit == False:
# redraw the screen
display.fill(pygame.Color('white'))
area = pygame.Rect(image_number * 100, 0, 100, 150)
display.blit(sprite_sheet, (0,0), area)
pygame.display.flip()
I've never really used Pygame before so maybe this code shoudln't really be taken as an example. I hope it shows the basics though.
To be more complete I should wait some time before updating, e.g. control that I update only 60 times per second.
It would also be handy to write a sprite class which would simplify your work. You would pass the size of a sprite frame in the constructor, and you'd have methodes like update() and draw() which would automatically do the work of selecting the next frame, blitting the sprite and so on.
Pygame seems to provide a base class for that purpose: link text.
dude the only thing you have to do is offcourse
import pygame and all the other stuff needed
type code and stuff..........then
when it comes to you making a spri
class .your class nam here. (pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.init(self)
self.image=pygame.image.load(your image and path)
self.rect=self.image.get_rect()
x=0
y=0
# any thing else is what you want like posistion and other variables
def update(self):
self.rect.move_ip((x,y))
and thats it!!!! but thats not the end. if you do this you will ony have made the sprite
to move it you need
I don't know much about Pygame, but I've used SDL (on which Pygame is based).
If you use Surface.blit(): link text
You can use the optional area argument to select which part of the surface to draw.
So if you put all the images that are part of the animation inside a single file, you can select which image will be drawn.
It's called "clipping".
I guess you will have a game loop that will update the game state (changing the current image of the sprite if necessary), then draw the sprites using their state.

Categories