Start the game! Just adds a basic player character with rough movement

This commit is contained in:
David Lenfesty 2023-09-19 21:56:03 -06:00
commit d640ad707f
14 changed files with 332 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Godot 4+ specific ignores
.godot/

BIN
Sprites/hockey_player.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bknjh6k2ocrri"
path="res://.godot/imported/hockey_player.png-2943b0999ca2f3e81e7d84176d3012c9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Sprites/hockey_player.png"
dest_files=["res://.godot/imported/hockey_player.png-2943b0999ca2f3e81e7d84176d3012c9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
Sprites/hockey_player.xcf Normal file

Binary file not shown.

6
game.gd Normal file
View File

@ -0,0 +1,6 @@
extends Node2D
# Called when the node enters the scene tree for the first time.
func _ready():
$PlayerController.set_player_node($Player)

12
game.tscn Normal file
View File

@ -0,0 +1,12 @@
[gd_scene load_steps=4 format=3 uid="uid://d2skh3wa6s2j7"]
[ext_resource type="PackedScene" uid="uid://b3llhcsie7y4u" path="res://player.tscn" id="1_2ej6p"]
[ext_resource type="Script" path="res://game.gd" id="1_swmdi"]
[ext_resource type="PackedScene" uid="uid://clntxmhd5uhlt" path="res://player_controller.tscn" id="3_v82a6"]
[node name="Game" type="Node2D"]
script = ExtResource("1_swmdi")
[node name="Player" parent="." instance=ExtResource("1_2ej6p")]
[node name="PlayerController" parent="." instance=ExtResource("3_v82a6")]

1
icon.svg Normal file
View File

@ -0,0 +1 @@
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>

After

Width:  |  Height:  |  Size: 950 B

37
icon.svg.import Normal file
View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bg5wwos0fgs03"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

78
player.gd Normal file
View File

@ -0,0 +1,78 @@
extends Area2D
# Maximum radial turning speed of the player
@export var turning_speed = PI/4 # (rad/sec)
# Maximum speed added to player's velocity per push
@export var skate_speed = 100 # (pixels/sec)
# Maximum speed deceleration while stopping
@export var braking_speed = 200 # (pixels/sec^2)
# "Natural" deceleration
@export var decel_ratio = 0.15 # (decel applied per second)
var velocity: Vector2
func _ready():
velocity = Vector2.ZERO
func _physics_process(delta: float):
# Flip sprite
if velocity.length() > 0:
$AnimatedSprite2D.flip_h = velocity.x > 0
# Update position
position = clamp_position(position + (velocity * delta))
# Decelerate naturally
# TODO fix vector math, need to apply to hypotenuse, not the sides
# TODO fix decel math, think compounding interest, it doesn't work this way
# TODO brake harder when almost stopped
velocity = velocity * (1 - decel_ratio * delta)
func push(effort: float, angle: float):
var delta_v = effort * skate_speed
velocity += delta_v * Vector2.from_angle(angle)
# TODO how to do doc comments?
# TODO should applying delta come from the controller or the player? It doesn't
# matter too much because these objects are pretty tightly coupled anyways.
func turn(effort: float, delta: float):
# Continuosly call with the effort while turning
# effort is +ve right, -ve left? maybe, some orientation
velocity = velocity.rotated(effort * turning_speed * delta)
func brake(effort: float, delta: float):
var delta_v = effort * braking_speed * delta
delta_v = min(delta_v, velocity.length())
velocity -= delta_v * velocity.normalized()
# TODO setup collision from world, and edges of arena, not the window
func clamp_position(new_pos: Vector2) -> Vector2:
var size = Vector2(get_window().size)
if new_pos.x > size.x:
if velocity.x > 0:
velocity.x = 0
new_pos.x = size.x
if new_pos.x < 0:
if velocity.x < 0:
velocity.x = 0
new_pos.x = 0
if new_pos.y > size.y:
if velocity.y > 0:
velocity.y = 0
new_pos.y = size.y
if new_pos.y < 0:
if velocity.y < 0:
velocity.y = 0
new_pos.y = 0
return new_pos

30
player.tscn Normal file
View File

@ -0,0 +1,30 @@
[gd_scene load_steps=5 format=3 uid="uid://b3llhcsie7y4u"]
[ext_resource type="Texture2D" uid="uid://bknjh6k2ocrri" path="res://Sprites/hockey_player.png" id="1_dtrap"]
[ext_resource type="Script" path="res://player.gd" id="1_gh3p0"]
[sub_resource type="SpriteFrames" id="SpriteFrames_oslmh"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": ExtResource("1_dtrap")
}],
"loop": true,
"name": &"default",
"speed": 5.0
}]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_exun0"]
size = Vector2(42, 108)
[node name="Player" type="Area2D"]
process_physics_priority = 1
script = ExtResource("1_gh3p0")
metadata/_edit_group_ = true
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
sprite_frames = SubResource("SpriteFrames_oslmh")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2(-7, -6)
shape = SubResource("RectangleShape2D_exun0")

85
player_controller.gd Normal file
View File

@ -0,0 +1,85 @@
extends Node
# Variables used by controller
@export var skate_push_start_len = 0.2
@export var skate_push_end_len = 0.9
@export var skate_min_time = 0.02
@export var skate_max_time = 0.1
@export var skate_max_turn_radius = PI / 8
@export var brake_deadzone = 0.3
var skate_occurred: bool
var time_for_push: float
var player_node: Node = null
# Called when the node enters the scene tree for the first time.
func _ready():
skate_occurred = false
time_for_push = 0
# Called every physics processing step
func _physics_process(delta):
if player_node == null:
# Don't call the processing functions if the player node isn't set
return
var joy = Input.get_vector("move_left", "move_right", "move_up", "move_down", 0)
handle_skate_push(joy, delta)
handle_turning(joy, delta)
handle_braking(joy, delta)
func set_player_node(node: Node):
player_node = node
func handle_skate_push(joy: Vector2, delta: float):
var pos = joy.length()
if pos >= skate_push_start_len and !skate_occurred:
time_for_push += delta
if pos >= skate_push_end_len and !skate_occurred:
if time_for_push >= skate_min_time and time_for_push <= skate_max_time:
var effort = 1 - time_for_push / skate_max_time
player_node.push(effort, joy.angle())
skate_occurred = true
elif pos < skate_push_start_len:
skate_occurred = false
time_for_push = 0
func handle_turning(joy: Vector2, delta: float):
if joy.length() < 0.95:
# Only turn if the stick is at the edge
return
# TODO this doesn't work well when you hit a wall
var radial_diff = player_node.velocity.angle_to(joy)
if (radial_diff >= PI/3):
# Only turn for roughlyone "half" of the stick. The other half is used for braking
return
var is_negative: bool = radial_diff < 0
var turn_effort = min(abs(radial_diff), skate_max_turn_radius) / skate_max_turn_radius
if is_negative:
turn_effort = -turn_effort
player_node.turn(turn_effort, delta)
func handle_braking(joy: Vector2, delta: float):
if joy.length() < brake_deadzone:
# Only brake past a certain amount
return
var radial_diff = player_node.velocity.angle_to(joy)
if (radial_diff < 3 * PI / 4):
# Only brake if controller is mostly facing away from velocity
return
player_node.brake(joy.length(), delta)

6
player_controller.tscn Normal file
View File

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://clntxmhd5uhlt"]
[ext_resource type="Script" path="res://player_controller.gd" id="1_fj1gd"]
[node name="PlayerController" type="Node"]
script = ExtResource("1_fj1gd")

39
project.godot Normal file
View File

@ -0,0 +1,39 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="Offside"
run/main_scene="res://game.tscn"
config/features=PackedStringArray("4.1", "Forward Plus")
config/icon="res://icon.svg"
[input]
move_left={
"deadzone": 0.5,
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
]
}
move_right={
"deadzone": 0.5,
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
]
}
move_up={
"deadzone": 0.5,
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
]
}
move_down={
"deadzone": 0.5,
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
]
}