Playing Sound Effects
In this article, we will play sound effects (SE) in a game.
Instead of using external audio files, we will introduce how to create simple sound effects directly in code by writing musical notes.
The complete source code is provided at the end.
1. Registering a Sound
First, register a sound inside the constructor of the Game class.
The argument of pyxel.sound() specifies the sound ID.
- Sound ID: This number is used later when playing the sound.
Next, pass the following data to the set() method:
- Notes (score): Specifies the pitch
-
tones: Type of waveform (e.g.p= pulse wave) -
volumes: Volume -
effects: Sound effect (e.g.f= fade out) -
speed: Playback speed (lower values play faster)
# main.py
pyxel.sound(0).set(
"c4g3",
tones="p",
volumes="76",
effects="f",
speed=20
)
2. Playing a Sound
With pyxel.play(), up to four sounds can be played simultaneously.
- The first argument specifies the channel number (0–3).
- If the same channel is used, the new sound overwrites the previous one.
- The second argument specifies the sound ID.
# main.py
pyxel.play(0, 0)
Complete Code
Below is the complete code implementing the features introduced in this article.
(The sprite.py file is the same as in the previous chapter.)
# main.py
import pyxel
import math
import random
import sprite
W, H = 160, 120
SHIP_SPD = 1.4
ASTEROID_INTERVAL = 20
ASTEROID_LIMIT = 30
ASTEROID_SPD_MIN = 1.0
ASTEROID_SPD_MAX = 2.0
ASTEROID_DEG_MIN = 30
ASTEROID_DEG_MAX = 150
BULLET_SPD = 3
# Game
class Game:
def __init__(self):
""" Constructor """
# Game over flag
self.game_over_flg = False
# Initialize score
self.score = 0
# Initialize player
self.ship = sprite.ShipSprite(W / 2, H - 40)
deg = 0 if random.random() < 0.5 else 180
self.ship.move(SHIP_SPD, deg)
# Asteroids
self.asteroid_time = 0
self.asteroids = []
# Bullets
self.bullets = []
# Initialize Pyxel
pyxel.init(W, H, title="Hello, Pyxel!!")
pyxel.load("shooter.pyxres")
# Sound (shot)
pyxel.sound(0).set(
"c4g3",
tones="p",
volumes="76",
effects="f",
speed=20
)
# Sound (hit)
pyxel.sound(1).set(
"e4d4c4",
tones="p",
volumes="76",
effects="n",
speed=20
)
pyxel.run(self.update, self.draw)
def update(self):
""" Update process """
# Game over
if self.game_over_flg:
return
# Update player
self.ship.update()
self.control_ship()
self.overlap_spr(self.ship)
self.check_interval() # Add asteroids
# Update asteroids
for asteroid in self.asteroids:
asteroid.update()
self.overlap_spr(asteroid)
# Collision check (asteroid x player)
if asteroid.intersects(self.ship):
self.game_over_flg = True
# Update bullets (reverse order)
for bullet in self.bullets[::-1]:
bullet.update()
# Remove if outside screen
if bullet.y < 0:
self.bullets.remove(bullet)
continue
# Collision check (bullet x asteroid)
for asteroid in self.asteroids[::-1]:
if asteroid.intersects(bullet):
self.score += 1
self.bullets.remove(bullet)
self.asteroids.remove(asteroid)
# Sound (hit)
pyxel.play(1, 1)
return
def draw(self):
""" Draw process """
pyxel.cls(0)
# Game over
if self.game_over_flg:
msg = "GAME OVER"
pyxel.text(W / 2 - len(msg) * 2, H / 2, msg, 13)
# Draw score
pyxel.text(10, 10, f"SCORE:{self.score:04}", 12)
# Draw player
self.ship.draw()
# Draw asteroids
for asteroid in self.asteroids:
asteroid.draw()
# Draw bullets
for bullet in self.bullets:
bullet.draw()
def control_ship(self):
""" Player action """
if pyxel.btnp(pyxel.KEY_SPACE):
self.ship.flip_x()
# Fire bullet
bullet = sprite.BulletSprite(self.ship.x, self.ship.y)
bullet.move(BULLET_SPD, 270)
self.bullets.append(bullet)
# Sound (shot)
pyxel.play(0, 0)
def overlap_spr(self, spr):
""" Wrap sprite around the screen """
if spr.x < -spr.w:
spr.x = W
return
if W < spr.x:
spr.x = -spr.w
return
if spr.y < -spr.h:
spr.y = H
return
if H < spr.y:
spr.y = -spr.h
return
def check_interval(self):
# Asteroid spawn interval
self.asteroid_time += 1
if self.asteroid_time < ASTEROID_INTERVAL:
return
self.asteroid_time = 0
# Limit number of asteroids
if ASTEROID_LIMIT < len(self.asteroids):
return
# Add asteroid
x = random.random() * W
y = 0
spd = random.uniform(ASTEROID_SPD_MIN, ASTEROID_SPD_MAX)
deg = random.uniform(ASTEROID_DEG_MIN, ASTEROID_DEG_MAX)
asteroid = sprite.AsteroidSprite(x, y)
asteroid.move(spd, deg)
self.asteroids.append(asteroid)
def main():
""" Main process """
Game()
if __name__ == "__main__":
main()
Final Words
Thank you for reading this far.
I hope this series becomes a starting point for your own game development journey.
If you enjoyed it, a 👍 would mean a lot!
Top comments (0)