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实现的tab文件操作类分享
Nov 20 Python
python利用装饰器进行运算的实例分析
Aug 04 Python
Python的Twisted框架中使用Deferred对象来管理回调函数
May 25 Python
python如何在列表、字典中筛选数据
Mar 19 Python
django 发送手机验证码的示例代码
Apr 25 Python
Python在Matplotlib图中显示中文字体的操作方法
Jul 29 Python
对YOLOv3模型调用时候的python接口详解
Aug 26 Python
python 字符串常用函数详解
Sep 11 Python
Python学习笔记之函数的参数和返回值的使用
Nov 20 Python
利用python生成照片墙的示例代码
Apr 09 Python
Python3 Tensorlfow:增加或者减小矩阵维度的实现
May 22 Python
Python 将代码转换为可执行文件脱离python环境运行(步骤详解)
Jan 25 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
FleaPHP的安全设置方法
2008/09/15 PHP
php新建文件自动编号的思路与实现
2011/06/27 PHP
php 注册时输入信息验证器的实现详解
2013/07/05 PHP
thinkPHP统计排行与分页显示功能示例
2016/12/02 PHP
PHP实现在windows下配置sendmail并通过mail()函数发送邮件的方法
2017/06/20 PHP
yii2安装详细流程
2018/05/23 PHP
PHP时间处理类操作示例
2018/09/05 PHP
JS兼容浏览器的导出Excel(CSV)文件的方法
2014/05/03 Javascript
JavaScript常用脚本汇总(一)
2015/03/04 Javascript
jQuery中dom元素上绑定的事件详解
2015/04/24 Javascript
分享一些常用的jQuery动画事件和动画函数
2015/11/27 Javascript
js实现select二级联动下拉菜单
2020/04/17 Javascript
JS生成和下载二维码的代码
2016/12/07 Javascript
web前端页面生成exe可执行文件的方法
2018/02/08 Javascript
javascript变量提升和闭包理解
2018/03/12 Javascript
JS实现关键词高亮显示正则匹配
2018/06/22 Javascript
vue组件实践之可搜索下拉框功能
2018/11/25 Javascript
Vue 利用指令实现禁止反复发送请求的两种方法
2019/09/15 Javascript
element-ui树形控件后台返回的数据+生成组织树的工具类
2020/03/05 Javascript
一篇文章带你使用Typescript封装一个Vue组件(简单易懂)
2020/06/05 Javascript
Python实现多线程下载文件的代码实例
2014/06/01 Python
python爬虫容易学吗
2020/06/02 Python
HTML5中通过li-canvas轻松实现单图、多图、圆角图绘制,单行文字、多行文字等
2018/11/30 HTML / CSS
HTML5标签小集
2011/08/02 HTML / CSS
菲律宾酒店预订网站:Hotels.com菲律宾
2017/07/12 全球购物
求职简历自我评价范例
2014/03/12 职场文书
中班开学寄语
2014/04/04 职场文书
本科毕业生自荐信
2014/06/02 职场文书
欢迎横幅标语
2014/06/17 职场文书
运动会加油稿100字
2014/09/19 职场文书
销售经理工作检讨书
2015/02/19 职场文书
施工安全保证书
2015/05/09 职场文书
2015年图书馆个人工作总结
2015/05/26 职场文书
2015年试用期工作总结范文
2015/05/28 职场文书
开机音效回归! Windows 11重新引入开机铃声
2021/11/21 数码科技
Nginx配置根据url参数重定向
2022/04/11 Servers