|
楼主 |
发表于 2018-3-2 13:04:59
|
显示全部楼层
第九篇:用kivy编写碰撞球小游戏
上一篇中,我们用kivy编写了一个倒计时的小程序。今天我们再增加一点难度,用kivy编写一个碰撞球小游戏,这个小游戏的原理与@小甲鱼的打飞机小游戏原理差不多,都是调用碰撞检查,然后改变位置。
看一下最终的游戏界面:
它可以编译成apk在手机安装,并支持双人对战(多点触控)。
第一步,我们先来创建程序。# -*- coding: utf-8 -*-
from random import randint
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty #导入kivy属性
Builder.load_string('''
<PongGame>:
ball: pong_ball #通过id引用PongBall对象
canvas:
Rectangle:
pos: self.center_x - 5, 0
size: 10, self.height
Label:
font_size: 70
center_x: root.width / 4
top: root.top - 50
text: '0'
Label:
font_size: 70
center_x: root.width * 3 / 4
top: root.top - 50
text: '0'
PongBall:
id: pong_ball
center: self.parent.center
<PongBall>:
size: 50, 50
canvas:
Ellipse:
pos: self.pos
size: self.size
''')
class PongGame(Widget):
ball = ObjectProperty(None) #声明ball是Object对象,这点与通常的python动态语言不同,通常python语言是不需要声明的。
def update(self, dt):
self.ball.move()
if self.ball.y<0 or self.ball.top>self.height: #纵向碰壁反弹
self.ball.velocity_y *= -1
if self.ball.x<0 or self.ball.right>self.width: #横向碰壁反弹
self.ball.velocity_x *= -1
def serve_ball(self): #发球
self.ball.center = self.center
self.ball.velocity = Vector(4,0).rotate(randint(0,360)) #矢量合成并旋转任意角度
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x,velocity_y)
def move(self):
self.pos = Vector(*self.velocity) + self.pos #位置更新
class PongApp(App):
def build(self):
game = PongGame()
game.serve_ball()
Clock.schedule_interval(game.update, 1.0/60.0)
return game
if __name__ == '__main__':
PongApp().run()
如果运行上述程序,我们已经可以看到有一个碰撞球在屏幕上来回滚动了。具体说明见注释。
第二步,为程序添加控制功能。# -*- coding: utf-8 -*-
from random import randint
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty #导入kivy属性
Builder.load_string('''
<PongGame>:
ball: pong_ball
player1: player_left #设定玩家1
player2: player_right #设定玩家2
canvas:
Rectangle:
pos: self.center_x - 5, 0
size: 10, self.height
Label:
font_size: 70
center_x: root.width / 4
top: root.top - 50
text: str(root.player1.score)
Label:
font_size: 70
center_x: root.width * 3 / 4
top: root.top - 50
text: str(root.player2.score)
PongBall:
id: pong_ball
center: self.parent.center
PongPaddle:
id: player_left
x: root.x
center_y: root.center_y
PongPaddle:
id: player_right
x: root.width - self.width
center_y: root.center_y
<PongBall>:
size: 50, 50
canvas:
Ellipse:
pos: self.pos
size: self.size
<PongPaddle>:
size: 25, 200
canvas:
Rectangle:
pos: self.pos
size: self.size
''')
class PongGame(Widget):
ball = ObjectProperty(None) #声明ball是Object对象,这点与通常的python动态语言不同,通常python语言是不需要声明的。
def update(self, dt):
self.ball.move()
self.player1.bounce_ball(self.ball)
self.player2.bounce_ball(self.ball)
if self.ball.y<0 or self.ball.top>self.height: #纵向碰壁反弹
self.ball.velocity_y *= -1
if self.ball.x<self.x:
self.player2.score += 1
self.serve_ball(vel=Vector((4,0)))
if self.ball.x>self.width:
self.player1.score += 1
self.serve_ball(vel=Vector((-4,0)))
def on_touch_move(self, touch): #设定滑动碰撞杆时的动作
if touch.x < self.width / 3:
self.player1.center_y = touch.y
if touch.x > self.width * 2 / 3:
self.player2.center_y = touch.y
def serve_ball(self, vel=Vector((4,0))): #发球
self.ball.center = self.center
self.ball.velocity = vel.rotate(randint(0,360)) #矢量合成并旋转任意角度
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x,velocity_y)
def move(self):
self.pos = Vector(*self.velocity) + self.pos #位置更新
class PongPaddle(Widget):
score = NumericProperty(0)
def bounce_ball(self, ball):
if self.collide_widget(ball): #碰撞判断
speedup = 1.1
vx, vy = ball.velocity
offset = (ball.center_y-self.center_y) / (self.height / 2)
bounced = Vector(-1*vx,vy) #Vector是kivy的一个矢量支持类,可以对矢量进行计算和旋转。
vel = bounced * speedup
ball.velocity = vel.x, vel.y+offset
class PongApp(App):
def build(self):
game = PongGame()
game.serve_ball()
Clock.schedule_interval(game.update, 1.0/60.0)
return game
if __name__ == '__main__':
PongApp().run()
再次运行程序,这样一个碰撞球小游戏已经可以正常运行了,拖动或点击左右两侧的滑杆可以控制滑杆的移动。
最后,我们再对这个小程序进行优化,添加背景图像、改变图形颜色和字体颜色等。
最终代码:# -*- coding: utf-8 -*-
from random import randint
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty #导入kivy属性
from kivy.uix.image import Image
from kivy.graphics import Color
Builder.load_string('''
<PongGame>:
ball: pong_ball #通过id引用PongBall对象
player1: player_left
player2: player_right
canvas.before:
BorderImage:
source: 'images.jpg'
pos: self.pos
size: self.size
canvas.after:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.center_x - 5, 0
size: 10, self.height
Label:
font_size: 70
color: 1,0,0,1
center_x: root.width / 4
top: root.top - 50
text: str(root.player1.score)
Label:
font_size: 70
color: 1,0,0,1
center_x: root.width * 3 / 4
top: root.top - 50
text: str(root.player2.score)
PongBall:
id: pong_ball
center: self.parent.center
PongPaddle:
id: player_left
x: root.x
center_y: root.center_y
PongPaddle:
id: player_right
x: root.width - self.width
center_y: root.center_y
<PongBall>:
size: 50, 50
canvas:
Color:
rgba: 0,0,1,1
Ellipse:
pos: self.pos
size: self.size
<PongPaddle>:
size: 25, 200
canvas:
Color:
rgba: 1,1,0,1
Rectangle:
pos: self.pos
size: self.size
''')
class PongGame(Widget):
ball = ObjectProperty(None) #声明ball是Object对象,这点与通常的python动态语言不同,通常python语言是不需要声明的。
def update(self, dt):
self.ball.move()
self.player1.bounce_ball(self.ball)
self.player2.bounce_ball(self.ball)
if self.ball.y<0 or self.ball.top>self.height: #纵向碰壁反弹
self.ball.velocity_y *= -1
if self.ball.x<self.x:
self.player2.score += 1
self.serve_ball(vel=Vector((4,0)))
if self.ball.x>self.width:
self.player1.score += 1
self.serve_ball(vel=Vector((-4,0)))
def on_touch_move(self, touch):
if touch.x < self.width / 3:
self.player1.center_y = touch.y
if touch.x > self.width * 2 / 3:
self.player2.center_y = touch.y
def serve_ball(self, vel=Vector((4,0))): #发球
self.ball.center = self.center
self.ball.velocity = vel.rotate(randint(0,360)) #矢量合成并旋转任意角度
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x,velocity_y)
def move(self):
self.pos = Vector(*self.velocity) + self.pos #位置更新
class PongPaddle(Widget):
score = NumericProperty(0)
def bounce_ball(self, ball):
if self.collide_widget(ball):
speedup = 1.1
vx, vy = ball.velocity
offset = (ball.center_y-self.center_y) / (self.height / 2)
bounced = Vector(-1*vx,vy)
vel = bounced * speedup
ball.velocity = Vector(vel.x, vel.y+offset).rotate(randint(-90,90))
class PongApp(App):
def build(self):
game = PongGame()
game.serve_ball()
Clock.schedule_interval(game.update, 1.0/60.0)
return game
if __name__ == '__main__':
PongApp().run()
|
|