15
2024
11

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库)。



« 上一篇下一篇 »

相关文章:

python编程学习-翻滚的方块  (2024-11-15 11:37:10)

python编程学习-汉诺塔  (2024-11-15 11:36:16)

python编程学习-模拟键盘按键  (2024-11-15 11:35:50)

python编程学习-显示帧频  (2024-11-15 11:35:26)

python编程学习-收不完的西瓜  (2024-11-15 11:35:0)

python编程学习-推箱子  (2024-11-15 11:34:1)

python编程学习-拼图  (2024-11-15 11:33:25)

python编程学习-扫雷  (2024-11-15 11:32:58)

python编程学习-小学数学加减分解题  (2024-11-15 11:32:29)

python编程学习-对角棋  (2024-11-15 11:32:8)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。