Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
405a998
"Creating File"
allisonlynnbasore14 Feb 25, 2017
e4740f8
"Setting up the screen and added picture"
allisonlynnbasore14 Feb 25, 2017
8a32df8
"Fixing Ice cream"
allisonlynnbasore14 Feb 25, 2017
b21b9bc
Started implementing base class Graphic.
kylecombes Feb 25, 2017
2e5c659
Merge branch 'master' of github.com:kylecombes/InteractiveProgramming
kylecombes Feb 25, 2017
16d8bde
Tweaked graphic to remove methods already implemented in pygame.sprit…
kylecombes Feb 25, 2017
f7a6ce8
"Added Cone. NOTICE: I was having trouble working with the file ice_c…
allisonlynnbasore14 Feb 26, 2017
c606adc
Merge branch 'master' of github.com:kylecombes/InteractiveProgramming
kylecombes Feb 26, 2017
5bb9ae3
Some refactoring
kylecombes Feb 26, 2017
b468426
"adding helper function"
allisonlynnbasore14 Feb 26, 2017
ad13137
Game runs. Can move cone with arrow keys and add scoops to cone by pr…
kylecombes Feb 26, 2017
5866af6
Added project description and proposal to README
kylecombes Feb 26, 2017
a26161a
"added diffrent ice cream flavors"
allisonlynnbasore14 Feb 27, 2017
1352ea6
"adding files"
allisonlynnbasore14 Feb 27, 2017
e1da37c
"commiting graphics file in graphics folder"
allisonlynnbasore14 Feb 27, 2017
13427ed
Started adding obstacles
kylecombes Feb 27, 2017
1874475
"added background picture"
allisonlynnbasore14 Feb 27, 2017
7d9b421
Merge branch 'master' of https://github.com/kylecombes/InteractivePro…
allisonlynnbasore14 Feb 27, 2017
36ebc2b
"added pictures"
allisonlynnbasore14 Feb 27, 2017
baa3516
"Added background(finally) and made it so when you get past 8 scoops,…
allisonlynnbasore14 Feb 28, 2017
131b3be
"adding picture becasue I forgot to add it to the last commit"
allisonlynnbasore14 Feb 28, 2017
c60c65d
"Replaced the cone"
allisonlynnbasore14 Mar 1, 2017
760d476
"Added end case (for when the cone reaches the top), fixed cone to mo…
allisonlynnbasore14 Mar 1, 2017
39bae34
"added draw function to asteroid, tested it in main code, added move …
allisonlynnbasore14 Mar 2, 2017
b849b83
"commented out draw function in main loop"
allisonlynnbasore14 Mar 2, 2017
7ea95ba
"Made several fixes. Mized and added scoop images. Fixed and added ob…
allisonlynnbasore14 Mar 5, 2017
b2921f2
"Adding moving obsgacles in correct intervals and fixed a couple docs…
allisonlynnbasore14 Mar 6, 2017
e29b7c3
"Collision works!! Need to add docstrings."
allisonlynnbasore14 Mar 6, 2017
a8b6f84
"added a file that makes obstacles"
allisonlynnbasore14 Mar 6, 2017
86b9b8d
"Added millions (ok, maybe more like 60) comments and docstrings. #ti…
allisonlynnbasore14 Mar 7, 2017
2393690
"fixed bugs"
allisonlynnbasore14 Mar 8, 2017
9caa4cb
"Adding PDF reflection docuemnt"
allisonlynnbasore14 Mar 8, 2017
21d00c8
"Added instructions in the README"
allisonlynnbasore14 Mar 8, 2017
3a12cae
"fixed error in README"
allisonlynnbasore14 Mar 8, 2017
204c833
"Fixed it again, but the right way"
allisonlynnbasore14 Mar 8, 2017
5db04b2
""
allisonlynnbasore14 Mar 8, 2017
4c27188
Tweaked run instructions in README
kylecombes Mar 9, 2017
a10fb9b
Changed link to summary
kylecombes Mar 9, 2017
99749a1
Added score tracking. Made it so arrow keys accelerate cone rather th…
kylecombes Mar 17, 2017
3ff5a18
Refactored code quite a bit to make more modular and readable. Still …
kylecombes Mar 21, 2017
d31e80d
Cropped obstacles to remove whitespace around edges. Made leaves and …
kylecombes Mar 21, 2017
80d006c
Refactored code to make it more concise and modular. Also addded rand…
kylecombes Apr 20, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ local_settings.py
instance/
.webassets-cache

# PyCharm
.idea/

# Scrapy stuff:
.scrapy

Expand Down
277 changes: 277 additions & 0 deletions IceCreamGame.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
"""
Cloudy with a Chance of Ice Cream is a game in which the player tries to catch falling
ice cream scoops in a cone while avoiding falling obstacles. The player gradually
progresses through the atmosphere and into space. If they make it all the way to Mars
without running into an obstacle, they win.
"""

import time
from graphics.ice_cream_cone import *
from graphics.background import Background
import random
from graphics.scoop import Scoop
from graphics.obstacles.asteroid import Asteroid
from graphics.obstacles.balloon import Balloon
from graphics.obstacles.bee import Bee
from graphics.obstacles.drone import Drone
from graphics.obstacles.leaf import Leaf


class IceCreamGame:

# ----- Constants -----

# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)

OBSTACLE_TYPES = [Leaf, Bee, Balloon, Drone, Asteroid]

CONE_ACCELERATION = 100 # pixels/second^2
CONE_ACCELERATION_PLUS = 150 # pixels/second^2
CONE_DRAG_ACCELERATION = 40 # pixels/second^2
MAX_CONE_SPEED = 500 # pixels/second

WINDOW_HEIGHT = 600 # size of screen (px)
WINDOW_WIDTH = 700 # size of screen (px)
WINDOW_TITLE = 'The Best Ice Cream Game Known to Man'

FPS = 20 # refresh rate (frames per second)

BG_CHANGE_SPEED_SCALAR = FPS / 10
BG_CHANGE_SPEED_EXP = 1.5

def __init__(self):
pygame.init() # initialize all imported pygame modules

self.FONT = pygame.font.SysFont(None, 50) # font for messages

# Initialize drawing canvas and background
self.screen = pygame.display.set_mode((self.WINDOW_WIDTH, self.WINDOW_HEIGHT))
self.background = Background(self.WINDOW_HEIGHT, self.BG_CHANGE_SPEED_SCALAR, self.BG_CHANGE_SPEED_EXP)

# Set window title
pygame.display.set_caption(self.WINDOW_TITLE)

# Set key repeat delay and interval
pygame.key.set_repeat(30, 20)

# Initialize clock for timing refreshes
self.clock = pygame.time.Clock()

# Initialize counters to keep track of time (s) till next scoop and obstacle should be released
# (could be done with separate timers, but don't need to be that precise)
self.time_till_next_obstacle_release = 5
self.time_till_next_scoop_release = 0.5

self.cone = IceCreamCone(400, self.WINDOW_HEIGHT - 230)
self.all_obstacles = list()
self.falling_scoops = list()

# Initialize player's score
self.score = 0


def message_to_screen(self, msg, c, x, y):
"""
Making a message to user function

:param msg: string you want to send as a message
:param c: color of words for message
:param x: x-coordinate you want to place message
:param y: y-coordinate you want to place message
"""
screen_text = self.FONT.render(msg, True, c)
self.screen.blit(screen_text, [x, y])

def check_for_scoop_collision(self):

# Get the object on the top of the cone stack (normally a scoop,
# unless there are no scoops, in which case it's the cone)
top_of_cone_stack = self.cone.get_top_scoop()
if top_of_cone_stack is None:
top_of_cone_stack = self.cone.cone

# Check all falling scoops for collision with top item
for scoop in self.falling_scoops:
if pygame.sprite.collide_rect(scoop, top_of_cone_stack): # Caught falling scoop
self.score += 1
self.falling_scoops.remove(scoop)
self.cone.add_scoop(scoop)

def launch_game(self):
""" Runs the game loop until the game ends

:return 0 if the window should stay open until the user closes it, or -1 if the window should be closed immediately
"""

# Time change from frame to frame
dt = 1 / self.FPS

while True:

""" ---- Acceleration of the Cone and Stacked Scoops ---- """
# Keep track of whether or not the user accelerated the cone with the keyboard
cone_did_accelerate = False

# First, respond to any user input
for event in pygame.event.get():
if event.type == pygame.QUIT:
return -1 # Exit immediately
if event.type == pygame.KEYDOWN:
# Pressing shift enables a speed boost
key_mods = pygame.key.get_mods()
accel = self.CONE_ACCELERATION_PLUS \
if key_mods & pygame.KMOD_LSHIFT or key_mods & pygame.KMOD_RSHIFT \
else self.CONE_ACCELERATION

if event.key == pygame.K_LEFT:
self.cone.accelerate(-accel, 0, dt, self.MAX_CONE_SPEED)
cone_did_accelerate = True
elif event.key == pygame.K_RIGHT:
self.cone.accelerate(accel, 0, dt, self.MAX_CONE_SPEED)
cone_did_accelerate = True
elif event.key == pygame.K_q:
return -1 # Exit immediately


# If user didn't accelerate cone, simulate drag slowing it down
if not cone_did_accelerate and self.cone.x_velocity != 0:
current_vel_sign = self.cone.x_velocity / math.fabs(self.cone.x_velocity)
self.cone.accelerate(-current_vel_sign*self.CONE_DRAG_ACCELERATION, 0, dt, self.MAX_CONE_SPEED, True)

""" ---- Update positions of everything ---- """
self.cone.update_state(dt)

for i, scoop in enumerate(self.falling_scoops):
scoop.move(0, 1) # TODO Remove hardcoding
# Remove off-screen scoops
if not scoop.is_on_screen(self.WINDOW_WIDTH, self.WINDOW_HEIGHT):
self.falling_scoops.remove(scoop)
for obstacle in self.all_obstacles:
obstacle.update_state(dt)
# Remove off-screen obstacles
if not obstacle.is_on_screen(self.WINDOW_WIDTH, self.WINDOW_HEIGHT):
self.all_obstacles.remove(obstacle)

self.background.update_state(pygame.time.get_ticks() / 1000)
if self.background.did_reach_end():
self.message_to_screen("You Win!", self.WHITE, self.WINDOW_WIDTH / 3, self.WINDOW_HEIGHT / 3)
pygame.display.update()
return 0 # Wait for user to exit

""" ---- Collision Detection ---- """
# Scoops onto cone (or top scoop on stack)
target_rect = self.cone.get_cone_top_rect()
for scoop in self.falling_scoops:
falling_rect = scoop.get_bottom_rect()
if target_rect.colliderect(falling_rect):
# Scoop collided with top of ice cream cone stack, so add it to cone stack
self.cone.add_scoop(scoop)
self.falling_scoops.remove(scoop)
self.score += 1
# Obstacles with cone or scoop stack
cone_rect = self.cone.get_rect()
for obstacle in self.all_obstacles:
if cone_rect.colliderect(obstacle.rect):
# Collision! Display message and exit loop
self.message_to_screen("You Lose!", self.RED, self.WINDOW_WIDTH / 3, self.WINDOW_HEIGHT / 3)
pygame.display.update()
return 0 # Wait for user to exit

elapsed_time = pygame.time.get_ticks() / 1000 # The number of seconds elapsed since the start of the game


""" ---- Falling Object Generation ---- """
# -- Obstacle Generation -- #
# Decrement obstacle release timer
if self.time_till_next_obstacle_release > 0:
self.time_till_next_obstacle_release -= 1 / self.FPS
# Check if timer has reached zero
if self.time_till_next_obstacle_release < 0:
self.release_obstacle(elapsed_time)
self.time_till_next_obstacle_release = random.uniform(3, 10) # TODO Change bounds with time

# -- Scoop Generation -- #
# Decrement scoop release timer
if self.time_till_next_scoop_release > 0:
self.time_till_next_scoop_release -= 1 / self.FPS
# Check if timer has reached zero
if self.time_till_next_scoop_release < 0:
self.release_scoop()
self.time_till_next_scoop_release = random.uniform(1, 6) # TODO Change bounds with time

""" ---- Draw everything ---- """
pygame.display.update() # updates the screen (for every run through the loop)
self.background.draw(self.screen)
for scoop in self.falling_scoops:
scoop.draw(self.screen)
for obstacle in self.all_obstacles:
obstacle.draw(self.screen)
self.cone.draw(self.screen)

# Display score
self.message_to_screen('Score: %i' % self.score, self.BLUE, 10, 10)

self.clock.tick(self.FPS) # Pause to maintain the given frame rate

def release_obstacle(self, time_elapsed):
""" Release an obstacle appropriate for the given time into the game

:param time_elapsed: number of seconds elapsed during the game
"""
# Calculate background position
y = self.BG_CHANGE_SPEED_SCALAR * math.pow(time_elapsed, self.BG_CHANGE_SPEED_EXP)
thresholds = [400*x for x in range(len(self.OBSTACLE_TYPES))]

obs_type = self.OBSTACLE_TYPES[0]
for i in range(len(thresholds)-1, 0, -1):
if y > thresholds[i]:
obs_type = self.OBSTACLE_TYPES[i]
break

rand_x_loc = random.randint(0, self.WINDOW_WIDTH)
print('Starting at {}'.format(rand_x_loc))
if obs_type == Leaf:
obs = Leaf(rand_x_loc, 0)
elif obs_type == Bee:
obs = Bee(rand_x_loc, 0)
elif obs_type == Drone:
obs = Drone(rand_x_loc, 0)
elif obs_type == Balloon:
obs = Balloon(rand_x_loc, 0)
elif obs_type == Asteroid:
obs = Asteroid(rand_x_loc, 0)
else:
raise Exception('Invalid obstacle type: %s' % obs_type)

obs.rect.bottom = 1 # Place just at top of screen
self.all_obstacles.append(obs)

def release_scoop(self):
""" Release a falling ice cream scoop """
rand_x = random.randint(0, self.WINDOW_WIDTH)
scoop = Scoop(rand_x, 0)
scoop.rect.bottom = 1 # Place just at top of screen
self.falling_scoops.append(scoop)


@staticmethod
def wait_for_close():
""" Pause execution until the user clicks Close """
time.sleep(2)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return


if __name__ == '__main__':
game = IceCreamGame()
exit_code = game.launch_game()
if exit_code == 0: # Player won or lost, wait to exit
game.wait_for_close()
pygame.quit() # uninitializes pygame
quit() # must have a quit
61 changes: 59 additions & 2 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,2 +1,59 @@
# InteractiveProgramming
This is the base repo for the interactive programming project for Software Design, Spring 2016 at Olin College.
## Cloudy with a Chance of Ice Cream

In Cloudy with a Chance of Ice Cream, you catch falling ice cream scoops while avoiding various atmospheric obstacles. Colliding with an obstacle results in a loss of health. As you continue to ascend, the environment changes and new obstacles emerge.

This game was created for [Mini Project 4 - Interactive Programming](https://sd17spring.github.io//assignments/mini-project-4-interactive-visualization/) of Software Design at [Olin College of Engineering](http://olin.edu/).

#### To Play
Run **python3 IceCreamGame.py**. Note: the pygame library must be installed.

#### Reflection

Our reflection and summary can be found [here](ReflectionSummary.pdf).



## Initial Project Proposal

#### Minimum Viable Product

Our MVP is a game in which the player moves an ice cream cone back and forth along the x-axis using the arrow keys in an attempt to catch ice cream scoops falling vertically. Obstacles, such as asteroids, will also fall vertically, and the player will need to avoid catching the obstacles lest they sustain damage. It will have one environment, outer space, which will be represented by an appropriately themed background image.

#### Stretch Goals
We foresee our MVP being improved by implementing any of the following additions:

* More environments ("levels"): going higher (or starting lower) in altitude would provide different background and obstacles
* Arrow keys accelerate cone (rather than move at constant velocity)
* Wobbling stack of scoops when cone accelerates. Player needs to be careful not to move too quickly.
* If high level entailed flying by planets, incorporate gravity from surrounding planets and give scoops an acceleration in x-direction
* Dynamic and adaptable difficulty thresholding

#### Individual Learning Goals

###### Allison

* Gain more experience with the pygame library
* Become more familiar with serious user input interactions

###### Kyle

* Gain experience with the pygame library
* Learn how to implement graceful environment transitions
* Learn how to implement realistic physics simulations (gravity, ice cream scoops sensitive to toppling) in a game

## Libraries
Our game will make heavy use of the [pygame](http://pygame.org/) library.

## Timeline
By our mid-project check-in, we plan to have the following done:
* All classes defined
* Good understanding of pygame options
* Identified basic physics implementations and have idea of how to implement
* Basic user interface
* Idea of how to change the background scene
* Detailed breakdown of all the project tasks

## Predicted Roadblocks
We feel we might run into trouble with the following:
* Implementing stretch goals and physics
* Implementing good graphics
Binary file added ReflectionSummary.pdf
Binary file not shown.
Binary file added assets/img/background.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/cone.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/ice-cream-scoops-ctr.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/obstacles/asteroid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/obstacles/balloon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/obstacles/bee.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/obstacles/drone.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/obstacles/leaf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/scoops/choc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/scoops/mint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/scoops/pink.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/scoops/scoop-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/scoops/strawberry.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/sky.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/space_bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added graphics/__init__.py
Empty file.
Loading