随机生成路径(二)

对上一个版本更改了一下,使得原动作可以自定义。

#baseAnimation.py
import math

#define world direction
Dir_Up, Dir_Right, Dir_Down, Dir_Left = range(0, 4)

#define move direction to local
Move_Left, Move_Forward, Move_Right = range(-1, 2)


class BaseAnimation:
def __init__(self, move_dir, v_step, h_step):

#定义动作的横向和纵向跨度
self.v_step = v_step
self.h_step = h_step

#动作作用方向(-1,左)(0,直)(1,右)
self.Move_Dir = move_dir
pass

#检测是否穿过了障碍物
def is_in_block(self, cur_pos, new_pos, block_map):
cur_x = cur_pos[0]
cur_y = cur_pos[1]
new_x = new_pos[0]
new_y = new_pos[1]

#增长系数
itr_x = -1
itr_y = -1
if new_x > cur_x:
itr_x = 1

if new_y > cur_y:
itr_y = 1

for i in range(cur_x, new_x+itr_x, itr_x):
for j in range(cur_y, new_y+itr_y, itr_y):
#print("check[%s][%s]"%(j,i))
if block_map[j][i] > 0:
return True

return False

#传入当前位置,当前方向,以及边界,障碍图
def after_move(self, cur_pos, cur_dir, border, block_map):
new_x = cur_pos[0]
new_y = cur_pos[1]
border_x = border[0]
border_y = border[1]
new_dir = (cur_dir + self.Move_Dir)%4
can_move = True

if cur_dir == Dir_Up:
new_x = new_x + self.h_step
new_y = new_y + self.v_step
elif cur_dir == Dir_Right:
new_x = new_x + self.v_step
new_y = new_y - self.h_step
elif cur_dir == Dir_Down:
new_x = new_x - self.h_step
new_y = new_y - self.v_step
elif cur_dir == Dir_Left:
new_x = new_x - self.v_step
new_y = new_y + self.h_step

if new_x < 0 or new_x > border_x-1 or new_y < 0 or new_y > border_y -1:
can_move = False
else:
if self.is_in_block(cur_pos, [new_x,new_y], block_map):
can_move = False

#print("can_move:%s|new_pos:%s,%s|new_dir:%s"%(can_move,new_x, new_y, new_dir))
return [can_move, [new_x, new_y], new_dir]



pass

def draw_path(self, cur_pos, cur_dir, color, width):

pass


##if __name__ == "__main__":
#
# testAnim = BaseAnimation(Move_Right, 0, 1)

## for i in range(0,4):
#
# testAnim.after_move([0,0],i, [8,8], None)

在生成路径过程中对各个元动作进行数量的限制。增加了鼠标点击事件,选中目标点然后生成路径。

import pygame
import math
import random

from baseAnimation import *

black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)

done = False


#define baseAnimationList
anim_list = [BaseAnimation(Move_Left, 0, -1), BaseAnimation(Move_Forward, 1, 0),
BaseAnimation(Move_Right, 0, 1), BaseAnimation(Move_Left, 0, -2),
BaseAnimation(Move_Right, 0, 3), BaseAnimation(-2, -1,-1)]



#define block type
Block_Blank,Block_Hold=range(0,2)

pygame.init()

size = [800, 600]

screen = pygame.display.set_mode(size)


pygame.display.set_caption("Animation Path")

def dir_str(cur_dir):
dir_str = ""
if cur_dir == Dir_Up:
dir_str = ""
elif cur_dir == Dir_Right:
dir_str = ""
elif cur_dir == Dir_Down:
dir_str = ""
elif cur_dir == Dir_Left:
dir_str = ""

return dir_str

def movestate_str(move_state):
move_str = ""
if move_state == Move_Left:
move_str = "Turn Left"
elif move_state == Move_Forward:
move_str = "Forward"
elif move_state == Move_Right:
move_str = "Turn Right"

return move_str

class TraceListener:
def __init__(self):
#设置动作个数限制
self.max_list = [5,5,5,1,1,1]

def constrain(self, anim_count, state):
if anim_count[state] > self.max_list[state]:
#print("anim_%s over"%(state))
return True
return False

class AnimationPath:
def __init__(self):
self.width = 10
self.height = 10
self.cell_size = 50
self.max_depth = 20

self.one_step = 1

self.start_pos = [0,0]

self.begin_pos = [0,0]
self.end_pos = [8,8]

self.path_width = 2

self.block_map = []

self.is_find = False
self.trace_listener = TraceListener()

self.initialize()

def initialize(self):
self.result_list = []
self.count = 0
self.recursive_count = 0

#统计动作使用数
self.anim_count = {}
#溢出,需重新找
self.need_refind = False

def init_block(self):
self.block_map[3][2] = 1
self.block_map[3][3] = 1
self.block_map[3][4] = 1
self.block_map[3][5] = 1
self.block_map[6][2] = 1
self.block_map[6][3] = 1
self.block_map[6][4] = 1


def draw_board(self):
start_pos = self.start_pos
total_width = self.width * self.cell_size
total_height = self.height * self.cell_size

#draw board lines 此处borad左移了cell_size/2
#"|"
for i in range(0, self.width+1):
begin_pos_x = start_pos[0] + i * self.cell_size - self.cell_size/2
end_pos_y = start_pos[1] - total_height
pygame.draw.line(screen, white, [begin_pos_x,start_pos[1]],
[begin_pos_x, end_pos_y], 1)
#"--"
for j in range(0, self.height+1):
begin_pos_y = start_pos[1] - j * self.cell_size
end_pos_x = start_pos[0] + total_width - self.cell_size/2
pygame.draw.line(screen, white, [start_pos[0] - self.cell_size/2, begin_pos_y],
[end_pos_x, begin_pos_y], 1)

#draw board elements
for row in range(0, self.height):
for col in range(0, self.width):
if self.block_map[row][col] == Block_Hold:
pygame.draw.circle(screen, yellow,
[start_pos[0] + col * self.cell_size,
start_pos[1] - row * self.cell_size-self.cell_size/2],
self.cell_size/2,
0)

#draw end_pos
pygame.draw.circle(screen, red,
[start_pos[0] + (self.end_pos[0]) * self.cell_size,
start_pos[1] - (self.end_pos[1]) * self.cell_size - self.cell_size/2],
self.cell_size/2,
0)

def draw_line(self, start_pos, end_pos, color, width):
pygame.draw.line(screen,color,
start_pos,
end_pos,
width)

def draw_arc(self, pos, diameter, section, color, width):
pygame.draw.arc(screen, color,
[pos[0] - diameter/2, pos[1] - diameter/2, diameter, diameter],
math.radians((section-1) * 90),
math.radians(section * 90),
width)

#根据方向获得真正的坐标位置
def get_real_pos(self, cur_pos, cur_dir):
base_x = self.start_pos[0]
base_y = self.start_pos[1]

real_x = self.start_pos[0] + cur_pos[0] * self.cell_size
real_y = self.start_pos[1] - cur_pos[1] * self.cell_size
if cur_dir == Dir_Up:
pass
elif cur_dir == Dir_Right:
real_x -= self.cell_size/2
real_y -= self.cell_size/2
elif cur_dir == Dir_Down:
real_y -= self.cell_size
elif cur_dir == Dir_Left:
real_x += self.cell_size/2
real_y -= self.cell_size/2

return [real_x, real_y]


#画出行走路线
def draw_path(self, cur_pos, cur_dir, move_anim, color, width):
cur_x = cur_pos[0]
cur_y = cur_pos[1]


new_state = move_anim.after_move(cur_pos, cur_dir, [self.width,self.height], self.block_map)

new_x = new_state[1][0]
new_y = new_state[1][1]

new_dir = new_state[2]

real_cur_pos = self.get_real_pos(cur_pos, cur_dir)
real_new_pos = self.get_real_pos([new_x, new_y], new_dir)

self.draw_line(real_cur_pos, real_new_pos, color, width)

pass


#根据现在的方向和动作判断下一个位置
def move_to_next(self, cur_pos, cur_dir, move_anim):
return move_anim.after_move(cur_pos, cur_dir,[self.width, self.height], self.block_map)


#递归移动
def traceback_move(self, cur_pos, cur_dir, end_dir):
self.recursive_count += 1
#print("count:%s"%self.recursive_count)

if self.recursive_count > self.max_depth:
#print("over flow")
self.need_refind = True
return False

if not self.is_find:

cur_x = cur_pos[0]
cur_y = cur_pos[1]

if cur_x == self.end_pos[0] and cur_y == self.end_pos[1]:
print("cur_dir:%s|end_dir:%s"%(dir_str(cur_dir), dir_str(end_dir)))
if end_dir <> None:
if end_dir == cur_dir:
self.count= self.count + 1
print ("reach goal with dir%s"%self.count)
#reslut_list.append([cur_x, cur_y])
self.is_find = True
self.need_rfind = False
return True
else:
self.need_rfind = True
return False
else:
self.count= self.count + 1
print ("reach goal not dir%s"%self.count)
#reslut_list.append([cur_x, cur_y])
self.is_find = True
self.need_rfind = False
return True

else:
state_list = range(0,len(anim_list))
while len(state_list) > 0:
#获得随机值
state_left = len(state_list)
state_index = random.randint(0, state_left-1)
state = state_list[state_index]
state_list.remove(state)
move_anim = anim_list[state]
if state in self.anim_count.keys():
self.anim_count[state] +=1
else:
self.anim_count[state] = 1

#限制数目
if self.trace_listener:
if self.trace_listener.constrain(self.anim_count, state):
self.anim_count[state] -= 1
continue
#是否可移动
move_result = self.move_to_next(cur_pos, cur_dir, move_anim)
if move_result[0]:
cur_x = move_result[1][0]
cur_y = move_result[1][1]

new_dir = move_result[2]


if self.traceback_move([cur_x,cur_y], new_dir, end_dir):
print ("[%s,%s]:%s:%s"%(cur_pos[0], cur_pos[1],dir_str(cur_dir), movestate_str(move_anim.Move_Dir)))
self.result_list.append([cur_pos,cur_dir,move_anim])
return True

else:
self.anim_count[state] -=1
else:
self.anim_count[state] -= 1
return False
else:
return True
pass


def calc_board_size(self, start_pos, end_pos):
self.end_pos[0] = abs(end_pos[0] - start_pos[0])/self.cell_size
self.end_pos[1] = abs(end_pos[1] - start_pos[1])/self.cell_size

#self.height = height+1
#self.width = width+1

for row in range(0,self.height):
per_row = [0]*self.width
self.block_map.append(per_row)

def findPath(self, start_pos, end_pos, start_dir, end_dir = None):
self.is_find = False
cur_x = 0
cur_y = 0
cur_dir = start_dir
self.start_pos = start_pos
self.calc_board_size(start_pos, end_pos)

self.init_block()
while not self.is_find:
self.initialize()
self.traceback_move([cur_x, cur_y], cur_dir, end_dir)
if not self.is_find and self.need_refind:
self.initialize()
self.traceback_move([cur_x, cur_y], cur_dir, end_dir)

print ("sum_anim:%s"%(len(self.result_list)))

sum_count = 0
for index in self.anim_count:
sum_count += self.anim_count[index]
print("Anim_%s:%s"%(index, self.anim_count[index]))
print ("sum_count:%s"%(sum_count))

def draw_result(self):
for step in self.result_list:
self.draw_path(step[0], step[1], step[2], green, 2)




s_pos = [100,500]
e_pos = [350,150]
c_dir = Dir_Up
anim_path = AnimationPath()
anim_path.findPath(s_pos, e_pos, c_dir)
##
results = anim_path.result_list
results.reverse()
step_index = 0

one_step = False

while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True

if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
one_step = not one_step
elif event.key == pygame.K_LEFT:
if step_index > 0:
step_index = step_index - 1
elif event.key == pygame.K_RIGHT:
if step_index < len(results)-1:
step_index = step_index + 1

elif event.key == pygame.K_g:
print ("G")
anim_path.findPath(s_pos, e_pos, c_dir)
results = anim_path.result_list
results.reverse()
step_index = 0
if event.type == pygame.MOUSEBUTTONUP:
e_pos = pygame.mouse.get_pos()
anim_path.findPath(s_pos, e_pos, c_dir)
results = anim_path.result_list
results.reverse()
step_index = 0


screen.fill(black)
anim_path.draw_board()
## for i in range(0,3):
#
# anim_path.draw_path([1,1], 3, i, red, 3)

anim_path.draw_result()

# pygame.draw.circle(screen, red, e_pos, 2, 0);

if not one_step:
for i in range(0,step_index+1):
step = results[i]
anim_path.draw_path(step[0],step[1],step[2], red, 3)
else:
step = results[step_index]
anim_path.draw_path(step[0],step[1],step[2], red, 3)
pygame.display.flip()
#clock.tick(5)

pygame.quit()

附上结果图:




原文地址:https://www.cnblogs.com/gameprogram/p/2285672.html