A downloadable game

Particle System (Rocket Landing Game)

Project Description

A simple rocket landing game with different difficulties selections and (real?) handcrafted physics simulation!

Assignment Rubrics

  • 2 points - use PVectors to keep track of position/velocity and any other relevant 2D coordinates
  • 8 points - have at least two different object classes, you need to be able to have many of the screen, they should animate/move around, and they should expire when appropriate (and remove themselves from the lists they are in)
  • Extra Credit (2 points) - make it a game.  This will probably involve some combination of a goal, fail/win state, score, and difficulty (with a curve too?).

My Code

# Rocket Landing Game
# Use Space to Ignite or shutdown Engine. 
# Use wasd to control the throttle and angle
# Also, The minimum throttle is somewhere between 15- 25
GRAV_CONST = 0.002
ROCKET_SPWAN_X_POS = [600, 1000]
ROCKET_SPWAN_Y_POS = [80, 30]
ROCKET_SPWAN_X_VEL = [-0.1, -0.05]
ROCKET_SPWAN_Y_VEL = [0.15, 0.1]
isOnMenu = True
isOnGame = False
isOnScore = False
rocketNo = 1
planetNo = 1
mouseClickPasser = False
particleList = []
def setup():
    global rocket, planet
    size(1280,800)
    rectMode(CENTER)
    textMode(CENTER)
    
    #print(getInitialRocketPos(), getInitialRocketVel())
    rocket = Rocket(getInitialRocketPos(), getInitialRocketVel(), PVector(30, 100))
    planet = Planet(100, color(133, 132, 121))
    background(0)
    
def draw():
    if isOnMenu:
        drawMenu()
    elif isOnGame:
        drawGame()
    elif isOnScore:
        drawScore()
def drawMenu():
    global rocketNo, planetNo, isOnMenu, isOnGame, rocket, planet
    background(0)
    
    fill(255)
    textSize(30)
    text("select your rocket to fly, your Choice is: " + str(rocketNo), 200, 100)
    text("select your planet to land, your Choice is: " + str(planetNo), 200, 400)
    
    if buttonCreation(300, 250, 200, 100, "Rocket 1 EZ"):
        rocketNo = 1
    if buttonCreation(600, 250, 200, 100, "Rocket 2 Mid"):
        rocketNo = 2
    if buttonCreation(900, 250, 200, 100, "Rocket 3 Hard"):
        rocketNo = 3
        
    if buttonCreation(300, 450, 200, 100, "Planet 1 EZ"):
        planetNo = 1
    if buttonCreation(600, 450, 200, 100, "Planet 2 Mid"):
        planetNo = 2
    if buttonCreation(900, 450, 200, 100, "Planet 3 Hard"):
        planetNo = 3
    
    if buttonCreation(640, 650, 300, 150, "Go"):
        isOnMenu = False
        isOnGame = True
        rocket = Rocket(getInitialRocketPos(), getInitialRocketVel().mult(rocketNo), PVector(30, 100).mult(rocketNo))
        planet = Planet(100 * planetNo, color(133, 132, 121)) 
    
def drawGame():
    global rocket, planet
    
    background(0)
    rocket.update()
    rocket.render()
    
    for particle in particleList:
        particle.update()
        #print("update Success")
        particle.render()
        
    drawThrottleBar()
    drawFuelBar()
    
    planet.render()
    drawScore()
def drawScore():
    global rocket, planet
    if rocket.landingStatus == True or rocket.landingStatus == False:
        drawScoreBoard(rocket.landingStatus)
#_______Key Functions________#
def keyPressed():
    global rocket
    if key == ' ':
        rocket.isEngineOn = not rocket.isEngineOn
    elif key == 'w':
        if rocket.throttle < rocket.maxThrottle:
            rocket.throttle = rocket.throttle + 5
    elif key == 's':
        if rocket.throttle > rocket.minThrottle:
            rocket.throttle = rocket.throttle - 5
    elif key == 'a':
        rocket.angularAcce = -1 * rocket.rotationPwr
    elif key == 'd':
        rocket.angularAcce = rocket.rotationPwr
        
def keyReleased():
    if key == 'a' or key == 'd':
        rocket.angularAcce = 0
    if key == 'w' or key == 's':
        rocket.throttle = rocket.throttle
#______Helper Function_______#
def getInitialRocketPos():
    tempPosX = random(ROCKET_SPWAN_X_POS[0], ROCKET_SPWAN_X_POS[1])
    tempPosY = random(ROCKET_SPWAN_Y_POS[0], ROCKET_SPWAN_Y_POS[1])
    return PVector(tempPosX, tempPosY)
def getInitialRocketVel():
    tempVelX = random(ROCKET_SPWAN_X_VEL[0], ROCKET_SPWAN_X_VEL[1])
    tempVelY = random(ROCKET_SPWAN_Y_VEL[0], ROCKET_SPWAN_Y_VEL[1])
    return PVector(tempVelX, tempVelY)
def drawThrottleBar():
    global rocket
    # Draw background of the throttle bar
    fill(100)
    rect(1250, 300, 20, 300)
    # Current Throttle level
    if rocket.isEngineOn:
        fill(0, 255, 0)  
    else:
        fill(255, 0, 0)
    throttleLevelHeight = map(rocket.throttle, 0, 100, 0, 300)
    rect(1250, 450 - throttleLevelHeight / 2, 20, rocket.throttle * 3)
    print(rocket.throttle)
    
def drawFuelBar():
    global rocket
    fill(100)
    rect(1200, 300, 20, 300)
    
    if rocket.isEngineOn:
        fill(240, 190, 53)
    else:
        fill(99, 87, 52)
    fuelLevelHeight = map(rocket.fuel, 0, rocket.maxFuel, 0, 300)
    rect(1200, 450 - fuelLevelHeight / 2, 20, fuelLevelHeight)
    
def drawScoreBoard(landingStatus):
    if landingStatus == None:
        pass
    elif landingStatus == True:
        fill(0, 255 ,0)
        rect(width / 2, height / 2, width - 200, height - 150)
        fill(0)
        textSize(100)
        text("You land successfully", 640, 400)
    elif landingStatus == False:
        fill(255, 0, 0)
        rect(width / 2, height / 2, width - 200, height - 150)
        fill(0)
        textSize(100)
        text("You failed", 640, 400)
    
def buttonCreation(posX, posY, sizeX, sizeY, tempText):
    global mouseClickPasser
    
    if (mouseX > posX - (0.5 * sizeX)) and (mouseX < (posX + (0.5 * sizeX))) and (mouseY > posY - (0.5 * sizeY)) and (mouseY < posY + (0.5 * sizeY)):
        fill(200, 200, 250)
        rect(posX, posY, sizeX, sizeY)
        fill(40)
        textSize(30)
        text(tempText, posX - 0.5 * sizeX, posY)
        if mouseClickPasser:
            mouseClickPasser = False
            return True
    else:
        fill(100, 100, 130)
        rect(posX, posY, sizeX, sizeY)
        fill(250)
        textSize(30)
        text(tempText, posX - 0.5 * sizeX, posY) 
    return False
        
        
def mouseClicked():
    global mouseClickPasser
    mouseClickPasser = True
    
#_______Yay, rocket Class_________#
class Rocket(object):
    def __init__(self, tempPos, tempVel, tempSize):
        self.pos = tempPos
        self.vel = tempVel
        self.siz = tempSize
        self.isEngineOn = False
        self.throttle = 100
        self.angle = atan2(self.vel.y, self.vel.x)
        self.angularVel = 0
        self.angularAcce = 0
        
        self.rotationPwr = 0.0003
        self.throttlePwr = 0.03
        
        self.maxThrottle = 100
        self.minThrottle = 15
        
        self.fuel = 1000
        self.maxFuel = self.fuel
        
        self.landingStatus = None
    
    def update(self):
        # Calculate the throttle
        self.vel += PVector(0, GRAV_CONST)
        if self.isEngineOn:
            tempThrottleAcceY = -0.001 * self.throttle * self.throttlePwr
            self.vel += PVector(0, tempThrottleAcceY).rotate(self.angle)
            
            self.fuel -= self.throttle / 100.0
            #print(self.fuel)
        if self.fuel <= 0:
            rocket.isEngineOn = False
        self.pos += self.vel
        
        # Calculate the Angle stuff
        self.angularVel += self.angularAcce
        self.angle += self.angularVel
        
        self.checkCollisionWithPlanet(planet)
        
        
        
    def render(self):
        pushMatrix()
        translate(self.pos.x, self.pos.y)
        rotate(self.angle)
        fill(255)
        rect(0, 0, self.siz.x, self.siz.y)
        popMatrix()
        if self.isEngineOn:
            #pass
            self.addSmoke()
        
    def addSmoke(self):
        tempPos = self.pos.copy()
        tempVel = PVector(cos(self.angle + 0.5 * PI), sin(self.angle + 0.5 * PI)).mult(self.throttle * 0.05)
        newSmoke = Particle(tempPos,                              #self.pos + PVector(0, 0.5 * self.siz.y),
                            tempVel,
                            180,
                            50,
                            color(99, 87, 83),
                            0.5 * PI)
        particleList.append(newSmoke)
        #print("Init particle success:", len(particleList))
        
    def checkCollisionWithPlanet(self, planet):
        halfWidth = self.siz.x / 2
        halfHeight = self.siz.y / 2
        corners = [
            PVector(-halfWidth, -halfHeight).rotate(self.angle) + self.pos,
            PVector(halfWidth, -halfHeight).rotate(self.angle) + self.pos,
            PVector(-halfWidth, halfHeight).rotate(self.angle) + self.pos,
            PVector(halfWidth, halfHeight).rotate(self.angle) + self.pos
        ]
        
        for corner in corners:
            if corner.y >= height - planet.hgt:
                if abs(self.vel.y) > 0.2 or abs(self.vel.x) > 0.2:  # Adjust the speed threshold as necessary
                    print("Rocket exploded!")
                    self.landingStatus = False
                else:
                    print("Safe landing!")
                    self.landingStatus = True
                    break
                self.isEngineOn = False  # Turn off the engine on collision
    
#________Particle Effects__________#
class Particle(object):
    def __init__(self, tempPos, tempVel, tempLife, tempSize, tempColor, tempDispersion): #Dispersion should be radian
        self.pos = tempPos
        initialAngle = atan2(tempVel.y, tempVel.x) #WTF??? why first y then x?
        tempDispersionAngle = random(-1 * tempDispersion / 2, tempDispersion / 2)
        finalAngle = initialAngle + tempDispersionAngle
        self.vel = PVector(cos(finalAngle), sin(finalAngle)) * tempVel.mag()
        #self.vel = tempVel
        self.curLife = 1.0
        self.life = tempLife
        #print("Life:", self.life)
        self.siz = 0.0
        self.finalSiz = tempSize
        self.col = tempColor
        
    def update(self):
        #print("Part update called")
        self.pos += self.vel
        #print("Part pos calculated", self.curLife, self.finalSiz, self.siz)
        self.siz = self.curLife / self.life * self.finalSiz
        #print("siz calcualted")
        self.curLife += 1.0
        #print("cal finish")
        if self.curLife >= self.life:
            self.selfDeletion()
        
        
    def render(self):
        tempTransparentColor = color(0, 0, 0, 0)
        tempColor = lerpColor(self.col, 
                             tempTransparentColor, 
                             (float(self.curLife) / float(self.life)))
        #fill(255)
        noStroke()
        fill(tempColor)
        #print(self.pos.x, self.pos.y, self.siz * 2)
        circle(self.pos.x, self.pos.y, self.siz * 2)
        
    def selfDeletion(self):
        particleList.remove(self)
        
#_________Planet Class_________#
class Planet(object):
    #TODO: change planet's color to actual image
    def __init__(self, tempHeight, tempColor):
        self.hgt = tempHeight
        self.col = tempColor
        
    def render(self):
        fill(self.col)
        #change it later to image
        rect(width / 2, height - self.hgt / 2, width, self.hgt) 

Screenshot


Simple Painter App Gameplay

Download

Download
application.windows64.zip 42 MB

Install instructions

Java 8 required~

Leave a comment

Log in with itch.io to leave a comment.