You can subscribe to this list here.
| 2007 |
Jan
(68) |
Feb
(49) |
Mar
(46) |
Apr
(44) |
May
(22) |
Jun
(6) |
Jul
(3) |
Aug
(3) |
Sep
(32) |
Oct
(44) |
Nov
(12) |
Dec
(1) |
|---|
|
From: <cd...@us...> - 2007-12-11 08:40:52
|
Revision: 330
http://eos-game.svn.sourceforge.net/eos-game/?rev=330&view=rev
Author: cduncan
Date: 2007-12-11 00:40:40 -0800 (Tue, 11 Dec 2007)
Log Message:
-----------
Set lower-limit of physics speed to 20fps, if the actual frame rate drops
below this then the physics will slow, but this is avoids big jumps when
an occasional single frame is very slow and generally makes the game less
jerky when the framerate varies.
Modified Paths:
--------------
game.py
Modified: game.py
===================================================================
--- game.py 2007-11-24 08:18:22 UTC (rev 329)
+++ game.py 2007-12-11 08:40:40 UTC (rev 330)
@@ -242,7 +242,7 @@
camera.update()
sprite.layers.draw(display.surface)
pygame.display.flip()
- universe.quickStep(clock.get_time() / 1000.0)
+ universe.quickStep(min(clock.get_time() / 1000.0, 0.05))
if server:
server.step()
time += clock.tick()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-24 08:18:26
|
Revision: 329
http://eos-game.svn.sourceforge.net/eos-game/?rev=329&view=rev
Author: cduncan
Date: 2007-11-24 00:18:22 -0800 (Sat, 24 Nov 2007)
Log Message:
-----------
- Add callback scheduler
- Vessel system repair now handled by the scheduler
- Panel updates are now done via the scheduler
- Add --stats option to print internal stats during the game
- Minor particle optimizations, among others
Modified Paths:
--------------
base.py
bay.py
camera.py
eos.py
event.py
game.py
map.py
media.py
panel.py
particle.py
projectile.py
vector.py
vessel.py
Added Paths:
-----------
scheduler.py
Modified: base.py
===================================================================
--- base.py 2007-11-19 07:55:50 UTC (rev 328)
+++ base.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -87,10 +87,12 @@
def build_vessel(self, config_file):
"""Start building the vessel if we can build it and nothing else
- is being built
+ is being built. Return True if the vessel will be built.
"""
if len(self.build_queue) < self.max_build_queue and self.can_build_vessel(config_file):
self.build_queue.append(VesselBuilder(self, config_file))
+ return True
+ return False
def cancel_builder(self, builder_idx=None):
"""Remove the builder from the build queue. If no index is given,
@@ -183,8 +185,7 @@
vessel.set_position(self.base.planet.position)
vessel.set_heading(random.random() * vector.fullcircle)
self.vessel_built = True
- message.send_status(self.base, self.base.owner,
- '%s built at %s' % (vessel.vessel_class, self.base.planet.name))
+ self.base.owner.vessel_built(self.base, vessel)
if __name__ == '__main__':
"""Run tests if executed directly"""
Modified: bay.py
===================================================================
--- bay.py 2007-11-19 07:55:50 UTC (rev 328)
+++ bay.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -48,9 +48,6 @@
for vessel in self.docked.sprites():
# Docked vessels are not drawn, but systems are still updated
vessel.update_systems()
- if self.vessel.control.show_status:
- for vessel in self.fighters.sprites():
- vessel.show_status()
if self.enabled:
if self.firing and game.time > self.last_launch + self.launch_delay:
self.launch()
Modified: camera.py
===================================================================
--- camera.py 2007-11-19 07:55:50 UTC (rev 328)
+++ camera.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -30,6 +30,7 @@
def center(self):
"""Setup camera center"""
self.rect = pygame.Rect(display.rect.width / 2, display.rect.height / 2, 0, 0)
+ self.screen_pos = vector.vector2(*self.rect.center)
self.base_scale = (float(display.rect.width) / float(self.virtual_width))**0.5
@property
Modified: eos.py
===================================================================
--- eos.py 2007-11-19 07:55:50 UTC (rev 328)
+++ eos.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -45,6 +45,9 @@
parser.add_option('-d', '--debug',
dest='debug', default=False, action='store_true',
help='Drop into the debugger on error')
+ parser.add_option('--stats',
+ dest='stats', default=False, action='store_true',
+ help='Output object stats during game')
parser.add_option('--fake-latency',
dest='latency', type='float', default=0.0,
help='artificial latency [default %default secs]')
@@ -61,6 +64,7 @@
if args: raise optparse.OptParseError('Unrecognized args: %s' % args)
game.debug = opts.debug
+ game.stats = opts.stats
game.init(opts.is_server, opts.is_client, opts.host, opts.port,
opts.fullscreen, opts.race, opts.ship, opts.resolution,
opts.latency, opts.packet_loss, opts.mute)
@@ -71,7 +75,18 @@
import cProfile as profile
except ImportError:
import profile
- profile.run('game.play()')
+ import pstats
+ # Monkey patch the pstats class to combine cum time and callees
+ def print_func_and_callees(self, func):
+ self.print_func_only(func)
+ self.print_call_line(self.max_name_len, func, self.all_callees[func])
+ pstats.Stats.print_func_only = pstats.Stats.print_line
+ pstats.Stats.print_line = print_func_and_callees
+ # Run the profiler and print the report
+ profile.run('game.play()', 'profile.out')
+ stats = pstats.Stats('profile.out')
+ stats.calc_callees()
+ stats.sort_stats('cum').print_stats(20)
else:
game.play()
except SystemExit:
Modified: event.py
===================================================================
--- event.py 2007-11-19 07:55:50 UTC (rev 328)
+++ event.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -213,6 +213,10 @@
if target:
game.local_player.switch_vessel(target)
+ def show_vessel_status(self):
+ if isinstance(game.local_player.vessel, Vessel):
+ game.local_player.vessel.show_status()
+
def __init__(self):
sprite.Sprite.__init__(self, sprite.layers.ui)
key_map = {
@@ -228,6 +232,7 @@
'\b': self.switch_local_player_vessel,
}
self.key_map = dict((ord(key), method) for key, method in key_map.items())
+ self.key_map[K_RSHIFT] = self.show_vessel_status
def key_down(self, event):
if event.key in self.key_map:
Modified: game.py
===================================================================
--- game.py 2007-11-19 07:55:50 UTC (rev 328)
+++ game.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -21,6 +21,7 @@
import message
import particle
import sprite
+import scheduler
fps = 40 # Framerate, averaged over time
ai_interval = 70 # Release AI every N seconds
@@ -36,11 +37,13 @@
client = None
objects = sprite.NetGroup()
local_player = None
+map = None
starfield = None
camera = None
target = None
windowed = False
debug = False
+stats = False
def init(is_server=False, is_client=False, host='127.0.0.1', port=252525,
fullscreen=False, race=None, ship=None, resolution=None, latency=None,
@@ -57,8 +60,8 @@
from camera import Camera
import player
global universe, collision_space, map, starfield
- global fps, avg_fps, clock, time, local_player, camera, ai
- global target, windowed, messenger, send_msg
+ global fps, clock, time, local_player, camera
+ global target, windowed
windowed = not fullscreen
# Initialize pygame and setup main screen
@@ -156,6 +159,7 @@
# Setup background and map
starfield = StarField(display.rect)
map = Map('sol')
+ map.vessels.add(local_player.vessel)
# Find the base and put the player next to it
for planet in map.planets:
@@ -217,9 +221,9 @@
import media
import event
import panel
- global universe, background, debug
- global fps, avg_fps, clock, time, frame_no
- global ai_interval, windowed, camera, map
+ global universe, background, stats
+ global fps, clock, time, frame_no
+ global ai_interval, camera, map
friends = pygame.sprite.Group()
enemies = pygame.sprite.Group()
next_wave = 0
@@ -234,18 +238,24 @@
handle_collisions()
display.surface.fill((0, 0, 0))
sprite.layers.update()
+ scheduler.dispatch(time)
camera.update()
sprite.layers.draw(display.surface)
pygame.display.flip()
universe.quickStep(clock.get_time() / 1000.0)
if server:
server.step()
- last_time = time
time += clock.tick()
sleep(0)
fps = clock.get_fps() or fps
- if debug and frame_no % 30 == 0:
- print body.body_count, len(sprite.layers), len(media._scaled_image_cache), fps
+ if stats and frame_no % 30 == 0:
+ cache = media._scaled_image_cache
+ print 'b:', body.body_count,
+ print 's:', len(sprite.layers),
+ print 'i:', len(cache), (cache.accesses - cache.misses) * 100 / cache.accesses, '%',
+ print 'p:', particle.particle_count,
+ print 't:', len(scheduler._taskq),
+ print 'fps:', fps
## Temporary wave-based game play ##
if not client:
Modified: map.py
===================================================================
--- map.py 2007-11-19 07:55:50 UTC (rev 328)
+++ map.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -78,6 +78,7 @@
parser.readfp(config_file)
self.rect = None
self.planets = []
+ self.vessels = pygame.sprite.Group()
for section in parser.sections():
if section == 'general':
for option, value in parser.items(section):
Modified: media.py
===================================================================
--- media.py 2007-11-19 07:55:50 UTC (rev 328)
+++ media.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -73,7 +73,7 @@
self.purged = 0
def __getitem__(self, key):
- #self.accesses += 1
+ self.accesses += 1
try:
try:
return self._recent[key]
@@ -94,7 +94,7 @@
def __setitem__(self, key, value):
assert value is not None
- #self.adds += 1
+ self.adds += 1
if key in self._aged:
del self._aged[key]
if len(self._recent) >= self.max_recent_size:
@@ -109,29 +109,33 @@
self._recent[key] = value
while self._aged and len(self) > self.max_size:
# Over max size, purge aged entries
- #self.purged += 1
+ self.purged += 1
self._aged.popitem()
_scaled_image_cache = Cache(6000)
_rotation_step_angle = fullcircle / 250.0
+_empty_image = pygame.Surface((0, 0))
def image(name, scale=1.0, rotation=0, colorkey=False):
"""Return a preloaded image by name at the specified scale and rotation"""
- global _images, _scaled_image_cache, _rotation_step_angle
+ global _images, _scaled_image_cache, _rotation_step_angle, _empty_image
orig_image, orig_width = _images[name]
- scaled_width = round(orig_width * scale)
- rotation_step = int(rotation / _rotation_step_angle) % 250
- try:
- return _scaled_image_cache[name, scaled_width, rotation_step]
- except KeyError:
- image = pygame.transform.rotozoom(orig_image, 270 - degrees(rotation), scale)
- if colorkey:
- image = image.convert()
- image.set_colorkey(image.get_at((0, 0)), pygame.RLEACCEL)
- else:
- image.set_alpha(0, pygame.RLEACCEL)
- _scaled_image_cache[name, scaled_width, rotation_step] = image
- return image
+ scaled_width = int(orig_width * scale)
+ if scaled_width:
+ rotation_step = int(rotation / _rotation_step_angle) % 250
+ try:
+ return _scaled_image_cache[name, scaled_width, rotation_step]
+ except KeyError:
+ image = pygame.transform.rotozoom(orig_image, 270 - degrees(rotation), scale)
+ if colorkey:
+ image = image.convert()
+ image.set_colorkey(image.get_at((0, 0)), pygame.RLEACCEL)
+ else:
+ image.set_alpha(0, pygame.RLEACCEL)
+ _scaled_image_cache[name, scaled_width, rotation_step] = image
+ return image
+ else:
+ return _empty_image
def fit_image(name, rect):
"""Return a preloaded image scaled to fit inside rect"""
Modified: panel.py
===================================================================
--- panel.py 2007-11-19 07:55:50 UTC (rev 328)
+++ panel.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -19,6 +19,7 @@
import sprite
import media
import selection
+import scheduler
class Panel(sprite.Sprite, event.Handler):
"""User interface panel. Panels contain controls. Enabled panels receive
@@ -29,6 +30,7 @@
slide_time = 0.25
border_color = (40, 40, 60, 150)
background_color = (0, 0, 40, 150)
+ update_interval = 300 # millis between panel updates
def __init__(self, enabled=True, *controls):
"""Create a panel and add it to the panel handler"""
@@ -44,6 +46,7 @@
self.slide_end_frame = None
handler.add_panel(self)
sprite.layers.ui.to_back(self)
+ scheduler.schedule(self.update_panel, sprite=self, recurrance=self.update_interval)
def create_image(self):
"""Return a panel image that is a background for the panel controls.
@@ -62,14 +65,13 @@
return control
def update_panel(self):
- """Panel-specific updates, called once per frame.
+ """Panel-specific updates, called once per update_inteval.
This is intended to be overridden by subclasses
"""
def update(self):
if self.slide_end_frame is not None and game.frame_no < self.slide_end_frame:
self.slide()
- self.update_panel()
self.controls.update()
def draw(self, surface):
@@ -267,6 +269,7 @@
width - border_width*2, height - border_width*2)
self.map_scale = self.map_rect.width / float(map.rect.width)
BottomPanel.__init__(self, width, height, align_right=True)
+ self.image = pygame.Surface(self.rect.size, pygame.SRCALPHA, 32)
self.tab = PanelTab(self, align_right=True)
self.controls.add(self.tab)
self.select_rect = None
@@ -294,30 +297,42 @@
centerx=pos_x + self.map_rect.centerx, centery=pos_y + self.map_rect.centery)
image.blit(planet_img, planet_rect)
self.map_points = pygame.Surface(self.rect.size, pygame.SRCALPHA, 32)
+ self.map_points.set_clip(
+ self.map_points.get_rect().inflate(-self.border_width * 2, -self.border_width * 2))
self.map_mask = pygame.Surface(self.rect.size, pygame.SRCALPHA, 32)
+ self.map_mask.set_clip(
+ self.map_mask.get_rect().inflate(-self.border_width * 2, -self.border_width * 2))
image.set_alpha(0, pygame.RLEACCEL)
+ self.background = image
return image
def update_panel(self):
- self.map_points.fill((0, 0, 0, 0))
- self.map_mask.fill((0, 0, 0, 0))
- self.tab.rect.right = self.rect.right
+ if self.enabled:
+ self.map_points.fill((0, 0, 0, 0))
+ self.map_mask.fill((0, 0, 0, 0))
+ self.tab.rect.right = self.rect.right
+ for vessel in self.map.vessels:
+ if not vessel.incidental:
+ if vessel.is_friendly(game.local_player.vessel):
+ if vessel is game.local_player.vessel:
+ color = (50, 50, 255)
+ elif vessel.selected:
+ color = (255, 255, 255)
+ else:
+ color = (0, 255, 0)
+ else:
+ color = (255, 0, 0)
+ pos_x, pos_y = vector.to_tuple(vessel.position * self.map_scale)
+ point_rect = pygame.Rect(
+ pos_x + self.map_rect.centerx, pos_y + self.map_rect.centery, 2, 2)
+ self.map_points.fill(color, point_rect)
+ self.map_mask.fill((0, 0, 0, 120), point_rect.inflate(4, 4))
+ self.image.fill((0, 0, 0, 0))
+ self.image.blit(self.background, (0, 0))
+ self.image.blit(self.map_mask, (0, 0))
+ self.image.blit(self.map_points, (0, 0))
+ self.image.set_alpha(0, pygame.RLEACCEL)
- def update_vessel(self, vessel):
- if not vessel.incidental:
- if vessel.is_friendly(game.local_player.vessel):
- if vessel.selected:
- color = (255, 255, 255)
- else:
- color = (0, 255, 0)
- else:
- color = (255, 0, 0)
- pos_x, pos_y = vector.to_tuple(vessel.position * self.map_scale)
- point_rect = pygame.Rect(
- pos_x + self.map_rect.centerx, pos_y + self.map_rect.centery, 2, 2)
- self.map_points.fill(color, point_rect)
- self.map_mask.fill((0, 0, 0, 120), point_rect.inflate(4, 4))
-
def mouse_drag(self, event, start_pos, end_pos):
if self.select_rect is None and not self.rect.collidepoint(start_pos):
return False # Drag did not originate in our panel
@@ -369,8 +384,6 @@
surface.set_clip(self.rect)
surface.blit(self.image, self.rect)
surface.set_clip(self.rect.inflate(-self.border_width * 2, -self.border_width * 2))
- surface.blit(self.map_mask, self.rect)
- surface.blit(self.map_points, self.rect)
if self.select_rect is not None:
pygame.draw.rect(surface, (200, 100, 0), self.select_rect, 1)
surface.set_clip(old_clip)
@@ -401,7 +414,6 @@
'warship': 3,
}
-
def __init__(self, planet):
self._last_builder = None
self.current_builder_btn = None
Modified: particle.py
===================================================================
--- particle.py 2007-11-19 07:55:50 UTC (rev 328)
+++ particle.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -32,16 +32,18 @@
self.color = color
self.apparent_size, screen_pos = vector.to_screen(position)
self.size = 2.0 * self.apparent_size
- self.frames = self.total_frames = time_to_live * game.fps
+ self.time_to_live = time_to_live * 1000
+ self.timeout = game.time + time_to_live * 1000
self.opacity = self.image_alpha = opacity
self.rect = pygame.Rect(0, 0, 0, 0)
+ self.image = None
self.set_image()
self.offscreen_img = None
global particle_count
particle_count += 1
def set_image(self):
- if self.size >= 0.1:
+ if self.size >= 0.1 or self.image is None:
img_key = int(self.size), self.color
if img_key in self._image_cache:
self.image = self._image_cache[img_key]
@@ -57,25 +59,22 @@
pygame.draw.ellipse(self.image, self.color, self.image.get_rect())
self._image_cache[img_key] = self.image
else:
- self.image = pygame.Surface((0,0))
+ self.image_alpha = 0
self.rect = self.image.get_rect(center=self.rect.center)
def update(self):
self.position += self.velocity
- if self.accel_rate:
- self.velocity *= self.accel_rate
+ self.velocity *= self.accel_rate
if random.random() <= self.growth_rate:
self.size += self.apparent_size
self.set_image()
- if self.frames > 0:
- self.frames -= 1
- self.apparent_size, screen_pos = vector.to_screen(self.position)
- self.rect.center = vector.to_tuple(screen_pos)
- else:
+ self.apparent_size, screen_pos = vector.to_screen(self.position)
+ self.rect.center = vector.to_tuple(screen_pos)
+ if game.time > self.timeout:
self.kill()
def draw(self, surface):
- alpha = self.frames * self.image_alpha / self.total_frames
+ alpha = (self.timeout - game.time) * self.image_alpha / self.time_to_live
if alpha > 5:
self.image.set_alpha(alpha)
return surface.blit(self.image, self.rect)
Modified: projectile.py
===================================================================
--- projectile.py 2007-11-19 07:55:50 UTC (rev 328)
+++ projectile.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -113,9 +113,6 @@
state['create_args'] = (self.charge, None)
return state
- def clear(self):
- display.surface.fill((0,0,0), self.rect)
-
def update(self):
# Position, velocity and heading are cached because they are frequently accessed
self.position = vector.vector2(*self.body.getPosition()[:2])
@@ -369,9 +366,6 @@
state['create_args'] = (self.shooter.net_id, self.image_name, self.start_damage, vector.vector2())
return state
- def clear(self):
- display.surface.fill((0,0,0), self.rect)
-
def update(self):
RoundBody.update(self)
self.damage_value -= self.damage_loss
Added: scheduler.py
===================================================================
--- scheduler.py (rev 0)
+++ scheduler.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -0,0 +1,113 @@
+## Eos, Dawn of Light -- A Space Opera
+## Copyright (c) 2007 Casey Duncan and contributors
+## See LICENSE.txt for licensing details
+
+# Periodic task scheduler
+# $Id$
+
+import sys
+from heapq import heappush, heappop, heapreplace
+
+# Initialize the task queue with a fake task that will always
+# be after any scheduled task so we can always assume the task
+# queue has at least one item in it.
+_taskq = [(sys.maxint,)]
+
+def schedule(callback, time=0, sprite=None, recurrance=None):
+ """Schedule the specified callback to be executed at the specified time.
+ If recurrance is specified, the callback will be rescheduled to occur
+ periodically every recurrance millis.
+
+ You can specify a time value of 0 if you want the task to be called
+ immediately on the next call to dispatch.
+
+ If sprite is specified, then the callback will only be dispatched
+ if the sprite is alive at the scheduled time.
+ """
+ heappush(_taskq, (time, callback, sprite, recurrance))
+
+def dispatch(time):
+ """Dispatch all scheduled items that are due to be executed on or
+ before time.
+
+ Any exceptions from a scheduled callback will be propagated, halting
+ dispatching at that point. Callables not executed are left in the
+ task queue.
+
+ Note this method is not currently thread-safe, though it could be
+ made so with a small loss in efficiency.
+
+ >>> class Foo:
+ ... one_calls = 0
+ ... two_calls = 0
+ ... def one(self):
+ ... self.one_calls += 1
+ ... def two(self):
+ ... self.two_calls += 1
+ >>> class Sprite:
+ ... is_alive = True
+ ... def alive(self):
+ ... return self.is_alive
+ >>> _clear()
+ >>> o = Foo()
+ >>> s = Sprite()
+ >>> schedule(o.one, 2)
+ >>> schedule(o.two, 3, s, 2)
+ >>> dispatch(1)
+ >>> o.one_calls
+ 0
+ >>> o.two_calls
+ 0
+ >>> dispatch(2)
+ >>> o.one_calls
+ 1
+ >>> o.two_calls
+ 0
+ >>> dispatch(3)
+ >>> o.one_calls
+ 1
+ >>> o.two_calls
+ 1
+ >>> dispatch(4)
+ >>> o.one_calls
+ 1
+ >>> o.two_calls
+ 1
+ >>> dispatch(6)
+ >>> o.one_calls
+ 1
+ >>> o.two_calls
+ 2
+ >>> dispatch(4000)
+ >>> o.one_calls
+ 1
+ >>> o.two_calls
+ 3
+ >>> s.is_alive = False
+ >>> dispatch(4100)
+ >>> o.one_calls
+ 1
+ >>> o.two_calls
+ 3
+ """
+ while _taskq[0][0] <= time:
+ nil, callback, sprite, recurrance = _taskq[0]
+ if sprite is None or sprite.alive():
+ if recurrance is not None:
+ heapreplace(_taskq, (time + recurrance, callback, sprite, recurrance))
+ else:
+ heappop(_taskq)
+ callback()
+ else:
+ heappop(_taskq)
+
+def _clear():
+ global _taskq
+ _taskq = []
+
+if __name__ == '__main__':
+ """Run tests if executed directly"""
+ import sys, doctest
+ failed, count = doctest.testmod()
+ print 'Ran', count, 'test cases with', failed, 'failures'
+ sys.exit(failed)
Property changes on: scheduler.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: vector.py
===================================================================
--- vector.py 2007-11-19 07:55:50 UTC (rev 328)
+++ vector.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -53,7 +53,7 @@
from_camera = position - camera.position
apparent_size = camera.zoom * log10(
10.0 * camera.zoom_size_factor / (length(from_camera) + camera.zoom_size_factor) + 1.0)
- return apparent_size**2, vector2(*camera.rect.center) + (
+ return apparent_size**2, camera.screen_pos + (
from_camera * camera.zoom * apparent_size)
def to_map(screen_pos, slop=50, max_iterations=100):
Modified: vessel.py
===================================================================
--- vessel.py 2007-11-19 07:55:50 UTC (rev 328)
+++ vessel.py 2007-11-24 08:18:22 UTC (rev 329)
@@ -20,6 +20,7 @@
import particle
import message
import sprite
+import scheduler
max_weapons = 5
_empty_rect = pygame.rect.Rect(0, 0, 0, 0)
@@ -34,7 +35,6 @@
self.right_maneuver = False
self.bw_maneuver = False
self.turn = 0 # -1 = left, 0 = stop, 1 = right
- self.show_status = False
self.weapons = [False] * max_weapons
self.target = None # body being targeted
@@ -52,7 +52,6 @@
self.left_maneuver = keystate[K_a]
self.right_maneuver = keystate[K_d]
self.bw_maneuver = keystate[K_s] or keystate[K_DOWN]
- self.show_status = keystate[K_RSHIFT]
self.weapons[0] = keystate[K_SPACE]
self.weapons[1] = keystate[K_LSHIFT]
self.target = game.target.selected
@@ -108,7 +107,6 @@
disable_factor = 5 # disabled if damage exceeds this factor * hull_mass
system_damage = 0 # System damage accumulator
system_damage_threshold = 10 # How much damage to disable a system
- system_repair_time = 15000 # Time to repair systems
max_speed = 0
max_energy = 0
energy_storage_mass = 0.02 # Mass per energy unit stored
@@ -116,6 +114,7 @@
status_bar_width = 37 # Width of status bar on-screen
status_fade_time = 300 # status fade out/in speed
status_timeout = 5000 # millis status remains visible
+ system_repair_time = 15000 # millis to repair a damaged system
selected = False
race = None
@@ -155,12 +154,13 @@
self._damage_sys = []
self.weapons = []
self.set_heading(random.random() * fullcircle)
- self._systems_to_repair = []
- self._repair_time = None
self.damage_time = 0
self.race = race
self.ai_name = ai
self.incidental = str(incidental) not in ('0', 'False')
+ if game.map is not None:
+ game.map.vessels.add(self)
+ self._systems_to_repair = []
@classmethod
def load(cls, config_file, **kw):
@@ -262,16 +262,9 @@
body.RoundBody.update(self)
if self.enabled:
self.control.update()
- if self.control.show_status:
- self.show_status()
for weapon, ctrl_state in zip(self.weapons, self.control.weapons):
weapon.firing = ctrl_state
self.update_systems()
- game.map.minimap.update_vessel(self)
- if not self._systems_to_repair and self.damage_smoke is not None:
- # Systems all repaired, no more smoke
- self.damage_smoke.kill()
- self.damage_smoke = None
if vector.length(self.velocity) > self.max_speed:
# If we are overspeed, bleed off a little
overspeed = vector.length(self.velocity) - self.max_speed
@@ -285,18 +278,6 @@
def update_systems(self):
for system in self._sys:
system.update_system()
- if self._systems_to_repair:
- if self._repair_time is None:
- # begin repair of first system in repair list
- self._repair_time = game.time + self.system_repair_time
- elif game.time > self._repair_time:
- # System repair completed, re-enable it
- repaired_system = self._systems_to_repair.pop(0)
- repaired_system.enable()
- self._repair_time = None
- message.send_status(
- self, self, '%s Repaired' % system.name.title(), message.notice)
-
def draw_status(self):
"""Return an image for the vessel status"""
@@ -490,6 +471,10 @@
self.status_time = max(
self.status_time, time + self.status_timeout + self.status_fade_time * 2)
+ @property
+ def status_shown(self):
+ return game.time < self.status_time
+
def damage(self, value):
"""Apply damage to the vessel
@@ -527,21 +512,36 @@
else:
self.system_damage += value
while self.system_damage > self.system_damage_threshold:
- system = random.choice(self._sys)
- system.disable()
- self._systems_to_repair.append(system)
- message.send_status(
- self, self, '%s Damaged' % system.name.title(), message.important)
+ self.damage_system(random.choice(self._sys))
self.system_damage -= self.system_damage_threshold
- if game.local_player.vessel is self:
- media.play_sound('power_down.wav', min_spacing=2)
- if self.damage_smoke is None and not self.incidental:
- self.damage_smoke = particle.SmokeTrail(self)
if (self.hull_damage > self.disable_factor * self.hull_mass * 0.75 and
self.explosion is None):
message.send_status(self, self, 'Severe Hull Damage', message.critical)
-
+
+ def damage_system(self, system):
+ """Render a system inoperable due to damage and schedule repair"""
+ system.disable()
+ if not self._systems_to_repair:
+ scheduler.schedule(self.repair_system, game.time + self.system_repair_time, self)
+ self._systems_to_repair.append(system)
+ message.send_status(self, self, '%s Damaged' % system.name.title(), message.important)
+ if game.local_player.vessel is self:
+ media.play_sound('power_down.wav', min_spacing=2)
+ if self.damage_smoke is None and not self.incidental:
+ self.damage_smoke = particle.SmokeTrail(self)
+ def repair_system(self):
+ """Repair the earliest damaged system"""
+ if self._systems_to_repair:
+ system = self._systems_to_repair.pop()
+ system.enable()
+ message.send_status(
+ self, self, '%s Repaired' % system.name.title(), message.notice)
+ if self._systems_to_repair:
+ scheduler.schedule(self.repair_system, game.time + self.system_repair_time, self)
+ elif self.damage_smoke is not None:
+ self.damage_smoke.kill()
+
def use_energy(self, energy, partial=False):
"""Consume vessel energy. Return the amount of energy that is available.
If partial is true, return whatever energy is available up to the amount
@@ -620,6 +620,7 @@
name = 'base system'
attr_name = None # Vessel attribute
+ vessel = None
mass = 0
priority = sys.maxint
enabled = True
@@ -732,7 +733,7 @@
>>> s.level
1.0
"""
- if self.vessel.control.show_status:
+ if self.vessel.status_shown:
self.show_shield()
if self.level < self.max_level and self.regeneration and self.enabled:
# Regenerate shields
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-19 07:55:54
|
Revision: 328
http://eos-game.svn.sourceforge.net/eos-game/?rev=328&view=rev
Author: cduncan
Date: 2007-11-18 23:55:50 -0800 (Sun, 18 Nov 2007)
Log Message:
-----------
Fix messages to local player vessel (i.e., system damage)
Modified Paths:
--------------
message.py
Modified: message.py
===================================================================
--- message.py 2007-11-13 07:29:12 UTC (rev 327)
+++ message.py 2007-11-19 07:55:50 UTC (rev 328)
@@ -83,7 +83,7 @@
def send(self, msg):
"""Send the message to its recipient queue"""
- if msg.recipient in (self.local_player, all_players):
+ if msg.recipient in (self.local_player.vessel, self.local_player, all_players):
self._queue_msg(self.local_queue, msg)
def get_next_msg(self, recipient, msg_type=None, current_msg=None):
@@ -117,7 +117,7 @@
>>> msgr.get_next_msg(other)
"""
for msg in self.local_queue:
- if msg.recipient in (recipient, all_players) and (
+ if msg.recipient in (recipient.vessel, recipient, all_players) and (
msg_type is None or isinstance(msg, msg_type)) and (
current_msg is None or msg.priority > current_msg.priority):
self.local_queue.remove(msg)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-13 07:29:16
|
Revision: 327
http://eos-game.svn.sourceforge.net/eos-game/?rev=327&view=rev
Author: cduncan
Date: 2007-11-12 23:29:12 -0800 (Mon, 12 Nov 2007)
Log Message:
-----------
- Update ai control only ever 100ms rather than every frame, except weapon
controls. This is a big performance win and actually results in smoother
flight.
- Make turn control a float so the ai can compensate for less frequent
updates.
- Cress ai uses off-axis beam arc to compensate for loss of precision in
turning.
- Make animations fixed duration with set frame times. Previously the
animation frames were tied to the screen flips, which meant they
didn't look right at different framerates.
- Pre-render fullerene animations for performance, also make them rotate
faster for a more shimmery look.
- Tweak to blit background nebula image a tad faster
- Simplify timing code in main loop by using clock.get_time() rather than
doing our own bookkeeping
- Use sleep(0) in main loop for best compromise in framerate/smoothness
Modified Paths:
--------------
ai.py
beam.py
game.py
media.py
projectile.py
stars.py
vector.py
Modified: ai.py
===================================================================
--- ai.py 2007-11-09 09:14:15 UTC (rev 326)
+++ ai.py 2007-11-13 07:29:12 UTC (rev 327)
@@ -29,6 +29,8 @@
evade_max_health = 0.75
evade_damage_timeout = 2000
evade_max_distance = 350
+
+ update_interval = 100 # millis between updates
def __init__(self, vessel, target=None, objective=None, sensor=None):
Control.__init__(self)
@@ -50,6 +52,7 @@
self.proximity_radius = self.vessel.collision_radius * 5
self.sensor = sensor
self.target_time = 0
+ self.next_update = 0
def seek_position(self, target_position, predict_ahead=2.0):
"""Return desired velocity towards a fixed position
@@ -250,10 +253,11 @@
heading_diff += fullcircle
turn_rate = self.vessel.turn_rate
- if heading_diff > turn_rate / 4:
- self.turn = 1
- elif heading_diff < -turn_rate / 4:
- self.turn = -1
+ max_turn_rate = self.vessel.directional_thrusters.max_turn_rate
+ if (heading_diff > turn_rate * (self.update_interval / 300.0)
+ or heading_diff < -turn_rate * (self.update_interval / 300.0)):
+ self.turn = (heading_diff / max_turn_rate) * 1000 / self.update_interval
+ self.turn = max(min(self.turn, 1), -1)
else:
self.turn = 0
if self.vessel.velocity != desired_velocity:
@@ -342,12 +346,14 @@
self.steerfunc = self.standoff
def update(self):
- self.acquire_target()
- self.select_steerfunc()
- # steering
- desired_heading, desired_velocity = self.steerfunc()
- desired_velocity += self.avoid_vessels()
- self.steer(desired_heading, desired_velocity)
+ if game.time > self.next_update:
+ self.next_update = game.time + self.update_interval
+ self.acquire_target()
+ self.select_steerfunc()
+ # steering
+ desired_heading, desired_velocity = self.steerfunc()
+ desired_velocity += self.avoid_vessels()
+ self.steer(desired_heading, desired_velocity)
# Fire all targeted weapons
for i, weapon in enumerate(self.vessel.weapons):
self.weapons[i] = weapon.targeted
Modified: beam.py
===================================================================
--- beam.py 2007-11-09 09:14:15 UTC (rev 326)
+++ beam.py 2007-11-13 07:29:12 UTC (rev 327)
@@ -54,9 +54,9 @@
self.ray.setCategoryBits(body.nothing)
self.ray.parent = self
self.ray.setCollideBits(body.everything & ~self.gunmount.category)
- if self.arc > 0 and self.gunmount is game.local_player.vessel and game.target.target:
+ if self.arc > 0 and self.gunmount.control.target:
# Track the selected target
- track_angle = self.gunmount.bearing(game.target.target)
+ track_angle = self.gunmount.bearing(self.gunmount.control.target.sprite)
if abs(track_angle) > self.arc:
# limit angle to maximum arc
track_angle /= track_angle / self.arc
Modified: game.py
===================================================================
--- game.py 2007-11-09 09:14:15 UTC (rev 326)
+++ game.py 2007-11-13 07:29:12 UTC (rev 327)
@@ -86,8 +86,7 @@
media.preload_images('data/*.png')
media.preload_images('data/*.gif')
media.create_images()
- media.LargeExplosion.preload_images()
- media.SmallExplosion.preload_images()
+ media.load_animations()
if ship is None and race is None:
stars = StarField(display.rect)
@@ -224,12 +223,8 @@
friends = pygame.sprite.Group()
enemies = pygame.sprite.Group()
next_wave = 0
- this_frame_time = last_frame_time = 1000 / fps
event_handler = event.MainHandler([panel.handler, event.playing_field_handler])
- if windowed:
- sleep_time = 0.01
- else:
- sleep_time = 0.001
+ clock.tick()
while 1:
event_handler.handle_events()
keystate = pygame.key.get_pressed()
@@ -242,14 +237,12 @@
camera.update()
sprite.layers.draw(display.surface)
pygame.display.flip()
- universe.quickStep(this_frame_time / 1000.0)
+ universe.quickStep(clock.get_time() / 1000.0)
if server:
server.step()
last_time = time
time += clock.tick()
- sleep(sleep_time)
- last_frame_time = this_frame_time
- this_frame_time = min(time - last_time, last_frame_time * 3)
+ sleep(0)
fps = clock.get_fps() or fps
if debug and frame_no % 30 == 0:
print body.body_count, len(sprite.layers), len(media._scaled_image_cache), fps
Modified: media.py
===================================================================
--- media.py 2007-11-09 09:14:15 UTC (rev 326)
+++ media.py 2007-11-13 07:29:12 UTC (rev 327)
@@ -152,6 +152,8 @@
colorkey = (0, 0, 0)
initial_alpha = 255
fade_alpha = 0
+ fps = 30
+ cycle = False
@classmethod
def preload_images(cls):
@@ -169,23 +171,23 @@
def __init__(self):
assert self.images is not None, 'Animation not loaded, did you call preload_images()?'
- self.image_iter = iter(self.images)
+ self.start_time = game.time
def next_image(self, apparent_size=1.0):
"""Return the next animation frame or None if the animation is complete"""
- global _scaled_image_cache
- try:
- image = self.image_iter.next()
- except StopIteration:
- return None
- apparent_size = round(apparent_size, 1)
- try:
- return _scaled_image_cache[image, apparent_size]
- except KeyError:
- scaled_image = pygame.transform.rotozoom(image, 0, apparent_size)
- #image.set_colorkey(colorkey, RLEACCEL)
- _scaled_image_cache[image, apparent_size] = scaled_image
- return scaled_image
+ frame = (game.time - self.start_time) / (1000 / self.fps)
+ if self.cycle:
+ frame = frame % len(self.images)
+ if frame < len(self.images):
+ global _scaled_image_cache
+ apparent_size = round(apparent_size, 1)
+ try:
+ return _scaled_image_cache[self.images[frame], apparent_size]
+ except KeyError:
+ scaled_image = pygame.transform.rotozoom(self.images[frame], 0, apparent_size)
+ #image.set_colorkey(colorkey, RLEACCEL)
+ _scaled_image_cache[self.images[frame], apparent_size] = scaled_image
+ return scaled_image
class LargeExplosion(Animation):
@@ -196,6 +198,115 @@
image_glob = 'data/proton-grenade/*.png'
+class FullereneAnimation(Animation):
+ cycle = True
+
+ rpm = 450
+ fps = 45
+ growth = 1.5
+ size = 31
+ max_shadows = 2
+ particles = 3
+ particle_radius = 5
+
+ @classmethod
+ def preload_images(cls):
+ """Render images for animation"""
+ shadows = []
+ cls.images = []
+ frames = cls.fps * 60 / cls.rpm
+ partsize = cls.particle_radius * 2
+ rot_per_frame = vector.fullcircle / frames
+ image = pygame.Surface((cls.size, cls.size))
+ image.fill((0,0,0))
+ for run in range(2):
+ for rot in range(frames):
+ if len(shadows) > cls.max_shadows:
+ shadows = shadows[1:]
+ shadows = [pygame.transform.rotozoom(image, 0, cls.growth)
+ for image in shadows + [image]]
+ image = pygame.Surface((cls.size, cls.size))
+ image.fill((0,0,0))
+ image.set_colorkey((0,0,0))
+ rect = image.get_rect()
+ for i in range(cls.particles):
+ direction_x, direction_y = vector.to_tuple(
+ vector.unit(rot * rot_per_frame + i * vector.fullcircle / cls.particles))
+ part = (int(rect.centerx + direction_x * cls.particle_radius),
+ int(rect.centery + direction_y * cls.particle_radius))
+ bg = random.randint(0, 255)
+ pygame.draw.circle(image, (255, bg, 255-bg), part, cls.particle_radius)
+ bg = random.randint(0, 255)
+ pygame.draw.circle(image, (255, bg, 255-bg), rect.center, cls.particle_radius)
+ if run:
+ rect = shadows[0].get_rect()
+ frame_img = pygame.Surface(rect.size, SRCALPHA, 32)
+ shade = 7
+ for shadow in shadows:
+ shade = shade * 11 / 6
+ shadow.set_colorkey(shadow.get_at((0, 0)))
+ shadow.set_alpha(shade)
+ frame_img.blit(shadow, shadow.get_rect(center=rect.center))
+ frame_img.blit(image, image.get_rect(center=rect.center))
+ frame_img.convert_alpha()
+ frame_img.set_alpha(255, RLEACCEL)
+ cls.images.append(frame_img)
+
+
+class FullereneExplosion(FullereneAnimation):
+ cycle = False
+
+ @classmethod
+ def preload_images(cls):
+ """Render images for animation"""
+ shadows = []
+ cls.images = []
+ frames = cls.fps * 60 / cls.rpm
+ rot_per_frame = vector.fullcircle / frames
+ image = pygame.Surface((cls.size, cls.size))
+ image.fill((0,0,0))
+ fade = 255 / frames
+ for run in range(2):
+ for rot in range(frames):
+ if len(shadows) > cls.max_shadows:
+ shadows = shadows[1:]
+ shadows = [pygame.transform.rotozoom(image, 0, cls.growth)
+ for image in shadows + [image]]
+ image = pygame.Surface((cls.size, cls.size))
+ image.fill((0,0,0))
+ image.set_colorkey((0,0,0))
+ rect = image.get_rect()
+ bright = 255 - rot * fade
+ for i in range(cls.particles):
+ direction_x, direction_y = vector.to_tuple(
+ vector.unit(rot * rot_per_frame + i * vector.fullcircle / cls.particles))
+ part = (int(rect.centerx + direction_x * cls.particle_radius),
+ int(rect.centery + direction_y * cls.particle_radius))
+ bg = random.randint(0, bright)
+ pygame.draw.circle(image, (bright, bg, bright-bg), part, cls.particle_radius)
+ bg = random.randint(0, bright)
+ pygame.draw.circle(image, (bright, bg, bright-bg), rect.center, cls.particle_radius)
+ if run:
+ rect = shadows[0].get_rect()
+ frame_img = pygame.Surface(rect.size, SRCALPHA, 32)
+ shade = 7 + rot * 2
+ for shadow in shadows:
+ shade = shade * 11 / 6
+ shadow.set_colorkey(shadow.get_at((0, 0)))
+ shadow.set_alpha(shade)
+ frame_img.blit(shadow, shadow.get_rect(center=rect.center))
+ frame_img.blit(image, image.get_rect(center=rect.center))
+ frame_img.convert_alpha()
+ frame_img.set_alpha(255, RLEACCEL)
+ cls.images.append(frame_img)
+
+
+def load_animations():
+ LargeExplosion.preload_images()
+ SmallExplosion.preload_images()
+ FullereneAnimation.preload_images()
+ FullereneExplosion.preload_images()
+
def create_images():
def pointy_image(color):
pointy = pygame.Surface((160, 190), SRCALPHA, 32)
Modified: projectile.py
===================================================================
--- projectile.py 2007-11-09 09:14:15 UTC (rev 326)
+++ projectile.py 2007-11-13 07:29:12 UTC (rev 327)
@@ -50,7 +50,7 @@
def update_system(self):
if self.firing and self.shot is None:
self.charge_start = game.time
- self.shot = Fullerene(self.gunmount)
+ self.shot = Fullerene(self.gunmount, self.max_charge)
if self.shot is not None:
self.shot.set_position(self.gunmount.position
+ vector.unit(self.gunmount.heading) * self.offset)
@@ -93,15 +93,10 @@
speed = 600
range = 600
base_damage = 1.0
- particles = 3
- rpm = 250
- growth = 1.5
- max_shadows = 2
- exploding = False
layer = sprite.layers.effects
exploding = False
- def __init__(self, gunmount, net_id=None):
+ def __init__(self, gunmount, max_charge, net_id=None):
self.radius = 1
if gunmount is None:
RoundBody.__init__(self, net_id=net_id)
@@ -109,18 +104,9 @@
RoundBody.__init__(self, gunmount.position, net_id=net_id)
self.gunmount = gunmount
self.charge = 0
+ self.max_charge = max_charge
self.distance = 0
- self.distance_per_frame = self.speed / game.fps
- self.partangle = fullcircle/self.particles
- self.rot_per_frame = self.rpm * fullcircle / (game.fps * 60)
- self.rot = 0
- self.step = range(self.particles)
- self.colormax = 255
- self.image = pygame.Surface((31, 31))
- self.image.fill((0,0,0))
- self.image.set_colorkey((0,0,0))
- self.rect = self.image.get_rect()
- self.shadows = []
+ self.animation = media.FullereneAnimation()
def get_state(self):
state = RoundBody.get_state(self)
@@ -139,58 +125,28 @@
self.partsize = max(self.charge * .45, 1)
self.apparent_size, screen_pos = vector.to_screen(self.position)
- self.rect.center = vector.to_tuple(screen_pos)
- if self.velocity:
- self.distance += self.distance_per_frame
- if self.range - self.distance < self.distance_per_frame * 10:
- self.colormax = int(self.colormax * 0.85)
- if self.distance >= self.range:
- self.kill()
- if len(self.shadows) > self.max_shadows:
- self.shadows = self.shadows[1:]
- self.shadows = [
- pygame.transform.rotozoom(image, 0, self.growth)
- for image in self.shadows + [self.image]]
- rect = self.image.get_rect()
- self.image.fill((0,0,0))
- if not self.exploding:
- partsize = self.partsize * self.apparent_size
- bg = random.randint(0, self.colormax)
- self.image.fill(
- (self.colormax, bg, self.colormax-bg), (rect.center, (partsize, partsize)))
- if partsize >= 1:
- for i in self.step:
- direction_x, direction_y = vector.to_tuple(vector.unit(self.rot))
- part = (rect.centerx + direction_x * partsize,
- rect.centery + direction_y * partsize)
- bg = random.randint(0, self.colormax)
- pygame.draw.circle(
- self.image, (self.colormax, bg, self.colormax-bg), part, partsize)
- self.rot += self.partangle
- self.rot += self.rot_per_frame
+ if self.velocity and vector.distance(self.start_position, self.position) > self.range:
+ self.kill()
+ if not self.gunmount.alive() and not self.exploding:
+ self.exploding = True
+ self.animation = media.FullereneExplosion()
+ image = self.animation.next_image(self.apparent_size * self.charge / self.max_charge)
+ if image is not None:
+ self.image = image
+ self.rect = self.image.get_rect(center=vector.to_tuple(screen_pos))
else:
- if self.exploding > self.max_shadows + 2:
- self.kill()
- self.exploding += 1
+ self.kill()
def launch(self):
self.set_velocity(vector.unit(self.gunmount.heading) * self.speed + self.gunmount.velocity)
self.setup_collision(body.nothing, everything & ~self.gunmount.category)
+ self.start_position = self.gunmount.position
media.play_sound('fullerene.wav', position=self.position)
-
- def draw(self, surface):
- shade = 7 + self.exploding * 3
- for shadow in self.shadows:
- shade = shade * 11 / 6
- shadow.set_colorkey(shadow.get_at((0, 0)))
- shadow.set_alpha(shade)
- surface.blit(shadow, shadow.get_rect(center=self.rect.center))
- surface.blit(self.image, self.image.get_rect(center=self.rect.center))
- return self.rect
def collide(self, other, contacts):
if not self.exploding:
- self.exploding = 1
+ self.exploding = True
+ self.animation = media.FullereneExplosion()
self.set_velocity(other.velocity)
other.damage((self.charge + self.base_damage)**2)
if other.explosion is None:
Modified: stars.py
===================================================================
--- stars.py 2007-11-09 09:14:15 UTC (rev 326)
+++ stars.py 2007-11-13 07:29:12 UTC (rev 327)
@@ -57,6 +57,7 @@
self.nebula_image = pygame.transform.rotozoom(
self.nebula_image, 30.0,
float(rect.width) / float(camera.Camera.virtual_width))
+ self.nebula_image.set_colorkey(self.nebula_image.get_at([0, 0]))
self.nebula_image.set_alpha(255, pygame.RLEACCEL)
rect = self.nebula_image.get_rect(center=rect.center)
self.nebula_pos = [float(rect.left), float(rect.top)]
Modified: vector.py
===================================================================
--- vector.py 2007-11-09 09:14:15 UTC (rev 326)
+++ vector.py 2007-11-13 07:29:12 UTC (rev 327)
@@ -72,7 +72,6 @@
error = distance(screen_pos, approx_screen_pos)
if error < slop:
return last_pos
- print approx_screen_pos, screen_pos, last_error, error
if error > last_error:
shift = (screen_pos - approx_screen_pos) * size
approx_pos = last_pos
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-09 09:14:17
|
Revision: 326
http://eos-game.svn.sourceforge.net/eos-game/?rev=326&view=rev
Author: cduncan
Date: 2007-11-09 01:14:15 -0800 (Fri, 09 Nov 2007)
Log Message:
-----------
Changes to lotus fullerene cannon:
- New alpha blended eye-candy
- Fullerene charges in view now, which helps with timing shots
and aiming, plus it looks cool.
- Fullerene draw energy as it charges rather than when fired
- Set min energy higher
Modified Paths:
--------------
projectile.py
vessels/naree/lotus
Modified: projectile.py
===================================================================
--- projectile.py 2007-11-08 22:47:41 UTC (rev 325)
+++ projectile.py 2007-11-09 09:14:15 UTC (rev 326)
@@ -43,24 +43,29 @@
self.max_charge_time = float(max_charge_time)
self.efficiency = float(efficiency)
self.charge_start = None
- self.charge = 0
+ self.shot = None
self.gunmount = gunmount
+ self.offset = self.gunmount.collision_radius * 1.6
def update_system(self):
- if (self.firing and (self.charge_start is None
- or game.time - self.charge_start < self.max_charge_time * 1000)):
- if self.charge_start is None:
- self.charge_start = game.time
- self.charge = min(self.charge + self.charge_rate / game.fps, self.max_charge)
- elif self.charge_start and self.charge >= self.min_charge:
- desired_energy = (self.charge+1)**2 / self.efficiency
- energy = self.gunmount.use_energy(desired_energy, partial=True)
- if energy:
- Fullerene(self.charge * energy / desired_energy, self.gunmount)
- self.charge = 0
- elif not self.firing:
- self.charge = 0
- self.charge_start = None
+ if self.firing and self.shot is None:
+ self.charge_start = game.time
+ self.shot = Fullerene(self.gunmount)
+ if self.shot is not None:
+ self.shot.set_position(self.gunmount.position
+ + vector.unit(self.gunmount.heading) * self.offset)
+ if self.firing:
+ old_charge_cost = (self.shot.charge + 1)**2 / self.efficiency
+ new_charge = min(self.shot.charge + self.charge_rate / game.fps, self.max_charge)
+ new_charge_cost = (new_charge + 1)**2 / self.efficiency
+ if self.gunmount.use_energy(new_charge_cost - old_charge_cost):
+ self.shot.charge = new_charge
+ elif self.shot.charge >= self.min_charge:
+ self.shot.launch()
+ self.shot = None
+ else: # Not charged enough to fire
+ self.shot.kill()
+ self.shot = None
@property
def targeted(self):
@@ -72,14 +77,13 @@
or not target.category & everything & ~self.gunmount.category):
return False
target_dist = vector.distance(target.position, self.gunmount.position)
- if self.firing:
- if (self.charge >= self.max_charge / 1.5
+ if self.shot is not None:
+ if (self.shot.charge >= self.max_charge / 1.5
and self.gunmount.bearing(target) < (diagonal / 4.0)
and target_dist < Fullerene.range * 2):
return False
else:
- return (game.time - self.charge_start < self.max_charge_time * 1000
- and self.gunmount.energy > 150)
+ return True
else:
return target_dist < Fullerene.range * 1.25
@@ -89,32 +93,34 @@
speed = 600
range = 600
base_damage = 1.0
- particles = 4
- rpm = 80
+ particles = 3
+ rpm = 250
+ growth = 1.5
+ max_shadows = 2
exploding = False
layer = sprite.layers.effects
+ exploding = False
- def __init__(self, charge, gunmount, net_id=None):
- self.mass = charge
- self.radius = max(charge, 1)
+ def __init__(self, gunmount, net_id=None):
+ self.radius = 1
if gunmount is None:
RoundBody.__init__(self, net_id=net_id)
else:
- RoundBody.__init__(
- self, gunmount.position,
- vector.unit(gunmount.heading) * self.speed + gunmount.velocity,
- collides_with=everything & ~gunmount.category,
- net_id=net_id)
- self.charge = charge
+ RoundBody.__init__(self, gunmount.position, net_id=net_id)
+ self.gunmount = gunmount
+ self.charge = 0
self.distance = 0
self.distance_per_frame = self.speed / game.fps
- self.partsize = max(charge * .6, 2)
self.partangle = fullcircle/self.particles
self.rot_per_frame = self.rpm * fullcircle / (game.fps * 60)
self.rot = 0
self.step = range(self.particles)
self.colormax = 255
- media.play_sound('fullerene.wav', position=self.position)
+ self.image = pygame.Surface((31, 31))
+ self.image.fill((0,0,0))
+ self.image.set_colorkey((0,0,0))
+ self.rect = self.image.get_rect()
+ self.shadows = []
def get_state(self):
state = RoundBody.get_state(self)
@@ -129,40 +135,63 @@
self.position = vector.vector2(*self.body.getPosition()[:2])
self.velocity = vector.vector2(*self.body.getLinearVel()[:2])
self.heading = self.get_heading()
- # place self relative to the camera at proper zoom level
+ self.radius = max(self.charge, 1)
+ self.partsize = max(self.charge * .45, 1)
self.apparent_size, screen_pos = vector.to_screen(self.position)
+
self.rect.center = vector.to_tuple(screen_pos)
- self.distance += self.distance_per_frame
- if self.range - self.distance < self.distance_per_frame * 10:
- self.colormax = int(self.colormax * 0.85)
- if self.distance >= self.range:
- self.kill()
+ if self.velocity:
+ self.distance += self.distance_per_frame
+ if self.range - self.distance < self.distance_per_frame * 10:
+ self.colormax = int(self.colormax * 0.85)
+ if self.distance >= self.range:
+ self.kill()
+ if len(self.shadows) > self.max_shadows:
+ self.shadows = self.shadows[1:]
+ self.shadows = [
+ pygame.transform.rotozoom(image, 0, self.growth)
+ for image in self.shadows + [self.image]]
+ rect = self.image.get_rect()
+ self.image.fill((0,0,0))
+ if not self.exploding:
+ partsize = self.partsize * self.apparent_size
+ bg = random.randint(0, self.colormax)
+ self.image.fill(
+ (self.colormax, bg, self.colormax-bg), (rect.center, (partsize, partsize)))
+ if partsize >= 1:
+ for i in self.step:
+ direction_x, direction_y = vector.to_tuple(vector.unit(self.rot))
+ part = (rect.centerx + direction_x * partsize,
+ rect.centery + direction_y * partsize)
+ bg = random.randint(0, self.colormax)
+ pygame.draw.circle(
+ self.image, (self.colormax, bg, self.colormax-bg), part, partsize)
+ self.rot += self.partangle
+ self.rot += self.rot_per_frame
+ else:
+ if self.exploding > self.max_shadows + 2:
+ self.kill()
+ self.exploding += 1
+ def launch(self):
+ self.set_velocity(vector.unit(self.gunmount.heading) * self.speed + self.gunmount.velocity)
+ self.setup_collision(body.nothing, everything & ~self.gunmount.category)
+ media.play_sound('fullerene.wav', position=self.position)
+
def draw(self, surface):
- partsize = self.partsize * self.apparent_size
- radius = self.charge / 2 * self.apparent_size
- bg = random.randint(0, self.colormax)
- surface.fill((self.colormax, bg, self.colormax-bg),
- (self.rect.center, (partsize, partsize)))
- if radius >= 2:
- rects = [self.rect]
- for i in self.step:
- direction_x, direction_y = vector.to_tuple(vector.unit(self.rot))
- part = (self.rect.centerx + direction_x * radius,
- self.rect.centery + direction_y * radius,
- partsize, partsize)
- rects.append(part)
- bg = random.randint(0, self.colormax)
- surface.fill((self.colormax, bg, self.colormax-bg) , part)
- self.rot += self.partangle
- self.rot += self.rot_per_frame
- return Rect(rects[0]).unionall(rects)
- else:
- return self.rect
+ shade = 7 + self.exploding * 3
+ for shadow in self.shadows:
+ shade = shade * 11 / 6
+ shadow.set_colorkey(shadow.get_at((0, 0)))
+ shadow.set_alpha(shade)
+ surface.blit(shadow, shadow.get_rect(center=self.rect.center))
+ surface.blit(self.image, self.image.get_rect(center=self.rect.center))
+ return self.rect
def collide(self, other, contacts):
- if self.alive():
- self.kill()
+ if not self.exploding:
+ self.exploding = 1
+ self.set_velocity(other.velocity)
other.damage((self.charge + self.base_damage)**2)
if other.explosion is None:
media.play_sound('hit.wav', volume=(self.charge/5), position=self.position)
Modified: vessels/naree/lotus
===================================================================
--- vessels/naree/lotus 2007-11-08 22:47:41 UTC (rev 325)
+++ vessels/naree/lotus 2007-11-09 09:14:15 UTC (rev 326)
@@ -30,7 +30,7 @@
[projectile.FullereneCannon]
charge_rate: 12
-min_charge: 1.5
+min_charge: 4
max_charge: 11
max_charge_time: 4
efficiency: 0.95
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-08 22:47:45
|
Revision: 325
http://eos-game.svn.sourceforge.net/eos-game/?rev=325&view=rev
Author: cduncan
Date: 2007-11-08 14:47:41 -0800 (Thu, 08 Nov 2007)
Log Message:
-----------
Reduce fullerene shot detail at small apparent sizes
Modified Paths:
--------------
projectile.py
Modified: projectile.py
===================================================================
--- projectile.py 2007-11-08 22:47:14 UTC (rev 324)
+++ projectile.py 2007-11-08 22:47:41 UTC (rev 325)
@@ -141,21 +141,24 @@
def draw(self, surface):
partsize = self.partsize * self.apparent_size
radius = self.charge / 2 * self.apparent_size
- rects = [self.rect]
bg = random.randint(0, self.colormax)
surface.fill((self.colormax, bg, self.colormax-bg),
(self.rect.center, (partsize, partsize)))
- for i in self.step:
- direction_x, direction_y = vector.to_tuple(vector.unit(self.rot))
- part = (self.rect.centerx + direction_x * radius,
- self.rect.centery + direction_y * radius,
- partsize, partsize)
- rects.append(part)
- bg = random.randint(0, self.colormax)
- surface.fill((self.colormax, bg, self.colormax-bg) , part)
- self.rot += self.partangle
- self.rot += self.rot_per_frame
- return Rect(rects[0]).unionall(rects)
+ if radius >= 2:
+ rects = [self.rect]
+ for i in self.step:
+ direction_x, direction_y = vector.to_tuple(vector.unit(self.rot))
+ part = (self.rect.centerx + direction_x * radius,
+ self.rect.centery + direction_y * radius,
+ partsize, partsize)
+ rects.append(part)
+ bg = random.randint(0, self.colormax)
+ surface.fill((self.colormax, bg, self.colormax-bg) , part)
+ self.rot += self.partangle
+ self.rot += self.rot_per_frame
+ return Rect(rects[0]).unionall(rects)
+ else:
+ return self.rect
def collide(self, other, contacts):
if self.alive():
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-08 22:47:16
|
Revision: 324
http://eos-game.svn.sourceforge.net/eos-game/?rev=324&view=rev
Author: cduncan
Date: 2007-11-08 14:47:14 -0800 (Thu, 08 Nov 2007)
Log Message:
-----------
- Build base level 2 on planets with >5 resource gen
- Fix bug in explode() signature in Vessel
Modified Paths:
--------------
vessel.py
Modified: vessel.py
===================================================================
--- vessel.py 2007-11-07 08:22:34 UTC (rev 323)
+++ vessel.py 2007-11-08 22:47:14 UTC (rev 324)
@@ -568,12 +568,12 @@
else:
return 0
- def explode(self):
+ def explode(self, sound='explode.wav'):
if self is game.local_player.vessel:
game.local_player.vessel = EscapePod(self)
game.camera.follow(game.local_player.vessel)
media.play_sound('launch.wav')
- body.RoundBody.explode(self)
+ body.RoundBody.explode(self, sound)
def kill(self):
for system in self._sys:
@@ -1249,7 +1249,9 @@
else:
import base # Avoid circular imports
# Landing cycle complete, build a base
- self.planet.base = base.PlanetaryBase(self.planet, game.local_player)
+
+ self.planet.base = base.PlanetaryBase(self.planet, game.local_player,
+ level=1 + (self.planet.resources >= 5))
message.send_status(self.planet, game.local_player,
'Base esablished on %s' % self.planet.name)
self.vessel.kill()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-07 08:22:35
|
Revision: 323
http://eos-game.svn.sourceforge.net/eos-game/?rev=323&view=rev
Author: cduncan
Date: 2007-11-07 00:22:34 -0800 (Wed, 07 Nov 2007)
Log Message:
-----------
Add a custom hit-and-run ai personality for the cress so it
takes better advantage of its maneuverability and doesn't
just hang out in the line of fire and get killed.
Modified Paths:
--------------
ai.py
vessels/naree/cress
Modified: ai.py
===================================================================
--- ai.py 2007-11-07 08:17:21 UTC (rev 322)
+++ ai.py 2007-11-07 08:22:34 UTC (rev 323)
@@ -387,8 +387,8 @@
class AggroAI(BasicAI):
- evade_min_health = 0.5
- evade_max_health = 0.7
+ evade_min_health = 0.4
+ evade_max_health = 0.5
def evade(self):
"""Head through the target"""
@@ -408,6 +408,16 @@
self.steerfunc = self.standoff
+class HitAndRun(BasicAI):
+
+ evade_min_health = 0.7
+ evade_max_health = 0.75
+ evade_damage_timeout = 1200
+ evade_max_distance = 250
+
+ evade = BasicAI.flee
+
+
class AssaultAI(BasicAI):
def select_steerfunc(self):
Modified: vessels/naree/cress
===================================================================
--- vessels/naree/cress 2007-11-07 08:17:21 UTC (rev 322)
+++ vessels/naree/cress 2007-11-07 08:22:34 UTC (rev 323)
@@ -11,7 +11,7 @@
max_energy: 200
standoff_distance: 125
cost: 125
-ai: Standoffish
+ai: HitAndRun
[vessel.Shield]
max_level: 100
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-07 08:18:09
|
Revision: 322
http://eos-game.svn.sourceforge.net/eos-game/?rev=322&view=rev
Author: cduncan
Date: 2007-11-07 00:17:21 -0800 (Wed, 07 Nov 2007)
Log Message:
-----------
- Add player abstraction to store player game state, such as current
vessel, race, category and owned planets
- Human players can switch ships by targetting a friendly with "t"
and pressing backspace/delete. the ai assumes control of the player's former
vessel
- When the player's ship is destroyed, a small escape pod is ejected
which drifts through space. The escape pod is invulnerable, but
cannot be controlled (it is in fact invisible to other players).
this provides a simple avatar for the player before a new
ship is selected.
Note: these changes likely broke multiplayer, though I did try to
refactor where I could.
Modified Paths:
--------------
ai.py
base.py
beam.py
body.py
event.py
game.py
net.py
panel.py
selection.py
station.py
vessel.py
Added Paths:
-----------
data/astronaut.png
player.py
Modified: ai.py
===================================================================
--- ai.py 2007-11-04 06:03:37 UTC (rev 321)
+++ ai.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -306,7 +306,7 @@
planets = sorted(game.map.planets, key=distance)
# Try for the closest friendly planet first
for planet in planets:
- if planet.base is not None and planet.base.owner.is_friendly(self.vessel):
+ if planet.base is not None and self.vessel.is_friendly(planet.base.owner):
self.objective.add(planet)
return
# Try for the closest neutral planet next
@@ -487,11 +487,18 @@
else:
BasicAI.collide(self, other, contacts)
+def control(vessel, target=None, objective=None, sensor=None):
+ """Return the appropriate ai control instance for the specified vessel"""
+ if sensor is None and vessel.category is not None:
+ sensor = Sensor(vessel, 10000, body.everything & ~vessel.category)
+ sensor.disable()
+ ai_class = globals()[vessel.ai_name]
+ return ai_class(vessel, target, objective, sensor)
class AIVessel(Vessel):
"""Vessel under ai control"""
- def __init__(self, target=None, category=body.foe, objective=None, sensor=None,
+ def __init__(self, target=None, category=None, objective=None, sensor=None,
ai='BasicAI', **kw):
"""
target -- Sprite to intercept and attack if foe.
@@ -500,15 +507,13 @@
sensor -- Sensor object to be used (if omitted one is created just for this vessel)
ai -- class name of ai personality.
"""
- Vessel.__init__(self, **kw)
- self.setup_collision(category, body.everything & ~body.shot)
- if sensor is None:
- sensor = Sensor(self, 10000, body.everything & ~category)
- sensor.disable()
- ai_class = globals()[ai]
- self.control = ai_class(self, target, objective, sensor)
+ Vessel.__init__(self, ai=ai, **kw)
+ if category is not None:
+ self.setup_collision(category, body.everything & ~body.shot)
+ self.control = control(self, target, objective, sensor)
# Make sure we are behind the local player
self.layer.to_back(self)
+
class Sensor:
Modified: base.py
===================================================================
--- base.py 2007-11-04 06:03:37 UTC (rev 321)
+++ base.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -14,8 +14,9 @@
import map
import message
import panel
+import sprite
-class PlanetaryBase:
+class PlanetaryBase(sprite.Sprite):
"""Planetary bases are owned by a player and can build using the planet's
resources. Bases have a level which determines which tings can be built.
In general bases can build three types of things:
@@ -43,14 +44,18 @@
max_build_queue = 6 # Maximum number of queued builders
def __init__(self, planet, owner, level=1, max_level=5):
+ sprite.Sprite.__init__(self)
if isinstance(planet, str):
self.planet = game.map.get_planet(planet_name)
if self.planet is None:
raise map.MapConfigError('Cannot create base, planet "%s" not found in map')
else:
self.planet = planet
+ if self.planet.base is not None:
+ self.planet.base.kill()
self.planet.base = self
self.owner = owner
+ owner.bases.add(self)
self.rally_point = self.planet
if max_level >= level:
self.level = level
Modified: beam.py
===================================================================
--- beam.py 2007-11-04 06:03:37 UTC (rev 321)
+++ beam.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -54,7 +54,7 @@
self.ray.setCategoryBits(body.nothing)
self.ray.parent = self
self.ray.setCollideBits(body.everything & ~self.gunmount.category)
- if self.arc > 0 and self.gunmount is game.local_player and game.target.target:
+ if self.arc > 0 and self.gunmount is game.local_player.vessel and game.target.target:
# Track the selected target
track_angle = self.gunmount.bearing(game.target.target)
if abs(track_angle) > self.arc:
Modified: body.py
===================================================================
--- body.py 2007-11-04 06:03:37 UTC (rev 321)
+++ body.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -22,13 +22,9 @@
# bitmap to determine whether it interacts with another body
# Objects only interact when the category bitmap of one
# intersects the collide bitmap of the other.
-friend = 1
-foe = 2
-shot = 4
-planet = 8
+shot = 1
nothing = 0
everything = 0x7fffffff
-categories = (friend, foe)
body_count = 0 # Counter for debugging
@@ -147,8 +143,10 @@
self.collides_with = collides_with
if game.local_player and self.category & game.local_player.category:
self.offscreen_img = 'pointy-green'
- elif self.category:
+ elif self.category and not self.incidental:
self.offscreen_img = 'pointy-red'
+ else:
+ self.offscreen_img = None
def __del__(self):
if self.geom is not None and game.collision_space.query(self.geom):
Added: data/astronaut.png
===================================================================
(Binary files differ)
Property changes on: data/astronaut.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Modified: event.py
===================================================================
--- event.py 2007-11-04 06:03:37 UTC (rev 321)
+++ event.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -180,7 +180,7 @@
def select_nearest_friends(self):
"""Select friends nearest to player"""
- selection.group.select_near_vessel(game.local_player, game.local_player.category)
+ selection.group.select_near_vessel(game.local_player.vessel, game.local_player.category)
def constrain_selected_friends(self):
"""Constrain friend selection by vessel class"""
@@ -205,8 +205,14 @@
def target_local_player(self):
"""Target your ship"""
- game.target.select(game.local_player)
+ game.target.select(game.local_player.vessel)
+ def switch_local_player_vessel(self):
+ """Change ships"""
+ target = game.target.selected.sprite
+ if target:
+ game.local_player.switch_vessel(target)
+
def __init__(self):
sprite.Sprite.__init__(self, sprite.layers.ui)
key_map = {
@@ -219,6 +225,7 @@
'p': self.target_nearest_planet,
't': self.target_nearest_friend,
'y': self.target_local_player,
+ '\b': self.switch_local_player_vessel,
}
self.key_map = dict((ord(key), method) for key, method in key_map.items())
@@ -240,7 +247,8 @@
and not vessel.incidental):
if event.button == 1:
# Left-click, select
- if vessel.is_friendly(game.local_player) and vessel is not game.local_player:
+ if vessel is not game.local_player.vessel and vessel.is_friendly(
+ game.local_player.vessel):
selection.group.select(vessel)
else:
game.target.select(vessel)
Modified: game.py
===================================================================
--- game.py 2007-11-04 06:03:37 UTC (rev 321)
+++ game.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -55,6 +55,7 @@
from media import load_image
from map import Map
from camera import Camera
+ import player
global universe, collision_space, map, starfield
global fps, avg_fps, clock, time, local_player, camera, ai
global target, windowed, messenger, send_msg
@@ -148,21 +149,20 @@
ship_choice.kill()
time = 0
- # Establish player
- local_player = vessel.KeyboardControl.new_player(race, ship)
- local_player.number = random.choice([1, 2]) # XXX Fix for real multiplayer
- camera = Camera(local_player)
- target = selection.Target(local_player)
+ # Establish player and ship, for now randomly select player number 1 or 2
+ local_player = player.HumanPlayer(random.choice([1, 2]), race, ship)
+ camera = Camera(local_player.vessel)
+ target = selection.Target(local_player.vessel)
# Setup background and map
starfield = StarField(display.rect)
map = Map('sol')
-
+
# Find the base and put the player next to it
for planet in map.planets:
if planet.base is not None and planet.base.owner is local_player:
offset = vector.vector2(planet.collision_radius * 1.25, planet.collision_radius * 1.25)
- local_player.set_position(planet.position + offset)
+ local_player.vessel.set_position(planet.position + offset)
# Setup local messaging
message.init(local_player)
@@ -257,21 +257,21 @@
## Temporary wave-based game play ##
if not client:
if time > next_wave:
- target = local_player
- target_race = target.race
+ target = local_player.vessel
wave_race = random.choice([r for r in ['naree', 'rone', 'sc']
- if r != target_race])
+ if r != local_player.race])
+ wave_category = local_player.category<<2
if not target.alive():
target = random.choice(map.planets)
position = vector.unit(random.random() * vector.fullcircle) * 1000
warship = random.random() * frame_no > 800
if warship and len(enemies) < max_fleet_size:
if wave_race == 'rone':
- ai = AIVessel.load('vessels/rone/draken')
+ ai = AIVessel.load('vessels/rone/draken', category=wave_category)
elif wave_race == 'naree':
- ai = AIVessel.load('vessels/naree/lotus')
+ ai = AIVessel.load('vessels/naree/lotus', category=wave_category)
elif wave_race == 'sc':
- ai = AIVessel.load('vessels/sc/pegasus')
+ ai = AIVessel.load('vessels/sc/pegasus', category=wave_category)
ai.set_position(target.position + position)
enemies.add(ai)
else:
@@ -281,20 +281,20 @@
while ((friendly or random.random() * frame_no > barrier)
and len(friends) < max_fleet_size):
if random.random() * frame_no < barrier * 6:
- if target_race == 'rone':
+ if local_player.race == 'rone':
ship = 'vessels/rone/drach'
- elif target_race == 'naree':
+ elif local_player.race == 'naree':
ship = 'vessels/naree/cress'
- elif target_race == 'sc':
+ elif local_player.race == 'sc':
ship = 'vessels/sc/striker'
else:
- if target_race == 'rone':
+ if local_player.race == 'rone':
ship = 'vessels/rone/draken'
- elif target_race == 'naree':
+ elif local_player.race == 'naree':
ship = 'vessels/naree/lotus'
- elif target_race == 'sc':
+ elif local_player.race == 'sc':
ship = 'vessels/sc/pegasus'
- friend = AIVessel.load(ship, objective=target, category=body.friend)
+ friend = AIVessel.load(ship, objective=target, category=local_player.category)
friend.set_position(target.position - position)
friends.add(friend)
barrier *= 2
@@ -304,11 +304,11 @@
if warship and random.random() * frame_no < barrier:
break
if wave_race == 'rone':
- ai = AIVessel.load('vessels/rone/drach')
+ ai = AIVessel.load('vessels/rone/drach', category=wave_category)
elif wave_race == 'naree':
- ai = AIVessel.load('vessels/naree/cress')
+ ai = AIVessel.load('vessels/naree/cress', category=wave_category)
elif wave_race == 'sc':
- ai = AIVessel.load('vessels/sc/striker')
+ ai = AIVessel.load('vessels/sc/striker', category=wave_category)
ai.set_position(target.position + position)
enemies.add(ai)
warship = True
Modified: net.py
===================================================================
--- net.py 2007-11-04 06:03:37 UTC (rev 321)
+++ net.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -87,8 +87,9 @@
net_id, ship, keystate = client_state
player = game.objects.get(net_id)
if player is None:
- player = vessel.KeyboardControl.new_player(net_id=net_id, ship=ship)
- player.setup_collision(body.foe, body.nothing)
+ player = Vessel.load(ship, net_id=net_id)
+ player.control = vessel.KeyboardControl()
+ player.setup_collision(game.local_player.category<<2, body.nothing)
player.control.set_keystate(keystate)
def step(self):
@@ -145,7 +146,7 @@
return create_func(*args, **kw)
def get_client_state(self, keystate):
- return game.local_player.net_id, game.local_player.vessel_class, keystate
+ return game.local_player.vessel.net_id, game.local_player.vessel.vessel_class, keystate
def set_game_state(self, game_state):
# update objects
Modified: panel.py
===================================================================
--- panel.py 2007-11-04 06:03:37 UTC (rev 321)
+++ panel.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -305,7 +305,7 @@
def update_vessel(self, vessel):
if not vessel.incidental:
- if vessel.is_friendly(game.local_player):
+ if vessel.is_friendly(game.local_player.vessel):
if vessel.selected:
color = (255, 255, 255)
else:
Added: player.py
===================================================================
--- player.py (rev 0)
+++ player.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -0,0 +1,67 @@
+## Eos, Dawn of Light -- A Space Opera
+## Copyright (c) 2007 Casey Duncan and contributors
+## See LICENSE.txt for licensing details
+
+# Player state
+# $Id$
+
+import glob
+import random
+import pygame
+import game
+import body
+from vessel import Vessel, KeyboardControl
+import ai
+import selection
+
+class Player:
+
+ number = None # Player number
+ race = None # Player race
+ category = None # Player category bitmap
+ vessel = None # Current player vessel
+ control = None # Player's vessel controls
+ bases = None # Bases owned by player
+
+
+class HumanPlayer(Player):
+ """A player presumably controlled by a hunam"""
+
+ def __init__(self, number, race, vessel_class):
+ self.number = number
+ self.race = race
+ self.category = 2**number
+ self.bases = pygame.sprite.Group()
+ self.control = KeyboardControl()
+ self.create_vessel(vessel_class)
+
+ def create_vessel(self, vessel_class=None, net_id=None):
+ """Create a vessel for this player"""
+ config = random.choice(glob.glob('vessels/%s/%s' % (self.race or '*', vessel_class or '*')))
+ self.race = config.split('/')[1]
+ self.vessel = Vessel.load(config, race=self.race, net_id=net_id)
+ self.vessel.setup_collision(self.category, body.nothing)
+ self.vessel.control = self.control
+ return self.vessel
+
+ def switch_vessel(self, vessel):
+ """Make the specified vessel the player's current vessel. If the player
+ already has a current vessel, it is put under ai control
+ """
+ if vessel.category == self.vessel.category and vessel is not self.vessel:
+ if isinstance(self.vessel, Vessel):
+ # Replace the player control with the appropriate ai control
+ self.vessel.control = ai.control(
+ self.vessel, target=game.target.selected.sprite, objective=vessel)
+ self.vessel.setup_collision(self.category, body.everything & ~body.shot)
+ else:
+ # We don't currently have a real vessel, just an avatar
+ self.vessel.kill()
+ vessel.setup_collision(self.category, body.nothing)
+ vessel.control = self.control
+ vessel.layer.to_front(vessel)
+ game.camera.follow(vessel)
+ game.target.kill()
+ game.target = selection.Target(vessel) # ick, make me better
+ self.vessel = vessel
+
Property changes on: player.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: selection.py
===================================================================
--- selection.py 2007-11-04 06:03:37 UTC (rev 321)
+++ selection.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -152,7 +152,7 @@
by_class = {}
for spr in sprite.layers.vessels:
if (isinstance(spr, Vessel) and spr.category & category and in_rect(spr.rect)
- and spr is not game.local_player and not spr.incidental):
+ and spr is not game.local_player.vessel and not spr.incidental):
self.selected.add(spr)
if spr.vessel_class not in by_class:
by_class[spr.vessel_class] = pygame.sprite.Group()
@@ -170,7 +170,7 @@
for spr in sprite.layers.vessels:
if (isinstance(spr, Vessel) and spr.category & category
and in_rect(vector.to_tuple(spr.position))
- and spr is not game.local_player and not spr.incidental):
+ and spr is not game.local_player.vessel and not spr.incidental):
self.selected.add(spr)
if spr.vessel_class not in by_class:
by_class[spr.vessel_class] = pygame.sprite.Group()
Modified: station.py
===================================================================
--- station.py 2007-11-04 06:03:37 UTC (rev 321)
+++ station.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -123,12 +123,12 @@
self.collision_frame = 0
def update(self):
- if vector.distance(game.local_player.position, self.planet.position) > self.distance:
+ if vector.distance(game.local_player.vessel.position, self.planet.position) > self.distance:
# Player is outside of station "orbit", cancel placement
self.kill()
return
self.position = self.planet.position + vector.unit(
- game.local_player.heading) * self.distance
+ game.local_player.vessel.heading) * self.distance
self.geom.setPosition(vector.to_tuple3(self.position))
self.heading = vector.radians(self.planet.position - self.position)
apparent_size, screen_pos = vector.to_screen(self.position)
Modified: vessel.py
===================================================================
--- vessel.py 2007-11-04 06:03:37 UTC (rev 321)
+++ vessel.py 2007-11-07 08:17:21 UTC (rev 322)
@@ -9,7 +9,6 @@
import body
import ConfigParser
import game
-import glob
import math
import pygame
import random
@@ -58,24 +57,6 @@
self.weapons[1] = keystate[K_LSHIFT]
self.target = game.target.selected
- @classmethod
- def new_player(cls, race=None, ship=None, net_id=None):
- if ship is not None:
- shipglob = 'vessels/*/%s' % ship
- elif race is not None:
- shipglob = 'vessels/%s/*' % race
- else:
- shipglob = 'vessels/*/*'
- ships = glob.glob(shipglob)
- assert len(ships) > 0, 'Invalid race/ship: %r/%r' % (race, ship)
- ship = random.choice(ships)
- race = ship.split('/')[1]
- player = Vessel.load(ship, race=race, net_id=net_id)
- player.setup_collision(body.friend, body.nothing)
- player.control = KeyboardControl()
- return player
-
-
class VesselConfigError(Exception):
"""Vessel configuration file error"""
@@ -178,6 +159,7 @@
self._repair_time = None
self.damage_time = 0
self.race = race
+ self.ai_name = ai
self.incidental = str(incidental) not in ('0', 'False')
@classmethod
@@ -551,7 +533,7 @@
message.send_status(
self, self, '%s Damaged' % system.name.title(), message.important)
self.system_damage -= self.system_damage_threshold
- if game.local_player is self:
+ if game.local_player.vessel is self:
media.play_sound('power_down.wav', min_spacing=2)
if self.damage_smoke is None and not self.incidental:
self.damage_smoke = particle.SmokeTrail(self)
@@ -586,6 +568,13 @@
else:
return 0
+ def explode(self):
+ if self is game.local_player.vessel:
+ game.local_player.vessel = EscapePod(self)
+ game.camera.follow(game.local_player.vessel)
+ media.play_sound('launch.wav')
+ body.RoundBody.explode(self)
+
def kill(self):
for system in self._sys:
if hasattr(system, 'kill'):
@@ -1274,6 +1263,30 @@
vector.distance(target.position, self.vessel.position) < target.collision_radius / 2)
+class EscapePod(body.RoundBody):
+
+ max_speed = 25
+ layer = sprite.layers.vessels
+ collision_radius = 0
+
+ def __init__(self, launch_vessel):
+ body.RoundBody.__init__(self,
+ position=launch_vessel.position,
+ velocity=(launch_vessel.velocity
+ - vector.normal(-launch_vessel.velocity) * self.max_speed),
+ heading=launch_vessel.heading + vector.halfcircle,
+ image_name='astronaut.png')
+ self.turn_rate = random.gauss(0, 0.4)
+ media.play_sound('launch.wav')
+ self.category = launch_vessel.category
+
+ def update(self):
+ if vector.length(self.velocity) > self.max_speed:
+ # If we are overspeed, bleed off a little
+ self.set_velocity(self.velocity * 0.98)
+ body.RoundBody.update(self)
+
+
def resolve(dotted_name):
"""Return the object corresponding to the dotted module/object name
pair specified.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-04 06:03:48
|
Revision: 321
http://eos-game.svn.sourceforge.net/eos-game/?rev=321&view=rev
Author: cduncan
Date: 2007-11-03 23:03:37 -0700 (Sat, 03 Nov 2007)
Log Message:
-----------
- Assault ships now called assault transports, since they double as transports
- Add sc assault transport ship: aurora
- Even out stats for assault vessels, improve turning thrust
- Add ability to direct ships to arbitrary locations in space on the
map and playing field
Modified Paths:
--------------
base.py
body.py
event.py
game.py
ideas/vessels.txt
panel.py
selection.py
vector.py
vessel.py
vessels/naree/corde
vessels/rone/kraken
Added Paths:
-----------
art/sc/aurora.xcf
data/aurora.png
vessels/sc/aurora
Added: art/sc/aurora.xcf
===================================================================
(Binary files differ)
Property changes on: art/sc/aurora.xcf
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: base.py
===================================================================
--- base.py 2007-11-04 05:58:12 UTC (rev 320)
+++ base.py 2007-11-04 06:03:37 UTC (rev 321)
@@ -36,7 +36,7 @@
# base level required to build certain vessels
vessel_level = {
'fighter': 1,
- 'assault ship': 1,
+ 'assault transport': 1,
'warship': 2,
}
_owner2number = {} # Map of owner => last base number
Modified: body.py
===================================================================
--- body.py 2007-11-04 05:58:12 UTC (rev 320)
+++ body.py 2007-11-04 06:03:37 UTC (rev 321)
@@ -52,6 +52,7 @@
offscreen_img = None # image to point to offscreen sprite
xplode_animation = media.LargeExplosion
+ explosion = None
layer = () # Sprite group(s) to add body to
rect = None
@@ -94,7 +95,6 @@
self.rect = pygame.Rect((0, 0, self.radius*2, self.radius*2))
self.enabled = True
self.on_screen = True
- self.explosion = None
self.apparent_size = 1.0
self.net_id = net_id
self.image_name = image_name
Added: data/aurora.png
===================================================================
(Binary files differ)
Property changes on: data/aurora.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Modified: event.py
===================================================================
--- event.py 2007-11-04 05:58:12 UTC (rev 320)
+++ event.py 2007-11-04 06:03:37 UTC (rev 321)
@@ -262,8 +262,14 @@
# Right-click, direct
selection.group.set_target(planet)
return True
- # Nothing specific was clicked, just clear the current selected group
- selection.group.select_none()
+ # Nothing specific was clicked
+ if event.button == 1:
+ # left-click in space, just clear the current selected group
+ selection.group.select_none()
+ elif event.button == 3:
+ # right-click in space, make a target marker and direct ships there
+ marker = selection.Marker(vector.to_map(vector.vector2(*event.pos)))
+ selection.group.set_target(marker)
return True
def mouse_drag(self, event, start_pos, end_pos):
Modified: game.py
===================================================================
--- game.py 2007-11-04 05:58:12 UTC (rev 320)
+++ game.py 2007-11-04 06:03:37 UTC (rev 321)
@@ -102,6 +102,7 @@
Vessel.load('vessels/naree/corde'),
Vessel.load('vessels/sc/pegasus'),
Vessel.load('vessels/sc/striker'),
+ Vessel.load('vessels/sc/aurora'),
]
import math
font = pygame.font.Font('fonts/forgottenfuturist/Forgotbi.ttf', 24)
Modified: ideas/vessels.txt
===================================================================
--- ideas/vessels.txt 2007-11-04 05:58:12 UTC (rev 320)
+++ ideas/vessels.txt 2007-11-04 06:03:37 UTC (rev 321)
@@ -73,11 +73,11 @@
Naree Cress: Lepton beam
Human Striker: Burst-fire rockets
-Secondary Weapon
-----------------
+Secondary Weapon/Ability
+------------------------
Rone Drach: Phase disruptors reduce shield regeneration and deflector screen efficiency
-Naree Cress: Energy mines sap energy from enemy craft
-Human Striker: Higgs well mines slow enemy movement
+Naree Cress: Rush ability allows them to approach unhindered with immediacy
+Human Striker: Plasmonic mines are invisible when not in motion, cause severe damage in an area upon contact.
Warships
========
Modified: panel.py
===================================================================
--- panel.py 2007-11-04 05:58:12 UTC (rev 320)
+++ panel.py 2007-11-04 06:03:37 UTC (rev 321)
@@ -358,6 +358,10 @@
# Right-click, direct
selection.group.set_target(planet)
return True
+ if event.button == 3:
+ # right-click in space, make a target marker and direct ships there
+ marker = selection.Marker(vector.vector2(*map_pos))
+ selection.group.set_target(marker)
return True
def draw(self, surface):
@@ -393,7 +397,7 @@
vessel_button_order = {
'fighter': 1,
- 'assault ship': 2,
+ 'assault transport': 2,
'warship': 3,
}
Modified: selection.py
===================================================================
--- selection.py 2007-11-04 05:58:12 UTC (rev 320)
+++ selection.py 2007-11-04 06:03:37 UTC (rev 321)
@@ -14,7 +14,7 @@
import sprite
from vessel import Vessel
import vector
-import staticbody
+import body
class Target(sprite.Sprite):
@@ -213,3 +213,19 @@
group = GroupSelector() # Singleton
+
+class Marker(body.RoundBody):
+ """Position marker for targetting arbitrary positions in space"""
+
+ rect = pygame.Rect(0, 0, 0, 0)
+ velocity = vector.vector2()
+ heading = 0
+ collision_radius = 0
+
+ def __init__(self, position):
+ sprite.Sprite.__init__(self)
+ self.position = position
+
+ def draw(self):
+ return self.rect
+
Modified: vector.py
===================================================================
--- vector.py 2007-11-04 05:58:12 UTC (rev 320)
+++ vector.py 2007-11-04 06:03:37 UTC (rev 321)
@@ -56,6 +56,30 @@
return apparent_size**2, vector2(*camera.rect.center) + (
from_camera * camera.zoom * apparent_size)
+def to_map(screen_pos, slop=50, max_iterations=100):
+ """Return a vector of the approximate map coordinate for the given screen position.
+ Note that without knowing the apparent size at that screen position, there is
+ no unambiguous way to derive the exact map position.
+ """
+ approx_pos = game.camera.position
+ size, approx_screen_pos = to_screen(approx_pos)
+ shift = (screen_pos - approx_screen_pos) * size
+ last_error = distance(screen_pos, approx_screen_pos)
+ while max_iterations > 0:
+ last_pos = approx_pos
+ approx_pos += shift
+ size, approx_screen_pos = to_screen(approx_pos)
+ error = distance(screen_pos, approx_screen_pos)
+ if error < slop:
+ return last_pos
+ print approx_screen_pos, screen_pos, last_error, error
+ if error > last_error:
+ shift = (screen_pos - approx_screen_pos) * size
+ approx_pos = last_pos
+ last_error = error
+ max_iterations -= 1
+ return last_pos
+
# angle aliases
fullcircle = pi * 2
halfcircle = pi
Modified: vessel.py
===================================================================
--- vessel.py 2007-11-04 05:58:12 UTC (rev 320)
+++ vessel.py 2007-11-04 06:03:37 UTC (rev 321)
@@ -1052,7 +1052,7 @@
self.vessel.body.addTorque((0, 0, self.vessel.control.turn * self.thrust))
else:
# slow or stop turning with no input
- if abs(turn_rate) < 0.25:
+ if abs(turn_rate) < 0.15:
self.vessel.turn_rate = 0
elif turn_rate > 0:
self.vessel.body.addTorque((0,0,-self.thrust))
Modified: vessels/naree/corde
===================================================================
--- vessels/naree/corde 2007-11-04 05:58:12 UTC (rev 320)
+++ vessels/naree/corde 2007-11-04 06:03:37 UTC (rev 321)
@@ -2,7 +2,7 @@
[general]
vessel_class: corde
-vessel_type: assault ship
+vessel_type: assault transport
description: As a pacifist race, the Naree have had no use for a planetary assault vessel. When it became clear that one was required, they refitted one of their ubiquitous freighter hulls for the purpose. The Naree abhor barbaric infantry warfare, and instead utilize a powerful stasis technology which renders the indigenous populations or enemy forces inert indefinitely with little or no bloodshed. Naree scientists and engineers are currently working on a space-born application of this technology to curtail the senseless violent plague of destruction in the skies.
hull_mass: 80
hull_length: 50
@@ -12,12 +12,11 @@
ai: AssaultAI
cost: 400
-[vessel.Shield]
-max_level: 1200
-regeneration: 10
+[vessel.Armor]
+durability: 1200
[vessel.DirectionalThrusters]
-thrust: 200
+thrust: 300
max_turn_rate: 1.0
[vessel.ManeuveringThrusters]
Modified: vessels/rone/kraken
===================================================================
--- vessels/rone/kraken 2007-11-04 05:58:12 UTC (rev 320)
+++ vessels/rone/kraken 2007-11-04 06:03:37 UTC (rev 321)
@@ -2,22 +2,21 @@
[general]
vessel_class: kraken
-vessel_type: assault ship
+vessel_type: assault transport
description: The sight of the kraken over a planet's skies is a foreboding one indeed. Teeming with droid war machines, the kraken's brutal efficiency is unmatched in ground attack. It is rumored that kraken variants can dispatch their droid warriors into space as well, though this is unconfirmed.
-hull_mass: 120
-hull_length: 60
+hull_mass: 80
+hull_length: 50
crew: 100
max_speed: 80
max_energy: 1000
ai: AssaultAI
cost: 400
-[vessel.Shield]
-max_level: 1500
-regeneration: 6
+[vessel.Armor]
+durability: 1200
[vessel.DirectionalThrusters]
-thrust: 200
+thrust: 300
max_turn_rate: 1.0
[vessel.ManeuveringThrusters]
Added: vessels/sc/aurora
===================================================================
--- vessels/sc/aurora (rev 0)
+++ vessels/sc/aurora 2007-11-04 06:03:37 UTC (rev 321)
@@ -0,0 +1,28 @@
+# $Id: lotus 271 2007-09-29 16:46:25Z cduncan $
+
+[general]
+vessel_class: aurora
+vessel_type: assault transport
+description: What the aurora lacks in form, it more than makes up for in function. Carrying a horde of marines and an immense quantity of equipment, ammunition and supplies, and aurora can make short work of opposing ground forces and erect a new base in short order. Marines in space are an impatient lot, however, and they've been know to partake in some extravehicular activities for "fun".
+hull_mass: 80
+hull_length: 50
+crew: 100
+max_speed: 80
+max_energy: 1000
+ai: AssaultAI
+cost: 400
+
+[vessel.Armor]
+durability: 1200
+
+[vessel.DirectionalThrusters]
+thrust: 300
+max_turn_rate: 1.0
+
+[vessel.ManeuveringThrusters]
+thrust: 100
+
+[vessel.PlanetaryLander]
+
+[vessel.Engine]
+thrust: 80
Property changes on: vessels/sc/aurora
___________________________________________________________________
Name: svn:eol-style
+ native
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-04 05:58:33
|
Revision: 320
http://eos-game.svn.sourceforge.net/eos-game/?rev=320&view=rev
Author: cduncan
Date: 2007-11-03 22:58:12 -0700 (Sat, 03 Nov 2007)
Log Message:
-----------
Improved ai behavior when near its stationary target
Modified Paths:
--------------
ai.py
Modified: ai.py
===================================================================
--- ai.py 2007-11-02 04:48:28 UTC (rev 319)
+++ ai.py 2007-11-04 05:58:12 UTC (rev 320)
@@ -177,7 +177,9 @@
if not target.velocity:
# stationary target
heading = vector.radians(to_target)
- desired_dist = target.collision_radius * 1.25
+ desired_dist = target.collision_radius + self.vessel.collision_radius * 5
+ if distance < desired_dist:
+ return self.vessel.heading, vector.vector2()
elif self.vessel.is_friendly(target):
heading = target.heading
desired_dist = self.vessel.collision_radius * 4 + target.collision_radius * 3
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-02 04:48:30
|
Revision: 319
http://eos-game.svn.sourceforge.net/eos-game/?rev=319&view=rev
Author: cduncan
Date: 2007-11-01 21:48:28 -0700 (Thu, 01 Nov 2007)
Log Message:
-----------
- Left click to select, right click to direct
Modified Paths:
--------------
event.py
panel.py
Modified: event.py
===================================================================
--- event.py 2007-11-01 22:01:50 UTC (rev 318)
+++ event.py 2007-11-02 04:48:28 UTC (rev 319)
@@ -109,7 +109,7 @@
def mouse_up(self, event):
"""Handle mouse button release"""
self.show_mouse()
- click_pos = vector.to_tuple(self.mouse_down_pos)
+ click_pos = self.mouse_down_pos and vector.to_tuple(self.mouse_down_pos) or event.pos
self.mouse_down_pos = None
if self.mouse_handler is not None:
if self.drag and self.mouse_handler.mouse_drag_end(event, click_pos, event.pos):
@@ -228,6 +228,8 @@
return True
def mouse_click(self, event, pos):
+ if event.button not in (1, 3):
+ return False # We only handle left and right clicks
# First check for vessel click
click_rect = pygame.Rect(0, 0, 10, 10)
click_rect.center = pos
@@ -235,19 +237,31 @@
vessels.reverse()
for vessel in vessels:
if (isinstance(vessel, Vessel) and vessel.rect.colliderect(click_rect)
- and vessel is not game.local_player and not vessel.incidental):
- if vessel.is_friendly(game.local_player):
- selection.group.select(vessel)
- else:
- game.target.select(vessel)
- return True
+ and not vessel.incidental):
+ if event.button == 1:
+ # Left-click, select
+ if vessel.is_friendly(game.local_player) and vessel is not game.local_player:
+ selection.group.select(vessel)
+ else:
+ game.target.select(vessel)
+ return True
+ elif event.button == 3:
+ # Right-click, direct
+ selection.group.set_target(vessel)
+ return True
# No vessel was there, see about planets
planets = [s for s in sprite.layers.background if isinstance(s, Planet)]
planets.reverse()
for planet in planets:
if planet.rect.colliderect(click_rect):
- game.target.select(planet)
- return True
+ if event.button == 1:
+ # Left-click, select
+ game.target.select(planet)
+ return True
+ elif event.button == 3:
+ # Right-click, direct
+ selection.group.set_target(planet)
+ return True
# Nothing specific was clicked, just clear the current selected group
selection.group.select_none()
return True
Modified: panel.py
===================================================================
--- panel.py 2007-11-01 22:01:50 UTC (rev 318)
+++ panel.py 2007-11-02 04:48:28 UTC (rev 319)
@@ -339,6 +339,8 @@
return True
def mouse_click(self, event, pos):
+ if event.button not in (1, 3):
+ return False # We only handle left and right clicks
if self.rect.collidepoint(pos):
# Translate the position to map coodinates
map_pos = ((pos[0] - self.rect.centerx) / self.map_scale,
@@ -348,8 +350,14 @@
planet_rect.width = planet_rect.height = planet.collision_radius * 4
planet_rect.center = vector.to_tuple(planet.position)
if planet_rect.collidepoint(map_pos):
- game.target.select(planet)
- break
+ if event.button == 1:
+ # Left-click, select
+ game.target.select(planet)
+ return True
+ elif event.button == 3:
+ # Right-click, direct
+ selection.group.set_target(planet)
+ return True
return True
def draw(self, surface):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-11-01 22:01:58
|
Revision: 318
http://eos-game.svn.sourceforge.net/eos-game/?rev=318&view=rev
Author: cduncan
Date: 2007-11-01 15:01:50 -0700 (Thu, 01 Nov 2007)
Log Message:
-----------
- Add event handler apis and supporting code for higher level mouse
events: click, double click and drag
- Add click and drag selection support to playing field and
minimap.
- Add 'incidental' flag to body objects so they can be configured
not to show on maps or be selectable (e.g., gnats). This removes
a bunch of special case checking throughout.
- Fix target timeout when setting the target of ai vessels explicitly.
Also, always set the objective as well, to allow ai vessels to
engage enemies on their way to their eventual target objective.
- Fix rare div by zero bug in tracker
Modified Paths:
--------------
ai.py
body.py
camera.py
event.py
game.py
panel.py
selection.py
vessel.py
vessels/naree/gnat
Modified: ai.py
===================================================================
--- ai.py 2007-10-30 07:25:40 UTC (rev 317)
+++ ai.py 2007-11-01 22:01:50 UTC (rev 318)
@@ -22,7 +22,6 @@
class BasicAI(Control):
"""Basic AI Control"""
- target_timeout = 5000
# Maximum distance to target when we have an objective
target_max_distance_with_objective = 2000
@@ -286,21 +285,37 @@
vector.distance(self.vessel.position,
self.sensor.closest_vessel.sprite.position) <
self.target_max_distance_with_objective)):
- self.target.add(self.sensor.closest_vessel)
- self.target_time = game.time + self.target_timeout
+ self.set_target(self.sensor.closest_vessel)
self.sensor.disable()
elif not self.sensor.enabled:
self.sensor.enable()
if not self.target:
- self.target_time = 0 # look for other targets immediately
- if self.objective:
- # head for the objective
- self.target.add(self.objective)
- else:
- # No objective, just head toward a planet
- self.target.add(game.map.planets)
+ if not self.objective:
+ self.choose_objective()
+ # head for the objective looking for other targets
+ self.set_target(self.objective, timeout=0)
- def set_target(self, target, timeout=None):
+ def choose_objective(self):
+ """Set the ship's objective, which by default is to head to the nearest
+ friendly or neutral planet
+ """
+ def distance(planet):
+ return vector.distance(self.vessel.position, planet.position)
+ planets = sorted(game.map.planets, key=distance)
+ # Try for the closest friendly planet first
+ for planet in planets:
+ if planet.base is not None and planet.base.owner.is_friendly(self.vessel):
+ self.objective.add(planet)
+ return
+ # Try for the closest neutral planet next
+ for planet in planets:
+ if planet.base is None:
+ self.objective.add(planet)
+ return
+ # Just head for the closest planet at all
+ self.objective.add(planets[0])
+
+ def set_target(self, target, timeout=3000):
"""Set the target for the ai, timing out in timeout seconds
at which time it will acquire another target
"""
@@ -591,16 +606,16 @@
# This is a new frame, start a new sensor sweep
self._detected = []
self._closest_dist = sys.maxint
- self._closest_type = None
+ self._closest_incidental = False
self.closest_vessel.empty()
self.last_sweep = game.frame_no
distance = vector.distance(self.vessel.position, other.position)
self._detected.append((distance, other))
if (isinstance(other, Vessel) and distance < self._closest_dist
- or self._closest_type == 'missile' and other.vessel_type != 'missle'):
+ or self._closest_incidental and other.incidental):
self.closest_vessel.sprite = other
self._closest_dist = distance
- self._closest_type = other.vessel_type
+ self._closest_incidental = other.incidental
@property
def detected(self):
@@ -679,7 +694,7 @@
top += x * y
bot_left += x * x
bot_right += y * y
- correlation = abs(top / math.sqrt(bot_left * bot_right))
+ correlation = abs(top / math.sqrt(bot_left * bot_right or float('nan')))
endx, endy = self.samples[-1]
v2 = vector.vector2(endx - startx, endy - starty) / (
len(self.samples) * self.sample_time) * time_ahead
Modified: body.py
===================================================================
--- body.py 2007-10-30 07:25:40 UTC (rev 317)
+++ body.py 2007-11-01 22:01:50 UTC (rev 318)
@@ -42,6 +42,7 @@
collision_radius = None # Optional collision radius if different from above
max_visible_dist = 10000 # Maximum distance pointy is shown
scale = 1.0 # Onscreen scale adjustment
+ incidental = False # Incidental bodies cannot be selected, do not show on maps, etc
category = nothing # category for collision interaction
collides_with = nothing # category bitmap this body collides with
Modified: camera.py
===================================================================
--- camera.py 2007-10-30 07:25:40 UTC (rev 317)
+++ camera.py 2007-11-01 22:01:50 UTC (rev 318)
@@ -58,8 +58,8 @@
def acquire_target(self):
# Select a new target
- for ship in sprite.layers.vessels.sprites():
- if (ship.alive() and getattr(ship, 'vessel_type', None) not in ('missile', 'station')):
+ for ship in sprite.layers.vessels:
+ if ship.alive() and not ship.incidental:
self.follow(ship)
break
Modified: event.py
===================================================================
--- event.py 2007-10-30 07:25:40 UTC (rev 317)
+++ event.py 2007-11-01 22:01:50 UTC (rev 318)
@@ -13,6 +13,9 @@
import vector
import panel
import selection
+import sprite
+from vessel import Vessel
+from staticbody import Planet
class Handler:
@@ -26,6 +29,18 @@
def mouse_down(self, event):
"""Handle mouse button press"""
+
+ def mouse_click(self, event, pos):
+ """Single mouse click at pos, event contains mouse button info"""
+
+ def mouse_double_click(self, event, pos):
+ """Double mouse click at pos, event contains mouse button info"""
+
+ def mouse_drag(self, event, start_pos, end_pos):
+ """Mouse drag in progress from start_pos to end_pos, event contains mouse button info"""
+
+ def mouse_drag_end(self, event, start_pos, end_pos):
+ """Mouse drag completed from tart_pos to end_pos, event contains mouse button info"""
def key_down(self, event):
"""Handle key press"""
@@ -35,6 +50,8 @@
"""Top-level event handler"""
mouse_timeout = 3000 # Time to hide mouse if not moved or clicked
+ double_click_time = 750 # max millis between click to be considered a double
+ mouse_slop = 5 # Amount mouse is allowed to move to differential between clicks and drags
def __init__(self, handlers=()):
"""Dispatches pygame events to the handler's methods"""
@@ -48,6 +65,11 @@
self.handlers = list(handlers)
self.mouse_visible = pygame.mouse.set_visible(not display.fullscreen)
self.mouse_hide_time = 0
+ self.last_click_time = 0
+ self.last_click_pos = None
+ self.mouse_down_pos = None
+ self.mouse_handler = None
+ self.drag = False
self.running = True
def handle_events(self):
@@ -68,22 +90,58 @@
def mouse_move(self, event):
"""Handle mouse movement"""
self.show_mouse()
+ if event.buttons and not self.drag and self.mouse_down_pos is not None:
+ # See if the user has moved enough to begin a drag
+ self.drag = (vector.distance(vector.vector2(*event.pos), self.mouse_down_pos)
+ > self.mouse_slop)
+ if self.drag and self.mouse_down_pos is not None:
+ if self.mouse_handler is not None and self.mouse_handler.mouse_drag(
+ event, vector.to_tuple(self.mouse_down_pos), event.pos):
+ return
+ elif self.mouse_handler is None:
+ for handler in self.handlers:
+ if handler.mouse_drag(event, vector.to_tuple(self.mouse_down_pos), event.pos):
+ self.mouse_handler = handler
+ return
for handler in self.handlers:
handler.mouse_move(event)
def mouse_up(self, event):
"""Handle mouse button release"""
self.show_mouse()
+ click_pos = vector.to_tuple(self.mouse_down_pos)
+ self.mouse_down_pos = None
+ if self.mouse_handler is not None:
+ if self.drag and self.mouse_handler.mouse_drag_end(event, click_pos, event.pos):
+ self.drag = False
+ self.last_click_time = 0
+ return
+ if game.time - self.last_click_time < self.double_click_time:
+ was_double_click = not self.drag
+ self.last_click_time = 0
+ else:
+ was_double_click = False
+ self.last_click_time = game.time
+ if was_double_click and self.mouse_handler.mouse_double_click(event, click_pos):
+ return
+ if not self.drag and self.mouse_handler.mouse_click(event, click_pos):
+ return
for handler in self.handlers:
+ if not self.drag and handler.mouse_click(event, click_pos):
+ break
if handler.mouse_up(event):
break
def mouse_down(self, event):
"""Handle mouse button press"""
self.show_mouse()
+ self.mouse_down_pos = vector.vector2(*event.pos)
+ self.drag = False
for handler in self.handlers:
if handler.mouse_down(event):
+ self.mouse_handler = handler
break
+ self.mouse_handler = None
def quit(self, event=None):
self.running = False
@@ -106,9 +164,12 @@
game.exit()
-class GameCommandsHandler(Handler):
- """Global game command event handler"""
+class PlayingFieldHandler(Handler, sprite.Sprite):
+ """Game playing field event handler"""
+ select_rect = None
+ rect = pygame.Rect(0, 0, 0, 0)
+
def zoom_in(self):
"""Zoom in"""
game.camera.zoom_in()
@@ -147,6 +208,7 @@
game.target.select(game.local_player)
def __init__(self):
+ sprite.Sprite.__init__(self, sprite.layers.ui)
key_map = {
'=': self.zoom_in,
'-': self.zoom_out,
@@ -165,6 +227,47 @@
self.key_map[event.key]()
return True
+ def mouse_click(self, event, pos):
+ # First check for vessel click
+ click_rect = pygame.Rect(0, 0, 10, 10)
+ click_rect.center = pos
+ vessels = [s for s in sprite.layers.vessels if isinstance(s, Vessel)]
+ vessels.reverse()
+ for vessel in vessels:
+ if (isinstance(vessel, Vessel) and vessel.rect.colliderect(click_rect)
+ and vessel is not game.local_player and not vessel.incidental):
+ if vessel.is_friendly(game.local_player):
+ selection.group.select(vessel)
+ else:
+ game.target.select(vessel)
+ return True
+ # No vessel was there, see about planets
+ planets = [s for s in sprite.layers.background if isinstance(s, Planet)]
+ planets.reverse()
+ for planet in planets:
+ if planet.rect.colliderect(click_rect):
+ game.target.select(planet)
+ return True
+ # Nothing specific was clicked, just clear the current selected group
+ selection.group.select_none()
+ return True
+
+ def mouse_drag(self, event, start_pos, end_pos):
+ self.select_rect = pygame.Rect(
+ min(start_pos[0], end_pos[0]), min(start_pos[1], end_pos[1]),
+ abs(start_pos[0] - end_pos[0]), abs(start_pos[1] - end_pos[1]))
+ return True
-
-
+ def mouse_drag_end(self, event, start_pos, end_pos):
+ selection.group.select_none()
+ selection.group.select_screen_rect(game.local_player.category, self.select_rect)
+ self.select_rect = None
+
+ def draw(self, surface):
+ if self.select_rect is not None:
+ pygame.draw.rect(surface, (100, 100, 200), self.select_rect, 1)
+ return self.select_rect
+ return self.rect
+
+playing_field_handler = PlayingFieldHandler()
+
Modified: game.py
===================================================================
--- game.py 2007-10-30 07:25:40 UTC (rev 317)
+++ game.py 2007-11-01 22:01:50 UTC (rev 318)
@@ -224,7 +224,7 @@
enemies = pygame.sprite.Group()
next_wave = 0
this_frame_time = last_frame_time = 1000 / fps
- event_handler = event.MainHandler([event.GameCommandsHandler(), panel.handler])
+ event_handler = event.MainHandler([panel.handler, event.playing_field_handler])
if windowed:
sleep_time = 0.01
else:
Modified: panel.py
===================================================================
--- panel.py 2007-10-30 07:25:40 UTC (rev 317)
+++ panel.py 2007-11-01 22:01:50 UTC (rev 318)
@@ -18,6 +18,7 @@
import widget
import sprite
import media
+import selection
class Panel(sprite.Sprite, event.Handler):
"""User interface panel. Panels contain controls. Enabled panels receive
@@ -268,6 +269,7 @@
BottomPanel.__init__(self, width, height, align_right=True)
self.tab = PanelTab(self, align_right=True)
self.controls.add(self.tab)
+ self.select_rect = None
def create_image(self):
image = pygame.Surface(self.rect.size, pygame.SRCALPHA, 32)
@@ -302,7 +304,7 @@
self.tab.rect.right = self.rect.right
def update_vessel(self, vessel):
- if vessel.vessel_type != 'missile':
+ if not vessel.incidental:
if vessel.is_friendly(game.local_player):
if vessel.selected:
color = (255, 255, 255)
@@ -315,11 +317,51 @@
pos_x + self.map_rect.centerx, pos_y + self.map_rect.centery, 2, 2)
self.map_points.fill(color, point_rect)
self.map_mask.fill((0, 0, 0, 120), point_rect.inflate(4, 4))
+
+ def mouse_drag(self, event, start_pos, end_pos):
+ if self.select_rect is None and not self.rect.collidepoint(start_pos):
+ return False # Drag did not originate in our panel
+ self.select_rect = pygame.Rect(
+ min(start_pos[0], end_pos[0]), min(start_pos[1], end_pos[1]),
+ abs(start_pos[0] - end_pos[0]), abs(start_pos[1] - end_pos[1]))
+ return True
+ def mouse_drag_end(self, event, start_pos, end_pos):
+ if self.select_rect is not None:
+ selection.group.select_none()
+ # Translate the select rect to map coordinates
+ (left, top), (width, height) = self.select_rect.topleft, self.select_rect.size
+ rect = pygame.Rect((left - self.rect.centerx) / self.map_scale,
+ (top - self.rect.centery) / self.map_scale,
+ width / self.map_scale, height / self.map_scale)
+ selection.group.select_map_rect(game.local_player.category, rect)
+ self.select_rect = None
+ return True
+
+ def mouse_click(self, event, pos):
+ if self.rect.collidepoint(pos):
+ # Translate the position to map coodinates
+ map_pos = ((pos[0] - self.rect.centerx) / self.map_scale,
+ (pos[1] - self.rect.centery) / self.map_scale)
+ planet_rect = pygame.Rect(0, 0, 0, 0)
+ for planet in game.map.planets:
+ planet_rect.width = planet_rect.height = planet.collision_radius * 4
+ planet_rect.center = vector.to_tuple(planet.position)
+ if planet_rect.collidepoint(map_pos):
+ game.target.select(planet)
+ break
+ return True
+
def draw(self, surface):
+ old_clip = surface.get_clip()
+ surface.set_clip(self.rect)
surface.blit(self.image, self.rect)
+ surface.set_clip(self.rect.inflate(-self.border_width * 2, -self.border_width * 2))
surface.blit(self.map_mask, self.rect)
surface.blit(self.map_points, self.rect)
+ if self.select_rect is not None:
+ pygame.draw.rect(surface, (200, 100, 0), self.select_rect, 1)
+ surface.set_clip(old_clip)
return self.rect
@@ -640,11 +682,28 @@
def mouse_down(self, event):
"""Handle mouse button press"""
- handled = False
for panel in self.panels:
if panel.mouse_down(event):
return panel
+
+ def mouse_click(self, event, pos):
+ """Handle click events"""
+ for panel in self.panels:
+ if panel.mouse_click(event, pos):
+ return panel
+
+ def mouse_drag(self, event, start_pos, end_pos):
+ """Handle drag events"""
+ for panel in self.panels:
+ if panel.mouse_drag(event, start_pos, end_pos):
+ return panel
+ def mouse_drag_end(self, event, start_pos, end_pos):
+ """Handle drag events"""
+ for panel in self.panels:
+ if panel.mouse_drag_end(event, start_pos, end_pos):
+ return panel
+
def key_down(self, event):
"""Handle key press"""
for panel in self.panels:
Modified: selection.py
===================================================================
--- selection.py 2007-10-30 07:25:40 UTC (rev 317)
+++ selection.py 2007-11-01 22:01:50 UTC (rev 318)
@@ -53,8 +53,7 @@
try:
while 1:
next = self._nearest_vessel_iter.next()
- if next is not self.selected.sprite and (
- getattr(next, 'vessel_type', None) != 'missile'):
+ if next is not self.selected.sprite and not next.incidental:
# Ensure we always select a new target
self.select(next)
break
@@ -141,13 +140,19 @@
if clear_class_iter:
self.by_class_iter = None
- def select_rect(self, category, rect):
- """Select all vessels matching the category inside the given rect"""
+ def select(self, vessel):
+ """Select a single vessel"""
+ self.select_none()
+ self.selected.add(vessel)
+ vessel.selected = True
+
+ def select_screen_rect(self, category, rect):
+ """Select all vessels matching the category inside the given rect in screen coordinates"""
in_rect = rect.colliderect
by_class = {}
for spr in sprite.layers.vessels:
if (isinstance(spr, Vessel) and spr.category & category and in_rect(spr.rect)
- and spr is not game.local_player and spr.vessel_type != 'missile'):
+ and spr is not game.local_player and not spr.incidental):
self.selected.add(spr)
if spr.vessel_class not in by_class:
by_class[spr.vessel_class] = pygame.sprite.Group()
@@ -158,6 +163,24 @@
else:
self.by_class = None
+ def select_map_rect(self, category, rect):
+ """Select all vessels matching the category inside the given rect in map coordinates"""
+ in_rect = rect.collidepoint
+ by_class = {}
+ for spr in sprite.layers.vessels:
+ if (isinstance(spr, Vessel) and spr.category & category
+ and in_rect(vector.to_tuple(spr.position))
+ and spr is not game.local_player and not spr.incidental):
+ self.selected.add(spr)
+ if spr.vessel_class not in by_class:
+ by_class[spr.vessel_class] = pygame.sprite.Group()
+ by_class[spr.vessel_class].add(spr)
+ spr.selected = True
+ if by_class:
+ self.by_class_iter = itertools.cycle(by_class.iteritems())
+ else:
+ self.by_class = None
+
def select_near_vessel(self, vessel, category):
"""Select vessels in an expanding area surround the vessel"""
if game.time > self._select_timeout:
@@ -167,8 +190,8 @@
size = self._last_select_size = self._last_select_size*2 or self.initial_select_size
size += vessel.collision_radius * 2
rect = pygame.Rect(0, 0, size, size)
- rect.center = vessel.rect.center
- self.select_rect(category, rect)
+ rect.center = vector.to_tuple(vessel.position)
+ self.select_map_rect(category, rect)
def constrain_by_class(self):
"""Constrain an existing selection to a single vessel class. Repeated
@@ -182,12 +205,11 @@
self.selected.add(vessel)
def set_target(self, target):
- """Set the target for all selected vessels. If the target is a planet
- or a friendly ship, it is also set as the objective for all
+ """Set the target and objective for all selected vessels.
"""
for vessel in self.selected:
vessel.control.set_target(target)
- if isinstance(target, staticbody.Planet) or vessel.is_friendly(target):
- vessel.control.objective.add(target)
+ vessel.control.objective.add(target)
group = GroupSelector() # Singleton
+
Modified: vessel.py
===================================================================
--- vessel.py 2007-10-30 07:25:40 UTC (rev 317)
+++ vessel.py 2007-11-01 22:01:50 UTC (rev 318)
@@ -145,7 +145,8 @@
def __init__(self, vessel_name=None, vessel_class='', vessel_type='', description='',
image_name=None, hull_mass=1, hull_length=1, crew=0, max_speed=0, max_energy=0,
- standoff_distance=0, race=None, ai=None, cost=None, config_file=None, net_id=None):
+ standoff_distance=0, race=None, ai=None, cost=None, config_file=None, net_id=None,
+ incidental=False):
if image_name is None and vessel_class:
image_name = vessel_class + '.png'
if image_name is not None:
@@ -177,6 +178,7 @@
self._repair_time = None
self.damage_time = 0
self.race = race
+ self.incidental = str(incidental) not in ('0', 'False')
@classmethod
def load(cls, config_file, **kw):
@@ -527,7 +529,7 @@
5
"""
self.damage_time = game.time
- if self.vessel_type != 'missile':
+ if not self.incidental:
self.show_status()
for s in self._damage_sys:
value = s.damage(value)
@@ -551,7 +553,7 @@
self.system_damage -= self.system_damage_threshold
if game.local_player is self:
media.play_sound('power_down.wav', min_spacing=2)
- if self.damage_smoke is None and self.vessel_type != 'missile':
+ if self.damage_smoke is None and not self.incidental:
self.damage_smoke = particle.SmokeTrail(self)
if (self.hull_damage > self.disable_factor * self.hull_mass * 0.75 and
self.explosion is None):
Modified: vessels/naree/gnat
===================================================================
--- vessels/naree/gnat 2007-10-30 07:25:40 UTC (rev 317)
+++ vessels/naree/gnat 2007-11-01 22:01:50 UTC (rev 318)
@@ -8,6 +8,7 @@
hull_length: 2
max_speed: 300
max_energy: 50
+incidental: True
ai: GnatAI
[vessel.Shield]
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-30 07:25:42
|
Revision: 317
http://eos-game.svn.sourceforge.net/eos-game/?rev=317&view=rev
Author: cduncan
Date: 2007-10-30 00:25:40 -0700 (Tue, 30 Oct 2007)
Log Message:
-----------
- Add remaining planets to sol map, with symmetric arch layout
- Can't land on "inhospitable" planets with no resources
- Allow initial base and player positions to be specified on the map
- Randomly choose initial starting position for player (now done in a tacky
way, will need refactoring for real multiplayer)
Modified Paths:
--------------
base.py
content/maps/sol
game.py
panel.py
staticbody.py
vessel.py
Added Paths:
-----------
data/jupiter.png
data/neptune.png
data/saturn.png
data/titan.png
data/triton.png
data/uranus.png
Modified: base.py
===================================================================
--- base.py 2007-10-28 07:20:31 UTC (rev 316)
+++ base.py 2007-10-30 07:25:40 UTC (rev 317)
@@ -13,6 +13,7 @@
import vector
import map
import message
+import panel
class PlanetaryBase:
"""Planetary bases are owned by a player and can build using the planet's
@@ -59,6 +60,8 @@
% (level, max_level))
self.number = self._owner2number[owner] = self._owner2number.get(owner, 0) + 1
self.build_queue = []
+ if owner is game.local_player:
+ panel.BasePanel(planet)
def update(self):
if self.builder is None and self.build_queue:
Modified: content/maps/sol
===================================================================
--- content/maps/sol 2007-10-28 07:20:31 UTC (rev 316)
+++ content/maps/sol 2007-10-30 07:25:40 UTC (rev 317)
@@ -1,3 +1,5 @@
+# $Id$
+
[general]
name: Sol
description: Home system of the Solar Coalition
@@ -2,29 +4,67 @@
+[planet:Mercury]
+image: mercury.png
+x:-9000
+y: 4500
+resources: 3
+
+[planet:Venus]
+image: venus.png
+x:-8000
+y: 2000
+
[planet:Earth]
image: earth-east.png,earth-west.png
-x: 250
-y: -50
+x:-6000
+y:-500
resources: 10
+player: 1
+base_level: 2
[planet:Moon]
image: moon.png
-x: -500
-y: -1000
+x:-7000
+y: 0
resources: 4
[planet:Mars]
image: mars.png
-x: 7500
-y: 2200
+x:-2500
+y: -3300
resources: 8
-[planet:Venus]
-image: venus.png
-x: -6000
-y: -1500
+[planet:Jupiter]
+image: jupiter.png
+x: 2500
+y: -3300
+resources: 8
-[planet:Mercury]
-image: mercury.png
-x: -9000
-y: -2200
+[planet:Saturn]
+image: saturn.png
+x: 6000
+y: -500
+player: 2
+base_level: 2
+resources: 10
+
+[planet:Titan]
+image: titan.png
+x: 7000
+y: 0
+resources: 4
+
+[planet:Uranus]
+image: uranus.png
+x: 8000
+y: 2000
+
+[planet:Triton]
+image: triton.png
+x: 9000
+y: 4500
resources: 3
+
+[planet:Neptune]
+image: neptune.png
+x: 10000
+y: 5000
Added: data/jupiter.png
===================================================================
(Binary files differ)
Property changes on: data/jupiter.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: data/neptune.png
===================================================================
(Binary files differ)
Property changes on: data/neptune.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: data/saturn.png
===================================================================
(Binary files differ)
Property changes on: data/saturn.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: data/titan.png
===================================================================
(Binary files differ)
Property changes on: data/titan.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: data/triton.png
===================================================================
(Binary files differ)
Property changes on: data/triton.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Added: data/uranus.png
===================================================================
(Binary files differ)
Property changes on: data/uranus.png
___________________________________________________________________
Name: svn:mime-type
+ image/png
Modified: game.py
===================================================================
--- game.py 2007-10-28 07:20:31 UTC (rev 316)
+++ game.py 2007-10-30 07:25:40 UTC (rev 317)
@@ -149,21 +149,20 @@
# Establish player
local_player = vessel.KeyboardControl.new_player(race, ship)
+ local_player.number = random.choice([1, 2]) # XXX Fix for real multiplayer
camera = Camera(local_player)
target = selection.Target(local_player)
# Setup background and map
starfield = StarField(display.rect)
map = Map('sol')
+
+ # Find the base and put the player next to it
+ for planet in map.planets:
+ if planet.base is not None and planet.base.owner is local_player:
+ offset = vector.vector2(planet.collision_radius * 1.25, planet.collision_radius * 1.25)
+ local_player.set_position(planet.position + offset)
- import panel, base
- earth = map.get_planet('Earth')
- earth.base = base.PlanetaryBase(earth, local_player, level=2)
- panel.BasePanel(earth)
- #moon = map.get_planet('Moon')
- #moon.base = base.PlanetaryBase(moon, local_player, level=1)
- #panel.BasePanel(moon)
-
# Setup local messaging
message.init(local_player)
Modified: panel.py
===================================================================
--- panel.py 2007-10-28 07:20:31 UTC (rev 316)
+++ panel.py 2007-10-30 07:25:40 UTC (rev 317)
@@ -470,7 +470,7 @@
desired_width = self.info_rect.width * 2.0
planet_img = media.image(planet.image_name)
planet_img = pygame.transform.rotozoom(planet_img,
- 0, desired_width / max(planet_img.get_rect().size))
+ 90, desired_width / max(planet_img.get_rect().size))
image.blit(planet_img, (0, self.info_rect.height / 4))
title_img = self.planet_font.render(planet.name, True, (255, 255, 255))
title_rect = title_img.get_rect(left=4, top=rect.top + 3)
Modified: staticbody.py
===================================================================
--- staticbody.py 2007-10-28 07:20:31 UTC (rev 316)
+++ staticbody.py 2007-10-30 07:25:40 UTC (rev 317)
@@ -22,7 +22,8 @@
base = None # Established planetary base
layer = sprite.layers.background
- def __init__(self, name, image, x=0, y=0, resources=0, net_id=None):
+ def __init__(self, name, image, x=0, y=0, resources=0, player=None, base_level=None,
+ max_base_level=5, net_id=None):
RoundBody.__init__(self, position=(int(x), int(y)), heading=-vector.rightangle,
net_id=net_id)
self.body.disable() # immobile
@@ -31,6 +32,12 @@
self.collision_radius = self.radius = media.image(self.image_name).get_rect().width / 2
self.resources = float(resources)
self.update()
+ if player is not None and base_level is not None:
+ import base
+ # XXX Hack, this needs to be better for real multiplayer
+ if game.local_player.number == int(player):
+ self.base = base.PlanetaryBase(
+ self, game.local_player, int(base_level), int(max_base_level))
def get_state(self):
state = RoundBody.get_state(self)
Modified: vessel.py
===================================================================
--- vessel.py 2007-10-28 07:20:31 UTC (rev 316)
+++ vessel.py 2007-10-30 07:25:40 UTC (rev 317)
@@ -21,7 +21,6 @@
import particle
import message
import sprite
-import staticbody
max_weapons = 5
_empty_rect = pygame.rect.Rect(0, 0, 0, 0)
@@ -1242,26 +1241,31 @@
if (self.enabled and self.firing and self.targeted and self.landing_end is None):
# Start landing cycle
self.planet = self.vessel.control.target.sprite
- self.landing_end = game.time + self.landing_time
- media.play_sound('land.wav', position=self.vessel.position, min_spacing=2.0)
- # restrict movement
- self.vessel.max_speed = 0
- self.vessel.engine.max_speed = 0
+ if self.planet.resources:
+ self.landing_end = game.time + self.landing_time
+ media.play_sound('land.wav', position=self.vessel.position, min_spacing=2.0)
+ # restrict movement
+ self.vessel.max_speed = 0
+ self.vessel.engine.max_speed = 0
+ else:
+ message.send_status(self.vessel, game.local_player,
+ 'Cannot land on %s, planet is inhospitable' % self.planet.name)
+ self.vessel.control.target.empty()
elif self.landing_end is not None:
# We are landing
if game.time < self.landing_end:
self.vessel.set_scale(float(self.landing_end - game.time) / self.landing_time)
else:
- import base, panel # Avoid circular imports
+ import base # Avoid circular imports
# Landing cycle complete, build a base
self.planet.base = base.PlanetaryBase(self.planet, game.local_player)
message.send_status(self.planet, game.local_player,
'Base esablished on %s' % self.planet.name)
- panel.BasePanel(self.planet)
self.vessel.kill()
@property
def targeted(self):
+ import staticbody # Avoid circular import
target = self.vessel.control.target.sprite
return (isinstance(target, staticbody.Planet) and
(target.base is None or target.base.owner.category & self.vessel.category == 0) and
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-28 07:20:37
|
Revision: 316
http://eos-game.svn.sourceforge.net/eos-game/?rev=316&view=rev
Author: cduncan
Date: 2007-10-28 00:20:31 -0700 (Sun, 28 Oct 2007)
Log Message:
-----------
- AI mothership becomes more general "objective" which is used to specify the
ship's mission object. Unlike for target, the vessel ai never changes this
value.
- The objective overrides the immediate target when the latter is a certain
distance away.
- Add AssaultAI personality which enables the ai to take planets with assault
ships.
- Add resources to other sol planets (though a redesign of the map is in the
works)
- Add a new game commands event handler which abstracts out game-level
keyboard (and later mouse) commands. This will enable later control remapping too.
- New keyboard commands:
't': target nearest friend
'y': target yourself
[return]: Direct selected friends to target
Modified Paths:
--------------
ai.py
base.py
bay.py
content/maps/sol
event.py
game.py
selection.py
sounds/land.wav
vessel.py
vessels/naree/corde
vessels/rone/kraken
Modified: ai.py
===================================================================
--- ai.py 2007-10-26 18:45:46 UTC (rev 315)
+++ ai.py 2007-10-28 07:20:31 UTC (rev 316)
@@ -17,18 +17,21 @@
import sprite
from vector import diagonal, halfcircle, rightangle, fullcircle
from vessel import Control, Vessel, DirectionalThrusters
+import staticbody
class BasicAI(Control):
"""Basic AI Control"""
target_timeout = 5000
+ # Maximum distance to target when we have an objective
+ target_max_distance_with_objective = 2000
evade_min_health = 0.66
evade_max_health = 0.75
evade_damage_timeout = 2000
evade_max_distance = 350
- def __init__(self, vessel, target=None, mothership=None, sensor=None):
+ def __init__(self, vessel, target=None, objective=None, sensor=None):
Control.__init__(self)
self.vessel = vessel
# override vessel collision handler with our own
@@ -40,9 +43,9 @@
target = target.sprite
if target.alive():
self.target.add(target)
- self.mothership = GroupSingle()
- if mothership:
- self.mothership.add(mothership)
+ self.objective = GroupSingle()
+ if objective:
+ self.objective.add(objective)
self.steerfunc = self.standoff
self.close_vessels = Group()
self.proximity_radius = self.vessel.collision_radius * 5
@@ -268,13 +271,21 @@
self.bw_maneuver = False
def acquire_target(self):
- """Select the approriate target vessel"""
+ """auto-select the approriate target"""
+ if (self.target and self.objective and vector.distance(
+ self.vessel.position, self.target.sprite.position) >
+ self.target_max_distance_with_objective
+ and self.target not in self.objective):
+ self.target.empty()
if (not self.target or game.time > self.target_time
or self.target.sprite.explosion is not None):
# acquire a target vessel
if self.sensor is not None:
# Use the sensor to find a target
- if self.sensor.closest_vessel:
+ if (self.sensor.closest_vessel and (not self.objective or
+ vector.distance(self.vessel.position,
+ self.sensor.closest_vessel.sprite.position) <
+ self.target_max_distance_with_objective)):
self.target.add(self.sensor.closest_vessel)
self.target_time = game.time + self.target_timeout
self.sensor.disable()
@@ -282,13 +293,23 @@
self.sensor.enable()
if not self.target:
self.target_time = 0 # look for other targets immediately
- if self.mothership:
- # head for the mothership
- self.target.add(self.mothership)
+ if self.objective:
+ # head for the objective
+ self.target.add(self.objective)
else:
- # No mothership, just head toward a planet
+ # No objective, just head toward a planet
self.target.add(game.map.planets)
+ def set_target(self, target, timeout=None):
+ """Set the target for the ai, timing out in timeout seconds
+ at which time it will acquire another target
+ """
+ self.target.add(target)
+ if timeout is not None:
+ self.target_time = game.time + timeout
+ else:
+ self.target_time = sys.maxint
+
def select_steerfunc(self):
"""Select the appropirate steering function"""
if (self.vessel.health < self.evade_min_health
@@ -311,8 +332,8 @@
desired_velocity += self.avoid_vessels()
self.steer(desired_heading, desired_velocity)
# Fire all targeted weapons
- for i in range(len(self.vessel.weapons)):
- self.weapons[i] = self.vessel.weapons[i].targeted
+ for i, weapon in enumerate(self.vessel.weapons):
+ self.weapons[i] = weapon.targeted
def collide(self, other, contacts):
"""Detect contact with other vessels to avoid stacking
@@ -340,7 +361,7 @@
evade_max_health = 0.7
def evade(self):
- """Turne away from the target"""
+ """Turn away from the target"""
heading, seek_velocity = self.pursue()
velocity = vector.unit(
vector.radians(seek_velocity) + rightangle) * self.vessel.max_speed * 10
@@ -367,13 +388,32 @@
return heading, velocity * self.orbit
def select_steerfunc(self):
- return self.standoff
+ self.steerfunc = self.standoff
+class AssaultAI(BasicAI):
+
+ def select_steerfunc(self):
+ target = self.target.sprite
+ if isinstance(target, staticbody.Planet):
+ self.steerfunc = self.seek
+ elif self.vessel.is_friendly(target) or self.vessel.health > .75:
+ self.steerfunc = self.pursue
+ else:
+ self.steerfunc = self.flee
+
+ def acquire_target(self):
+ if isinstance(self.objective.sprite, staticbody.Planet):
+ # When targetting a planet, always go there
+ self.target.add(self.objective)
+ else:
+ BasicAI.acquire_target(self)
+
+
class GnatAI(BasicAI):
"""Gnat AI control"""
- is_returning = False # Is returning to the mothership
+ is_returning = False # Is returning to the objective
had_target = False
def steer(self, desired_heading, desired_velocity):
@@ -390,18 +430,18 @@
self.is_returning = True
if self.is_returning or (self.vessel.energy < (self.vessel.max_energy * 0.1)
or self.vessel.health < 0.25):
- # Return to the mothership if our energy is expended
- self.target.add(self.mothership)
+ # Return to the objective if our energy is expended
+ self.target.add(self.objective)
self.is_returning = True
- elif (not self.target or self.vessel.is_friendly(self.target.sprite)) and self.mothership:
- # Target whatever the mothership is targeting
- self.target.add(self.mothership.sprite.control.target)
+ elif (not self.target or self.vessel.is_friendly(self.target.sprite)) and self.objective:
+ # Target whatever the objective is targeting
+ self.target.add(self.objective.sprite.control.target)
if not self.target:
- if self.mothership:
- # head for the mothership
- self.target.add(self.mothership)
+ if self.objective:
+ # head for the objective
+ self.target.add(self.objective)
else:
- # Commit suicide if our mothership dies
+ # Commit suicide if our objective dies
self.vessel.explode('hit.wav')
self.target.add(game.map.planets)
@@ -421,9 +461,9 @@
return heading, seek_velocity
def collide(self, other, contacts):
- if self.is_returning and other in self.mothership:
- if hasattr(self.mothership.sprite, 'fighter_bay'):
- self.mothership.sprite.fighter_bay.dock(self.vessel)
+ if self.is_returning and other in self.objective:
+ if hasattr(self.objective.sprite, 'fighter_bay'):
+ self.objective.sprite.fighter_bay.dock(self.vessel)
self.is_returning = False
self.had_target = False
self.target.empty()
@@ -434,15 +474,22 @@
class AIVessel(Vessel):
"""Vessel under ai control"""
- def __init__(self, target=None, category=body.foe, mothership=None, sensor=None,
+ def __init__(self, target=None, category=body.foe, objective=None, sensor=None,
ai='BasicAI', **kw):
+ """
+ target -- Sprite to intercept and attack if foe.
+ category -- Vessel category, determines friends and foes.
+ objective -- Long term objective sprite or base
+ sensor -- Sensor object to be used (if omitted one is created just for this vessel)
+ ai -- class name of ai personality.
+ """
Vessel.__init__(self, **kw)
self.setup_collision(category, body.everything & ~body.shot)
if sensor is None:
sensor = Sensor(self, 10000, body.everything & ~category)
sensor.disable()
ai_class = globals()[ai]
- self.control = ai_class(self, target, mothership, sensor)
+ self.control = ai_class(self, target, objective, sensor)
# Make sure we are behind the local player
self.layer.to_back(self)
Modified: base.py
===================================================================
--- base.py 2007-10-26 18:45:46 UTC (rev 315)
+++ base.py 2007-10-28 07:20:31 UTC (rev 316)
@@ -170,7 +170,8 @@
"""Construct vessel"""
if not self.vessel_built:
vessel = ai.AIVessel.load(
- self.config_file, target=self.base.rally_point, category=self.base.owner.category)
+ self.config_file, target=self.base.rally_point, objective=self.base.rally_point,
+ category=self.base.owner.category)
vessel.set_position(self.base.planet.position)
vessel.set_heading(random.random() * vector.fullcircle)
self.vessel_built = True
Modified: bay.py
===================================================================
--- bay.py 2007-10-26 18:45:46 UTC (rev 315)
+++ bay.py 2007-10-28 07:20:31 UTC (rev 316)
@@ -85,7 +85,7 @@
self.vessel, 1000, body.everything & ~self.vessel.category)
fighter = ai.AIVessel.load(self.fighter_config,
target=self.vessel.control.target,
- mothership=self.vessel,
+ objective=self.vessel,
sensor=self.sensor,
category=self.vessel.category)
self.fighters.add(fighter)
Modified: content/maps/sol
===================================================================
--- content/maps/sol 2007-10-26 18:45:46 UTC (rev 315)
+++ content/maps/sol 2007-10-28 07:20:31 UTC (rev 316)
@@ -12,12 +12,13 @@
image: moon.png
x: -500
y: -1000
-resources: 2.5
+resources: 4
[planet:Mars]
image: mars.png
x: 7500
y: 2200
+resources: 8
[planet:Venus]
image: venus.png
@@ -28,3 +29,4 @@
image: mercury.png
x: -9000
y: -2200
+resources: 3
Modified: event.py
===================================================================
--- event.py 2007-10-26 18:45:46 UTC (rev 315)
+++ event.py 2007-10-28 07:20:31 UTC (rev 316)
@@ -20,19 +20,15 @@
def mouse_move(self, event):
"""Handle mouse movement"""
- raise NotImplementedError
def mouse_up(self, event):
"""Handle mouse button release"""
- raise NotImplementedError
def mouse_down(self, event):
"""Handle mouse button press"""
- raise NotImplementedError
def key_down(self, event):
"""Handle key press"""
- raise NotImplementedError
class MainHandler(Handler):
@@ -101,18 +97,6 @@
game.camera.center()
game.starfield.set_rect(display.rect)
panel.handler.hide_all(force=True)
- elif event.key == K_f:
- selection.group.select_near_vessel(game.local_player, game.local_player.category)
- elif event.key == K_TAB:
- selection.group.constrain_by_class()
- elif event.key == K_e:
- game.target.select_nearest(~game.local_player.category)
- elif event.key == K_p:
- game.target.select_next_planet()
- elif event.key == K_MINUS:
- game.camera.zoom_out()
- elif event.key == K_EQUALS:
- game.camera.zoom_in()
else:
for handler in self.handlers:
if handler.key_down(event):
@@ -121,3 +105,66 @@
def quit(self, event=None):
game.exit()
+
+class GameCommandsHandler(Handler):
+ """Global game command event handler"""
+
+ def zoom_in(self):
+ """Zoom in"""
+ game.camera.zoom_in()
+
+ def zoom_out(self):
+ """Zoom out"""
+ game.camera.zoom_out()
+
+ def select_nearest_friends(self):
+ """Select friends nearest to player"""
+ selection.group.select_near_vessel(game.local_player, game.local_player.category)
+
+ def constrain_selected_friends(self):
+ """Constrain friend selection by vessel class"""
+ selection.group.constrain_by_class()
+
+ def set_selected_friends_target(self):
+ """Command selected friends to the current target"""
+ if game.target.selected:
+ selection.group.set_target(game.target.selected.sprite)
+
+ def target_nearest_enemy(self):
+ """Target nearest enemy"""
+ game.target.select_nearest(~game.local_player.category)
+
+ def target_nearest_planet(self):
+ """Target nearest planet"""
+ game.target.select_next_planet()
+
+ def target_nearest_friend(self):
+ """Target nearest friend"""
+ game.target.select_nearest(game.local_player.category)
+
+ def target_local_player(self):
+ """Target your ship"""
+ game.target.select(game.local_player)
+
+ def __init__(self):
+ key_map = {
+ '=': self.zoom_in,
+ '-': self.zoom_out,
+ 'f': self.select_nearest_friends,
+ '\t': self.constrain_selected_friends,
+ '\r': self.set_selected_friends_target,
+ 'e': self.target_nearest_enemy,
+ 'p': self.target_nearest_planet,
+ 't': self.target_nearest_friend,
+ 'y': self.target_local_player,
+ }
+ self.key_map = dict((ord(key), method) for key, method in key_map.items())
+
+ def key_down(self, event):
+ if event.key in self.key_map:
+ self.key_map[event.key]()
+ return True
+
+
+
+
Modified: game.py
===================================================================
--- game.py 2007-10-26 18:45:46 UTC (rev 315)
+++ game.py 2007-10-28 07:20:31 UTC (rev 316)
@@ -225,7 +225,7 @@
enemies = pygame.sprite.Group()
next_wave = 0
this_frame_time = last_frame_time = 1000 / fps
- event_handler = event.MainHandler([panel.handler])
+ event_handler = event.MainHandler([event.GameCommandsHandler(), panel.handler])
if windowed:
sleep_time = 0.01
else:
@@ -294,7 +294,7 @@
ship = 'vessels/naree/lotus'
elif target_race == 'sc':
ship = 'vessels/sc/pegasus'
- friend = AIVessel.load(ship, mothership=target, category=body.friend)
+ friend = AIVessel.load(ship, objective=target, category=body.friend)
friend.set_position(target.position - position)
friends.add(friend)
barrier *= 2
Modified: selection.py
===================================================================
--- selection.py 2007-10-26 18:45:46 UTC (rev 315)
+++ selection.py 2007-10-28 07:20:31 UTC (rev 316)
@@ -14,6 +14,7 @@
import sprite
from vessel import Vessel
import vector
+import staticbody
class Target(sprite.Sprite):
@@ -146,7 +147,7 @@
by_class = {}
for spr in sprite.layers.vessels:
if (isinstance(spr, Vessel) and spr.category & category and in_rect(spr.rect)
- and spr.vessel_type != 'missile'):
+ and spr is not game.local_player and spr.vessel_type != 'missile'):
self.selected.add(spr)
if spr.vessel_class not in by_class:
by_class[spr.vessel_class] = pygame.sprite.Group()
@@ -179,5 +180,14 @@
for vessel in vessels:
vessel.selected = True
self.selected.add(vessel)
+
+ def set_target(self, target):
+ """Set the target for all selected vessels. If the target is a planet
+ or a friendly ship, it is also set as the objective for all
+ """
+ for vessel in self.selected:
+ vessel.control.set_target(target)
+ if isinstance(target, staticbody.Planet) or vessel.is_friendly(target):
+ vessel.control.objective.add(target)
group = GroupSelector() # Singleton
Modified: sounds/land.wav
===================================================================
(Binary files differ)
Modified: vessel.py
===================================================================
--- vessel.py 2007-10-26 18:45:46 UTC (rev 315)
+++ vessel.py 2007-10-28 07:20:31 UTC (rev 316)
@@ -1215,8 +1215,8 @@
self.energy_flow = float(energy_flow)
def update_system(self):
- if self.vessel.control.mothership:
- mothership = self.vessel.control.mothership.sprite
+ if self.vessel.control.objective:
+ mothership = self.vessel.control.objective.sprite
if (self.vessel.energy < self.vessel.max_energy
and hasattr(mothership, 'fighter_bay')
and self.vessel in mothership.fighter_bay):
@@ -1239,7 +1239,7 @@
self.landing_end = None
def update_system(self):
- if (self.enabled and self.firing and self.targetted and self.landing_end is None):
+ if (self.enabled and self.firing and self.targeted and self.landing_end is None):
# Start landing cycle
self.planet = self.vessel.control.target.sprite
self.landing_end = game.time + self.landing_time
@@ -1261,7 +1261,7 @@
self.vessel.kill()
@property
- def targetted(self):
+ def targeted(self):
target = self.vessel.control.target.sprite
return (isinstance(target, staticbody.Planet) and
(target.base is None or target.base.owner.category & self.vessel.category == 0) and
Modified: vessels/naree/corde
===================================================================
--- vessels/naree/corde 2007-10-26 18:45:46 UTC (rev 315)
+++ vessels/naree/corde 2007-10-28 07:20:31 UTC (rev 316)
@@ -9,7 +9,7 @@
crew: 100
max_speed: 80
max_energy: 1000
-ai: EvaderAI
+ai: AssaultAI
cost: 400
[vessel.Shield]
Modified: vessels/rone/kraken
===================================================================
--- vessels/rone/kraken 2007-10-26 18:45:46 UTC (rev 315)
+++ vessels/rone/kraken 2007-10-28 07:20:31 UTC (rev 316)
@@ -9,7 +9,7 @@
crew: 100
max_speed: 80
max_energy: 1000
-ai: EvaderAI
+ai: AssaultAI
cost: 400
[vessel.Shield]
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-26 18:45:49
|
Revision: 315
http://eos-game.svn.sourceforge.net/eos-game/?rev=315&view=rev
Author: cduncan
Date: 2007-10-26 11:45:46 -0700 (Fri, 26 Oct 2007)
Log Message:
-----------
Fix white planet pointy
Modified Paths:
--------------
media.py
Modified: media.py
===================================================================
--- media.py 2007-10-26 18:45:20 UTC (rev 314)
+++ media.py 2007-10-26 18:45:46 UTC (rev 315)
@@ -222,7 +222,7 @@
set_image('pointy-planet-blue', planet_pointy_image((55, 80, 216)))
set_image('pointy-planet-green', planet_pointy_image((0, 155, 38)))
set_image('pointy-planet-red', planet_pointy_image((216, 36, 30)))
- set_image('pointy-planet-white', pointy_image((255, 255, 255)))
+ set_image('pointy-planet-white', planet_pointy_image((255, 255, 255)))
_sound_cache = {}
_sound_last_played = {}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-26 18:45:24
|
Revision: 314
http://eos-game.svn.sourceforge.net/eos-game/?rev=314&view=rev
Author: cduncan
Date: 2007-10-26 11:45:20 -0700 (Fri, 26 Oct 2007)
Log Message:
-----------
- Use white planet pointies for selected planet, dynamically update pointy
color
- Select planets in distance order when using "p"
Modified Paths:
--------------
base.py
selection.py
staticbody.py
Modified: base.py
===================================================================
--- base.py 2007-10-26 06:26:59 UTC (rev 313)
+++ base.py 2007-10-26 18:45:20 UTC (rev 314)
@@ -50,10 +50,6 @@
self.planet = planet
self.planet.base = self
self.owner = owner
- if owner is game.local_player:
- planet.offscreen_img = 'pointy-planet-green'
- else:
- planet.offscreen_img = 'pointy-planet-red'
self.rally_point = self.planet
if max_level >= level:
self.level = level
Modified: selection.py
===================================================================
--- selection.py 2007-10-26 06:26:59 UTC (rev 313)
+++ selection.py 2007-10-26 18:45:20 UTC (rev 314)
@@ -13,6 +13,7 @@
import media
import sprite
from vessel import Vessel
+import vector
class Target(sprite.Sprite):
@@ -71,8 +72,10 @@
self.sensor.enable()
def select_next_planet(self):
+ def distance(planet):
+ return vector.distance(planet.position, game.camera.position)
if self._planet_iter is None:
- self._planet_iter = itertools.cycle(game.map.planets)
+ self._planet_iter = itertools.cycle(sorted(game.map.planets, key=distance))
self.sensor.disable()
self.select(self._planet_iter.next())
Modified: staticbody.py
===================================================================
--- staticbody.py 2007-10-26 06:26:59 UTC (rev 313)
+++ staticbody.py 2007-10-26 18:45:20 UTC (rev 314)
@@ -28,7 +28,6 @@
self.body.disable() # immobile
self.name = name
self.image_name = random.choice(image.split(','))
- self.offscreen_img = 'pointy-planet-blue'
self.collision_radius = self.radius = media.image(self.image_name).get_rect().width / 2
self.resources = float(resources)
self.update()
@@ -37,9 +36,17 @@
state = RoundBody.get_state(self)
state['create_args'] = (self.name, self.image_name)
return state
-
+
def update(self):
RoundBody.update(self)
if self.base is not None:
self.base.update()
+ if self in game.target.selected:
+ self.offscreen_img = 'pointy-planet-white'
+ elif self.base is None:
+ self.offscreen_img = 'pointy-planet-blue'
+ elif self.base.owner.category & game.local_player.category:
+ self.offscreen_img = 'pointy-planet-green'
+ else:
+ self.offscreen_img = 'pointy-planet-red'
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-26 06:27:03
|
Revision: 313
http://eos-game.svn.sourceforge.net/eos-game/?rev=313&view=rev
Author: cduncan
Date: 2007-10-25 23:26:59 -0700 (Thu, 25 Oct 2007)
Log Message:
-----------
- Add "PlanetaryLander" weapon for assault ships which lands the ship
establishing a base on the selected planet once you are over it.
- Remove free moon base
For now you must pilot the assault ship yourself, which is silly, but
next I'll add ai to do it.
Modified Paths:
--------------
body.py
display.py
game.py
vessel.py
vessels/naree/corde
vessels/rone/kraken
Added Paths:
-----------
sounds/land.wav
Modified: body.py
===================================================================
--- body.py 2007-10-26 06:22:56 UTC (rev 312)
+++ body.py 2007-10-26 06:26:59 UTC (rev 313)
@@ -41,6 +41,7 @@
radius = 0.1 # Radius in meters, affects rotation
collision_radius = None # Optional collision radius if different from above
max_visible_dist = 10000 # Maximum distance pointy is shown
+ scale = 1.0 # Onscreen scale adjustment
category = nothing # category for collision interaction
collides_with = nothing # category bitmap this body collides with
@@ -189,9 +190,9 @@
# place self relative to the camera at proper zoom level
self.apparent_size, screen_pos = vector.to_screen(self.position)
if self.explosion is None:
- self.image = media.image(self.image_name, self.apparent_size, self.heading)
+ self.image = media.image(self.image_name, self.apparent_size * self.scale, self.heading)
else:
- image = self.explosion.next_image(self.apparent_size)
+ image = self.explosion.next_image(self.apparent_size * self.scale)
if image is not None:
self.image = image
else:
@@ -202,7 +203,6 @@
def draw(self, surface):
"""Draw either sprite image or offscreen pointer"""
if self.on_screen:
- #pygame.draw.circle(surface, (255,255,255), self.rect.center, self.collision_radius * self.appsz, 2)
surface.blit(self.image, self.rect)
return self.rect
elif self.offscreen_img is not None:
Modified: display.py
===================================================================
--- display.py 2007-10-26 06:22:56 UTC (rev 312)
+++ display.py 2007-10-26 06:26:59 UTC (rev 313)
@@ -52,7 +52,7 @@
surface = pygame.display.set_mode(window_size)
pygame.display.set_icon(media.load_image('eos-icon.png'))
- rect = surface.get_rect()
+ rect = surface.get_rect()
pygame.display.set_caption('EOS [ctrl+f full screen]', 'EOS')
def toggle_fullscreen():
Modified: game.py
===================================================================
--- game.py 2007-10-26 06:22:56 UTC (rev 312)
+++ game.py 2007-10-26 06:26:59 UTC (rev 313)
@@ -160,9 +160,9 @@
earth = map.get_planet('Earth')
earth.base = base.PlanetaryBase(earth, local_player, level=2)
panel.BasePanel(earth)
- moon = map.get_planet('Moon')
- moon.base = base.PlanetaryBase(moon, local_player, level=1)
- panel.BasePanel(moon)
+ #moon = map.get_planet('Moon')
+ #moon.base = base.PlanetaryBase(moon, local_player, level=1)
+ #panel.BasePanel(moon)
# Setup local messaging
message.init(local_player)
@@ -229,7 +229,7 @@
if windowed:
sleep_time = 0.01
else:
- sleep_time = 0.0015
+ sleep_time = 0.001
while 1:
event_handler.handle_events()
keystate = pygame.key.get_pressed()
Added: sounds/land.wav
===================================================================
(Binary files differ)
Property changes on: sounds/land.wav
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: vessel.py
===================================================================
--- vessel.py 2007-10-26 06:22:56 UTC (rev 312)
+++ vessel.py 2007-10-26 06:26:59 UTC (rev 313)
@@ -21,6 +21,7 @@
import particle
import message
import sprite
+import staticbody
max_weapons = 5
_empty_rect = pygame.rect.Rect(0, 0, 0, 0)
@@ -483,6 +484,13 @@
massobj.adjust(self.mass)
self.body.setMass(massobj)
+ def set_scale(self, scale):
+ """Change the vessel scale, adjusting both the collision geom
+ radius and image scaling factor
+ """
+ self.scale = scale
+ self.geom.setRadius(self.collision_radius * scale)
+
def __iter__(self):
return iter(self._sys)
@@ -1217,6 +1225,49 @@
self.vessel.energy += mothership.use_energy(energy, partial=True)
+class PlanetaryLander(Weapon):
+ """Land on a planet and make a base"""
+
+ name = 'landing system'
+ priority = 1
+ mass = 100
+ landing_time = 3000 # Milliseconds it takes to descend
+
+ def __init__(self, vessel):
+ self.vessel = vessel
+ self.planet = None
+ self.landing_end = None
+
+ def update_system(self):
+ if (self.enabled and self.firing and self.targetted and self.landing_end is None):
+ # Start landing cycle
+ self.planet = self.vessel.control.target.sprite
+ self.landing_end = game.time + self.landing_time
+ media.play_sound('land.wav', position=self.vessel.position, min_spacing=2.0)
+ # restrict movement
+ self.vessel.max_speed = 0
+ self.vessel.engine.max_speed = 0
+ elif self.landing_end is not None:
+ # We are landing
+ if game.time < self.landing_end:
+ self.vessel.set_scale(float(self.landing_end - game.time) / self.landing_time)
+ else:
+ import base, panel # Avoid circular imports
+ # Landing cycle complete, build a base
+ self.planet.base = base.PlanetaryBase(self.planet, game.local_player)
+ message.send_status(self.planet, game.local_player,
+ 'Base esablished on %s' % self.planet.name)
+ panel.BasePanel(self.planet)
+ self.vessel.kill()
+
+ @property
+ def targetted(self):
+ target = self.vessel.control.target.sprite
+ return (isinstance(target, staticbody.Planet) and
+ (target.base is None or target.base.owner.category & self.vessel.category == 0) and
+ vector.distance(target.position, self.vessel.position) < target.collision_radius / 2)
+
+
def resolve(dotted_name):
"""Return the object corresponding to the dotted module/object name
pair specified.
Modified: vessels/naree/corde
===================================================================
--- vessels/naree/corde 2007-10-26 06:22:56 UTC (rev 312)
+++ vessels/naree/corde 2007-10-26 06:26:59 UTC (rev 313)
@@ -25,3 +25,5 @@
[vessel.Engine]
thrust: 80
+
+[vessel.PlanetaryLander]
Modified: vessels/rone/kraken
===================================================================
--- vessels/rone/kraken 2007-10-26 06:22:56 UTC (rev 312)
+++ vessels/rone/kraken 2007-10-26 06:26:59 UTC (rev 313)
@@ -23,5 +23,7 @@
[vessel.ManeuveringThrusters]
thrust: 100
+[vessel.PlanetaryLander]
+
[vessel.Engine]
thrust: 80
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-26 06:22:58
|
Revision: 312
http://eos-game.svn.sourceforge.net/eos-game/?rev=312&view=rev
Author: cduncan
Date: 2007-10-25 23:22:56 -0700 (Thu, 25 Oct 2007)
Log Message:
-----------
Fix tab placement
Modified Paths:
--------------
panel.py
Modified: panel.py
===================================================================
--- panel.py 2007-10-26 06:20:53 UTC (rev 311)
+++ panel.py 2007-10-26 06:22:56 UTC (rev 312)
@@ -568,7 +568,7 @@
self.hotkey_font = pygame.font.Font(self.hotkey_font, 72)
self.render()
if not align_right:
- rect = self.image.get_rect(left=self.panel_left)
+ rect = self.image.get_rect(left=PanelTab.panel_left)
PanelTab.panel_left = rect.right + 6
else:
rect = self.image.get_rect(right=display.rect.right)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-26 06:20:58
|
Revision: 311
http://eos-game.svn.sourceforge.net/eos-game/?rev=311&view=rev
Author: cduncan
Date: 2007-10-25 23:20:53 -0700 (Thu, 25 Oct 2007)
Log Message:
-----------
Use psyco if available
Modified Paths:
--------------
eos.py
Modified: eos.py
===================================================================
--- eos.py 2007-10-24 07:47:45 UTC (rev 310)
+++ eos.py 2007-10-26 06:20:53 UTC (rev 311)
@@ -9,6 +9,13 @@
import optparse
import pygame
+try:
+ import psyco
+except ImportError:
+ pass
+else:
+ psyco.full()
+
def run():
parser = optparse.OptionParser()
parser.add_option('-s', '--server',
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-24 07:47:49
|
Revision: 310
http://eos-game.svn.sourceforge.net/eos-game/?rev=310&view=rev
Author: cduncan
Date: 2007-10-24 00:47:45 -0700 (Wed, 24 Oct 2007)
Log Message:
-----------
Formative script to generate explosion animations. Considering how crude it is the results are excellent IMO.
Added Paths:
-----------
splode.py
Added: splode.py
===================================================================
--- splode.py (rev 0)
+++ splode.py 2007-10-24 07:47:45 UTC (rev 310)
@@ -0,0 +1,173 @@
+import sys
+import pygame
+from pygame.locals import *
+import random
+import time
+import itertools
+
+pygame.init()
+screen = pygame.display.set_mode((800,600))
+
+class Particle:
+
+ def __init__(self, color, pos, vel=(0,0), drag=0, initial_size=1, initial_expand=0.1, accel=1.5, accel_time=8, deccel=1.05, deccel_time=80):
+ self.velx, self.vely = vel
+ self.x = float(pos[0])
+ self.y = float(pos[1])
+ self.drag = 1.0 - drag
+ self.size = float(initial_size)
+ self.expand = initial_expand
+ self.rect = pygame.Rect(pos[0], pos[1], initial_size, initial_size)
+ self.orig_color = color
+ self.accel = accel
+ self.accel_time = accel_time
+ self.deccel = deccel
+ self.deccel_time = deccel_time
+
+ def update(self):
+ width = min(int(self.size), 500)
+ self.image = pygame.Surface((width, width), SRCALPHA, 32)
+ self.x += self.velx
+ self.y += self.vely
+ self.rect = self.image.get_rect(centerx=self.x, centery=self.y)
+ self.velx *= self.drag
+ self.vely *= self.drag
+ color = [max(min(int(c * self.expand), 255), 0) for c in self.orig_color]
+ pygame.draw.circle(self.image, color, self.image.get_rect().center, int(width / 2))
+ self.size += self.expand
+ if self.accel_time:
+ self.expand *= self.accel
+ self.accel_time -= 1
+ elif self.deccel_time:
+ self.expand /= self.deccel
+ self.deccel_time -= 1
+
+class Particle:
+
+ def __init__(self, color, pos, vel=(0,0), drag=0, initial_size=1, max_size=1, size_interval=2, fade_start=sys.maxint, fade_end=sys.maxint):
+ self.velx, self.vely = vel
+ self.x = float(pos[0])
+ self.y = float(pos[1])
+ self.drag = drag
+ self.size = float(initial_size)
+ self.max_size = float(max_size)
+ self.size_interval = float(size_interval)
+ self.fade_start = fade_start
+ self.fade_end = fade_end
+ self.frame = 0
+ self.rect = pygame.Rect(pos[0], pos[1], initial_size, initial_size)
+ self.color = list(color)
+
+ def update(self):
+ width = int(self.size)
+ self.image = pygame.Surface((width, width), SRCALPHA, 32)
+ self.x += self.velx
+ self.y += self.vely
+ self.rect = self.image.get_rect(centerx=self.x, centery=self.y)
+ self.velx -= self.velx * self.drag
+ self.vely -= self.vely * self.drag
+ if self.frame < self.fade_start:
+ color = [max(min(int(c), 255), 0) for c in self.color]
+ else:
+ fade = float(self.fade_end - self.frame) / float(self.fade_end - self.fade_start)
+ color = [max(min(int(c * fade), 255), 0) for c in self.color]
+ pygame.draw.circle(self.image, color, self.image.get_rect().center, int(width / 2))
+ self.frame += 1
+ if self.size < self.max_size:
+ self.size += (self.max_size - self.size) / self.size_interval
+
+particles = []
+rect = pygame.Rect(0,0,0,0)
+
+
+for i in range(50):
+ red=random.randint(100,200)
+ green=random.randint(50, red)
+ blue=random.randint(50, green)
+ p = Particle(
+ color=(red, green, blue, 10),
+ pos=(200,200), #(200 + random.gauss(40, 15), 200 + random.gauss(40, 15)),
+ vel=(random.gauss(0, 4), random.gauss(0, 4)),
+ drag=random.gauss(0.15, .01),
+ max_size=random.gauss(150, 10),
+ size_interval=random.uniform(35,80),
+ fade_start=random.gauss(5,1),
+ fade_end=100)
+ particles.append(p)
+ rect.union_ip(p.rect)
+
+for i in range(250):
+ red=random.randint(150,255)
+ green=random.randint(20, red)
+ blue=random.randint(0, green)
+ p = Particle(
+ color=(red, green, blue, 50),
+ pos=(200,200), #(200 + random.gauss(40, 15), 200 + random.gauss(40, 15)),
+ vel=(random.gauss(0, 4), random.gauss(0, 4)),
+ drag=random.gauss(0.35, .02),
+ max_size=random.gauss(40, 10),
+ size_interval=random.uniform(5,70),
+ fade_start=random.gauss(5,1),
+ fade_end=70)
+ particles.append(p)
+ rect.union_ip(p.rect)
+
+
+for i in range(500):
+ bright=random.gauss(200,20)
+ p = Particle(
+ color=(bright, bright, bright, 150),
+ pos=(200,200),
+ vel=(random.gauss(0, 3), random.gauss(0, 3)),
+ drag=0.1,
+ initial_size=1,
+ max_size=random.gauss(5, 1),
+ size_interval=random.uniform(60,100),
+ fade_start=random.gauss(15,12),
+ fade_end=random.gauss(80,5))
+ particles.append(p)
+ rect.union_ip(p.rect)
+
+for i in range(250):
+ red=random.randint(150,255)
+ green=random.randint(20, red)
+ blue=random.randint(0, green)
+ p = Particle(
+ color=(red, green, blue, 50),
+ pos=(200,200), #(200 + random.gauss(40, 15), 200 + random.gauss(40, 15)),
+ vel=(random.gauss(0, 4), random.gauss(0, 4)),
+ drag=random.gauss(0.35, .01),
+ max_size=random.gauss(40, 10),
+ size_interval=random.uniform(5,70),
+ fade_start=random.gauss(5,1),
+ fade_end=random.gauss(70, 10))
+ particles.append(p)
+ rect.union_ip(p.rect)
+
+frames = []
+slomo = False
+for i in range(200):
+ image = pygame.Surface(rect.size, SRCALPHA, 32)
+ for p in particles:
+ p.update()
+ image.blit(p.image, p.rect)
+ rect.union_ip(p.rect)
+ frames.append(image)
+ for event in pygame.event.get():
+ if event.type == QUIT or (
+ event.type == KEYDOWN and event.key == K_ESCAPE):
+ raise SystemExit
+screen_center = screen.get_rect().center
+for image in itertools.cycle(frames):
+ screen.fill((0, 0, 0))
+ #image = pygame.transform.rotozoom(image, 0, .5)
+ screen.blit(image, image.get_rect())
+ pygame.display.flip()
+ if slomo:
+ time.sleep(0.1)
+ for event in pygame.event.get():
+ if event.type == QUIT or (
+ event.type == KEYDOWN and event.key == K_ESCAPE):
+ raise SystemExit
+ if event.type == KEYDOWN and event.key == K_SPACE:
+ slomo = not slomo
Property changes on: splode.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-23 06:30:50
|
Revision: 309
http://eos-game.svn.sourceforge.net/eos-game/?rev=309&view=rev
Author: cduncan
Date: 2007-10-22 23:30:48 -0700 (Mon, 22 Oct 2007)
Log Message:
-----------
- Different offscreen pointies for planets
- Select planets using "p" to cycle through (click-select is next)
Modified Paths:
--------------
base.py
body.py
event.py
media.py
selection.py
staticbody.py
Modified: base.py
===================================================================
--- base.py 2007-10-21 18:35:47 UTC (rev 308)
+++ base.py 2007-10-23 06:30:48 UTC (rev 309)
@@ -50,6 +50,10 @@
self.planet = planet
self.planet.base = self
self.owner = owner
+ if owner is game.local_player:
+ planet.offscreen_img = 'pointy-planet-green'
+ else:
+ planet.offscreen_img = 'pointy-planet-red'
self.rally_point = self.planet
if max_level >= level:
self.level = level
Modified: body.py
===================================================================
--- body.py 2007-10-21 18:35:47 UTC (rev 308)
+++ body.py 2007-10-23 06:30:48 UTC (rev 309)
@@ -25,6 +25,7 @@
friend = 1
foe = 2
shot = 4
+planet = 8
nothing = 0
everything = 0x7fffffff
categories = (friend, foe)
@@ -92,7 +93,7 @@
self.enabled = True
self.on_screen = True
self.explosion = None
- self.apparent_size = None
+ self.apparent_size = 1.0
self.net_id = net_id
self.image_name = image_name
game.objects.add(self)
@@ -186,11 +187,11 @@
self.velocity = vector.vector2(*self.body.getLinearVel()[:2])
self.heading = self.get_heading()
# place self relative to the camera at proper zoom level
- apparent_size, screen_pos = vector.to_screen(self.position)
+ self.apparent_size, screen_pos = vector.to_screen(self.position)
if self.explosion is None:
- self.image = media.image(self.image_name, apparent_size, self.heading)
+ self.image = media.image(self.image_name, self.apparent_size, self.heading)
else:
- image = self.explosion.next_image(apparent_size)
+ image = self.explosion.next_image(self.apparent_size)
if image is not None:
self.image = image
else:
@@ -201,6 +202,7 @@
def draw(self, surface):
"""Draw either sprite image or offscreen pointer"""
if self.on_screen:
+ #pygame.draw.circle(surface, (255,255,255), self.rect.center, self.collision_radius * self.appsz, 2)
surface.blit(self.image, self.rect)
return self.rect
elif self.offscreen_img is not None:
Modified: event.py
===================================================================
--- event.py 2007-10-21 18:35:47 UTC (rev 308)
+++ event.py 2007-10-23 06:30:48 UTC (rev 309)
@@ -39,7 +39,6 @@
"""Top-level event handler"""
mouse_timeout = 3000 # Time to hide mouse if not moved or clicked
- base_keys = [K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9]
def __init__(self, handlers=()):
"""Dispatches pygame events to the handler's methods"""
@@ -108,6 +107,8 @@
selection.group.constrain_by_class()
elif event.key == K_e:
game.target.select_nearest(~game.local_player.category)
+ elif event.key == K_p:
+ game.target.select_next_planet()
elif event.key == K_MINUS:
game.camera.zoom_out()
elif event.key == K_EQUALS:
Modified: media.py
===================================================================
--- media.py 2007-10-21 18:35:47 UTC (rev 308)
+++ media.py 2007-10-23 06:30:48 UTC (rev 309)
@@ -208,6 +208,21 @@
set_image('pointy-blue', pointy_image((55, 80, 216)))
set_image('pointy-green', pointy_image((0, 155, 38)))
set_image('pointy-red', pointy_image((216, 36, 30)))
+ set_image('pointy-white', pointy_image((255, 255, 255)))
+ def planet_pointy_image(color):
+ pointy = pygame.Surface((160, 290), SRCALPHA, 32)
+ pygame.draw.polygon(pointy, color, [(0, 130), (80, 0), (160, 130)])
+ color2 = pygame.color.subtract(color, 60)
+ pygame.draw.polygon(pointy, color2, [(0, 130), (80, 0), (160, 130)], 15)
+ pygame.draw.circle(pointy, color2, (80, 175), 85)
+ pygame.draw.circle(pointy, (0, 0, 0, 0), (80, 190), 85)
+ pygame.draw.circle(pointy, color2, (80, 185), 60)
+ pygame.draw.circle(pointy, color, (80, 185), 45)
+ return pygame.transform.rotozoom(pointy, 0, 0.1)
+ set_image('pointy-planet-blue', planet_pointy_image((55, 80, 216)))
+ set_image('pointy-planet-green', planet_pointy_image((0, 155, 38)))
+ set_image('pointy-planet-red', planet_pointy_image((216, 36, 30)))
+ set_image('pointy-planet-white', pointy_image((255, 255, 255)))
_sound_cache = {}
_sound_last_played = {}
Modified: selection.py
===================================================================
--- selection.py 2007-10-21 18:35:47 UTC (rev 308)
+++ selection.py 2007-10-23 06:30:48 UTC (rev 309)
@@ -17,7 +17,7 @@
class Target(sprite.Sprite):
- size_factor = 1.8
+ size_factor = 1.5
color = (255, 255, 255)
timeout = 2000
sensor = None
@@ -28,7 +28,8 @@
self._select_timeout = sys.maxint
self._sensor_off_frame = None
self.rect = pygame.rect.Rect(0, 0, 0, 0)
- self._nearest_iter = None
+ self._nearest_vessel_iter = None
+ self._planet_iter = None
self.sensor = ai.Sensor(source_vessel, range)
self.sensor.disable()
@@ -46,10 +47,10 @@
def select_nearest(self, category, cycle=True):
"""Select the nearest body that is in the category."""
- if self._nearest_iter is not None and self._last_category == category:
+ if self._nearest_vessel_iter is not None and self._last_category == category:
try:
while 1:
- next = self._nearest_iter.next()
+ next = self._nearest_vessel_iter.next()
if next is not self.selected.sprite and (
getattr(next, 'vessel_type', None) != 'missile'):
# Ensure we always select a new target
@@ -58,25 +59,33 @@
return
except StopIteration:
if cycle:
- self._nearest_iter = (body for body in self.sensor.detected if body.alive())
+ self._nearest_vessel_iter = (body for body in self.sensor.detected
+ if body.alive())
nearest = self.select_nearest(category, cycle=False)
else:
- self._nearest_iter = None
+ self._nearest_vessel_iter = None
self.sensor.setDetect(category)
self._last_category = category
# Enable the sensor for the next few frames
self._sensor_off_frame = game.frame_no + 3
self.sensor.enable()
+ def select_next_planet(self):
+ if self._planet_iter is None:
+ self._planet_iter = itertools.cycle(game.map.planets)
+ self.sensor.disable()
+ self.select(self._planet_iter.next())
+
def update(self):
if game.time > self._select_timeout:
# forget about all previously selected targets
- self._nearest_iter = None
+ self._nearest_vessel_iter = None
+ self._planet_iter = None
self._select_timeout = sys.maxint
if self.sensor.enabled:
if self.sensor.closest_vessel:
# See what our sensor detected
- self._nearest_iter = (body for body in self.sensor.detected if body.alive())
+ self._nearest_vessel_iter = (body for body in self.sensor.detected if body.alive())
self.select_nearest(self._last_category)
self.sensor.disable() # Stop detection
elif game.frame_no > self._sensor_off_frame:
@@ -88,13 +97,14 @@
if target is not None:
# To avoid lagging behind the target, we update our rect here
# which guarantees that the target's rect is already updated
- if hasattr(target, 'collision_radius'):
- width = target.collision_radius * 2 * self.size_factor
- else:
- width = max(target.rect.size) * self.size_factor
+ width = target.collision_radius * 3 * target.apparent_size
+ if width <= max(target.rect.size):
+ # compensate for smaller collision radii
+ width *= 2
+ width = max(width, 3)
rect.center = target.rect.center
rect.size = (width, width)
- line_len = max(self.rect.width / 10, 4)
+ line_len = min(max(self.rect.width / 10, 3), 75)
pygame.draw.line(surface, self.color,
(rect.left, rect.centery), (rect.left + line_len, rect.centery))
pygame.draw.line(surface, self.color,
Modified: staticbody.py
===================================================================
--- staticbody.py 2007-10-21 18:35:47 UTC (rev 308)
+++ staticbody.py 2007-10-23 06:30:48 UTC (rev 309)
@@ -23,11 +23,12 @@
layer = sprite.layers.background
def __init__(self, name, image, x=0, y=0, resources=0, net_id=None):
- RoundBody.__init__(self, position=(int(x), int(y)), heading=-vector.rightangle, net_id=net_id)
+ RoundBody.__init__(self, position=(int(x), int(y)), heading=-vector.rightangle,
+ net_id=net_id)
self.body.disable() # immobile
self.name = name
self.image_name = random.choice(image.split(','))
- self.offscreen_img = 'pointy-blue'
+ self.offscreen_img = 'pointy-planet-blue'
self.collision_radius = self.radius = media.image(self.image_name).get_rect().width / 2
self.resources = float(resources)
self.update()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-21 18:35:49
|
Revision: 308
http://eos-game.svn.sourceforge.net/eos-game/?rev=308&view=rev
Author: cduncan
Date: 2007-10-21 11:35:47 -0700 (Sun, 21 Oct 2007)
Log Message:
-----------
Add a fixed sleep interval per frame (more if in windowed mode) to even out
the framerate especially when other processes are burning lots of cpu
(*cough* pandora *cough*). Even though this reduces the maximum framerate
possible, it makes things noticably smoother to me overall.
Modified Paths:
--------------
game.py
Modified: game.py
===================================================================
--- game.py 2007-10-21 08:57:23 UTC (rev 307)
+++ game.py 2007-10-21 18:35:47 UTC (rev 308)
@@ -226,6 +226,10 @@
next_wave = 0
this_frame_time = last_frame_time = 1000 / fps
event_handler = event.MainHandler([panel.handler])
+ if windowed:
+ sleep_time = 0.01
+ else:
+ sleep_time = 0.0015
while 1:
event_handler.handle_events()
keystate = pygame.key.get_pressed()
@@ -243,8 +247,7 @@
server.step()
last_time = time
time += clock.tick()
- if windowed and time - last_time < 33:
- sleep(0.02)
+ sleep(sleep_time)
last_frame_time = this_frame_time
this_frame_time = min(time - last_time, last_frame_time * 3)
fps = clock.get_fps() or fps
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-21 08:57:25
|
Revision: 307
http://eos-game.svn.sourceforge.net/eos-game/?rev=307&view=rev
Author: cduncan
Date: 2007-10-21 01:57:23 -0700 (Sun, 21 Oct 2007)
Log Message:
-----------
Base the star movement solely on the camera, instead of
approximating it from the camera target's movement.
This eliminates the need to special-case panning
Modified Paths:
--------------
camera.py
stars.py
Modified: camera.py
===================================================================
--- camera.py 2007-10-21 08:40:25 UTC (rev 306)
+++ camera.py 2007-10-21 08:57:23 UTC (rev 307)
@@ -45,11 +45,7 @@
def update(self):
if not self.target.alive():
self.acquire_target()
- old_offset = self.offset
self.offset *= self.centering
- panning = old_offset - self.offset
- if vector.length(panning) >= 1:
- game.starfield.move(vector.to_tuple(panning))
accel = self.target.velocity - self.last_velocity
self.offset += -vector.normal(accel) * (vector.length(accel) / self.adhesion)**2
self.last_velocity = self.target.velocity
Modified: stars.py
===================================================================
--- stars.py 2007-10-21 08:40:25 UTC (rev 306)
+++ stars.py 2007-10-21 08:57:23 UTC (rev 307)
@@ -25,6 +25,7 @@
big_star_count = 30
parallax_depths = 20
parallax_factor = 0.95
+ last_camera_pos = None
def __init__(self, rect):
sprite.Sprite.__init__(self, sprite.layers.background)
@@ -131,5 +132,7 @@
self.nebula_pos[1] += vec[1] * 0.15
def update(self):
- star_velocity = game.camera.zoom * -game.camera.target.velocity / game.fps
- self.move(vector.to_tuple(star_velocity))
+ if self.last_camera_pos is not None:
+ star_velocity = game.camera.zoom * (self.last_camera_pos - game.camera.position)
+ self.move(vector.to_tuple(star_velocity))
+ self.last_camera_pos = game.camera.position
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cd...@us...> - 2007-10-21 08:40:27
|
Revision: 306
http://eos-game.svn.sourceforge.net/eos-game/?rev=306&view=rev
Author: cduncan
Date: 2007-10-21 01:40:25 -0700 (Sun, 21 Oct 2007)
Log Message:
-----------
Stars now pan properly with the camera
Modified Paths:
--------------
camera.py
Modified: camera.py
===================================================================
--- camera.py 2007-10-21 05:41:31 UTC (rev 305)
+++ camera.py 2007-10-21 08:40:25 UTC (rev 306)
@@ -45,7 +45,11 @@
def update(self):
if not self.target.alive():
self.acquire_target()
+ old_offset = self.offset
self.offset *= self.centering
+ panning = old_offset - self.offset
+ if vector.length(panning) >= 1:
+ game.starfield.move(vector.to_tuple(panning))
accel = self.target.velocity - self.last_velocity
self.offset += -vector.normal(accel) * (vector.length(accel) / self.adhesion)**2
self.last_velocity = self.target.velocity
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|