ways of using midi events to make a player move in pygame - python

I have made some little games with the pygame module and it had been fun. However, right now i´m trying to move the character with a piano via midi using pygame.midi. there´s the problem. I did it but not in the way i wanted to because
the character moves sometimes and other it doesn´t. I think i know where is the problem: If i understand correctly, the pygame.event.get() function "catch" the events always, it does not matter when (inside the main loop of the game), so i think that with my code this is not happening, i mean, i believe that the player not always do what is supposed to do because the midi input has to be in a specific "time" not as pygame.event.get(). I looked into the pygame documentation and there seems to be a function that does the trick: pygame.midi.midis2events(), but i don´t know how to use it.The question is just:
How can i move the character through the piano via midi with pygame in order that the character moves everytime?
import pygame as pg, pygame.midi
WIDTH = 800
HEIGHT = 600
FPS = 60
BLACK = (0,0,0)
BLUE = (0,0,255)
pg.init()
pg.midi.init()
screen = pg.display.set_mode((WIDTH,HEIGHT))
pg.display.set_caption('STACKOVERFLOW_EXAMPLE_MIDI')
clock = pg.time.Clock()
running = True
inp = pg.midi.Input(1)
x = WIDTH//2
y = HEIGHT//2
speedx = 0
midi_list = []
while running:
clock.tick(FPS)
if inp.poll():
midi_value = inp.read(1000)[0][0][1]
if midi_value==57:
midi_list.append(midi_value)
if len(midi_list)==1:
speedx = -1
else:
speedx = 0
midi_list = []
if midi_value == 63:
running = False
x = x+speedx
screen.fill(BLUE)
pg.draw.rect(screen,BLACK,[x,y,50,60])
pg.display.update()
pg.display.flip()
pg.quit()
I need that the player moves to the left (or to the right) when the piano´s key A3 (a specific note) is being pressed and that the player stops moving when
the key has been released. In this particular fragment of the code, but also to do things like press a piano´s key an shoot one bullet regardless of whether is being pressed or not, in short, to do the same things i can do with the keyboard events.

ok! i found and answer that works well for the time being:
if inp.poll():
s(0.1)
midi_values = inp.read(1000)
for midi in midi_values:
midi_value = midi[0][1]
#Movement to the left
if midi_value==57:
midi_list.append(midi_value)
if len(midi_list)==1:
speedx = -50
Modifying the code in order to iterate the list midi_values gives me the correct input-output response without the inestability which i experienced. Also i did introduce a sleep(0.1) delay and works well without to much cpu use. I found the answer here:
https://www.reddit.com/r/learnpython/comments/36dxu9/python_whileloop_cpu_demanding/
The only problem which i find now is that the pygame window stops with the message no responde (doesn´t respond or something similar) and it stops working.
For example the cube which i´m moving with the keys of the piano doesn´t do anything but the key to close the program does work fine!!

Related

How to display text for only a certain amount of time?

I'm looking to display a message on the screen when a player wins, and get the text to display for 5 seconds, and then go back to the main menu start screen. Using the time.delay function however, my screen pauses and then displays the text in a flash, but then immediately goes to the startscreen. Is there a more efficient way of getting the text to be displayed for long enough to be read?
Below is the function I use to actually display the message:
def winnerPlayerOne():
screen.fill(PINK)
winnerP1Message = winnerFont.render("Congrats Player 1. You Win!", True, WHITE)
screen.blit(winnerP1Message, ((400 - (winnerP1Message.get_width()/2)),(300 - (winnerP1Message.get_height()/2))))
pygame.display.update()
pygame.time.delay(5000)
startscreen()
And below this is how I call this function, within the main loop:
if playeroneScore == 5:
winnerPlayerOne()
if playertwoScore == 5:
winnerPlayerTwo()
Any help would be greatly appreciated!
Benjamin's answer probably will work fine in your case. But if you want something that doesn't interfere with your game's visuals, I would consider setting a timer like so...
WITHIN GAME LOOP:
if gameWonScreen:
screen.fill(PINK)
winnerP1Message = winnerFont.render("Congrats Player 1. You Win!", True, WHITE)
screen.blit(winnerP1Message, ((400 - (winnerP1Message.get_width()/2)),(300 - (winnerP1Message.get_height()/2))))
timer = timer + elapsed/1000
elapsed = fpsClock.tick(FPS)
if timer > timeWinScreen:
gameWonScreen = false
Initialize 'timeWinScreen' to the desired message duration at the start of the application and set 'timer' to '0' and gameWonScreen to 'true' when the player wins. Using elapsed = fpsClock.tick(FPS) will hold the time value since the last tick. You don't need to use it for this process (you could just use a fraction of your FPS) but using 'elapsed' is good practice because it helps with smoothing animations of certain objects.
Try out pygame.time.wait(5000). It should behave more in the way you are expecting. It does prevent any code running in the background as well, but that didn't seem like it would be an issue for your use case.
Try this:
Remember that in the class below, time is not the way you measure time in pygame. It is the number of loop happened in the main loop.
class disp_txt:
def __init__(self,text,time,destination):
self.text = text
self.time = time
self.destination = destination
self.shfnt = pygame.font.SysFont("comicsens",30,False)
self.shtxt = self.shfnt.render(self.text,0,(255,0,0))
def show(self,surface):
if self.time>0:
surface.blit(self.shtxt,self.destination)
self.time -= 1
hint = disp_txt("text",100,(100,400)) #example
hint.show(screen) #in the main loop or where you are drawing

pygame simple game lagging

hi i am beginner in programming and pygame
and i was trying to make game like this
http://dan-ball.jp/en/javagame/dust/
and i started by making this simple code
import pygame
from pygame.locals import*
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0,25)
pygame.init()
screen=pygame.display.set_mode((1360,705))
clock = pygame.time.Clock()
boxs=[]
while True :
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type==QUIT :
pygame.quit()
quit()
if event.type== pygame.MOUSEBUTTONDOWN:
if event.button == 1:
mous=pygame.math.Vector2(event.pos[0]-4,event.pos[1]-4)
boxs.append(mous)
if event.type== pygame.MOUSEBUTTONDOWN:
if event.button == 3:
print (len(boxs))
for i in range(len(boxs)):
if ((boxs[i])[1])>=685:
pass
else:
(boxs[i])[1]=(boxs[i])[1]+2
for v in range (len(boxs)):
if v==i:
pass
else :
if (int((boxs[i])[1]))+4 >= (int((boxs[v])[1])) and (int((boxs[i])[1])) <= (int((boxs[v])[1]))+4 and (int((boxs[i])[0]))+4 >= (int((boxs[v])[0])) and (int((boxs[i])[0])) <= (int((boxs[v])[0]))+4:
(boxs[i])[1]=(boxs[i])[1]-2
break
pygame.draw.rect(screen,(250,250,250),((boxs[i])[0],(boxs[i])[1], 4, 4))
pygame.display.update()
clock.tick(60)
it works very good as start but my problem is that when the boxes became more the 350 or 400 the game will be lagging too much i dont know what iam doing wrong
and sorry if i was asking too much bad questions but thank you so much i have learned so much from you guys
I notice that you're doing this:
if ((boxs[i])[1])>=685:
pass
That means that you're never deleting boxes that go off the bottom of the screen, so as time goes by, your box list is getting larger and larger, which is going to eventually lead to lag.
You're also using Pygame vectors for your list, and then not taking advantage of them. For example, instead of:
(boxs[i])[1]=(boxs[i])[1]+2
you can say:
boxs[i].y += 2
Finally, you are not looping in a Pythonic way. In Python, you almost never need to loop with an index variable. Instead, you should be doing something like this:
for box in boxs:
if box.y >= 685:
pass
else:
box.y += 2
for other in boxs:
if other == box:
pass
and so on...
Finally, you should be using pygame Rect() objects, because then you can use the builtin pygame collision functions to easily handle your collisions.
http://www.pygame.org/docs/ref/rect.html

Change the character image for a while in Python Pygame

I am struggling with a problem I can't solve.
I want to change the image of my character when the enemy hurts it.
In pseudocode, it would be like this:
*If enemy collides -> player close eyes and get red;*
*After 0.50 seg -> player gets normal back again*
I tried to do it with Clock and Timers but it is very difficult. I only get changing the image, but not getting it back.
Any ideas?
Thank you!
I would assume it's as easy as this. pygame.time.set_timer(x, y) basically creates an x event on the event stack every y milliseconds.
# Main game loop
while True:
# display stuff and other parts of your game
# replace this with whatever detection you have for collision
if enemycollide:
player.setSprite(1)
pygame.time.set_timer(14, 500) # 500 milliseconds = .5 seconds
# event handling
for event in pygame.event.get():
if event.type == 14:
player.setSprite(0)
pygame.time.set_timer(14, 0) # Disable the timer

blit function to render a utf-8 string across the screen

I have written a pygame script that renders a horizontally moving text across the screen. It works, but when I change the string to a non-latin string (Persian), it does not work completely. I mean it does everything (animation, rendering ...) but the characters are depareted from each, though they are shown healthy, but are not in the expected order. I mean each letter is shown well, but a word is not rendered, a sequence of characters are rendered.
the string should beسلام
but it is rendered م ا ل س
Here is the full code:
import sys, pygame; #importing the required modules
#initialize the game module
pygame.init();
#setting the display properties and put in a variable
width = 800; #px
height = 600; #px
display_info = (width, height);
screen = pygame.display.set_mode(display_info);
# adding contents
arial = pygame.font.SysFont("Tahoma", 21);
text = arial.render("سلام", 1, (233,114,93), (255,255,255));
clock = pygame.time.Clock();
x = 0;
#starting the game loop
while True :
#it sets the timing of the loop-execution (40 fps)
clock.tick(40);
#getting the list of event on each game loop
for event in pygame.event.get() :
#if the event is QUIT (if the user has acted to close the application)
if event.type == pygame.QUIT :
pygame.quit(); #terminate python-side
sys.exit(); #exits system-side
#refreshing the screen with overall blackness
screen.fill((0,0,0));
#rendering the text. We do not move the text, we just increment the position on each loop
screen.blit(text, (x, height/3));
#incrementing the x-position
x += 1;
#updating the display to the latest changes
pygame.display.update();
#end of the while loop
This is a known bug in pygame and is currently classified as "won't fix", because:
To support all languages, we'd need to include a much larger font file, and changing files would break existing games.
One user in the thread suggests that python-fribidi can be used to get the correct behaviour.

Pygame Invalid Syntax I just can't figure out

I've been following a tutorial "McGugan - Beginning Game Development with Python and Pygame (Apress, 2007)" and in the code at around chapter five involving object movement I keep getting invalid syntax alerts on '-' being used in the code. It isn't up to date but I would've thought a subtract wouldn't be changed in any updates due to its simplicity and necessity.
This is the code I have:
background_image_filename = 'sushiplate.jpg'
sprite_image_filename = 'fugu.png'
import pygame
from pygame.locals import *
from sys import exit
from gameobjects.vector2 import Vector2
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
background = pygame.image.load(background_image_filename).convert()
sprite = pygame.image.load(sprite_image_filename).convert_alpha()
clock = pygame.time.Clock()
position = Vector2(100.0, 100.0)
speed = 250.
heading = Vector2()
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == MOUSEBUTTONDOWN:
destination = Vector2(*event.pos) – Vector2(*sprite.get_size())/2.
heading = Vector2.from_points(position, destination)
heading.normalize()
screen.blit(background, (0,0))
screen.blit(sprite, position)
time_passed = clock.tick()
time_passed_seconds = time_passed / 1000.0
distance_moved = time_passed_seconds * speed
position += heading * distance_moved
pygame.display.update()
am I doing something wrong or is it just simply outdated?
Any help is much needed.
In this line:
destination = Vector2(*event.pos) – Vector2(*sprite.get_size())/2.
You somehow typed the character "–" (EN DASH) instead of "-" (HYPHEN-MINUS).
Use "-" (HYPHEN-MINUS) instead, like this:
destination = Vector2(*event.pos) - Vector2(*sprite.get_size())/2.
I can't be sure without a stack trace, but I have a hunch that it's the wrong - symbol. What editor are you using? Is it possible that your editor is taking the - symbol and turning it into a fancier dash, like an ndash or an mdash?
Maybe try changing speed to "speed = 250.0". I don't know if that dangling dot would throw python off.
What is going on here, with your error message at least, is the Python parser is stumbling over something before your '-', which screws up its interpretation of '-'. So I recommend looking before the '-' for typos.
Also, make sure you turn on visible white space in your editor when debugging Python code. This could be a white space error, which would be invisible to us at Stack Overflow.
EDIT:
So I was completely wrong about that '-' error being a red herring. But keep that parser behavior in mind/white space thing in mind, could help in the future.
Apologies if this is obvious to you, I don't know what level you are at with Python.

Categories

Resources