I'm trying to make a simple game but I'm having issues
this is my code:
from myvector import myVector
from car import Car
import pyglet
width = 1000
height = 600
agent = None
agent = Car(int(width/2), int(height/2))
window = pyglet.window.Window()
window.set_size(width,height)
#window.event
def on_key_press(symbol, modifiers):
if symbol == 119: # w
agent.applyForce(myVector(-1, 0))
if symbol == 115: # s
agent.applyForce(myVector(1, 0))
if symbol == 97: # a
agent.applyForce(myVector(0, -1))
if symbol == 100: # d
agent.applyForce(myVector(0, 1))
#window.event
def on_draw():
window.clear()
agent.update()
agent.sprite.draw()
print(1)
if __name__ == "__main__":
pyglet.app.run()
problem is on_draw event is only called when I input something on keyboard
I'm using python 3.6 and latest pyglet package
I found nothing on internet
why is this happening?
Pyglet invokes on_draw only if an event occurs. Use pyglet.clock.schedule_interval to continuously invoke a function by a timer invent. That causes that on_draw is triggered, too:
#window.event
def on_draw():
window.clear()
agent.update()
agent.sprite.draw()
print(1)
def update(dt):
# update objects
# [...]
pass
if __name__ == "__main__":
pyglet.clock.schedule_interval(update, 1/60) # schedule 60 times per second
pyglet.app.run()
It could be an issue with the decorator function.
Instead of decorating the on_draw, replace the window object's on_draw function with your own declaration of that function:
See this example on on_mouse_press, which is replced with its own declaration.
#window.event
def on_mouse_press(x, y, button, modifiers):
global state, image
if button == pyglet.window.mouse.LEFT:
print('mouse press')
if state:
state = False
else:
state = True
Replaced to
import pyglet
image = pyglet.resource.image('test.png')
image.anchor_x = image.width // 2
image.anchor_y = image.height // 2
state = True
def on_draw():
print('on_draw() called')
window.clear()
if state:
image.blit(window.width // 2, window.height // 2)
def on_mouse_press(x, y, button, modifiers):
global state
print('mouse pressed')
if state:
state = False
else:
state = True
window = pyglet.window.Window()
window.on_draw = on_draw
window.on_mouse_press = on_mouse_press
pyglet.app.run()
Related
A few days ago I started making my first professional pygame (didn t do any pygame ever before), so for the first time I made a main menu, for the actual game, after that the game, so I have 2 files in that project(main menu and the game).
But after some seconds I realised i don t know how to start the game from the main menu by clicking the START button. SO I NEED SOME HELP......
I will let you down my main menu code.
import pygame
import pygame.freetype
from pygame.sprite import Sprite
from pygame.rect import Rect
from enum import Enum
from pygame.sprite import RenderUpdates
BLUE = (106, 159, 181)
WHITE = (255, 255, 255)
def create_surface_with_text(text, font_size, text_rgb, bg_rgb):
""" Returns surface with text written on """
font = pygame.freetype.SysFont("Courier", font_size, bold=True)
surface, _ = font.render(text=text, fgcolor=text_rgb, bgcolor=bg_rgb)
return surface.convert_alpha()
class UIElement(Sprite):
""" An user interface element that can be added to a surface """
def __init__(self, center_position, text, font_size, bg_rgb, text_rgb, action=None):
"""
Args:
center_position - tuple (x, y)
text - string of text to write
font_size - int
bg_rgb (background colour) - tuple (r, g, b)
text_rgb (text colour) - tuple (r, g, b)
action - the gamestate change associated with this button
"""
self.mouse_over = False
default_image = create_surface_with_text(
text=text, font_size=font_size, text_rgb=text_rgb, bg_rgb=bg_rgb
)
highlighted_image = create_surface_with_text(
text=text, font_size=font_size * 1.2, text_rgb=text_rgb, bg_rgb=bg_rgb
)
self.images = [default_image, highlighted_image]
self.rects = [
default_image.get_rect(center=center_position),
highlighted_image.get_rect(center=center_position),
]
self.action = action
super().__init__()
#property
def image(self):
return self.images[1] if self.mouse_over else self.images[0]
#property
def rect(self):
return self.rects[1] if self.mouse_over else self.rects[0]
def update(self, mouse_pos, mouse_up):
""" Updates the mouse_over variable and returns the button's
action value when clicked.
"""
if self.rect.collidepoint(mouse_pos):
self.mouse_over = True
if mouse_up:
return self.action
else:
self.mouse_over = False
def draw(self, surface):
""" Draws element onto a surface """
surface.blit(self.image, self.rect)
class Player:
""" Stores information about a player """
def __init__(self, score=0, lives=3, current_level=1):
self.score = score
self.lives = lives
self.current_level = current_level
def main():
pygame.init()
screen = pygame.display.set_mode((800, 600))
game_state = GameState.TITLE
while True:
if game_state == GameState.TITLE:
game_state = title_screen(screen)
if game_state == GameState.NEWGAME:
player = Player()
game_state = play_level(screen, player)
if game_state == GameState.NEXT_LEVEL:
player.current_level += 1
game_state = play_level(screen, player)
if game_state == GameState.QUIT:
pygame.quit()
return
def title_screen(screen):
start_btn = UIElement(
center_position=(400, 400),
font_size=30,
bg_rgb=BLUE,
text_rgb=WHITE,
text="Start",
action=GameState.NEWGAME,
)
quit_btn = UIElement(
center_position=(400, 500),
font_size=30,
bg_rgb=BLUE,
text_rgb=WHITE,
text="Quit",
action=GameState.QUIT,
)
buttons = RenderUpdates(start_btn, quit_btn)
return game_loop(screen, buttons)
def play_level(screen, player):
return_btn = UIElement(
center_position=(140, 570),
font_size=20,
bg_rgb=BLUE,
text_rgb=WHITE,
text="Return to main menu",
action=GameState.TITLE,
)
nextlevel_btn = UIElement(
center_position=(400, 400),
font_size=30,
bg_rgb=BLUE,
text_rgb=WHITE,
text=f"Next level ({player.current_level + 1})",
action=GameState.NEXT_LEVEL,
)
buttons = RenderUpdates(return_btn, nextlevel_btn)
return game_loop(screen, buttons)
def game_loop(screen, buttons):
""" Handles game loop until an action is return by a button in the
buttons sprite renderer.
"""
while True:
mouse_up = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
mouse_up = True
screen.fill(BLUE)
for button in buttons:
ui_action = button.update(pygame.mouse.get_pos(), mouse_up)
if ui_action is not None:
return ui_action
buttons.draw(screen)
pygame.display.flip()
class GameState(Enum):
QUIT = -1
TITLE = 0
NEWGAME = 1
NEXT_LEVEL = 2
if __name__ == "__main__":
main()
Thank you in advice!!!!
i have two ideas:
1st:
just import it. When you import it it will be executed.
import importlib
importlib.import("name of you file without extension") # i dont know the command
2nd:
use
exec()
exec(open("filename.py").read())
or
with open("file.py", "r") as f:
exec(f.read())
ywc
couple of days ago, I made a code that plays a video in pygame window.
Code works just fine, just as I originally intended. However, when I print debug statement to see its fps, it's somewhere around 30fps. If I were to increase fps, what should I do?
Here is the code I used.
import sys
from color import *
import pyglet
pygame.init()
running = True
gameDisplay= pygame.display.set_mode((800,600))
window = pyglet.window.Window(visible=False)
background_vid = pyglet.media.Player()
background_vid.queue(pyglet.media.load(".\\music_folder\\music_vid/servant_of_evil_converted.mp4"))
background_vid.play()
def hellow():
print "hellow bloody world"
def on_draw():
#We have to convert the Pyglet media player's image to a Pygame surface
rawimage = background_vid.get_texture().get_image_data()
print "rawimage "+str(rawimage)
pixels = rawimage.get_data('RGBA', rawimage.width *8)
video = pygame.image.frombuffer(pixels, (rawimage.width*2,rawimage.height), 'RGBA')
#Blit the image to the screen
gameDisplay.blit(video, (0, 0))
circle_x=300
while True:
pyglet.clock.tick()
on_draw()
print "fps: "+str(pyglet.clock.get_fps())
for event in pygame.event.get():
if(event.type == pygame.QUIT):
sys.exit()
pygame.quit()
pygame.draw.rect(gameDisplay, red, (circle_x, 300, 300, 300), 5)
circle_x+=1
pygame.display.update()
So what #pydude said is not completely wrong.
However, in order to actually messure FPS I'd put a custom counter in the on_draw function, that will give better accuracy.
Further more, the only real problem with your code is that you don't insert vsync=False into your Window() decorator.
I've reworked your code to make it a little bit more modular, I've also removed potential bottle-necks and added my own custom FPS counter (via GL and not console), here - have a go and see if it works better for you.
(Note: Pressing Escape will exit the application)
import sys
from color import *
import pyglet
from pyglet.gl import *
from time import time # Used for FPS calc
key = pyglet.window.key
class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(800, 800, fullscreen = False, vsync = True)
self.running = True
self.background_vid = pyglet.media.Player()
self.background_vid.queue(pyglet.media.load(".\\music_folder\\music_vid/servant_of_evil_converted.mp4"))
self.background_vid.play()
self.fps_counter = 0
self.last_fps = time()
self.fps_text = pyglet.text.Label(str(self.fps_counter), font_size=12, x=10, y=10)
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE: # [ESC]
self.running = False
def on_draw(self):
self.render()
#We have to convert the Pyglet media player's image to a Pygame surface
def render(self):
self.clear()
rawimage = background_vid.get_texture().get_image_data()
pixels = rawimage.get_data('RGBA', rawimage.width *8)
video = pygame.image.frombuffer(pixels, (rawimage.width*2,rawimage.height), 'RGBA')
#Blit the image to the screen
self.blit(video, (0, 0))
# And flip the GL buffer
self.fps_counter += 1
if time() - self.last_fps > 1:
self.fps_text.text = str(self.fps_counter)
self.fps_counter = 0
self.last_fps = time()
self.fps_text.draw()
self.flip()
def run(self):
while self.running is True:
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()
if event and event.type == pygame.QUIT:
self.running = False
x = main()
x.run()
Try toggling vsync = True to vsync = False and watch the difference in the FPS counter.
With python, printing is very slow. Try just printing every once and a while.
Example:(requires import random):
if random.random()>0.09:print "fps: "+str(pyglet.clock.get_fps())
I am new to pyglet and I have a question about the image on the screen update. Necessary each time the mouse pressed to change the count, but I have all the time is zero, where did I go wrong and how can I fix it?
from pyglet.window import mouse
from pyglet import *
import pyglet
window = pyglet.window.Window(800, 600)
n = 0
label = pyglet.text.Label(str(n), x = window.width/2, y = window.width/2 )
#window.event
def on_mouse_press(x, y, button, modifiers):
if button == mouse.LEFT:
global n
n += 1
#window.event
def on_draw():
window.clear()
label.draw()
def update():
pass
pyglet.app.run()
pyglet.clock.schedule_interval(update, 1/30.0)
Thank you!
You need to create again the label in order to change its value (or better modify the label.text attribute)! Actually you didn't pass n to pyglet.text.Label but a string created "on the fly" containing that value.
#window.event
def on_mouse_press(x, y, button, modifiers):
if button == mouse.LEFT:
global n
n += 1
label.text = str(n)
Hope it helps.
I'm trying to write my first pyglet animation and I ran into a problem.
I have an update function called from the on_draw function. It does what it should do, but it stops at random places down the loop.
If I start moving the mouse it continues going down the loop.
I saw there is a question made here in 2011 about the same problem but with no relevant answer: (pyglet on_draw event occurs only when mouse moves)
To work I need to keep calling the update function inside the on_draw.
This is the code for both functions:
def update(zd):
stripe.y += zd[0]
stripe._set_rotation(zd[0])
#window.event
def on_draw():
window.clear()
window.clear()
batch.draw()
try:
update(next(calc))
except:
pass
I get the zd to the update from a big loop with a lot of calculations in the calc function.
Here, try this code instead:
import pyglet
from pyglet.gl import *
from math import radians, cos, sin, degrees, atan2
from time import time
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_LINE_SMOOTH)
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE)
pyglet.options['audio'] = ('alsa', 'openal', 'silent')
key = pyglet.window.key
class GUI(pyglet.window.Window):
def __init__(self):
super(GUI, self).__init__(640,340, caption='My app')
self.alive = True
self.keys_down = {}
imgTexture = pyglet.image.load('/path/to/image.png')
self.myImage = pyglet.sprite.Sprite(imgTexture)
self.myImage.x, self.myImage.y = 10, 50 # x,y from bottom left corner
def render(self, *args):
pyglet.gl.glClearColor(1, 1, 1, 1)
self.clear()
# .. This is where you draw your objects, for instance
self.myImage.draw()
self.flip()
def on_draw(self):
self.render()
def on_close(self):
self.alive = False
def on_key_press(self, symbol, modkey):
self.keys_down[symbol] = time()
def on_key_release(self, symbol, modkey):
if symbol in self.keys_down:
del(self.keys_down[symbol])
def on_mouse_release(self, x, y, button, modifiers):
pass
def on_mouse_press(self, x, y, button, modifiers):
print(button,'pressed',(x,y))
def on_mouse_motion(self, x, y, dx, dy):
pass
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
pass
def run(self):
while self.alive:
event = self.dispatch_events()
for symbol in self.keys_down:
if symbol == key.ESCAPE:
self.alive = None
break
elif symbol == key.LEFT:
pass #Arrowkey Left
elif symbol == key.RIGHT:
pass #Arrowkey Right
elif symbol == key.UP:
pass #Arrowkey Up
elif symbol == key.DOWN:
pass #Arrowkey Down
elif symbol == 65515:
pass # Win key
else:
print(symbol)
self.render()
if __name__ == '__main__':
x = GUI()
pyglet.clock.set_fps_limit(120)
x.run()
Note that on_draw() is not really called ever in this code.
In the traditional pyglet code on_draw() is only called whenever a event exists, normally you trigger these with a timer or otherwise scheduled event.. Moving the mouse is one such event.
This is a manual override of the traditional app.run() that you're used to.
So the two main functions here are:
event = self.dispatch_events()
self.render()
The first fetches any events from pyglet effectively releasing any locks because even empty events must be fetched.
The second is the rendering functions which is what on_draw() normally does, except we can now call it all the time (or whenever we want).
I'm no expert but this works for 99% of any GUI making you'll ever encounter, as long as you're not going to do massive 3D games, this will do the job for you.
I'm new to working with Pyglet and I've written a small program which moves a ball around the screen. Right now I'm having difficulty establishing a steady frame rate of 60 fps. While Pyglet is supposed to sync with my monitor's refresh rate of 60Hz, Pyglet is setting my fps to half of my refresh rate (ex. when 60Hz, 30 fps). Is there something wrong in my code that is causing this?
import pyglet
import physicalobject
import random
from pyglet.window import mouse
pyglet.resource.path = ['./resources']
pyglet.resource.reindex()
ball_image = pyglet.resource.image("ball2.png")
#sets clock format
fps_display = pyglet.clock.ClockDisplay(format='%(fps).2f fps')
def center_image(image):
image.anchor_x = image.width/2
image.anchor_y = image.height/2
center_image(ball_image)
ball = physicalobject.PhysicalObject(img=ball_image, x = 400, y = 300)
ball.scale = .2
ball.velocity_x = random.randint(-4,4)*150
ball.velocity_y = random.randint(-4,4)*150
#Calls update function to set new ball position based on velocity
def update(dt):
ball.update(dt)
#window.event
def on_mouse_drag(x, y, dx, dy, button, modifiers):
ball.x = x
ball.y = y
ball.velocity_x = dx * 20
ball.velocity_y = dy * 20
#window.event
def on_draw():
window.clear()
ball.draw()
fps_display.draw()
def main():
pyglet.clock.schedule_interval(update, 1/120.0)
pyglet.app.run()
if __name__ == '__main__':
main()
Pyglet simply doesn't handle it correctly on some systems, you have to disable your application window's vsync in order to get it to work. Here's an example script you can run to get a feel for how it works:
import pyglet
# Show FPS
fps = pyglet.clock.ClockDisplay()
# The game window
class Window(pyglet.window.Window):
def __init__(self):
super(Window, self).__init__(vsync = False)
# Run "self.update" 128 frames a second and set FPS limit to 128.
pyglet.clock.schedule_interval(self.update, 1.0/128.0)
pyglet.clock.set_fps_limit(128)
# You need the dt argument there to prevent errors,
# it does nothing as far as I know.
def update(self, dt):
pass
def on_draw(self):
pyglet.clock.tick() # Make sure you tick the clock!
self.clear()
fps.draw()
# Create a window and run
win = Window()
pyglet.app.run()
import pyglet
from time import time, sleep
class Window(pyglet.window.Window):
def __init__(self, refreshrate):
super(Window, self).__init__(vsync = False)
self.frames = 0
self.framerate = pyglet.text.Label(text='Unknown', font_name='Verdana', font_size=8, x=10, y=10, color=(255,255,255,255))
self.last = time()
self.alive = 1
self.refreshrate = refreshrate
def on_draw(self):
self.render()
def render(self):
self.clear()
if time() - self.last >= 1:
self.framerate.text = str(self.frames)
self.frames = 0
self.last = time()
else:
self.frames += 1
self.framerate.draw()
self.flip()
def on_close(self):
self.alive = 0
def run(self):
while self.alive:
self.render()
event = self.dispatch_events()
sleep(1.0/self.refreshrate)
win = Window(23) # set the fps
win.run()
Note the lack of the clock feature.
Also, try setting vsync = True and removing the sleep(1.0/self.refreshrate), this will lock the refresh rate to your monitor.
Also, note that i don't use pyglet.app.run() to lock the rendering process, i call self.dispatch_events() instead.. it doesn't really do anything except let the graphic "poll" and move on, without it.. pyglet waits for a poll to occur, which pyglet.app.run() normally does.