现实世界充满了运动和生命。使现实世界如此繁忙和动态的原因是物理学。物理学是物质在空间中运动的方式。由于视频游戏世界没有物质,它也没有物理学,因此游戏程序员必须模拟物理学。
对于大多数视频游戏而言,基本上只有两个重要的物理方面:重力和碰撞。
当您向游戏中添加敌人时,您已经实现了一些碰撞检测,但本文添加了更多内容,因为重力需要碰撞检测。思考一下为什么重力可能涉及碰撞。如果您想不出任何理由,请不要担心——当您完成示例代码时,它会变得显而易见。
现实世界中的重力是具有质量的物体相互吸引的趋势。物体越大,它施加的引力影响就越大。在视频游戏物理学中,您不必创建质量大到足以证明引力是合理的物体;您只需对物体编程,使其具有向视频游戏世界中假定最大的物体(世界本身)坠落的趋势。
添加重力函数
请记住,您的玩家已经有一个属性来确定运动。使用此属性将玩家精灵拉向屏幕底部。
在 Pygame 中,数字越大,越靠近屏幕底部边缘。
在现实世界中,重力影响一切。然而,在平台游戏中,重力是选择性的——如果您将重力添加到整个游戏世界,您的所有平台都会掉到地面上。相反,您只需将重力添加到玩家和敌人精灵。
首先,在您的 Player 类中添加一个 gravity 函数
def gravity(self):
self.movey += 3.2 # how fast player falls
这是一个简单的函数。首先,您将玩家设置为垂直运动,无论您的玩家是否想要运动。换句话说,您已将玩家编程为始终处于坠落状态。这基本上就是重力。
为了使重力函数生效,您必须在主循环中调用它。这样,Python 每隔一个时钟周期将坠落运动应用于您的玩家一次。
在此代码中,将第一行添加到您的循环中
player.gravity() # check gravity
player.update()
启动您的游戏以查看会发生什么。注意观察,因为它发生得很快:您的玩家从空中掉下来,直接掉出您的游戏屏幕。
您的重力模拟正在工作,但可能太好了。
作为实验,尝试更改玩家坠落的速度。
为重力添加地板
您的角色从世界中掉落的问题在于您的游戏无法检测到它。在某些游戏中,如果玩家从世界中掉落,精灵将被删除并在新的地方重生。在其他游戏中,玩家会失去积分或生命。无论您希望在玩家从世界中掉落时发生什么,您都必须能够检测到玩家何时消失在屏幕外。
在 Python 中,要检查条件,您可以使用 if 语句。
您必须检查if您的玩家是否正在坠落以及您的玩家坠落了多远。如果您的玩家坠落得太远以至于到达屏幕底部,那么您可以做某些事情。为了保持简单,将玩家精灵的位置设置为屏幕底部边缘上方 20 像素。
使您的 gravity 函数看起来像这样
def gravity(self):
self.movey += 3.2 # how fast player falls
if self.rect.y > worldy and self.movey >= 0:
self.movey = 0
self.rect.y = worldy-ty
然后启动您的游戏。您的精灵仍然会坠落,但它会在屏幕底部停止。您可能无法看到地面图层后面的精灵。一个简单的解决方法是通过在精灵击中游戏世界底部后在其新的 Y 位置添加另一个 -ty 来使您的玩家精灵弹得更高
def gravity(self):
self.movey += 3.2 # how fast player falls
if self.rect.y > worldy and self.movey >= 0:
self.movey = 0
self.rect.y = worldy-ty-ty
现在您的玩家在屏幕底部弹跳,就在您的地面精灵后面。
您的玩家真正需要的是一种对抗重力的方法。重力的问题在于,除非您有可以推开的东西,否则您无法对抗它。因此,在下一篇文章中,您将添加地面和平台碰撞以及跳跃能力。 在此期间,尝试将重力应用于敌人精灵。
这是到目前为止的所有代码
#!/usr/bin/env python3
# by Seth Kenlon
# GPLv3
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://gnu.ac.cn/licenses/>.
import pygame
import sys
import os
'''
Variables
'''
worldx = 960
worldy = 720
fps = 40
ani = 4
world = pygame.display.set_mode([worldx, worldy])
BLUE = (25, 25, 200)
BLACK = (23, 23, 23)
WHITE = (254, 254, 254)
ALPHA = (0, 255, 0)
'''
Objects
'''
# x location, y location, img width, img height, img file
class Platform(pygame.sprite.Sprite):
def __init__(self, xloc, yloc, imgw, imgh, img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images', img)).convert()
self.image.convert_alpha()
self.image.set_colorkey(ALPHA)
self.rect = self.image.get_rect()
self.rect.y = yloc
self.rect.x = xloc
class Player(pygame.sprite.Sprite):
"""
Spawn a player
"""
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
self.images = []
for i in range(1, 5):
img = pygame.image.load(os.path.join('images', 'hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(ALPHA)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def gravity(self):
self.movey += 3.2
if self.rect.y > worldy and self.movey >= 0:
self.movey = 0
self.rect.y = worldy-ty-ty
def control(self, x, y):
"""
control player movement
"""
self.movex += x
self.movey += y
def update(self):
"""
Update sprite position
"""
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3 * ani:
self.frame = 0
self.image = pygame.transform.flip(self.images[self.frame // ani], True, False)
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3 * ani:
self.frame = 0
self.image = self.images[self.frame // ani]
hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
for enemy in hit_list:
self.health -= 1
print(self.health)
class Enemy(pygame.sprite.Sprite):
"""
Spawn an enemy
"""
def __init__(self, x, y, img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images', img))
self.image.convert_alpha()
self.image.set_colorkey(ALPHA)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.counter = 0
def move(self):
"""
enemy movement
"""
distance = 80
speed = 8
if self.counter >= 0 and self.counter <= distance:
self.rect.x += speed
elif self.counter >= distance and self.counter <= distance * 2:
self.rect.x -= speed
else:
self.counter = 0
self.counter += 1
class Level:
def ground(lvl, gloc, tx, ty):
ground_list = pygame.sprite.Group()
i = 0
if lvl == 1:
while i < len(gloc):
ground = Platform(gloc[i], worldy - ty, tx, ty, 'tile-ground.png')
ground_list.add(ground)
i = i + 1
if lvl == 2:
print("Level " + str(lvl))
return ground_list
def bad(lvl, eloc):
if lvl == 1:
enemy = Enemy(eloc[0], eloc[1], 'enemy.png')
enemy_list = pygame.sprite.Group()
enemy_list.add(enemy)
if lvl == 2:
print("Level " + str(lvl))
return enemy_list
# x location, y location, img width, img height, img file
def platform(lvl, tx, ty):
plat_list = pygame.sprite.Group()
ploc = []
i = 0
if lvl == 1:
ploc.append((200, worldy - ty - 128, 3))
ploc.append((300, worldy - ty - 256, 3))
ploc.append((500, worldy - ty - 128, 4))
while i < len(ploc):
j = 0
while j <= ploc[i][2]:
plat = Platform((ploc[i][0] + (j * tx)), ploc[i][1], tx, ty, 'tile.png')
plat_list.add(plat)
j = j + 1
print('run' + str(i) + str(ploc[i]))
i = i + 1
if lvl == 2:
print("Level " + str(lvl))
return plat_list
'''
Setup
'''
backdrop = pygame.image.load(os.path.join('images', 'stage.png'))
clock = pygame.time.Clock()
pygame.init()
backdropbox = world.get_rect()
main = True
player = Player() # spawn player
player.rect.x = 0 # go to x
player.rect.y = 30 # go to y
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10
eloc = []
eloc = [300, 0]
enemy_list = Level.bad(1, eloc)
gloc = []
tx = 64
ty = 64
i = 0
while i <= (worldx / tx) + tx:
gloc.append(i * tx)
i = i + 1
ground_list = Level.ground(1, gloc, tx, ty)
plat_list = Level.platform(1, tx, ty)
'''
Main Loop
'''
while main:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
try:
sys.exit()
finally:
main = False
if event.type == pygame.KEYDOWN:
if event.key == ord('q'):
pygame.quit()
try:
sys.exit()
finally:
main = False
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(-steps, 0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(steps, 0)
if event.key == pygame.K_UP or event.key == ord('w'):
print('jump')
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(steps, 0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(-steps, 0)
world.blit(backdrop, backdropbox)
player.gravity()
player.update()
player_list.draw(world)
enemy_list.draw(world)
ground_list.draw(world)
plat_list.draw(world)
for e in enemy_list:
e.move()
pygame.display.flip()
clock.tick(fps)
6 条评论