Dateien sortiert, Hintergrund angepasst, Platzierungslogik und Basis für Combat angelegt. Gewehr schießt und Gegner nehmen Schaden
This commit is contained in:
1 parent
02b9ddb226
commit
e8c81646c4
59 files changed
+2616
-179
No files matched your search
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d14ad0391252c4c44ae83d6fc8386cb3
|
||||
guid: 89f34c5b2bc781e479a5da1cb918f3aa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,108 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(Rigidbody2D))]
|
||||
[RequireComponent(typeof(Collider2D))]
|
||||
public class Bullet : MonoBehaviour
|
||||
{
|
||||
[Header("Runtime Values")]
|
||||
private Vector2 direction;
|
||||
|
||||
private float speed;
|
||||
private float damage;
|
||||
private float maxDistance;
|
||||
|
||||
private float distanceTravelled;
|
||||
|
||||
private bool initialized;
|
||||
|
||||
// Speichert alle Gegner, die diese Kugel bereits getroffen hat.
|
||||
private HashSet<Enemy> hitEnemies = new HashSet<Enemy>();
|
||||
|
||||
private Rigidbody2D rb;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
rb = GetComponent<Rigidbody2D>();
|
||||
|
||||
rb.gravityScale = 0f;
|
||||
rb.bodyType = RigidbodyType2D.Kinematic;
|
||||
rb.collisionDetectionMode =
|
||||
CollisionDetectionMode2D.Continuous;
|
||||
}
|
||||
|
||||
public void Initialize(
|
||||
Vector2 shootDirection,
|
||||
float bulletSpeed,
|
||||
float bulletDamage,
|
||||
float range
|
||||
)
|
||||
{
|
||||
direction = shootDirection.normalized;
|
||||
|
||||
speed = bulletSpeed;
|
||||
damage = bulletDamage;
|
||||
maxDistance = range;
|
||||
|
||||
// Sprite zeigt standardmäßig mit seiner lokalen Y-Achse nach oben.
|
||||
float angle =
|
||||
Mathf.Atan2(direction.y, direction.x)
|
||||
* Mathf.Rad2Deg - 90f;
|
||||
|
||||
transform.rotation =
|
||||
Quaternion.Euler(0f, 0f, angle);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
float remainingDistance =
|
||||
maxDistance - distanceTravelled;
|
||||
|
||||
if (remainingDistance <= 0f)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
float movementDistance = Mathf.Min(
|
||||
speed * Time.fixedDeltaTime,
|
||||
remainingDistance
|
||||
);
|
||||
|
||||
Vector2 movement =
|
||||
direction * movementDistance;
|
||||
|
||||
rb.MovePosition(rb.position + movement);
|
||||
|
||||
distanceTravelled += movementDistance;
|
||||
|
||||
if (distanceTravelled >= maxDistance)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
Enemy enemy =
|
||||
other.GetComponentInParent<Enemy>();
|
||||
|
||||
if (enemy == null)
|
||||
return;
|
||||
|
||||
// Bereits getroffenen Gegner ignorieren.
|
||||
if (!hitEnemies.Add(enemy))
|
||||
return;
|
||||
|
||||
// Keine weiteren Treffer auf tote Gegner.
|
||||
if (enemy.IsDead)
|
||||
return;
|
||||
|
||||
enemy.TakeDamage(damage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e19c6e90338ca14d8f1aa88ff9b01fc
|
||||
File renamed without changes.
File renamed without changes.
@@ -15,8 +15,20 @@ public class Enemy : MonoBehaviour, IMovementDirection
|
||||
// Wird von CharacterRotation verwendet.
|
||||
public Vector2 MovementDirection { get; private set; }
|
||||
|
||||
[Header("Health")]
|
||||
[SerializeField]
|
||||
private float maxHealth = 100f;
|
||||
|
||||
private float currentHealth;
|
||||
|
||||
public float CurrentHealth => currentHealth;
|
||||
|
||||
public bool IsDead { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
currentHealth = maxHealth;
|
||||
|
||||
targetManager =
|
||||
FindFirstObjectByType<EnemyTargetManager>();
|
||||
|
||||
@@ -87,6 +99,10 @@ public class Enemy : MonoBehaviour, IMovementDirection
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// BEWEGUNGSLOGIK
|
||||
//
|
||||
|
||||
private void SelectClosestTarget()
|
||||
{
|
||||
if (targetManager == null)
|
||||
@@ -133,4 +149,47 @@ public class Enemy : MonoBehaviour, IMovementDirection
|
||||
currentTarget.position
|
||||
) <= targetReachedDistance;
|
||||
}
|
||||
|
||||
|
||||
// LEBENSLOGIK
|
||||
//
|
||||
|
||||
public void TakeDamage(float damage)
|
||||
{
|
||||
if (IsDead || damage <= 0f)
|
||||
return;
|
||||
|
||||
currentHealth -= damage;
|
||||
|
||||
Debug.Log(
|
||||
gameObject.name +
|
||||
" erhält " + damage +
|
||||
" Schaden. HP: " +
|
||||
currentHealth + "/" + maxHealth
|
||||
);
|
||||
|
||||
if (currentHealth <= 0f)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
private void Die()
|
||||
{
|
||||
if (IsDead)
|
||||
return;
|
||||
|
||||
IsDead = true;
|
||||
|
||||
Debug.Log(
|
||||
gameObject.name + " wurde besiegt!"
|
||||
);
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
|
||||
// ANGRIFFSLOGIK (möglicherweise in anderem Skript)
|
||||
//
|
||||
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,209 @@
|
||||
using UnityEngine;
|
||||
using DepthsOfGreed.HandbookUI;
|
||||
|
||||
public class Turret : MonoBehaviour
|
||||
{
|
||||
[Header("Tower Data")]
|
||||
[SerializeField]
|
||||
private HandbookTowerEntry towerData;
|
||||
|
||||
[Header("Turret Setup")]
|
||||
[SerializeField]
|
||||
private Transform turret;
|
||||
|
||||
[SerializeField]
|
||||
private Transform tip;
|
||||
|
||||
[SerializeField]
|
||||
private float rotationSpeed = 360f;
|
||||
|
||||
[Header("Projectile Setup")]
|
||||
[SerializeField]
|
||||
private GameObject bulletPrefab;
|
||||
|
||||
[SerializeField]
|
||||
private float bulletSpeed = 8f;
|
||||
|
||||
private CombatDefinition combatStats;
|
||||
|
||||
private float nextAttackTime;
|
||||
|
||||
private Enemy currentTarget;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (towerData == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
"TowerShooting: Kein HandbookTowerEntry zugewiesen!",
|
||||
this
|
||||
);
|
||||
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (turret == null || tip == null || bulletPrefab == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
"TowerShooting: Turret, Tip oder Bullet Prefab fehlt!",
|
||||
this
|
||||
);
|
||||
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
combatStats = towerData.CreateCombatSnapshot(0);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (combatStats == null)
|
||||
return;
|
||||
|
||||
// Ziel innerhalb der Reichweite suchen.
|
||||
currentTarget = FindTarget();
|
||||
|
||||
if (currentTarget != null)
|
||||
{
|
||||
RotateTowardsTarget();
|
||||
TryShoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Zur ursprünglichen Ausrichtung zurückkehren.
|
||||
RotateTowardsOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
private Enemy FindTarget()
|
||||
{
|
||||
Enemy[] enemies =
|
||||
FindObjectsByType<Enemy>(
|
||||
FindObjectsSortMode.None
|
||||
);
|
||||
|
||||
Enemy closestEnemy = null;
|
||||
|
||||
float closestDistance = float.MaxValue;
|
||||
|
||||
float rangeSquared =
|
||||
combatStats.range * combatStats.range;
|
||||
|
||||
foreach (Enemy enemy in enemies)
|
||||
{
|
||||
if (enemy == null || enemy.IsDead)
|
||||
continue;
|
||||
|
||||
Vector2 difference =
|
||||
enemy.transform.position - transform.position;
|
||||
|
||||
float distanceSquared = difference.sqrMagnitude;
|
||||
|
||||
if (distanceSquared > rangeSquared)
|
||||
continue;
|
||||
|
||||
if (distanceSquared < closestDistance)
|
||||
{
|
||||
closestDistance = distanceSquared;
|
||||
closestEnemy = enemy;
|
||||
}
|
||||
}
|
||||
|
||||
return closestEnemy;
|
||||
}
|
||||
|
||||
private void RotateTowardsTarget()
|
||||
{
|
||||
Vector3 worldDirection =
|
||||
currentTarget.transform.position - turret.position;
|
||||
|
||||
// Richtung in den lokalen Raum der Turmbasis umwandeln.
|
||||
Vector3 localDirection =
|
||||
turret.parent != null
|
||||
? turret.parent.InverseTransformDirection(worldDirection)
|
||||
: worldDirection;
|
||||
|
||||
float targetAngle =
|
||||
Mathf.Atan2(localDirection.y, localDirection.x)
|
||||
* Mathf.Rad2Deg - 90f;
|
||||
|
||||
Quaternion targetRotation =
|
||||
Quaternion.Euler(0f, 0f, targetAngle);
|
||||
|
||||
turret.localRotation = Quaternion.RotateTowards(
|
||||
turret.localRotation,
|
||||
targetRotation,
|
||||
rotationSpeed * Time.deltaTime
|
||||
);
|
||||
}
|
||||
|
||||
private void RotateTowardsOrigin()
|
||||
{
|
||||
turret.localRotation = Quaternion.RotateTowards(
|
||||
turret.localRotation,
|
||||
Quaternion.identity,
|
||||
rotationSpeed * Time.deltaTime
|
||||
);
|
||||
}
|
||||
|
||||
private void TryShoot()
|
||||
{
|
||||
if (combatStats.attacksPerSecond <= 0f)
|
||||
return;
|
||||
|
||||
if (Time.time < nextAttackTime)
|
||||
return;
|
||||
|
||||
Shoot();
|
||||
|
||||
float attackInterval =
|
||||
1f / combatStats.attacksPerSecond;
|
||||
|
||||
nextAttackTime = Time.time + attackInterval;
|
||||
}
|
||||
|
||||
private void Shoot()
|
||||
{
|
||||
GameObject bulletObject = Instantiate(
|
||||
bulletPrefab,
|
||||
tip.position,
|
||||
tip.rotation
|
||||
);
|
||||
|
||||
Bullet bullet =
|
||||
bulletObject.GetComponent<Bullet>();
|
||||
|
||||
if (bullet == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
"TowerShooting: Bullet Prefab besitzt kein TowerBullet-Skript!",
|
||||
bulletObject
|
||||
);
|
||||
|
||||
Destroy(bulletObject);
|
||||
return;
|
||||
}
|
||||
|
||||
bullet.Initialize(
|
||||
tip.up,
|
||||
bulletSpeed,
|
||||
combatStats.damagePerHit,
|
||||
combatStats.range
|
||||
);
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
if (towerData == null)
|
||||
return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
|
||||
Gizmos.DrawWireSphere(
|
||||
transform.position,
|
||||
towerData.combat.range
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ec586d6b5f1d324d89950df76c68b91
|
||||
@@ -1,16 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class Gewehr : MonoBehaviour
|
||||
{
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20a1554fc2589f941b773279b280cb4c
|
||||
Reference in new issue
Block a user