Guest User

Collision Bug Test

a guest
Jul 15th, 2026
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.02 KB | Software | 0 0
  1. project.godot ################################################################################################
  2. ; Engine configuration file.
  3. ; It's best edited using the editor UI and not directly,
  4. ; since the parameters that go here are not all obvious.
  5. ;
  6. ; Format:
  7. ;   [section] ; section goes between []
  8. ;   param=value ; assign values to parameters
  9.  
  10. config_version=5
  11.  
  12. [application]
  13.  
  14. config/name="CollisionBugTest"
  15. run/main_scene="uid://chiiwry3l2pkm"
  16. config/features=PackedStringArray("4.7", "C#", "Mobile")
  17. config/icon="res://icon.svg"
  18.  
  19. [autoload]
  20.  
  21. EnemyObjectPool="*uid://dkifioyg6eets"
  22.  
  23. [display]
  24.  
  25. window/size/viewport_width=640
  26. window/size/viewport_height=360
  27. window/stretch/mode="viewport"
  28. window/stretch/scale_mode="integer"
  29.  
  30. [dotnet]
  31.  
  32. project/assembly_name="CollisionBugTest"
  33.  
  34. [layer_names]
  35.  
  36. 2d_physics/layer_1="Player"
  37. 2d_physics/layer_2="Enemy"
  38.  
  39. [physics]
  40.  
  41. 3d/physics_engine="Jolt Physics"
  42.  
  43. [rendering]
  44.  
  45. rendering_device/driver.windows="d3d12"
  46. renderer/rendering_method="mobile"
  47.  
  48. PlayableArea.cs ################################################################################################
  49. using Godot;
  50. using System;
  51.  
  52. public partial class PlayableArea : Area2D
  53. {
  54.     public override void _Ready()
  55.     {
  56.         BodyEntered += OnBodyEntered;
  57.         BodyExited += OnBodyExited;
  58.     }
  59.  
  60.     private void OnBodyEntered(Node2D body)
  61.     {
  62.         if (body is Enemy)
  63.             GD.Print($"[Playable area] Enemy entered");
  64.     }
  65.  
  66.     private async void OnBodyExited(Node2D body)
  67.     {
  68.         try
  69.         {
  70.             if (body is Enemy enemy)
  71.             {
  72.                 GD.Print("[Playable area] Enemy left.");
  73.                 await enemy.DefeatAsync(); //you would remove enemy here without full animated sequence but for minimal example it's okay
  74.             }
  75.         }
  76.         catch (Exception e)
  77.         {
  78.             GD.PrintErr(e);
  79.         }
  80.     }
  81. }
  82.  
  83. Game.cs ################################################################################################
  84. using Godot;
  85. using System;
  86. using System.Collections.Generic;
  87. using System.Linq;
  88. using System.Threading.Tasks;
  89.  
  90. public partial class Game : Node2D
  91. {
  92.     [Export] private Button _btnStart;
  93.     [Export] private Button _btnKill;
  94.  
  95.     private EnemyObjectPool _objectPool;
  96.  
  97.     private List<Enemy> _spawnedEnemies;
  98.  
  99.     private bool _started = false;
  100.     private bool _killed = false;
  101.  
  102.     public override void _Ready()
  103.     {
  104.         base._Ready();
  105.         _objectPool = EnemyObjectPool.Instance;
  106.         _spawnedEnemies = [];
  107.  
  108.         _btnStart.Pressed += OnButtonStartPressed;
  109.         _btnKill.Pressed += OnButtonKillPressed;
  110.  
  111.         _btnKill.Disabled = true;
  112.  
  113.         GD.Print($"[Game] Ready \n");
  114.     }
  115.  
  116.     private async Task SpawnAsync()
  117.     {
  118.         GD.Print("[Game] Starting spawn sequence");
  119.         var enemy = _objectPool.Dequeue();
  120.         _spawnedEnemies.Add(enemy);
  121.         enemy.Enable(new Vector2(512, 102));
  122.  
  123.         var position = new Vector2(64, 102);
  124.  
  125.         Tween tween = CreateTween();
  126.         tween.SetEase(Tween.EaseType.Out);
  127.         tween.SetTrans(Tween.TransitionType.Linear);
  128.         tween.TweenProperty(enemy, "global_position", position, 2.0);
  129.         await ToSignal(tween, Tween.SignalName.Finished);
  130.         enemy.ReachedDesignatedLocation = true;
  131.         GD.Print("\n");
  132.     }
  133.  
  134.     private async Task DestroyEnemyAsync()
  135.     {
  136.         GD.Print($"[Game] Enemy defeated by player request.");
  137.         var enemy = _spawnedEnemies.FirstOrDefault();
  138.         if (enemy != null && enemy.ReachedDesignatedLocation)
  139.         {
  140.             await enemy.DefeatAsync();
  141.             _spawnedEnemies.Remove(enemy);
  142.         }
  143.         GD.Print($"\n");
  144.     }
  145.  
  146.     #region controls
  147.  
  148.     private async void OnButtonStartPressed()
  149.     {
  150.         try
  151.         {
  152.             _btnStart.Disabled = true;
  153.  
  154.             await SpawnAsync();
  155.  
  156.             _btnKill.Disabled = false;
  157.         }
  158.         catch (Exception e)
  159.         {
  160.             GD.PrintErr(e);
  161.         }
  162.     }
  163.  
  164.     private async void OnButtonKillPressed()
  165.     {
  166.         try
  167.         {
  168.             _btnKill.Disabled = true;
  169.  
  170.             await DestroyEnemyAsync();
  171.  
  172.             await SpawnAsync();
  173.         }
  174.         catch (Exception e)
  175.         {
  176.             GD.PrintErr(e);
  177.         }
  178.     }
  179.  
  180.     #endregion
  181. }
  182.  
  183. EnemyObjectPool.cs ################################################################################################
  184. using Godot;
  185. using System;
  186. using System.Collections.Generic;
  187.  
  188. public partial class EnemyObjectPool : Node
  189. {
  190.     public static EnemyObjectPool Instance { get; private set; }
  191.  
  192.     [Export] private PackedScene _enemy;
  193.  
  194.     private int _maxMobs = 1;
  195.     private Queue<Enemy> _objectPool;
  196.  
  197.     public override void _Ready()
  198.     {
  199.         Instance = this;
  200.  
  201.         var currentScene = GetTree()?.CurrentScene;
  202.         var enemyContainer = currentScene.GetNode<Node2D>("EnemyContainer");
  203.         InitializeEnemy(enemyContainer);
  204.         GD.Print("[Object pool] Ready");
  205.     }
  206.  
  207.     private void InitializeEnemy(Node2D container)
  208.     {
  209.         _objectPool = new();
  210.         for (int i = 0; i < _maxMobs; i++)
  211.         {
  212.             var instance = _enemy.Instantiate() as Enemy;
  213.             instance.Defeated += Enqueue;
  214.             _objectPool.Enqueue(instance);
  215.             container.AddChild(instance);
  216.         }
  217.     }
  218.     private void Enqueue(Enemy enemy)
  219.     {
  220.         GD.Print("[Object pool] Enqueue");
  221.         _objectPool.Enqueue(enemy);
  222.         if (_objectPool.Count > _maxMobs) GD.PrintErr("Object pool size exceeded.");
  223.     }
  224.  
  225.     public Enemy Dequeue()
  226.     {
  227.         GD.Print("[Object pool] Dequeue");
  228.         return _objectPool.Dequeue();
  229.     }
  230. }
  231.  
  232. Enemy.cs ################################################################################################
  233. using Godot;
  234. using System;
  235. using System.Threading.Tasks;
  236.  
  237. public partial class Enemy : CharacterBody2D
  238. {
  239.     [Export] private CollisionShape2D _collision;
  240.  
  241.     public event Action<Enemy> Defeated;
  242.     public bool ReachedDesignatedLocation { get; set; }
  243.  
  244.     private Vector2 _storagePoint = new(608, 90);
  245.     private int _direction = 1;
  246.     private bool _defeated = false;
  247.  
  248.     public void InvokeDefeated()
  249.     {
  250.         Defeated?.Invoke(this);
  251.     }
  252.  
  253.     public override void _Ready()
  254.     {
  255.         base._Ready();
  256.         Disable();
  257.         GD.Print("[Enemy] Ready");
  258.     }
  259.  
  260.     public override void _PhysicsProcess(double delta)
  261.     {
  262.         base._PhysicsProcess(delta);
  263.  
  264.         if(!ReachedDesignatedLocation) return;
  265.  
  266.         _direction *= -1;
  267.         GlobalPosition += new Vector2(5 * _direction, 0);
  268.     }
  269.  
  270.     public void Enable(Vector2 position)
  271.     {
  272.         GD.Print("[Enemy] Enable");
  273.         _defeated = false;
  274.         SetPhysicsProcess(true);
  275.         GlobalPosition = position;
  276.         _collision.SetDeferred(CollisionShape2D.PropertyName.Disabled, false);
  277.     }
  278.  
  279.     public async Task DefeatAsync()
  280.     {
  281.         if(_defeated) return;
  282.         _defeated = true;
  283.  
  284.         GD.Print("[Enemy] Defeat");
  285.  
  286.         StopProcessing();
  287.         await SimulateDefeatAnimationAsync();
  288.         MoveToStoragePoint();
  289.         InvokeDefeated();
  290.         //not hiding the sprite to see where the guy actually is
  291.     }
  292.  
  293.     private async Task SimulateDefeatAnimationAsync()
  294.     {
  295.         Tween tween = CreateTween();
  296.         tween.TweenProperty(this, "rotation_degrees", RotationDegrees + 360, 1.0f);
  297.         await ToSignal(tween, Tween.SignalName.Finished);
  298.     }
  299.  
  300.     private void StopProcessing()
  301.     {
  302.         _collision.SetDeferred(CollisionShape2D.PropertyName.Disabled, true);
  303.         SetPhysicsProcess(false);
  304.     }
  305.  
  306.     private void Disable()
  307.     {
  308.         StopProcessing();
  309.         MoveToStoragePoint();
  310.     }
  311.  
  312.     private void MoveToStoragePoint()
  313.     {
  314.         GlobalPosition = _storagePoint;
  315.     }
  316. }
  317.  
  318. enemy_object_pool.tscn ################################################################################################
  319. [gd_scene format=3 uid="uid://dkifioyg6eets"]
  320.  
  321. [ext_resource type="Script" uid="uid://b3k174bgmq0lm" path="res://EnemyObjectPool.cs" id="1_0mxj6"]
  322. [ext_resource type="PackedScene" uid="uid://bxjv371c24hv6" path="res://enemy.tscn" id="2_omt7x"]
  323.  
  324. [node name="EnemyObjectPool" type="Node" unique_id=1887825628]
  325. script = ExtResource("1_0mxj6")
  326. _enemy = ExtResource("2_omt7x")
  327.  
  328. enemy.tscn ################################################################################################
  329. [gd_scene format=3 uid="uid://bxjv371c24hv6"]
  330.  
  331. [ext_resource type="Script" uid="uid://cqilqfy20e3fw" path="res://Enemy.cs" id="1_7k104"]
  332.  
  333. [sub_resource type="Gradient" id="Gradient_7xaro"]
  334.  
  335. [sub_resource type="GradientTexture2D" id="GradientTexture2D_plrnn"]
  336. gradient = SubResource("Gradient_7xaro")
  337. fill = 1
  338. fill_from = Vector2(0.51304346, 0.5)
  339.  
  340. [sub_resource type="RectangleShape2D" id="RectangleShape2D_7xaro"]
  341. size = Vector2(64, 64)
  342.  
  343. [node name="Enemy" type="CharacterBody2D" unique_id=1267955304 node_paths=PackedStringArray("_collision")]
  344. collision_layer = 2
  345. script = ExtResource("1_7k104")
  346. _collision = NodePath("CollisionShape2D")
  347.  
  348. [node name="Sprite2D" type="Sprite2D" parent="." unique_id=1626383384]
  349. texture = SubResource("GradientTexture2D_plrnn")
  350.  
  351. [node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=1732114049]
  352. shape = SubResource("RectangleShape2D_7xaro")
  353.  
  354. game.tscn ################################################################################################
  355. [gd_scene format=3 uid="uid://chiiwry3l2pkm"]
  356.  
  357. [ext_resource type="Script" uid="uid://ce2yo6xexi7a6" path="res://Game.cs" id="1_80nbo"]
  358. [ext_resource type="Script" uid="uid://cov46dvwceotm" path="res://PlayableArea.cs" id="2_e2o6t"]
  359.  
  360. [sub_resource type="RectangleShape2D" id="RectangleShape2D_plrnn"]
  361. size = Vector2(320, 360)
  362.  
  363. [node name="Game" type="Node2D" unique_id=325719013 node_paths=PackedStringArray("_btnStart", "_btnKill")]
  364. script = ExtResource("1_80nbo")
  365. _btnStart = NodePath("Button")
  366. _btnKill = NodePath("Button2")
  367.  
  368. [node name="Camera2D" type="Camera2D" parent="." unique_id=540720120]
  369. position = Vector2(320, 176)
  370.  
  371. [node name="PlayableArea" type="Area2D" parent="." unique_id=467738821]
  372. collision_layer = 0
  373. collision_mask = 2
  374. script = ExtResource("2_e2o6t")
  375.  
  376. [node name="CollisionShape2D" type="CollisionShape2D" parent="PlayableArea" unique_id=577274571]
  377. position = Vector2(160, 180)
  378. shape = SubResource("RectangleShape2D_plrnn")
  379.  
  380. [node name="EnemyContainer" type="Node2D" parent="." unique_id=1525994715]
  381.  
  382. [node name="Button" type="Button" parent="." unique_id=1855880708]
  383. offset_left = 328.0
  384. offset_top = 240.0
  385. offset_right = 384.0
  386. offset_bottom = 271.0
  387. text = "START"
  388.  
  389. [node name="Button2" type="Button" parent="." unique_id=1367707068]
  390. offset_left = 328.0
  391. offset_top = 280.0
  392. offset_right = 369.0
  393. offset_bottom = 311.0
  394. text = "KILL & RESPAWN"
  395.  
Advertisement
Add Comment
Please, Sign In to add comment