猫史档案馆


【Python作品分享】我的世界【作品秀】

用户:RtsstsRtssts查看:0 回复:0 评论:0 创建时间:2023-03-26T12:03:18


【作品展示】

center_image

 

【作品介绍】

w,a,s,d

 

【作品源代码】

from __future__ import division
import sys
import math
import time
import random
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
SECTOR_SIZE=2000
WALKING_SPEED=5
FLYING_SPEED=15
GRAVITY=20
MAX_JUMP_HEIGHT=1
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,  
        x-n,y-n,z-n,x+n,y-n,z-n,x+n,y-n,z+n,x-n,y-n,z+n,  
        x-n,y-n,z-n,x-n,y-n,z+n,x-n,y+n,z+n,x-n,y+n,z-n, 
        x+n,y-n,z+n,x+n,y-n,z-n,x+n,y+n,z-n,x+n,y+n,z+n, 
        x-n,y-n,z+n,x+n,y-n,z+n,x+n,y+n,z+n,x-n,y+n,z+n,  
        x+n,y-n,z-n,x-n,y-n,z-n,x-n,y+n,z-n,x+n,y+n,z-n,  
    ]
def tex_coord(x,y,n=4):
    """ 
    Return the bounding vertices of the texture square.
    """
    m=1.00/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))
PURPLE=tex_coords((3,1),(3,1),(3,1))
RED=tex_coords((3,0),(3,0),(3,0))
GREEN=tex_coords((3,2),(3,2),(3,2))
BLUE=tex_coords((1,2),(1,2),(1,2))
BLACK=tex_coords((2,2),(2,2),(2,2))
ORANGE=tex_coords((3,2),(3,2),(3,2))
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):
        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):
        """ Initialize the world by placing all the blocks.
        """
        n=200
        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)
                self.add_block((x,y-3,z),STONE,immediate=False)
                if x in (-n,n) or z in (-n,n):
                    for dy in xrange(-2,3):
                        self.add_block((x,y+dy,z),STONE,immediate=False)
        o=n-15
        for _ in xrange(120):
            a=random.randint(-o,o)  
            b=random.randint(-o,o)  
            c=-1  
            h=random.randint(2,6) 
            s=random.randint(4,12)  
            d=1  
            t=random.choice([GRASS, SAND,STONE])
            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 
    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 29
            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)
        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]:  
                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 喵oothly. 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.time
        while self.queue and time.time <1/ 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)
        self.exclusive=False
        self.flying=False
        self.strafe=[0,0]
        self.position=(0,0,0)
        self.rotation=(0,0)
        self.sector=None
        self.reticle=None
        self.dy=0
        self.inventory=[BRICK, GRASS, SAND,STONE,RED,PURPLE,GREEN,BLUE,BLACK,ORANGE]
        self.block=self.inventory[0]
        self.num_keys=[
            key._1,key._2,key._3,key._4,key._5,
            key._6,key._7,key._8,key._9,key._0,key.E,key.R] 
        self.model=Model() 
        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))
        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
        m=math.cos(math.radians(y))
        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]:
                    dy=0.00
                    m=1
                if self.strafe[0]>0:
                    dy*=-1
                dx=math.cos(x_angle)*m
                dz=math.sin(x_angle)*m
            else:
                dy=0.00
                dx=math.cos(x_angle)
                dz=math.sin(x_angle)
        else:
            dy=0.00
            dx=0.00
            dz=0.00
        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.
        """
        speed=FLYING_SPEED if self.flying else WALKING_SPEED
        d=dt*speed
        dx,dy,dz=self.get_motion_vector()
        dx,dy,dz=dx*d,dy*d,dz*d
        if not self.flying:
            self.dy-=dt*GRAVITY
            self.dy=max(self.dy,-TERMINAL_VELOCITY)
            dy+=self.dy*dt
        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.
        """
        p=list(position)
        np=normalize(position)
        for face in FACES:  
            for i in xrange(3): 
                if not face[i]:
                    continue
                d=(p[i]-np[i])*face[i]
                if d>pad:
                    continue
                for dy in xrange(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):
                        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)):
                if previous:
                    self.model.add_block(previous,self.block)
            elif button==pyglet.window.mouse.LEFT and block:
                self.model.world[block]
                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):
        self.label.y=height-10
        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():
    """ Basic OpenGL configuration.
    """
    glClearColor(0.5,0.69,1.0,1)
    glEnable(GL_CULL_FACE)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
def main():
    window=Window(width=990,height=500,caption='main',resizable=True)
    window.set_exclusive_mouse(True)
    setup()
    pyglet.app.run()
if __name__=='__main__':
    main()

 

【提示】

部分含有Python第三方库相关内容的作品,在海龟编辑器网页端无法运行哦!如遇到这种情况,可以打开下面的链接,下载海龟编辑器客户端:

https://python.codemao.cn


回复

上一页1 页 / 共 0下一页