Mercurial > atc
view atc_plane.py @ 13:4a95c5552d3b
Stall speed and normal rate of climb adjustment
committer: Jeff Sipek <jeffpc@jeff.(none)> 1120872321 -0400
author | Jeff Sipek <jeffpc@jeff.(none)> |
---|---|
date | Sat, 09 Jul 2005 01:25:21 -0400 |
parents | 243941ec0a36 |
children | d9c394a5ef77 |
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_colors import atc_utils from atc_plane_specs import * mperpix = 30000.0/800.0 # 800 px == 30 km 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,callsign,flightno,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 # 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 = plane_SPECS[0] # default to a simple prop plane, FIXME: add param to override # 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: print "Nothing calculated" return if ijk == None: self.vel["i"] = sin(self.vel["heading"]) * sqrt(self.vel["speed"]**2 - self.vel["climb"]**2) self.vel["j"] = cos(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["k"] = 0 self.targetPos["Z"] = None self.complete_vel(ijk=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 radians)""" if (self.vel["i"] == self.vel["j"] == 0): # no movement return 0 try: head = fabs(atan(self.vel["i"]/-self.vel["j"])) except ZeroDivisionError: if (self.vel["i"]>0): return pi/2 # east return 3*pi/2 # west return head 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["k"] = self.specs["climb_normal"] if (self.pos["Z"] > self.targetPos["Z"]): self.vel["k"] *= -1 self.complete_vel(ijk=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.vel["heading"] *= pi/180.0 self.complete_vel(hac=1) def display(self,screen): """ Put everything onto the screen """ screen.blit(self.image, (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 x = int(1024/2+m2pix(self.pos["X"])) + 10 y = int(768/2-m2pix(self.pos["Y"])) - 5 # FIXME: display geographic coordinates with NSWE appended/prepended #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(atc_utils.todeg(self.vel["heading"]))), # "AS: " + str(int(self.vel["speed"]*3.6))) strings = ( self.flightno, "%03d %03d" % (int(atc_utils.todeg(self.vel["heading"])), int(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)