doppeldecker
# requriements: | |
# sudo pip3 install vpython | |
# sudo pip3 install pygame | |
import vpython as v | |
import random | |
import pygame | |
#except ModuleNotFoundError: | |
# print("I could not import pygame - joystick support is disabled. Try to (re)install pygame") | |
#delete, backspace, page up, page down, home, end, left, up, right, down, numlock, scrlock, f1, f2, f3, f4, f5, f6, f7, f8. Windows and Linux also have f9, f11, f12, insert | |
#if you hold down the shift key and press F3, key will be the character string 'shift+f3', which you can test for explicitly. If you hold down all three modifier keys, you get 'ctrl+alt+shift+f3'; the order is always ctrl, alt, shift. | |
# constants | |
class Game: | |
scene1 = v.canvas(title="Doppeldecker", | |
width=800, | |
height=600, | |
center=v.vector(0, 0, 0), | |
background=v.vector(0.8, 0.8, 1), | |
resizable=False | |
) | |
#camera_mode = "follow" | |
scene1.autoscale = False | |
scene1.userspin = False | |
camera_delay = 0.0 # seconds | |
camera_history = [] | |
# scene1.range = 200 | |
max_depth = -10 # lowest point of the landscape? | |
dt = 0.005 # delta t | |
world = 100 # half lenght (x,y) of world | |
rotation = 60 # rotation speed of plane | |
cooldown_gun = 0.05 | |
cooldown_flak = 0.20 | |
cooldown_bomb = 0.3 | |
drag_player = 5.5 # 5.515 | |
drag_bullet = 0.1 | |
drag_bomb = 2.0 | |
radius_player = 0.15 # for ground collision hitbox | |
cannon_power = 17000 # bullet speed at start | |
lift_factor = 0.5 | |
mass_player = 0.1 | |
mass_bullet = 0.011 | |
mass_bomb = 0.05 | |
mass_particle = 0.005 | |
flak_range = 40 # range when flak start shooting at player | |
flak_crit_distance = 0.5 # how close flak shell must be to player center to make damage | |
g = 9.81 | |
#g_player = 9.81 | |
#g_bullet = 9.81 | |
#g_bomb = 5.2 | |
particle_list = [] | |
tank_list = [] | |
bullet_list = [] | |
explosion_list = [] | |
static_list = [] | |
bomb_list = [] | |
target_list = [] | |
ring_list = [] | |
#flak_list = [] | |
flak_barrel_list = [] | |
ring_center_distance = 1 # 1 is hard, 10 is super easy | |
# UI widgets, initialized in function main() | |
vlist = [] # list for ground vertices | |
label_dt = None | |
label_lift = None | |
label_ring_center_distance = None | |
label_rotation = None | |
label_delay = None | |
ring_index = 0 | |
my_ring = None | |
max_power = 20 # values over 20 make the plane slower.... bug in physic ? | |
min_power = 0 | |
def create_sun(): | |
s = v.simple_sphere( | |
pos = v.vector(random.uniform(-Game.world,Game.world), # x | |
random.uniform(50,60), # y | |
random.uniform(-Game.world,Game.world) # z | |
), | |
#radius = random.random()*2 + 0.5 # 0.5 - 2.5 | |
radius = random.uniform(0.5, 2.5), # 0.5 bis 2.5 | |
color = v.vector(1,1,0), #100%red, 100%green, 0%blue = gelb | |
shininess = 0.6, # häääääää ? | |
emissive = True, # leuchtet? | |
) | |
return s | |
def create_ring(): | |
r = v.ring(pos=v.vector(random.randint(-Game.world,Game.world), random.randint(5,15), random.randint(-Game.world,Game.world)), | |
axis=v.vector(random.random()*2-1,0,random.random()*2-1), | |
radius= 2.5 + random.random()*7, | |
thickness=0.1 + random.random()*2, | |
) | |
return r | |
def create_flak(): | |
h = random.randint(5,12) # height | |
body = v.box( | |
size=v.vector(0.5,h,0.5), | |
pos= v.vector(2,h/2,2), | |
axis = v.vector(1,0,0), | |
color = v.vector(1,1,0), | |
) | |
ball = v.simple_sphere( | |
size = v.vector(2,2,2), | |
pos = v.vector(2,h,2), | |
axis = v.vector(1,0,0), | |
color = v.vector(0.8,0.8,0) | |
) | |
flak = v.compound([body, ball]) | |
x = random.uniform(-Game.world +1, Game.world -1) | |
z = random.uniform(-Game.world +1, Game.world -1) | |
y = f(x,z) * Game.max_depth | |
flak.pos = v.vector(x, y + h/2, z) | |
flak.hitpoints = 100 | |
flak.rot_speed_y = 30 | |
flak.rot_speed_x = 20 | |
Game.target_list.append(flak) | |
create_flak_barrel(flak) | |
def create_flak_barrel(flak): | |
barrel = v.cylinder( pos=v.vector(0,0,0), | |
radius = 0.2, | |
axis = v.vector(3,0,0), | |
color = v.vector(0.1,0.1,0.1) | |
) | |
barrel.pos = v.vector(flak.pos.x, flak.pos.y + flak.size.y/2 -0.5, flak.pos.z) | |
barrel.age = 0 | |
barrel.block_gun_until = 0 | |
barrel.move = v.vector(0,0,0) # important for bullets! | |
barrel.flak = flak | |
Game.flak_barrel_list.append(barrel) | |
def create_tank(): | |
body = v.box( | |
size=v.vector(2,0.5,1), | |
pos=v.vector(0, 0.25 ,0), | |
axis=v.vector(1,0,0), | |
color=v.vector(0,0, random.uniform(.65,0.90)), | |
) | |
turret = v.cylinder( | |
size=v.vector(0.3,0.75, 0.75), | |
pos = v.vector(0, 0.5, 0), | |
axis = v.vector(0,1,0), | |
color=v.vector(0.2,0.2,0.2) | |
) | |
cannon = v.cylinder( | |
size=v.vector(2 , 0.1, 0.1), | |
axis= v.vector(1,0,0), | |
pos = v.vector(-0.25, 0.75, 0 ), | |
color = v.vector(0.8,0.8,1.0) | |
) | |
tank = v.compound([body, turret, cannon]) | |
tank.size = v.vector(4,1,2) | |
#tank.pos.y += 2 | |
tank.pos = v.vector(random.randint(-Game.world+1, Game.world-1),0.25, random.randint(-Game.world+1, Game.world-1)) | |
tank.power = random.uniform(1, 3) | |
tank.angle = random.random() * 360 | |
tank.rotate(angle=v.radians(tank.angle), axis=v.vector(0,1,0) ) | |
tank.move = tank.axis.norm() * tank.power | |
tank.hitpoints = 100 | |
#tank.hy = v.vector(0, -10, 0) | |
#v.attach_arrow(tank, "hy" , color=v.vector(1,1,1) ) | |
Game.tank_list.append(tank) | |
Game.target_list.append(tank) | |
def create_cross(): | |
"""create three arrows (pointing to x, y, z) at pos (0,0,0)""" | |
xpointer = v.arrow( | |
pos=v.vector(0, 0, 0), | |
axis=v.vector(1, 0, 0), | |
shaftwidth=0.1, | |
color=v.color.yellow, | |
) | |
ypointer = v.arrow( | |
pos=v.vector(0, 0, 0), | |
axis=v.vector(0, 1, 0), | |
shaftwidth=0.1, | |
color=v.color.purple, | |
) | |
zpointer = v.arrow( | |
pos=v.vector(0, 0, 0), | |
axis=v.vector(0, 0, 1), | |
shaftwidth=0.1, | |
color=v.color.blue, | |
) | |
cross = v.compound((xpointer, ypointer, zpointer)) | |
cross.pos = v.vector(0,1,0) | |
xlabel = v.label( | |
pos=cross.pos + xpointer.axis, | |
text='x', xoffset=0, yoffset=5, space=1, height=16, border=4 | |
) | |
ylabel = v.label( | |
pos=cross.pos + ypointer.axis, | |
text='y', xoffset=0, yoffset=5, space=1, height=16, border=4 | |
) | |
zlabel = v.label( | |
pos=cross.pos + zpointer.axis, | |
text='z', xoffset=0, yoffset=5, space=1, height=16, border=4 | |
) | |
return cross | |
def create_player(): | |
# ----- player (flugzeug) ----- | |
body = v.box( | |
# x y z | |
size=v.vector(2,0.25,0.25), | |
pos = v.vector(0,0,0), | |
color=v.vector(0.72,0.42,0) | |
) | |
upperwing = v.box( | |
# x y z | |
size=v.vector(0.5,0.05,2), | |
pos = v.vector(0.5,0.2,0), | |
color=v.vector(0.26,0.99,0.78), | |
) | |
lowerwing = v.box( | |
# x y z | |
size=v.vector(0.5,0.05,2), | |
pos = v.vector(0.5,-0.2,0), | |
color=v.vector(0.26,0.99,0.78),) | |
#make_trail=True, | |
#trail_type="points", | |
#interval=10, | |
#retain=150, | |
#trail_color=v.vector(0,1,0) | |
#) | |
# höhenruder | |
rudder1 = v.box( | |
size=v.vector(0.2, 0.05, 1), | |
pos=v.vector(-1, 0, 0), | |
color=v.vector(0.26, 0.99, 0.78), | |
) | |
# seitenruder | |
rudder2 = v.box( | |
# x y z | |
size=v.vector(0.2, 0.5, 0.05), | |
pos=v.vector(-1, 0.25, 0), | |
color=v.vector(0.26, 0.99, 0.78), | |
) | |
player = v.compound([body, upperwing, lowerwing, rudder1, rudder2],) | |
#make_trail=True, | |
#trail_type="points", | |
#interval=10, | |
#retain=150, | |
#trail_color=v.vector(0,1,0)) | |
player.axis = v.vector(1, 0, 0) | |
player.pos = v.vector(0, 2, 0) | |
player.power = 0.0 | |
player.block_gun_until = 0.0 | |
player.block_bomb_until = 0.0 | |
player.age = 0.0 | |
player.move = v.vector(0,0,0) | |
player.points = 0 #https://vpython.org/ | |
player.hitpoints = 100 | |
player.modus = "ground" | |
player.pos.y = player.size.y // 2 | |
player.move = v.vector(0, 0, 0) | |
player.motor = v.vector(0, 0, 0) | |
player.lift = v.vector(0, 0, 0) | |
player.gravity = v.vector(0, -1, 0) * Game.mass_player * Game.g | |
player.ring = v.vector(0,0,0) | |
player.shadow = v.box(pos=v.vector(0,0,0), size=v.vector(1,0.1,1), color=v.vector(0.2,0,0), opacity=0.5) | |
player.shadow_pos_old = v.vector(0,0,0) | |
#print("player size:", player.size) | |
return player | |
def f(x, z): | |
"""returns y value for a given x and z""" | |
# ----- landing strip ------ | |
if -15 < x < 30: | |
if -15 < z < 15: | |
return 0 | |
# ----- rest of the world ------ | |
t = 0.1 | |
#return 0.7+0.5*v.sin(10*x)*v.cos(10*z)*v.sin(5*t) | |
return 0.7 + 0.5 * v.sin(.1 * x) * v.cos(0.1 * z) * v.sin(5 * t) | |
# static objects | |
def create_world(): | |
"""puts diverse objects into static_list""" | |
# fence post | |
middle = 0 | |
h = Game.max_depth * 2 | |
Game.static_list.append(v.box(pos=v.vector(-Game.world, middle, -Game.world), size=v.vector(1.5,h,1.5))) | |
Game.static_list.append(v.box(pos=v.vector(-Game.world, middle, Game.world),size=v.vector(1.5,h,1.5))) | |
Game.static_list.append(v.box(pos=v.vector(Game.world, middle, -Game.world),size=v.vector(1.5,h,1.5))) | |
Game.static_list.append(v.box(pos=v.vector(Game.world, middle, Game.world),size=v.vector(1.5,h,1.5))) | |
# fence | |
Game.static_list.append(v.cylinder(pos=v.vector(-Game.world,1,Game.world), size=v.vector(2*Game.world,0.1,0.1), color=v.vector(0,1,0))) | |
Game.static_list.append(v.cylinder(pos=v.vector(-Game.world,1,-Game.world), size=v.vector(2*Game.world,0.1,0.1), color=v.vector(0,1,0))) | |
Game.static_list.append(v.cylinder(pos=v.vector(-Game.world,1,Game.world), size=v.vector(2*Game.world,0.1,0.1), axis=v.vector(0,0,-1), color=v.vector(0,1,0))) | |
Game.static_list.append(v.cylinder(pos=v.vector(Game.world,1,Game.world), size=v.vector(2*Game.world,0.1,0.1), axis=v.vector(0,0,-1), color=v.vector(0,1,0))) | |
# ground texture | |
#Game.static_list.append(v.box( | |
# pos=v.vector(0,-0.01,0), | |
# size=v.vector(Game.world*2,0.01,Game.world*2), | |
# color=v.vector(0.8,0.3,0.0), | |
# texture=v.textures.stucco, | |
# opacity = 0.2, | |
# )) | |
Game.vlist = [] | |
parts = 10 | |
#Game.max_depth = -10 | |
for z in v.arange(-Game.world, Game.world+1,Game.world/parts ): | |
li = [] | |
for x in v.arange(-Game.world, Game.world+1,Game.world/parts ): | |
#y= random.uniform(max_depth,0) | |
y = f(x,z) * Game.max_depth | |
li.append(v.vertex(pos=v.vec(x, y, z), | |
color=v.vector(0,y/Game.max_depth,0), | |
normal=v.vec(0,1,0) | |
)) | |
#v.arrow(pos=v.vector(x,0,z), | |
# axis=v.vector(0,y,0), | |
# shaftwidth=1) | |
Game.vlist.append(li) | |
for z in range(parts*2): | |
for x in range(parts*2): | |
Game.static_list.append( | |
v.quad(v0 = Game.vlist[z][x], | |
v1 = Game.vlist[z][x+1], | |
v2 = Game.vlist[z+1][x+1], | |
v3 = Game.vlist[z+1][x], | |
) | |
) | |
#Game.static_list.append( | |
# v.quad( | |
# v0=v.vertex(pos=v.vec(-Game.world, 0, -Game.world)), | |
# v1=v.vertex(pos=v.vec(-Game.world, 12.2, Game.world)), | |
# v2=v.vertex(pos=v.vec(Game.world, -5, Game.world)), | |
# v3=v.vertex(pos=v.vec(Game.world, 4, -Game.world)), | |
# texture=v.textures.stucco, | |
# ), | |
# | |
# ) | |
# rings to fly through | |
for _ in range(5): | |
Game.ring_list.append(create_ring()) | |
update_rings() | |
Game.static_list.append(create_sun()) | |
#Game.static_list.append(create_cross()) | |
for _ in range(4): | |
create_building() | |
for _ in range(5): | |
create_flak() | |
for _ in range(14): | |
create_tank() | |
#for t in Game.tank_list: | |
# v.attach_arrow(t, "up", color=v.vector(1,1,1)) | |
def create_building(): | |
"""create a box for bomb practice (a house)""" | |
height = random.uniform(1,15) | |
x = random.uniform(-Game.world, Game.world) | |
z = random.uniform(-Game.world, Game.world) | |
y = f(x,z) * Game.max_depth | |
box = v.box(pos= v.vector(x,y + height/2,z), | |
size= v.vector(random.uniform(1,9), height , random.uniform(1,5), ), | |
axis= v.vector(random.random(), 0, random.random() ), | |
color=v.vector(0.7,0.4,0.1), | |
) | |
box.hitpoints = 800 | |
box.age = 0 | |
Game.target_list.append(box) | |
def create_bomb(shooter): | |
#b = v.simple_sphere(pos=v.vector(shooter.pos.x, shooter.pos.y+5, shooter.pos.z), | |
#color=v.vector(0.2, 0.2, 0.2), | |
#radius=0.2,) | |
b = v.cylinder(pos=v.vector(shooter.pos.x, shooter.pos.y, shooter.pos.z), | |
color= v.vector(0.2,0.2,0.2), axis = v.norm(shooter.axis)*2, radius=0.35 ) | |
b.move = v.vector(shooter.move.x, shooter.move.y, shooter.move.z) | |
shooter.block_bomb_until = shooter.age + Game.cooldown_bomb | |
b.fresh = True | |
Game.bomb_list.append(b) | |
def create_explosion(pos, max_age=0.4, hit=False): | |
e = v.simple_sphere(pos=pos, | |
radius = 0.001, | |
color=v.vector(1,1,0)) | |
e.age = 0 | |
e.max_age = max_age | |
e.hit = hit | |
#e.start_radius = start_radius | |
Game.explosion_list.append(e) | |
def update_hud(): | |
Game.hud.text = f"score: {Game.player1.points} hp: {Game.player1.hitpoints} engine: {(Game.player1.power/Game.max_power)*100:.0f}% {Game.player1.modus} y: {Game.player1.pos.y:.1f} ground:{f(Game.player1.pos.x, Game.player1.pos.z)*Game.max_depth:.1f} distance to next ring: {v.mag(Game.ring_distance):.2f} " | |
def create_particle(pos): | |
color = v.vector(random.random(), random.random(), random.random()) | |
size = random.random() * 0.1 + 0.01 | |
p = v.box(pos=pos, size=v.vector(size,size,size), color=color, axis=v.vector.random()) | |
p.max_age = random.random() + 0.1 | |
p.age = 0 | |
p.move = v.vector.random() | |
p.move *= 10 | |
Game.particle_list.append(p) | |
def create_bullet(shooter, error=0.025): | |
if shooter == Game.player1: | |
c = v.vector(1,0,0) | |
shooter.block_gun_until = shooter.age + Game.cooldown_gun | |
else: | |
c = v.vector(0.8,0.8,0) | |
shooter.block_gun_until = shooter.age + Game.cooldown_flak | |
b = v.cylinder(size=v.vector(1, 0.1, 0.1), axis=v.vector(1, 0, 0), color=c) | |
b.shooter = shooter | |
b.axis = shooter.axis | |
b.pos = shooter.pos | |
b.age = 0 | |
b.max_age = 5.5 | |
b.fresh = True | |
b.error = error | |
b.move = shooter.move | |
Game.bullet_list.append(b) | |
def rotate_plane(player): | |
"""rotate smoke emitters at the plane's wings """ | |
pos1 = v.vector(player.pos.x, player.pos.y, player.pos.z) | |
# pos=v.vector(0.7,0,1), | |
pos1 += player.axis.norm() * 0.7 | |
pos2 = pos1 + v.cross(player.axis, player.up) | |
pos3 = pos1 - v.cross(player.axis, player.up) | |
return pos2, pos3 | |
def fly(): | |
ground_here = f(Game.player1.pos.x, Game.player1.pos.z) * Game.max_depth | |
if Game.player1.pos.y - Game.radius_player >= ground_here: | |
Game.player1.modus = "fly" | |
Game.player1.gravity = v.vector(0, -1, 0) * Game.g * Game.mass_player * Game.dt | |
elif Game.player1.pos.y - Game.radius_player < ground_here: | |
Game.player1.modus = "ground" | |
Game.player1.pos.y = ground_here + Game.radius_player | |
Game.player1.gravity = v.vector(0, 0, 0) | |
# Game.player1.gravity = v.vector(0,0,0) | |
if Game.player1.axis.y < 0: | |
Game.player1.power = 0 # turn engine off | |
#else: | |
# Game.player1.modus = "ground" | |
#if Game.player1.modus == "ground": | |
Game.player1.motor = Game.player1.power * Game.dt * Game.player1.axis.norm() | |
# gravitation | |
# gravity = 9.81 * dt * v.vector(0,-1,0) #player1.up.norm() # v.vector(0,-1,0) # player1.up.norm() #TODO ABSOLUTE GRAVITY | |
# -------- lift ------ | |
# a = nase vom flugzeug | |
# b = move vom flugzeug | |
# print("comp b.a", b.axis.comp(a.axis)) | |
# p = v.arrow(pos=v.vector(0, 0, 0), axis=v.proj(b.axis, a.axis), shaftwidth=0.1, color=v.vector(0.5, 0, 0.5)) | |
#Game.player1.lift = Game.lift_factor * Game.player1.power * Game.dt * Game.player1.up.norm() | |
if Game.player1.move.comp(Game.player1.axis) > 0: | |
# Auftrieb findet statt | |
Game.player1.lift = v.mag(v.proj(Game.player1.move, Game.player1.axis)) * Game.player1.up.norm() * Game.dt * Game.lift_factor | |
else: | |
# stall | |
Game.player1.lift = v.vector(0,0,0) | |
Game.player1.move += Game.player1.motor + Game.player1.lift | |
# drag | |
drag = Game.player1.move.mag2 * Game.drag_player * -Game.player1.move.norm() | |
Game.player1.move += drag | |
# flugzeug position update | |
#position_old = v.vector(player1.pos.x, player1.pos.y, player1.pos.z) | |
Game.player1.pos += Game.player1.move | |
#if player1.pos.y < 0 and position_old.y >= 0: | |
# player1.power = 0 | |
# positionslichter update | |
Game.smoke1.pos += Game.player1.move | |
Game.smoke2.pos += Game.player1.move | |
#if Game.player1.pos.y < Game.player1.size.y / 2: | |
# Game.player1.pos.y = Game.player1.size.y / 2 | |
# Game.smoke1.pos.y = Game.player1.size.y / 2 | |
# Game.smoke2.pos.y = Game.player1.size.y / 2 | |
#elif Game.player1.pos.y >= Game.player1.size.y / 2: | |
if Game.player1.modus == "fly": | |
Game.player1.move += Game.player1.gravity | |
# update camera axis | |
#Game.scene1.forward = Game.player1.axis | |
# update shadow | |
Game.player1.shadow_pos_old = v.vector(Game.player1.shadow.pos.x, Game.player1.shadow.pos.y, Game.player1.shadow.pos.z) | |
Game.player1.shadow.pos = v.vector(Game.player1.pos.x, f(Game.player1.pos.x, Game.player1.pos.z) * Game.max_depth + 0.3, Game.player1.pos.z) | |
diff = Game.player1.shadow.pos - Game.player1.shadow_pos_old | |
Game.player1.shadow.axis = diff | |
Game.player1.shadow.axis.x = Game.player1.axis.x | |
Game.player1.shadow.axis.z = Game.player1.axis.z | |
def update_bullets(): | |
for bullet in Game.bullet_list: | |
if bullet.fresh: | |
bullet.move += (v.norm(bullet.axis) + v.vector.random() * bullet.error) * Game.cannon_power * Game.dt | |
bullet.fresh = False | |
bullet.move += Game.g * Game.mass_bullet * v.vector(0,-1,0) | |
# drag = bullet.move.mag2 * 5.515 * -bullet.move.norm() | |
#bullet.move += drag | |
bullet.pos += bullet.move * Game.dt | |
bullet.age += Game.dt | |
# collision detection bullet <-> target | |
if bullet.shooter == Game.player1: | |
for target in Game.target_list: | |
distance = bullet.pos - target.pos | |
if abs(distance.x) < target.size.x / 2: | |
if abs(distance.y) < target.size.y / 2: | |
if abs(distance.z) < target.size.z / 2: | |
# explosion | |
create_explosion(pos=bullet.pos, hit=True) | |
Game.player1.points += 1 | |
# hud.text = f"points: {player1.points} engine power: {player1.power:.2f}" | |
# update_hud() | |
target.hitpoints -= 2 # damage of bullet | |
#bullet.age = bullet.max_age | |
bullet.visible = False | |
bullet.delete() | |
else: | |
# ---- flak bullet, target is the player ! ----- | |
target = Game.player1 | |
distance = bullet.pos - target.pos | |
if v.mag(distance) < Game.flak_crit_distance: | |
target.hitpoints -= 1 | |
create_explosion(bullet.pos, hit=False) | |
#bullet.age = bullet.max_age | |
bullet.visible = False | |
bullet.delete() | |
ground_here = f(bullet.pos.x, bullet.pos.z) * Game.max_depth | |
if bullet.pos.y <= ground_here: | |
# bullet.age = 1+ bullet.max_age | |
create_explosion(pos=bullet.pos) | |
#bullet.age = bullet.max_age | |
bullet.visible = False | |
bullet.delete() | |
if bullet.age > bullet.max_age: | |
bullet.visible = False | |
bullet.delete() | |
Game.bullet_list = [b for b in Game.bullet_list if b.visible] | |
def update_rings(): | |
for index, r in enumerate(Game.ring_list): | |
if index == Game.ring_index: | |
r.color = v.vector(0,0,1) # blue | |
else: | |
r.color = v.vector(1,1,1) # white | |
def update_flak_barrels(): | |
for b in Game.flak_barrel_list: | |
b.age += Game.dt | |
distance = Game.player1.pos - b.pos | |
b.axis = v.norm(distance) * 3 | |
if b.flak.hitpoints > 0 and v.mag(distance) < Game.flak_range and b.age > b.block_gun_until: | |
create_bullet(b) | |
def update_bombs(): | |
for b in Game.bomb_list: | |
gravity = Game.g * Game.mass_bomb * v.vector(0,-1,0) | |
#print("b.move", b.move, "move:", move) | |
b.move += gravity | |
#b.move += 0.0181 * dt * v.vector(0, -1, 0).norm() | |
b.pos += b.move * Game.dt | |
# --- collision detection bomb -> target -- | |
for target in Game.target_list: | |
distance = b.pos - target.pos | |
if abs(distance.x) < target.size.x / 2: | |
if abs(distance.y) < target.size.y / 2: | |
if abs(distance.z) < target.size.z / 2: | |
# explosion | |
create_explosion(pos=b.pos, hit=True, max_age=7) | |
Game.player1.points += 1 | |
# hud.text = f"points: {player1.points} engine power: {player1.power:.2f}" | |
# update_hud() | |
target.hitpoints -= 10 | |
# b.age = b.max_age # AUSKOMMENTIEREN! | |
b.visible = False | |
b.delete() | |
ground_here = f(b.pos.x, b.pos.z) * Game.max_depth | |
if b.pos.y < ground_here: | |
b.visible = False | |
b.delete() | |
create_explosion(b.pos) | |
#explosion_list.append(create_flash) | |
Game.bomb_list = [b for b in Game.bomb_list if b.visible] | |
def update_explosions(): | |
# explosion animation | |
for e in Game.explosion_list: | |
e.age += Game.dt | |
e.radius = 0.01 + e.age * 1.1 | |
if e.age < e.max_age: | |
white = 0.8 + random.random() * 0.2 | |
if e.hit: | |
e.color = v.vector(white, white, 0) | |
else: | |
e.color = v.vector(white, white, white) | |
else: | |
e.visible = False | |
e.delete() | |
Game.explosion_list = [e for e in Game.explosion_list if e.visible] | |
def update_particles(): | |
# particle movement | |
for p in Game.particle_list: | |
p.age += Game.dt | |
p.move += Game.g * Game.mass_particle * v.vector(0,-1,0) | |
p.pos += p.move * Game.dt | |
if p.pos.y < 0: | |
p.age = p.max_age | |
if p.age >= p.max_age: | |
p.visible = False | |
p.delete() | |
Game.particle_list = [p for p in Game.particle_list if p.visible] | |
def update_tanks(): | |
# tank movement | |
for t in Game.tank_list: | |
if t.hitpoints > 0: | |
old_pos = v.vector(t.pos.x, t.pos.y, t.pos.z) | |
t.pos += t.move * Game.dt | |
bounce = False | |
if t.pos.x < -Game.world: | |
t.pos.x = -Game.world | |
bounce = True | |
new_angle = -t.angle + 180 # bounce direction | |
t.rotate(angle=v.radians(new_angle - t.angle), axis=t.up) | |
t.move = t.axis.norm() * t.power | |
t.angle = new_angle | |
#t.move = v.vector(random.randint(1,20),0,random.randint(-50, 50)).norm() * t.power | |
#t.axis = t.move.norm() | |
if t.pos.x > Game.world: | |
t.pos.x = Game.world | |
bounce = True | |
new_angle = -t.angle + 180 # bounce direction | |
t.rotate(angle=v.radians(new_angle - t.angle), axis=t.up) | |
t.move = t.axis.norm() * t.power | |
t.angle = new_angle | |
if t.pos.z < -Game.world: | |
t.pos.z = -Game.world | |
bounce = True | |
new_angle = -t.angle # bounce direction | |
t.rotate(angle=v.radians(new_angle - t.angle), axis=t.up) | |
t.move = t.axis.norm() * t.power | |
t.angle = new_angle | |
if t.pos.z > Game.world: | |
t.pos.z = Game.world | |
bounce = True | |
new_angle = -t.angle # bounce direction | |
t.rotate(angle=v.radians(new_angle - t.angle), axis=t.up) | |
t.move = t.axis.norm() * t.power | |
t.angle = new_angle | |
# ----- over ground ------ | |
ground_here = f(t.pos.x, t.pos.z) * Game.max_depth | |
#t.hy.y = ground_here | |
t.pos.y = ground_here + t.size.y / 2 | |
# update tank axis | |
if not bounce: | |
t.axis = t.pos - old_pos | |
#return tank_list | |
def slider_dt(s): | |
#print("slider1 is now:", s.value) | |
Game.dt = s.value | |
Game.label_dt.text = f"{Game.dt:.4f}" | |
def slider_lift(s): | |
Game.lift_factor = s.value | |
Game.label_lift.text = f"{Game.lift_factor:.4f}" | |
def slider_ring_center_distance(s): | |
"""how close the player must fly to the center of a ring to proceed to next ring""" | |
Game.ring_center_distance = s.value | |
Game.label_ring_center_distance.text = f"{Game.ring_center_distance:.1f}" | |
def slider_rotation(s): | |
"""how fast the plane rotates around its axis""" | |
Game.rotation = s.value | |
Game.label_rotation.text = f"{Game.rotation:.1f}" | |
def slider_delay(s): | |
"""time delay of the camera flying behind the player """ | |
Game.camera_delay = s.value | |
Game.label_delay.text = f"{Game.camera_delay:.2f}" | |
def create_widgets(): | |
Game.scene1.append_to_title(" keys: engine: 1=full 2=more 3=less 4=off. flight controls: WASDQE gun: Space bomb: Ctrl") | |
Game.scene1.append_to_title(" or use first joystick") | |
Game.scene1.append_to_caption("rotation speed: ") | |
v.slider(bind=slider_rotation, min=1, max=200, step=0.1, value=Game.rotation) | |
Game.label_rotation = v.wtext(text=f"{Game.rotation}") | |
Game.scene1.append_to_caption(Game.label_rotation) | |
Game.scene1.append_to_caption('\n\n') | |
Game.scene1.append_to_caption("camera delay [seconds]:") | |
v.slider(bind=slider_delay, min=0, max=5, step=0.01, value=Game.camera_delay) | |
Game.label_delay = v.wtext(text=f"{Game.camera_delay:.2f}") | |
Game.scene1.append_to_caption(Game.label_delay) | |
Game.scene1.append_to_caption('\n\n') | |
Game.scene1.append_to_caption("ring_center_distance:") | |
v.slider(bind= slider_ring_center_distance, min=0.2, max=15.0, step=0.1, value=Game.ring_center_distance) | |
Game.label_ring_center_distance = v.wtext(text=f"{Game.ring_center_distance:.1f}") | |
Game.scene1.append_to_caption(Game.label_ring_center_distance) | |
Game.scene1.append_to_caption('\n\n') | |
Game.scene1.append_to_caption("dt (delta time) in [seconds]:") | |
v.slider(bind=slider_dt, min=0.0001, max=0.01, step=0.00001, value=Game.dt) | |
Game.label_dt = v.wtext(text=f"{Game.dt:.4f}") | |
Game.scene1.append_to_caption(Game.label_dt) | |
Game.scene1.append_to_caption('\n\n') | |
Game.scene1.append_to_caption("lift_factor (force up vs. force forward):") | |
v.slider(bind=slider_lift, min=0.0, max=200.0, step=0.1, value=Game.lift_factor) | |
Game.label_lift = v.wtext(text=f"{Game.lift_factor:.4f}") | |
Game.scene1.append_to_caption(Game.label_lift) | |
Game.scene1.append_to_caption('\n\n') | |
def main(): | |
# Initialize the joysticks. | |
pygame.init() | |
joystick_count = pygame.joystick.get_count() | |
for i in range(joystick_count): | |
joystick = pygame.joystick.Joystick(i) | |
joystick.init() | |
#joystick = pygame.joystick.Joystick(0) | |
#joystick.init() | |
create_widgets() | |
# horst spielt mit Camera | |
Game.scene1.center= v.vector(0,0,0) | |
#scene1.autoscale=False | |
Game.scene1.camera.pos = v.vector(0,0,-1) | |
Game.player1 = create_player() | |
#Game.scene1.camera.follow(Game.player1) | |
Game.hud = v.label(pixel_pos=True, | |
pos=v.vec(5,15,0), | |
text=f"points: {Game.player1.points}", | |
#hud.text = f"points: {player1.points} engine power: {player1.power:.2f}" | |
color=v.vector(1,1,0), | |
align="left", | |
opacity=0, | |
box=False, | |
) | |
Game.smoke1 = v.simple_sphere(pos=v.vector(0.7,0,1), | |
size=v.vector(0.25,0.25,0.25), | |
color=v.vector(0,1,0), # rechts grün ) | |
make_trail=True, | |
trail_type="points", | |
interval=10, | |
retain=150, | |
trail_color=v.vector(0,1,0), | |
) | |
Game.smoke2 = v.simple_sphere(pos=v.vector(0.7,0,-1), | |
size=v.vector(0.25,0.25,0.25), | |
color=v.vector(1,0,0), # links rot) | |
make_trail=True, | |
trail_type="points", | |
interval=10, | |
retain=150, | |
trail_color=v.vector(1,0,0), | |
) | |
create_world() # put stuff into static_list | |
# -------------- movement ------------- | |
#age = 0 | |
Game.ring_index = 0 | |
Game.my_ring = Game.ring_list[Game.ring_index] | |
Game.disc= v.cylinder(pos=Game.my_ring.pos, axis=Game.my_ring.axis, radius=Game.ring_center_distance/2, length=0.1, color=v.vector(1,0,0)) | |
Game.ring_distance = Game.player1.pos - Game.my_ring.pos | |
a7 = v.attach_arrow(Game.player1, "ring", scale=55, shaftwidth=0.2, color=v.color.blue) | |
#a8 = v.attach_arrow(Game.player1, "axis", scale=100, color=v.color.white) | |
camera_zoom = 1.0 | |
camera_x_angle = 0.0 | |
camera_y_angle = 0.0 | |
camera_change = False | |
while True: | |
v.rate(200) | |
#age += Game.dt | |
#gravity = v.vector(0, -1, 0) * Game.g_player * Game.dt | |
Game.player1.age += Game.dt | |
keys = v.keysdown() | |
# player bewegung | |
# player1.pos += player1.power * dt * player1.axis.norm() | |
fly() # player1 | |
# ------update camera --- | |
# this is the same as follow player1 | |
#Game.scene1.camera.pos = Game.player1.pos + v.norm( | |
# v.vector(Game.player1.axis.x, Game.player1.axis.y, Game.player1.axis.z)) * -9 + v.vector(0, 5, 0) | |
ray = v.norm(Game.player1.axis) * 10 | |
new_pos = Game.player1.pos - ray + v.vector(0,5,0) | |
f_value = f(new_pos.x, new_pos.z) * Game.max_depth | |
height_over_ground = new_pos.y - f_value | |
if height_over_ground < 5: | |
new_pos.y += 5 - height_over_ground | |
Game.scene1.camera.pos = new_pos | |
Game.camera_history.append(new_pos) | |
Game.scene1.camera.pos = Game.camera_history[0] | |
while len(Game.camera_history) > Game.camera_delay / Game.dt: | |
Game.scene1.camera.pos = Game.camera_history.pop(0) | |
caxis = v.norm(Game.player1.pos - Game.scene1.camera.pos) * 10 | |
if camera_x_angle != 0: | |
caxis = v.rotate(caxis, angle=v.radians(camera_x_angle), axis=v.vector(0,1,0)) | |
# ---- too confusing for the human eye ---- | |
#if camera_y_angle != 0: | |
# caxis = v.rotate(caxis, angle=v.radians(camera_y_angle), axis=v.vector(v.cross(caxis, v.vector(0,1,0)))) | |
Game.scene1.camera.pos = Game.player1.pos - caxis | |
Game.scene1.camera.axis = caxis | |
#Game.scene1.camera.pos = new_pos | |
#Game.scene1.camera.axis = v.norm(Game.player1.pos - Game.scene1.camera.pos) * 10 | |
# ---- ring control ----- | |
Game.ring_distance = Game.player1.pos - Game.my_ring.pos | |
if v.mag(Game.ring_distance) < Game.ring_center_distance: | |
if Game.ring_index == len(Game.ring_list) - 1: | |
Game.ring_index = 0 | |
else: | |
Game.ring_index += 1 | |
Game.my_ring = Game.ring_list[Game.ring_index] | |
Game.disc.visible = False | |
Game.disc.delete() | |
Game.disc = v.cylinder(pos=Game.my_ring.pos, axis=Game.my_ring.axis, radius=0.5, length=0.1, color=v.vector(1,0,0)) | |
update_rings() | |
Game.player1.points += 100 | |
# confetti for player | |
for _ in range(100): | |
create_particle(Game.player1.pos) | |
rdiff = Game.my_ring.pos - Game.player1.pos | |
Game.player1.ring = v.norm(rdiff) * 0.05 | |
#print(rdiff, v.mag(rdiff), v.norm(rdiff), v.mag(v.norm(rdiff))) | |
#Game.player1.ring = v.norm(Game.ring_list[Game.ring_index].pos - Game.player1.pos) * 3 | |
update_hud() | |
# --- event handler | |
# k = keysdown() # a list of keys that are down | |
for char in "wasdqe,.": | |
if char in keys: | |
if ('q' in keys or "," in keys) and not ('e' in keys or "." in keys): | |
Game.player1.rotate(angle=v.radians(Game.rotation) * Game.dt, axis=Game.player1.up) | |
# smoke1.axis, smoke2.axis = player1.axis.norm()*0.1, player1.axis.norm()*0.1 | |
if ('e' in keys or "." in keys) and not ('q' in keys or "," in keys): | |
Game.player1.rotate(angle=v.radians(-Game.rotation) * Game.dt, axis=Game.player1.up) | |
if "s" in keys and not "w" in keys: | |
Game.player1.rotate(angle=v.radians(Game.rotation) * Game.dt, | |
axis=v.cross(Game.player1.axis, Game.player1.up)) | |
if "w" in keys and not "s" in keys: | |
Game.player1.rotate(angle=v.radians(-Game.rotation) * Game.dt, | |
axis=v.cross(Game.player1.axis, Game.player1.up)) | |
if "d" in keys and not "a" in keys: | |
Game.player1.rotate(angle=v.radians(Game.rotation) * Game.dt, | |
axis=Game.player1.axis) # axis=v.vector(1, 0, 0), ) | |
if "a" in keys and not "d" in keys: | |
Game.player1.rotate(angle=v.radians(-Game.rotation) * Game.dt, | |
axis=Game.player1.axis) # axis=v.vector(1, 0, 0), ) | |
# whatever rotation, update the somke emitters: | |
Game.smoke1.pos, Game.smoke2.pos = rotate_plane(Game.player1) | |
#smoke1.axis, smoke2.axis = player1.axis.norm() * 0.1, player1.axis.norm() * 0.1 | |
#if "p" in keys: | |
# create_particle(Game.player1.pos) | |
# ---- update sprites ---- | |
update_bullets() | |
update_bombs() | |
update_explosions() | |
update_particles() | |
update_tanks() | |
update_flak_barrels() | |
# ---------- joystick --------- | |
# see joystick module in pygame documentation | |
# ------ necessary! without pygame event.get(), joystick events are not pulled ---- | |
for event in pygame.event.get(): # User did something. | |
if event.type == pygame.QUIT: # If user clicked close. | |
pass # done = True # Flag that we are done so we exit this loop. | |
#elif event.type == pygame.JOYBUTTONDOWN: | |
# print("Joystick button pressed.") | |
#elif event.type == pygame.JOYBUTTONUP: | |
# print("Joystick button released.") | |
if joystick_count > 0: | |
joystick = pygame.joystick.Joystick(0) | |
else: | |
joystick = None | |
if " " in keys or (joystick is not None and joystick.get_button(5)): | |
# ---------fire forward gun ---------- | |
if Game.player1.age > Game.player1.block_gun_until: | |
create_bullet(shooter=Game.player1, ) | |
if "ctrl" in keys or (joystick is not None and joystick.get_button(4)): | |
# -------- drop bomb -------------- | |
if Game.player1.age > Game.player1.block_bomb_until: | |
create_bomb(shooter=Game.player1) | |
#print("bomb released") | |
#else: | |
#print("no bomb") | |
if "1" in keys or (joystick is not None and joystick.get_button(0)): | |
Game.player1.power = Game.max_power | |
elif "2" in keys or (joystick is not None and joystick.get_axis(1) < -0.1): | |
Game.player1.power += 0.01 | |
Game.player1.power = min(Game.max_power, Game.player1.power) | |
elif "3" in keys or (joystick is not None and joystick.get_axis(1) > 0.1): | |
Game.player1.power -= 0.01 | |
Game.player1.power = max(Game.min_power, Game.player1.power) | |
elif "4" in keys: | |
Game.player1.power = 0 | |
if "c" in keys or (joystick and joystick.get_button(1)): | |
# --- reset camera --- | |
camera_zoom = 1.0 | |
camera_x_angle = 0.0 | |
camera_y_angle = 0.0 | |
if joystick is not None: | |
# flight control | |
if joystick.get_axis(0) != 0 or joystick.get_axis(2) != 0 or joystick.get_axis(3) != 0: | |
# get_axis(<number of axis>) is a float value from -1 to +1, 0 at neutral position | |
if joystick.get_axis(0) != 0: | |
# --------- joystick rudder (yaw) left/right ---------------- | |
Game.player1.rotate(angle=v.radians(Game.rotation * -joystick.get_axis(0)) * Game.dt, | |
axis=Game.player1.up) | |
if joystick.get_axis(2) != 0: | |
# -------- joystick roll left/right ------------------- | |
Game.player1.rotate(angle=v.radians(Game.rotation * joystick.get_axis(2)) * Game.dt, | |
axis=Game.player1.axis) # axis=v.vector(1, 0, 0), ) | |
if joystick.get_axis(3) != 0: | |
# -------- joystick pitch up/down ------------------- | |
# get_axis(3) is a float value from -1 to +1, 0 at neutral position | |
Game.player1.rotate(angle=v.radians(Game.rotation * joystick.get_axis(3)) * Game.dt, | |
axis=v.cross(Game.player1.axis, Game.player1.up)) | |
# in any rotation event, update the smoke emitters position: | |
Game.smoke1.pos, Game.smoke2.pos = rotate_plane(Game.player1) | |
# camera control | |
if joystick.get_hat(0)[0] == -1: | |
camera_x_angle -= 0.25 | |
camera_change = True | |
elif joystick.get_hat(0)[0] == 1: | |
camera_x_angle += 0.25 | |
camera_change = True | |
#if joystick.get_hat(0)[1] == -1: | |
# camera_y_angle -= 0.25 | |
# camera_change = True | |
#elif joystick.get_hat(0)[1] == 1: | |
# camera_y_angle += 0.25 | |
# camera_change = True | |
if __name__ == "__main__": | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment