Sign in to follow this  
sandorlev

Coding jump for a 2d Python game

Recommended Posts

Hello forum!

I've recently started writing a 2d platformer in Python, using pyGame. It is based heavily on [url="http://ezide.com/games/writing-games.html"]this tutorial[/url], 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
[CODE]
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)
[/CODE]

control.py
[CODE]
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)
[/CODE]

avatar.py
[CODE]
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)
[/CODE]

view.py
[CODE]
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)
[/CODE]

Thanks for reading, I hope you can help!

Share this post


Link to post
Share on other sites
This is [b]dummy code[/b], but this should get you a good idea of jumping ... remember to apply gravity affects also
[code]
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[/code]

Edit: changed dummy code for clarity Edited by Shippou

Share this post


Link to post
Share on other sites
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)
[code]
// 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;
}
}
[/code]

Share this post


Link to post
Share on other sites
[quote name='BeerNutts' timestamp='1344373635' post='4967145']
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)
[code]
// 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;
}
}
[/code]
[/quote]

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! :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this