Here's part 5.5 (part 2 of part 5) for making Maze Crawl the game using Python in the BGE. Hey, so we left off looking at the source code for the Player.
So, here's the source code for the Player's function.
---- Bullet Physics Player Function ----
from bge import logic
from bge import events
def Sign(value):
if value > 0:
return 1
elif value < 0:
return -1
else:
return 0
def AxisCheck(mx, my, size = 1.0):
cont = logic.getCurrentController()
obj = cont.owner
pos = obj.position # Get the Player's current position
topos = pos.copy() # Make a copy of the Player's current position
topos.x += (Sign(mx) * size) + mx # Offset the copy by the movement value for the X-axis
topos.y += (Sign(my) * size) + my # And offset the copy by the movement value for the Y-axis
return obj.rayCast(topos, pos, 0, 'wall', 1, 1) # We may have just collided with something on the line specified
def Player():
cont = logic.getCurrentController()
obj = cont.owner
motion = cont.actuators['Motion']
key = logic.keyboard.events
kbleft = key[events.LEFTARROWKEY]
kbright = key[events.RIGHTARROWKEY]
kbup = key[events.UPARROWKEY]
kbdown = key[events.DOWNARROWKEY]
def Init():
if not 'init' in obj:
obj['init'] = 1
def Update():
movespd = 10.0
mx = 0.0
my = 0.0
if kbleft > 0:
mx = -movespd
elif kbright > 0:
mx = movespd
if kbup > 0:
my = movespd
elif kbdown > 0:
my = -movespd
motion.linV = [mx, my, 0.0]
cont.activate(motion)
Init()
Update()
As you can see, we don't use the AxisCheck functions anymore (they're commented out in the source code file) because the Bullet physics engine will handle collision. Bullet also handles the acceleration and movement functions - Bullet will make the Player gradually move up to top speed and control his movement angles. This is the upside of the Bullet engine - we don't have to worry about these things ourselves.
The downside is that we can't handle things like gravity locally - the physics engine will do it for us. We could get around it by using a motion actuator setting force equal to gravity (9.8 default) upwards to negate gravity's effect and then make any changes from there, but it's still a bit easier to just do this ourself. Let's take a look next at the custom Player function without Bullet physics enabled.
---- Custom Physics Player Function ----
from bge import logic
from bge import events
def Sign(value):
if value > 0:
return 1
elif value < 0:
return -1
else:
return 0
def Clamp(value, min, max):
if value > max:
return max
elif value < min:
return min
else:
return value
def AxisCheck(mx, my, size = 1.0):
cont = logic.getCurrentController()
obj = cont.owner
pos = obj.position # Get the Player's current position
topos = pos.copy() # Make a copy of the Player's current position
topos.x += (Sign(mx) * size) + mx # Offset the copy by the movement value for the X-axis
topos.y += (Sign(my) * size) + my # And offset the copy by the movement value for the Y-axis
return obj.rayCast(topos, pos, 0, 'wall', 1, 1) # We may have just collided with something on the line specified
def Player():
cont = logic.getCurrentController()
obj = cont.owner
motion = cont.actuators['Motion']
key = logic.keyboard.events
kbleft = key[events.LEFTARROWKEY]
kbright = key[events.RIGHTARROWKEY]
kbup = key[events.UPARROWKEY]
kbdown = key[events.DOWNARROWKEY]
def Init():
if not 'init' in obj:
obj['init'] = 1
obj['mx'] = 0.0 # Movement values
obj['my'] = 0.0
obj['accel'] = 0.05 # Acceleration rate
obj['maxspd'] = 0.2 # Maximum speed
obj['friction'] = 0.7 # Friction
def Update():
if kbleft > 0:
obj['mx'] -= obj['accel']
elif kbright > 0:
obj['mx'] += obj['accel']
else:
obj['mx'] *= obj['friction']
if kbup > 0:
obj['my'] += obj['accel']
elif kbdown > 0:
obj['my'] -= obj['accel']
else:
obj['my'] *= obj['friction']
obj['mx'] = Clamp(obj['mx'], -obj['maxspd'], obj['maxspd'])
obj['my'] = Clamp(obj['my'], -obj['maxspd'], obj['maxspd'])
if AxisCheck(obj['mx'], 0, .5)[0] != None: # We just collided with something on the X-axis
obj['mx'] = 0 # So stop movement on the X-axis
if AxisCheck(0, obj['my'], .5)[0] != None: # We just collided with something on the Y-axis
obj['my'] = 0 # So stop movement on the Y-axis
motion.dLoc = [obj['mx'], obj['my'], 0.0]
cont.activate(motion)
Init()
Update()
In this source, there's a bit of difference. We now use an object variable (mx and my) to store the movement variable so that the Player can move gradually by adding acceleration to those variables. When we don't press any keys, the speed slows down by basically multiplying the speed by a friction amount. We created a new function, Clamp, which will do just that - clamp the input variable to the specified minimum and maximum values. We clamp the movement speed values to ensure that it doesn't go over the new variable maxspd. Then, we move the object by the new movement values.
So, that's the basic difference between the Bullet Physics Player function and the Custom Physics Player Function. You'll have to decide which to use - I'd personally lean towards the Python physics method unless you want to have advanced physics-enabled objects like ropes or chains.
Anyway, if you have input, please don't hesitate to tell me here or on the BlenderArtists forum (on the post related to this blog or by personal messaging me). Anyway, here's the source code for Maze Crawl Part 5 - Physics (Bullet) and (Custom Python). As always, have fun!
So here's a case where your if/elif control scheme has a clear advantage over my if/if approach. When you add the friction variable, you can just use an if/elif/else statement to code it up. My code is less elegant (since you end up with six if statements in a row!!!):
ReplyDeleteif kbleft > 0:
obj['mx'] -= obj['accel']
if kbright > 0:
obj['mx'] += obj['accel']
if (kbleft, kbright) == (0, 0):
obj['mx'] *= obj['friction']
In the last if statement, it's important that the tuple on each side of the '==' is in parentheses.
For keyboard controls, I personally still like this approach, but for a joystick or gamepad, pressing two buttons at once is impossible, so I would definitely go with your code.
Ah, I see. That's a good point. With 'elif', friction's easier to implement.
ReplyDeleteSomething else I noticed from playing around with this -- if you set friction to 0.99, you've got a nice little simulated hockey rink!
ReplyDeleteJust wanted to let you know that the freezing stuff when moving the character disapeared since we use Servo Control now.... i think it had to do with the script loop or something.
ReplyDelete