7 构建2048游戏

game.kv

#:set padding 20

FloatLayout:
    Board:
        id:board
        pos_hint:{'center_x':0.5,'center_y':0.5}
        size_hint:(None,None)
        center:root.center
        size:[min(root.width,root.height)- 2 * padding]*2

<Tile>:
    canvas:
        Color:
            rgb:self.color
        BorderImage:
            pos:self.pos
            size:self.size
            source:'cell.png'
    Label:
        pos:root.pos
        size:root.size
        bold:True
        color:root.number_color
        font_size:root.font_size
        text:str(root.number)

 main.py

import random
from kivy.app import App
from kivy.animation import Animation
from kivy.graphics import Color,BorderImage
from kivy.properties import ListProperty,NumericProperty
from kivy.uix.widget import Widget
from kivy.vector import Vector
from kivy.core.window import Window,Keyboard
from kivy.utils import get_color_from_hex

spacing = 15

colors = ('eee4da', 'ede0c8', 'f2b179', 'f59563','f67c5f', 'f65e3b', 'edcf72',
          'edcc61','edc850', 'edc53f', 'edc22e')

tile_colors = {2**i:color for i,color in
               enumerate(colors,start=1)}

key_vectors = {
    Keyboard.keycodes['up']:(0,1),
    Keyboard.keycodes['right']:(1,0),
    Keyboard.keycodes['down']:(0,-1),
    Keyboard.keycodes['left']:(-1,0),
}

class Tile(Widget):    #方块类
    font_size = NumericProperty(24)
    number  = NumericProperty(2)
    color = ListProperty(get_color_from_hex(tile_colors[2]))
    number_color = ListProperty(get_color_from_hex('776e65'))

    def __init__(self,number=2,**kwargs): #初始化
        super(Tile, self).__init__(**kwargs)
        self.font_size = 0.5 * self.width
        self.number = number
        self.update_colors()

    def update_colors(self):             #更新颜色
        self.color = get_color_from_hex(tile_colors[self.number])
        if self.number > 4 :
            self.number_color = get_color_from_hex('f9f6f2')

    def resize(self,pos,size):           #计算大小和位置
        self.pos = pos
        self.size = size
        self.font_size = 0.5 * self.width

def all_cells(flip_x=False,flip_y=False):  #遍历所有表格
    for x in (reversed(range(4)) if flip_x else range(4)):
        for y in (reversed(range(4)) if flip_y else range(4)):
            yield (x,y)


class Board(Widget):                   #棋盘类
    b = None
    moving = False

    def __init__(self,**kwargs):       #初始化
        super(Board,self).__init__(**kwargs)
        self.resize()

    def reset(self):                   #重置
        self.b = [[None for i in range(4)] for j in range(4)]
        self.new_tile()
        self.new_tile()

    def new_tile(self, *args):        #生成一个新方块
        empty_cells = [(x, y) for x, y in all_cells()
                       if self.b[x][y] is None]
        if not empty_cells:
            print('Game over(tentative:no cells)')
            return

        x,y = random.choice(empty_cells)
        tile = Tile(pos = self.cell_pos(x,y),
                    size = self.cell_size)
        self.b[x][y] = tile
        self.add_widget(tile)

        if len(empty_cells) == 1  and self.is_deadlocked():
            print('Grame over (board is deadlocked)')

        self.moving = False

    def is_deadlocked(self):
        for x,y in all_cells():
            if self.b[x][y] is None:
                return False

            number = self.b[x][y].number
            if self.can_combine(x + 1, y, number) or \
                self.can_combine(x,y+1,number):
                return False
        return True

    def move(self,dir_x,dir_y):        #移动方块
        if self.moving:
            return

        dir_x = int(dir_x)
        dir_y = int(dir_y)

        for board_x, board_y in all_cells(dir_x > 0,dir_y > 0):
            tile = self.b[board_x][board_y]
            if not tile:
                continue

            x,y = board_x,board_y
            while self.can_move(x+dir_x,y+dir_y):
                self.b[x][y] = None
                x += dir_x
                y += dir_y
                self.b[x][y] = tile

            if self.can_combine(x+dir_x,y+dir_y,tile.number):
                self.b[x][y] = None
                x += dir_x
                y += dir_y
                self.remove_widget(self.b[x][y])
                self.b[x][y] = tile
                tile.number *= 2
                if(tile.number == 2048):
                    print('You win the game')

                tile.update_colors()

            if x == board_x and y == board_y:
                continue

            anim = Animation(pos = self.cell_pos(x,y),duration=0.25,
                             transition='linear')

            if not self.moving:
                anim.on_complete = self.new_tile
                self.moving = True

            anim.start(tile)

    def cell_pos(self, board_x, board_y):     #方块位置
        return (self.x + board_x * (self.cell_size[0] + spacing) + spacing,
                self.y + board_y * (self.cell_size[1] + spacing) + spacing)

    def valid_cell(self,board_x,board_y):     #判断是否可以移动
        return (board_x >= 0 and board_y >= 0 and board_x <=3 and board_y <=3)

    def can_move(self,board_x,board_y):       #判断移动
        return (self.valid_cell(board_x, board_y) and self.b[board_x][board_y] is None)

    def can_combine(self,board_x,board_y,number):     #判断合并
        return (self.valid_cell(board_x,board_y) and
            self.b[board_x][board_y] is not None and
            self.b[board_x][board_y].number == number)

    def resize(self,*args):                     #初始化尺寸
        self.cell_size = (0.25*(self.width-5*spacing),)*2

        self.canvas.before.clear()
        with self.canvas.before:
            BorderImage(pos = self.pos,size = self.size,source='board.png')
            Color(*get_color_from_hex('ccc0b4'))
            for board_x,board_y in all_cells():
                BorderImage(pos=self.cell_pos(board_x,board_y),
                            size=self.cell_size,source='cell.png')

        if not self.b:
            return

        for board_x,board_y in all_cells():
            tile = self.b[board_x][board_y]
            if tile:
                tile.resize(pos=self.cell_pos(board_x,board_y),
                            size=self.cell_size)

    def on_key_down(self,window,key,*args):   #触发事件,回调函数
        if key in key_vectors:
            self.move(*key_vectors[key])

    def on_touch_up(self, touch):              #触发事件,回调函数
        """判断是否滑动"""
        v = Vector(touch.pos) - Vector(touch.opos)
        if v.length() < 20:
            return
        # 比较绝对值
        if abs(v.x) > abs(v.y):
            v.y  = 0
        else:
            v.x = 0
        # 移动
        self.move(*v.normalize())

    on_pos = resize
    on_size = resize

class GameApp(App):
    def build(self):
        # 通过id获取到FloatLayout布局中的Board
        board = self.root.ids.board
        board.reset()
        Window.bind(on_key_down = board.on_key_down)

if __name__ == '__main__':
    Window.clearcolor = get_color_from_hex('faf8ef')
    GameApp().run()                    #启动应用程序

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值