DEV Community

Palak Hirave
Palak Hirave

Posted on

Day 23 of 100

Today I made the capstone project for the beginners section of my 100 days of python challenge. It is similar to the Crossy Roads game. There is a turtle which has to make it to the end of the screen before any of the colourful blocks(which move from the right to left) hit it. Each time it crosses the northern boundary(the turtle starts in the south and heads upwards) it returns to its original position for the next level, except this time the blocks are moving faster.

Overall I had a great time building this project. After a quick overview into how the game was supposed to work I found that it was quite straightforward and didn't need much problem solving. I flew though creating the turtle, scoreboard and game over screen but got a little stuck on how to make so many blocks and how to detect if a block has collided with the turtle. In the end, it worked out quite nicely.

When it comes to the actual program, I should have cleaned up the code a bit but was not quite sure how to. Mostly on the car_manager part(The cars are the blocks). I could have turned all of the workings for the blocks/cars I did in the while loop into separate functions in the CarManager class and then simply called them but I wasn't quite sure how to. That is definitely something to improve/look into next time. I am quite happy to finally be in the intermediate territory of python programming.

Here's the code -

main.py

import time
from turtle import Screen
from player import Player
from car_manager import CarManager
from scoreboard import Scoreboard

screen = Screen()
screen.setup(width=600, height=600)
screen.tracer(0)
screen.title("Turtle Crossing Game")

player = Player()
scoreboard = Scoreboard()
cars = []
car = CarManager()

cars.append(car)

loop_count = 0
MOVE_SEGMENT = 5

game_is_on = True
while game_is_on:
    time.sleep(0.1)
    screen.update()
    for c in cars:
        c.backward(MOVE_SEGMENT)

    screen.onkey(player.move_up, "Up")
    screen.listen()

    if player.ycor() >= 280:
        scoreboard.update_score()
        player.reset_pos()
        MOVE_SEGMENT += 7

    loop_count += 1
    if loop_count == 6:
        car = CarManager()
        cars.append(car)
        loop_count = 0

    for cr in cars:
        if player.distance(cr) < 20:
            game_is_on = False

screen.tracer(1)
scoreboard.game_over()

screen.exitonclick()

Enter fullscreen mode Exit fullscreen mode

player.py

from turtle import Turtle

STARTING_POSITION = (0, -280)
MOVE_DISTANCE = 10
FINISH_LINE_Y = 280

class Player(Turtle):
    def __init__(self):
        super().__init__()
        self.color("black")
        self.shape("turtle")
        self.setheading(90)
        self.penup()
        self.goto(STARTING_POSITION)


    def move_up(self):
        self.forward(MOVE_DISTANCE)

    def reset_pos(self):
        self.goto(STARTING_POSITION)

Enter fullscreen mode Exit fullscreen mode

scoreboard.py

from turtle import Turtle

FONT = ("Courier New", 22, "bold")

class Scoreboard(Turtle):
    def __init__(self):
        super().__init__()
        self.color("black")
        self.penup()
        self.hideturtle()
        self.goto(-280,260)
        self.write("Score:0", font = FONT)
        self.score = 0

    def update_score(self):
        self.score += 1
        self.clear()
        self.write("Score:" + str(self.score), font = FONT)

    def game_over(self):
        self.goto(-70,-10)
        self.write("Game Over.", font=FONT)
Enter fullscreen mode Exit fullscreen mode

car_manager.py

from turtle import Turtle
import random

COLORS = ["red", "orange", "yellow", "green", "blue", "purple"]
STARTING_MOVE_DISTANCE = 5
MOVE_INCREMENT = 10

class CarManager(Turtle):
    def __init__(self):
        super().__init__()
        self.color(random.choice(COLORS))
        self.shape("square")
        self.penup()
        self.shapesize(stretch_wid=1, stretch_len=2)
        self.random_y = random.randint(-250, 250)
        self.goto(300,self.random_y)

    def collision(self):
        pass


Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
algorhymer profile image
algorhymer

Here's the part of Crossy Roads which got me really thinking:

The game is a discrete grid. You move from one point/tile to the other, like chessboard.
Except for rivers... where you have to jump on logs.
Floating logs...
So you have to jump from a still grid to a moving grid and 100% align with the other grid on landing.
This cannot be done, so you - as a dev - must precompute the flight, add enough cheat into it, so the player feels like she/he pulled off the perfect jump.
In reality noone can get it right, so your code must babysit the entire flight path and act like the player did it.
Jeez even the flight path must look 'believable' so you have to do a U-shape which is turned upside down, to imply the quadratic arc, but you can't do actual quadratic etc. etc.

Another thing in real Crossy road is that there are no levels.
It is one continous procedurally generated long map with biomes.
Ofc you can't hold all of that in memory...
Aaand the biomes have to be a little bit ordered.
It cannot be truly random like river-river-river-river-river-river.
People's notion of random is not random at all.
People want an enjoyable game, rather than a random game.
So you cannot just randomly sew together strips of random biomes, but you need to have some 'business rule' deciding the minimal and maximal strip count for a single biome, and pseudo randomly generate these strip-collections.
Then you have to pseudo randomly pick the next strip-collection and sew it to the visible world...
And you must delete the part of the world which is now off-screen.
And all of this is bound to the chicken's camera.
But the chicken must start at the bottom, and proceed to the mid point, and only after that can you start deleting (once your strips start going out of camera view).
Aaaand the camera has to follow the chicken with a delay... kind of like being rubberbanded to the chicken.

Another thing is, or rather are, the cars.
In the real game the chicken should be somehow collision boxed, just like the cars...
I mean a car is definitely not a sphere, and it would look weird if the chicken was KO-ed by a car which did not even touch it.
But... collision boxing and making that many car entities would just make the CPU burn, so...
What if cars in a lane weren't separate cars, but one actual thing, which - instead of a real collision shape encompassing all the cars - is just a union of boxes.

Yeah Crossy Road looks simple, but it is actually not that simple if we think about it.

There's a really cool easy competitive programming puzzle.
It goes by the codename UVa 00478, Points in Figures: Rectangles, Circles, Triangles.
It is quite a nice little puzzle I think.

I have crazier puzzles too in case you are interested.
For example one puzzle is about beating Rust wall clock time from simple good ole' Python! ☺️
For more information, please check my bio and my latest article, Jon.