小游戏《Let's Go! PiPiXia!》

在知乎上发现此游戏的分享,非常感谢作者的分享。这是我阅读的第一个小项目代码。给我最深的体会便是divide and conquer,逐步实现模块的功能,最后实现游戏的功能。简单分析,好像游戏实现的思路并不难。

module 1. PPX的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# -*- coding: utf-8 -*-
import math
import random
import cocos

class PPX(cocos.sprite.Sprite):
def __init__(self):
super(PPX, self).__init__('ppx.png')
self.can_jump = False
self.speed = 0
self.image_anchor = 0, 0
self.position = 100, 300
self.schedule(self.update)

def jump(self, h):
if self.can_jump:
self.y += 1
self.speed -= max(min(h, 10), 7)
self.can_jump = False

def land(self, y):
if self.y > y - 30:
self.can_jump = True
self.speed = 0
self.y = y

def update(self, dt): #重力属性
self.speed += 10 * dt
self.y -= self.speed
if self.y < -80:
self.reset()

def reset(self):
self.parent.reset()
self.can_jump = False
self.speed = 0
self.position = 100, 300

module 2. Block的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: utf-8 -*-
import math
import random
import cocos

class Block(cocos.sprite.Sprite):
def __init__(self, pos):
super(Block, self).__init__('black.png')
self.image_anchor = 0, 0
x, y = pos
if x == 0:
self.scale_x = 5
self.scale_y = 1
else:
# 随机产生黑块的大小
# random.random() 产生0 ~ 1 的小数
self.scale_x = 0.5 + random.random() * 1.5
self.scale_y = min(max(y - 50 + random.random() * 100, 50), 300) / 100.0
self.position = x + 50 + random.random() * 100, 0

module 3. 主体的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# -*- coding: utf-8 -*-
import cocos
from cocos.sprite import Sprite
from pyaudio import PyAudio, paInt16
import struct
from ppx import PPX
from block import Block

class VoiceGame(cocos.layer.ColorLayer):
is_event_handler = True

def __init__(self):
super(VoiceGame, self).__init__(255, 255, 255, 255, 800, 600)



# init voice
self.NUM_SAMPLES = 1000 # pyAudio内部缓存的块的大小
self.LEVEL = 1500 # 声音保存的阈值
#声音强度条
self.voicebar = Sprite('black.png', color=(0, 0, 255))
self.voicebar.position = 20, 450
self.voicebar.scale_y = 0.1
self.voicebar.image_anchor = 0, 0
self.add(self.voicebar)

self.ppx = PPX()
self.add(self.ppx)

self.floor = cocos.cocosnode.CocosNode()
self.add(self.floor)
pos = 0, 100
#循环产生100个黑块
for i in range(100):
b = Block(pos)
self.floor.add(b)
pos = b.x + b.width, b.height

# 开启声音输入
pa = PyAudio()
SAMPLING_RATE = int(pa.get_device_info_by_index(0)['defaultSampleRate'])
self.stream = pa.open(format=paInt16, channels=1, rate=SAMPLING_RATE, input=True, frames_per_buffer=self.NUM_SAMPLES)

self.schedule(self.update)

def on_mouse_press(self, x, y, buttons, modifiers):
pass

def collide(self):
px = self.ppx.x - self.floor.x
for b in self.floor.get_children():
if b.x <= px + self.ppx.width * 0.8 and px + self.ppx.width * 0.2 <= b.x + b.width: #落在黑块
if self.ppx.y < b.height:
self.ppx.land(b.height)
break

def update(self, dt):
# 读入NUM_SAMPLES个取样
string_audio_data = self.stream.read(self.NUM_SAMPLES)
k = max(struct.unpack('1000h', string_audio_data))
# print k
self.voicebar.scale_x = k / 10000.0
if k > 3000:
self.floor.x -= min((k / 20.0), 150) * dt
if k > 8000:
self.ppx.jump((k - 8000) / 1000.0)
self.collide()

def reset(self):
self.floor.x = 0


cocos.director.director.init(caption="Let's Go! PiPiXia!")
cocos.director.director.run(cocos.scene.Scene(VoiceGame()))

附上源码地址:http://git.oschina.net/crossin/learn-python/tree/master/voicegame

公众号:Crossin的编程教室