diff options
Diffstat (limited to 'Towers')
| -rw-r--r-- | Towers/Components/AttackComponent.gd | 77 | ||||
| -rw-r--r-- | Towers/Components/BurnComponent.gd | 2 | ||||
| -rw-r--r-- | Towers/Components/FrostComponent.gd | 2 | ||||
| -rw-r--r-- | Towers/Components/RangeComponent.gd | 52 | ||||
| -rw-r--r-- | Towers/Components/TowerComponent.gd | 48 | ||||
| -rw-r--r-- | Towers/Tower.gd | 154 | ||||
| -rw-r--r-- | Towers/Tower.tscn | 15 | 
7 files changed, 266 insertions, 84 deletions
| diff --git a/Towers/Components/AttackComponent.gd b/Towers/Components/AttackComponent.gd new file mode 100644 index 0000000..c7660cf --- /dev/null +++ b/Towers/Components/AttackComponent.gd @@ -0,0 +1,77 @@ +class_name AttackTowerComponent +extends TowerComponent + + +var power := 1 + +var speed_base := 1.0 +var speed := 1 + +var shoot_cooldown := Timer.new() +var shoot_sound := AudioStreamPlayer2D.new() + +@export var range_component: RangeTowerComponent: +	get(): +		return current_tower.components[ComponentType.Range] + + +func _init() -> void: +	type = ComponentType.Attack +	set_sprite(preload("res://Towers/Components/Assets/attack-component.png")) +	 +	update_power() +	update_speed() +	level_changed.connect(update_power) +	level_changed.connect(update_speed) + + +func update_power(): +	power = ceil(level / 2.0) + +func update_speed(): +	speed = level - ceil(level / 2.0) +	shoot_cooldown.wait_time = speed_base / speed + +func update_range(): +	shoot_sound.max_distance = range_component.range * Client.current_stage.map.tile_set.tile_size.x + + +func on_add(tower: Tower): +	super.on_add(tower) +	 +	shoot_cooldown.one_shot = true +	tower.add_child(shoot_cooldown) +	 +	shoot_sound.stream = preload("res://Towers/Assets/shoot.ogg") +	tower.add_child(shoot_sound) +	 +	update_range() +	range_component.range_changed.connect(update_range) + + +func process(_delta: float): +	if shoot_cooldown.is_stopped() and not range_component.units_in_range.is_empty(): +		shoot() +		shoot_cooldown.start() + + +func shoot(): +	var target = range_component.units_in_range[0] +	 +	for component in current_tower.components.values(): +		if component.has_method("on_shoot"): +			component.on_shoot(target) +	 +	shoot_fx.rpc() +	 +	if is_melee_range(): +		target.set_hp(target.hp - 1) +	else: # TODO +		target.set_hp(target.hp - 1) + +@rpc("authority", "call_local") +func shoot_fx(): +	shoot_sound.play() + +func is_melee_range(): +	return range_component.range <= (Client.current_stage.map.tile_set.tile_size.x * 2) diff --git a/Towers/Components/BurnComponent.gd b/Towers/Components/BurnComponent.gd index 96c24f7..d708d4f 100644 --- a/Towers/Components/BurnComponent.gd +++ b/Towers/Components/BurnComponent.gd @@ -2,7 +2,7 @@ extends TowerComponent  func _init() -> void: -	name = "Burn" +	type = ComponentType.Burn  	set_sprite(preload("res://Towers/Components/Assets/burn-component.png")) diff --git a/Towers/Components/FrostComponent.gd b/Towers/Components/FrostComponent.gd index 473baf6..2443b70 100644 --- a/Towers/Components/FrostComponent.gd +++ b/Towers/Components/FrostComponent.gd @@ -2,7 +2,7 @@ extends TowerComponent  func _init() -> void: -	name = "Frost" +	type = ComponentType.Frost  	set_sprite(preload("res://Towers/Components/Assets/frost-component.png")) diff --git a/Towers/Components/RangeComponent.gd b/Towers/Components/RangeComponent.gd new file mode 100644 index 0000000..a2f7ae7 --- /dev/null +++ b/Towers/Components/RangeComponent.gd @@ -0,0 +1,52 @@ +class_name RangeTowerComponent +extends TowerComponent + + +signal range_changed +@warning_ignore("shadowed_global_identifier") +var range := 0: +	set(value): +		range = value +		range_changed.emit() + +var area := Area2D.new() +var collision_shape := CollisionShape2D.new() +var shape := CircleShape2D.new() + +var units_in_range: Array[Unit] + + +func _init() -> void: +	type = ComponentType.Range +	set_sprite(preload("res://Towers/Components/Assets/range-component.png")) +	 +	update_range() +	level_changed.connect(update_range) + + +func update_range(): +	var tile_size = Client.current_stage.map.tile_set.tile_size.x +	@warning_ignore("integer_division") +	range = (tile_size * 2) + ((tile_size / 2) * level) +	shape.radius = range + + +func on_add(tower: Tower): +	super.on_add(tower) +	 +	area.set_collision_layer_value(1, false) +	area.set_collision_mask_value(1, true) +	 +	area.body_entered.connect(func(body: Node2D): +		units_in_range.append(body) +	) +	area.body_exited.connect(func(body: Node2D): +		units_in_range.erase(body) +	) +	 +	area.position = tower.get_node("CenterAnchor").position +	 +	collision_shape.shape = shape +	area.add_child(collision_shape) +	 +	tower.add_child(area) diff --git a/Towers/Components/TowerComponent.gd b/Towers/Components/TowerComponent.gd index 609f88c..7ca766a 100644 --- a/Towers/Components/TowerComponent.gd +++ b/Towers/Components/TowerComponent.gd @@ -1,30 +1,58 @@  class_name TowerComponent -extends Resource +extends Node -var name: String -var sprite: Sprite2D = Sprite2D.new() -var level: int = 1 +var current_tower: Tower + +enum ComponentType { +	Range, +	Attack, +	Speed, +	Frost, +	Burn, +	Poison, +} + +var type: ComponentType +var sprite: TextureRect = TextureRect.new() + +var id: String: +	get(): +		return get_type_name() + +signal level_changed +var level: int = 1: +	set(value): +		level = value +		level_changed.emit()  func set_sprite(texture: Texture2D):  	sprite.texture = texture  	sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST -	sprite.centered = false -	sprite.scale = Vector2(2, 2) -	sprite.name = name +	#sprite.centered = false +	sprite.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED +	#sprite.scale = Vector2(2, 2) +	sprite.name = get_type_name() + + +func get_type_name(component_type: ComponentType = type): +	return ComponentType.keys()[component_type] + +func on_add(tower: Tower): +	current_tower = tower  class NetworkData extends Resource: -	var name: String +	var type: ComponentType  	var level: int  func to_network_data() -> NetworkData:  	var data = NetworkData.new() -	data.name = name +	data.type = type  	data.level = level  	return data @@ -35,7 +63,7 @@ func update_with_network_data(_data: NetworkData):  static func from_network_data(data: NetworkData) -> TowerComponent:  	var component = preload("res://Towers/Components/TowerComponent.gd").new() -	component.name = data.name +	component.type = data.type  	component.level = data.level  	return component diff --git a/Towers/Tower.gd b/Towers/Tower.gd index 187cd93..1d856f3 100644 --- a/Towers/Tower.gd +++ b/Towers/Tower.gd @@ -40,7 +40,7 @@ var is_highlighted := false:  		is_highlighted = value  		queue_redraw() -var mobs_in_range: Array = [] +#var mobs_in_range: Array = []  #var selection_area: Area2D @@ -54,22 +54,22 @@ signal selection_group_id_changed(previous_id: String)  # rpc owner id  @export var owner_id = 1 -@export var attack_range: int = 32: -	set(value): -		attack_range = value -		$Range/CollisionShape2D.shape.radius = attack_range -		$SoundShoot.max_distance = attack_range * Client.current_stage.map.tile_set.tile_size.x +#@export var attack_range: int = 32: +	#set(value): +		#attack_range = value +		#$Range/CollisionShape2D.shape.radius = attack_range +		#$SoundShoot.max_distance = attack_range * Client.current_stage.map.tile_set.tile_size.x -@export var attack_power: int = 1 +#@export var attack_power: int = 1 -var attack_speed_base: float = 2.0 -@export var attack_speed: int = 1: -	set(value): -		attack_speed = value -		%ShootCooldown.wait_time = attack_speed_base / attack_speed +#var attack_speed_base: float = 2.0 +#@export var attack_speed: int = 1: +	#set(value): +		#attack_speed = value +		#%ShootCooldown.wait_time = attack_speed_base / attack_speed  signal components_changed -@export var components: Array[TowerComponent] = [] +@export var components: Dictionary  func _init(): @@ -79,6 +79,9 @@ func _init():  func _ready():  	$AnimatedSprite2D.play() +	for component in [RangeTowerComponent.new(), AttackTowerComponent.new()]: +		add_component(component) +	  	redraw_components()  	components_changed.connect(func():  		selection_group_id = get_group_id() @@ -92,7 +95,7 @@ func _draw():  		if Client.state is StateDefault:  			draw_circle(  				Vector2(Client.current_stage.map.tile_set.tile_size) / scale, -				8 + attack_range, +				8 + components.get(TowerComponent.ComponentType.Range).range,  				Color(1, 1, 1, 0.5),  				false,  				1.0 @@ -112,11 +115,15 @@ func _draw():  		) -func _process(_delta: float) -> void: +func _process(delta: float) -> void:  	if multiplayer.is_server(): -		if $ShootCooldown.is_stopped() and not mobs_in_range.is_empty(): -			shoot() -			$ShootCooldown.start() +		for component in components.values(): +			if component.has_method("process"): +				component.process(delta) +		 +		#if $ShootCooldown.is_stopped() and not mobs_in_range.is_empty(): +			#shoot() +			#$ShootCooldown.start()  	#if selection_area and is_instance_valid(selection_area):  		#var bodies = selection_area.get_overlapping_bodies() @@ -139,11 +146,11 @@ func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int):  			Client.remove_tower(self) -func _on_range_body_entered(body: Node2D) -> void: -	mobs_in_range.append(body) - -func _on_range_body_exited(body: Node2D) -> void: -	mobs_in_range.erase(body) +#func _on_range_body_entered(body: Node2D) -> void: +	#mobs_in_range.append(body) +# +#func _on_range_body_exited(body: Node2D) -> void: +	#mobs_in_range.erase(body)  func _on_selectable_area_hover_enter() -> void: @@ -168,49 +175,56 @@ func _on_selectable_area_select_primary(event: InputEvent) -> void:  func add_component(component: TowerComponent): -	components.append(component) +	components[component.type] = component +	component.on_add(self) +	  	var sprite = component.sprite -	$ComponentsAnchor.add_child(sprite) +	%ComponentsAnchor.add_child(sprite)  	redraw_components() +	  	components_changed.emit() -func remove_component(component_name: String): -	for component in components: -		if component.name == component_name: -			components.erase(component) -			$ComponentsAnchor.remove_child($ComponentsAnchor.get_node(NodePath(component.name))) -			break +func remove_component(component: TowerComponent): +	components.erase(component.type) +	%ComponentsAnchor.remove_child(%ComponentsAnchor.get_node(NodePath(component.id))) +	#for component in components: +		#if component.name == component_name: +			#components.erase(component) +			#$ComponentsAnchor.remove_child($ComponentsAnchor.get_node(NodePath(component.name))) +			#break  	redraw_components()  	components_changed.emit()  func redraw_components(): -	for idx in range(components.size()): -		var component = components[idx] -		var sprite = $ComponentsAnchor.get_node(NodePath(component.name)) +	var keys = components.keys() +	for idx in range(keys.size()): +		var key = keys[idx] +		var component: TowerComponent = components[key] +		var sprite = %ComponentsAnchor.get_node(NodePath(component.id))  		sprite.position.y = (idx + 1) * -16 -func is_melee_range(): -	return attack_range <= (Client.current_stage.map.tile_set.tile_size.x * 2) - - -func shoot(): -	var target = mobs_in_range[0] as Unit -	 -	for component in components: -		if component.has_method("on_shoot"): -			component.on_shoot(target) -	 -	shoot_fx.rpc() -	 -	if is_melee_range(): -		target.set_hp(target.hp - 1) -	else: # TODO -		target.set_hp(target.hp - 1) - -@rpc("authority", "call_local") -func shoot_fx(): -	$SoundShoot.play() +#func is_melee_range(): +	#return attack_range <= (Client.current_stage.map.tile_set.tile_size.x * 2) + + +#func shoot(): +	#var target = mobs_in_range[0] as Unit +	# +	#for component in components: +		#if component.has_method("on_shoot"): +			#component.on_shoot(target) +	# +	#shoot_fx.rpc() +	# +	#if is_melee_range(): +		#target.set_hp(target.hp - 1) +	#else: # TODO +		#target.set_hp(target.hp - 1) +# +#@rpc("authority", "call_local") +#func shoot_fx(): +	#$SoundShoot.play() @@ -227,12 +241,12 @@ func get_region():  func get_group_id() -> String:  	var string := "" -	string += str(attack_range) -	string += str(attack_power) -	string += str(attack_speed) +	#string += str(attack_range) +	#string += str(attack_power) +	#string += str(attack_speed) -	for component in components: -		string += component.name +	for component: TowerComponent in components.values(): +		string += component.id  		string += str(component.level)  	return string.md5_text() @@ -263,15 +277,15 @@ func to_network_data() -> NetworkData:  	data.owner_id = owner_id  	data.position = global_position -	data.attack_range = attack_range -	data.attack_power = attack_power -	data.attack_speed = attack_speed -	data.components = components.map(func(item: TowerComponent): +	#data.attack_range = attack_range +	#data.attack_power = attack_power +	#data.attack_speed = attack_speed +	data.components = components.values().map(func(item: TowerComponent):  		return inst_to_dict(item.to_network_data())  	)  	data.sprite_modulate = $AnimatedSprite2D.modulate -	data.components_anchor_modulate = $ComponentsAnchor.modulate +	data.components_anchor_modulate = %ComponentsAnchor.modulate  	# IMPROVEMENT: check against last update and only set changed values @@ -279,7 +293,7 @@ func to_network_data() -> NetworkData:  func update_with_network_data(data: NetworkData):  	for component in components.duplicate(): -		remove_component(component.name) +		remove_component(component.id)  	for component_data in data.components:  		var component_network_data: TowerComponent.NetworkData = dict_to_inst(component_data) @@ -294,11 +308,11 @@ static func from_network_data(data: NetworkData) -> Tower:  	tower.owner_id = data.owner_id  	tower.global_position = data.position -	tower.attack_range = data.attack_range -	tower.attack_power = data.attack_power -	tower.attack_speed = data.attack_speed +	#tower.attack_range = data.attack_range +	#tower.attack_power = data.attack_power +	#tower.attack_speed = data.attack_speed  	tower.get_node("AnimatedSprite2D").modulate = data.sprite_modulate -	tower.get_node("ComponentsAnchor").modulate = data.components_anchor_modulate +	tower.get_node("%ComponentsAnchor").modulate = data.components_anchor_modulate  	return tower diff --git a/Towers/Tower.tscn b/Towers/Tower.tscn index 25388f6..0bd4579 100644 --- a/Towers/Tower.tscn +++ b/Towers/Tower.tscn @@ -93,6 +93,7 @@ shape = SubResource("RectangleShape2D_atm5x")  [node name="Range" type="Area2D" parent="."]  unique_name_in_owner = true +visible = false  collision_layer = 0  [node name="CollisionShape2D" type="CollisionShape2D" parent="Range"] @@ -109,13 +110,23 @@ one_shot = true  position = Vector2(16, 16)  shape = SubResource("RectangleShape2D_312i7") -[node name="ComponentsAnchor" type="Marker2D" parent="."] -position = Vector2(0, 32) +[node name="ComponentsAnchor" type="HFlowContainer" parent="."] +unique_name_in_owner = true +offset_right = 32.0 +offset_bottom = 32.0 +size_flags_vertical = 3 +theme_override_constants/h_separation = 0 +theme_override_constants/v_separation = 0 +reverse_fill = true  [node name="GroundAnchor" type="Marker2D" parent="."]  position = Vector2(16, 29) +[node name="CenterAnchor" type="Marker2D" parent="."] +position = Vector2(16, 16) +  [node name="SoundShoot" type="AudioStreamPlayer2D" parent="."] +visible = false  stream = ExtResource("5_i05ow")  [connection signal="input_event" from="." to="." method="_on_input_event"] | 
