Python实现我的世界小游戏源代码


Posted in Python onMarch 02, 2021

我的世界小游戏使用方法:

移动

前进:W,后退:S,向左:A,向右:D,环顾四周:鼠标,跳起:空格键,切换飞行模式:Tab;

选择建筑材料

砖:1,草:2,沙子:3,删除建筑:鼠标左键单击,创建建筑块:鼠标右键单击

ESC退出程序。

完整程序包请通过文末地址下载,程序运行截图如下:

Python实现我的世界小游戏源代码

from __future__ import division

import sys
import math
import random
import time

from collections import deque
from pyglet import image
from pyglet.gl import *
from pyglet.graphics import TextureGroup
from pyglet.window import key, mouse

TICKS_PER_SEC = 60

# Size of sectors used to ease block loading.
SECTOR_SIZE = 16

WALKING_SPEED = 5
FLYING_SPEED = 15

GRAVITY = 20.0
MAX_JUMP_HEIGHT = 1.0 # About the height of a block.
# To derive the formula for calculating jump speed, first solve
#  v_t = v_0 + a * t
# for the time at which you achieve maximum height, where a is the acceleration
# due to gravity and v_t = 0. This gives:
#  t = - v_0 / a
# Use t and the desired MAX_JUMP_HEIGHT to solve for v_0 (jump speed) in
#  s = s_0 + v_0 * t + (a * t^2) / 2
JUMP_SPEED = math.sqrt(2 * GRAVITY * MAX_JUMP_HEIGHT)
TERMINAL_VELOCITY = 50

PLAYER_HEIGHT = 2

if sys.version_info[0] >= 3:
  xrange = range

def cube_vertices(x, y, z, n):
  """ Return the vertices of the cube at position x, y, z with size 2*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):
  """ Return the bounding vertices of the texture square.

  """
  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):
  """ Return a list of the texture squares for the top, bottom and 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 = 'texture.png'

GRASS = tex_coords((1, 0), (0, 1), (0, 0))
SAND = tex_coords((1, 1), (1, 1), (1, 1))
BRICK = tex_coords((2, 0), (2, 0), (2, 0))
STONE = tex_coords((2, 1), (2, 1), (2, 1))

FACES = [
  ( 0, 1, 0),
  ( 0,-1, 0),
  (-1, 0, 0),
  ( 1, 0, 0),
  ( 0, 0, 1),
  ( 0, 0,-1),
]


def normalize(position):
  """ Accepts `position` of arbitrary precision and returns the block
  containing that position.

  Parameters
  ----------
  position : tuple of len 3

  Returns
  -------
  block_position : tuple of ints of len 3

  """
  x, y, z = position
  x, y, z = (int(round(x)), int(round(y)), int(round(z)))
  return (x, y, z)


def sectorize(position):
  """ Returns a tuple representing the sector for the given `position`.

  Parameters
  ----------
  position : tuple of len 3

  Returns
  -------
  sector : tuple of len 3

  """
  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):

    # A Batch is a collection of vertex lists for batched rendering.
    self.batch = pyglet.graphics.Batch()

    # A TextureGroup manages an OpenGL texture.
    self.group = TextureGroup(image.load(TEXTURE_PATH).get_texture())

    # A mapping from position to the texture of the block at that position.
    # This defines all the blocks that are currently in the world.
    self.world = {}

    # Same mapping as `world` but only contains blocks that are shown.
    self.shown = {}

    # Mapping from position to a pyglet `VertextList` for all shown blocks.
    self._shown = {}

    # Mapping from sector to a list of positions inside that sector.
    self.sectors = {}

    # Simple function queue implementation. The queue is populated with
    # _show_block() and _hide_block() calls
    self.queue = deque()

    self._initialize()

  def _initialize(self):
    """ Initialize the world by placing all the blocks.

    """
    n = 80 # 1/2 width and height of world
    s = 1 # step size
    y = 0 # initial y height
    for x in xrange(-n, n + 1, s):
      for z in xrange(-n, n + 1, s):
        # create a layer stone an grass everywhere.
        self.add_block((x, y - 2, z), GRASS, immediate=False)
        self.add_block((x, y - 3, z), STONE, immediate=False)
        if x in (-n, n) or z in (-n, n):
          # create outer walls.
          for dy in xrange(-2, 3):
            self.add_block((x, y + dy, z), STONE, immediate=False)

    # generate the hills randomly
    o = n - 10
    for _ in xrange(120):
      a = random.randint(-o, o) # x position of the hill
      b = random.randint(-o, o) # z position of the hill
      c = -1 # base of the hill
      h = random.randint(1, 6) # height of the hill
      s = random.randint(4, 8) # 2 * s is the side length of the hill
      d = 1 # how quickly to taper off the hills
      t = random.choice([GRASS, SAND, BRICK])
      for y in xrange(c, c + h):
        for x in xrange(a - s, a + s + 1):
          for z in xrange(b - s, b + s + 1):
            if (x - a) ** 2 + (z - b) ** 2 > (s + 1) ** 2:
              continue
            if (x - 0) ** 2 + (z - 0) ** 2 < 5 ** 2:
              continue
            self.add_block((x, y, z), t, immediate=False)
        s -= d # decrement side lenth so hills taper off

  def hit_test(self, position, vector, max_distance=8):
    """ Line of sight search from current position. If a block is
    intersected it is returned, along with the block previously in the line
    of sight. If no block is found, return None, None.

    Parameters
    ----------
    position : tuple of len 3
      The (x, y, z) position to check visibility from.
    vector : tuple of len 3
      The line of sight vector.
    max_distance : int
      How many blocks away to search for a hit.

    """
    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):
    """ Returns False is given `position` is surrounded on all 6 sides by
    blocks, True otherwise.

    """
    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):
    """ Add a block with the given `texture` and `position` to the world.

    Parameters
    ----------
    position : tuple of len 3
      The (x, y, z) position of the block to add.
    texture : list of len 3
      The coordinates of the texture squares. Use `tex_coords()` to
      generate.
    immediate : bool
      Whether or not to draw the block immediately.

    """
    if position in self.world:
      self.remove_block(position, immediate)
    self.world[position] = texture
    self.sectors.setdefault(sectorize(position), []).append(position)
    if immediate:
      if self.exposed(position):
        self.show_block(position)
      self.check_neighbors(position)

  def remove_block(self, position, immediate=True):
    """ Remove the block at the given `position`.

    Parameters
    ----------
    position : tuple of len 3
      The (x, y, z) position of the block to remove.
    immediate : bool
      Whether or not to immediately remove block from canvas.

    """
    del self.world[position]
    self.sectors[sectorize(position)].remove(position)
    if immediate:
      if position in self.shown:
        self.hide_block(position)
      self.check_neighbors(position)

  def check_neighbors(self, position):
    """ Check all blocks surrounding `position` and ensure their visual
    state is current. This means hiding blocks that are not exposed and
    ensuring that all exposed blocks are shown. Usually used after a block
    is added or removed.

    """
    x, y, z = position
    for dx, dy, dz in FACES:
      key = (x + dx, y + dy, z + dz)
      if key not in self.world:
        continue
      if self.exposed(key):
        if key not in self.shown:
          self.show_block(key)
      else:
        if key in self.shown:
          self.hide_block(key)

  def show_block(self, position, immediate=True):
    """ Show the block at the given `position`. This method assumes the
    block has already been added with add_block()

    Parameters
    ----------
    position : tuple of len 3
      The (x, y, z) position of the block to show.
    immediate : bool
      Whether or not to show the block immediately.

    """
    texture = self.world[position]
    self.shown[position] = texture
    if immediate:
      self._show_block(position, texture)
    else:
      self._enqueue(self._show_block, position, texture)

  def _show_block(self, position, texture):
    """ Private implementation of the `show_block()` method.

    Parameters
    ----------
    position : tuple of len 3
      The (x, y, z) position of the block to show.
    texture : list of len 3
      The coordinates of the texture squares. Use `tex_coords()` to
      generate.

    """
    x, y, z = position
    vertex_data = cube_vertices(x, y, z, 0.5)
    texture_data = list(texture)
    # create vertex list
    # FIXME Maybe `add_indexed()` should be used instead
    self._shown[position] = self.batch.add(24, GL_QUADS, self.group,
      ('v3f/static', vertex_data),
      ('t2f/static', texture_data))

  def hide_block(self, position, immediate=True):
    """ Hide the block at the given `position`. Hiding does not remove the
    block from the world.

    Parameters
    ----------
    position : tuple of len 3
      The (x, y, z) position of the block to hide.
    immediate : bool
      Whether or not to immediately remove the block from the canvas.

    """
    self.shown.pop(position)
    if immediate:
      self._hide_block(position)
    else:
      self._enqueue(self._hide_block, position)

  def _hide_block(self, position):
    """ Private implementation of the 'hide_block()` method.

    """
    self._shown.pop(position).delete()

  def show_sector(self, sector):
    """ Ensure all blocks in the given sector that should be shown are
    drawn to the canvas.

    """
    for position in self.sectors.get(sector, []):
      if position not in self.shown and self.exposed(position):
        self.show_block(position, False)

  def hide_sector(self, sector):
    """ Ensure all blocks in the given sector that should be hidden are
    removed from the canvas.

    """
    for position in self.sectors.get(sector, []):
      if position in self.shown:
        self.hide_block(position, False)

  def change_sectors(self, before, after):
    """ Move from sector `before` to sector `after`. A sector is a
    contiguous x, y sub-region of world. Sectors are used to speed up
    world rendering.

    """
    before_set = set()
    after_set = set()
    pad = 4
    for dx in xrange(-pad, pad + 1):
      for dy in [0]: # xrange(-pad, pad + 1):
        for dz in xrange(-pad, pad + 1):
          if dx ** 2 + dy ** 2 + dz ** 2 > (pad + 1) ** 2:
            continue
          if before:
            x, y, z = before
            before_set.add((x + dx, y + dy, z + dz))
          if after:
            x, y, z = after
            after_set.add((x + dx, y + dy, z + dz))
    show = after_set - before_set
    hide = before_set - after_set
    for sector in show:
      self.show_sector(sector)
    for sector in hide:
      self.hide_sector(sector)

  def _enqueue(self, func, *args):
    """ Add `func` to the internal queue.

    """
    self.queue.append((func, args))

  def _dequeue(self):
    """ Pop the top function from the internal queue and call it.

    """
    func, args = self.queue.popleft()
    func(*args)

  def process_queue(self):
    """ Process the entire queue while taking periodic breaks. This allows
    the game loop to run smoothly. The queue contains calls to
    _show_block() and _hide_block() so this method should be called if
    add_block() or remove_block() was called with immediate=False

    """
    start = time.perf_counter()
    while self.queue and time.time()- start < 1.0 / TICKS_PER_SEC:
      self._dequeue()

  def process_entire_queue(self):
    """ Process the entire queue with no breaks.

    """
    while self.queue:
      self._dequeue()


class Window(pyglet.window.Window):

  def __init__(self, *args, **kwargs):
    super(Window, self).__init__(*args, **kwargs)

    # Whether or not the window exclusively captures the mouse.
    self.exclusive = False

    # When flying gravity has no effect and speed is increased.
    self.flying = False

    # Strafing is moving lateral to the direction you are facing,
    # e.g. moving to the left or right while continuing to face forward.
    #
    # First element is -1 when moving forward, 1 when moving back, and 0
    # otherwise. The second element is -1 when moving left, 1 when moving
    # right, and 0 otherwise.
    self.strafe = [0, 0]

    # Current (x, y, z) position in the world, specified with floats. Note
    # that, perhaps unlike in math class, the y-axis is the vertical axis.
    self.position = (0, 0, 0)

    # First element is rotation of the player in the x-z plane (ground
    # plane) measured from the z-axis down. The second is the rotation
    # angle from the ground plane up. Rotation is in degrees.
    #
    # The vertical plane rotation ranges from -90 (looking straight down) to
    # 90 (looking straight up). The horizontal rotation range is unbounded.
    self.rotation = (0, 0)

    # Which sector the player is currently in.
    self.sector = None

    # The crosshairs at the center of the screen.
    self.reticle = None

    # Velocity in the y (upward) direction.
    self.dy = 0

    # A list of blocks the player can place. Hit num keys to cycle.
    self.inventory = [BRICK, GRASS, SAND]

    # The current block the user can place. Hit num keys to cycle.
    self.block = self.inventory[0]

    # Convenience list of num keys.
    self.num_keys = [
      key._1, key._2, key._3, key._4, key._5,
      key._6, key._7, key._8, key._9, key._0]

    # Instance of the model that handles the world.
    self.model = Model()

    # The label that is displayed in the top left of the canvas.
    self.label = pyglet.text.Label('', font_name='Arial', font_size=18,
      x=10, y=self.height - 10, anchor_x='left', anchor_y='top',
      color=(0, 0, 0, 255))

    # This call schedules the `update()` method to be called
    # TICKS_PER_SEC. This is the main game event loop.
    pyglet.clock.schedule_interval(self.update, 1.0 / TICKS_PER_SEC)

  def set_exclusive_mouse(self, exclusive):
    """ If `exclusive` is True, the game will capture the mouse, if False
    the game will ignore the mouse.

    """
    super(Window, self).set_exclusive_mouse(exclusive)
    self.exclusive = exclusive

  def get_sight_vector(self):
    """ Returns the current line of sight vector indicating the direction
    the player is looking.

    """
    x, y = self.rotation
    # y ranges from -90 to 90, or -pi/2 to pi/2, so m ranges from 0 to 1 and
    # is 1 when looking ahead parallel to the ground and 0 when looking
    # straight up or down.
    m = math.cos(math.radians(y))
    # dy ranges from -1 to 1 and is -1 when looking straight down and 1 when
    # looking straight up.
    dy = math.sin(math.radians(y))
    dx = math.cos(math.radians(x - 90)) * m
    dz = math.sin(math.radians(x - 90)) * m
    return (dx, dy, dz)

  def get_motion_vector(self):
    """ Returns the current motion vector indicating the velocity of the
    player.

    Returns
    -------
    vector : tuple of len 3
      Tuple containing the velocity in x, y, and z respectively.

    """
    if any(self.strafe):
      x, y = self.rotation
      strafe = math.degrees(math.atan2(*self.strafe))
      y_angle = math.radians(y)
      x_angle = math.radians(x + strafe)
      if self.flying:
        m = math.cos(y_angle)
        dy = math.sin(y_angle)
        if self.strafe[1]:
          # Moving left or right.
          dy = 0.0
          m = 1
        if self.strafe[0] > 0:
          # Moving backwards.
          dy *= -1
        # When you are flying up or down, you have less left and right
        # motion.
        dx = math.cos(x_angle) * m
        dz = math.sin(x_angle) * m
      else:
        dy = 0.0
        dx = math.cos(x_angle)
        dz = math.sin(x_angle)
    else:
      dy = 0.0
      dx = 0.0
      dz = 0.0
    return (dx, dy, dz)

  def update(self, dt):
    """ This method is scheduled to be called repeatedly by the pyglet
    clock.

    Parameters
    ----------
    dt : float
      The change in time since the last call.

    """
    self.model.process_queue()
    sector = sectorize(self.position)
    if sector != self.sector:
      self.model.change_sectors(self.sector, sector)
      if self.sector is None:
        self.model.process_entire_queue()
      self.sector = sector
    m = 8
    dt = min(dt, 0.2)
    for _ in xrange(m):
      self._update(dt / m)

  def _update(self, dt):
    """ Private implementation of the `update()` method. This is where most
    of the motion logic lives, along with gravity and collision detection.

    Parameters
    ----------
    dt : float
      The change in time since the last call.

    """
    # walking
    speed = FLYING_SPEED if self.flying else WALKING_SPEED
    d = dt * speed # distance covered this tick.
    dx, dy, dz = self.get_motion_vector()
    # New position in space, before accounting for gravity.
    dx, dy, dz = dx * d, dy * d, dz * d
    # gravity
    if not self.flying:
      # Update your vertical speed: if you are falling, speed up until you
      # hit terminal velocity; if you are jumping, slow down until you
      # start falling.
      self.dy -= dt * GRAVITY
      self.dy = max(self.dy, -TERMINAL_VELOCITY)
      dy += self.dy * dt
    # collisions
    x, y, z = self.position
    x, y, z = self.collide((x + dx, y + dy, z + dz), PLAYER_HEIGHT)
    self.position = (x, y, z)

  def collide(self, position, height):
    """ Checks to see if the player at the given `position` and `height`
    is colliding with any blocks in the world.

    Parameters
    ----------
    position : tuple of len 3
      The (x, y, z) position to check for collisions at.
    height : int or float
      The height of the player.

    Returns
    -------
    position : tuple of len 3
      The new position of the player taking into account collisions.

    """
    # How much overlap with a dimension of a surrounding block you need to
    # have to count as a collision. If 0, touching terrain at all counts as
    # a collision. If .49, you sink into the ground, as if walking through
    # tall grass. If >= .5, you'll fall through the ground.
    pad = 0.25
    p = list(position)
    np = normalize(position)
    for face in FACES: # check all surrounding blocks
      for i in xrange(3): # check each dimension independently
        if not face[i]:
          continue
        # How much overlap you have with this dimension.
        d = (p[i] - np[i]) * face[i]
        if d < pad:
          continue
        for dy in xrange(height): # check each height
          op = list(np)
          op[1] -= dy
          op[i] += face[i]
          if tuple(op) not in self.model.world:
            continue
          p[i] -= (d - pad) * face[i]
          if face == (0, -1, 0) or face == (0, 1, 0):
            # You are colliding with the ground or ceiling, so stop
            # falling / rising.
            self.dy = 0
          break
    return tuple(p)

  def on_mouse_press(self, x, y, button, modifiers):
    """ Called when a mouse button is pressed. See pyglet docs for button
    amd modifier mappings.

    Parameters
    ----------
    x, y : int
      The coordinates of the mouse click. Always center of the screen if
      the mouse is captured.
    button : int
      Number representing mouse button that was clicked. 1 = left button,
      4 = right button.
    modifiers : int
      Number representing any modifying keys that were pressed when the
      mouse button was clicked.

    """
    if self.exclusive:
      vector = self.get_sight_vector()
      block, previous = self.model.hit_test(self.position, vector)
      if (button == mouse.RIGHT) or \
          ((button == mouse.LEFT) and (modifiers & key.MOD_CTRL)):
        # ON OSX, control + left click = right click.
        if previous:
          self.model.add_block(previous, self.block)
      elif button == pyglet.window.mouse.LEFT and block:
        texture = self.model.world[block]
        if texture != STONE:
          self.model.remove_block(block)
    else:
      self.set_exclusive_mouse(True)

  def on_mouse_motion(self, x, y, dx, dy):
    """ Called when the player moves the mouse.

    Parameters
    ----------
    x, y : int
      The coordinates of the mouse click. Always center of the screen if
      the mouse is captured.
    dx, dy : float
      The movement of the mouse.

    """
    if self.exclusive:
      m = 0.15
      x, y = self.rotation
      x, y = x + dx * m, y + dy * m
      y = max(-90, min(90, y))
      self.rotation = (x, y)

  def on_key_press(self, symbol, modifiers):
    """ Called when the player presses a key. See pyglet docs for key
    mappings.

    Parameters
    ----------
    symbol : int
      Number representing the key that was pressed.
    modifiers : int
      Number representing any modifying keys that were pressed.

    """
    if symbol == key.W:
      self.strafe[0] -= 1
    elif symbol == key.S:
      self.strafe[0] += 1
    elif symbol == key.A:
      self.strafe[1] -= 1
    elif symbol == key.D:
      self.strafe[1] += 1
    elif symbol == key.SPACE:
      if self.dy == 0:
        self.dy = JUMP_SPEED
    elif symbol == key.ESCAPE:
      self.set_exclusive_mouse(False)
    elif symbol == key.TAB:
      self.flying = not self.flying
    elif symbol in self.num_keys:
      index = (symbol - self.num_keys[0]) % len(self.inventory)
      self.block = self.inventory[index]

  def on_key_release(self, symbol, modifiers):
    """ Called when the player releases a key. See pyglet docs for key
    mappings.

    Parameters
    ----------
    symbol : int
      Number representing the key that was pressed.
    modifiers : int
      Number representing any modifying keys that were pressed.

    """
    if symbol == key.W:
      self.strafe[0] += 1
    elif symbol == key.S:
      self.strafe[0] -= 1
    elif symbol == key.A:
      self.strafe[1] += 1
    elif symbol == key.D:
      self.strafe[1] -= 1

  def on_resize(self, width, height):
    """ Called when the window is resized to a new `width` and `height`.

    """
    # label
    self.label.y = height - 10
    # reticle
    if self.reticle:
      self.reticle.delete()
    x, y = self.width // 2, self.height // 2
    n = 10
    self.reticle = pyglet.graphics.vertex_list(4,
      ('v2i', (x - n, y, x + n, y, x, y - n, x, y + n))
    )

  def set_2d(self):
    """ Configure OpenGL to draw in 2d.

    """
    width, height = self.get_size()
    glDisable(GL_DEPTH_TEST)
    viewport = self.get_viewport_size()
    glViewport(0, 0, max(1, viewport[0]), max(1, viewport[1]))
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0, max(1, width), 0, max(1, height), -1, 1)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

  def set_3d(self):
    """ Configure OpenGL to draw in 3d.

    """
    width, height = self.get_size()
    glEnable(GL_DEPTH_TEST)
    viewport = self.get_viewport_size()
    glViewport(0, 0, max(1, viewport[0]), max(1, viewport[1]))
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(65.0, width / float(height), 0.1, 60.0)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    x, y = self.rotation
    glRotatef(x, 0, 1, 0)
    glRotatef(-y, math.cos(math.radians(x)), 0, math.sin(math.radians(x)))
    x, y, z = self.position
    glTranslatef(-x, -y, -z)

  def on_draw(self):
    """ Called by pyglet to draw the canvas.

    """
    self.clear()
    self.set_3d()
    glColor3d(1, 1, 1)
    self.model.batch.draw()
    self.draw_focused_block()
    self.set_2d()
    self.draw_label()
    self.draw_reticle()

  def draw_focused_block(self):
    """ Draw black edges around the block that is currently under the
    crosshairs.

    """
    vector = self.get_sight_vector()
    block = self.model.hit_test(self.position, vector)[0]
    if block:
      x, y, z = block
      vertex_data = cube_vertices(x, y, z, 0.51)
      glColor3d(0, 0, 0)
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
      pyglet.graphics.draw(24, GL_QUADS, ('v3f/static', vertex_data))
      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

  def draw_label(self):
    """ Draw the label in the top left of the screen.

    """
    x, y, z = self.position
    self.label.text = '%02d (%.2f, %.2f, %.2f) %d / %d' % (
      pyglet.clock.get_fps(), x, y, z,
      len(self.model._shown), len(self.model.world))
    self.label.draw()

  def draw_reticle(self):
    """ Draw the crosshairs in the center of the screen.

    """
    glColor3d(0, 0, 0)
    self.reticle.draw(GL_LINES)


def setup_fog():
  """ Configure the OpenGL fog properties.

  """
  # Enable fog. Fog "blends a fog color with each rasterized pixel fragment's
  # post-texturing color."
  glEnable(GL_FOG)
  # Set the fog color.
  glFogfv(GL_FOG_COLOR, (GLfloat * 4)(0.5, 0.69, 1.0, 1))
  # Say we have no preference between rendering speed and quality.
  glHint(GL_FOG_HINT, GL_DONT_CARE)
  # Specify the equation used to compute the blending factor.
  glFogi(GL_FOG_MODE, GL_LINEAR)
  # How close and far away fog starts and ends. The closer the start and end,
  # the denser the fog in the fog range.
  glFogf(GL_FOG_START, 20.0)
  glFogf(GL_FOG_END, 60.0)


def setup():
  """ Basic OpenGL configuration.

  """
  # Set the color of "clear", i.e. the sky, in rgba.
  glClearColor(0.5, 0.69, 1.0, 1)
  # Enable culling (not rendering) of back-facing facets -- facets that aren't
  # visible to you.
  glEnable(GL_CULL_FACE)
  # Set the texture minification/magnification function to GL_NEAREST (nearest
  # in Manhattan distance) to the specified texture coordinates. GL_NEAREST
  # "is generally faster than GL_LINEAR, but it can produce textured 图片
  # with sharper edges because the transition between texture elements is not
  # as smooth."
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
  setup_fog()


def main():
  window = Window(width=1800, height=1600, caption='Pyglet', resizable=True)
  # Hide the mouse cursor and prevent the mouse from leaving the window.
  window.set_exclusive_mouse(True)
  setup()
  pyglet.app.run()


if __name__ == '__main__':
  main()

我的世界小游戏python源代码包下载地址:

链接: https://pan.baidu.com/s/1gKAheRzAeNmRXgSU-A4PPg

提取码: rya9

到此这篇关于Python实现我的世界小游戏源代码的文章就介绍到这了,更多相关Python小游戏源代码内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python脚本暴力破解栅栏密码
Oct 19 Python
python中函数默认值使用注意点详解
Jun 01 Python
总结网络IO模型与select模型的Python实例讲解
Jun 27 Python
Python实现将16进制字符串转化为ascii字符的方法分析
Jul 21 Python
老生常谈Python startswith()函数与endswith函数
Sep 08 Python
python正则表达式面试题解答
Apr 28 Python
pycharm使用matplotlib.pyplot不显示图形的解决方法
Oct 28 Python
python flask安装和命令详解
Apr 02 Python
Python3 列表,数组,矩阵的相互转换的方法示例
Aug 05 Python
Python基于yield遍历多个可迭代对象
Mar 12 Python
python爬取网易云音乐热歌榜实例代码
Aug 07 Python
python一些性能分析的技巧
Aug 30 Python
VSCode中autopep8无法运行问题解决方案(提示Error: Command failed,usage)
Mar 02 #Python
python 基于pygame实现俄罗斯方块
Mar 02 #Python
使用Python快速打开一个百万行级别的超大Excel文件的方法
Mar 02 #Python
Autopep8的使用(python自动编排工具)
Mar 02 #Python
python 将Excel转Word的示例
Mar 02 #Python
Python字节单位转换(将字节转换为K M G T)
Mar 02 #Python
Python使用cn2an实现中文数字与阿拉伯数字的相互转换
Mar 02 #Python
You might like
我的论坛源代码(二)
2006/10/09 PHP
php处理json时中文问题的解决方法
2011/04/12 PHP
PHP中mysql_field_type()函数用法
2014/11/24 PHP
浅谈ThinkPHP中initialize和construct的区别
2017/04/01 PHP
IE中jscript/javascript的条件编译
2006/09/07 Javascript
jquery中event对象属性与方法小结
2013/12/18 Javascript
window.onload追加函数使用示例
2014/03/03 Javascript
JS动态改变浏览器标题的方法
2016/04/06 Javascript
select隐藏选中值对应的id,显示其它id的简单实现方法
2016/08/25 Javascript
详解使用angularjs的ng-options时如何设置默认值(初始值)
2017/07/18 Javascript
node实现的爬虫功能示例
2018/05/04 Javascript
angular.js实现列表orderby排序的方法
2018/10/02 Javascript
详解React 的几种条件渲染以及选择
2018/10/23 Javascript
js实现简单商品筛选功能
2021/02/02 Javascript
[03:32]2014DOTA2西雅图邀请赛 CIS外卡赛赛前black专访
2014/07/09 DOTA
[01:05:07]DOTA2-DPC中国联赛 正赛 DLG vs Dragon BO3 第一场2月1日
2021/03/11 DOTA
Python内置函数之filter map reduce介绍
2014/11/30 Python
Python的“二维”字典 (two-dimension dictionary)定义与实现方法
2016/04/27 Python
django解决跨域请求的问题
2018/11/11 Python
使用Python实现微信提醒备忘录功能
2018/12/04 Python
解决keras backend 越跑越慢问题
2020/06/18 Python
通过实例了解python__slots__使用方法
2020/09/14 Python
深入解读CSS3中transform变换模型的渲染
2016/05/27 HTML / CSS
CSS3实现超慢速移动动画效果非常流畅无卡顿
2014/06/15 HTML / CSS
海外淘书首选:AbeBooks
2017/07/31 全球购物
应届生污水处理求职信
2013/11/06 职场文书
主管职责范文
2013/11/09 职场文书
社区庆八一活动方案
2014/02/02 职场文书
《最大的麦穗》教学反思
2014/04/17 职场文书
公司试用期员工自我评价
2014/09/17 职场文书
财务工作犯错检讨书
2014/10/07 职场文书
2014年体育工作总结
2014/11/24 职场文书
介绍长城的导游词
2015/01/30 职场文书
服装区域经理岗位职责
2015/04/10 职场文书
能用CSS实现的就不要麻烦JavaScript了
2021/10/05 HTML / CSS
利用 Python 的 Pandas和 NumPy 库来清理数据
2022/04/13 Python