Compare commits

..

6 Commits

Author SHA1 Message Date
a3ef6f5328 floating tile detection 2024-12-04 16:17:31 +01:00
32ccd05d9d kleine änderungen 2024-12-04 12:17:13 +01:00
bb7dbb054a local Multiplayer support 2024-12-04 08:48:48 +01:00
15be351c86 Add README.md 2024-12-03 21:02:08 +01:00
28462f4c0d Controller Support added 2024-12-03 21:01:00 +01:00
af0a145953 Sprengen funktioniert 2024-12-03 20:16:17 +01:00
18 changed files with 2226 additions and 66 deletions

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# Bomber-Thorsten
Ein sehr cooles Spiel
- Local Multiplayer support

60
bomb.gd
View File

@@ -1,7 +1,7 @@
extends RigidBody2D
@export var speed = 400
@export var explosion_damage = 2000
@export var explosion_damage = 600
var velocity = Vector2.ZERO
var is_in_flight = false
@@ -37,10 +37,6 @@ func _process(delta: float) -> void:
if is_off_screen() and not has_exploded:
trigger_explosion()
# Check for spacebar press to explode, only if the bomb hasn't exploded
if Input.is_action_just_pressed("throw_bomb") and not has_exploded:
trigger_explosion()
# This function is used to set the velocity of the bomb when its thrown
func set_velocity(new_velocity: Vector2) -> void:
# Apply an impulse based on the new velocity
@@ -69,6 +65,8 @@ func trigger_explosion():
# Destroy tiles in the explosion radius
destroy_tiles_in_explosion_area()
tile_map_layer.detect_and_make_tiles_fall()
# Start the timer to cleanup the explosion
timer.start()
@@ -93,39 +91,41 @@ func push_away_players():
body.apply_central_impulse(impulse)
func destroy_tiles_in_explosion_area():
var center = global_position # This is the center of the explosion in global coordinates
var radius = 30 # The radius of the explosion
# Convert center to map coordinates, taking scale into account
var center = global_position # Explosion center in global coordinates
var radius = 150 # Explosion radius in pixels
# Convert center to map coordinates
var map_center = tile_map_layer.local_to_map(center)
print("Center: ", map_center)
# Get the scale factor of the TileMapLayer
var scale = tile_map_layer.scale.x # Assuming uniform scale for both x and y
print("Explosion center in map coordinates:", center, map_center)
# Tile dimensions
var tile_width = 16
var tile_height = 16
# Get the bounding box for the explosion area in map coordinates
var min_x = int((map_center.x - radius * tile_width) / tile_width)
var max_x = int((map_center.x + radius * tile_width) / tile_width)
var min_y = int((map_center.y - radius * tile_height) / tile_height)
var max_y = int((map_center.y + radius * tile_height) / tile_height)
# Loop through all cells in the bounding box
# Calculate bounds of explosion in tile coordinates
var min_x = int((center.x - radius) / tile_width)
var max_x = int((center.x + radius) / tile_width)
var min_y = int((center.y - radius) / tile_height)
var max_y = int((center.y + radius) / tile_height)
print("Explosion bounds in tile coordinates: ", Vector2i(min_x, min_y), Vector2i(max_x, max_y))
# Loop through the affected tiles
for x in range(min_x, max_x + 1):
for y in range(min_y, max_y + 1):
# Calculate distance from the center of the explosion (map coordinates)
var dist = map_center.distance_to(Vector2(x, y))
# Check if the tile is within the explosion radius (using the distance check)
# Calculate the distance from the explosion center to the tile center
var tile_pos = tile_map_layer.map_to_local(Vector2i(x, y))
var dist = center.distance_to(tile_pos)
# Check if the tile is within the explosion radius
if dist <= radius:
# Print out some debug information
print("Checking tile:", Vector2i(x, y), "Distance:", dist)
# Check if the tile is within the bounds of the map and not empty
print("Checking tile at:", Vector2i(x, y), "Distance:", dist)
print(tile_map_layer.get_cell_source_id(Vector2i(x, y)))
# Erase the tile if it exists
if tile_map_layer.get_cell_source_id(Vector2i(x, y)) != -1:
# Erase the tile at coordinates (x, y) in map coordinates
tile_map_layer.erase_cell(Vector2i(x, y))
print("Erased tile at:", Vector2i(x, y))
# Function to check if the bomb is off-screen

41
export_presets.cfg Normal file
View File

@@ -0,0 +1,41 @@
[preset.0]
name="Web"
platform="Web"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../export/Bomber-Thorsten.html"
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.0.options]
custom_template/debug=""
custom_template/release=""
variant/extensions_support=false
variant/thread_support=false
vram_texture_compression/for_desktop=true
vram_texture_compression/for_mobile=false
html/export_icon=true
html/custom_html_shell=""
html/head_include=""
html/canvas_resize_policy=2
html/focus_canvas_on_start=true
html/experimental_virtual_keyboard=false
progressive_web_app/enabled=false
progressive_web_app/ensure_cross_origin_isolation_headers=true
progressive_web_app/offline_page=""
progressive_web_app/display=1
progressive_web_app/orientation=0
progressive_web_app/icon_144x144=""
progressive_web_app/icon_180x180=""
progressive_web_app/icon_512x512=""
progressive_web_app/background_color=Color(0, 0, 0, 1)

12
global.gd Normal file
View File

@@ -0,0 +1,12 @@
extends Node
var player_ids = []
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass

23
lob4F13.tmp Normal file
View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=2 format=3 uid="uid://l4sh5qah5jln"]
[ext_resource type="Script" path="res://lobby.gd" id="1_p5ww4"]
[node name="Lobby" type="Control"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("1_p5ww4")
[node name="PlayerList" type="VBoxContainer" parent="."]
layout_mode = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="StartButton" type="Button" parent="."]
layout_mode = 2
offset_left = 47.0
offset_top = 12.0
offset_right = 87.0
offset_bottom = 20.0
text = "Start"

23
lob5137.tmp Normal file
View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=2 format=3 uid="uid://l4sh5qah5jln"]
[ext_resource type="Script" path="res://lobby.gd" id="1_p5ww4"]
[node name="Lobby" type="Control"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("1_p5ww4")
[node name="PlayerList" type="VBoxContainer" parent="."]
layout_mode = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="StartButton" type="Button" parent="."]
layout_mode = 2
offset_left = 47.0
offset_top = 12.0
offset_right = 87.0
offset_bottom = 20.0
text = "Start"

23
lob7BAA.tmp Normal file
View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=2 format=3 uid="uid://l4sh5qah5jln"]
[ext_resource type="Script" path="res://lobby.gd" id="1_p5ww4"]
[node name="Lobby" type="Control"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("1_p5ww4")
[node name="PlayerList" type="VBoxContainer" parent="."]
layout_mode = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="StartButton" type="Button" parent="."]
layout_mode = 2
offset_left = 47.0
offset_top = 12.0
offset_right = 87.0
offset_bottom = 20.0
text = "Start"

23
lobB0BD.tmp Normal file
View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=2 format=3 uid="uid://l4sh5qah5jln"]
[ext_resource type="Script" path="res://lobby.gd" id="1_p5ww4"]
[node name="Lobby" type="Control"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("1_p5ww4")
[node name="PlayerList" type="VBoxContainer" parent="."]
layout_mode = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="StartButton" type="Button" parent="."]
layout_mode = 2
offset_left = 47.0
offset_top = 12.0
offset_right = 87.0
offset_bottom = 20.0
text = "Start"

51
lobby.gd Normal file
View File

@@ -0,0 +1,51 @@
extends Control
@export var max_players = 4
const game_scene = "res://main.tscn" # Path to the main game scene
var ready_states = {} # Dictionary to track ready states for each player ID
@onready var player_list = $PlayerList
@onready var start_button = $StartButton
func _ready() -> void:
start_button.disabled = true
start_button.connect("pressed", _on_start_game)
func _process(delta: float) -> void:
# Handle player joining
if (Input.is_action_just_pressed("throw_bomb")):
add_player(-1) # -1 for keyboard
for i in range(0, 7): # 0-7 for controllers
if (i >= 0 and Input.is_joy_button_pressed(i, JOY_BUTTON_A)):
add_player(i)
func add_player(input_id: int) -> void:
# Prevent duplicate players
if input_id in Global.player_ids:
return
if len(Global.player_ids) >= max_players:
return # Max players reached
# Add player to the list
Global.player_ids.append(input_id)
# Create a new label to display the player ID
var label = Label.new()
label.text = "Player ID: %d" % input_id
player_list.add_child(label)
# Track ready state for the player
ready_states[input_id] = false
# Update the start button state
check_all_ready()
func check_all_ready() -> void:
# Enable the start button if at least one player has joined
start_button.disabled = len(Global.player_ids) == 0
func _on_start_game() -> void:
get_tree().change_scene_to_file(game_scene)

41
lobby.tscn Normal file
View File

@@ -0,0 +1,41 @@
[gd_scene load_steps=2 format=3 uid="uid://l4sh5qah5jln"]
[ext_resource type="Script" path="res://lobby.gd" id="1_p5ww4"]
[node name="Lobby" type="Control"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("1_p5ww4")
[node name="PlayerList" type="VBoxContainer" parent="."]
layout_mode = 0
offset_left = 531.0
offset_top = 168.0
offset_right = 648.0
offset_bottom = 382.0
[node name="StartButton" type="Button" parent="."]
layout_mode = 2
offset_left = 516.0
offset_top = 464.0
offset_right = 666.0
offset_bottom = 511.0
text = "Start"
[node name="Label" type="Label" parent="."]
layout_mode = 0
offset_left = 514.0
offset_top = 88.0
offset_right = 651.0
offset_bottom = 111.0
text = "Bomber-Thorsten"
[node name="Label2" type="Label" parent="."]
layout_mode = 0
offset_left = 530.0
offset_top = 614.0
offset_right = 660.0
offset_bottom = 637.0
text = "www.it-thaler.de"

758
mai5410.tmp Normal file

File diff suppressed because one or more lines are too long

758
mai9FEE.tmp Normal file

File diff suppressed because one or more lines are too long

16
main.gd
View File

@@ -1,9 +1,21 @@
extends Node2D
@export var player_scene = preload("res://player.tscn")
@onready var spawn_points = $PlayerSpawnPoints.get_children()
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
$MultiTargetCamera.add_target($Player)
func _ready() -> void:
# Spawn players at designated spawn points
for i in range(len(Global.player_ids)):
if i >= spawn_points.size():
break # Ensure we don't exceed available spawn points
var player_instance = player_scene.instantiate()
player_instance.set_input_id(Global.player_ids[i]) # Assign the input ID to the player
player_instance.global_position = spawn_points[i].global_position
$MultiTargetCamera.add_target(player_instance)
print(Global.player_ids[i])
add_child(player_instance)
# Called every frame. 'delta' is the elapsed time since the previous frame.

290
main.tscn

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,7 @@ extends RigidBody2D
@export var speed = 400
@export var Bomb = load("res://bomb.tscn")
@export var max_power = 1000 # Maximum throw power
@export var charge_rate = 500 # Power increase per second
@export var charge_rate = 900 # Power increase per second
@export var line_start_offset = 30 # Distance from the player where the line starts (in pixels)
@export var gravity = 800.0 # Gravity force (pixels per second squared)
@@ -12,15 +12,23 @@ extends RigidBody2D
@export var friction = 5
@export var max_speed = 500.0
var input_id = -1 # Default to keyboard (-1). Set to controller ID for multiplayer.
var charging = false
var current_power = 0.0
var direction = Vector2(2, -2) # Default direction, can be modified for aiming
var bomb = null # Global bomb reference
var aim_direction = Vector2(1, -1) # Default aiming direction
@onready var velocity_label = $Label
@onready var label = $Label
@onready var line_indicator = $Line2D # Reference to the Line2D node
# Dead zone for joystick input
var dead_zone = 0.2
func _ready() -> void:
label.text = str(input_id)
# Set the initial points for the Line2D to indicate the starting vector
line_indicator.clear_points()
line_indicator.add_point(Vector2.ZERO) # Starting point at the player
@@ -29,53 +37,65 @@ func _ready() -> void:
func _process(delta: float) -> void:
if position.y > 2000:
get_tree().reload_current_scene()
# Start charging when "throw_bomb" is pressed
if Input.is_action_pressed("throw_bomb") and (!bomb or !is_instance_valid(bomb)):
update_aim_direction() # Continuously update aiming direction
# Start charging when "throw_bomb" is pressed (either button or key)
if is_throwing_input_pressed() and (!bomb or !is_instance_valid(bomb)):
charging = true
current_power += charge_rate * delta
current_power = min(current_power, max_power) # Cap power at max_power
# Update velocity on the label
velocity_label.text = "Power: " + str(current_power)
# Calculate the direction based on the input (for example, using the mouse position or joystick)
var aim_direction = (get_global_mouse_position() - global_position).normalized()
# Set the start position of the line a bit away from the player
var start_position = aim_direction * line_start_offset
# Update the Line2D to visualize the throw direction and power
var end_point = start_position + (aim_direction * current_power / 10)
#line_indicator.set_point_position(1, end_point) # Set the ending point of the vector
line_indicator.set_point_position(0, start_position) # Set the starting point of the vector
line_indicator.set_point_position(1, end_point) # Set the ending point of the vector
elif Input.is_action_just_released("throw_bomb") and charging:
elif is_throwing_input_pressed() and is_instance_valid(bomb):
bomb.trigger_explosion()
elif not is_throwing_input_pressed() and charging:
# Throw bomb when the action is released
throw_bomb(current_power)
charging = false
throw_bomb(current_power)
current_power = 0.0 # Reset power
# Reset Line2D to initial state after release
line_indicator.set_point_position(0, Vector2.ZERO)
line_indicator.set_point_position(1, Vector2.ZERO)
func update_aim_direction():
if input_id == -1: # Keyboard/Mouse
aim_direction = (get_global_mouse_position() - global_position).normalized()
else: # Controller
var joy_x = Input.get_joy_axis(input_id, JOY_AXIS_LEFT_X)
var joy_y = Input.get_joy_axis(input_id, JOY_AXIS_LEFT_Y)
# Apply dead zone
if abs(joy_x) > dead_zone or abs(joy_y) > dead_zone:
aim_direction = Vector2(joy_x, joy_y).normalized()
func is_throwing_input_pressed() -> bool:
if input_id == -1: # Keyboard/Mouse
return Input.is_action_pressed("throw_bomb")
else: # Controller (use A button for throwing)
return Input.is_joy_button_pressed(input_id, JOY_BUTTON_A)
func throw_bomb(power: float):
# Check if there is no bomb or if the current bomb instance is invalid
if !bomb or !is_instance_valid(bomb):
# Instantiate the bomb
bomb = Bomb.instantiate() # Use global bomb reference
bomb.position = global_position
# Calculate the direction based on the mouse position
var aim_direction = (get_global_mouse_position() - global_position).normalized()
# Set the velocity for the bomb: direction * power
var launch_velocity = aim_direction * power * 2
bomb.set_velocity(launch_velocity)
# Add the bomb to the scene
add_child(bomb)
# Clear velocity display after throwing (optional)
velocity_label.text = "Power: 0"
func set_input_id(id: int) -> void:
input_id = id

View File

@@ -74,10 +74,10 @@ shape = SubResource("CapsuleShape2D_ogije")
one_way_collision_margin = 32.1
[node name="Label" type="Label" parent="."]
offset_left = 38.0
offset_top = 7.0
offset_right = 78.0
offset_bottom = 30.0
offset_left = -19.0
offset_top = -14.0
offset_right = 21.0
offset_bottom = 9.0
[node name="Line2D" type="Line2D" parent="."]
scale = Vector2(2, 2)

View File

@@ -11,10 +11,14 @@ config_version=5
[application]
config/name="Bomber-Thorsten"
run/main_scene="res://main.tscn"
run/main_scene="res://lobby.tscn"
config/features=PackedStringArray("4.3")
config/icon="res://icon.svg"
[autoload]
Global="*res://global.gd"
[input]
throw_bomb={

94
tile_map_layer.gd Normal file
View File

@@ -0,0 +1,94 @@
extends TileMapLayer
# Detect and make tiles fall
func detect_and_make_tiles_fall():
var all_tiles = get_used_cells()
var grounded_tiles = get_grounded_tiles()
print("Grounded tiles:", grounded_tiles)
var floating_tiles = []
for tile in all_tiles:
if tile not in grounded_tiles:
floating_tiles.append(tile)
print("Floating tiles:", floating_tiles)
for tile_pos in floating_tiles:
make_tile_fall(tile_pos)
# Returns all the grounded tiles (tiles connected to the bottom-most tiles)
func get_grounded_tiles() -> Array:
var grounded_tiles = []
var bottom_y = get_bottom_y() # Identify the bottom-most y coordinate
print("Bottom y:", bottom_y)
# Get all tiles at the bottom-most y-coordinate
var bottom_tiles = []
for tile in get_used_cells():
if tile.y == bottom_y:
bottom_tiles.append(tile)
print("Bottom tiles:", bottom_tiles)
# Traverse all tiles connected to the bottom-most tiles (iteratively)
var visited = {} # Dictionary to track visited tiles
var queue = bottom_tiles.duplicate() # Initialize the queue with bottom-most tiles
while queue.size() > 0:
var current = queue.pop_front() # Get the next tile to process
# Skip if already visited
if visited.has(current):
continue
visited[current] = true # Mark as visited
grounded_tiles.append(current) # Add to grounded tiles
# Check neighboring tiles (up, down, left, right)
var neighbors = [
current + Vector2i(1, 0), # Right
current + Vector2i(-1, 0), # Left
current + Vector2i(0, 1), # Down (already checked for bottom-most)
current + Vector2i(0, -1) # Up
]
for neighbor in neighbors:
if has_tile(neighbor) and not visited.has(neighbor):
queue.append(neighbor) # Add unvisited neighboring tile to the queue
return grounded_tiles
# Function to get the lowest y-coordinate of tiles in the map
func get_bottom_y() -> int:
var bottom_y = -1
for tile in get_used_cells():
if tile.y > bottom_y:
bottom_y = tile.y # Keep track of the largest y value (lowest tile)
return bottom_y
# Check if a specific tile exists at the given coordinates
func has_tile(coords: Vector2i) -> bool:
return get_cell_source_id(coords) != -1
# Make a tile fall by erasing it and placing it below
func make_tile_fall(coords: Vector2i) -> void:
var source_id = get_cell_source_id(coords) # Get the source ID of the tile
var atlas_coords = get_cell_atlas_coords(coords) # Get the atlas coordinates
var below_coords = coords + Vector2i(0, 1) # Position where the tile will fall
# Erase the current tile
erase_cell(coords)
# Place the tile one step below
#set_cell(below_coords, source_id, atlas_coords)
func _ready():
# Automatically call the function to test it when the scene runs
detect_and_make_tiles_fall()