# _*_ coding:utf-8 _*_
from random import randint
import sys
import pygame
from pygame.locals import *
from gameobjects.vector2 import Vector2
import time
__author__ = 'admin'
'''
蚂蚁状态机(二)
目标1:实现蚂蚁的状态机,并实现蚂蚁的等待和探索机制
已完成信号0/1,状态WaitSate/ExploreState
目标2:实现在屏幕中生成叶子Leaf
已完成
目标3:如果蚂蚁活动范围内100像素内存下叶子,则奔向叶子
之前不成功的原因是因为没有为各个对象绑定micr,以致于micr中objects_dict不能被所有对象共享使用
已经实现蚂蚁全屏搜索叶子吗,遇到叶子并将叶子吃掉
目标4:在屏幕上若有一个叶子被吃掉,再生出一个叶子
可以实现,只要将生成叶子的循环处加一个变量控制即可,即总叶子数-剩余叶子数=要生产的叶子数
目标5:实现叶子随机产生,不固定数目
已经实现,比目标4要简单的多
目标6:实现蚂蚁将叶子搬回蚁巢
待实现
'''
SCREEN_SIZE = (640, 480)
NEST_POSITION = (320, 240)
NEST_SIZE = 100.
WHITE = (255, 255, 255)
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
clock = pygame.time.Clock()
class Microcosm(object):
def __init__(self):
self.objects_dict = {}
self.obj_id = 0
self.objects_list = []
def addObj(self, obj):
self.objects_list.append(obj)
self.objects_dict[self.obj_id] = obj
# 是在这个位置为对象附上id属性的,下面删除字典元素时要用到这个id
obj.id = self.obj_id
self.obj_id += 1
def getObj(self, obj_id):
return self.objects[obj_id]
def get_closeTo_obj(self, name, location, range=50):
for obj in self.objects_dict.values():
if obj.name == name:
distance = location.get_distance_to(obj.location)
if distance <= range:
return obj
return None
class ObjProduct(object):
def __init__(self, microcosm, name, path):
self.microcosm = microcosm
self.name = name
self.op_path = path
self.op = pygame.image.load(self.op_path).convert_alpha()
self.state = 0
self.fsm = None
self.id = 0
self.speed = 0
self.location = Vector2(0, 0)
self.destination = Vector2(0, 0)
def bind(self, state, fsm):
self.fsm = fsm
self.state = state
class Leaf(ObjProduct):
def __init__(self, microcosm, name, path):
ObjProduct.__init__(self, microcosm, name, path)
self.leaf = self.op
self.location = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))
self.leaf_position = self.location
self.draw(self.leaf_position)
def draw(self, location):
screen.blit(self.leaf, location)
def wait(self):
self.draw(self.leaf_position)
class Ant(ObjProduct):
def __init__(self, microcosm, name, path):
ObjProduct.__init__(self, microcosm, name, path)
self.ant = self.op
self.location = Vector2(100, 100)
self.ant_position = self.location
self.draw(self.ant_position)
self.destination = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))
def draw(self, location):
screen.blit(self.ant, location)
def explore(self):
# print("探索中.....")
distance = self.destination - self.ant_position
# 获取此时蚂蚁距离目标点间的向量长度(即两点间的实际距离)
x = self.ant_position.get_distance_to(self.destination)
# 获取单位向量,即每次蚂蚁移动的向量
heading = distance.normalise()
# 如果蚂蚁再移动单位向量就会越过目标点
if x <= heading.get_length():
# print("到达目的地了....前往下一个点")
self.destination = Vector2(randint(0, SCREEN_SIZE[0] // 2), randint(0, SCREEN_SIZE[1] // 2))
else:
self.ant_position += heading
self.draw(self.ant_position)
def wait(self):
# print("停顿下,思考人生.....")
self.draw(self.ant_position)
class State(object):
def exec(self, obj):
pass
def exit(self, obj):
pass
class ExploreState(State):
def exec(self, obj):
leaf_ = obj.microcosm.get_closeTo_obj('leaf', obj.location)
if leaf_ is not None:
# print("发现目标叶子")
obj.destination = leaf_.location
distance = obj.destination - obj.ant_position
# 获取此时蚂蚁距离目标点间的向量长度(即两点间的实际距离)
x = obj.ant_position.get_distance_to(obj.destination)
# 获取单位向量,即每次蚂蚁移动的向量
heading = distance.normalise()
# 如果蚂蚁再移动单位向量就会越过目标点
if x <= heading.get_length():
# 让蚂蚁吃掉叶子,即在字典和列表中删除叶子对象,以防止下一次explore时蚂蚁距离该叶子还很近再被拉回
obj.microcosm.objects_dict.pop(leaf_.id)
obj.microcosm.objects_list.remove(leaf_)
obj.explore()
class WaitSate(State):
def exec(self, obj):
obj.wait()
class StateMachine(object):
def __init__(self):
self.states = {0: WaitSate(), 1: ExploreState()}
def changeState(self, newState, objs):
for obj in objs:
if obj.name == 'leaf':
curFsm = self.states[0]
curFsm.exec(obj)
elif obj.name == 'ant':
if newState == obj.state:
oldFsm = self.states[obj.state]
oldFsm.exec(obj)
else:
newFsm = self.states[newState]
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()
micr = Microcosm()
sm = StateMachine()
for i in range(1):
ant = Ant(micr, 'ant', r"E:\PycharmProjects\PGStudy\resource\ant.png")
ant.bind(0, sm.states[0])
micr.addObj(ant)
left_ln = 0
while True:
checkForOut()
screen.fill(WHITE)
pygame.draw.circle(screen, (200, 255, 200), NEST_POSITION, int(NEST_SIZE))
if randint(1, 100) == 1:
leaf = Leaf(micr, 'leaf', r"E:\PycharmProjects\PGStudy\resource\leaf.png")
leaf.bind(0, sm.states[0])
micr.addObj(leaf)
# 用于控制蚂蚁的停顿状态
if randint(0, 50) == -1:
state = 0
else:
state = 1
sm.changeState(state, micr.objects_list)
pygame.display.update()
pygame.time.delay(10)