“嗨嗨嗨!別睡了,醒醒醒醒!該干活兒了~” by——顧木子吖!
?
“剛睡醒,大佬你有什么事兒吖?” by——全體成員!
上期給大家分享的超詳細——簡易版本的2048都吃透了沒?咳咳咳......沒吃透也沒關系!
慢慢來,木木子一直在等你們崛起~哈哈哈哈 ,吶~ 現在這篇文章的話是上次承諾的一個升級版本的2048小游戲。
比之之前那款呢?有什么不同?
?
?那當然是大大的不同那,今天教大家寫的這款是有界面的小程序,單單是有界面的這一點就可以超前面那款了,更加富有趣味性的撒~來,我們來看看!
?
正文環境安裝:Python3、pycharm、Pygame模塊等。
pip install -i https://pypi.douban.com/simple/ pygame
配置文件:
音樂、背景、字體等。
import os
'''FPS'''
FPS = 60
'''背景顏色'''
BG_COLOR = '#D3D3D3'
'''屏幕大小'''
SCREENSIZE = (650, 370)
'''保存當前最高分的文件'''
MAX_SCORE_FILEPATH = 'score'
'''字體路徑'''
FONTPATH = os.path.join(os.getcwd(), 'resources/font/Gabriola.ttf')
'''背景音樂路徑'''
BGMPATH = os.path.join(os.getcwd(), 'resources/audio/bgm.mp3')
'''其他一些必要的常量'''
MARGIN_SIZE = 10
BLOCK_SIZE = 80
GAME_MATRIX_SIZE = (4, 4)
?定義2048游戲:
class Game2048(object):
def __init__(self, matrix_size=(4, 4), max_score_filepath=None, **kwargs):
# matrix_size: (num_rows, num_cols)
self.matrix_size = matrix_size
# 游戲最高分保存路徑
self.max_score_filepath = max_score_filepath
# 初始化
self.initialize()
'''更新游戲狀態'''
def update(self):
game_matrix_before = copy.deepcopy(self.game_matrix)
self.move()
if game_matrix_before != self.game_matrix: self.randomGenerateNumber()
if self.score > self.max_score: self.max_score = self.score
'''根據指定的方向, 移動所有數字塊'''
def move(self):
# 提取非空數字
def extract(array):
array_new = []
for item in array:
if item != 'null': array_new.append(item)
return array_new
# 合并非空數字
def merge(array):
score = 0
if len(array) < 2: return array, score
for i in range(len(array)-1):
if array[i] == 'null':
break
if array[i] == array[i+1]:
array[i] *= 2
array.pop(i+1)
array.append('null')
score += array[i]
return extract(array), score
# 不需要移動的話直接return
if self.move_direction is None: return
# 向上
if self.move_direction == 'up':
for j in range(self.matrix_size[1]):
col = []
for i in range(self.matrix_size[0]):
col.append(self.game_matrix[i][j])
col = extract(col)
col.reverse()
col, score = merge(col)
self.score += score
col.reverse()
col = col + ['null',] * (self.matrix_size[0] - len(col))
for i in range(self.matrix_size[0]):
self.game_matrix[i][j] = col[i]
# 向下
elif self.move_direction == 'down':
for j in range(self.matrix_size[1]):
col = []
for i in range(self.matrix_size[0]):
col.append(self.game_matrix[i][j])
col = extract(col)
col, score = merge(col)
self.score += score
col = ['null',] * (self.matrix_size[0] - len(col)) + col
for i in range(self.matrix_size[0]):
self.game_matrix[i][j] = col[i]
# 向左
elif self.move_direction == 'left':
for idx, row in enumerate(copy.deepcopy(self.game_matrix)):
row = extract(row)
row.reverse()
row, score = merge(row)
self.score += score
row.reverse()
row = row + ['null',] * (self.matrix_size[1] - len(row))
self.game_matrix[idx] = row
# 向右
elif self.move_direction == 'right':
for idx, row in enumerate(copy.deepcopy(self.game_matrix)):
row = extract(row)
row, score = merge(row)
self.score += score
row = ['null',] * (self.matrix_size[1] - len(row)) + row
self.game_matrix[idx] = row
self.move_direction = None
'''在新的位置隨機生成數字'''
def randomGenerateNumber(self):
empty_pos = []
for i in range(self.matrix_size[0]):
for j in range(self.matrix_size[1]):
if self.game_matrix[i][j] == 'null': empty_pos.append([i, j])
i, j = random.choice(empty_pos)
self.game_matrix[i][j] = 2 if random.random() > 0.1 else 4
'''初始化'''
def initialize(self):
self.game_matrix = [['null' for _ in range(self.matrix_size[1])] for _ in range(self.matrix_size[0])]
self.score = 0
self.max_score = self.readMaxScore()
self.move_direction = None
self.randomGenerateNumber()
self.randomGenerateNumber()
'''設置移動方向'''
def setDirection(self, direction):
assert direction in ['up', 'down', 'left', 'right']
self.move_direction = direction
'''保存最高分'''
def saveMaxScore(self):
f = open(self.max_score_filepath, 'w', encoding='utf-8')
f.write(str(self.max_score))
f.close()
'''讀取游戲最高分'''
def readMaxScore(self):
try:
f = open(self.max_score_filepath, 'r', encoding='utf-8')
score = int(f.read().strip())
f.close()
return score
except:
return 0
'''游戲是否結束'''
@property
def isgameover(self):
for i in range(self.matrix_size[0]):
for j in range(self.matrix_size[1]):
if self.game_matrix[i][j] == 'null': return False
if (i == self.matrix_size[0] - 1) and (j == self.matrix_size[1] - 1):
continue
elif (i == self.matrix_size[0] - 1):
if (self.game_matrix[i][j] == self.game_matrix[i][j+1]):
return False
elif (j == self.matrix_size[1] - 1):
if (self.game_matrix[i][j] == self.game_matrix[i+1][j]):
return False
else:
if (self.game_matrix[i][j] == self.game_matrix[i+1][j]) or (self.game_matrix[i][j] == self.game_matrix[i][j+1]):
return False
return True
?然后設置不同的顏色。
不同的數字2-4-8等等組合成不同的數字顏色相應的變化。
顏色展示:
def getColorByNumber(number):
number2color_dict = {
2: ['#eee4da', '#776e65'], 4: ['#ede0c8', '#776e65'], 8: ['#f2b179', '#f9f6f2'],
16: ['#f59563', '#f9f6f2'], 32: ['#f67c5f', '#f9f6f2'], 64: ['#f65e3b', '#f9f6f2'],
128: ['#edcf72', '#f9f6f2'], 256: ['#edcc61', '#f9f6f2'], 512: ['#edc850', '#f9f6f2'],
1024: ['#edc53f', '#f9f6f2'], 2048: ['#edc22e', '#f9f6f2'], 4096: ['#eee4da', '#776e65'],
8192: ['#edc22e', '#f9f6f2'], 16384: ['#f2b179', '#776e65'], 32768: ['#f59563', '#776e65'],
65536: ['#f67c5f', '#f9f6f2'], 'null': ['#9e948a', None]
}
return number2color_dict[number]
'''將2048游戲的當前數字排列畫到屏幕上'''
def drawGameMatrix(screen, game_matrix, cfg):
for i in range(len(game_matrix)):
for j in range(len(game_matrix[i])):
number = game_matrix[i][j]
x = cfg.MARGIN_SIZE * (j + 1) + cfg.BLOCK_SIZE * j
y = cfg.MARGIN_SIZE * (i + 1) + cfg.BLOCK_SIZE * i
pygame.draw.rect(screen, pygame.Color(getColorByNumber(number)[0]), (x, y, cfg.BLOCK_SIZE, cfg.BLOCK_SIZE))
if number != 'null':
font_color = pygame.Color(getColorByNumber(number)[1])
font_size = cfg.BLOCK_SIZE - 10 * len(str(number))
font = pygame.font.Font(cfg.FONTPATH, font_size)
text = font.render(str(number), True, font_color)
text_rect = text.get_rect()
text_rect.centerx, text_rect.centery = x + cfg.BLOCK_SIZE / 2, y + cfg.BLOCK_SIZE / 2
screen.blit(text, text_rect)
?游戲界面添加額外的元素。
如下圖:玩法介紹、分數顯示。
?
'''將游戲的最高分和當前分數畫到屏幕上'''
def drawScore(screen, score, max_score, cfg):
font_color = (255, 255, 255)
font_size = 30
font = pygame.font.Font(cfg.FONTPATH, font_size)
text_max_score = font.render('Best: %s' % max_score, True, font_color)
text_score = font.render('Score: %s' % score, True, font_color)
start_x = cfg.BLOCK_SIZE * cfg.GAME_MATRIX_SIZE[1] + cfg.MARGIN_SIZE * (cfg.GAME_MATRIX_SIZE[1] + 1)
screen.blit(text_max_score, (start_x+10, 10))
screen.blit(text_score, (start_x+10, 20+text_score.get_rect().height))
start_y = 30 + text_score.get_rect().height + text_max_score.get_rect().height
return (start_x, start_y)
'''游戲介紹'''
def drawGameIntro(screen, start_x, start_y, cfg):
start_y += 40
font_color = (0, 0, 0)
font_size_big = 30
font_size_small = 20
font_big = pygame.font.Font(cfg.FONTPATH, font_size_big)
font_small = pygame.font.Font(cfg.FONTPATH, font_size_small)
intros = ['Game play:', ' Slide the keyboard up, down, left and right.', 'Combine two identical numbers', 'For example: 2 + 2 = 4, 4 + 4 = 8... Until 1024 + 1024 = 2048!', 'You win!']
for idx, intro in enumerate(intros):
font = font_big if idx == 0 else font_small
text = font.render(intro, True, font_color)
screen.blit(text, (start_x+10, start_y))
start_y += text.get_rect().height + 10
游戲結束界面:
附源碼:
def endInterface(screen, cfg):
font_size_big = 60
font_size_small = 30
font_color = (255, 255, 255)
font_big = pygame.font.Font(cfg.FONTPATH, font_size_big)
font_small = pygame.font.Font(cfg.FONTPATH, font_size_small)
surface = screen.convert_alpha()
surface.fill((127, 255, 212, 2))
text = font_big.render('Game Over!', True, font_color)
text_rect = text.get_rect()
text_rect.centerx, text_rect.centery = cfg.SCREENSIZE[0]/2, cfg.SCREENSIZE[1]/2-50
surface.blit(text, text_rect)
button_width, button_height = 100, 40
button_start_x_left = cfg.SCREENSIZE[0] / 2 - button_width - 20
button_start_x_right = cfg.SCREENSIZE[0] / 2 + 20
button_start_y = cfg.SCREENSIZE[1] / 2 - button_height / 2 + 20
pygame.draw.rect(surface, (0, 255, 255), (button_start_x_left, button_start_y, button_width, button_height))
text_restart = font_small.render('Restart', True, font_color)
text_restart_rect = text_restart.get_rect()
text_restart_rect.centerx, text_restart_rect.centery = button_start_x_left + button_width / 2, button_start_y + button_height / 2
surface.blit(text_restart, text_restart_rect)
pygame.draw.rect(surface, (0, 255, 255), (button_start_x_right, button_start_y, button_width, button_height))
text_quit = font_small.render('Quit', True, font_color)
text_quit_rect = text_quit.get_rect()
text_quit_rect.centerx, text_quit_rect.centery = button_start_x_right + button_width / 2, button_start_y + button_height / 2
surface.blit(text_quit, text_quit_rect)
while True:
screen.blit(surface, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN and event.button:
if text_quit_rect.collidepoint(pygame.mouse.get_pos()):
return False
if text_restart_rect.collidepoint(pygame.mouse.get_pos()):
return True
pygame.display.update()
主程序:
def main(cfg):
# 游戲初始化
pygame.init()
screen = pygame.display.set_mode(cfg.SCREENSIZE)
pygame.display.set_caption('2048小游戲升級版')
# 播放背景音樂
pygame.mixer.music.load(cfg.BGMPATH)
pygame.mixer.music.play(-1)
# 實例化2048游戲
game_2048 = Game2048(matrix_size=cfg.GAME_MATRIX_SIZE, max_score_filepath=cfg.MAX_SCORE_FILEPATH)
# 游戲主循環
clock = pygame.time.Clock()
is_running = True
while is_running:
screen.fill(pygame.Color(cfg.BG_COLOR))
# --按鍵檢測
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key in [pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT]:
game_2048.setDirection({pygame.K_UP: 'up', pygame.K_DOWN: 'down', pygame.K_LEFT: 'left', pygame.K_RIGHT: 'right'}[event.key])
# --更新游戲狀態
game_2048.update()
if game_2048.isgameover:
game_2048.saveMaxScore()
is_running = False
# --將必要的游戲元素畫到屏幕上
drawGameMatrix(screen, game_2048.game_matrix, cfg)
start_x, start_y = drawScore(screen, game_2048.score, game_2048.max_score, cfg)
drawGameIntro(screen, start_x, start_y, cfg)
# --屏幕更新
pygame.display.update()
clock.tick(cfg.FPS)
return endInterface(screen, cfg)
'''run'''
if __name__ == '__main__':
while True:
if not main(cfg):
break
2048游戲效果如下圖所示:
?
本來是想給大家截一張2048的圖的,但是玩了好幾遍都卡死了,這圖你們就將就著看叭~我盡力了!
?
?總結好啦!這篇升級版的2048小游戲就到這里結束啦,快來試試你能通關嘛?
?
免費源碼領取處:如需完整的項目源碼+素材源碼基地見:#私信小編06#即可獲取免費的福利!
你們的支持是我最大的動力?。?strong>記得三連哦~mua 歡迎大家閱讀往期的文章哦~
本文作者:愛折騰的老司機
一、前言
近期先是N家推出了支持光線追蹤的RTX系列顯卡,接著是A家推出了Radeon? VII顯卡,不管是RTX2080還是Radeon? VII,對普通玩家來說,5000+的價格等于一臺整機的價格了,所以我們只能看看評測,口水一下就好。
適逢近期戰地5、APEX英雄、刺客信條 奧德賽、古墓麗影 暗影等游戲新作上市,難不成沒有高級的顯卡,我們就不玩這些游戲了?
非也,非也!對于大多數人來說,千元級的顯卡才是需求量最大的產品,這個級別的顯卡盡管不支持最新的光線追蹤技術,但在1080P分辨率下,還是能夠暢玩大多數游戲的,就算遇到個別要求高的,降降抗鋸齒之類的特效也是能玩的。
目前這個價位A、N都有顯卡,A家的自然是馬甲卡RX 580 2048SP 4G,N家則是挖礦庫存貨GTX1060 3G。
其實本人以前對比過RX 480 4G(2304SP)和GTX1060 3G,RX 480 4G(2304SP)能夠勉勝GTX1060 3G,那么,RX 580 2048SP 4G在SP少了256個的情況下,對上GTX1060 3G豈不是很懸?
No,No,No,別忘了DIY圈子里還流傳著一句話:“A卡戰未來”,尤其是近期AMD的驅動升級到腎上腺素Adrenalin 2019 Edition后,RX 570綜合性能都可以提高15%,要知道,RX 580 2048SP 4G就是RX 570 4G的馬甲版本。這樣一來,RX 580 2048SP 4G對上GTX1060 3G鹿死誰手,尤未可知呢!
是騾子是馬,拉出來溜溜,誰強誰弱,PK一番不就知道了。本人手頭已經有一張RX 580 2048SP 4G了,后來又找朋友借了一張GTX1060 3G,正好春節放假有時間,索性就進行了一番對比測試,看看結果究竟怎么樣。
兩張顯卡合影,左下為迪蘭RX 580 2048SP 4G X-Serial,右上為銘瑄 GTX1060 3G 巨無霸,從正面來看,兩張卡都是雙風扇,長度也基本差不多,價格方面, GTX1060 3G要比RX 580 2048SP 4G貴200多,但迪蘭的卡散熱明顯好一些,一來風扇大一些,二來熱管和散熱片多一些。
迪蘭(Dataland)RX 580 2048SP 4G X-Serial 戰將 1284-1310/7000MHz 4GB/256-bit GDDR5 DX12獨立游戲顯卡1049元
背面,迪蘭的卡有背板,銘瑄的無背板。
頂部,迪蘭的造型復雜一些,銘瑄的簡約一些,供電接口迪蘭8PIN、銘瑄6PIN。
輸出接口數量一致,就是位置稍微有點不同。
二、搭建測試平臺
要進行對比測試, 自然要搭建測試平臺。
簡單介紹一下主要配件吧,盒裝銳龍 5 2600。
AMD 銳龍 5 2600 處理器 (r5) 6核12線程 AM4 接口 3.4GHz 盒裝CPU1299元
銳龍 5 2600,6核12線程,使用12nm工藝制造,主頻3.4GHz,最大加速頻率3.9GHz,是性能比很高的一款U。
主板,微星B350M GAMING PRO,盡管是B350,但刷個BIOS就能支持2字開頭的銳龍。
淘寶網 - 淘!我喜歡s.taobao.com
去看看
內存,金士頓Predator DDR4 2933 8GX2 RGB。
SSD,金士頓 HyperX Fury 雷電 RGB SSD 480G,其實之前其實有一塊480G SSD,當時是夠用的,可這次下載了戰地5(50G)、APEX英雄(20G)、刺客信條 奧德賽(50G)、古墓麗影 暗影(40G)等新游戲后,那塊480G就放不下了,只好再新入一塊SSD。
該盤某東自營目前480G無貨,只有960G,想要480G可以第三方或者某寶買。
金士頓(Kingston)HyperX Fury系列 雷電 960G SATA3 RGB SSD固態硬盤1399元
金士頓 HyperX Fury 雷電 RGB SSD 480G在性能方面和其他SATA接口的SSD基本差不多,比較有特色的是支持RGB燈效,這個功能在SSD上還是比較少見的。
附件一覽,可以看出多了一條線,它就是實現RGB的關鍵。
盤的外觀和普通的Fury SSD也有不同,尤其是上下有兩排可以透光的小顆粒。
背面沒啥奇特的。
這里多了個類似Micro USB的接口,但其實是RGB接口,其電壓定義是和Micro USB不同的,請不要用安卓手機充電線作死去試。
另一端可以接主板RGB接口或控制器。
順便簡單測試一下,先看看S.M.A.R.T信息,由于我測試完游戲才想起用CrystalDiskInfo看SSD信息,所以有一定的通電時間和次數,其中大多數通電時間是浪費在掛機下載戰地5和APEX上的,這里我要吐槽一下EA的服務器,真的很慢,掛機2天才下完兩個游戲。當然,要不是網上找了攻略,三天都未必能下完。
AS SSD Benchmark測試,受限于SATA接口,所以和主流SATA接口的產品區別不大。
CrystalDiskMark測試,也基本跑滿SATA接口的極限了。
TxBench測試。
Anvil's Storage Utilities測試,跟NVME盤沒得比,但在SATA盤中分數也算可以了,反正用來當游戲倉庫,容量第一。
裝機,機器基本是現成的,上次體驗AMD LINK時就裝了一臺,這次增加一塊SSD就行了。
機箱背面有兩個2.5吋磁盤位,直接裝上即可。
背面一覽,這下兩個2.5吋磁盤位都滿了。
蓋好側板就完事了。
順便體驗一下燈光,金士頓 HyperX Fury RGB SSD 480G可以用主板軟件控制RGB燈效,MSI的GAMING APP走起。
機箱正面燈效。
機箱背面的2.5吋磁盤位正好留了透光的位置,所以SSD的燈光能夠通過側板透出,先是紫色。
再看白色。
三、大戰三百回合
開戰前,先看兩款顯卡的規格,GPU-Z走起。
圖形理論性能測試:
3Dmark FireStrike,可以看出,在最新腎上腺素的加成下,RX 580 2048SP 4G已經略勝一籌。
3Dmark Time Spy,依然是RX 580 2048SP 4G小勝。
游戲性能測試:
戰地5是一款由EA制作并發行的第一人稱射擊游戲,其畫質達到了照片級,可玩性也十分豐富,需要用橘子(Origin)平臺登陸才能玩。游戲支持DX11和DX12兩種模式,由于游戲沒有自帶Benchmark程序,而第三方的DX12測試軟件比較少,所以這里只測試DX11模式。
圖形設置如下。
由于是手動操作,為了減小誤差,采用訓練場跑固定圈,Fraps記錄的方式進行測試。
起點就在這里。
測試完畢,RX 580 2048SP 4G比GTX1060 3G高了12幀,這幅度還是比較大的。
另外,從兩條曲線基本平行可以看出,本人的手動跑圈測試法誤差還是比較小的。
APEX英雄,還是EA的游戲,要玩也得用橘子(Origin)平臺,游戲和吃雞類似,玩法卻豐富了許多,但我能吐槽服務器嗎,游戲更新慢不說,還各種登不進去。
當然,吐槽歸吐槽,由于該游戲完全免費,所以還是說一聲“真香”吧!
圖形設置。
組個隊先體驗一把,開始跳傘了,這跳傘方式比吃雞酷炫很多。
落地了,開始沖鴨,然而,很快就團滅了。。。。
還是收了心,先為大家跑測試吧,這個游戲也不帶Benchmark程序,所以這里繼續用訓練場跑圈法測試。
這款游戲依然是RX 580 2048SP 4G表現較好,GTX1060 3G的曲線出現了許多狗牙,這說明其3G顯存在某些場景會不夠用,俗稱爆顯存。
刺客信條 奧德賽,育碧的經典游戲,已經是第十一部了,盡管這是一款DX11游戲,但其畫質是很贊的。
圖形設置,環境細節設置為極高。
看似GTX1060 3G平均幀數只低了2幀,但其實又爆顯存了,最低幀只有4,曲線圖也是各種狗牙。大家想要流暢玩耍,可酌情降低特效。
古墓麗影 暗影是一款由Eidos Montreal工作室制作的動作冒險游戲,該系列也是大家耳熟能詳的經典游戲了,此版本為重啟系列三部曲的終章。好不好玩咱先不說,但本人覺得這個版本的女漢子勞拉是最好看的。
圖形設置,這次吸取了刺客信條 奧德賽的經驗教訓,將抗鋸齒由4倍降為1倍,其他依然是能高則高。
測試結果,RX 580 2048SP 4G高出GTX1060 3G 11幀。
絕地求生 大逃殺圖形設置。
測試結果,這里GTX1060 3G終于扳回一局,小勝RX 580 2048SP 4G。
四、測試匯總及總結
為了不因篇幅過長導致大家看的太累,剩下的游戲測試我就不逐一上圖了,這里直接放匯總結果。
可以看出,通過驅動的不停優化,到了腎上腺素Adrenalin 2019 Edition時,量變終于引起質變,RX 580 2048SP 4G可以在大多數游戲中打敗比自身貴200多的GTX1060 3G,這證明了“A卡戰未來”所言不虛。
另外,還有一部分游戲,GTX1060 3G輸在顯存少了1G上,這1G顯存看似不多,但游戲出現較低幀的頻率明顯高了很多,這對游戲體驗影響很大。
當然,由于架構偏老,所以RX 580 2048SP 4G在功耗方面比不過GTX1060 3G。
以上測試就到這里了,鑒于測試不易、寫文不易,還請大家點贊、收藏、打賞支持,如果有不同觀點或者想進一步了解相關技術,也可以回帖討論。
五、文末彩蛋
這里教大家一個方法,能解決大部分戰地5及APEX等Origin平臺游戲更新慢的問題,新人趕緊收藏,老鳥請無視。
首先用Origin CDN切換器選擇Akamai,然后應用(需要在Origin退出時進行)。
接著打開UsbEAm Hosts Editor,點擊左下角的+號。
選擇Origin,再選最后一個。
然后出現一堆服務器,點檢測延遲,隨后會顯示延遲數值。
然后選中延遲最低的,點應用選中。
應用成功就可以打開Origin進行游戲更新了,如果過了一會兒這條線路又變慢了,可以繼續換一條,方法是退出Origin,然后點清除當前,然后繼續檢測延遲,誰低就選誰