263 lines
5.9 KiB
GDScript
263 lines
5.9 KiB
GDScript
extends RigidBody2D
|
|
|
|
# Character Demo, written by Juan Linietsky.
|
|
#
|
|
# Implementation of a 2D Character controller.
|
|
# This implementation uses the physics engine for
|
|
# controlling a character, in a very similar way
|
|
# than a 3D character controller would be implemented.
|
|
#
|
|
# Using the physics engine for this has the main
|
|
# advantages:
|
|
# -Easy to write.
|
|
# -Interaction with other physics-based objects is free
|
|
# -Only have to deal with the object linear velocity, not position
|
|
# -All collision/area framework available
|
|
#
|
|
# But also has the following disadvantages:
|
|
#
|
|
# -Objects may bounce a little bit sometimes
|
|
# -Going up ramps sends the chracter flying up, small hack is needed.
|
|
# -A ray collider is needed to avoid sliding down on ramps and
|
|
# undesiderd bumps, small steps and rare numerical precision errors.
|
|
# (another alternative may be to turn on friction when the character is not moving).
|
|
# -Friction cant be used, so floor velocity must be considered
|
|
# for moving platforms.
|
|
|
|
var anim=""
|
|
var siding_left=false
|
|
var jumping=false
|
|
var stopping_jump=false
|
|
var shooting=false
|
|
|
|
var WALK_ACCEL = 800.0
|
|
var WALK_DEACCEL= 800.0
|
|
var WALK_MAX_VELOCITY= 200.0
|
|
var GRAVITY = 700.0
|
|
var AIR_ACCEL = 200.0
|
|
var AIR_DEACCEL= 200.0
|
|
var JUMP_VELOCITY=460
|
|
var STOP_JUMP_FORCE=900.0
|
|
|
|
var MAX_FLOOR_AIRBORNE_TIME = 0.15
|
|
|
|
var airborne_time=1e20
|
|
var shoot_time=1e20
|
|
|
|
var MAX_SHOOT_POSE_TIME = 0.3
|
|
|
|
var bullet = preload("res://bullet.xml")
|
|
|
|
var floor_h_velocity=0.0
|
|
var enemy
|
|
|
|
func _integrate_forces(s):
|
|
|
|
|
|
|
|
var lv = s.get_linear_velocity()
|
|
var step = s.get_step()
|
|
|
|
var new_anim=anim
|
|
var new_siding_left=siding_left
|
|
|
|
|
|
# Get the controls
|
|
var move_left = Input.is_action_pressed("move_left")
|
|
var move_right = Input.is_action_pressed("move_right")
|
|
var jump = Input.is_action_pressed("jump")
|
|
var shoot = Input.is_action_pressed("shoot")
|
|
var spawn = Input.is_action_pressed("spawn")
|
|
|
|
if spawn:
|
|
var e = enemy.instance()
|
|
var p = get_pos()
|
|
p.y = p.y - 100
|
|
e.set_pos(p)
|
|
get_parent().add_child(e)
|
|
|
|
|
|
#deapply prev floor velocity
|
|
lv.x-=floor_h_velocity
|
|
floor_h_velocity=0.0
|
|
|
|
|
|
# Find the floor (a contact with upwards facing collision normal)
|
|
var found_floor=false
|
|
var floor_index=-1
|
|
|
|
for x in range(s.get_contact_count()):
|
|
|
|
var ci = s.get_contact_local_normal(x)
|
|
if (ci.dot(Vector2(0,-1))>0.6):
|
|
found_floor=true
|
|
floor_index=x
|
|
|
|
# A good idea when impementing characters of all kinds,
|
|
# Compensates for physics imprecission, as well as human
|
|
# reaction delay.
|
|
|
|
if (shoot and not shooting):
|
|
shoot_time=0
|
|
var bi = bullet.instance()
|
|
var ss
|
|
if (siding_left):
|
|
ss=-1.0
|
|
else:
|
|
ss=1.0
|
|
var pos = get_pos() + get_node("bullet_shoot").get_pos()*Vector2(ss,1.0)
|
|
|
|
bi.set_pos(pos)
|
|
get_parent().add_child(bi)
|
|
|
|
bi.set_linear_velocity( Vector2(800.0*ss,-80) )
|
|
get_node("sprite/smoke").set_emitting(true)
|
|
get_node("sound").play("shoot")
|
|
PS2D.body_add_collision_exception(bi.get_rid(),get_rid()) # make bullet and this not collide
|
|
|
|
|
|
else:
|
|
shoot_time+=step
|
|
|
|
|
|
if (found_floor):
|
|
airborne_time=0.0
|
|
else:
|
|
airborne_time+=step #time it spent in the air
|
|
|
|
var on_floor = airborne_time < MAX_FLOOR_AIRBORNE_TIME
|
|
|
|
# Process jump
|
|
if (jumping):
|
|
if (lv.y>0):
|
|
#set off the jumping flag if going down
|
|
jumping=false
|
|
elif (not jump):
|
|
stopping_jump=true
|
|
|
|
if (stopping_jump):
|
|
lv.y+=STOP_JUMP_FORCE*step
|
|
|
|
if (on_floor):
|
|
|
|
# Process logic when character is on floor
|
|
|
|
if (move_left and not move_right):
|
|
if (lv.x > -WALK_MAX_VELOCITY):
|
|
lv.x-=WALK_ACCEL*step
|
|
elif (move_right and not move_left):
|
|
if (lv.x < WALK_MAX_VELOCITY):
|
|
lv.x+=WALK_ACCEL*step
|
|
else:
|
|
var xv = abs(lv.x)
|
|
xv-=WALK_DEACCEL*step
|
|
if (xv<0):
|
|
xv=0
|
|
lv.x=sign(lv.x)*xv
|
|
|
|
#Check jump
|
|
if (not jumping and jump):
|
|
lv.y=-JUMP_VELOCITY
|
|
jumping=true
|
|
stopping_jump=false
|
|
get_node("sound").play("jump")
|
|
|
|
#check siding
|
|
|
|
if (lv.x < 0 and move_left):
|
|
new_siding_left=true
|
|
elif (lv.x > 0 and move_right):
|
|
new_siding_left=false
|
|
if (jumping):
|
|
new_anim="jumping"
|
|
elif (abs(lv.x)<0.1):
|
|
if (shoot_time<MAX_SHOOT_POSE_TIME):
|
|
new_anim="idle_weapon"
|
|
else:
|
|
new_anim="idle"
|
|
else:
|
|
if (shoot_time<MAX_SHOOT_POSE_TIME):
|
|
new_anim="run_weapon"
|
|
else:
|
|
new_anim="run"
|
|
else:
|
|
|
|
# Process logic when the character is in the air
|
|
|
|
if (move_left and not move_right):
|
|
if (lv.x > -WALK_MAX_VELOCITY):
|
|
lv.x-=AIR_ACCEL*step
|
|
elif (move_right and not move_left):
|
|
if (lv.x < WALK_MAX_VELOCITY):
|
|
lv.x+=AIR_ACCEL*step
|
|
else:
|
|
var xv = abs(lv.x)
|
|
xv-=AIR_DEACCEL*step
|
|
if (xv<0):
|
|
xv=0
|
|
lv.x=sign(lv.x)*xv
|
|
|
|
if (lv.y<0):
|
|
if (shoot_time<MAX_SHOOT_POSE_TIME):
|
|
new_anim="jumping_weapon"
|
|
else:
|
|
new_anim="jumping"
|
|
else:
|
|
if (shoot_time<MAX_SHOOT_POSE_TIME):
|
|
new_anim="falling_weapon"
|
|
else:
|
|
new_anim="falling"
|
|
|
|
|
|
#Update siding
|
|
|
|
if (new_siding_left!=siding_left):
|
|
if (new_siding_left):
|
|
get_node("sprite").set_scale( Vector2(-1,1) )
|
|
else:
|
|
get_node("sprite").set_scale( Vector2(1,1) )
|
|
|
|
siding_left=new_siding_left
|
|
|
|
#Change animation
|
|
if (new_anim!=anim):
|
|
anim=new_anim
|
|
get_node("anim").play(anim)
|
|
|
|
shooting=shoot
|
|
|
|
# Apply floor velocity
|
|
if (found_floor):
|
|
floor_h_velocity=s.get_contact_collider_velocity_at_pos(floor_index).x
|
|
lv.x+=floor_h_velocity
|
|
|
|
|
|
|
|
|
|
#Finally, apply gravity and set back the linear velocity
|
|
lv+=s.get_total_gravity()*step
|
|
s.set_linear_velocity(lv)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _ready():
|
|
# Initalization here
|
|
|
|
# if !Globals.has_singleton("Facebook"):
|
|
# return
|
|
# var Facebook = Globals.get_singleton("Facebook")
|
|
# var link = Globals.get("facebook/link")
|
|
# var icon = Globals.get("facebook/icon")
|
|
# var msg = "I just sneezed on your wall! Beat my score and Stop the Running nose!"
|
|
# var title = "I just sneezed on your wall!"
|
|
# Facebook.post("feed", msg, title, link, icon)
|
|
enemy = ResourceLoader.load("res://enemy.xml")
|
|
pass
|
|
|
|
|
|
|