Coding jump for a 2d Python game

Started by
2 comments, last by sandorlev 11 years, 8 months ago
Hello forum!

I've recently started writing a 2d platformer in Python, using pyGame. It is based heavily on this tutorial, which means it is built by the MVC design. Now I managed to load spritesheets and make my character move around, but I have no idea of how to make it jump. I've been trying all day with no result. I coded it the way I did because I want it to be easily turned into an online game. I would really appreciate some pointers. Below, there is the code for movement, just so you can see how it works.

events.py

class AvatarMoveRequest(Request):
def __init__(self, vector):
self.name = 'Avatar Move'
self.vector = vector

...

class AvatarMoveEvent(Event):
def __init__(self, avatar):
self.name = 'Avatar Move'
self.avatar = avatar

...

class EventManager:
def __init__(self):
from weakref import WeakKeyDictionary
self.listeners = WeakKeyDictionary()
self.eventQueue = []
def RegisterListener(self, listener):
self.listeners[listener] = 1
def UnregisterListener(self, listener):
if listener in self.listeners.keys():
del self.listeners[listener]
def Post(self, event):
#if not isinstance(event, TickEvent):
# utility.Debug('\tMessage: %s' % event)
if isinstance(event, AvatarJumpRequest) or\
isinstance(event, AvatarJumpEvent):
utility.Debug('\t%s' % event)
for listener in self.listeners.keys():
listener.Notify(event)


control.py

class KeyboardController:
def __init__(self, evManager):
self.evManager = evManager
self.evManager.RegisterListener(self)
def Notify(self, event):
if isinstance(event, events.TickEvent):
for event in pygame.event.get():
if event.type == QUIT:
ev = events.QuitEvent()
self.evManager.Post(ev)
key = pygame.key.get_pressed()
# Horizontal movement
direction = (key[K_RIGHT] - key[K_LEFT])
if direction:
vector = utility.Vec2d(
utility.settings['SPEED'], 0
)
ev = events.AvatarMoveRequest(vector * direction)
self.evManager.Post(ev)


avatar.py

class Avatar:
...
def Move(self, vector):
if self.state == Avatar.STATE_INACTIVE:
return
if (self.rect.x + vector.x) <= 0:
self.rect.x = 0
elif (self.rect.x + vector.x) >= (utility.settings['WIDTH'] - 28):
self.rect.x = (utility.settings['WIDTH'] - 28)
else:
self.rect.x += vector.x
ev = events.AvatarMoveEvent(self)
self.evManager.Post(ev)
self.vector = vector
def Notify(self, event):

elif isinstance(event, events.AvatarMoveRequest):
self.Move(event.vector)


view.py

import pygame
from pygame.locals import *
import events
import utility
import sprite
class PygameView:
def __init__(self, evManager):
self.evManager = evManager
self.evManager.RegisterListener(self)
# Display
pygame.init()
self.window = pygame.display.set_mode(
(utility.settings['WIDTH'], utility.settings['HEIGHT']), 0, 32
)
pygame.display.set_caption('game')
self.background = pygame.Surface(self.window.get_size())
self.background.fill((255, 255, 255))
self.window.blit(self.background, (0, 0))
pygame.display.flip()
self.backSprites = pygame.sprite.RenderUpdates()
self.frontSprites = pygame.sprite.RenderUpdates()
def MoveAvatar(self, avatar):
avatarSprite = self.GetAvatarSprite(avatar)
if avatar.vector.x < 0:
avatarSprite.Update(pygame.time.get_ticks(), True)
else:
avatarSprite.Update(pygame.time.get_ticks())
avatarSprite.rect = avatar.rect
def GetAvatarSprite(self, avatar):
for s in self.frontSprites:
return s
return None
def Notify(self, event):
if isinstance(event, events.TickEvent):
self.background.fill((255, 255, 255))
for s in self.frontSprites:
self.background.blit(s.image, (s.rect.x, s.rect.y))
self.window.blit(self.background, (0, 0))
pygame.display.flip()
elif isinstance(event, events.AvatarMoveEvent):
self.MoveAvatar(event.avatar)


Thanks for reading, I hope you can help!
Advertisement
This is dummy code, but this should get you a good idea of jumping ... remember to apply gravity affects also

If (key_pressed == up and sprite_not_in_air() ):
sprite_Y = getY() + 10

if(key_pressed == right ):
sprite_X = getX() + 5
elseif(key_pressed == left ):
sprite_X = getX() - 5


Edit: changed dummy code for clarity

I cannot remember the books I've read any more than the meals I have eaten; even so, they have made me.

~ Ralph Waldo Emerson

I would suggest something different from what Shippou suggests. You should test the keys independently, not test if key Up and Key Right. Also, you should be applying a velocity for movement, just just moving the sprite based on keys (which it seems you are doing from looking at the python code). I must admit, it's not the easiest to follow, but, of course, I don't know Python.

In another post, i gave some sample code (for C++) which shows, in general how you handle jumping. You should be able to get the gist of it form this code. The main points are:
#1, you can jump if you're on the ground and hit the jump key
#2, you apply an initial Negative Y velocity(which is up on the screen) once when jumping, and then subtract from the velocity every frame (to simulate gravity).
#3, if you hit anything in the Y direction (your head or your feet), reset the location, and set Y velocity to 0.

Good Luck!
(#define values are just guessed examples, you'll have to change them to fit your game)

// Speed player moves left or right
#define MOVEMENT_SPEED 10.0f
// initial velocity given to player when he jumps
#define JUMP_VELOCITY 20.0f
void Player::HandleInput()
{
if (LeftIsPressed()) {
this.xVelocity = -MOVEMENT_SPEED;
}
else if (RightIsPressed()) {
this.xVelocity = MOVEMENT_SPEED;
else {
this.xVelocity = 0.0f;
}
// Only jump if we're not already jumping or falling
if (JumpIsPressed() && this.OnGround) {
this.yVelocity = -JUMP_VELOCITY;
}
}
// defines amount to increase downward velocity every frame
#define GRAVITY_FORCE 4.0f
void Player::Update()
{
// Apply downward force to player
this.yVelocity += GRAVITY_FORCE;
// Move the Player
this.xLocation += this.xVelocity;
this.yLocation += this.yVelocity;
// Check we've collide with something above or below us
bool CollideBelow;
if (CheckCollisionY(CollideBelow)) {
// move us back to previous location and Stop Y Velocity
this.yLocation -= this.yVelocity;
this.yVelocity = 0.0f;
if (CollideBelow) {
this.OnGround = true;
}
}
else {
this.OnGround = false;
}
// Check if we've collided with anything on our left or right
if (CheckCollisionX()) {
// move us back to previous location and Stop X Velocity
this.xLocation -= this.xVelocity;
this.xVelocity = 0.0f;
}
}

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)


I would suggest something different from what Shippou suggests. You should test the keys independently, not test if key Up and Key Right. Also, you should be applying a velocity for movement, just just moving the sprite based on keys (which it seems you are doing from looking at the python code). I must admit, it's not the easiest to follow, but, of course, I don't know Python.

In another post, i gave some sample code (for C++) which shows, in general how you handle jumping. You should be able to get the gist of it form this code. The main points are:
#1, you can jump if you're on the ground and hit the jump key
#2, you apply an initial Negative Y velocity(which is up on the screen) once when jumping, and then subtract from the velocity every frame (to simulate gravity).
#3, if you hit anything in the Y direction (your head or your feet), reset the location, and set Y velocity to 0.

Good Luck!
(#define values are just guessed examples, you'll have to change them to fit your game)

// Speed player moves left or right
#define MOVEMENT_SPEED 10.0f
// initial velocity given to player when he jumps
#define JUMP_VELOCITY 20.0f
void Player::HandleInput()
{
if (LeftIsPressed()) {
this.xVelocity = -MOVEMENT_SPEED;
}
else if (RightIsPressed()) {
this.xVelocity = MOVEMENT_SPEED;
else {
this.xVelocity = 0.0f;
}
// Only jump if we're not already jumping or falling
if (JumpIsPressed() && this.OnGround) {
this.yVelocity = -JUMP_VELOCITY;
}
}
// defines amount to increase downward velocity every frame
#define GRAVITY_FORCE 4.0f
void Player::Update()
{
// Apply downward force to player
this.yVelocity += GRAVITY_FORCE;
// Move the Player
this.xLocation += this.xVelocity;
this.yLocation += this.yVelocity;
// Check we've collide with something above or below us
bool CollideBelow;
if (CheckCollisionY(CollideBelow)) {
// move us back to previous location and Stop Y Velocity
this.yLocation -= this.yVelocity;
this.yVelocity = 0.0f;
if (CollideBelow) {
this.OnGround = true;
}
}
else {
this.OnGround = false;
}
// Check if we've collided with anything on our left or right
if (CheckCollisionX()) {
// move us back to previous location and Stop X Velocity
this.xLocation -= this.xVelocity;
this.xVelocity = 0.0f;
}
}



Although it was hardly what I was asking for, your post made me feel hopeless so I started rewriting some code that disable me from getting the jumping done. ~1.5 hours later, here I am, having a perfectly functioning jumping and moving system, so thank you! :)

This topic is closed to new replies.

Advertisement