前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在Python游戏中模拟重力

在Python游戏中模拟重力

作者头像
五月Rambo
修改2019-12-09 15:11:03
2K0
修改2019-12-09 15:11:03
举报
文章被收录于专栏:Opensource翻译专栏

一起来学习如何使用Python的Pygame模块来对游戏进行编程并操纵重力。

我们的现实生活中充满了运动和生命。物理让我们的世界变得如此繁忙和生动。 同时我们要知道,物理阐释了物质在空间中移动的方式。 不过呢,因为我们的游戏世界本不存在物理,所以作为游戏程序员,我们必须在游戏中模拟物理。

对于大多数游戏而言,我们基本上关注的是两种物理现象:重力和碰撞。

你在向游戏中添加敌方目标时,通常会实现一些碰撞检测,但是由于重力同样涉及到碰撞检测,因此本文会对此作出更多解释。 让我们来思考一下,为什么重力会涉及到碰撞呢?如果你还没有头绪,也没关系,我们处理示例代码时,这个问题会很清晰明了。

现实中重力的本质是物体相互吸引的一个过程。物体越大,其重力也就越大。在游戏物理学中,您不必为了证明引力的合理性而去相应地去创建一个质量数据; 您只需编程一种趋势,就可以让物体掉落到游戏世界中最大的物体:世界。

添加重力函数

请记住,您的Player已经具有确定运动的属性。 使用此属性将播放器拉向屏幕底部。

在Pygame中,较高的数字更靠近屏幕的底部边缘。

在现实世界中,重力会影响所有物体。 但在游戏中,重力是有选择的——如果你将重力添加到整个游戏世界中,则所有物体都会掉落到地面。 相反,你也可以仅将重力添加到玩家和敌人上.

首先,在您的Player选项中添加重力功能:

代码语言:javascript
复制
 def gravity(self):
 self.movey += 3.2 # how fast player falls

这是一个基本的功能。 首先,无论玩家是否要运动,都将其设置为垂直运动。 换句话说,你已将玩家编程为始终处于下降状态—— 这基本上是重力的基础。

为了使重力函数起作用,我们必须在主循环中调用它。 这样,Python每个时间点都会向玩家施加一次下降运动。

这段代码,将第一行添加到循环中:

代码语言:javascript
复制
    player.gravity() # check gravity
    player.update()

启动游戏,看看会发生什么。 看起来很突然,因为它发生得很快:您的玩家从游戏屏幕掉向了天空。

这说明你的重力模拟生效了,不过好像效果好过了头。

后续调试中,你可以更改玩家下降的速率。

添加地面

角色之所以会掉出世界,是因为游戏无法检测到他。 在某些游戏中,如果玩家掉没了,角色将被删除并在出生点重新生成。 在有些其他游戏中,玩家会失去分数或生命。 无论如何当角色掉出世界的时候,你必须用某种方法来检测角色是否掉出了屏幕之外。

在Python中,要检完成这类检测,可以使用if语句。

您必须检查查看您的玩家是否掉落以及掉了多远。如果您的玩家跌落到可以到达屏幕底部的程度,则可以执行某些操作。 为简单起见,请将玩家的位置设置为底部边缘上方20像素。

你的重力函数应该长这样。。:

代码语言:javascript
复制
 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 来使得目标弹跳得更高:

代码语言:javascript
复制
 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

现在您的玩家会在屏幕底部的地面开始弹跳了。

玩家需要一种对抗重力的方法。问题的核心在于。除非你有什么东西可以使力,否则你无法对抗重力。因此,在下一篇文章中,你可以添加地面和平台碰撞以及跳跃的能力。同时,尝试对敌人的目标施加重力。

这是到目前为止的所有代码:

代码语言:javascript
复制
#!/usr/bin/env python3
# draw a world
# add a player and player control
# add player movement
# add enemy and basic collision
# add platform
# add gravity

# GNU All-Permissive License
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.  This file is offered as-is,
# without any warranty.

import pygame
import sys
import os

'''
Objects
'''

class Platform(pygame.sprite.Sprite):
 # x location, y location, img width, img height, img file    
 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.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.score = 1
 self.images = []
 for i in range(1,9):
            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 # how fast player falls
 
 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 > ani*3:
 self.frame = 0
 self.image = self.images[self.frame//ani]

 # moving right
 if self.movex > 0:
 self.frame += 1
 if self.frame > ani*3:
 self.frame = 0
 self.image = self.images[(self.frame//ani)+4]

 # collisions
        enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
 for enemy in enemy_hit_list:
 self.health -= 1
 print(self.health)

        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
 for g in ground_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 bad(lvl,eloc):
 if lvl == 1:
            enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
            enemy_list = pygame.sprite.Group() # create enemy group
            enemy_list.add(enemy) # add enemy to group
 
 if lvl == 2:
 print("Level " + str(lvl) )

 return enemy_list

 def loot(lvl,lloc):
 print(lvl)

 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,'ground.png')
                ground_list.add(ground)
                i=i+1

 if lvl == 2:
 print("Level " + str(lvl) )

 return ground_list

 def platform(lvl,tx,ty):
        plat_list = pygame.sprite.Group()
        ploc = []
        i=0
 if lvl == 1:
            ploc.append((0,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,'ground.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
'''
worldx = 960
worldy = 720

fps = 40 # frame rate
ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True

BLUE  = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)

world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move

eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size

i=0
while i <= (worldx/tx)+tx:
    gloc.append(i*tx)
    i=i+1

enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )

'''
Main loop
'''
while main == True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
            pygame.quit(); sys.exit()
            main = False

 if event.type == pygame.KEYDOWN:
 if event.key == pygame.K_LEFT or event.key == ord('a'):
 print("LEFT")
                player.control(-steps,0)
 if event.key == pygame.K_RIGHT or event.key == ord('d'):
 print("RIGHT")
                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)
 if event.key == pygame.K_UP or event.key == ord('w'):
 print('jump')

 if event.key == ord('q'):
                pygame.quit()
 sys.exit()
                main = False

    world.blit(backdrop, backdropbox)
    player.gravity() # check 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)

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 添加重力函数
  • 添加地面
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档