# Gegnercharactere Im Spiel kommen zwei verschiedene Genertypen vor: Shooter und Charger Alle Gegner teilen sich Characteristiken. So können sie Schaden bekommen und werden sie aus dem Spiel entfernt, sobald ihre Lebenspunkte auf Null sinken. Beim Entfernen aus dem Spiel erzeugen sie noch einen kleinen Explosionseffekt. Das wird über die Funktionen "take_damage" und "die" geregelt. Die Bewegungslogik wird über die Funktion "_physics_process" geregelt. Diese behandelt auch die Zusammenstöße mit anderen Objekten. ```{code-block} gdscript func take_damage(damage: int): health -= damage if health <= 0: die() func die(): var explosion = preload("res://Entity/explosion.tscn") explosion = explosion.instantiate() explosion.position = position get_tree().current_scene.add_child(explosion) queue_free() ``` ## Shooter Der Shooter Gegner stellt den klassischen Gegner eines "Shoot 'em Up" Spiels dar. Er bewegt sich horizontal von einer Bildschirmseite zur anderen. Gemäß seines Namens schießt er konstant gerade nach unten und damit auf den Spieler zu. Berührt er ein anderes Objekt oder den Bildschirmrand ändert er seine Richtung. Mit der geringen Anzahl an Lebenspunkten und dem geringen am Spieler verursachten Schaden, dienen sie dazu, dem Spieler nach und nach die Lebenspunkte abzuziehen. Das schießen nach unten wird über die Funktion "shoot" geregelt, die periodisch aufgerufen wird. Diese Funktion erzeugt einfach ein neues "Bullet" Objekt welches in die gewünschte Richtung fliegt. Alles Weitere übernimmt die Bullet selbst. Das Ändern der Bewegungsrichtung wird über die Funktion "turn_around" geregelt. Diese wird von einem screen_checker Objekt aufgerufen sobald der Gegner den Bildschirm verlässt oder wenn dieser mit etwas zusammenstößt. ```{code-block} gdscript extends CharacterBody2D signal max_health_updated(health) signal health_updated(health) signal killed() const SPEED = 300.0 const JUMP_VELOCITY = -400.0 var screensize export var move_direction = -1 export var max_health = 100 onready var health = max_health onready var shooting_delay = $ShootingDelay var sprite_index = randi_range(0, 2) const turnaround_delay = 0.5 var next_turnaround = 0 const death_score_points = 100 func _ready(): emit_signal("max_health_updated", max_health) emit_signal("health_updated", health) screensize = get_viewport_rect().size var random_number = randi()% 2 var direction match random_number: 0: velocity.x = SPEED 1: velocity.x = -SPEED func shoot(): if shooting_delay.is_stopped(): shooting_delay.start() var projectile = preload("res://Entity/bullet.tscn") var bullet = projectile.instantiate() bullet.position = Vector2(0,100) + position bullet.direction = -1 get_tree().current_scene.add_child(bullet) func _set_health(value): var prev_health = health health = clamp(value, 0, max_health) if health != prev_health: emit_signal("health_updated", health) if health == 0: die() emit_signal("killed") func turn_around(): if next_turnaround > turnaround_delay: move_direction = -1 * move_direction next_turnaround = 0 func _physics_process(delta): next_turnaround += delta shoot() velocity.x = SPEED * move_direction # turns around on collision var collision_info = move_and_collide(velocity * delta) if collision_info: turn_around() var collider = collision_info.get_collider() if collider.is_class("Bullet"): take_damage(collider.damage) collider.free() ``` ## Charger Der Charger Gegner stellt wiederum etwas Besonderes dar und stellt essentiell eine raumschiffförmige Ramme dar. Er steht erst für eine bestimmte Zeit still und richtet sich in Richtung des Spielers aus. Sobald die Zeit abgelaufen ist, hört er auf sich zu drehen und rast auf den letzten Zielpunkt zu. Dem Spieler bleibt etwas Zeit um dem Ansturm auszuweichen. Mit der großen Anzahl an Lebenspunkten und dem enormen Schaden bei Zusammenstoß, sind sie schwer für den Spieler zu entfernen und dienen dazu den Spieler dazu zu zwingen sich zu bewegen. Die Entscheidung ob der Gegner stillsteht oder losfliegt wird über die Funktion "determine_flight" geregelt. Das Zielen auf den Spieler übernimmt die Funktion "adjust_target_direction". ```{code-block} gdscript extends StaticBody2D const SPEED = 10.0 var target_locked = false export var fuel_lifetime = 5 var current_fuel = fuel_lifetime export var target_time = 5 export var remaining_target_time = target_time export var max_health = 1000 var health = max_health export var damage = 2000 onready var _sprite = $AnimatedSprite2D const death_score_points = 100 func adjust_target_direction() : if is_inside_tree(): var player = get_parent().get_node("Player")# only works if Player and Charger are on the same layer if player != null: player.position look_at(player.position) func determine_flight(delta): if remaining_target_time > 0: adjust_target_direction() remaining_target_time -= delta else: target_locked = true _sprite.play("blast") constant_linear_velocity = transform.x * SPEED func check_fuel(delta): if current_fuel > 0: current_fuel -= delta else: die() func _physics_process(delta): if target_locked: check_fuel(delta) else: determine_flight(delta) var collision_info = move_and_collide(constant_linear_velocity) if target_locked: if collision_info: var collider = collision_info.get_collider() if collider.has_method("take_damage"): collider.call("take_damage", get_damage()) else: collider.free() func get_damage(): return damage ``` ## Healthpack Obwohl sie dem Spieler nicht schaden werden Healthpacks genau wie die Gegner zufällig erzeugt. Berührt der Spieler diese werden seine Lebenspunkte um einen bestimmten Betrag geheilt. ```{code-block} gdscript extends StaticBody2D class_name Healthpack export var health = 100 func get_healing(): return health ```