godot_tiny_crate/Script/Actor.gd

169 lines
3.9 KiB
GDScript

extends Node2D
class_name Actor
export var tag := "actor"
export var hitbox_x := 8
export var hitbox_y := 8
var speed_x := 0.0
var speed_y := 0.0
export var gravity := 0.2
var remainder_x := 0.0
var remainder_y := 0.0
export var is_moving := false
export var is_solid := false
export var is_colliding := false
export var is_using_gravity := false
export var is_on_treadmill := false
var has_moved_x := false
var has_moved_y := false
var has_hit_up := false
var has_hit_down := false
var has_hit_left := false
var has_hit_right := false
var is_on_floor := false
var time_since_floor := 0
# Called when the node enters the scene tree for the first time.
func _ready():
position.x = floor(position.x)
position.y = floor(position.y)
func _process(delta):
move()
if is_using_gravity:
speed_y += gravity
if not is_on_floor:
time_since_floor += 1
# axis aligned bounding box
func aabb(x1 : int, y1 : int, w1 : int, h1 : int, x2 : int, y2 : int, w2 : int, h2 : int):
return x1 < x2 + w2 and x2 < x1 + w1 and y1 < y2 + h2 and y2 < y1 + h1
# move actor
func move():
# clear bools
has_moved_x = false
has_moved_y = false
has_hit_up = false
has_hit_down = false
has_hit_left = false
has_hit_right = false
remainder_y += speed_y
var dy = floor(remainder_y + 0.5) # distance y
remainder_y -= dy
if dy != 0:
move_y(dy)
remainder_x += speed_x
var dx = floor(remainder_x + 0.5) # distance x
remainder_x -= dx
if dx != 0:
move_x(dx)
# return distance of upcoming move
func move_get_dist():
return Vector2(floor(remainder_x + speed_x + 0.5), floor(remainder_y + speed_y + 0.5))
# move x axis
func move_x(dist : int):
var hit = false
has_moved_x = true
if is_colliding:
var step = sign(dist)
for i in range(abs(dist)):
if is_area_solid(position.x + step, position.y):
speed_x = 0
remainder_x = 0
has_hit_left = (step == -1)
has_hit_right = (step == 1)
hit = true
break
else:
position.x += step
else:
position.x += dist
position.x = position.x
return hit
# move y axis
func move_y(dist : int):
var hit = false
has_moved_y = true
is_on_floor = false
if is_colliding:
var step = sign(dist)
for i in range(abs(dist)):
if is_area_solid(position.x, position.y + step):
speed_y = 0
remainder_y = 0
has_hit_up = (step == -1)
has_hit_down = (step == 1)
is_on_floor = has_hit_down
time_since_floor = 0
hit = true
break
else:
position.y += step
else:
position.y += dist
position.y = position.y
return hit
# check area for solid tiles
func is_area_solid_tile(x1, y1, width, height):
var w2m = Shared.node_map_solid.world_to_map(Vector2(x1, y1))
var cell = Shared.node_map_solid.cell_size.x
# check more than four points if hitbox is longer than 8 pixels
for ix in range((width / cell) + 1):
for iy in range((height / cell) + 1):
var check = Vector2(w2m.x + ix, w2m.y + iy)
if Shared.node_map_solid.get_cellv(check) != -1:
check *= cell
if aabb(x1, y1, width, height, check.x, check.y, cell, cell):
return true
return false
# check area for solid actors
func is_area_solid_actor(x, y, width = hitbox_x, height = hitbox_y, ignore = null) -> bool:
for a in get_tree().get_nodes_in_group("actor"):
if a != self and a.is_solid and a != ignore:
if aabb(x, y, width, height, a.position.x, a.position.y, a.hitbox_x, a.hitbox_y):
return true
return false
# check if area is solid
func is_area_solid(x, y, width = hitbox_x, height = hitbox_y, ignore = null) -> bool:
if is_area_solid_tile(x, y, width, height):
return true
if is_area_solid_actor(x, y, width, height, ignore):
return true
return false
# return array of actors
func check_area_actors(x, y, width = hitbox_x, height = hitbox_y, group_name = "actor", ignore = null):
var act = []
for a in get_tree().get_nodes_in_group(group_name):
if a != self and a != ignore:
if aabb(x, y, width, height, a.position.x, a.position.y, a.hitbox_x, a.hitbox_y):
act.append(a)
return act