Mercurial > atc
view atc_plane.py @ 42:05245904f997
Slight change in map specs
Map parsing is more OOP-ish
author | Josef "Jeff" Sipek <jeffpc@optonline.net> |
---|---|
date | Fri, 19 Aug 2005 19:09:27 -0500 |
parents | 61defd11d98c |
children | c93c3c910c85 |
line wrap: on
line source
#/* # * ATC - Air Traffic Controller simulation game # * # * Copyright (C) 2004, 2005 Josef "Jeff" Sipek <jeffpc@optonline.net> # * # * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # * # * @(#) %M% %I% %E% %U% # */ import os import sys import time import pygame from math import * import atc_config import atc_colors import atc_utils from atc_plane_specs import * from atc_maps import * mperpix = MAPS[0].mperpix mperdeg = 1852.0*60.0 # == 1852 m/min * 60 min/deg def m2pix(m): """ Meters to pixels conversion fn """ return m/mperpix def pix2m(pix): """ Pixels to meters conversion fn """ return pix*mperpix def pix2geo(pix): return pix2m(pix)/mperdeg plane_OK = 0 plane_RANGE = 1 plane_CRASHED = 2 plane_STALL = 3 plane_DEAD = 4 plane_PROXY = 5 class Plane(pygame.sprite.Sprite): """ Class to manage one plane's motion """ def __init__(self,type,callsign,flightno,squawk="1200",pos=(0.0, 0.0, 0.0),vel=(0.0, 0.0, 0.0)): """ Set up everything """ pygame.sprite.Sprite.__init__(self) # screen screen = pygame.display.get_surface() self.area = screen.get_rect() # plane image (self.image, self.rect) = atc_utils.load_png('data/image/plane.png') # call sign self.callsign = callsign # flight number self.flightno = flightno # squawk code (shoud be octal number digits 0-7 only) self.squawk = squawk # position (X, Y, Z) self.pos = { \ "X":pos[0], \ "Y":pos[1], \ "Z":pos[2]} # target position self.targetPos = { \ "X":None, \ "Y":None, \ "Z":None} # velocity self.vel = { \ "i":vel[0], \ "j":vel[1], \ "k":vel[2], \ "heading":0, \ "speed":0, \ "climb":0} self.complete_vel(ijk=1) self.timer = 0 # this is timeout the next time we try to recalculate position # plane specs self.specs = None for p in plane_SPECS: if p['name'] == type: self.specs= p break if self.specs == None: self.specs = plane_SPECS[0] # status flag self.status = plane_OK def complete_vel(self, ijk=None, hac=None): """ Recalculate all the velocity variables """ if ijk == None and hac == None: return if ijk == None: self.vel["i"] = sin(atc_utils.torad(self.vel["heading"])) * sqrt(self.vel["speed"]**2 - self.vel["climb"]**2) self.vel["j"] = cos(atc_utils.torad(self.vel["heading"])) * sqrt(self.vel["speed"]**2 - self.vel["climb"]**2) self.vel["k"] = self.vel["climb"] else: self.vel["heading"] = self.calc_head() self.vel["speed"] = sqrt(self.vel["i"]**2 + self.vel["j"]**2 + self.vel["k"]**2) self.vel["climb"] = self.vel["k"] def update(self): """ Move the plane, and check for collisions """ if (self.timer > time.time()): return if (self.status != plane_OK): return self.pos["X"] += self.vel["i"]/10.0 self.pos["Y"] += self.vel["j"]/10.0 self.pos["Z"] += self.vel["k"]/10.0 # FIXME: need physics if (self.targetPos["Z"] != None) and (self.pos["Z"] >= (self.targetPos["Z"] - 25)) and (self.pos["Z"] <= (self.targetPos["Z"] + 25)): self.vel["climb"] = 0 self.targetPos["Z"] = None self.complete_vel(hac=1) #if (self.pos["X"] < 0) or (self.pos["Y"] < 0): # FIXME: max values # self.status = plane_RANGE if (self.pos["Z"] < 0): self.vel["i"] = self.vel["j"] = self.vel["k"] = 0 self.status = plane_CRASHED if (self.vel["speed"]<m2pix(self.specs["stall_speed"])) and (not self.status==plane_CRASHED): self.status = plane_STALL self.rect.move(m2pix(self.vel["i"])/10.0,m2pix(self.vel["j"])/10.0) self.timer = time.time() + m2pix(self.vel["speed"])**-1/10.0 def calc_head(self): """ Calculate heading of the airplane (in degrees)""" if (self.vel["i"] == self.vel["j"] == 0): # no movement return 0 try: head = fabs(atan(self.vel["i"]/self.vel["j"])) # yes this is "backwards" except ZeroDivisionError: if (self.vel["i"]>0): return 90 # east return 270 # west head = abs(head*180/pi) if self.vel["i"]>0 and self.vel["j"]>0: # quad I return head if self.vel["i"]<0 and self.vel["j"]>0: # quad II return 360-head if self.vel["i"]<0 and self.vel["j"]<0: # quad III return 270-head if self.vel["i"]>0 and self.vel["j"]<0: # quad IV return 180-head if self.vel["i"]==0 and self.vel["j"]>0: # north return 0 return 180 # south def calc_geo(self, xy, prefix): """ Return a geographic coodrinate-formated xy """ df = m2pix(pix2geo(xy)) minus = prefix[0] if df<0: df *= -1 minus = prefix[1] d = floor(df) mf = (df-d) * 60.0 m = floor(mf) s = (mf-m) * 60.0 return "%s %dd %02dm %02ds" % (minus, int(d), int(m), int(s)) def process(self,cmd): """ Process a user command """ # FIXME: convert multiple spaces to single parts = cmd.split(' ') if (parts[0] == "ALT"): print "Changing altitude to " + parts[1] + "m" self.targetPos["Z"] = int(parts[1]) self.vel["climb"] = self.specs["climb_normal"] if (self.pos["Z"] > self.targetPos["Z"]): self.vel["climb"] *= -1 self.complete_vel(hac=1) if (parts[0] == "HEAD"): self.vel["heading"] = int(parts[1]) while(True): if self.vel["heading"]>=360: self.vel["heading"] -= 360 elif self.vel["heading"]<0: self.vel["heading"] += 360 else: break print "Changing heading to " + str(self.vel["heading"]) self.complete_vel(hac=1) if (parts[0] == "SQUAWK"): self.squawk = parts[1] def display(self,screen): """ Put everything onto the screen """ rotimage = pygame.transform.rotate(self.image, 360.0-self.vel["heading"]) screen.blit(rotimage, (int(1024/2+m2pix(self.pos["X"])), int(768/2-m2pix(self.pos["Y"])))) # Plane info font = pygame.font.Font(None, 16) color = atc_colors.planeinfo_ok if (self.status == plane_CRASHED) or (self.status == plane_DEAD): color = atc_colors.planeinfo_crashed if (self.squawk == "7700") or \ (self.squawk == "7600") or \ (self.squawk == "7500") or \ (self.squawk == "0000"): color = atc_colors.planeinfo_emergency x = int(1024/2+m2pix(self.pos["X"])) + 10 y = int(768/2-m2pix(self.pos["Y"])) - 5 if (atc_config.plane_label == 2): strings = ( self.flightno, self.callsign + " " + str(self.status), "Alt: " + str(int(self.pos["Z"])), "Lat: " + self.calc_geo(self.pos["Y"],"NS"), "Long: " + self.calc_geo(self.pos["X"],"EW"), "Head: " + str(int(self.vel["heading"])), "AS: " + str(int(self.vel["speed"]*3.6))) else: strings = ( self.flightno, "%03d %03d" % (int(round(self.vel["heading"])), int(round(self.vel["speed"]*3.6))), self.specs["name"]) for stri in strings: alt = font.render(stri, 1, color) altpos = alt.get_rect() altpos.topleft = (x,y) screen.blit(alt, altpos) (x,y) = (x,y+10)