Navigation
indexmenu_n_9999
msort nsort navbar
indexmenu_n_9999
msort nsort navbar
Schiff signifie vaisseau en allemand. Il aurait besoin de plus de travail, mais il est jouable.
pilotez votre(vos) vaisseau(x) 1) au clavier pour les orienter ou les déplacer vers l'avant ou l'arrière. Essayez d'éviter les balles ennemies et les rectangles jaunes flottants. Le dernier vaisseau flottant gagne la partie.
aucun fichier externe nécessire en dehors de python et de pygame
jusqu'à 4 joueurs, en se partageant un clavier.
Vous aurez besoin de Python (2.5.2 ou plus) et de Pygame (1.8.1 ou plus) pour lancer ce jeu.
#!/usr/bin/env python # -*- coding: utf-8 -*- # - - - - - - # example with vector class for my pygamebook # LICENSE: Gnu General Public License (GPL) # includes vec2d class from www.pygame.org # AUTHOR: (from the game, not from the vec2dclass): Horst JENS # email: horst.jens@gmail.com # web: http://www.spielend-programmieren.at # - - - - - - - # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # idee Theo: # schlachtschiff # ölflecken, minen # single mit mehr tasten # peace-modus # 4 Tasten für Schiffsteuerung, 2 Tasten für Geschützsturm-Steuerung # Items # bonus wenn mehrere Items der selben ARt (Laser, Gescütz etc) aufgesammelt werden -> Upgrades # Item in Fässern, Fässer muss man zerschiessen ( viele Hitpoints) #FIXME: seit pygame.clock-reparatur alles zu schnell ? #FIXME: tank.reload ist derzeit sinnlos #FIXME: bar vom AI Schiff hinkt nach #FIXME: rotation ordentlich machen, ohne -90° und *-1 #FIXME: self.rect.center - oldcenter in Ordnung bringen #FIXME: Modus sinnvoll machen (derzeit nur space sinnvoll) #FIXME: spacemove und newmoving vereinheitlichen #FIXME: division by Zero kapieren #FIXME: myfont eine globale Variable oder Konstante machen (im Sprite Text) #Fixme: öltropfen spawnen zu sehr/dauernd nach Explosion... nicht-spawn-zeit einbauen ? #TODO: AI-Schiff fährt immer in die Mitte der 4 Spieler...4 Viereck hat nicht unbedingt einen exakten Mittelpunkt #TODO: AI-Schiff Masse (soll nicht so leicht aus der Bahn schiessbar sein) #TODO: AI-Schiff drehen #TODO: braunes AI Schiff ruckelt #TODO: recalc raushaun #TODO: tracer code entfernen oder Bugwellensystem / Blasen #TODO: braunes Schiff: schönere Form, drehung, Antrieb, schüsse #TODO: 4 Player / Bots / AI ! #TODO: verstehen: wird ein pos-Vektor als positionsargument übergeben wandert das ding mit (siehe victory) #TODO: GUI oder config #TODO: Reibung, #TODO: optional sich in die Kurve legen (x-schrumpfen) bei rotation-speed<>0 #TODO: Wind #TODO: Feuer, Riffe oder gefährlicher Rand #TODO: Segelschiffe, schiessen seitlich, eventuell Buggeschütz, schwaches Heckgeschütz(e) #TODO: Rammen (Rammwinkel) #TODO: mehr Segelschiff-sim #TODO: Vektoren schöner machen, mit Pfeilspitzen oder Dreiecke #TODO: wenn ölfleck getroffen, schneller / grösser / driften #done: AI-Schiff hat 3 Kreise (Geschütztürme) #done: schussweite (flytime) verringert. #done: patrol oil rausgehaut. ölflecken nur noch dann wenn ein schiff abgeschossen wird (inkl. grosses AI schiff) #done: patrol oil spawnt nur im eck und schrumpft nicht #done: schwarzes AI Schiff verschwindet manchmal #done: stossen 2 Ölflecken längere Zeit zusammen dann "kalben" Sie einen baby-Ölfleck der ins Spielfeld schwimmt und bei Kollision mit Player explodiert. #done: AI-Schiffe kommen auch vom Zentrum. Sind selbst Feuerempfindlich- #done: gelbe Vektoren für Feuer, schwarze Vektoren für AI Schiff #done: schwarze statt braun, violett statt schwarz. #done: Ölflecken patrollieren am Rand, spawnen von rand-mitte #done: GhostTank dreht sich nicht ordentlich mit boss mit. #done: regeneration (self.regen) von Tanks #done: Schüsse werden kleiner, mehr damage wenn Schüsse gross sind, Tank hat flytime (für Schüsse) #done: cooler Bug am Anfang, Schiffe schiessen am Start #done: Spiel erkennt nicht Game-Over Situation #done: hitratio - division by zero bug gelöst #done: pygame <1.8 versionsabfrage, sollte jetzt auch mit pygame 1.7 laufen #done: Tastaturkürzel sinnvoller (links/rechts), auf mac/netbook testen. Vorschlag: player1: wasd, player2: ijkl oder cursor #done: 4 Player ! #done: feuervektorliste, gegnervektorliste #done: Mausvecktor und Positionsvektor mit variabler Länge #done: Vektorenkreise schön an screenrectseiten ausrichten (Blocksatz) #done: Vektoren wachsen aus kreis raus (bei ship-coll) #done: seltsamer zoom-fehler debugt (textsize erhöht anstatt rotozoom bei text verwendet) #done: Text-classe die schön zoomt und davon abgeleitete hitpointtext mit hitpoint-update #done: hitpointtext machen #done: gelber Damagetext bei Ölflecken (danger) #done: Vectorsprite holt sich koordinaten von bosssprite (Tank) #done: Victory und Looser Text, vorbereitet für mehr als 2 Spieler #done: Ölflecken "fressen" Bälle #done: 4 Ölflecken, am Rand #done: player2 startet rechts unten #done: finale Explosion #done: 2. Vektorspirte mehr nach rechts #done: unglieche tick-zeit..kugeln fliegen unterschiedlich schnell (?) #done: schiffe stoppen total bei zusammenstoss #done: schüsse bremsen (gegenvektor), nicht nur verschieben der Position #done: schwimmendes Feuer (sehr primitv) #done: hitpoints-balken, trefferanzeige #done: Kugeln haben Farbe von Bosssprite #done: keine Schmutzflecken mehr. Vorher: entstehen bei speed und schiessen. #done: ball und schuss #done: screen und screenrect #done: move-vektor #done: Forcevektor #done: Mausvektor #done: brems-steuerungslichter #done: speedlimit #done: modus umschalten mit m #done: time-based movement #done: 2 Tracer Linien von den Eckpunkten, wie Kondensstreifen from __future__ import division import operator # für vec2d import math # für vec2d # für mich import pygame import random random.seed() # init random generator with time or other random value #import vec2d class vec2d(object): """2d vector class, supports vector and scalar operators, and also provides a bunch of high level functions """ __slots__ = ['x', 'y'] def __init__(self, x_or_pair, y = None): if y == None: self.x = x_or_pair[0] self.y = x_or_pair[1] else: self.x = x_or_pair self.y = y def __len__(self): return 2 def __getitem__(self, key): if key == 0: return self.x elif key == 1: return self.y else: raise IndexError("Invalid subscript "+str(key)+" to vec2d") def __setitem__(self, key, value): if key == 0: self.x = value elif key == 1: self.y = value else: raise IndexError("Invalid subscript "+str(key)+" to vec2d") # String representaion (for debugging) def __repr__(self): return 'vec2d(%s, %s)' % (self.x, self.y) # Comparison def __eq__(self, other): if hasattr(other, "__getitem__") and len(other) == 2: return self.x == other[0] and self.y == other[1] else: return False def __ne__(self, other): if hasattr(other, "__getitem__") and len(other) == 2: return self.x != other[0] or self.y != other[1] else: return True def __nonzero__(self): return self.x or self.y # Generic operator handlers def _o2(self, other, f): "Any two-operator operation where the left operand is a vec2d" if isinstance(other, vec2d): return vec2d(f(self.x, other.x), f(self.y, other.y)) elif (hasattr(other, "__getitem__")): return vec2d(f(self.x, other[0]), f(self.y, other[1])) else: return vec2d(f(self.x, other), f(self.y, other)) def _r_o2(self, other, f): "Any two-operator operation where the right operand is a vec2d" if (hasattr(other, "__getitem__")): return vec2d(f(other[0], self.x), f(other[1], self.y)) else: return vec2d(f(other, self.x), f(other, self.y)) def _io(self, other, f): "inplace operator" if (hasattr(other, "__getitem__")): self.x = f(self.x, other[0]) self.y = f(self.y, other[1]) else: self.x = f(self.x, other) self.y = f(self.y, other) return self # Addition def __add__(self, other): if isinstance(other, vec2d): return vec2d(self.x + other.x, self.y + other.y) elif hasattr(other, "__getitem__"): return vec2d(self.x + other[0], self.y + other[1]) else: return vec2d(self.x + other, self.y + other) __radd__ = __add__ def __iadd__(self, other): if isinstance(other, vec2d): self.x += other.x self.y += other.y elif hasattr(other, "__getitem__"): self.x += other[0] self.y += other[1] else: self.x += other self.y += other return self # Subtraction def __sub__(self, other): if isinstance(other, vec2d): return vec2d(self.x - other.x, self.y - other.y) elif (hasattr(other, "__getitem__")): return vec2d(self.x - other[0], self.y - other[1]) else: return vec2d(self.x - other, self.y - other) def __rsub__(self, other): if isinstance(other, vec2d): return vec2d(other.x - self.x, other.y - self.y) if (hasattr(other, "__getitem__")): return vec2d(other[0] - self.x, other[1] - self.y) else: return vec2d(other - self.x, other - self.y) def __isub__(self, other): if isinstance(other, vec2d): self.x -= other.x self.y -= other.y elif (hasattr(other, "__getitem__")): self.x -= other[0] self.y -= other[1] else: self.x -= other self.y -= other return self # Multiplication def __mul__(self, other): if isinstance(other, vec2d): return vec2d(self.x*other.x, self.y*other.y) if (hasattr(other, "__getitem__")): return vec2d(self.x*other[0], self.y*other[1]) else: return vec2d(self.x*other, self.y*other) __rmul__ = __mul__ def __imul__(self, other): if isinstance(other, vec2d): self.x *= other.x self.y *= other.y elif (hasattr(other, "__getitem__")): self.x *= other[0] self.y *= other[1] else: self.x *= other self.y *= other return self # Division def __div__(self, other): return self._o2(other, operator.div) def __rdiv__(self, other): return self._r_o2(other, operator.div) def __idiv__(self, other): return self._io(other, operator.div) def __floordiv__(self, other): return self._o2(other, operator.floordiv) def __rfloordiv__(self, other): return self._r_o2(other, operator.floordiv) def __ifloordiv__(self, other): return self._io(other, operator.floordiv) def __truediv__(self, other): return self._o2(other, operator.truediv) def __rtruediv__(self, other): return self._r_o2(other, operator.truediv) def __itruediv__(self, other): return self._io(other, operator.floordiv) # Modulo def __mod__(self, other): return self._o2(other, operator.mod) def __rmod__(self, other): return self._r_o2(other, operator.mod) def __divmod__(self, other): return self._o2(other, operator.divmod) def __rdivmod__(self, other): return self._r_o2(other, operator.divmod) # Exponentation def __pow__(self, other): return self._o2(other, operator.pow) def __rpow__(self, other): return self._r_o2(other, operator.pow) # Bitwise operators def __lshift__(self, other): return self._o2(other, operator.lshift) def __rlshift__(self, other): return self._r_o2(other, operator.lshift) def __rshift__(self, other): return self._o2(other, operator.rshift) def __rrshift__(self, other): return self._r_o2(other, operator.rshift) def __and__(self, other): return self._o2(other, operator.and_) __rand__ = __and__ def __or__(self, other): return self._o2(other, operator.or_) __ror__ = __or__ def __xor__(self, other): return self._o2(other, operator.xor) __rxor__ = __xor__ # Unary operations def __neg__(self): return vec2d(operator.neg(self.x), operator.neg(self.y)) def __pos__(self): return vec2d(operator.pos(self.x), operator.pos(self.y)) def __abs__(self): return vec2d(abs(self.x), abs(self.y)) def __invert__(self): return vec2d(-self.x, -self.y) # vectory functions def get_length_sqrd(self): return self.x**2 + self.y**2 def get_length(self): return math.sqrt(self.x**2 + self.y**2) def __setlength(self, value): length = self.get_length() if length == 0: pass # do nothing else: self.x *= value/length self.y *= value/length length = property(get_length, __setlength, None, "gets or sets the magnitude of the vector") def rotate(self, angle_degrees): radians = math.radians(angle_degrees) cos = math.cos(radians) sin = math.sin(radians) x = self.x*cos - self.y*sin y = self.x*sin + self.y*cos self.x = x self.y = y def rotated(self, angle_degrees): radians = math.radians(angle_degrees) cos = math.cos(radians) sin = math.sin(radians) x = self.x*cos - self.y*sin y = self.x*sin + self.y*cos return vec2d(x, y) def get_angle(self): if (self.get_length_sqrd() == 0): return 0 return math.degrees(math.atan2(self.y, self.x)) def __setangle(self, angle_degrees): self.x = self.length self.y = 0 self.rotate(angle_degrees) angle = property(get_angle, __setangle, None, "gets or sets the angle of a vector") def get_angle_between(self, other): cross = self.x*other[1] - self.y*other[0] dot = self.x*other[0] + self.y*other[1] return math.degrees(math.atan2(cross, dot)) def normalized(self): length = self.length if length != 0: return self/length return vec2d(self) def normalize_return_length(self): length = self.length if length != 0: self.x /= length self.y /= length return length def perpendicular(self): return vec2d(-self.y, self.x) def perpendicular_normal(self): length = self.length if length != 0: return vec2d(-self.y/length, self.x/length) return vec2d(self) def dot(self, other): return float(self.x*other[0] + self.y*other[1]) def get_distance(self, other): return math.sqrt((self.x - other[0])**2 + (self.y - other[1])**2) def get_dist_sqrd(self, other): return (self.x - other[0])**2 + (self.y - other[1])**2 def projection(self, other): other_length_sqrd = other[0]*other[0] + other[1]*other[1] projected_length_times_other_length = self.dot(other) return other*(projected_length_times_other_length/other_length_sqrd) def cross(self, other): return self.x*other[1] - self.y*other[0] def interpolate_to(self, other, range): return vec2d(self.x + (other[0] - self.x)*range, self.y + (other[1] - self.y)*range) def convert_to_basis(self, x_vector, y_vector): return vec2d(self.dot(x_vector)/x_vector.get_length_sqrd(), self.dot(y_vector)/y_vector.get_length_sqrd()) def __getstate__(self): return [self.x, self.y] def __setstate__(self, dict): self.x, self.y = dict # --------------------------- # start class Tank(pygame.sprite.Sprite): def __init__(self, screenrect, id="player1", mass=100.0): pygame.sprite.Sprite.__init__(self) #, color=(0,255,0) , pos=(100.0,100.0) self.screenrect = screenrect #self.mass = mass # how heavy the ship is self.mass = 100 self.geist = False # i am not a ghost self.friction = 0.9 # 0.9 reduce speed for 10% each second if id == "player1": self.vc = (160,200) self.pos = vec2d(160,200) self.rotating=-30.0 # heading west self.color = (255,64,64) self.color2 = (255,0,128) self.color3 = (255,128,0) self.l = pygame.K_a self.r = pygame.K_d self.u = pygame.K_w self.d = pygame.K_s elif id == "player2": #self.rotating = 0.0 self.vc = (screenrect.width - 160, 200) self.pos = vec2d(screenrect.width - 160, 200) self.rotating=-150.0 # heading west self.color = (64,64,255) self.color2 = (0,128,255) self.color3 = (128,0,255) self.l = pygame.K_LEFT self.r = pygame.K_RIGHT self.u = pygame.K_UP self.d = pygame.K_DOWN elif id=="player3": self.vc = (160, screenrect.height - 200) self.pos = vec2d(160, screenrect.height - 200) self.rotating= 30.0 # heading west self.color = (64,255,64) self.color2 = (0,255,128) self.color3 = (128,255,0) self.l = pygame.K_j self.r = pygame.K_l self.u = pygame.K_i self.d = pygame.K_k elif id=="player4": self.vc = (screenrect.width - 160, screenrect.height - 200) self.pos = vec2d(screenrect.width - 160, screenrect.height - 200) self.rotating= 150.0 # heading west self.color = (255,64,255) #64x3 self.color2 = (32,64,0) self.color3 = (10,64,32) self.l = pygame.K_KP4 self.r = pygame.K_KP6 self.u = pygame.K_KP8 # or KP8 self.d = pygame.K_KP5 self.shotby = {} self.shotby["player1"] = 0 self.shotby["player2"] = 0 self.shotby["player3"] = 0 self.shotby["player4"] = 0 self.shotby["danger"] = 0 self.shotbysomebody = 0 self.wrap = True # wrap-around world self.force = 0 self.regen = 1 # regenarte hitpoints per full second #--- reloading and ammo self.flytime = 2.5 #1.0 # 5.0 seconds ... how long a shot fly self.reloading = 0.1 # tank can not fire while relaoding -------- BUG !!!! ----- self.reloadingtime = 0.3 # seconds needed to reload, 0.0 means automatic fire self.ammowrap = 1 # how many time the ammo will wrap around world edge self.moving = vec2d(0.0,0.0) self.image1 = pygame.Surface((50,50)) self.image1.fill((255,255,255)) # fill with white self.image1.set_colorkey((255,255,255)) # make white transparent pygame.draw.rect(self.image1 , (10,10,10), (0,0,50,8)) pygame.draw.rect(self.image1, (10,10,10), (0,42,50,50)) self.p1 = (-25.0,-25.0) # middle is 25,25 self.p2 = (-25.0, 25.0) # middle is 25,25 pygame.draw.polygon(self.image1, (64,64,64), [(5,10),(5,40),(50,25)],0) pygame.draw.circle(self.image1, self.color,(25,25),16,0) # 0 füllt den Kreis self.image1.convert_alpha() self.image = self.image1.copy() # copy to not destroy image1 self.rect = self.image.get_rect() self.rect.center = (round(self.pos.x,0),round(self.pos.y,0)) self.limit = 100 # the speed limit # --------------------- ausprobieren self.rotspeed = 0.0 self.maxrotspeed =300 # maximum turnspeed self.rotdelta = 30 # um wieviel gedreht wird self.forcedelta = 5 # self.oldcenter = (0,0) self.oldcenter2 = (0,0) self.oldrot = 0 self.spacemove= vec2d(0,0) self.newmoving = vec2d(0,0) self.cm = 0.0 # angle to mouse self.cmd = 0.0 # distance to mouse self.showvector = True self.modus = "space" self.speedflag = False self.showtext = False self.drawTracer = False self.id= id self.hitpoints = 500.0 # float division ! # 500.0 self.hitpointsfull = 500.0 # 500.0 self.peaceful = False self.hitradius = 20.0 #self.damagemax = 1 # how much damage a bullet in the center does (20) # damagemax can be higher by 5 because it is difficult to # teleport a bullet into the center #self.damagemin = 1 # how much damage a bullet on the edge does self.offset = 15 # if set to 0 tank can complete disappear behind # screen edge bevor wrap-around on other site # a offset > 0 spoil that, so that a bit of the tank # should be always visible #self.shotby = None self.shots = 0 # how many balls this tank shoots in his lifetime self.hits = 0 # how many times this thank hits an enemy in his lifetime self.age = 0.0 self.ageseconds = 0 self.alive = True def fire(self): """check if firing is allowed, return True if yes and set the reloadingtime""" if self.peaceful: return False elif self.reloading > 0: return False # Tank is still reloading elif not self.screenrect.collidepoint(self.rect.center): # firing not allowed if Tank center out of screenrect return False else: self.reloading = self.reloadingtime # now the weapon must be reloaded for some time self.shots += 1 return True def update(self, tick_seconds): """tick is the time passed since last frame in seconds""" #save old position self.age += tick_seconds # Tank get older if self.age - self.ageseconds > 1: # a full second survived, time for regeneration self.ageseconds = int(self.age) self.hitpoints += self.regen # heals each full second self.rect = self.image.get_rect() self.oldcenter = self.rect.center # from the image, only for rotating # check reloading time,check if ready to fire again if self.reloading: # <>0..True, 0..False self.reloading -= tick_seconds if self.reloading < 0: self.reloading = 0 # image selector / rotation / speed lights painting self.image = self.image1.copy() if self.rotspeed < 0: #self.image = self.image2 pygame.draw.rect(self.image, (255,0,0), (0,0,8,8)) pygame.draw.rect(self.image, (255,0,0), (42,42,50,50)) elif self.rotspeed > 0: pygame.draw.rect(self.image, (255,0,0), (0,42,8,50)) pygame.draw.rect(self.image, (255,0,0), (42,0,50,8)) if self.force > 0: pygame.draw.rect(self.image, (255,0,0), (0,10,5,30)) elif self.force < 0: pygame.draw.rect(self.image, (255,0,0), (45,10,50,30)) #--- rotate the sprite self.rot(self.image) #--- calculate new position self.rect.center = (round(self.pos.x,0), round(self.pos.y,0)) #self.oldcenter2 = self.rect.center # save for drawing #--- render mousevector # FIXME...ugly ! c = vec2d(self.rect.center) # vector to center on screen m = vec2d(pygame.mouse.get_pos()) #vector to mousepos on screen cm = m - c # vector from sprite-center to mousepos self.cm = cm.angle self.cmd = cm.length cm.length = 16 # shrink length to radius of sprite circle # calulate the new middle of the rotated sprite nm = vec2d(self.image.get_rect().width/2,self.image.get_rect().height/2) cm += nm # correction because sprite is rotated, middle point moves pygame.draw.line(self.image, (0,0,0), (nm.x,nm.y), (int(cm.x), int(cm.y)),1) # more precise keyboard event handler pressed_keys = pygame.key.get_pressed() if pressed_keys[self.l]: self.rotspeed += self.rotdelta if pressed_keys[self.r]: self.rotspeed -= self.rotdelta if pressed_keys[self.u]: self.force += self.forcedelta if pressed_keys[self.d]: self.force -= self.forcedelta # halt rotation when not-auto if self.modus != "auto": if (not pressed_keys[self.l] and not pressed_keys[self.r]): self.rotspeed = 0 # stop rotation if (not pressed_keys[self.u] and not pressed_keys[self.d]): self.force = 0 # stop moving #limit to limit, maxrotspeed if self.rotspeed > self.maxrotspeed: self.rotspeed = self.maxrotspeed if self.rotspeed < -self.maxrotspeed: self.rotspeed = -self.maxrotspeed if self.force >= self.limit: self.force = self.limit self.speedflag = True elif self.force <= -self.limit: self.force = -self.limit self.speedflag = True else: self.speedflag = False #reset rotation on 360 Degree if self.rotating < -360: self.rotating += 360 if self.rotating > 360: self.rotating -= 360 # time-based rotation self.rotating += self.rotspeed * tick_seconds #FIXME: das geht sicher einfacher auch # simple forward movement if self.modus=="space": if self.force!=0: if self.rotating != 0: dazu = vec2d(self.force, 0) dazu.rotate(-self.rotating) self.spacemove += dazu else: self.spacemove += vec2d(self.force,0) # check speed limit if self.spacemove.length >= self.limit: self.spacemove.length = self.limit self.speedflag = True else: self.speedflag = False #self.pos += self.spacemove * tick_seconds self.newmoving = self.spacemove # komaptibel machen ? else: if self.force!= 0: self.newmoving = vec2d(self.force,0) if self.rotating != 0: self.newmoving.rotate(-self.rotating) #self.pos += self.newmoving * tick_seconds self.newmoving *= self.friction ** tick_seconds # Reibung Leo self.pos += self.newmoving * tick_seconds if self.wrap: # wrap-around world #if self.pos.x + self.rect.width/2 < 0: # #self.pos.x = self.screenrect.get_width() + self.rect.width/2 # self.pos.x = self.screenrect.width + self.rect.width/2 - self.offset #if self.pos.x - self.rect.width/2 > self.screenrect.width: # self.pos.x = 0 - self.rect.width/2 + self.offset #if self.pos.y + self.rect.height/2 < 0: # self.pos.y = self.screenrect.height + self.rect.height/2 - self.offset #if self.pos.y - self.rect.height/2 > self.screenrect.height: # self.pos.y = 0 - self.rect.height/2 + self.offset #--------- wrap at self.rect.center, TankGhost will care about the Rest if self.pos.x < 0: self.pos.x = self.screenrect.width if self.pos.x > self.screenrect.width: self.pos.x = 0 if self.pos.y < 0: self.pos.y = self.screenrect.height if self.pos.y > self.screenrect.height: self.pos.y = 0 else: #no wrap-around , stop on end of screen if self.pos.x < 0: self.pos.x = 0 if self.pos.x > self.screenrect.width: self.pos.x = self.screenrect.width if self.pos.y < 0: self.pos.y = 0 if self.pos.y > self.screenrect.height: self.pos.y = self.screenrect.height #draw tracer ? if self.drawTracer: self.tracer() #else: # self.dirtyrect=(0,0,0,0) def tracer(self): #test if tracer is not too long (because world-wrap) nc = vec2d(self.rect.center) oc = vec2d(self.oldcenter2) if (nc - oc).length < self.rect.width: pygame.draw.line(background, self.color,self.oldcenter2, self.rect.center,2) nc1 = vec2d(self.p1) nc2 = vec2d(self.p2) oc1 = vec2d(self.p1) oc2 = vec2d(self.p2) # rotate the tracer-vectors vec2d.rotate(nc1,-self.rotating) vec2d.rotate(nc2,-self.rotating) vec2d.rotate(oc1,-self.rotating) vec2d.rotate(oc2,-self.rotating) #"----adding rect center----" nc1 += nc nc2 += nc #"------ adding oldcenter ------" oc1 += oc oc2 += oc # draw the lines from old to new pygame.draw.line(background, self.color2, (oc1.x, oc1.y),(nc1.x,nc1.y),1) pygame.draw.line(background, self.color3, (oc2.x, oc2.y),(nc2.x,nc2.y),1) #self.dirtyrect =(int(min(nc1.x, nc2.x, oc1.x, oc2.x, oc.x, nc.x))-1, # int(min(nc1.y, nc2.y, oc1.y, oc2.y, oc.y, nc.y))-1, # int(max(nc1.x, nc2.x, oc1.x, oc2.x, oc.x, nc.x))+1, # int(max(nc1.y, nc2.y, oc1.y, oc2.y, oc.y, nc.y))+1) self.oldcenter2 = self.rect.center # save old tracerposition def rot(self, image): self.image = pygame.transform.rotate(image, self.rotating) self.rect.center = self.oldcenter def kill(self): self.alive = False pygame.sprite.Sprite.kill(self) class TankGhost(Tank): def __init__(self, boss, id): """ id = N, S , W, E""" Tank.__init__(self, boss.screenrect, boss.id, mass=100.0) self.boss = boss self.id = id self.color = boss.color self.peaceful = True # Ghost does not fire self.geist = True # i am a ghost def update(self, tick_seconds): # is boss dead ? if self.boss.alive == False: pygame.sprite.Sprite.kill(self) #TankGhost.kill(self) self.image = self.boss.image self.rect = self.image.get_rect() if self.id == "N": self.rect.center = (self.boss.rect.centerx, self.boss.rect.centery - self.boss.screenrect.height) elif self.id == "S": self.rect.center = (self.boss.rect.centerx, self.boss.rect.centery + self.boss.screenrect.height) elif self.id == "W": self.rect.center = (self.boss.rect.centerx - self.boss.screenrect.width , self.boss.rect.centery) elif self.id =="E": self.rect.center = (self.boss.rect.centerx + self.boss.screenrect.width , self.boss.rect.centery) class Bar(pygame.sprite.Sprite): """ a health-bar floating above each player""" def __init__(self, boss, vectorbar=False, color=(0,255,0)): pygame.sprite.Sprite.__init__(self) self.vectorbar = vectorbar self.boss = boss if self.vectorbar: self.long = 300 # vectorsprite circle radius * 2 else: self.long = boss.rect.width self.longold = self.long self.percent = 1.0 self.percentold = 0.0 self.color = color self.image = pygame.Surface((self.long,5)) def update(self, tick): """tick is the time passed since last frame in seconds""" if self.boss.hitpoints <= 0: self.kill() self.percent = (self.boss.hitpoints / self.boss.hitpointsfull) if not self.vectorbar: self.long = self.boss.rect.width if self.percent != self.percentold or self.longold != self.long: self.image = pygame.Surface((self.long,5)) self.rect = self.image.get_rect() self.image.fill((255,255,255)) # white pygame.draw.rect(self.image,(0,255,0),(0,0, int(self.long*self.percent), 5)) #black rectangle pygame.draw.rect(self.image,(0,0,0),(0,0,self.long,5), 1) self.image.set_colorkey((255,255,255)) self.image.convert_alpha() if self.vectorbar: self.rect.centerx = self.boss.vc[0] self.rect.centery = self.boss.vc[1] - 160 # vectorbar above vectorcircle else: self.rect.centerx = self.boss.rect.centerx self.rect.centery = self.boss.rect.y - 10 self.percentold = self.percent self.longold = self.long class Text(pygame.sprite.Sprite): """a changable text""" def __init__(self, pos, msg="Hello World",color=(5,5,5), maxlifetime=-1.0, textsize=25, vec=vec2d(0,0),msgchange=False, zoom=False): """ negative maxlifetime means stay until Game Over msgchange means the message may change over time pos in format(x,y), will be changed into vec2d in Text__init__""" pygame.sprite.Sprite.__init__(self) #self.static = static #static means text does not disappear self.zoom = zoom self.zoomfactor = 4.0 self.textsize = int(textsize) self.textsize0 = self.textsize self.msgchange = msgchange self.vec = vec self.pos = vec2d(pos) self.msg = msg self.color = color self.recalcimage() self.rect.center = pos self.lifetime = 0 self.maxlifetime = maxlifetime #seconds self.tick = 0.0 # seconds since last frame #self.recalc(self.msg) def update(self, tick): """tick is passed seconds""" self.tick = tick self.lifetime += tick if self.zoom: self.textsize = int(self.textsize0 + self.lifetime * self.zoomfactor) # int instead of round becaouse round makes float and float upset pygame.font self.msgchange = True if self.msgchange: self.recalcimage() if self.vec != vec2d(0,0): self.pos += self.vec * self.tick # self.pos is a vec2d object self.rect.center = (round(self.pos.x,0), round(self.pos.y,0)) if self.maxlifetime > 0 and self.lifetime > self.maxlifetime: self.kill() #def kill(self): # pygame.sprite.Sprite.kill(self) def recalcimage(self): """renders the text to self.image""" self.font = pygame.font.SysFont("None",self.textsize) self.textsurface1 = self.font.render(self.msg, True, self.color) #antialias = False self.image = pygame.Surface((self.textsurface1.get_size())) self.image.fill((255,255,255)) # fill with white self.image.set_colorkey((255,255,255)) # make white transparent #self.image = self.image1.copy() # to save image1 self.image.blit(self.textsurface1,(0,0)) self.rect = self.image.get_rect() self.rect.center = (round(self.pos.x,0), round(self.pos.y,0)) class HitpointText(Text): """ this class inherit from Text class and updated the hitpoints of a given player""" def __init__(self, boss): Text.__init__(self, boss.vc , "dummytext", (0,0,0),-1,20, vec2d(0,0), True, False) self.boss = boss self.pos += vec2d(0,-170) # self.pos is a vec2d object from Text ? def update(self, tick): self.msg = "Hitpoints:"+str(self.boss.hitpoints) Text.update(self, tick) class VectorSprite(pygame.sprite.Sprite): """draws a drawing of the tank in a fixed position including vectors for relative speed, enemy etc.""" def __init__(self, boss): pygame.sprite.Sprite.__init__(self) self.boss = boss #self.startx = startx self.image0 = pygame.Surface((300,300)) # 200,200 self.image0.fill((255,255,255)) # fill with white self.image0.set_colorkey((255,255,255)) # make white transparent self.image0.convert_alpha() self.vc = (int(self.boss.vc[0]),int(self.boss.vc[1])) # Vectorcenter from boss_sprite self.color = self.boss.color # get color from boss # draw polygon, same as Tank, but without colors self.image1 = pygame.Surface((50,50)) self.image1.fill((255,255,255)) # fill with white self.image1.set_colorkey((255,255,255)) # make white transparent pygame.draw.rect(self.image1 , self.color, (0,0,50,8),1) pygame.draw.rect(self.image1 , self.color, (0,42,50,8),1) # small bug pygame.draw.polygon(self.image1, self.color, [(0,10),(0,40),(50,25)],1) pygame.draw.circle(self.image1, self.color,(25,25),16,1) # 0 füllt den Kreis pygame.draw.line(self.image1, self.color,(25,25),(50,25),1) # strich schaut nach rechts self.image1.convert_alpha() self.image = self.image0.copy() # to save image1 self.rect = self.image.get_rect() self.size = 5 self.dangerlist = [] self.enemylist = [] def learn(self, enemy, danger=True): """ learn about one enemy at a time, but not about self""" if danger: self.dangerlist.append(enemy) else: if enemy.color != self.boss.color: self.enemylist.append(enemy) def update(self, tick_seconds): """ update the vectors and rotation of the tank. tick_seconds is only here to get accepted, but i do nothing with it""" #self.dangerlist = [] #self.enemylist = [] if self.boss.showvector: #--- draw vectorsprite with correct rotation self.image = self.image0.copy() self.image2 = self.image1.copy() self.image2 = pygame.transform.rotate(self.image2 , self.boss.rotating) rect = self.image2.get_rect() center2 = rect.center #self.image.blit(self.image2, (100-rect.width/2, 100-rect.height/2)) self.image.blit(self.image2, (150-rect.width/2, 150-rect.height/2)) self.rect.center = self.vc #--- draw big mousevector #cm = vec2d(0,min(150, self.boss.cmd)) # cmd is sprite-mousedistance #cm.rotate(self.boss.cm-90) # self.boss.cm contains the angle from tank to mouse #cm += vec2d(self.vc) #pygame.draw.line(screen, (0,255,255),(self.vc), (cm.x, cm.y),1) # cyan #--- draw force vector f = 1.0 * self.boss.force / self.boss.limit # 1.5 is around the vectorcircle cm = vec2d(0, f*150.0) cm.rotate(-self.boss.rotating-90) cm += vec2d(self.vc) pygame.draw.line(screen, self.boss.color, (self.vc), (round(cm.x,0), round(cm.y,0)),20) #--- draw space vector if self.boss.modus =="space": speed = 1.0 * self.boss.spacemove.length / self.boss.limit s = min(1, speed) if speed > 1: self.size +=1 else: self.size = 5 cm = vec2d(0, s*150.0) cm.rotate(self.boss.spacemove.angle-90) cm += vec2d(self.vc) pygame.draw.line(screen, (255,0,255), (self.vc), (int(cm.x), int(cm.y)),self.size) # pink #--- draw sprite vector cm = vec2d(self.boss.rect.center) - vec2d(self.vc) #diagonal = vec2d(self.vc) - vec2d(self.boss.screenrect.width, self.boss.screenrect.height) #dia = diagonal.length * 1.0 # to get float #cm.length = (cm.length / dia)*100 cm.length = min(cm.length, 150.0) #100 cm+=vec2d(self.vc) pygame.draw.line(screen, (0,0,0), (self.vc), (int(cm.x), int(cm.y)),1) #--- draw dangervector for dang in self.dangerlist: size = 1 cd = dang.pos - self.boss.pos cd.length = min(cd.length, 150.0) if cd.length < 150: size = int(150 - cd.length) cd+=vec2d(self.vc) if dang.type == "oil": col = (255,255,0) else: col = (0,0,0) pygame.draw.line(screen, col, (self.vc), (int(cd.x), int(cd.y)),size) self.dangerlist = [] #--- draw enemyvector for enemy in self.enemylist: size = 1 cd = enemy.pos - self.boss.pos cd.length = min(cd.length, 150.0) if cd.length < 150: size = int(150 - cd.length) cd+=vec2d(self.vc) pygame.draw.line(screen, enemy.color, (self.vc), (int(cd.x), int(cd.y)),size) self.enemylist = [] else: self.rect.center = (-400,-400) # hide vectorsprite out of screenrect class Ball(pygame.sprite.Sprite): def __init__(self, bossSprite, smoke=False, mass=1): pygame.sprite.Sprite.__init__(self) self.boss = bossSprite self.radius = 5 #5 Ball.paintme(self, self.radius) self.pos = vec2d(self.boss.rect.center) self.rect.center = (round(self.pos.x,0), round(self.pos.y,0)) self.moving=vec2d(self.boss.limit * 1.1,0) # speeed of bullet = 110% of max speed of player #self.moving.rotate(self.boss.cm) # shoot to mousepointer self.moving.rotate(-self.boss.rotating) # shoot to direction of Tank/Ship self.moving += self.boss.spacemove # add tank velocity to ball velocity self.massfactor = 0.2 # reduces the impact in relation to a players mass. #.91 a bissl gross self.ammowrap = self.boss.ammowrap # how many times bullet can wrap around screen edge self.age = 0.0 # lifetime of ball since start in seconds self.maxage = self.boss.flytime # ball is killed if he gets older than this time (in seconds) def update(self, tick_seconds): '''tick is time passed in seconds''' self.age += tick_seconds # ball get older if self.age > self.maxage: self.kill() else: factor = self.age / self.maxage # % of oldness of Ball Ball.paintme(self, 1 + self.radius - int(self.radius * factor)) self.pos += self.moving * tick_seconds self.rect.center = (round(self.pos.x,0), round(self.pos.y,0)) if not self.boss.screenrect.collidepoint(self.rect.center): if self.ammowrap > 0: self.ammowrap -=1 # one less time allowed to wrap world if self.pos.x > self.boss.screenrect.width: self.pos.x = 0 if self.pos.x < 0: self.pos.x = self.boss.screenrect.width if self.pos.y > self.boss.screenrect.height: self.pos.y = 0 if self.pos.y < 0: self.pos.y= self.boss.screenrect.height else: self.kill() def paintme(self, radius): self.tempradius = radius self.image = pygame.Surface((radius*2,radius*2)) self.image.fill((255,255,255)) # fill with white self.image.set_colorkey((255,255,255)) # make white transparent pygame.draw.circle( self.image,self.boss.color, (radius,radius), radius , 0) self.image.convert_alpha() self.rect = self.image.get_rect() class Danger(pygame.sprite.Sprite): """ an enemy to all players. can be a floating piece of burning oil that damage players but ignore shooting. or can be an enemy ship.""" oilborder = [0,0,0,0] # n,w,s,o # this is a class variable def __init__(self, screenrect, type="oil", size=40, pos=(0,0)): pygame.sprite.Sprite.__init__(self) self.size = size self.lifetime = 0.0 self.oldsize = size self.screenrect = screenrect self.limit = 500 # absolute speed limit self.type = type # what kind of Danger, an oil or an boat ? self.bar = False # check if i have an hitpoint-bar self.wo = -1 # indicator of border of oil, -1 means free floating #self.pregnant = 0 # spawn a baby danger ? #self.birth = 100 # if self.pregnant reach this value, it will spawn a new baby-danger distance = 30 # distance from screenrect border to oil.rect.center if self.type == "oil": self.vulnerable = False # can be shot down self.damagePlayer = True # can damage player that bumb into it self.color = (255,random.randint(128,255),0) # between yellow and red ? if self.size==40: pass ## big oil, patrol border #self.hitpoints = 100 #self.hitpointsfull = 100 #self.size = 40 #self.min = 50 #self.max = 100 # oil float very slow ## where to spawn oil ? #for side in Danger.oilborder: #if side == min(Danger.oilborder): #wo = Danger.oilborder.index(min(Danger.oilborder)) #self.wo = wo #Danger.oilborder[wo] += 1 #break #if wo == 0: #self.pos = vec2d(self.screenrect.centerx, distance) #self.vec = vec2d(random.randrange(self.min,self.max) * random.choice([-1,1]), 0) #elif wo == 1: #self.pos = vec2d(distance, self.screenrect.centery) #self.vec = vec2d(0, random.randrange(self.min,self.max) * random.choice([-1,1])) #elif wo == 2: #self.pos = vec2d(self.screenrect.centerx, self.screenrect.height - distance) #self.vec = vec2d(random.randrange(self.min,self.max) * random.choice([-1,1]), 0) #elif wo == 3: #self.pos = vec2d(self.screenrect.width - distance, self.screenrect.centery) #self.vec = vec2d(0, random.randrange(self.min,self.max) * random.choice([-1,1])) else: # small oil. self.wo = -1 self.hitpoints = 10 self.hitpointsfull = 10 self.min = 100 self.max = 200 self.pos = vec2d(pos) self.vec = vec2d(random.randrange(self.min, self.max) * random.choice([-1,1]), random.randrange(self.min, self.max) * random.choice([-1,1])) #for all oil: self.image = pygame.Surface((self.size,self.size)) self.damage = 1 # hitpoint loss for player pygame.draw.rect( self.image,self.color, (0,0,self.size,self.size), 0) elif self.type == "boat": self.vulnerable = True self.hitpoints = 100 self.hitpointsfull = 100 self.size = 50 self.damagePlayer = True self.min = 5 # minimal speed self.max = 100 # maximal speed self.pos = vec2d(self.screenrect.centerx, self.screenrect.centery) self.vec = vec2d(random.randrange(self.min,self.max) * random.choice([-1,1]), random.randrange(self.min,self.max) * random.choice([-1,1])) #self.damageBall = True self.heading = self.vec.angle self.vulnerable = True self.color = (100,100,100) # grey #------- self.damage = 10 # damage to player ? self.image = pygame.Surface((200,200)) self.image.fill((255,255,255)) # fill white self.image.set_colorkey((255,255,255)) # make white transparent pygame.draw.polygon(self.image, self.color, [(0,100), (20,70), (190,70), (200,100), (190,130), (20,130) ] , 0) pygame.draw.circle(self.image, (40,100,40), (50,100), 20, 0) pygame.draw.circle(self.image, (40,100,40), (100,100), 20, 0) pygame.draw.rect(self.image, (40,40,100), [120,72,30,58]) pygame.draw.circle(self.image, (40,100,40), (170,100), 20, 0) self.image.convert_alpha() #pygame.transform.flip(self.image, True, False) self.image0 = self.image.copy() # start in screenrect #complete random direction #self.image.convert_alpha() self.rect = self.image.get_rect() self.rect.center= (round(self.pos.x,0), round(self.pos.y,0)) def update(self, tick_seconds): '''tick is time passed in seconds''' self.lifetime+= tick_seconds if self.hitpoints < 0: self.kill() if self.type == "oil": if self.size != self.oldsize: self.image = pygame.Surface((self.size,self.size)) self.rect = self.image.get_rect() self.color = (255,random.randint(128,255),0) # between yellow and red ? pygame.draw.rect( self.image,self.color, (0,0,self.size,self.size), 0) elif self.type == "boat": #heading is actual mouse position #self.vec = vec2d(pygame.mouse.get_pos) - vec2d(self.rect.center) c = vec2d(self.rect.center) # vector to center on screen m = vec2d(pygame.mouse.get_pos()) #vector to mousepos on screen cm = m - c # vector from sprite-center to mousepos #self.cm = cm.angle #self.cmd = cm.length cm.length = min(self.max, cm.length) # not faster than self.max self.vec = cm #rotate boat toward heading #self.oldpos = self.rect.center self.image = pygame.transform.rotate( self.image0, self.vec.angle) #self.rect.center = self.oldpos if self.vec.length > self.limit: self.vec.length = self.limit self.pos += self.vec * tick_seconds grow = False #no wrap-around , stop on end of screen if self.pos.x < 0: #grow = True self.pos.x = 0 # stuck on the left side #if self.wo == 0 or self.wo == 2: #self.vec = vec2d(random.randrange(self.min,self.max), 0) #else: self.vec = vec2d(random.randrange(self.min,self.max), random.randrange(self.min,self.max) * random.choice([-1,1])) if self.pos.x > self.screenrect.width: #grow = True self.pos.x = self.screenrect.width # stuck on the right side #if self.wo == 0 or self.wo == 2: #self.vec = vec2d(random.randrange(self.min,self.max)*-1, 0) #else: self.vec = vec2d(random.randrange(self.min,self.max)*-1, random.randrange(self.min,self.max) * random.choice([-1,1])) if self.pos.y < 0: #grow = True self.pos.y = 0 # stuck on top border #if self.wo == 1 or self.wo == 3: #self.vec = vec2d(0,random.randrange(self.min, self.max)) #else: self.vec = vec2d(random.randrange(self.min,self.max) * random.choice([-1,1]), random.randrange(self.min,self.max) ) if self.pos.y > self.screenrect.height: #grow = True self.pos.y = self.screenrect.height #stuck on bottom #if self.wo == 1 or self.wo == 3: #self.vec = vec2d(0,random.randrange(self.min, self.max)*-1) #else: self.vec = vec2d(random.randrange(self.min,self.max) * random.choice([-1,1]), random.randrange(self.min,self.max) * -1) self.rect.center = (round(self.pos.x,0), round(self.pos.y,0)) #self.oldsize = self.size #if grow and self.wo > -1: #self.size +=1 class Wound(pygame.sprite.Sprite): """ a little explosion marking the 'wound' of a hit""" def __init__(self, pos, size, maxlifetime=0.5, boss_sprite=None): pygame.sprite.Sprite.__init__(self) self.size = int(size) # sometimes, wound comes as float (from tux?) #if self.size < medium: # self.size *=2 self.pos = pos self.maxlifetime = maxlifetime # in seconds self.boss_sprite = boss_sprite self.age = 0 # age in decimal seconds self.frames = 0 #frames in integer self.image = pygame.Surface((size*2, size*2)) self.surface_center = (self.size, self.size) self.rect = self.image.get_rect() self.rect.center = (round(self.pos.x,0),round(self.pos.y,0)) #if self.boss_sprite: # self.dx = self.pos[0] - self.boss_sprite.rect.centerx # self.dy = self.pos[1] - self.boss_sprite.rect.centery self.update(0) # update need the argument tick def update(self, tick_seconds): """ tick_seconds is decimalseconds passed since last frame""" self.age += tick_seconds self.frames +=1 if self.age > self.maxlifetime: #one second at 30 fps self.kill() else: self.rect.center = (round(self.pos.x, 0), round(self.pos.y,0)) pygame.draw.circle(self.image, (255,random.randint(0,255),0), self.surface_center,min(self.size,self.frames), 0) self.image.set_colorkey((0,0,0)) self.image.convert_alpha() #if self.boss_sprite: # self.rect.centerx = self.boss_sprite.rect.centerx + self.dx # self.rect.centery = self.boss_sprite.rect.centery + self.dy #else: # self.rect.center = self.pos def paint(x, y, color): pygame.draw.circle(background, color, (x,y), 150, 1) pygame.draw.line(background, color, (x-160, y) , (x+160,y), 1) pygame.draw.line(background, color, (x,y-160), (x,y+160),1) textsurface = myFont.render(u"0° = 360°", True, color) background.blit(textsurface, (x+50,y-20)) textsurface = myFont.render(u"90°", True, color) background.blit(textsurface, (x-10,y-150)) textsurface = myFont.render(u"180°", True, color) background.blit(textsurface, (x-140,y-20)) textsurface = myFont.render(u"270°", True, color) background.blit(textsurface, (x-10,y+125)) #--- main start -- pygame.init() try: screen=pygame.display.set_mode((0,0)) # (0,0) uses the full screensize except: x = raw_input("enter x resolution of screen:", 800) y = raw_input("enter y resolution of screen:", 600) if int(x) <= 0 or int(y) <= 0: print "bad integer value. defaulting to 800x600" x = 800 y = 600 screen=pygame.display.set_mode((x,y)) screenrect = screen.get_rect() pygame.display.set_caption("press Esc to exit") #--- background background = pygame.Surface(screen.get_size()) #background = background.convert() background.fill((255,255,255)) #fill the background white #a bit of text myFont = pygame.font.SysFont("None",25) #textsurface = myFont.render("Player1: F1=modus, w,as,d,cursor=move, space=shoot", True, (0,0,255)) textsurface0 = myFont.render("pres ESC to Quit", True, (0,0,0)) textsurface1 = myFont.render("Player1: w,a,s,d", True, (0,0,0)) #textsurface2 = myFont.render("Player2: F12=modus, j,i,l,k, Numpad=move, RCTRl,NUM_Enter=shoot", True, (0,0,255)) textsurface2 = myFont.render("Player2: j,i,l,k", True, (0,0,0)) textsurface3 = myFont.render("Player3: cursor-keys", True, (0,0,0)) textsurface4 = myFont.render("Player4: Numpad 4,8,5,6", True, (0,0,0)) #background.blit(textsurface, (20,410)) # blit the textsurface on the backgroundsurface #background.blit(textsurface2, (20, 430)) #background.blit(textsurface3, (20, 450)) # red circle with crosshair paint(160, 200, (255,32,32)) # player1, red, left upper corner paint(screenrect.width - 160, 200, (32,32,255)) # player2, blue right upper corner paint(160, screenrect.height - 200 , (32,255,32)) # player3, green, lower left corner paint(screenrect.width - 160, screenrect.height - 200 , (32,32,32)) # player4, black, lower right corner background.blit(textsurface1, (screenrect.width/2-40,50)) background.blit(textsurface2, (screenrect.width/2-40,70)) background.blit(textsurface3, (screenrect.width/2-40,90)) background.blit(textsurface4, (screenrect.width/2-40,110)) background.blit(textsurface0, (screenrect.width/2-40,130)) backgroundnew = background.copy() screen.blit(background, (0,0)) # blit the backgroundsurface on the screen #--- sprite groups vectorgroup = pygame.sprite.Group() ballgroup = pygame.sprite.Group() tankgroup = pygame.sprite.Group() bargroup = pygame.sprite.Group() dangergroup = pygame.sprite.Group() woundgroup = pygame.sprite.Group() textgroup = pygame.sprite.Group() newgroup = pygame.sprite.Group() # create some sprites #--- player1 player1 = Tank(screenrect,"player1") #red player1vector = VectorSprite(player1) textgroup.add( HitpointText(player1) ) #--- player2 player2 = Tank(screenrect,"player2") # blue player2vector = VectorSprite(player2) textgroup.add( HitpointText(player2) ) #-- player3 player3 = Tank(screenrect, "player3") # green player3vector = VectorSprite(player3) textgroup.add( HitpointText(player3)) #-- player4 player4 = Tank(screenrect, "player4") # black player4vector = VectorSprite(player4) textgroup.add( HitpointText(player4)) # put the sprites in the correct group bargroup.add(Bar(player1), Bar(player1, True), Bar(player2), Bar(player2, True), Bar(player3), Bar(player3, True), Bar(player4), Bar(player4, True) ) tankgroup.add(player1, TankGhost(player1, "N"), TankGhost(player1, "S"), TankGhost(player1, "W"), TankGhost(player1, "E"), player2, TankGhost(player2, "N"), TankGhost(player2, "S"), TankGhost(player2, "W"), TankGhost(player2, "E"), player3, TankGhost(player3, "N"), TankGhost(player3, "S"), TankGhost(player3, "W"), TankGhost(player3, "E"), player4, TankGhost(player4, "N"), TankGhost(player4, "S"), TankGhost(player4, "W"), TankGhost(player4, "E")) #stuffgroup.add(player1text, player1speedtext, player1vector, player2text, player2speedtext, player2vector) vectorgroup.add(player1vector, player2vector, player3vector, player4vector) #dangergroup.add( Danger(screenrect, "oil"), # Danger(screenrect, "oil"), # Danger(screenrect, "oil"), # Danger(screenrect, "oil"), # Danger(screenrect, "boat")) dangergroup.add( Danger(screenrect, "boat") ) # hitpoints for boat for dang in dangergroup: #if dang.vulnerable and not dang.bar: if (dang.bar == False) and (dang.type != "oil"): bargroup.add(Bar(dang)) dang.bar = True #allgroup = pygame.sprite.LayeredUpdates(playervector, playertext, speedtext, player, ballgroup) if pygame.ver < "1.8.1": allgroup = pygame.sprite.LayeredUpdates(vectorgroup, dangergroup, woundgroup, textgroup, bargroup, ballgroup, tankgroup) else: allgroup = pygame.sprite.Group(vectorgroup, dangergroup, woundgroup, textgroup, bargroup, ballgroup, tankgroup) #--- loop prepare --- mainloop = True #clock = pygame.time.Clock() fps = 30 #frames per second seconds_played = 0.0 recalc = False # recalculate the sprite groups reset to False finale = False # draw the game-over scene (final explosion etc.) startGameOverMsg = False rank = 4 # decrease at each playerkill. 4 because 4 players at maximum clock = pygame.time.Clock() # create Clock object #--- mainloop ------ while mainloop: tick_time = clock.tick(fps) # milliseconds since last frame tick_seconds = tick_time / 1000.0 # decimal-seconds since last frame seconds_played += tick_seconds # counter, will not be resetted #clock.tick(30) #event handler for event in pygame.event.get(): if event.type == pygame.QUIT: mainloop = False elif event.type == pygame.KEYDOWN: # Toggle keys better with keydown than with pressed_keys #--- Esc quit ------------- if event.key == pygame.K_ESCAPE: mainloop = False #--- clean F5 ------------- if event.key == pygame.K_F5: background = backgroundnew.copy() screen.blit(background, (0,0)) # redraw the background #---tracer F6 ----------------- if event.key == pygame.K_F6: for tank in tankgroup: tank.drawTracer = not tank.drawTracer #--- fire for tank in tankgroup: if tank.fire(): ballgroup.add(Ball(tank)) recalc = True #--- mainloop core ----------- #--- clear the sprites allgroup.clear(screen, background) if recalc: # it is very important that this lines comes AFTER allgroup.clear! # else there will be ugly uncleaned sprites all around # allgroup = pygame.sprite.LayeredUpdates(stuffgroup, woundgroup, textgroup, dangergroup, bargroup, tankgroup, ballgroup) #allgroup = pygame.sprite.LayeredUpdates(vectorgroup, dangergroup, woundgroup, textgroup, bargroup, ballgroup, tankgroup) if newgroup: # any new dangersprites in this group ? for dang in newgroup: dangergroup.add(dang) #newgroup = [] # will be empty at beginning of danger-danger-collision-detection print len(dangergroup) for dang in dangergroup: # add hitbar if missing if (dang.bar == False) and (dang.type != "oil"): bargroup.add(Bar(dang)) dang.bar = True newgroup.empty() # remove all sprites from this group if pygame.ver < "1.8.1": allgroup = pygame.sprite.LayeredUpdates(vectorgroup, dangergroup, woundgroup, textgroup, bargroup, ballgroup, tankgroup) else: allgroup = pygame.sprite.Group(vectorgroup, dangergroup, woundgroup, textgroup, bargroup, ballgroup, tankgroup) recalc = False # reset recalc #--- update all sprites allgroup.update(tick_seconds) #--- feed sprite-position to vectorgroup for vsprite in vectorgroup: for dang in dangergroup: vsprite.learn(dang, True) for tank in tankgroup: vsprite.learn(tank, False) #--- collision detection # ball kills ball:--- removed, because too slow #for ball in ballgroup: # ballgroup2 = ballgroup.copy() # crashgroup = pygame.sprite.spritecollide(ball, ballgroup2, False) # killme = False # for ball2 in crashgroup: # if ball2.boss == ball.boss: # #friendly fire # pass # survive # else: # ball2.kill() # killme = True # if killme: # ball.kill() # --- collision with tank and ball ? for tank in tankgroup: # ball is always inside screenrect. crashgroup = pygame.sprite.spritecollide(tank, ballgroup, False) for ball in crashgroup: if ball.boss != tank: # no friendly fire distance1 = vec2d(tank.pos) #calculate distance to tank center distance2 = vec2d(ball.pos) distance = distance1 - distance2 if distance.length > tank.hitradius: pass # nothing happened, bullet missed tank else: tank.shotby[ball.boss.id] += 1 tank.shotbysomebody += 1 ball.boss.hits += 1 # one point for the shooter # ----- more damage depending on impact speed impact = tank.spacemove - ball.moving damage = int(impact.length/100) # ----- additional damage if radius of Ball > 1 (point blank shot) damage += ball.tempradius - 1 # tempradius is minimum 1 #print "imact: %i + ballsize: %i = damage: %i " % (int(impact.length/100), ball.tempradius - 1, damage) textgroup.add(Text(vec2d(tank.pos), str(damage), ball.boss.color, 1.5, 25, vec2d(random.randint(-90,90),random.randint(-250,-120)), False, True )) # vc = vectorcenter if tank.id[0] == "p": # is it the Tank or a TankGhost ? Tank name begins with player tank.hitpoints -= damage tank.spacemove += ball.moving * ball.massfactor else: tank.boss.hitpoints -= damage tank.boss.spacemove += ball.moving * ball.massfactor woundgroup.add(Wound(ball.pos, 5)) recalc = True ball.kill() # -- collision tank with danger ? for tank in tankgroup: crashgroup = pygame.sprite.spritecollide(tank, dangergroup, False) for dang in crashgroup: if dang.damagePlayer: damage = dang.damage textgroup.add(Text(vec2d(tank.pos), str(damage), dang.color, 1.5, 25, vec2d(random.randint(-90,90),random.randint(-250,-120)), False, True )) # vc = vectorcenter if tank.id[0] == "p": # is it the Tank or a TankGhost ? tank.hitpoints -= damage tank.shotby["danger"] += 1 else: tank.boss.hitpoints -= damage tank.boss.shotby["danger"] +=1 tank.shotbysomebody += 1 if dang.type == "oil": dang.size -=1 #dang.size +=1 pass else: dang.hitpoints -= 1 #-- collision between ball and danger, explosion, : for dang in dangergroup: if dang.vulnerable: # ---------dang is an AI boat crashgroup = pygame.sprite.spritecollide(dang, ballgroup, True) #kill shot for ball in crashgroup: dang.vec += ball.moving * ball.massfactor woundgroup.add(Wound(ball.pos, 5)) dang.hitpoints -= 1 # dang dead ? explosion, drop goodie, respawn at center # -- collision danger with danger ? for dang in dangergroup: dangergroup2 = dangergroup.copy() dangergroup2.remove(dang) # remove myself from the clone group crashgroup = pygame.sprite.spritecollide(dang, dangergroup2, False) # dang survives for dang2 in crashgroup: if dang.type == "oil" and dang2.type == "oil" and dang.wo == -1 and dang2.wo == -1: # border patrols spawn only at corner #the bigger oil eats the smaller oil if dang.size > dang2.size and dang2.lifetime > 2.0: dang.size += 1 dang2.size = max(5, dang2.size-1) if dang.type == "boat" and dang2.type == "oil": dang.hitpoints -= 1 dang2.size -=1 textgroup.add(Text(vec2d(dang.pos), str(1), (255,255,0), 1.5, 25, vec2d(random.randint(-90,90),random.randint(120,240)), False, True )) # -- collision tank with other player ? for tank in tankgroup: if tank.id[0] == "p": # is it the Tank or a TankGhost ? tankgroup2 = tankgroup.copy() # copy of tankgroup, include self tankgroup2.remove(tank) # remove self of group crashgroup = pygame.sprite.spritecollide(tank, tankgroup2, False) for tank2 in crashgroup: #FIXME --- bis mir was bessers einfällt tank.hitpoints -= 1 textgroup.add(Text(vec2d(tank.pos), str(1), tank2.color, 1.5, 25, vec2d(random.randint(-90,90),random.randint(120,240)), False, True )) # tank-collision: damage text floats DOWN instead up else: pass # no collision damage for TankGhost (yet) #-- danger hitpoint check and oilspawn check for dang in dangergroup: if dang.type == "oil": if dang.wo != -1: # immortal oil, patrol the border dang.size = max(40, dang.size) # size can not be less than 10 else: if dang.size < 1: woundgroup.add(Wound(dang.pos, 50, .5)) # small explosion dang.kill() if dang.size > 40: dang.size = 40 # reduce size and spawn child newgroup.add(Danger(screenrect, "oil", 10, dang.pos)) else: #dang is a boat if dang.hitpoints < 1: woundgroup.add(Wound(dang.pos, 75, .5)) # final explosion #rebirth of ship in the middel of the screen #spawn 5 mini-oils newgroup.add(Danger(screenrect, "oil", 10, dang.pos), Danger(screenrect, "oil", 10, dang.pos), Danger(screenrect, "oil", 10, dang.pos), Danger(screenrect, "oil", 10, dang.pos), Danger(screenrect, "oil", 10, dang.pos)) dang.pos = vec2d(screenrect.centerx, screenrect.centery) dang.hitpoints = dang.hitpointsfull #--- calculate middle position of polygon made by surviving players calclist = [] for tank in tankgroup: if not tank.geist: calclist.append(tank.rect.center) #print calclist #--- tank hitpoint check, game over ? for tank in tankgroup: if tank.hitpoints < 0: woundgroup.add(Wound(tank.pos, 100, .75)) # final explosion tank.peaceful = True # dead Tank cannot shoot #spawn oil newgroup.add(Danger(screenrect, "oil", 10, tank.pos), Danger(screenrect, "oil", 10, tank.pos), Danger(screenrect, "oil", 10, tank.pos), Danger(screenrect, "oil", 10, tank.pos), Danger(screenrect, "oil", 10, tank.pos)) if len(tankgroup) > 5: textgroup.add(Text(tank.pos, "Loser", tank.color, 5.0, 72, vec2d(0,0), False, True)) textgroup.add(Text(tank.vc+ vec2d(0,-50), "Loser", (0,0,0), -1, 48, vec2d(0,0), False, False)) textgroup.add(Text(tank.vc+ vec2d(0,-25), "Rank: %i " % rank, (0,0,0), -1, 48, vec2d(0,0), False, False)) rank -= 1 textgroup.add(Text(tank.vc+ vec2d(0,35), "shot by:", (0,0,0), -1, 24, vec2d(0,0), False, False)) if tank.shotbysomebody == 0: tank.shotbysomebody = 1 # to avoid division by zero dy = 75 if tank.id != "player1" and tank.shotby["player1"] > 0: textgroup.add(Text(tank.vc+ vec2d(0,dy), "player1: %.2f%% " % (100*tank.shotby["player1"] / tank.shotbysomebody), (255,0,0), -1, 24, vec2d(0,0), False, False)) dy += 20 if tank.id != "player2" and tank.shotby["player2"] > 0: textgroup.add(Text(tank.vc+ vec2d(0,dy), "player2: %.2f%% " % (100*tank.shotby["player2"] / tank.shotbysomebody), (0,0,255), -1, 24, vec2d(0,0), False, False)) dy += 20 if tank.id != "player3" and tank.shotby["player3"] > 0: textgroup.add(Text(tank.vc+ vec2d(0,dy), "player3: %.2f%% " % (100*tank.shotby["player3"] / tank.shotbysomebody), (0,255,0), -1, 24, vec2d(0,0), False, False)) dy += 20 if tank.id != "player4" and tank.shotby["player4"] > 0: textgroup.add(Text(tank.vc+ vec2d(0,dy), "player4: %.2f%% " % (100*tank.shotby["player4"] / tank.shotbysomebody), (255,0,255), -1, 24, vec2d(0,0), False, False)) if tank.hits == 0: quota = 0.0 else: quota = tank.shots / tank.hits textgroup.add(Text(tank.vc+ vec2d(0,5), "hit ratio: %f" % (quota))) # future division, result in float tank.showvector = False # kill TankGhost's tank.kill() #if len(tankgroup) == 1 and not startGameOverMsg: if len(tankgroup) == 5 and not startGameOverMsg: # 1 Tank and 4 TankGhost startGameOverMsg = True for tank in tankgroup: textgroup.add(Text(tank.pos, "Victory", tank.color, 5.0, 72, vec2d(0,-50), False, True)) textgroup.add(Text(tank.vc + vec2d(0,-50), "Winner", (0,0,0), -1, 48, vec2d(0,0), False, False)) textgroup.add(Text(tank.vc + vec2d(0,-25), "Rank: %i " % rank, (0,0,0), -1, 48, vec2d(0,0), False, False)) if tank.hits == 0: quota = 0.0 else: quota = tank.shots / tank.hits textgroup.add(Text(tank.vc+ vec2d(0,5), "hit ratio: %.2f" % (quota))) # future division, result in float textgroup.add(Text((screenrect.width/2,screenrect.height/2), "Game Over", (1,1,1), 5.0,100, vec2d(0,-20), False, True)) finale = True if finale: if len(woundgroup) == 0: mainloop = False # leave game #--- draw the sprites allgroup.draw(screen) #--- decorate screen #pygame.display.set_caption("player1 [F1]: %s player2 [F12]: %s mouse: %s balls: %i " #% (player.modus, p2.modus , pygame.mouse.get_pos(),len(ballgroup))) pygame.display.set_caption( "# text: %i, # balls: %i fps: %.2f" % (len(textgroup), len(ballgroup), 1000.0/tick_time)) pygame.display.flip() # flip the screen 30 times a second #--- end of loop
~~DISQUS~~