python编程学习-玛丽跳跳跳
学习python编程,在新东方少儿编程官网的自由创作平台做的一些作品。
可以在线运行,效果如下(在新页面中打开链接):
代码如下(用到平台自定义的xdf库):
from xdf import *
import math
TIME_SCALE = 1.5
GROUND_Y = 800
SCREEN_W = 768
SCREEN_H = 1024
GRAVITY = 1.0 * TIME_SCALE
AREA_RECT = "rect"
AREA_CIRCLE = "circle"
def rad2ang(rad):
return 180 * rad / math.pi
def ang2rad(ang):
return math.pi * ang / 180
class Mario:
def __init__(self, positionX, positionY):
self.g = GRAVITY
self.groundY = GROUND_Y
self.positionX = positionX
self.positionY = positionY
self.x = 0
self.y = 0
self.vx = 0
self.vy = 0
self.maxV = 6 * TIME_SCALE
self.jumpForce = 20.0 * TIME_SCALE
self.ax = 1.0 * TIME_SCALE
self.ux = 0.05
self.uy = 0.05
self.key = {}
self.isDie = False
self.godMode = False
self.bulletMode = False
self.clearanceMode = False
self.width = 32
self.height = 54
self.currentFrame = 0
self.scaleX = 1
self.isPlaying = True
self.starCount = 0
self.hitArea = [
AREA_RECT,
self.x - self.width / 2,
self.y - self.height,
self.width,
self.height
]
#
self.frames = ["mario001@001n", "mario002@001o", "mario003@001m", "mario002@001o", "mario004@001t"]
self.totalFrames = len(self.frames)
self.sp = stamp(self.frames[0])
self.sp.size(self.height)
#
self.lastFrame = 0
self.lastScaleX = 1
#
self.reset()
pass
def updateHitArea(self):
self.hitArea[1] = self.x - self.width / 2
self.hitArea[2] = self.y - self.height
pass
def reset(self):
self.starCount = 0
self.isDie = False
self.godMode = False
self.scaleX = 1
self.x = self.positionX
self.y = self.positionY
self.gotoAndStop(0)
pass
def refresh(self):
if self.isPlaying:
self.currentFrame += 1
if self.currentFrame == self.totalFrames:
self.currentFrame = 0
elif self.currentFrame == 4:
self.currentFrame = 0
if self.lastScaleX != self.scaleX:
self.lastScaleX = self.scaleX
self.sp.flip()
if self.lastFrame != self.currentFrame:
self.lastFrame = self.currentFrame
self.sp.change(self.frames[self.currentFrame])
self.sp.move(self.x, self.y - self.height / 2)
self.sp.front()
if self.starCount > 0:
self.starCount -= 1
if self.starCount % 5 == 3:
self.sp.hide()
else:
self.sp.show()
if self.starCount == 0:
self.godMode = False
pass
def gotoAndStop(self, frame):
self.currentFrame = frame
self.isPlaying = False
pass
def play(self):
self.isPlaying = True
pass
def keyDown(self, code, key):
self.key[code] = True
pass
def keyUp(self, code, key):
self.key[code] = False
pass
def update(self):
if self.isDie:
if self.y > 100:
self.y -= 50
else:
self.move()
pass
def move(self):
self.checkKey()
# 更新速度
if abs(self.vx) < 1:
self.vx = 0
else:
self.vx -= self.vx * self.ux
if self.y + self.vy + self.g - self.vy * self.uy > self.groundY:
self.y = self.groundY
self.vy = 0
else:
self.vy += self.g - self.vy * self.uy
# 更新位置
if self.x + self.vx > 0 and self.x + self.vx < 768:
self.x += self.vx
self.y += self.vy
# 人物的动画效果
if self.y < self.groundY:
self.gotoAndStop(2)
elif self.vx != 0:
if self.vx < 0:
self.scaleX = -1
else:
self.scaleX = 1
self.play()
else:
if self.currentFrame == 2:
self.gotoAndStop(0)
pass
def checkKey(self):
for i in self.key:
if self.key[i]:
if i == 39:
if self.vx < self.maxV:
self.vx += self.ax
elif i == 37:
if self.vx > -self.maxV:
self.vx -= self.ax
elif i == 38:
if self.y == self.groundY:
self.vy = -self.jumpForce * (1 + self.vx * self.vx * 0.003)
pass
def die(self):
self.isDie = True
self.gotoAndStop(4)
pass
def setGodMode(self, mode):
self.godMode = mode
self.starCount = 100
pass
pass
class Ball:
def __init__(self):
self.groundY = GROUND_Y
self.g = GRAVITY
self.x = 0
self.y = 0
self.vx = 0
self.vy = 0
self.r = 30
self.rotation = 0
self.isDie = False
self.color = "red"
self.score = 1
self.moveMode = Ball.RIGHT2LEFT
self.ballMode = Ball.NORMAL
self.jumpMode = Ball.HAVELOSS
self.hitArea = [
AREA_CIRCLE,
self.x,
self.y,
self.r
]
#
self.circle = circle(0, 0, self.r, self.color)
self.sp = stamp("face001@001r")
#
self.reset()
pass
def updateHitArea(self):
self.hitArea[1] = self.x
self.hitArea[2] = self.y
self.hitArea[3] = self.r
pass
def reset(self):
self.score = 1
self.isDie = False
self.moveMode = Ball.RIGHT2LEFT
self.ballMode = Ball.NORMAL
self.vx = (-random(300) / 100 - 3) * TIME_SCALE
self.vy = 0
self.x = SCREEN_W + self.r
self.y = self.groundY - 180 - random(self.r * 2)
a = random(len(Ball.COLORS))-1
self.color = Ball.COLORS[a]
self.circle.change(self.color)
if random(100) > 95:
self.setBallMode(Ball.BIG)
self.setMoveMode(Ball.LEFT2RIGHT)
pass
def update(self):
self.rolling()
self.x += self.vx
if self.jumpMode == Ball.HAVELOSS:
self.vy += self.g
self.y += self.vy
else:
self.y += self.vy
self.vy += self.g
pass
if self.y >= self.groundY - self.r:
self.y = self.groundY - self.r
self.vy *= -1
if self.x < -self.r * 2 - 10 or self.x > SCREEN_W + self.r * 2:
self.die()
pass
pass
def refresh(self):
self.sp.size(self.r)
self.sp.move(self.x, self.y)
self.sp.rotate(self.rotation)
self.circle.size(self.r)
self.circle.move(self.x, self.y)
if self.isDie:
self.sp.hide()
self.circle.hide()
else:
self.sp.show()
self.circle.show()
pass
def die(self):
self.isDie = True
pass
def rolling(self):
self.rotation += rad2ang(self.vx / self.r)
pass
def setMoveMode(self, dr):
if dr == Ball.LEFT2RIGHT:
self.moveMode = Ball.LEFT2RIGHT
self.x = -self.r
self.vx = -self.vx
pass
def setBallMode(self, mode):
if mode == Ball.BIG:
self.score = 2
self.ballMode = Ball.BIG
self.r = 90
self.y = self.groundY - self.r
pass
pass
Ball.COLORS = ["red", "green", "blue", "yellow", "aqua", "fuchsia"]
Ball.RIGHT2LEFT = 1
Ball.LEFT2RIGHT = -1
Ball.NORMAL = "normal"
Ball.BIG = "big"
Ball.HAVELOSS = "haveLoss"
Ball.NOLOSS = "noLoss"
class Star:
def __init__(self):
self.groundY = GROUND_Y
self.g = GRAVITY
self.x = 0
self.y = 0
self.vx = 0
self.vy = 0
self.r = 25
self.rotation = 0
self.isDie = False
self.starCount = 0
self.score = 2
self.hitArea = [
AREA_CIRCLE,
self.x,
self.y,
self.r
]
#
self.sp = stamp("star001@001p")
#
self.reset()
pass
def updateHitArea(self):
self.hitArea[1] = self.x
self.hitArea[2] = self.y
self.hitArea[3] = self.r
pass
def reset(self):
self.isDie = False
self.starCount = 0
self.vx = (-random(300) / 100 - 3) * TIME_SCALE
self.vy = 0
self.x = SCREEN_W + self.r
self.y = self.groundY - random(self.r * 2) - 180
pass
def update(self):
self.rolling()
self.x += self.vx
self.vy += self.g
self.y += self.vy
if self.y >= self.groundY - self.r:
self.y = self.groundY - self.r
self.vy *= -1
if self.x < -self.r * 2 - 10 or self.x > SCREEN_W + self.r * 2:
self.die()
pass
pass
def refresh(self):
self.sp.size(self.r * 2)
self.sp.move(self.x, self.y)
self.sp.rotate(self.rotation)
self.starCount += 1
if self.isDie or self.starCount % 5 == 0:
self.sp.hide()
else:
self.sp.show()
pass
def die(self):
self.isDie = True
pass
def rolling(self):
self.rotation += rad2ang(self.vx / self.r)
pass
pass
class Mushroom:
def __init__(self, name = "mogu001@001s", size = 50):
self.vx = 0
self.score = 1
self.x = 0
self.y = 0
self.isDie = False
self.height = self.width = size
self.hitArea = [
AREA_RECT,
self.x - self.width / 2,
self.y - self.height,
self.width,
self.height
]
#
self.sp = stamp(name)
self.sp.size(self.width)
#
self.reset()
pass
def updateHitArea(self):
self.hitArea[1] = self.x - self.width / 2
self.hitArea[2] = self.y - self.height
pass
def reset(self):
self.isDie = False
self.vx = (random(300) / 100 - 5) * TIME_SCALE
self.x = SCREEN_W
self.y = GROUND_Y
pass
def refresh(self):
self.sp.move(self.x, self.y - self.height / 2)
if self.isDie:
self.sp.hide()
else:
self.sp.show()
pass
def update(self):
self.x += self.vx
if self.x < -20:
self.die()
pass
def die(self):
self.isDie =True
pass
pass
def getSp(Cla):
for sp in spPool:
if isinstance(sp, Cla):
spPool.remove(sp)
sp.reset()
return sp
return Cla()
def addMc(Cla):
mc = getSp(Cla)
addChild(mc)
pass
def addChild(sp):
spArr.append(sp)
def hitRectCircle(rec, cir):
rec2 = [
rec[0] + rec[2] / 2 - cir[0],
rec[1] + rec[3] / 2 - cir[1],
cir[2] + rec[2] / 2,
cir[2] + rec[3] / 2
]
if rec2[0] <= rec2[2] and rec2[0] >= -rec2[2] and rec2[1] <= rec2[3] and rec2[1] >= -rec2[3]:
return True
dx = min(abs(cir[0] - rec[0]), abs(cir[0] - rec[0] - rec[2]))
dy = min(abs(cir[1] - rec[1]), abs(cir[1] - rec[1] - rec[3]))
return dx * dx + dy * dy <= cir[2] * cir[2]
def hitRectRect(rec1, rec2):
return rec1[0] <= rec2[0] + rec2[2] and rec1[0] + rec1[2] >= rec2[0] and rec1[1] <= rec2[1] + rec2[3] and rec1[1] + rec1[3] >= rec2[1]
def checkHit(area0, area1):
if area0[0] == AREA_RECT and area1[0] == AREA_CIRCLE:
return hitRectCircle(area0[1:], area1[1:])
if area0[0] == AREA_CIRCLE and area1[0] == AREA_RECT:
return hitRectCircle(area1[1:], area0[1:])
if area0[0] == AREA_RECT and area1[0] == AREA_RECT:
return hitRectRect(area0[1:], area1[1:])
return False
def checkCollision():
global score
for sp in spArr:
sp.updateHitArea()
for sp in spArr:
if not mario.isDie and not sp.isDie and sp != mario:
if checkHit(mario.hitArea, sp.hitArea):
sp.die()
score += sp.score
if isinstance(sp, Ball):
if not mario.godMode:
mario.die()
elif isinstance(sp, Mushroom):
pass
elif isinstance(sp, Star):
mario.setGodMode(True)
pass
pass
pass
def addMcs():
global N
N += 1
if N % 60 == 0:
addMc(Ball)
if N % 100 == 0:
addMc(Mushroom)
if N % 200 == 0:
addMc(Star)
pass
def removeDie():
i = len(spArr) - 1
while i >= 0:
sp = spArr[i]
if sp.isDie and not isinstance(sp, Mario):
spPool.append(sp)
spArr.pop(i)
i -= 1
def reset():
global score, N
N = 0
score = 0
gameOverTf.hide()
for sp in spArr:
sp.die()
mario.reset()
pass
def keydown(code, key):
mario.keyDown(code, key)
pass
def keyup(code, key):
mario.keyUp(code, key)
pass
def tap():
if mario.isDie:
reset()
def loop():
for sp in spArr:
sp.update()
#
if not mario.isDie:
addMcs()
checkCollision()
gameOverTf.hide()
else:
gameOverTf.show()
#
for sp in spArr:
sp.refresh()
#
removeDie()
#
global score
scoreTf.change("得分:" + str(score))
pass
ground = box(0, GROUND_Y, SCREEN_W, SCREEN_H - GROUND_Y, "blue")
mario = Mario(200, 100)
spArr = [mario]
spPool = []
score = 0
scoreTf = text("得分:0", 0, 50, 50, "red")
gameOverTf = text("Game Over", 100, "red", "center")
N = 0
也可以下载代码,本地python环境运行(用pygame封装了xdf库)。