Skip to content

Instantly share code, notes, and snippets.

@horstjens
Created August 25, 2023 07:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save horstjens/b64c10b968fee92eab28a1cf824fd5f9 to your computer and use it in GitHub Desktop.
Save horstjens/b64c10b968fee92eab28a1cf824fd5f9 to your computer and use it in GitHub Desktop.
vpython catcher
import vpython as vp
import random
class Game:
player1 = None
player2 = None
fps = 30 # frames per second
dt = 1/fps # delta time in seconds
board_size = 10
player_speed = 2
player_max_height = 3
max_balls = 3
gravity = -0.2
score1 = 0
score2 = 0
w = 1200
h = 800
dark = vp.vector(0.3,0.3,0.3)
light = vp.vector(0.8,0.8,0.8)
scene = vp.canvas(width=w,
height=h,
center=vp.vector(5,1,5),
background=vp.vector(0.5,0.5,0.5))
class Player(vp.box):
def __init__(self, player_number):
if player_number == 1:
self.left_key = "a"
self.right_key = "d"
self.forward_key = "w"
self.backward_key = "s"
self.up_key = "q"
self.down_key = "e"
c = vp.color.blue
self.startpos = vp.vector(3,0.25,3)
if player_number == 2:
self.left_key = "j"
self.right_key = "l"
self.forward_key = "i"
self.backward_key = "k"
self.up_key = "u"
self.down_key = "o"
c = vp.color.yellow
self.startpos = vp.vector(7,0.25,7)
super().__init__(pos=self.startpos, color=c,
size=vp.vector(0.5,0.5,0.5))
self.number = player_number
def update(self, delta_time):
move = vp.vector(0,0,0)
keys = vp.keysdown()
print(self.pos)
if self.forward_key in keys:
move += vp.vector(0,0,-1)
if self.backward_key in keys:
move += vp.vector(0,0,1)
if self.left_key in keys:
move += vp.vector(-1,0,0)
if self.right_key in keys:
move += vp.vector(1,0,0)
if self.up_key in keys:
move += vp.vector(0,1,0)
if self.down_key in keys:
move += vp.vector(0,-1,0)
# for obj in Game.scene.objects:
# print(obj, type(obj))
# normalize the move vector
move = move.norm()
self.pos += move * Game.player_speed * delta_time
# stay on board
if self.pos.x < 1:
self.pos.x = 1
if self.pos.z < 1:
self.pos.z = 1
if self.pos.x > Game.board_size:
self.pos.x = Game.board_size
if self.pos.z > Game.board_size:
self.pos.z = Game.board_size
if self.pos.y < 0.25:
self.pos.y = 0.25
if self.pos.y > Game.player_max_height:
self.pos.y = Game.player_max_height
class Coin(vp.cylinder):
coins = []
def __init__(self, startpos):
p = vp.vector(startpos.x, startpos.y, startpos.z)
super().__init__(pos=p,
radius=0.2,
length=0.05,
color=vp.color.yellow)
self.move = vp.vector(random.uiform(-0.2,0.2),
1,
random.uiform(-0.2,0.2))
self.speed = random.uniform(10,20)
self.coins.append(self)
def update(self, delta_time):
self.pos = self.move * delta_time * self.speed
self.move += vp.vector(0,Game.gravity,0)
if self.pos.y < 0:
self.visible = False
self.coins = [c for c in self.coins if c.visible]
class Ball(vp.sphere):
balls = []
def __init__(self):
#balls = []
#for object in Game.scene.objects:
# if object.__class__.__name__ == "Ball":
# Ball.balls.append(object)
#if len(self.balls) > Game.max_balls:
# return # everything is full already
# find empty start_position
start_position = self.find_empty_position()
#print(start_position)
# we now have a valid start position. let's create a new ball here
r = random.uniform(0.25,0.45)
super().__init__(pos=vp.vector(start_position.x, -r, start_position.z),
color=vp.vector(0, random.uniform(0.5,1),0),
radius=r)
self.age = 0
self.durations = {"raising":random.uniform(0.5,1.5),
"alive":random.uniform(4,8),
"sinking":random.uniform(0.5,0.7),
"dead":random.uniform(2,12)}
self.state = "raising"
self.balls.append(self)
def update(self,delta_time):
self.age += delta_time
match self.state:
case "raising":
#self.pos.y = -self.radius + self.radius * self.age / self.durations["raising"]
self.pos.y += delta_time * self.radius/ self.durations["raising"]
if self.age > self.durations["raising"]:
self.state = "alive"
case "alive":
if self.age > self.durations["raising"] + self.durations["alive"]:
self.state = "sinking"
case "sinking":
#self.pos.y = -self.radius + self.radius * (1- self.age / (self.durations["raising"] + self.durations["alive"]+self.durations["sinking"]))
self.pos.y -= delta_time * self.radius / self.durations["sinking"]
if self.age > self.durations["raising"] + self.durations["alive"]+self.durations["sinking"]:
self.state = "dead"
#self.visible = False
self.pos.x = -1
self.pos.z = -1
case "dead":
if self.age > self.durations["raising"] + self.durations["alive"] + self.durations["sinking"] + self.durations["dead"]:
# create new
if self.pos.z > -100:
Ball()
self.pos.z = -100
self.visible = False
# kill this one
#self.balls = [b for b in self.balls if b.visible]
self.balls = []
for o in Game.scene.objects:
if o.__class__.__name__ == "Ball":
self.balls.append(o)
#print(self.balls)
def find_empty_position(self):
while True:
start_position = vp.vector(random.randint(1,Game.board_size),
0.25,
random.randint(1, Game.board_size))
for b in self.balls:
if b.pos.x == start_position.x and b.pos.z == start_position.z:
continue # go back to start of the while loop
return start_position
# create 3 arrows for x,y,z axis
vp.arrow(axis=vp.vector(1,0,0),
color=vp.color.red)
vp.arrow(axis=vp.vector(0,1,0),
color=vp.color.green)
vp.arrow(axis=vp.vector(0,0,1),
color=vp.color.blue)
# create chessboard
i = 0
for x in range(1,Game.board_size+1):
remainder = i%2
for z in range(1,Game.board_size+1):
i += 1
if i % 2 == 0:
board_color = Game.dark
else:
board_color = Game.light
vp.box(pos=vp.vector(x,-0.1,z),
size=vp.vector(1,0.2,1),
color=board_color)
if i%2 == remainder:
i+=1
#Game.player1 = vp.box(pos=vp.vector(5,0.25,5),
# size=vp.vector(0.5,0.5,0.5),
# color=vp.color.green)
Game.player1 = Player(1)
Game.player2 = Player(2)
instruction_label = vp.label(pixel_pos=True,
align="center",
pos=vp.vector(Game.w/2, Game.h-30,0),
text="press w a s d keys to move. collect red balls",
height=16,
box=False,
color = vp.color.blue)
score_label1 = vp.label(pixel_pos=True,
align="left",
pos=vp.vector(10, Game.h-30,0),
text="Player1: 0",
height=24,
box=False,
color=vp.color.white)
score_label2 = vp.label(pixel_pos=True,
align="right",
pos=vp.vector(Game.w-10, Game.h-30,0),
text="Player2: 0",
height=24,
box=False,
color=vp.color.white)
#add_ball()
seconds = 0
special = Ball()
Ball()
Ball()
while True:
vp.rate(Game.fps)
seconds += Game.dt
keys = vp.keysdown()
for p in (Game.player1, Game.player2):
p.update(Game.dt)
#for c in Coin.coins:
# c.update(Game.dt)
for b in Ball.balls:
#b.age += Game.dt
b.update(Game.dt)
hit = False
if vp.mag(Game.player1.pos - b.pos) < 0.5:
Game.score1 += 1
hit = True
if vp.mag(Game.player2.pos - b.pos) < 0.5:
Game.score2 += 1
hit = True
if hit:
#for _ in range(3):
# Coin(Game.player1.pos)
b.state = "dead"
b.pos.x = -1
b.pos.z = -1
b.pos.y = -1
score_label1.text=f"Score: {Game.score1}"
score_label2.text=f"Score: {Game.score1}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment