Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- these are the tweaks for the mechanics, feel free to change them for a different feeling
- -- the acceleration to move right/left
- local move_acceleration = 3500
- -- acceleration factor to use when air-borne
- local air_acceleration_factor = 0.8
- -- max speed right/left
- local max_speed = 400
- -- gravity pulling the player down in pixel units
- local gravity = -1100
- -- take-off speed when jumping in pixel units
- local jump_takeoff_speed = 700
- -- time within a double tap must occur to be considered a jump (only used for mouse/touch controls)
- local touch_jump_timeout = 0.2
- -- pre-hashing ids improves performance
- local msg_contact_point_response = hash("contact_point_response")
- local msg_animation_done = hash("animation_done")
- local group_geometry = hash("geometry")
- local input_left = hash("left")
- local input_right = hash("right")
- local input_jump = hash("jump")
- local input_touch = hash("touch")
- local anim_run = hash("run")
- local anim_idle = hash("idle")
- local anim_jump = hash("jump")
- local anim_fall = hash("fall")
- function init(self)
- -- this lets us handle input in this script
- msg.post(".", "acquire_input_focus")
- -- initial player velocity
- self.velocity = vmath.vector3(0, 0, 0)
- -- support variable to keep track of collisions and separation
- self.correction = vmath.vector3()
- -- if the player stands on ground or not
- self.ground_contact = false
- -- movement input in the range [-1,1]
- self.move_input = 0
- -- character direction, for anim selection (-1 or 1)
- self.direction = 1
- -- the currently playing animation
- self.anim = nil
- -- timer that controls the jump-window when using mouse/touch
- self.touch_jump_timer = 0
- end
- local function play_animation(self, anim)
- -- only play animations which are not already playing
- if self.anim ~= anim then
- -- tell the sprite to play the animation
- msg.post("#sprite", "play_animation", {id = anim})
- -- remember which animation is playing
- self.anim = anim
- end
- end
- local function update_animations(self)
- -- make sure the player character faces the right way
- sprite.set_hflip("#sprite", self.direction < 0)
- -- make sure the right animation is playing
- if self.ground_contact then
- if self.velocity.x == 0 then
- play_animation(self, anim_idle)
- else
- play_animation(self, anim_run)
- end
- else
- if self.velocity.y > 0 then
- play_animation(self, anim_jump)
- else
- play_animation(self, anim_fall)
- end
- end
- end
- function update(self, dt)
- -- determine the target speed based on input
- local target_speed = self.move_input * max_speed
- -- calculate the difference between our current speed and the target speed
- local speed_diff = target_speed - self.velocity.x
- -- the complete acceleration to integrate over this frame
- local acceleration = vmath.vector3(0, gravity, 0)
- if speed_diff ~= 0 then
- -- set the acceleration to work in the direction of the difference
- if speed_diff < 0 then
- acceleration.x = -move_acceleration
- else
- acceleration.x = move_acceleration
- end
- -- decrease the acceleration when air-borne to give a slower feel
- if not self.ground_contact then
- acceleration.x = air_acceleration_factor * acceleration.x
- end
- end
- -- calculate the velocity change this frame (dv is short for delta-velocity)
- local dv = acceleration * dt
- -- check if dv exceeds the intended speed difference, clamp it in that case
- if math.abs(dv.x) > math.abs(speed_diff) then
- dv.x = speed_diff
- end
- -- save the current velocity for later use
- -- (self.velocity, which right now is the velocity used the previous frame)
- local v0 = self.velocity
- -- calculate the new velocity by adding the velocity change
- self.velocity = self.velocity + dv
- -- calculate the translation this frame by integrating the velocity
- local dp = (v0 + self.velocity) * dt * 0.5
- -- apply it to the player character
- go.set_position(go.get_position() + dp)
- -- update the jump timer
- if self.touch_jump_timer > 0 then
- self.touch_jump_timer = self.touch_jump_timer - dt
- end
- update_animations(self)
- -- reset volatile state
- self.correction = vmath.vector3()
- self.move_input = 0
- self.ground_contact = false
- end
- local function handle_geometry_contact(self, normal, distance)
- -- project the correction vector onto the contact normal
- -- (the correction vector is the 0-vector for the first contact point)
- local proj = vmath.dot(self.correction, normal)
- -- calculate the compensation we need to make for this contact point
- local comp = (distance - proj) * normal
- -- add it to the correction vector
- self.correction = self.correction + comp
- -- apply the compensation to the player character
- go.set_position(go.get_position() + comp)
- -- check if the normal points enough up to consider the player standing on the ground
- -- (0.7 is roughly equal to 45 degrees deviation from pure vertical direction)
- if normal.y > 0.7 then
- self.ground_contact = true
- end
- -- project the velocity onto the normal
- proj = vmath.dot(self.velocity, normal)
- -- if the projection is negative, it means that some of the velocity points towards the contact point
- if proj < 0 then
- -- remove that component in that case
- self.velocity = self.velocity - proj * normal
- end
- end
- function on_message(self, message_id, message, sender)
- -- check if we received a contact point message
- if message_id == msg_contact_point_response then
- -- check that the object is something we consider geometry
- if message.group == group_geometry then
- handle_geometry_contact(self, message.normal, message.distance)
- end
- end
- end
- local function jump(self)
- -- only allow jump from ground
- -- (extend this with a counter to do things like double-jumps)
- if self.ground_contact then
- -- set take-off speed
- self.velocity.y = jump_takeoff_speed
- -- play animation
- play_animation(self, anim_jump)
- end
- end
- local function abort_jump(self)
- -- cut the jump short if we are still going up
- if self.velocity.y > 0 then
- -- scale down the upwards speed
- self.velocity.y = self.velocity.y * 0.5
- end
- end
- function on_input(self, action_id, action)
- if action_id == input_left then
- self.move_input = -action.value
- self.direction = -1
- elseif action_id == input_right then
- self.move_input = action.value
- self.direction = 1
- elseif action_id == input_jump then
- if action.pressed then
- jump(self)
- elseif action.released then
- abort_jump(self)
- end
- elseif action_id == input_touch then
- -- move towards the touch-point
- local diff = action.x - go.get_position().x
- -- update direction
- if diff > 0 then
- self.direction = 1
- else
- self.direction = -1
- end
- -- only give input when far away (more than 10 pixels)
- if math.abs(diff) > 10 then
- -- slow down when less than 100 pixels away
- self.move_input = diff / 100
- -- clamp input to [-1,1]
- self.move_input = math.min(1, math.max(-1, self.move_input))
- end
- if action.released then
- -- start timing the last release to see if we are about to jump
- self.touch_jump_timer = touch_jump_timeout
- elseif action.pressed then
- -- jump on double tap
- if self.touch_jump_timer > 0 then
- jump(self)
- end
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement