You are no hardcore gamer.
Or a developer.
Post code or leave.
class Character(entity.MovingObject):
# base acceleration amount in pixels per second
base_acceleration = 0.85*30*30
# friction factor per second of null movement
friction = 0.01510305449388463132584804061124
# acceleration factor, overridden in each class
run_power = 1.4;
def __init__(self, game, state, player_id):
super(Character, self).__init__(game, state)
self.player_id = player_id
self.flip = False # are we flipped around?
self.intel = False # has intel (for drawing purposes)
self.just_spawned = False # have we just spawned?
# time tracker for the moving of the character's legs
self.animoffset = 0.0
self.hp_offset = -1 # FIXME: REMOVE; THIS ONLY EXISTS FOR HEALTH HUD TESTING
self.can_doublejump = False
self.desired_direction = 0
self.issynced = True
def step(self, game, state, frametime):
player = self.get_player(game, state)
# this is quite important, if hspeed / 20 drops below 1 self.animoffset will rapidly change and cause very fast moving legs (while we are moving very slow)
if abs(self.hspeed) > 20:
self.animoffset += frametime * abs(self.hspeed) / 20
self.animoffset %= 2
if abs(self.hspeed) == 0:
self.animoffset = 0
self.flip = not (player.aimdirection < 90 or player.aimdirection > 270)
# awesome handy movement code
# current code essentially goes in the most recent direction pressed,
# unlike the null movement in Source or the "preferred direction" that's
# present in a lot of indie games (aigh)
# rewrite acceptable if it makes it less stuffload of code :[
old_hspeed = self.hspeed;
# left movement
if player.left and not player.last_left:
self.desired_direction = -1
# right movement
elif player.last_left and not player.left:
if player.right:
self.desired_direction = 1
# null movement
else:
self.desired_direction = 0
# right movement
if player.right and not player.last_right:
self.desired_direction = 1
# left movement
elif player.last_right and not player.right:
if player.left:
self.desired_direction = -1
# null movement
else:
self.desired_direction = 0
# accelerate left
if self.desired_direction == -1:
self.hspeed -= self.base_acceleration * self.run_power * frametime
if self.hspeed > 0:
self.hspeed *= self.friction ** frametime
# accelerate right
if self.desired_direction == 1:
self.hspeed += self.base_acceleration * self.run_power * frametime
if self.hspeed < 0:
self.hspeed *= self.friction ** frametime
self.hspeed *= self.friction ** frametime
if abs(self.hspeed) < 10 and abs(old_hspeed) > abs(self.hspeed):
self.hspeed = 0
#print("broken")
if player.up and not player.old_up:
self.jump(game, state)
player.old_up = player.up
# gravitational force
self.vspeed += 700 * frametime
# TODO: air resistance, not hard limit
self.vspeed = min(800, self.vspeed)
# note: air resistance might have awkward side effects if implemented "naturally".
# Please consider resistance that's amplified at higher speeds & a threshold.
# hspeed limit
# self.hspeed = min(self.max_speed, max(-self.max_speed, self.hspeed))
self.hp+=self.hp_offset # test health change
if self.hp < 0:
self.hp_offset = 1
if self.hp > self.maxhp:
self.hp_offset = -1
def endstep(self, game, state, frametime):
player = self.get_player(game, state)
# check if we are on the ground before moving (for walking over 1 unit walls)
onground = True
# first we move, ignoring walls
self.x += self.hspeed * frametime
# if we are in a wall now, we must move back
if game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y))):
# but if we just walked onto a one-unit wall it's ok
# but we had to be on the ground
if onground and not game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y - 6))):
while game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y))):
self.y -= 1
# but sometimes we are so fast we will need to take two stairs at the same time
elif onground and not game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y - 12))) and game.map.collision_mask.overlap(self.collision_mask, (int(self.x - 6 * function.sign(self.hspeed)), int(self.y))):
while game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y))):
self.y -= 1
else:
self.x = math.floor(self.x) # move back to a whole pixel - TODO math.floor/math.ceil depending on direction
# and if one pixel wasn't enough
while game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y))):
self.x -= function.sign(self.hspeed)
self.hspeed = 0
#downward stairscript with hspeed checks
if onground and not game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y + 6))):
if game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y + 7))):
self.y += 6
elif game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y + 13))):
if (self.hspeed !=0):
if game.map.collision_mask.overlap(self.collision_mask, (int(self.x + function.sign(self.hspeed)*-6), int(self.y + 7))) and not game.map.collision_mask.overlap(self.collision_mask, (int(self.x + 6), int(self.y + 1))):
self.y += 12
# same stuff, but now vertically
self.y += self.vspeed * frametime
if game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y))):
self.y = float(int(self.y))
while game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y))):
self.y -= function.sign(self.vspeed)
self.vspeed = 0
player.last_left = player.left;
player.last_right = player.right;
def onground(self, game, state):
# are we on the ground? About one third of an unit from the ground is enough to qualify for this
return game.map.collision_mask.overlap(self.collision_mask, (int(self.x), int(self.y + 1)))
def interpolate(self, prev_obj, next_obj, alpha):
super(Character, self).interpolate(prev_obj, next_obj, alpha)
self.animoffset = prev_obj.animoffset + (next_obj.animoffset - prev_obj.animoffset) * alpha
if alpha > 0.5: refobj = next_obj
else: refobj = prev_obj
self.flip = refobj.flip
self.hp = prev_obj.hp + (next_obj.hp - prev_obj.hp) * alpha
def jump(self, game, state):
player = self.get_player(game, state)
if player.up:
if self.onground(game, state):
self.vspeed = -300
def die(self, game, state):
# first we must unregister ourselves from our player
self.get_player(game, state).character_id = None
self.get_player(game, state).respawntimer = 1# in seconds
# Then we have to destroy our weapon
state.entities[self.weapon].destroy(state)
# TODO: destroy our sentry
self.destroy(state)
def get_player(self, game, state):
return state.players[self.player_id]
def serialize(self, state):
packetstr = ""
packetstr += struct.pack(">IIii", self.x, self.y, round(self.hspeed*10), self.vspeed)
# Serialize intel, doublejump, etc... in one byte. Should we merge this with the input serialization in Player? Move the input ser. here?
byte = 0
byte |= self.intel << 0
byte |= self.can_doublejump << 1
#byte |= self.sentry << 2
packetstr += struct.pack(">B", byte)
packetstr += state.entities[self.weapon].serialize(state)
return packetstr
def deserialize(self, state, packetstr):
self.x, self.y, self.hspeed, self.vspeed = struct.unpack_from(">IIii", packetstr)
self.hspeed /= 10;
packetstr = packetstr[16:]
byte = struct.unpack_from(">B", packetstr)[0]
packetstr = packetstr[1:]
self.intel = byte & (1 << 0)
self.can_doublejump = byte & (1 << 1)
#self.sentry = byte & (1 << 2)
weapon_string_length = state.entities[self.weapon].deserialize(state, packetstr)
return struct.calcsize(">IIiiB")+weapon_string_length
pls