–DownhillAutoscroller.tscn changes

This commit is contained in:
D L 2023-01-27 13:55:12 -08:00
parent dd148ba02a
commit 6fec533222
10 changed files with 280 additions and 34 deletions

File diff suppressed because one or more lines are too long

View File

@ -177,7 +177,7 @@ const UNIT_SPRITES = {
} }
const UNIT_TYPE_MOVE_SPEEDS = { const UNIT_TYPE_MOVE_SPEEDS = {
UnitType.PLAYER: 6, UnitType.PLAYER: 5,
UnitType.NPC: 3, UnitType.NPC: 3,
} }
@ -187,8 +187,8 @@ const UNIT_TYPE_JUMP_SPEEDS = {
const SCALE_FACTOR = 2.4 const SCALE_FACTOR = 2.4
const GRID_SIZE = 20 # pixels const GRID_SIZE = 20 # pixels
const GRAVITY = 30 const GRAVITY = 10
const MAX_FALL_SPEED = -12 const MAX_FALL_SPEED = -9
const ACCELERATION = 35 const ACCELERATION = 35
const QUANTUM_DIST = 0.001 const QUANTUM_DIST = 0.001
const SPAWN_DISTANCE = 10 const SPAWN_DISTANCE = 10

View File

@ -9,10 +9,11 @@ extends Node
class_name GameScene class_name GameScene
export var tile_set_name: String export var tile_set_name: String
export var camera_h_offset : float = 1
const Constants = preload("res://Scripts/Constants.gd") const Constants = preload("res://Scripts/Constants.gd")
const Unit = preload("res://Scripts/Unit.gd") const Unit = preload("res://Scripts/Unit.gd")
const UNIT_DIRECTORY = { const UNIT_DIRECTORY = {
Constants.UnitType.NPC: preload("res://Units/NPC.tscn"), Constants.UnitType.NPC: preload("res://Units/DownhillAutoscrollerNPC.tscn"),
} }
# positions to unit string # positions to unit string
@ -62,9 +63,9 @@ func _ready():
func _process(delta): func _process(delta):
# visual effects # visual effects
if (player.facing == Constants.Direction.RIGHT): if (player.facing == Constants.Direction.RIGHT):
player_cam.offset_h = 1 player_cam.offset_h = camera_h_offset
else: else:
player_cam.offset_h = -1 player_cam.offset_h = -camera_h_offset
read_paused() read_paused()
if not paused: if not paused:

View File

@ -12,6 +12,7 @@ var colliders = []
# if unit's move vector has at least one of these directional components, # if unit's move vector has at least one of these directional components,
# do the collision check # do the collision check
var collision_into_direction_arrays = [] # nested array var collision_into_direction_arrays = [] # nested array
var collider_to_map_elem_type = {}
var unit_collision_bounds = {} # maps unit type to [upper, lower, left, right] var unit_collision_bounds = {} # maps unit type to [upper, lower, left, right]
@ -68,64 +69,70 @@ func init_stage_grid(tilemap : TileMap):
break break
match map_elem_type: match map_elem_type:
Constants.MapElemType.SQUARE: Constants.MapElemType.SQUARE:
insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.DOWN, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.DOWN, 1, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, 1, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, 1, map_elem_type)
Constants.MapElemType.SLOPE_LEFT: Constants.MapElemType.SLOPE_LEFT:
try_insert_collider( try_insert_collider(
Vector2(stage_x, stage_y), Vector2(stage_x, stage_y),
Vector2(stage_x + 1, stage_y + 1), Vector2(stage_x + 1, stage_y + 1),
[Constants.Direction.RIGHT, Constants.Direction.DOWN] [Constants.Direction.RIGHT, Constants.Direction.DOWN],
map_elem_type
) )
insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, 1, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1, map_elem_type)
Constants.MapElemType.SLOPE_RIGHT: Constants.MapElemType.SLOPE_RIGHT:
try_insert_collider( try_insert_collider(
Vector2(stage_x, stage_y + 1), Vector2(stage_x, stage_y + 1),
Vector2(stage_x + 1, stage_y), Vector2(stage_x + 1, stage_y),
[Constants.Direction.LEFT, Constants.Direction.DOWN] [Constants.Direction.LEFT, Constants.Direction.DOWN],
map_elem_type
) )
insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, 1, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1, map_elem_type)
Constants.MapElemType.SMALL_SLOPE_LEFT_1: Constants.MapElemType.SMALL_SLOPE_LEFT_1:
try_insert_collider( try_insert_collider(
Vector2(stage_x, stage_y), Vector2(stage_x, stage_y),
Vector2(stage_x + 1, stage_y + .5), Vector2(stage_x + 1, stage_y + .5),
[Constants.Direction.RIGHT, Constants.Direction.DOWN] [Constants.Direction.RIGHT, Constants.Direction.DOWN],
map_elem_type
) )
insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, .5) insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, .5, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1, map_elem_type)
Constants.MapElemType.SMALL_SLOPE_LEFT_2: Constants.MapElemType.SMALL_SLOPE_LEFT_2:
try_insert_collider( try_insert_collider(
Vector2(stage_x, stage_y + .5), Vector2(stage_x, stage_y + .5),
Vector2(stage_x + 1, stage_y + 1), Vector2(stage_x + 1, stage_y + 1),
[Constants.Direction.RIGHT, Constants.Direction.DOWN] [Constants.Direction.RIGHT, Constants.Direction.DOWN],
map_elem_type
) )
insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, .5) insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, .5, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, 1, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1, map_elem_type)
Constants.MapElemType.SMALL_SLOPE_RIGHT_1: Constants.MapElemType.SMALL_SLOPE_RIGHT_1:
try_insert_collider( try_insert_collider(
Vector2(stage_x, stage_y + .5), Vector2(stage_x, stage_y + .5),
Vector2(stage_x + 1, stage_y), Vector2(stage_x + 1, stage_y),
[Constants.Direction.LEFT, Constants.Direction.DOWN] [Constants.Direction.LEFT, Constants.Direction.DOWN],
map_elem_type
) )
insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, .5) insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, .5, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1, map_elem_type)
Constants.MapElemType.SMALL_SLOPE_RIGHT_2: Constants.MapElemType.SMALL_SLOPE_RIGHT_2:
try_insert_collider( try_insert_collider(
Vector2(stage_x, stage_y + 1), Vector2(stage_x, stage_y + 1),
Vector2(stage_x + 1, stage_y + .5), Vector2(stage_x + 1, stage_y + .5),
[Constants.Direction.LEFT, Constants.Direction.DOWN] [Constants.Direction.LEFT, Constants.Direction.DOWN],
map_elem_type
) )
insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.RIGHT, 1, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, .5) insert_grid_collider(stage_x, stage_y, Constants.Direction.LEFT, .5, map_elem_type)
insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.UP, 1, map_elem_type)
Constants.MapElemType.LEDGE: Constants.MapElemType.LEDGE:
insert_grid_collider(stage_x, stage_y, Constants.Direction.DOWN, 1) insert_grid_collider(stage_x, stage_y, Constants.Direction.DOWN, 1, map_elem_type)
func insert_grid_collider(stage_x, stage_y, direction : int, fractional_height : float): func insert_grid_collider(stage_x, stage_y, direction : int, fractional_height : float, map_elem_type : int):
var check_colliders = [] var check_colliders = []
var insert_colliders = [] var insert_colliders = []
var point_a : Vector2 var point_a : Vector2
@ -143,9 +150,9 @@ func insert_grid_collider(stage_x, stage_y, direction : int, fractional_height :
Constants.Direction.RIGHT: Constants.Direction.RIGHT:
point_a = Vector2(stage_x, stage_y + (1 * fractional_height)) point_a = Vector2(stage_x, stage_y + (1 * fractional_height))
point_b = Vector2(stage_x, stage_y) point_b = Vector2(stage_x, stage_y)
try_insert_collider(point_a, point_b, [direction]) try_insert_collider(point_a, point_b, [direction], map_elem_type)
func try_insert_collider(point_a : Vector2, point_b : Vector2, directions : Array): func try_insert_collider(point_a : Vector2, point_b : Vector2, directions : Array, map_elem_type : int):
if directions.size() == 1: if directions.size() == 1:
# aligned with grid # aligned with grid
for i in range(len(colliders)): for i in range(len(colliders)):
@ -157,6 +164,7 @@ func try_insert_collider(point_a : Vector2, point_b : Vector2, directions : Arra
return return
colliders.append([point_a, point_b]) colliders.append([point_a, point_b])
collision_into_direction_arrays.append(directions) collision_into_direction_arrays.append(directions)
collider_to_map_elem_type[[point_a, point_b]] = map_elem_type
func are_inverse_directions(d1, d2): func are_inverse_directions(d1, d2):
return ((d1 == Constants.Direction.LEFT and d2 == Constants.Direction.RIGHT) return ((d1 == Constants.Direction.LEFT and d2 == Constants.Direction.RIGHT)
@ -205,6 +213,10 @@ func reangle_grounded_move(unit : Unit):
unit.pos.y = intersects_results[1].y + Constants.QUANTUM_DIST unit.pos.y = intersects_results[1].y + Constants.QUANTUM_DIST
unit.last_contacted_ground_collider = collider unit.last_contacted_ground_collider = collider
reangle_move(unit, collider, true) reangle_move(unit, collider, true)
# slope acceleration for DownhillAutoscroller:
# set the player's last_contacted_map_elem_type field
if unit is DownhillAutoscrollerPlayer:
unit.last_contacted_map_elem_type = collider_to_map_elem_type[collider]
if !has_ground_collision: if !has_ground_collision:
reangle_move(unit, unit.last_contacted_ground_collider, true) reangle_move(unit, unit.last_contacted_ground_collider, true)
unit.set_unit_condition(Constants.UnitCondition.IS_ON_GROUND, false) unit.set_unit_condition(Constants.UnitCondition.IS_ON_GROUND, false)
@ -249,6 +261,11 @@ func check_collision(unit : Unit, collider, collision_into_directions, delta):
# landed on ground, horizontal component to become magnitude # landed on ground, horizontal component to become magnitude
unit.v_speed = 0 unit.v_speed = 0
reangle_move(unit, collider, false) reangle_move(unit, collider, false)
# slope acceleration for DownhillAutoscroller:
# set the player's last_contacted_map_elem_type field
if unit is DownhillAutoscrollerPlayer:
unit.last_contacted_map_elem_type = collider_to_map_elem_type[collider]
else: else:
if collider[0].x == collider[1].x: if collider[0].x == collider[1].x:
# vertical wall collision # vertical wall collision

View File

@ -0,0 +1,94 @@
extends Player
class_name DownhillAutoscrollerPlayer
export var min_speed : float = 2
export var max_speed : float = 10
export var player_initiated_acceleration : float = 6
var last_contacted_map_elem_type : int = Constants.MapElemType.SQUARE
func process_unit(delta, time_elapsed : float):
# always be movin'
facing = Constants.Direction.RIGHT
actions[Constants.ActionType.MOVE] = true
# Fine tune the player's speed
if get_current_action() == Constants.UnitCurrentAction.RECOILING:
target_move_speed = min_speed
else:
# override player input so that leftward movement is deceleration,
# right movement is acceleration
if scene.input_table[Constants.PlayerInput.LEFT][scene.I_T_PRESSED]:
target_move_speed = move_toward(target_move_speed, min_speed, player_initiated_acceleration * delta)
else:
if not get_condition(Constants.UnitCondition.IS_ON_GROUND, true):
if (target_move_speed < Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type]
and scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]):
target_move_speed = move_toward(target_move_speed, Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type], player_initiated_acceleration * delta)
else:
# shallow slope: arctan(.5) = 27 degrees, sin(27) = 0.45
# steep slope: sin(45) = 0.71
var ground_influenced_acceleration = 0
var is_decel : bool = false
if (last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_RIGHT_1
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_RIGHT_2
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_1
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_2):
ground_influenced_acceleration = Constants.GRAVITY * 0.45
if (last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_1
or last_contacted_map_elem_type == Constants.MapElemType.SMALL_SLOPE_LEFT_2):
is_decel = true
elif (last_contacted_map_elem_type == Constants.MapElemType.SLOPE_RIGHT
or last_contacted_map_elem_type == Constants.MapElemType.SLOPE_LEFT):
ground_influenced_acceleration = Constants.GRAVITY * 0.71
if last_contacted_map_elem_type == Constants.MapElemType.SLOPE_LEFT:
is_decel = true
if is_decel or ground_influenced_acceleration == 0:
var end_speed
if ground_influenced_acceleration == 0:
# flat ground
if scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]:
end_speed = max(target_move_speed, Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type])
else:
end_speed = target_move_speed
else:
# incline
if scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]:
end_speed = Constants.UNIT_TYPE_MOVE_SPEEDS[unit_type]
else:
end_speed = min_speed
if target_move_speed < end_speed:
target_move_speed = move_toward(target_move_speed, end_speed, player_initiated_acceleration * delta)
else:
target_move_speed = move_toward(target_move_speed, end_speed, ground_influenced_acceleration * delta)
else:
var acceleration = ground_influenced_acceleration
if scene.input_table[Constants.PlayerInput.RIGHT][scene.I_T_PRESSED]:
acceleration = max(acceleration, player_initiated_acceleration)
if target_move_speed < max_speed:
target_move_speed = move_toward(target_move_speed, max_speed, acceleration * delta)
.process_unit(delta, time_elapsed)
# treat all collisions as right-side collisions
func hit(dir : int):
# Unit.gd implementation override
hit_queued = true
hit_dir = Constants.Direction.RIGHT
# Player.gd implementation
set_unit_condition_with_timer(Constants.UnitCondition.IS_INVINCIBLE)
start_flash()
set_action(Constants.ActionType.RECOIL)
set_current_action(Constants.UnitCurrentAction.RECOILING)
set_unit_condition(Constants.UnitCondition.MOVING_STATUS, Constants.UnitMovingStatus.IDLE)
# override super class's RECOIL_PUSHBACK
func handle_recoil():
if not hit_queued:
return
hit_queued = false
# skip recoil pushback logic, since target_move_speed is already
# set to min_speed

View File

@ -1,5 +1,7 @@
extends NPCUnit extends NPCUnit
class_name NPCExample
func before_tick(): func before_tick():
if scene.rng.randf() < 0.5: if scene.rng.randf() < 0.5:

View File

@ -0,0 +1,5 @@
extends NPCExample
func before_tick():
pass

View File

@ -0,0 +1,39 @@
[gd_scene load_steps=7 format=2]
[ext_resource path="res://Units/DownhillAutoscrollerNPC.gd" type="Script" id=1]
[ext_resource path="res://Graphics/Units/NPC.png" type="Texture" id=2]
[ext_resource path="res://Graphics/Animations/NPCWalk.tres" type="SpriteFrames" id=3]
[ext_resource path="res://Graphics/Units/NPCJump2.png" type="Texture" id=4]
[ext_resource path="res://Graphics/Units/NPCJump1.png" type="Texture" id=5]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 6, 14 )
[node name="NPC" type="Area2D"]
collision_mask = 2
script = ExtResource( 1 )
unit_type = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2( 0, -14 )
shape = SubResource( 1 )
[node name="Idle" type="Sprite" parent="."]
visible = false
texture = ExtResource( 2 )
offset = Vector2( 0, -15 )
[node name="Jump1" type="Sprite" parent="."]
visible = false
texture = ExtResource( 5 )
offset = Vector2( 0, -15 )
[node name="Jump2" type="Sprite" parent="."]
visible = false
texture = ExtResource( 4 )
offset = Vector2( 0, -15 )
[node name="Walk" type="AnimatedSprite" parent="."]
visible = false
frames = ExtResource( 3 )
offset = Vector2( 0, -15 )

View File

@ -0,0 +1,47 @@
[gd_scene load_steps=8 format=2]
[ext_resource path="res://Scripts/Units/DownhillAutoscrollerPlayer.gd" type="Script" id=1]
[ext_resource path="res://Graphics/Units/Player.png" type="Texture" id=2]
[ext_resource path="res://Graphics/Units/PlayerJump2.png" type="Texture" id=3]
[ext_resource path="res://Graphics/Units/PlayerJump1.png" type="Texture" id=4]
[ext_resource path="res://Graphics/Animations/PlayerWalk.tres" type="SpriteFrames" id=5]
[ext_resource path="res://Graphics/Units/PlayerRecoil.png" type="Texture" id=6]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 6, 14 )
[node name="Player" type="Area2D"]
z_index = 1
collision_layer = 0
script = ExtResource( 1 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2( 0, -14 )
shape = SubResource( 1 )
[node name="Idle" type="Sprite" parent="."]
visible = false
texture = ExtResource( 2 )
offset = Vector2( 0, -15 )
[node name="Walk" type="AnimatedSprite" parent="."]
visible = false
frames = ExtResource( 5 )
offset = Vector2( 0, -15 )
[node name="Jump1" type="Sprite" parent="."]
visible = false
texture = ExtResource( 4 )
offset = Vector2( 0, -15 )
[node name="Jump2" type="Sprite" parent="."]
visible = false
texture = ExtResource( 3 )
offset = Vector2( 0, -15 )
[node name="Recoil" type="Sprite" parent="."]
visible = false
texture = ExtResource( 6 )
offset = Vector2( 0, -15 )
[connection signal="area_entered" from="." to="." method="_on_Player_area_entered"]

View File

@ -9,11 +9,21 @@
config_version=4 config_version=4
_global_script_classes=[ { _global_script_classes=[ {
"base": "Player",
"class": "DownhillAutoscrollerPlayer",
"language": "GDScript",
"path": "res://Scripts/Units/DownhillAutoscrollerPlayer.gd"
}, {
"base": "Node", "base": "Node",
"class": "GameScene", "class": "GameScene",
"language": "GDScript", "language": "GDScript",
"path": "res://Scripts/GameScene.gd" "path": "res://Scripts/GameScene.gd"
}, { }, {
"base": "NPCUnit",
"class": "NPCExample",
"language": "GDScript",
"path": "res://Scripts/Units/NPCExample.gd"
}, {
"base": "Unit", "base": "Unit",
"class": "NPCUnit", "class": "NPCUnit",
"language": "GDScript", "language": "GDScript",
@ -30,7 +40,9 @@ _global_script_classes=[ {
"path": "res://Scripts/Unit.gd" "path": "res://Scripts/Unit.gd"
} ] } ]
_global_script_class_icons={ _global_script_class_icons={
"DownhillAutoscrollerPlayer": "",
"GameScene": "", "GameScene": "",
"NPCExample": "",
"NPCUnit": "", "NPCUnit": "",
"Player": "", "Player": "",
"Unit": "" "Unit": ""