当前位置:   article > 正文

Pyglet图形界面版2048游戏——详尽实现教程(上)

Pyglet图形界面版2048游戏——详尽实现教程(上)

目录

Pyglet图形界面版2048游戏

一、色块展示

二、绘制标题

三、方阵色块

四、界面布局

五、键鼠操作


Pyglet图形界面版2048游戏

一、色块展示

准备好游戏数字的背景颜色,如以下12种:

COLOR = ((206, 194, 180, 255), (237, 229, 218, 255), (237, 220, 190, 255),
                  (241, 176, 120, 255), (247, 146, 90, 255), (245, 118, 86, 255),
                  (247, 83, 44, 255), (237, 206, 115, 255), (229, 210, 82, 255),
                  (208, 164, 13, 255), (230, 180, 5, 255), (160, 134, 117, 255))

这些颜色用于pyglet.shapes.Rectangle()绘制方块,用法:

Rectangle(x, y, width, height, color=(255, 255, 255, 255), batch=None, group=None)

示例代码: 

  1. import pyglet
  2. window = pyglet.window.Window(800, 600, caption='色块展示')
  3. COLOR = ((206, 194, 180), (237, 229, 218), (237, 220, 190), (241, 176, 120),
  4. (247, 146, 90), (245, 118, 86), (247, 83, 44), (237, 206, 115),
  5. (229, 210, 82), (208, 164, 13), (230, 180, 5), (160, 134, 117))
  6. batch = pyglet.graphics.Batch()
  7. shape = [pyglet.shapes.Rectangle(180+i%4*120, 120+i//4*120, 100, 100, color=COLOR[i], batch=batch) for i in range(len(COLOR))]
  8. @window.event
  9. def on_draw():
  10. window.clear()
  11. batch.draw()
  12. pyglet.app.run()

运行效果:

二、绘制标题

使用pyglet.text.Label()+pyglet.shapes.Rectangle()绘制标题图片,为美化效果把数字0转过一定角度,属性.rotaion为旋转角度,属性.anchor_position为旋转中心坐标,属性.x和.y为控件坐标,可以对个别控件的位置作出调整。

示例代码:

  1. import pyglet
  2. from pyglet import shapes,text
  3. window = pyglet.window.Window(800, 600, caption='2048')
  4. batch = pyglet.graphics.Batch()
  5. x, y = 280, 260
  6. width, height = 70, 80
  7. coord = (x, y), (x+120, y), (x+70, y+60), (x+200, y)
  8. color = (230, 182, 71), (220, 112, 82), (245, 112, 88), (248, 160, 88)
  9. label = [text.Label(s,font_name='Arial',font_size=42,bold=True,
  10. x=coord[i][0]+width//2, y=coord[i][1]+height//2,
  11. anchor_x='center', anchor_y='center',
  12. batch=batch) for i,s in enumerate('2408')]
  13. rectangle = [shapes.Rectangle(coord[i][0], coord[i][1], width, height,
  14. color=color[i], batch=batch) for i in range(4)]
  15. rectangle[2].anchor_position = (15, 15)
  16. rectangle[2].rotation = 30
  17. label[2].rotation = 30
  18. label[2].x += 10
  19. label[2].y -= 25
  20. @window.event
  21. def on_draw():
  22. window.clear()
  23. batch.draw()
  24. pyglet.app.run()

运行效果: 

三、方阵色块

方阵色块和数字设置成一个类class Game2048,从2阶到9阶,数字色块的背景随数字的变化而变化,色块和数字也使用 Rectangle 和 Label 绘制。

self.shapes = []
self.labels = []
for i in range(order**2):
       x, y = i%order*(size+margin)+38, i//order*(size+margin)+38
       index = randint(0, min(self.index, len(COLOR)-1))
       self.shapes.append(shapes.Rectangle(x,y,size,size,color=COLOR[index],batch=batch))
       self.labels.append(text.Label(str(2**index) if index else '', font_size=font_size,
                    x=x+size//2, y=y+size//2,anchor_x='center', 

                    anchor_y='center',bold=True,batch=batch))

示例代码:

  1. import pyglet
  2. from pyglet import shapes,text
  3. from random import randint
  4. window = pyglet.window.Window(600, 600, caption='2048')
  5. pyglet.gl.glClearColor(176/255, 196/255, 222/255, 0.6)
  6. COLOR = ((206, 194, 180), (237, 229, 218), (237, 220, 190), (241, 176, 120), (247, 146, 90),
  7. (245, 118, 86), (247, 83, 44), (237, 206, 115), (229, 210, 82), (208, 164, 13),
  8. (230, 180, 5), (160, 134, 117))
  9. batch = pyglet.graphics.Batch()
  10. class Game2048:
  11. def __init__(self, order=4):
  12. size = 255,165,120,96,77,65,55,48
  13. font_size = 128,60,30,24,21,16,12,11
  14. size = size[order-2]
  15. font_size = font_size[order-2]
  16. margin = 14 if order<5 else 12
  17. self.order = order
  18. self.index = order+7 if order>3 else (4 if order==2 else 7)
  19. self.shape = shapes.Rectangle(20, 20, 560, 560, color=(190,176,160), batch=batch)
  20. self.shapes = []
  21. self.labels = []
  22. for i in range(order**2):
  23. x, y = i%order*(size+margin)+38, i//order*(size+margin)+38
  24. index = randint(0, min(self.index, len(COLOR)-1))
  25. self.shapes.append(shapes.Rectangle(x,y,size,size,color=COLOR[index],batch=batch))
  26. self.labels.append(text.Label(str(2**index) if index else '', font_size=font_size,
  27. x=x+size//2, y=y+size//2,anchor_x='center', anchor_y='center',bold=True,batch=batch))
  28. @window.event
  29. def on_draw():
  30. window.clear()
  31. batch.draw()
  32. @window.event
  33. def on_key_press(symbol, modifiers):
  34. global box
  35. order = symbol - 48 if symbol<100 else symbol - 65456
  36. if order in range(2,10):
  37. game = Game2048(order)
  38. box = Boxes(5)
  39. pyglet.app.run()

运行效果:可以用键盘操作,数字2~9分别对应方阵的2~9阶。

四、界面布局

把以上内容结合到一起成为游戏的主界面,在屏幕中央显示标题图以及提示语,任意键后显示标题移到界面左上方,色块盘则显示在界面下方。另外,使用pyglet.clock.schedule_interval()切换提示语的可见性,产生动画效果:

def switch_visible(event):
    any_key_label.visible = not any_key_label.visible

pyglet.clock.schedule_interval(switch_visible, 0.5)

完整示例代码:

  1. import pyglet
  2. from pyglet import shapes,text
  3. from random import randint
  4. window = pyglet.window.Window(600, 800, caption='2048')
  5. pyglet.gl.glClearColor(176/255, 196/255, 222/255, 0.6)
  6. COLOR = ((206, 194, 180), (237, 229, 218), (237, 220, 190), (241, 176, 120), (247, 146, 90),
  7. (245, 118, 86), (247, 83, 44), (237, 206, 115), (229, 210, 82), (208, 164, 13),
  8. (230, 180, 5), (160, 134, 117))
  9. batch = pyglet.graphics.Batch()
  10. group = pyglet.graphics.Group()
  11. def title2048(x=170, y=450):
  12. global label,rectangle
  13. width, height = 70, 80
  14. coord = (x, y), (x+width*2-20, y), (x+width, y+height), (x+width*3-10, y)
  15. color = (230, 182, 71), (220, 112, 82), (245, 112, 88), (248, 160, 88)
  16. label = [text.Label(s, font_name='Arial', font_size=42, bold=True, batch=batch, group=group,
  17. x=coord[i][0]+width//2, y=coord[i][1]+height//2, anchor_x='center',
  18. anchor_y='center') for i,s in enumerate('2408')]
  19. rect = lambda i:(coord[i][0], coord[i][1], width, height)
  20. rectangle = [shapes.Rectangle(*rect(i), color=color[i], batch=batch, group=group) for i in range(4)]
  21. rectangle[2].anchor_position = (15, 15)
  22. rectangle[2].rotation = 30
  23. label[2].rotation = 30
  24. label[2].x += 10
  25. label[2].y -= 25
  26. class Game2048:
  27. def __init__(self, order=4):
  28. size = 255,165,120,96,77,65,55,48
  29. font_size = 128,60,30,24,21,16,12,11
  30. size = size[order-2]
  31. font_size = font_size[order-2]
  32. margin = 14 if order<5 else 12
  33. self.order = order
  34. self.index = order+7 if order>3 else (4 if order==2 else 7)
  35. self.shape = shapes.Rectangle(20, 20, 560, 560, color=(190, 176, 160), batch=batch)
  36. self.shapes = []
  37. self.labels = []
  38. for i in range(order**2):
  39. x, y = i%order*(size+margin)+38, i//order*(size+margin)+38
  40. index = randint(0, min(self.index, len(COLOR)-1))
  41. rect = x, y, size, size
  42. self.shapes.append(shapes.Rectangle(*rect, color=COLOR[index], batch=batch))
  43. text = str(2**index) if index else ''
  44. self.labels.append(text.Label(text, font_size=font_size, x=x+size//2, y=y+size//2,
  45. anchor_x='center', anchor_y='center', bold=True, batch=batch))
  46. any_key = True
  47. any_key_label = text.Label("any key to start ......", x=window.width//2, y=window.height//2,
  48. font_size=24, anchor_x='center', anchor_y='center')
  49. @window.event
  50. def on_draw():
  51. window.clear()
  52. batch.draw()
  53. if any_key:
  54. any_key_label.draw()
  55. @window.event
  56. def on_key_press(symbol, modifiers):
  57. global any_key, game
  58. if any_key:
  59. any_key = False
  60. title2048(20, 630)
  61. game = Game2048(5)
  62. return
  63. order = symbol - 48 if symbol<100 else symbol - 65456
  64. if order in range(2,10):
  65. game = Game2048(order)
  66. @window.event
  67. def on_mouse_press(x, y, button, modifier):
  68. if any_key:
  69. on_key_press(0, 0)
  70. def switch_visible(event):
  71. any_key_label.visible = not any_key_label.visible
  72. if any_key:
  73. pyglet.clock.schedule_interval(switch_visible, 0.5)
  74. title2048()
  75. pyglet.app.run()

运行效果:

五、键鼠操作

增加上下左右方向的键盘操作,左手操作也可以用ASDW四个字符键;鼠标操作则检测在色块盘的位置,如下图所示,对角线分割出的四个区域分别分表上下左右。四个区域由y=x,y=-x+600两条直线方程所分割,并且满足20<x,y<580即可。测试用控件放在class Game2048类里:

        '''以下控件测试用'''

        self.line1 = shapes.Line(20, 20, 580, 580, width=4, color=(255, 0, 0), batch=batch)
        self.line2 = shapes.Line(20, 580, 580, 20, width=4, color=(255, 0, 0), batch=batch)
        self.box = shapes.Box(18, 18, 564, 564, thickness=4, color=(255, 0, 0), batch=batch)
        self.text = text.Label("", x=450, y=650, font_size=24, color=(250, 0, 0, 255),
                    anchor_x='center', anchor_y='center', bold=True, batch=batch)

键盘操作:

@window.event
def on_key_press(symbol, modifiers):
    if symbol in (key.A, key.LEFT):
        move_test('left')
    elif symbol in (key.D, key.RIGHT):
        move_test('right')
    elif symbol in (key.W, key.UP):
        move_test('up')
    elif symbol in (key.S, key.DOWN):
        move_test('down')

鼠标操作:

@window.event
def on_mouse_press(x, y, button, modifier):
    if any_key:
        on_key_press(0, 0)
    if direction == 'left':
        move_test('left')
    elif direction == 'right':
        move_test('right')
    elif direction == 'up':
        move_test('up')
    elif direction == 'down':
        move_test('down')

@window.event
def on_mouse_motion(x, y, dx, dy):
    global direction
    if 20<x<y<580 and x+y<600:
        direction = 'left'
    elif 20<y<x<580 and x+y>600:
        direction = 'right'
    elif 20<x<y<580 and x+y>600:
        direction = 'up'
    elif 20<y<x<580 and x+y<600:
        direction = 'down'
    else:
        direction = None

完整代码:

  1. import pyglet
  2. from pyglet import shapes,text
  3. from pyglet.window import key
  4. from random import randint
  5. window = pyglet.window.Window(600, 800, caption='2048')
  6. pyglet.gl.glClearColor(176/255, 196/255, 222/255, 0.6)
  7. COLOR = ((206, 194, 180), (237, 229, 218), (237, 220, 190), (241, 176, 120), (247, 146, 90),
  8. (245, 118, 86), (247, 83, 44), (237, 206, 115), (229, 210, 82), (208, 164, 13),
  9. (230, 180, 5), (160, 134, 117))
  10. batch = pyglet.graphics.Batch()
  11. group = pyglet.graphics.Group()
  12. def title2048(x=170, y=450):
  13. global label,rectangle
  14. width, height = 70, 80
  15. coord = (x, y), (x+width*2-20, y), (x+width, y+height), (x+width*3-10, y)
  16. color = (230, 182, 71), (220, 112, 82), (245, 112, 88), (248, 160, 88)
  17. label = [text.Label(s, font_name='Arial', font_size=42, bold=True, batch=batch, group=group,
  18. x=coord[i][0]+width//2, y=coord[i][1]+height//2, anchor_x='center',
  19. anchor_y='center') for i,s in enumerate('2408')]
  20. rect = lambda i:(coord[i][0], coord[i][1], width, height)
  21. rectangle = [shapes.Rectangle(*rect(i), color=color[i], batch=batch, group=group) for i in range(4)]
  22. rectangle[2].anchor_position = (15, 15)
  23. rectangle[2].rotation = 30
  24. label[2].rotation = 30
  25. label[2].x += 10
  26. label[2].y -= 25
  27. class Game2048:
  28. def __init__(self, order=4):
  29. size = 255,165,120,96,77,65,55,48
  30. font_size = 128,60,30,24,21,16,12,11
  31. size = size[order-2]
  32. font_size = font_size[order-2]
  33. margin = 14 if order<5 else 12
  34. self.order = order
  35. self.index = order+7 if order>3 else (4 if order==2 else 7)
  36. self.shape = shapes.Rectangle(20, 20, 560, 560, color=(190, 176, 160), batch=batch)
  37. self.shapes = []
  38. self.labels = []
  39. for i in range(order**2):
  40. x, y = i%order*(size+margin)+38, i//order*(size+margin)+38
  41. index = randint(0, min(self.index, len(COLOR)-1))
  42. rect = x, y, size, size
  43. self.shapes.append(shapes.Rectangle(*rect, color=COLOR[index], batch=batch))
  44. txt = str(2**index) if index else ''
  45. self.labels.append(text.Label(txt, font_size=font_size, x=x+size//2, y=y+size//2,
  46. anchor_x='center', anchor_y='center', bold=True, batch=batch))
  47. '''以下控件测试用'''
  48. self.line1 = shapes.Line(20, 20, 580, 580, width=4, color=(255, 0, 0), batch=batch)
  49. self.line2 = shapes.Line(20, 580, 580, 20, width=4, color=(255, 0, 0), batch=batch)
  50. self.box = shapes.Box(18, 18, 564, 564, thickness=4, color=(255, 0, 0), batch=batch)
  51. self.text = text.Label("", x=450, y=650, font_size=24, color=(250, 0, 0, 255),
  52. anchor_x='center', anchor_y='center', bold=True, batch=batch)
  53. any_key = True
  54. any_key_label = text.Label("any key to start ......", x=window.width//2, y=window.height//2,
  55. font_size=24, anchor_x='center', anchor_y='center')
  56. @window.event
  57. def on_draw():
  58. window.clear()
  59. batch.draw()
  60. if any_key:
  61. any_key_label.draw()
  62. def move_test(direction):
  63. global game
  64. game.text.text = direction.title()
  65. @window.event
  66. def on_key_press(symbol, modifiers):
  67. global any_key, game, direction
  68. if any_key:
  69. any_key = False
  70. title2048(20, 630)
  71. game = Game2048(5)
  72. return
  73. order = symbol - 48 if symbol<100 else symbol - 65456
  74. if order in range(2,10):
  75. game = Game2048(order)
  76. if symbol in (key.A, key.LEFT):
  77. move_test('left')
  78. elif symbol in (key.D, key.RIGHT):
  79. move_test('right')
  80. elif symbol in (key.W, key.UP):
  81. move_test('up')
  82. elif symbol in (key.S, key.DOWN):
  83. move_test('down')
  84. direction = None
  85. @window.event
  86. def on_mouse_press(x, y, button, modifier):
  87. if any_key:
  88. on_key_press(0, 0)
  89. if direction == 'left':
  90. move_test('left')
  91. elif direction == 'right':
  92. move_test('right')
  93. elif direction == 'up':
  94. move_test('up')
  95. elif direction == 'down':
  96. move_test('down')
  97. @window.event
  98. def on_mouse_motion(x, y, dx, dy):
  99. global direction
  100. if 20<x<y<580 and x+y<600:
  101. direction = 'left'
  102. elif 20<y<x<580 and x+y>600:
  103. direction = 'right'
  104. elif 20<x<y<580 and x+y>600:
  105. direction = 'up'
  106. elif 20<y<x<580 and x+y<600:
  107. direction = 'down'
  108. else:
  109. direction = None
  110. def switch_visible(event):
  111. any_key_label.visible = not any_key_label.visible
  112. if any_key:
  113. pyglet.clock.schedule_interval(switch_visible, 0.5)
  114. title2048()
  115. pyglet.app.run()

待续......

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/585684
推荐阅读
相关标签
  

闽ICP备14008679号