6.6. 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.

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()

6.6.1. 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.

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()

6.6.2. 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”.

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

6.6.3. 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.

extends StaticBody2D

class_name Healthpack

export var health = 100

func get_healing():
	return health