Ruch statku
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 168 KiB |
@ -29,6 +29,25 @@ window/size/window_height_override=720
|
|||||||
window/stretch/mode="canvas_items"
|
window/stretch/mode="canvas_items"
|
||||||
window/stretch/aspect="expand"
|
window/stretch/aspect="expand"
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
ship_thrust={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"physical_keycode":87)]
|
||||||
|
}
|
||||||
|
ship_brake={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"physical_keycode":83)]
|
||||||
|
}
|
||||||
|
ship_turn_left={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"physical_keycode":65)]
|
||||||
|
}
|
||||||
|
ship_turn_right={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"physical_keycode":68)]
|
||||||
|
}
|
||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
enabled=PackedStringArray("res://addons/godot_mcp_toolkit/plugin.cfg")
|
enabled=PackedStringArray("res://addons/godot_mcp_toolkit/plugin.cfg")
|
||||||
|
|||||||
@ -1,13 +1,74 @@
|
|||||||
[gd_scene load_steps=2 format=3]
|
[gd_scene load_steps=9 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/game/game.gd" id="1"]
|
[ext_resource type="Script" path="res://scripts/game/game.gd" id="1_game"]
|
||||||
|
[ext_resource type="Script" path="res://scripts/game/space_level_background.gd" id="2_background"]
|
||||||
|
[ext_resource type="PackedScene" path="res://scenes/game/player_ship.tscn" id="3_player"]
|
||||||
|
[ext_resource type="Script" path="res://scripts/game/flight_hud.gd" id="4_hud"]
|
||||||
|
|
||||||
[node name="Game" type="Control"]
|
[sub_resource type="RectangleShape2D" id="TopWall"]
|
||||||
|
size = Vector2(5200, 40)
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="BottomWall"]
|
||||||
|
size = Vector2(5200, 40)
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="LeftWall"]
|
||||||
|
size = Vector2(40, 3600)
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RightWall"]
|
||||||
|
size = Vector2(40, 3600)
|
||||||
|
|
||||||
|
[node name="Game" type="Node2D"]
|
||||||
|
script = ExtResource("1_game")
|
||||||
|
|
||||||
|
[node name="SpaceBackground" type="Node2D" parent="."]
|
||||||
|
z_index = -20
|
||||||
|
script = ExtResource("2_background")
|
||||||
|
|
||||||
|
[node name="WorldBounds" type="StaticBody2D" parent="."]
|
||||||
|
collision_layer = 1
|
||||||
|
collision_mask = 0
|
||||||
|
|
||||||
|
[node name="TopWall" type="CollisionShape2D" parent="WorldBounds"]
|
||||||
|
position = Vector2(0, -1780)
|
||||||
|
shape = SubResource("TopWall")
|
||||||
|
|
||||||
|
[node name="BottomWall" type="CollisionShape2D" parent="WorldBounds"]
|
||||||
|
position = Vector2(0, 1780)
|
||||||
|
shape = SubResource("BottomWall")
|
||||||
|
|
||||||
|
[node name="LeftWall" type="CollisionShape2D" parent="WorldBounds"]
|
||||||
|
position = Vector2(-2580, 0)
|
||||||
|
shape = SubResource("LeftWall")
|
||||||
|
|
||||||
|
[node name="RightWall" type="CollisionShape2D" parent="WorldBounds"]
|
||||||
|
position = Vector2(2580, 0)
|
||||||
|
shape = SubResource("RightWall")
|
||||||
|
|
||||||
|
[node name="PlayerShip" parent="." instance=ExtResource("3_player")]
|
||||||
|
|
||||||
|
[node name="HUD" type="CanvasLayer" parent="."]
|
||||||
|
script = ExtResource("4_hud")
|
||||||
|
|
||||||
|
[node name="HUDRoot" type="Control" parent="HUD"]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
|
[node name="ReadoutBackground" type="ColorRect" parent="HUD/HUDRoot"]
|
||||||
|
offset_left = 18.0
|
||||||
|
offset_top = 18.0
|
||||||
|
offset_right = 292.0
|
||||||
|
offset_bottom = 166.0
|
||||||
|
color = Color(0.018, 0.045, 0.085, 0.86)
|
||||||
|
|
||||||
|
[node name="Readout" type="Label" parent="HUD/HUDRoot"]
|
||||||
|
offset_left = 32.0
|
||||||
|
offset_top = 28.0
|
||||||
|
offset_right = 278.0
|
||||||
|
offset_bottom = 156.0
|
||||||
|
theme_override_colors/font_color = Color(0.72, 0.88, 0.98, 1)
|
||||||
|
theme_override_font_sizes/font_size = 17
|
||||||
|
text = "W — ciąg S — hamulec\nA / D — płynny obrót\n\nPRĘDKOŚĆ 000 px/s\nPOZYCJA 0, 0"
|
||||||
|
|||||||
21
scenes/game/player_ship.tscn
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[gd_scene load_steps=3 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/game/ship_controller.gd" id="1_controller"]
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="ShipCollision"]
|
||||||
|
radius = 24.0
|
||||||
|
|
||||||
|
[node name="PlayerShip" type="CharacterBody2D"]
|
||||||
|
collision_layer = 2
|
||||||
|
collision_mask = 1
|
||||||
|
script = ExtResource("1_controller")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
texture_filter = 1
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("ShipCollision")
|
||||||
|
|
||||||
|
[node name="Camera2D" type="Camera2D" parent="."]
|
||||||
|
position_smoothing_enabled = true
|
||||||
|
position_smoothing_speed = 4.0
|
||||||
9
scripts/game/flight_hud.gd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
extends CanvasLayer
|
||||||
|
|
||||||
|
@onready var readout: Label = $HUDRoot/Readout
|
||||||
|
@onready var player: CharacterBody2D = get_parent().get_node("PlayerShip")
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
var speed := player.velocity.length()
|
||||||
|
var position := player.global_position
|
||||||
|
readout.text = "W — ciąg S — hamulec / wsteczny (50%)\nA / D — płynny obrót\n\nPRĘDKOŚĆ %03d px/s\nPOZYCJA %d, %d" % [roundi(speed), roundi(position.x), roundi(position.y)]
|
||||||
1
scripts/game/flight_hud.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bcfvflaqnmfa5
|
||||||
@ -1,25 +1,14 @@
|
|||||||
extends Control
|
extends Node2D
|
||||||
|
|
||||||
var ship_sprite: Sprite2D
|
const WORLD_SIZE := Vector2(5200.0, 3600.0)
|
||||||
|
|
||||||
|
@onready var player: CharacterBody2D = $PlayerShip
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if GameState.selected_ship_path.is_empty() or not ResourceLoader.exists(GameState.selected_ship_path):
|
# Keep the camera limits aligned with the test map if its size is tuned later.
|
||||||
push_warning("Nie wybrano statku do nowej gry.")
|
var camera := player.get_node_or_null("Camera2D") as Camera2D
|
||||||
return
|
if camera:
|
||||||
|
camera.limit_left = int(-WORLD_SIZE.x * 0.5)
|
||||||
var ship_texture := load(GameState.selected_ship_path) as Texture2D
|
camera.limit_right = int(WORLD_SIZE.x * 0.5)
|
||||||
if ship_texture == null:
|
camera.limit_top = int(-WORLD_SIZE.y * 0.5)
|
||||||
push_warning("Nie udało się wczytać wybranego statku.")
|
camera.limit_bottom = int(WORLD_SIZE.y * 0.5)
|
||||||
return
|
|
||||||
|
|
||||||
ship_sprite = Sprite2D.new()
|
|
||||||
ship_sprite.name = "PlayerShip"
|
|
||||||
ship_sprite.texture = ship_texture
|
|
||||||
add_child(ship_sprite)
|
|
||||||
_update_game_layout()
|
|
||||||
get_viewport().size_changed.connect(_update_game_layout)
|
|
||||||
|
|
||||||
func _update_game_layout() -> void:
|
|
||||||
if ship_sprite:
|
|
||||||
var viewport_size := get_viewport_rect().size
|
|
||||||
ship_sprite.position = viewport_size * 0.5
|
|
||||||
|
|||||||
71
scripts/game/ship_controller.gd
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
extends CharacterBody2D
|
||||||
|
|
||||||
|
const DEFAULT_SHIP_TEXTURE := "res://assets/Ships/Spaceship_0.png"
|
||||||
|
|
||||||
|
@export var max_speed := 420.0
|
||||||
|
@export var reverse_max_speed := 210.0
|
||||||
|
@export var thrust_acceleration := 260.0
|
||||||
|
@export var brake_acceleration := 540.0
|
||||||
|
@export var space_drag := 24.0
|
||||||
|
@export var max_turn_speed := 2.8
|
||||||
|
@export var turn_acceleration := 7.0
|
||||||
|
@export var turn_damping := 4.0
|
||||||
|
|
||||||
|
var angular_velocity := 0.0
|
||||||
|
var _sprite: Sprite2D
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_ensure_input_action(&"ship_thrust", KEY_W)
|
||||||
|
_ensure_input_action(&"ship_brake", KEY_S)
|
||||||
|
_ensure_input_action(&"ship_turn_left", KEY_A)
|
||||||
|
_ensure_input_action(&"ship_turn_right", KEY_D)
|
||||||
|
|
||||||
|
_sprite = $Sprite2D
|
||||||
|
var texture_path := GameState.selected_ship_path
|
||||||
|
if texture_path.is_empty() or not ResourceLoader.exists(texture_path):
|
||||||
|
texture_path = DEFAULT_SHIP_TEXTURE
|
||||||
|
|
||||||
|
var ship_texture := load(texture_path) as Texture2D
|
||||||
|
if ship_texture:
|
||||||
|
_sprite.texture = ship_texture
|
||||||
|
var largest_dimension := maxf(ship_texture.get_width(), ship_texture.get_height())
|
||||||
|
_sprite.scale = Vector2.ONE * (92.0 / largest_dimension)
|
||||||
|
|
||||||
|
func _ensure_input_action(action_name: StringName, physical_key: Key) -> void:
|
||||||
|
if not InputMap.has_action(action_name):
|
||||||
|
InputMap.add_action(action_name, 0.5)
|
||||||
|
var event := InputEventKey.new()
|
||||||
|
event.physical_keycode = physical_key
|
||||||
|
if not InputMap.action_has_event(action_name, event):
|
||||||
|
InputMap.action_add_event(action_name, event)
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
var turn_input := Input.get_axis("ship_turn_left", "ship_turn_right")
|
||||||
|
if not is_zero_approx(turn_input):
|
||||||
|
angular_velocity = move_toward(
|
||||||
|
angular_velocity,
|
||||||
|
turn_input * max_turn_speed,
|
||||||
|
turn_acceleration * delta
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
angular_velocity = move_toward(angular_velocity, 0.0, turn_damping * delta)
|
||||||
|
rotation += angular_velocity * delta
|
||||||
|
|
||||||
|
var forward := Vector2.UP.rotated(rotation)
|
||||||
|
if Input.is_action_pressed("ship_brake"):
|
||||||
|
if velocity.length_squared() > 1.0:
|
||||||
|
velocity = velocity.move_toward(Vector2.ZERO, brake_acceleration * delta)
|
||||||
|
else:
|
||||||
|
velocity -= forward * thrust_acceleration * delta
|
||||||
|
var reverse_speed := velocity.dot(forward)
|
||||||
|
if reverse_speed < -reverse_max_speed:
|
||||||
|
velocity += forward * (-reverse_max_speed - reverse_speed)
|
||||||
|
elif Input.is_action_pressed("ship_thrust"):
|
||||||
|
velocity += forward * thrust_acceleration * delta
|
||||||
|
var forward_speed := velocity.dot(forward)
|
||||||
|
if forward_speed > max_speed:
|
||||||
|
velocity += forward * (max_speed - forward_speed)
|
||||||
|
else:
|
||||||
|
velocity = velocity.move_toward(Vector2.ZERO, space_drag * delta)
|
||||||
|
|
||||||
|
move_and_slide()
|
||||||
1
scripts/game/ship_controller.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://b1sdo5uwspn5d
|
||||||
88
scripts/game/space_level_background.gd
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
const WORLD_SIZE := Vector2(5200.0, 3600.0)
|
||||||
|
const GRID_STEP := 320
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
var half_size := WORLD_SIZE * 0.5
|
||||||
|
draw_rect(Rect2(-half_size, WORLD_SIZE), Color("050b18"), true)
|
||||||
|
_draw_grid(half_size)
|
||||||
|
_draw_stars(half_size)
|
||||||
|
_draw_landmarks()
|
||||||
|
_draw_world_border(half_size)
|
||||||
|
|
||||||
|
func _draw_grid(half_size: Vector2) -> void:
|
||||||
|
for x in range(-2600, 2601, GRID_STEP):
|
||||||
|
var major := x % (GRID_STEP * 4) == 0
|
||||||
|
var color := Color(0.16, 0.28, 0.42, 0.2 if major else 0.075)
|
||||||
|
draw_line(Vector2(x, -half_size.y), Vector2(x, half_size.y), color, 1.0)
|
||||||
|
for y in range(-1800, 1801, GRID_STEP):
|
||||||
|
var major := y % (GRID_STEP * 4) == 0
|
||||||
|
var color := Color(0.16, 0.28, 0.42, 0.2 if major else 0.075)
|
||||||
|
draw_line(Vector2(-half_size.x, y), Vector2(half_size.x, y), color, 1.0)
|
||||||
|
|
||||||
|
func _draw_stars(half_size: Vector2) -> void:
|
||||||
|
var rng := RandomNumberGenerator.new()
|
||||||
|
rng.seed = 640_118
|
||||||
|
for index in 420:
|
||||||
|
var point := Vector2(
|
||||||
|
rng.randf_range(-half_size.x + 35.0, half_size.x - 35.0),
|
||||||
|
rng.randf_range(-half_size.y + 35.0, half_size.y - 35.0)
|
||||||
|
)
|
||||||
|
var radius := rng.randf_range(0.7, 2.0)
|
||||||
|
var alpha := rng.randf_range(0.2, 0.72)
|
||||||
|
var color := Color(0.58, 0.76, 1.0, alpha)
|
||||||
|
if index % 9 == 0:
|
||||||
|
color = Color(0.35, 0.88, 0.94, alpha)
|
||||||
|
draw_circle(point, radius, color)
|
||||||
|
|
||||||
|
func _draw_landmarks() -> void:
|
||||||
|
# Safe starting area around the spawn point.
|
||||||
|
draw_circle(Vector2.ZERO, 300.0, Color(0.08, 0.65, 0.72, 0.035))
|
||||||
|
draw_arc(Vector2.ZERO, 300.0, 0.0, TAU, 96, Color(0.16, 0.78, 0.84, 0.32), 2.0)
|
||||||
|
_draw_label(Vector2(28, -316), "STREFA STARTOWA", Color(0.38, 0.81, 0.87, 0.78))
|
||||||
|
|
||||||
|
_draw_planet(Vector2(-1420, -760), 150.0, Color("e9904e"), "HELION")
|
||||||
|
_draw_planet(Vector2(1420, -940), 112.0, Color("397fa9"), "NEREIDA")
|
||||||
|
_draw_planet(Vector2(1110, 1170), 86.0, Color("8d6cbb"), "VESPER")
|
||||||
|
_draw_planet(Vector2(-1580, 1120), 72.0, Color("72a58b"), "TUBYLCY")
|
||||||
|
_draw_asteroid_field(Vector2(420, 160), 400.0, 34, 9_183)
|
||||||
|
_draw_asteroid_field(Vector2(-930, 460), 270.0, 22, 3_277)
|
||||||
|
_draw_navigation_beacon(Vector2(520, -190))
|
||||||
|
|
||||||
|
func _draw_navigation_beacon(center: Vector2) -> void:
|
||||||
|
draw_circle(center, 58.0, Color(0.1, 0.72, 0.86, 0.07))
|
||||||
|
draw_arc(center, 44.0, 0.0, TAU, 64, Color(0.25, 0.82, 0.9, 0.75), 2.0)
|
||||||
|
draw_arc(center, 31.0, 0.0, TAU, 64, Color(0.25, 0.82, 0.9, 0.4), 1.0)
|
||||||
|
draw_line(center + Vector2(-54, 0), center + Vector2(54, 0), Color(0.25, 0.82, 0.9, 0.6), 1.0)
|
||||||
|
draw_line(center + Vector2(0, -54), center + Vector2(0, 54), Color(0.25, 0.82, 0.9, 0.6), 1.0)
|
||||||
|
draw_circle(center, 12.0, Color(0.35, 0.92, 1.0, 0.9))
|
||||||
|
_draw_label(center + Vector2(-88, 78), "BOJA NAWIGACYJNA", Color(0.45, 0.83, 0.9, 0.82))
|
||||||
|
|
||||||
|
func _draw_planet(center: Vector2, radius: float, color: Color, label: String) -> void:
|
||||||
|
draw_circle(center, radius * 1.55, Color(color.r, color.g, color.b, 0.055))
|
||||||
|
draw_arc(center, radius * 1.42, 0.0, TAU, 96, Color(color.r, color.g, color.b, 0.2), 2.0)
|
||||||
|
draw_circle(center, radius, color.darkened(0.48))
|
||||||
|
draw_circle(center + Vector2(-radius * 0.22, -radius * 0.24), radius * 0.68, color.darkened(0.15))
|
||||||
|
draw_arc(center, radius * 1.26, deg_to_rad(-18), deg_to_rad(205), 64, Color(0.64, 0.79, 0.91, 0.55), 5.0)
|
||||||
|
_draw_label(center + Vector2(-radius, radius + 34.0), label, Color(0.77, 0.85, 0.95, 0.76))
|
||||||
|
|
||||||
|
func _draw_asteroid_field(center: Vector2, spread: float, count: int, seed_value: int) -> void:
|
||||||
|
var rng := RandomNumberGenerator.new()
|
||||||
|
rng.seed = seed_value
|
||||||
|
for index in count:
|
||||||
|
var angle := rng.randf_range(0.0, TAU)
|
||||||
|
var distance := sqrt(rng.randf()) * spread
|
||||||
|
var point := center + Vector2.RIGHT.rotated(angle) * distance
|
||||||
|
var size := rng.randf_range(5.0, 15.0)
|
||||||
|
var color := Color(0.42, 0.53, 0.65, rng.randf_range(0.35, 0.75))
|
||||||
|
draw_circle(point, size, color)
|
||||||
|
draw_circle(point + Vector2(-size * 0.25, -size * 0.25), size * 0.55, color.lightened(0.18))
|
||||||
|
|
||||||
|
func _draw_world_border(half_size: Vector2) -> void:
|
||||||
|
var bounds := Rect2(-half_size, WORLD_SIZE)
|
||||||
|
draw_rect(bounds, Color(0.12, 0.52, 0.68, 0.48), false, 3.0)
|
||||||
|
_draw_label(Vector2(-half_size.x + 22.0, -half_size.y + 38.0), "SEKTOR TESTOWY 01 / 5200 × 3600", Color(0.4, 0.7, 0.8, 0.7))
|
||||||
|
|
||||||
|
func _draw_label(position: Vector2, text: String, color: Color) -> void:
|
||||||
|
draw_string(ThemeDB.fallback_font, position, text, HORIZONTAL_ALIGNMENT_LEFT, -1.0, 18, color)
|
||||||
1
scripts/game/space_level_background.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://b20w2c0ucytmg
|
||||||