此次做的是一个模拟windows桌面屏幕保护程序—气泡,截图如下:
情景是:
气泡之间有碰撞行为,并满足简单的物理规律,气泡遇到边界会反弹
代码如下:
#encoding:utf-8
import pygame
from pygame.locals import *
from random import randint
from gameobjects.vector2 import Vector2
SCREEN_SIZE = (1366, 768)
screen = pygame.display.set_mode(SCREEN_SIZE, FULLSCREEN, 32)
class World(object):
def __init__(self):
self.entities = []
def add_entity(self, entity):
if entity is None:
return
self.entities.append(entity)
def remove(self, entity):
pass
def process(self, time_passed_seconds):
for entity in self.entities:
entity.process(self, time_passed_seconds)
def get_crash_entity(self, world, bubble):
for entity in world.entities:
if entity.name == bubble.name:
continue
else:
point_distance = entity.point - bubble.point
point_distance_len =point_distance.get_magnitude()
if point_distance_len <= bubble.size[0]:
bubble.speed, entity.speed = entity.speed, bubble.speed #exchange two bubbles' speed
return entity
return None
class State(object):
def __init__(self,name):
self.name = name
def check_conditions(self):
pass
def do_actions(self):
pass
class Traveling(State):
def __init__(self, entity):
State.__init__(self, "traveling")
self.bubble = entity
return None
def check_conditions(self,world, bubble):
entity = world.get_crash_entity(world, bubble)
if entity is None:
return "traveling"
return "crash"
def do_actions(self):
print "traveling!"
class Crash(State):
def __init__(self, entity):
State.__init__(self, "crash")
self.bubble = entity
def check_conditions(self,world, bubble):
return "traveling"
def do_actions(self):
print "crash!"
class StateMachine(object):
def __init__(self):
self.states = {} #States is used to store every kinds of state
self.active_state = None
def add_state(self, state):
self.states[state.name] = state
self.active_state = state #set current state as active_state
def think(self,world,bubble): #think() is the most important function
if self.active_state is None: #it is busy to judge the conditions and adjust the bubbles' actions
return
new_state_name = self.active_state.check_conditions(world,bubble)
if new_state_name is not None:
self.set_state(new_state_name)
def set_state(self, new_state_name):
self.active_state = self.states[new_state_name]
self.active_state.do_actions()
class Bubble(object):
def __init__(self, name, speed, position, image):
self.name = name
self.speed = speed
self.pos = position #left-top position
self.image = image
self.crash_id = None
self.size = self.image.get_size()
self.point = Vector2(self.pos.x + self.size[0]/2, self.pos.y + self.size[1]/2)
self.brain = StateMachine()
traveling = Traveling(self)
crash = Crash(self)
self.brain.add_state(crash)
self.brain.add_state(traveling)
def check_bounder(self):
if self.pos.x >= SCREEN_SIZE[0]-self.size[0]:
self.speed.x = -self.speed.x
if self.pos.x <= 0:
self.speed.x = -self.speed.x
if self.pos.y >= SCREEN_SIZE[1]-self.size[1]:
self.speed.y = -self.speed.y
if self.pos.y <= 0:
self.speed.y = -self.speed.y
def process(self, world, time_passed_seconds):
self.check_bounder()
self.brain.think(world, self)
self.pos += self.speed * time_passed_seconds
self.point = Vector2(self.pos.x + self.size[0]/2, self.pos.y + self.size[1]/2)
screen.blit(self.image, self.pos)
def run():
world = World()
bubble_image = []
Bubbles = []
for i in range(8):
bubble_tmpimage = pygame.image.load(r'bubble/bubble%d.png' %i).convert_alpha()
bubble_image.append(bubble_tmpimage)
speed_tmp = Vector2(randint(60,300), randint(60,300))
position_tmp = Vector2(randint(0,600),randint(0,300))
tmp_bubble = Bubble('bubble%d' %i, speed_tmp, position_tmp, bubble_image[i])
Bubbles.append(tmp_bubble)
world.add_entity(Bubbles[i])
pygame.init()
clock = pygame.time.Clock()
while True:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == QUIT:
return
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
return
time_passed = clock.tick()
time_passed_seconds = time_passed / 1000.
world.process(time_passed_seconds)
pygame.display.update()
if __name__ == "__main__":
run()
为帮助理解状态机具体工作流程,可参考如下线索(参见代码):
run() —> world.process()—> bubble.process() —> StateMachine.think()—> check_conditions()—>traveling/crash
气泡(bubble)有两张状态,一种是自由移动,一种是当和其他气泡碰撞行为(严格来说,碰撞并不是一种状态,倒不如说是一个动作,这里是为了举例方便)
Traveling 和crash 是State的子类,在StateMachine中用self.states(字典)来存储bubble当前的状态。
每一个bubble都会实例化一个StateMachine,用来监控或者他们的环境还有做出相应行为。
在run()函数中的while True中总是调用world.process(),这个方法调用了每个bubble的process方法,用来时刻刷新bubble的数据。在bubble.process 中使用了StakeMachine.think()方法,这个方法总是依据bubble的当前状态(traveling or crash)监视bubble的环境(check_conditions()),并作出相应的行为,check_conditons()的返回值很关键,因为他决定下一次bubble的状态是什么。
如果需要源码,资源以及可执行文件的可以到我的下载频道下载
欢迎交流指误