大家好啊,今天就来跟大家分享一下Python Pyglet的实战样例吧。
一.导入所需模块
1.导入__future__模块
首先,我们需要导入__future__模块中的division变量,此变量在__future__.py中的定义如下:
division = _Feature((2, 2, 0, "alpha", 2),
(3, 0, 0, "alpha", 0),
CO_FUTURE_DIVISION)
导入方法如下:
from __future__ import division
2.导入基本模块
我们需要导入一些基本模块:sys(用于退出游戏)、random(随机生成迷宫)、math(进行运算)、time(进行基础的时间设置):
import sys
import math
import random
import time
3.导入deque队列
在这个项目中我们需要使用deque队列,所以我们需要导入deque队列:
from collections import deque
4.导入pyglet模块
我们需要使用pyglet模块进行绘制、检测按键等,所以需要导入pyglet模块:
from pyglet import image
from pyglet.gl import *
from pyglet.graphics import TextureGroup
from pyglet.window import key, mouse
5.导入Enum变量
我们现在需要从enum.py中导入Enum变量,Enum变量在enum.py中的定义方法如下:
Enum = Flag = EJECT = _stdlib_enums = ReprEnum = None
导入方法如下:
from enum import Enum
二.定义基础常量
我们需要定义帧率、重力、方块大小、最大跳跃高度等常量:
TICKS_PER_SEC = 60
SIZEG = 10
SECTOR_SIZE = 16
WALKING_SPEED = 4
FLYING_SPEED = 15
GRAVITY = 20.0
MAX_JUMP_HEIGHT = 1.125
JUMP_SPEED = math.sqrt(2 * GRAVITY * MAX_JUMP_HEIGHT)
TERMINAL_VELOCITY = 50
PLAYER_HEIGHT = 2
if sys.version_info[0] >= 3:
xrange = range
三.随机创建地图
随机地图算法的代码:
class MAP_ENTRY_TYPE(Enum):
MAP_EMPTY = 0,
MAP_BLOCK = 1,
class WALL_DIRECTION(Enum):
WALL_LEFT = 0,
WALL_UP = 1,
WALL_RIGHT = 2,
WALL_DOWN = 3,
class Map():
def __init__(self, width, height):
self.width = width
self.height = height
self.map = [[0 for x in range(self.width)] for y in range(self.height)]
def resetMap(self, value):
for y in range(self.height):
for x in range(self.width):
self.setMap(x, y, value)
def setMap(self, x, y, value):
if value == MAP_ENTRY_TYPE.MAP_EMPTY:
self.map[y][x] = 0
elif value == MAP_ENTRY_TYPE.MAP_BLOCK:
self.map[y][x] = 1
def isVisited(self, x, y):
return self.map[y][x] != 1
def checkAdjacentPos(map, x, y, width, height, checklist):
directions = []
if x > 0:
if not map.isVisited(2*(x-1)+1, 2*y+1):
directions.append(WALL_DIRECTION.WALL_LEFT)
if y > 0:
if not map.isVisited(2*x+1, 2*(y-1)+1):
directions.append(WALL_DIRECTION.WALL_UP)
if x < width - 1:
if not map.isVisited(2*(x+1)+1, 2*y+1):
directions.append(WALL_DIRECTION.WALL_RIGHT)
if y < height - 1:
if not map.isVisited(2*x+1, 2*(y+1)+1):
directions.append(WALL_DIRECTION.WALL_DOWN)
if len(directions):
direction = random.choice(directions)
if direction == WALL_DIRECTION.WALL_LEFT:
map.setMap(2*(x-1)+1, 2*y+1, MAP_ENTRY_TYPE.MAP_EMPTY)
map.setMap(2*x, 2*y+1, MAP_ENTRY_TYPE.MAP_EMPTY)
checklist.append((x-1, y))
elif direction == WALL_DIRECTION.WALL_UP:
map.setMap(2*x+1, 2*(y-1)+1, MAP_ENTRY_TYPE.MAP_EMPTY)
map.setMap(2*x+1, 2*y, MAP_ENTRY_TYPE.MAP_EMPTY)
checklist.append((x, y-1))
elif direction == WALL_DIRECTION.WALL_RIGHT:
map.setMap(2*(x+1)+1, 2*y+1, MAP_ENTRY_TYPE.MAP_EMPTY)
map.setMap(2*x+2, 2*y+1, MAP_ENTRY_TYPE.MAP_EMPTY)
checklist.append((x+1, y))
elif direction == WALL_DIRECTION.WALL_DOWN:
map.setMap(2*x+1, 2*(y+1)+1, MAP_ENTRY_TYPE.MAP_EMPTY)
map.setMap(2*x+1, 2*y+2, MAP_ENTRY_TYPE.MAP_EMPTY)
checklist.append((x, y+1))
return True
else:
return False
def randomPrim(map, width, height):
checklist = []
checklist.append((random.randint(0, width-1), random.randint(0, height-1)))
while len(checklist):
entry = random.choice(checklist)
if not checkAdjacentPos(map, entry[0], entry[1], width, height, checklist):
checklist.remove(entry)
def doRandomPrim(map):
map.resetMap(MAP_ENTRY_TYPE.MAP_BLOCK)
randomPrim(map, (map.width-1)//2, (map.height-1)//2)
四.创建方块
我们在这个游戏中使用方块作为墙壁,方块的贴图放在文章顶部,注意这里的路径要改成自己图片的路径:
def cube_vertices(x, y, z, n):
return [
x-n, y+n, z-n, x-n, y+n, z+n, x+n, y+n, z+n, x+n, y+n, z-n, # top
x-n, y-n, z-n, x+n, y-n, z-n, x+n, y-n, z+n, x-n, y-n, z+n, # bottom
x-n, y-n, z-n, x-n, y-n, z+n, x-n, y+n, z+n, x-n, y+n, z-n, # left
x+n, y-n, z+n, x+n, y-n, z-n, x+n, y+n, z-n, x+n, y+n, z+n, # right
x-n, y-n, z+n, x+n, y-n, z+n, x+n, y+n, z+n, x-n, y+n, z+n, # front
x+n, y-n, z-n, x-n, y-n, z-n, x-n, y+n, z-n, x+n, y+n, z-n, # back
]
def tex_coord(x, y, n=4):
m = 1.0 / n
dx = x * m
dy = y * m
return dx, dy, dx + m, dy, dx + m, dy + m, dx, dy + m
def tex_coords(top, bottom, side):
top = tex_coord(*top)
bottom = tex_coord(*bottom)
side = tex_coord(*side)
result = []
result.extend(top)
result.extend(bottom)
result.extend(side * 4)
return result
TEXTURE_PATH = 'D:\\Users\\shen jia qi\\Desktop\\python资源\\游戏\\Python+PyGlet制作迷宫\\texture.png'
GRASS = tex_coords((0, 0), (0, 0), (0, 0))
STONE = tex_coords((2, 1), (2, 1), (2, 1))
GREEN = tex_coords((0, 1), (0, 1), (0, 1))
FACES = [
(0, 1, 0),
(0, -1, 0),
(-1, 0, 0),
(1, 0, 0),
(0, 0, 1),
(0, 0, -1),
]
def normalize(position):
x, y, z = position
x, y, z = (int(round(x)), int(round(y)), int(round(z)))
return (x, y, z)
def sectorize(position):
x, y, z = normalize(position)
x, y, z = x // SECTOR_SIZE, y // SECTOR_SIZE, z // SECTOR_SIZE
return (x, 0, z)
class Model(object):
def __init__(self):
self.batch = pyglet.graphics.Batch()
self.group = TextureGroup(image.load(TEXTURE_PATH).get_texture())
self.world = {}
self.shown = {}
self._shown = {}
self.sectors = {}
self.queue = deque()
self._initialize()
def _initialize(self):
n = SIZEG
s = 1
y = 0
for x in xrange(-n, n + 1, s):
for z in xrange(-n, n + 1, s):
self.add_block((x, y - 2, z), GRASS, immediate=False)
map = Map(n*2+1, n*2+1)
doRandomPrim(map)
for row in xrange(len(map.map)):
for entry in xrange(len(map.map[row])):
if map.map[row][entry] == 1:
self.add_block((-n+row, -1, -n+entry),
STONE, immediate=False)
self.add_block((-n+row, 0, -n+entry),
STONE, immediate=False)
self.add_block((-n+row, 1, -n+entry),
STONE, immediate=False)
def hit_test(self, position, vector, max_distance=8):
m = 8
x, y, z = position
dx, dy, dz = vector
previous = None
for _ in xrange(max_distance * m):
key = normalize((x, y, z))
if key != previous and key in self.world:
return key, previous
previous = key
x, y, z = x + dx / m, y + dy / m, z + dz / m
return None, None
def exposed(self, position):
x, y, z = position
for dx, dy, dz in FACES:
if (x + dx, y + dy, z + dz) not in self.world:
return True
return False
def add_block(self, position, texture, immediate=True):
if position in self.world:
self