#   _*_ coding:utf-8 _*_
from random import randint
import sys
import pygame
from pygame.locals import *
from gameobjects.vector2 import Vector2
import time__author__ = 'admin''''蚂蚁状态机(十三)新目标:若蜘蛛死亡,将蜘蛛运回巢中objects_dict中就不能将health为0的蜘蛛删除了,需要保留hunt中将蜘蛛杀死后也进入ant的trans状态改造trans状态的方法,在里面判断被携带的对象是leaf还是spider
'''
SCREEN_SIZE = (640, 480)
NEST_POSITION = (320, 240)
NEST_SIZE = 100.WHITE = (255, 255, 255)clock = pygame.time.Clock()class Microcosm(object):def __init__(self):self.objects_dict = {}self.capricious_dict = {}self.obj_id = 0self.capricious_list = []def addObj(self, obj):#   在changeState方法中需要传入一个包含所有蚂蚁对象的列表,这个列表中也包含有未被拾取的叶子self.capricious_list.append(obj)#   用于存储程序运行之后生成的所有对象及其对应的idself.objects_dict[self.obj_id] = obj#   道理同objects_dict,只不过该dict会不断的被添加和删除,主要是确定哪些叶子允许被蚂蚁seekself.capricious_dict[self.obj_id] = obj#   是在这个位置为对象附上id属性的,下面删除字典元素时要用到这个idobj.id = self.obj_idself.obj_id += 1def getObj(self, obj_id):return self.objects_dict[obj_id]def get_closeTo_obj(self, name, position, range=50):for obj in self.capricious_dict.values():if obj.name == name:distance = position.get_distance_to(obj.position)if distance <= range:return objreturn Nonedef get_obj_InNest(self, name):for obj in self.capricious_dict.values():if obj.name == name:distance = obj.position.get_distance_to(NEST_POSITION)if distance < NEST_SIZE:return objreturn None#   绘制方法存在这里,每个继承的子类都在这里绘制,无需在每个对象类中再绘制了#   每个对象类中只需要实时的变更其位置即可def draw(self, surface):surface.fill(WHITE)pygame.draw.circle(surface, (200, 255, 200), NEST_POSITION, int(NEST_SIZE))for obj in self.objects_dict.values():obj.draw(surface)class ObjProduct(object):def __init__(self, microcosm, name, path):self.microcosm = microcosmself.name = nameself.image_path = pathself.image = pygame.image.load(self.image_path).convert_alpha()self.state = 0self.fsm = Noneself.id = 0self.speed = 0self.position = Vector2(0, 0)self.destination = Vector2(0, 0)def bind(self, state, fsm):self.fsm = fsmself.state = statedef draw(self, surface):x, y = self.positionw, h = self.image.get_size()surface.blit(self.image, (x - w / 2, y - h / 2))def explore(self):print("[%s-%d]探索中....." % (self.name, self.id))distance = self.destination - self.position#   获取此时蚂蚁距离目标点间的向量长度(即两点间的实际距离)x = self.position.get_distance_to(self.destination)#   获取单位向量,即每次蚂蚁移动的向量heading = distance.normalise()#   如果蚂蚁再移动单位向量就会越过目标点if x <= heading.get_length():print("[%s-%d]到达目的地了....前往下一个点" % (self.name, self.id))# self.destination = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))return Trueelse:self.position += headingclass Spider(ObjProduct):def __init__(self, microcosm, name, path):ObjProduct.__init__(self, microcosm, name, path)self.position = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))self.health = 25def draw(self, surface):ObjProduct.draw(self, surface)#   为蜘蛛增加血条,依据health进行血量调整x, y = self.positionw, h = self.image.get_size()blood_x = x - w / 2blood_y = y + h / 2screen.fill((255, 0, 0), (blood_x, blood_y, 25, 4))screen.fill((0, 255, 0), (blood_x, blood_y, self.health, 4))def wait(self):print("[%s-%d]停顿下,思考人生....." % (self.name, self.id))pygame.time.delay(10)class Leaf(ObjProduct):def __init__(self, microcosm, name, path):ObjProduct.__init__(self, microcosm, name, path)self.position = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))def draw(self, surface):ObjProduct.draw(self, surface)class Ant(ObjProduct):def __init__(self, microcosm, name, path):ObjProduct.__init__(self, microcosm, name, path)self.position = Vector2(NEST_POSITION)self.destination = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))#   这里让leaf_id为None,单纯就是不想给它一个数字而已,避免这个默认值作为Key使用时报错self.leaf_id = None#   这里让leaf_id为None,单纯就是不想给它一个数字而已,避免这个默认值作为Key使用时报错self.spider_id = Nonedef draw(self, surface):ObjProduct.draw(self, surface)def wait(self):print("[%s-%d]停顿下,思考人生....." % (self.name, self.id))pygame.time.delay(10)class State(object):def exec(self, obj):passdef exit(self, obj):passclass ExploreState(State):def exec(self, obj):#   决定探索过程中触发wait的频率if randint(1, 1000) == 1:#   信号置为0obj.state = 0else:if obj.name == 'ant':#   检测此时是否有蜘蛛进入巢穴spider_ = obj.microcosm.get_obj_InNest('spider')#   如果有这样的蜘蛛对象if spider_ is not None:#   为当前蚂蚁对象添加该目标蜘蛛id属性(将该蜘蛛绑定到该蚂蚁上,方便调用)obj.spider_id = spider_.idobj.state = 4else:#   判断当前蚂蚁对象附近范围内是否有叶子存在,并获取这个叶子对象leaf_ = obj.microcosm.get_closeTo_obj('leaf', obj.position)#   如果有这样的叶子对象if leaf_ is not None:#   为当前蚂蚁对象添加该目标叶子id属性(将该叶子绑定到该蚂蚁上,方便调用)obj.leaf_id = leaf_.id#   信号置为seekobj.state = 2else:#   附近没有叶子就执行exploreif obj.explore():obj.destination = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))elif obj.name == 'spider':if obj.explore():obj.destination = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))class WaitSate(State):def exec(self, obj):#   执行wait方法obj.wait()#   信号置为1,使得蚂蚁再动起来obj.state = 1class SeekState(State):def exec(self, obj):#   当前蚂蚁对象是否绑定了leaf_id属性(这点可以说明蚂蚁附近是否有叶子)if obj.leaf_id is not None:#   当前蚂蚁已经有了叶子目标,capricious_dict中该叶子还未被删除,说明未被其他蚂蚁抢先拾取if obj.leaf_id in obj.microcosm.capricious_dict.keys():print("[%s-%d]发现目标叶子..走过去" % (obj.name, obj.id))#   通过已知的叶子id获取对应的叶子对象leaf_ = obj.microcosm.getObj(obj.leaf_id)#   将叶子的位置当做蚂蚁本次行为的终点obj.destination = leaf_.positionif obj.explore():print("[%s-%d]已达到目标叶子" % (obj.name, obj.id))#   将该叶子移出capricious_dict中,起到不可被seek的作用obj.microcosm.capricious_dict.pop(leaf_.id)obj.microcosm.capricious_list.remove(leaf_)#   将巢穴范围内随机的一个位置当做蚂蚁TransState的终点obj.destination = Vector2(NEST_POSITION) + Vector2(randint(-40, 40), randint(-40, 40))obj.state = 3else:#   当前蚂蚁锁定的叶子被其他蚂蚁抢先拾取print("[%s-%d]的叶子被别的蚂蚁抢先拾取...." % (obj.name, obj.id))#   叶子被别的蚂蚁抢先拾取,则把该蚂蚁绑定的叶子id置为None吧obj.leaf_id = Noneobj.state = 1else:#   当前蚂蚁附近没有叶子了,执行探索obj.state = 1class TransState(State):def exec(self, obj):global prey, prey_id# prey意为猎物,这里代指叶子或蜘蛛if obj.leaf_id is not None:prey = obj.microcosm.getObj(obj.leaf_id)prey_id = obj.leaf_idelif obj.spider_id is not None:prey = obj.microcosm.getObj(obj.spider_id)prey_id = obj.spider_idprint("[%s-%d]拾起[%s],走回巢穴..." % (obj.name, obj.id, prey.name))#   通过蚂蚁当前的位置确定其拾取到的叶子的位置-----》待优化prey.position = Vector2(obj.position)#   获取此时蚂蚁起点->终点的向量distance = obj.destination - obj.position#   获取此时蚂蚁距离目标点间的向量长度(即两点间的实际距离)x = obj.position.get_distance_to(obj.destination)#   获取单位向量,即每次蚂蚁移动的向量heading = distance.normalise()#   如果蚂蚁再移动单位向量就会越过目标点if x <= heading.get_length():# print("[Ant-%d]已回到巢穴之中" % obj.id)#   将该蚂蚁绑定的叶子id置为Noneprey_id = None#   信号置为1,继续探索obj.state = 1else:obj.position += heading#   还未将叶子运回巢穴之内,继续transobj.state = 3class HuntState(State):def exec(self, obj):#   当前蚂蚁已经有了蜘蛛目标,capricious_dict中该蜘蛛还未被删除,说明该蜘蛛还未死亡if obj.spider_id in obj.microcosm.capricious_dict.keys():print("[%s-%d]发现目标蜘蛛..走过去" % (obj.name, obj.id))spider_ = obj.microcosm.getObj(obj.spider_id)obj.destination = spider_.positionif obj.explore():print("[%s-%d]已经追击到蜘蛛" % (obj.name, obj.id))#   这里模拟攻击状态--------》待优化if randint(1, 1) == 1:print("[%s-%d]正在攻击蜘蛛" % (obj.name, obj.id))spider_.health -= 1if spider_.health <= 0:#   将该叶子移出capricious_dict中,起到不可被seek的作用,这里其实也应该将objects_dict中的该蜘蛛删除obj.microcosm.capricious_dict.pop(spider_.id)obj.microcosm.capricious_list.remove(spider_)# obj.microcosm.objects_dict.pop(spider_.id)#   将巢穴范围内随机的一个位置当做蚂蚁TransState的终点obj.destination = Vector2(NEST_POSITION) + Vector2(randint(-40, 40), randint(-40, 40))#   蜘蛛已死,开始搬运死蜘蛛回巢obj.state = 3else:#   该侵犯巢穴的蜘蛛未死亡,继续huntobj.state = 4else:#   当前蚂蚁锁定的蜘蛛被其他蚂蚁抢先杀死print("[%s-%d]锁定的蜘蛛已被其他蚂蚁杀死...." % (obj.name, obj.id))#   蜘蛛被别的蚂蚁杀死,则把该蚂蚁绑定的蜘蛛id置为None吧obj.spider_id = None#   进入exploreobj.state = 1class StateMachine(object):def __init__(self):#   状态集合self.states_Ant = {0: WaitSate(), 1: ExploreState(), 2: SeekState(), 3: TransState(), 4: HuntState()}self.states_Spider = {0: WaitSate(), 1: ExploreState()}#   改变状态def changeState(self, objs):for obj in objs:#   这里先留着吧,考虑下state是否有为None的必要if obj.state is None:returnelse:if obj.name == 'leaf':#   无状态,不做处理,其实也可以在外层先过滤掉leaf对象passelif obj.name == 'spider':# print("name[%s]--state[%d]" % (obj.name, obj.state))newFsm = self.states_Spider[obj.state]newFsm.exec(obj)else:# print("name[%s]--state[%d]" % (obj.name, obj.state))newFsm = self.states_Ant[obj.state]newFsm.exec(obj)def checkForOut():for event in pygame.event.get():if event.type == 12:sys.exit()if event.type == 2:if event.key == 27:exit()pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)micr = Microcosm()
sm = StateMachine()
for i in range(10):ant = Ant(micr, 'ant', r"E:\PycharmProjects\PGStudy\resource\ant.png")ant.bind(0, sm.states_Ant[0])micr.addObj(ant)while True:checkForOut()#   生出叶子if randint(1, 50) == 1:leaf = Leaf(micr, 'leaf', r"E:\PycharmProjects\PGStudy\resource\leaf.png")micr.addObj(leaf)if randint(1, 1000) == 1:spider = Spider(micr, 'spider', r"E:\PycharmProjects\PGStudy\resource\spider.png")micr.addObj(spider)#   将绘制方法全部封装,每次循环重刷屏幕上所有对象micr.draw(screen)sm.changeState(micr.capricious_list)pygame.display.update()pygame.time.delay(10)

PyGmae:有限状态机实践(十三)相关推荐

  1. PyGmae:有限状态机实践(十四)

    # _*_ coding:utf-8 _*_ from random import randint import sys import pygame from pygame.locals import ...

  2. PyGmae:有限状态机实践(十一)

    # _*_ coding:utf-8 _*_ from random import randint import sys import pygame from pygame.locals import ...

  3. PyGmae:有限状态机实践(十二)

    # _*_ coding:utf-8 _*_ from random import randint import sys import pygame from pygame.locals import ...

  4. PyGmae:有限状态机实践(五)

    # _*_ coding:utf-8 _*_ from random import randint import sys import pygame from pygame.locals import ...

  5. zouxy09博客原创性博文导航

    zouxy09博客原创性博文导航 zouxy09@qq.com http://blog.csdn.net/zouxy09 2012年8月21号开始了我的第一篇博文,也开始了我的研究生生涯.怀着对机器学 ...

  6. 20172310《程序设计与数据结构》(上)课程总结

    20172310 2017-2018-2<程序设计与数据结构>课程总结 博客链接 每周作业链接汇总 预备作业1:对大一上学期进行总结,谈了谈对本专业的认识和期望 预备作业2: 写了自己的优 ...

  7. ApacheCN DevOps 译文集 20211227 更新

    Docker DevOps 入门手册 零.前言 一.映像和容器 二.应用容器管理 三.编排和交付 DevOps 2.5 工具包 零.前言 一.根据资源使用情况自动缩放部署和状态集 二.自动缩放 Kub ...

  8. ApacheCN 大数据译文集 20211206 更新

    PySpark 大数据分析实用指南 零.前言 一.安装 Pyspark 并设置您的开发环境 二.使用 RDD 将您的大数据带入 Spark 环境 三.Spark 笔记本的大数据清理和整理 四.将数据汇 ...

  9. ApacheCN JavaWeb 译文集 20211017 更新

    使用 Spring5 构建 REST Web 服务 零.前言 一.一些基本知识 二.在 Spring5 中使用 Maven 构建 RESTfulWeb 服务 三.Spring 中的 Flux 和 Mo ...

最新文章

  1. 几种和边框相关的CSS样式修改
  2. Five Hundred Miles——The Innocence Mission
  3. ylbtech-LanguageSamples-PythonSample
  4. java8新特性(四)_Stream详解
  5. 公有云厂商DDoS防护产品竞品分析——内含CC的一些简单分析,貌似多是基于规则,CC策略细粒度ip/url//ua/refer...
  6. SQL Server性能计数器部署(批量)
  7. php mb strimwidth,wordpress截断函数mb_strimwidth()失效的解决方法
  8. VS2012 打包部署程序
  9. 老生常谈.优化linux内核参数
  10. POJ-2777-CountColor(线段树,位运算)
  11. 链接选项-rpath的一个问题记录
  12. android imagebutton 点击效果缩小,ImageButton和ZoomButton使用
  13. OpManager引领智能运维未来的发展方向
  14. windows常用系统命令
  15. vs2019开发android so库
  16. 在jsp中使用ECharts制作图表
  17. 聚焦“数字中国” | 以“云智原生”为基石,激发数字化创新红利
  18. 拉格朗日对偶问题的解释
  19. 项目十大管理之成本管理
  20. STC单片机获取红外解码从串口输出

热门文章

  1. 【雕爷学编程】Arduino动手做(61)---电压检测传感器
  2. 拿到天使投资是一种怎样的体验
  3. 传统学术研究中有哪些现实问题可望用区块链来解决?
  4. 丹尼斯·里奇-C语言创始人
  5. Linux语音通话如何消除回声(PulseAudio)
  6. 安装Windows操作系统纯净版
  7. C++ STL(第二十篇:算法-- 排序)
  8. 力出一孔,向工而生丨ClickPaaS毕普科技战略合并发布会圆满收官
  9. Android Verified Boot dm-verity 优化和实战
  10. c语言程序设计课程作用,《C语言程序设计》课程标准