Coder the game Geometry Dash in Python
SolvedAnonymous user -
Hello hello !!
I'm making a geometry dash for school and I'm a complete beginner.
So far, I have my character moving and jumping. The next step is to create platforms in the air and obstacles; as well as to have the background scroll. I'm starting with the obstacles and platforms, but I'm having trouble connecting them to my code.
My question is the following: does anyone have a link to a tutorial on platforms and obstacles that I could easily adapt and understand for my code?
Thank you
6 answers
Hello,
Without seeing your code, it's hard to respond.
But by doing a quick Google search, I found this video that seems to answer your question exactly, and the description provides the link to the code.
The code is based on ursina.
Good luck
Hello,
If you don't want to use ursina and prefer to use pygame, you can take a look at this repository.
Good luck
Hello.
The thing is, to make even a simple game, you have to get really familiar with the library you want to use, which means doing lots of tests, and obviously, this takes time. Making a game with obstacles and platforms requires a lot of time, whether it’s about game mechanics or game strategy, map design, etc. Not to mention that obviously, you need to master the basic concepts of Python, including objects. Making a complex game without object-oriented programming is, for me, an impossible mission; well, it can be done but at the expense of code readability and organization, especially since everything is an object in Python.
Making a game with Pygame means using sprites. A Pygame sprite must have attributes like image and rect, so the player, obstacles, platforms, and all entities must be sprites.
I don’t know what you mean by "geometry dash". Making obstacles that the player has to avoid or collect is not difficult (provided you know a bit about Pygame).
.
Do it quickly according to your code.
import pygame import random SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 SCREEN_COLOR = 120, 170, 255 FLOOR_Y = 550 PLAYER_COLOR = 255, 255, 255 EVENT_OBSTACLE_SPAWN = pygame.USEREVENT + 1 FPS = 60 class Floor(pygame.sprite.Sprite): def __init__(self, y): super().__init__() self.image = pygame.Surface((SCREEN_RECT.w, 100)) self.image.fill((100, 200, 80)) self.rect = self.image.get_rect() self.rect.topleft = 0, y class Player(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.image = pygame.Surface((50, 50)) self.image.fill(PLAYER_COLOR) self.rect = self.image.get_rect() self.rect.bottomleft = x, y self.x = x self.y = y self.jumping = False self.jump_count = 20 def move(self, amount): self.rect.x += amount def jump(self): self.jumping = True def collide(self, sprites): # Returns the sprites colliding with the player return tuple(sprites[i] for i in self.rect.collidelistall(sprites)) def update(self): if self.jumping: # step = -(0.5 * self.jump_count ** 2) step = -(0.05 * self.jump_count ** 2) * (60 / FPS) if self.jump_count > 0: step *= -1 self.rect.y -= step self.jump_count -= 1 if self.rect.bottom >= self.y: self.rect.bottom = self.y self.jumping = False self.jump_count = 20 class Obstacle(pygame.sprite.Sprite): def __init__(self, x, y, width, height): super().__init__() self.image = pygame.Surface((width, height), pygame.SRCALPHA) self.rect = self.image.get_rect() self.rect.bottomleft = x, y def update(self): self.rect.x -= 5 class Friend(Obstacle): points = 10 def __init__(self, x, y): super().__init__(x, y, 60, 60) pygame.draw.circle(self.image, (0, 155, 155), (30, 30), 30) class Ennemy(Obstacle): points = -15 def __init__(self, x, y): super().__init__(x, y, 60, 60) pygame.draw.polygon(self.image, (0, 0, 0), ((30, 0), (0, 60), (60, 60))) def obstacle_spawn(): # Choosing an obstacle (30% friend, 70% enemy) obstacle_class = random.choices((Friend, Ennemy), (3, 7))[0] obstacle = obstacle_class(SCREEN_RECT.w, FLOOR_Y) draw_group.add(obstacle) obstacles_group.add(obstacle) def spawn_timer(): ms = random.randrange(500, 1100) pygame.time.set_timer(EVENT_OBSTACLE_SPAWN, ms) def sprites_clear(surface, rect): surface.fill(SCREEN_COLOR, rect) def pause(): clock = pygame.time.Clock() while True: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.KEYDOWN and event.key == pygame.K_p: return screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) SCREEN_RECT = screen.get_rect() pygame.mouse.set_visible(False) pygame.display.set_caption("game test") draw_group = pygame.sprite.RenderUpdates() obstacles_group = pygame.sprite.Group() player = Player(150, FLOOR_Y) draw_group.add(player) floor = Floor(FLOOR_Y) draw_group.add(floor) screen.fill(SCREEN_COLOR) pygame.display.update() clock = pygame.time.Clock() running = True points = 0 spawn_timer() game_paused = False while running: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP and not player.jumping: player.jump() elif event.key == pygame.K_p: game_paused = not game_paused if game_paused: pause() game_paused = False elif event.key == pygame.K_ESCAPE: running = False elif event.type == EVENT_OBSTACLE_SPAWN: obstacle_spawn() spawn_timer() draw_group.remove(player) draw_group.add(player) elif event.type == pygame.QUIT: running = False # Collision of obstacles with the player for sprite in player.collide(obstacles_group.sprites()): points += sprite.points obstacles_group.remove(sprite) draw_group.remove(sprite) print("points : ", points) # Removing sprites off-screen for sprite in obstacles_group.copy().sprites(): if sprite.rect.right < SCREEN_RECT.x: obstacles_group.remove(sprite) draw_group.remove(sprite) draw_group.clear(screen, sprites_clear) draw_group.update() rects = draw_group.draw(screen) pygame.display.update(rects) pygame.quit()
Now, if you want to also create platforms with enemies and collectible items, this won’t be able to be done on the fly; you will need to create a map (or several if there are levels), manage life, score, and everything necessary for the game to function properly.
.
So for a simple student project, maybe you should lower your expectations and conceptualize a simpler 2D game, not necessarily a Pong (which even for a novice is not that simple), but something with a similar level of complexity.
.
Good luck.
Good evening, it's me again (and I think this is the last time)
I have one last problem: I'm desperately trying to display the score at the top of the screen based on time, and there's an issue I don't understand on line 139
import pygame import random pygame.init() SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 SCREEN_COLOR = 120, 170, 255 SOL_Y = 550 PLAYER_COLOR = 255, 255, 255 PLAYER_HEIGHT = 30 PLAYER_WIDTH = 30 EVENT_OBSTACLE_SPAWN = pygame.USEREVENT + 1 FPS = 60 class Sol(pygame.sprite.Sprite): def __init__(self, y): super().__init__() self.image = pygame.Surface((SCREEN_RECT.w, 100)) self.image.fill((100, 200, 80)) self.rect = self.image.get_rect() self.rect.topleft = 0, y class Player(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.image = pygame.Surface((30, 30)) self.image.fill(PLAYER_COLOR) self.rect = self.image.get_rect() self.rect.bottomleft = x, y self.x = x self.y = y self.jumping = False self.jump_count = 20 def move(self, amount): self.rect.x += amount def jump(self): self.jumping = True def collision(self, sprites): for sprite in sprites: if isinstance(sprite, Cercle): if self.rect.colliderect(sprite.rect): if self.rect.bottom <= sprite.rect.centery: self.rect.bottom = sprite.rect.top elif self.rect.top >= sprite.rect.centery: pygame.time.wait(2000) quit() else: if self.rect.centerx < sprite.rect.centerx: self.rect.right = sprite.rect.left else: self.rect.left = sprite.rect.right elif isinstance(sprite, Triangle): if self.rect.colliderect(sprite.rect): if self.rect.bottom <= sprite.rect.centery: self.rect.bottom = sprite.rect.top elif self.rect.top >= sprite.rect.centery: pygame.time.wait(2000) quit() else: if self.rect.centerx < sprite.rect.centerx: self.rect.right = sprite.rect.left else: self.rect.left = sprite.rect.right elif isinstance(sprite, Rectangle): if self.rect.colliderect(sprite.rect): if self.rect.bottom <= sprite.rect.centery: self.rect.bottom = sprite.rect.top elif self.rect.top >= sprite.rect.centery: pygame.time.wait(2000) quit() else: if self.rect.centerx < sprite.rect.centerx: self.rect.right = sprite.rect.left else: self.rect.left = sprite.rect.right # Return the sprites that collide with the player return tuple(s for s in sprites if s.rect.colliderect(self.rect)) def update(self): if self.jumping: step = -(0.05 * self.jump_count ** 2) * (60 / FPS) if self.jump_count > 0: step *= -1 self.rect.y -= step self.jump_count -= 1 if self.rect.bottom >= self.y: self.rect.bottom = self.y self.jumping = False self.jump_count = 20 class ScoreBoard: def __init__(self, screen_rect): self.screen_rect = screen_rect self.score = 0 self.font = pygame.font.SysFont('Arial', 30) self.color = (255, 255, 255) def update1(self, time): self.score = int(time / 1000) def draw(self, screen): text_surface = self.font.render(f"Score: {self.score}", True, self.color) text_rect = text_surface.get_rect(topleft=(0, 0)) screen.blit(text_surface, text_rect) score_board = ScoreBoard(SCREEN_WIDTH, SCREEN_HEIGHT) SCREEN_HEIGHT = 600 class Obstacle(pygame.sprite.Sprite): def __init__(self, x, y, width, height): super().__init__() self.image = pygame.Surface((width, height), pygame.SRCALPHA) self.rect = self.image.get_rect() self.rect.bottomleft = x, y def update(self): self.rect.x -= 6 class Cercle(Obstacle): points = 10 def __init__(self, x, y): super().__init__(x, y, 60, 60) pygame.draw.circle(self.image, (0, 155, 155), (30, 30), 30) class Triangle(Obstacle): points = -15 def __init__(self, x, y): super().__init__(x, y, 60, 60) pygame.draw.polygon(self.image, (0, 255, 0), ((30, 0), (0, 60), (60, 60))) # forming the triangle class Rectangle(Obstacle): points = 10 def __init__(self, x, y): super().__init__(x, y, 70, 135) pygame.draw.rect(self.image, (12, 48, 255), (5, 5, 130, 130)) class LongRectangle(Obstacle): points = 10 def __init__(self, x, y): super().__init__(x, y, 620, 65) pygame.draw.rect(self.image, (255, 255, 0), (15, 15, 230, 230)) # spawning; it's a kind of real-time creation of objects or characters (here it's going to be obstacles) def obstacle_spawn(): # Choosing the obstacle (in a way you choose if you want more triangles or circles obstacle_class = random.choices((Cercle, Triangle, Rectangle, LongRectangle), (10, 14, 6, 3))[0] obstacle = obstacle_class(SCREEN_RECT.w, SOL_Y) draw_group.add(obstacle) obstacles_group.add(obstacle) def spawn_timer(): ms = random.randrange(500, 1100) pygame.time.set_timer(EVENT_OBSTACLE_SPAWN, ms) def sprites_clear(surface, rect): surface.fill(SCREEN_COLOR, rect) # application, screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) SCREEN_RECT = screen.get_rect() pygame.mouse.set_visible(False) pygame.display.set_caption("Geo update") draw_group = pygame.sprite.RenderUpdates() obstacles_group = pygame.sprite.Group() player = Player(100, SOL_Y) draw_group.add(player) sol = Sol(SOL_Y) draw_group.add(sol) screen.fill(SCREEN_COLOR) pygame.display.update() clock = pygame.time.Clock() running = True points = 0 spawn_timer() # main loop running = True while running: clock.tick(FPS) score_board.update1(pygame.time.get_ticks()) sprites_clear(screen, SCREEN_WIDTH, SCREEN_HEIGHT) score_board.draw(screen) draw_group.update() draw_group.draw(screen) obstacles_group.update() pygame.display.update(SCREEN_HEIGHT, SCREEN_WIDTH) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == EVENT_OBSTACLE_SPAWN: obstacle_spawn() spawn_timer() if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP or pygame.K_SPACE and not player.jumping: player.jump() elif event.type == EVENT_OBSTACLE_SPAWN: obstacle_spawn() spawn_timer() draw_group.remove(player) draw_group.add(player) if pygame.sprite.spritecollide(player, obstacles_group, False): running = False # Collision with obstacles and the player for sprite in player.collision(obstacles_group.sprites()): # point system to change points += sprite.points obstacles_group.remove(sprite) draw_group.remove(sprite) print("points : ", points) # Removing sprites off-screen for sprite in obstacles_group.copy().sprites(): if sprite.rect.right < SCREEN_RECT.x: obstacles_group.remove(sprite) draw_group.remove(sprite) draw_group.clear(screen, sprites_clear) pygame.display.update() pygame.quit() So I created a class for the score, and I also called it in the main loop but I don't understand the problem
Why??
Thanks :))
Hello,
Your ScoreBoard class takes a single argument screen_rect (why?), yet you are passing 2 parameters when you instantiate it, SCREEN_WIDTH and SCREEN_HEIGHT, so Python is complaining.
This class doesn't need that; it should only receive the x, y position where the score should be displayed, nothing more, and, in fact, we could even do without it and manage the position outside this class.
.
What is what you did in the player collision supposed to do? I don't understand why you are quitting the game, nor why you want to handle collisions differently based on the type of obstacle.
.
For any type of element to display, use a sprite.
.
class ScoreBoard(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.x = x self.y = y self.score = 0 self.font = pygame.font.SysFont('Arial', 30) self.color = (255, 255, 255) self.image = self.font.render('0', True, self.color) self.rect = self.image.get_rect() self.rect.topright = x, y def add(self, amount): self.score += amount self.image = self.font.render(str(self.score), True, self.color) self.rect = self.image.get_rect() self.rect.topright = self.x, self.y .
We then add it, just like the other objects, to the display group.
.
# .... sol = Sol(SOL_Y) draw_group.add(sol) score = ScoreBoard(SCREEN_RECT.right - 10, 10) draw_group.add(score) # ...
.
And update the score in the game loop when the player collides with the obstacles.
.
# Collision of obstacles with the player for sprite in player.collision(obstacles_group.sprites()): obstacles_group.remove(sprite) draw_group.remove(sprite) score.add(sprite.points)
.
This works while keeping the collision method code that I had shown you.
I'm going to try that later.
My goal with the collisions:
For the triangles and circles, as soon as it touches them, I've set a pause time to display a message, and I will remove the quit option later when I set it to press a key to go back to the homepage or to restart the game.
And for the vertical rectangles, it's so that it can pass over them (but I see that it's not the right way :(
Thanks :)
Good evening.
.
If you want the player to be able to walk on obstacles, then you will need to revise the way the player jumps, that is to say, manage it in 2 phases: one for ascent, which is simple, and thus a falling phase until the player touches a surface on which he can move.
.
So you will need to detect when the player is falling and collides with a solid element; collisions are one of the most difficult things to manage in a game, and it can quickly become complicated and turn into a nightmare ^^
.
You should simplify your code as much as possible to create your jumping system: a ground, a simple block (or several at different heights), and obviously the player. There are quite a few examples online regarding jump mechanics.
Hello, thank you for responding :)
Yeah, I saw that video
My code looks like this; but I don't know, I can't get it :(
import pygame #screen size and initialization SCREEN_WIDTH = 1600 SCREEN_HEIGHT = 850 pygame.display.set_caption("test game") screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT]) pygame.init() #jump x = 800 #initial position of the cube y = 600 #initial position of the cube width = 80 height = 80 vel = 15 isJump = False jumpCount = 10 #jump height """you can put classes between here and the continuous loop""" #loop run = True while run: pygame.time.delay(30) #clock for event in pygame.event.get(): if event.type == pygame.QUIT: run = False keys = pygame.key.get_pressed() #directions if keys[pygame.K_LEFT] and x > vel: x -= vel if keys[pygame.K_RIGHT] and x < 1600 - vel - width: x += vel #jump if not (isJump): if keys[pygame.K_SPACE]: isJump = True else: if jumpCount >= -10: y -= (jumpCount * abs(jumpCount)) * 0.5 jumpCount -= 1 else: jumpCount = 10 isJump = False #draw elements screen.fill((120, 170, 255)) pygame.draw.rect(screen, (100, 200, 80), (0, 680, 1600, 350)) pygame.draw.rect(screen, (255, 255, 255), (x, y, width, height)) pygame.display.update() pygame.quit()