Code Appendix

Our Code


import os
import pygame
from pygame.locals import *
import pygame.mixer
import RPi.GPIO as GPIO

import sys
import random

# copy from test.py
import time
import board
import busio
import adafruit_lis3dh
# Hardware I2C setup. Use the CircuitPlayground built-in accelerometer if available;
# otherwise check I2C pins.
if hasattr(board, "ACCELEROMETER_SCL"):
    i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
    lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, address=0x19)
else:
    i2c = board.I2C()  # uses board.SCL and board.SDA
    lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c)

lis3dh.range = adafruit_lis3dh.RANGE_2_G

os.putenv('SDL_VIDEODRIVER', 'fbcon')   # Display on piTFT
os.putenv('SDL_FBDEV', '/dev/fb0')
os.putenv('SDL_MOUSEDRV', 'TSLIB')     # Track mouse clicks on piTFT 
os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')

# physical quit button
code_run = True
GPIO.setmode(GPIO.BCM)
GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def GPIO27_callback(channel):
  global code_run
  code_run = False
GPIO.add_event_detect(27,GPIO.FALLING,callback=GPIO27_callback,bouncetime=300)

FPS = 40
clock=pygame.time.Clock()

pygame.init()
pygame.display.init()
pygame.mouse.set_visible(False)
size = width, height = 320, 240 

BACK = 238, 217, 145, 0.3
WHITE = 255, 255, 255
BLACK = 0,0,0

# Menu button
my_font = pygame.font.Font(None, 25)
menu_button = { 'Play':(80,200), 'Score':(230,200)}
v0y = -13
# screen.fill(BACK)  


class DoodleJump:
    def __init__(self):
        self.screen = pygame.display.set_mode((width, height))
        self.green = pygame.image.load("assets/green.png")
        self.platform_width = self.green.get_width()
        self.platform_height = self.green.get_height()
        pygame.font.init()
        
        self.font = pygame.font.SysFont("Arial", 15)
        self.blue = pygame.image.load("assets/blue.png")
        self.red = pygame.image.load("assets/red.png")
        self.red_1 = pygame.image.load("assets/red_1.png")
        self.playerRight = pygame.image.load("assets/right.png")
        self.playerRight_1 = pygame.image.load("assets/right_1.png") # use this to get width and height
        self.player_width = self.playerRight_1.get_width()
        self.player_height = self.playerRight_1.get_height()
        self.spring = pygame.image.load("assets/spring.png")
        self.spring_1 = pygame.image.load("assets/spring_1.png")

        self.direction = 0
        self.score = 0
        self.scorelist = [0,0,0]
        self.playerx = 160 - (self.platform_width)/2 # 160
        self.playery = 200 - self.player_height + 5 # height - self.player_height
        self.platforms = []
        self.springs = []
        self.relative_y = 0
        self.gravity = 0.8 
        self.vx = 0
        self.vy = v0y
        self.accx = 0
        self.first_flag = 1
        # state == 0: menu; 1: new game. 2: score board
        self.state = 0
        # platform verticle distance max:35
        self.hard = 20
    
    def updatePlayer(self):
        self.vy += self.gravity
        self.playery += self.vy
        # get x value from accelerometer
        x, y, z = [
            value / adafruit_lis3dh.STANDARD_GRAVITY for value in lis3dh.acceleration
        ]
        if(abs(x-0) < 0.05):
            self.vx = 0  # if the user change the direction, immediately start to go to that direction
        if(x < 0):
            self.direction = 0 # right
        elif(x > 0):
            self.direction = 1 # left
        self.accx = - x
        self.vx += 2 * self.accx
        # check if touch the edge
        if self.playerx > width:
            self.playerx = -self.player_width
        elif self.playerx < -self.player_width:
            self.playerx = width
        # update x position
        self.playerx += self.vx

        if self.playery - self.relative_y <= 80:
            self.relative_y -= 10
            if (self.hard <= 35):
                self.hard += 1
            else:
                self.hard = 20
        
        if self.vy > 0:
            self.screen.blit(self.playerRight_1, (self.playerx, self.playery - self.relative_y))
        else:
            self.screen.blit(self.playerRight, (self.playerx, self.playery - self.relative_y))

    def updatePlatforms(self):
        for p in self.platforms:
            rect = pygame.Rect(p[0], p[1], self.green.get_width() , self.green.get_height()) 
            player = pygame.Rect(self.playerx, self.playery, self.playerRight.get_width() - 10, self.playerRight.get_height())
            
            # when the alien is falling down and collide with platforms from top
            if rect.colliderect(player) and self.vy > 0 and self.playery < p[1]:#< (p[1] - self.relative_y):
                self.first_flag = 0
                # not on a red platform, jump
                if p[2] != 2:
                    self.vy = v0y
                # red platform
                else:
                    p[-1] = 1
            # blue platform
            if p[2] == 1:
                # p[-1] = 1: right; 0: left
                if p[-1] == 1:
                    p[0] += 2
                    if p[0] > width - self.platform_width:
                        p[-1] = 0
                else:
                    p[0] -= 2
                    if p[0] <= 0:
                        p[-1] = 1

    def drawPlatforms(self):
        for p in self.platforms:
            # lowest platform
            check = self.platforms[0][1] - self.relative_y
            # decide platform categories
            if check > height: # 600
                platform = random.randint(0, 1000)
                # green platform
                if platform < 800:
                    platform = 0
                # blue platform
                elif platform < 900:
                    platform = 1
                # red platform
                else:
                    platform = 2

                self.platforms.append([random.randint(0, width - self.platform_width), self.platforms[-1][1] - random.randint(self.hard-5, self.hard+5), platform, 0])
                coords = self.platforms[-1]
                check = random.randint(0, 1000)
                if check > 920 and platform == 0:
                    self.springs.append([coords[0], coords[1] - self.spring.get_height() + 3, 0])
                self.platforms.pop(0)
                # self.score += 100
            if p[2] == 0:
                self.screen.blit(self.green, (p[0], p[1] - self.relative_y))
            elif p[2] == 1:
                self.screen.blit(self.blue, (p[0], p[1] - self.relative_y))
            elif p[2] == 2:
                if not p[3]:
                    self.screen.blit(self.red, (p[0], p[1] - self.relative_y))
                else:
                    if (p[1] - self.relative_y < height):
                        p[1] += 1
                    self.screen.blit(self.red_1, (p[0], p[1] - self.relative_y))
    
        for spring in self.springs:
            if spring[-1]:
                self.screen.blit(self.spring_1, (spring[0], spring[1] - self.relative_y))
            else:
                self.screen.blit(self.spring, (spring[0], spring[1]  - self.relative_y))
            if pygame.Rect(spring[0], spring[1], self.spring.get_width(), self.spring.get_height()).colliderect(pygame.Rect(self.playerx, self.playery, self.playerRight.get_width(), self.playerRight.get_height())):
                self.vy = -26
                self.relative_y -= 70

    def generatePlatforms(self):
        py = height - self.platform_height
        while py >= self.platform_height:
            x = random.randint(0, width - self.platform_width)
            # platform category
            platform = random.randint(0, 1000)
            if platform < 800:
                platform = 0
            elif platform < 900:
                platform = 1
            else:
                platform = 2
            self.platforms.append([x, py, platform, 0])
            py -= random.randint(self.hard-5, self.hard+5)
        # print(self.platforms)


    def reset_state0(self):
        self.vy = v0y
        self.hard = 20
        self.first_flag = 1
        self.playerx = 141
        self.playery = 200 - self.player_height + 5 
        self.relative_y = 0
        self.springs = []
        self.platforms = []
        
        self.screen.fill(BACK)
        if (self.score > self.scorelist[0] or self.score > self.scorelist[1] or self.score > self.scorelist[2]):
            # pygame.mixer.music.load('assets/win.mp3')
            # pygame.mixer.music.play()
            text_surface = my_font.render("New High Score!", True, BLACK)
        else:
            text_surface = my_font.render("Game Over", True, BLACK)
        rect = text_surface.get_rect(center=(width/2, height/2))
        self.screen.blit(text_surface, rect)
        pygame.display.flip() 
        time.sleep(3)

        self.scorelist.append(self.score)
        self.scorelist.sort(reverse=True)
        self.score = 0
        self.generatePlatforms()
    
    def run(self):
        clock = pygame.time.Clock()
        self.generatePlatforms()

        while code_run:
            self.screen.fill(BACK)
            clock.tick(FPS)

            for event in pygame.event.get():
                if(event.type is MOUSEBUTTONDOWN):            
                    pos = pygame.mouse.get_pos()           
                elif(event.type is MOUSEBUTTONUP):            
                    pos = pygame.mouse.get_pos() 
                    x,y = pos
                    #print(x,y)
                    if(x > 65 and x < 95 and y > 190 and y < 210 and self.state == 0):
                        self.state = 1

                    elif(x > 215 and x < 245 and y < 210 and self.state == 0):
                        self.state = 2

                    elif(x > 0 and x < 40 and y > 0 and y < 40 and self.state == 2):
                        self.state = 0
            # menu
            if (self.state == 0):
                    # self.screen.fill(BACK) 
                    background = pygame.image.load("assets/background.png")
                    self.screen.blit(background, (0,0))
                    if (self.playerx != 141):
                        self.reset_state0() 
                    
                    self.vy += self.gravity
                    self.playery += self.vy
                    # self.generatePlatforms()

                    for my_text, text_pos in menu_button.items():
                        text_surface = my_font.render(my_text, True, BLACK)
                        rect = text_surface.get_rect(center=text_pos)
                        self.screen.blit(text_surface, rect)
                    self.screen.blit(self.green, (160 - (self.platform_width)/2,200))
      
                   
                    rect = pygame.Rect((160 - (self.platform_width)/2, 200, self.green.get_width() , self.green.get_height()))  # width - 10
                    player = pygame.Rect(self.playerx, self.playery, self.playerRight.get_width() - 10, self.playerRight.get_height())
                    # when the alien is falling down and collide with platforms from top
                    if rect.colliderect(player) and self.vy > 0 :#and self.playery <= 200:
                        self.vy = v0y
                    if self.vy > 0:
                        self.screen.blit(self.playerRight_1, (self.playerx, self.playery))
                    else:
                        self.screen.blit(self.playerRight, (self.playerx, self.playery))

            if (self.state == 2):
                # print(str(self.scorelist[1]) )
                background = pygame.image.load("assets/scoreback.png")
                self.screen.blit(background, (0,0))
                rank = {(70,80):"Gold", (70,120): "Silver", (70,160):"Bronze", (20,10):"BACK",
                        (160, 80):str(self.scorelist[0]), (160, 120):str(self.scorelist[1]),(160, 160): str(self.scorelist[2])}
                for text_pos, my_text in rank.items():
                    text_surface = my_font.render(my_text, True, BLACK)
                    rect = text_surface.get_rect(topleft=text_pos)
                    self.screen.blit(text_surface, rect)

                        
            if (self.state == 1):            
            # lose the game
                if (self.playery - self.relative_y >= height and self.first_flag == 0):
                    # print("lose")
                    # self.dieAnimation()
                    self.state = 0
                elif (self.playery - self.relative_y + self.player_height >= height and self.first_flag == 1):
                    self.vy = v0y
                # self.generatePlatforms()
                self.drawPlatforms()
                self.updatePlayer()
                self.updatePlatforms()
                self.score = - self.relative_y
                self.screen.blit(self.font.render(str(self.score), -1, (0, 0, 0)), (25, 25))
            pygame.display.flip() 


DoodleJump().run()