使用状态机实现简单的AI

此次做的是一个模拟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的状态是什么。

如果需要源码,资源以及可执行文件的可以到我的下载频道下载

欢迎交流指误



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值