the enemy can now scale to the resolution.
i made a BasePaddle class so i can put commonly used fields in a base class. this means i made a new plugin called CustomTypes which contains both Base classes.
This commit is contained in:
parent
3e61187065
commit
8072cf4961
12 changed files with 113 additions and 67 deletions
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=4 format=3]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://dts6gwgqbre22"]
|
||||
|
||||
[ext_resource type="Script" path="res://Scripts/Objects/Ball.cs" id="1_474si"]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=5 format=3]
|
||||
[gd_scene load_steps=5 format=3 uid="uid://ch0fhyeawosrh"]
|
||||
|
||||
[ext_resource type="PhysicsMaterial" uid="uid://e05n66x8ug77" path="res://Resources/BouncyMaterial.tres" id="1_e3kk5"]
|
||||
[ext_resource type="Script" path="res://Scripts/Objects/Enemy.cs" id="1_fbrtv"]
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[gd_scene load_steps=8 format=3 uid="uid://bh3p1hnvsviu6"]
|
||||
|
||||
[ext_resource type="PackedScene" path="res://Scenes/Objects/Paddle.tscn" id="1_5rs0o"]
|
||||
[ext_resource type="PackedScene" uid="uid://ijf4pw1wmb4t" path="res://Scenes/Objects/Paddle.tscn" id="1_5rs0o"]
|
||||
[ext_resource type="Script" path="res://Scripts/Managers/PongSceneManager.cs" id="1_ee533"]
|
||||
[ext_resource type="Script" path="res://Scripts/Managers/ScalingManager.cs" id="2_dc5sv"]
|
||||
[ext_resource type="PackedScene" uid="uid://clsmrwvyrt7av" path="res://Scenes/UI/Score.tscn" id="2_f3jwj"]
|
||||
[ext_resource type="PackedScene" path="res://Scenes/Objects/Ball.tscn" id="2_u2ksv"]
|
||||
[ext_resource type="PackedScene" uid="uid://dts6gwgqbre22" path="res://Scenes/Objects/Ball.tscn" id="2_u2ksv"]
|
||||
[ext_resource type="PackedScene" uid="uid://cmk6ierwi7sdt" path="res://Scenes/Objects/Walls.tscn" id="3_jfis7"]
|
||||
[ext_resource type="PackedScene" path="res://Scenes/Objects/Enemy.tscn" id="4_uwvof"]
|
||||
[ext_resource type="PackedScene" uid="uid://ch0fhyeawosrh" path="res://Scenes/Objects/Enemy.tscn" id="4_uwvof"]
|
||||
|
||||
[node name="Pong" type="Node2D"]
|
||||
script = ExtResource("1_ee533")
|
||||
|
@ -19,7 +19,7 @@ offset_bottom = 270.0
|
|||
|
||||
[node name="Paddle" parent="." instance=ExtResource("1_5rs0o")]
|
||||
position = Vector2(-350, 0)
|
||||
_moveSpeed = 50.0
|
||||
MoveSpeed = 50.0
|
||||
|
||||
[node name="Camera2D" type="Camera2D" parent="."]
|
||||
|
||||
|
@ -31,7 +31,7 @@ _maxRandomAngle = 0.42
|
|||
|
||||
[node name="Enemy" parent="." instance=ExtResource("4_uwvof")]
|
||||
position = Vector2(350, 0)
|
||||
_moveSpeed = 50.0
|
||||
MoveSpeed = 50.0
|
||||
|
||||
[node name="ScalingManager" type="Node" parent="."]
|
||||
script = ExtResource("2_dc5sv")
|
||||
|
|
9
Scripts/Data/DoubleExtensions.cs
Normal file
9
Scripts/Data/DoubleExtensions.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Pong.Scripts.Data;
|
||||
|
||||
public static class DoubleExtensions
|
||||
{
|
||||
public static double ByMeter(this double num)
|
||||
{
|
||||
return num * Constants.Meter;
|
||||
}
|
||||
}
|
19
Scripts/Managers/BasePaddle.cs
Normal file
19
Scripts/Managers/BasePaddle.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
namespace Pong.Scripts.Managers;
|
||||
|
||||
public partial class BasePaddle: RigidBody2D
|
||||
{
|
||||
[Export] protected double MoveSpeed;
|
||||
|
||||
protected ScalingManager ScalingManager;
|
||||
protected Vector2? NewPosition;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
ScalingManager = GetNode<ScalingManager>("../ScalingManager");
|
||||
}
|
||||
|
||||
protected void SetNewPosition(Vector2 newPosition)
|
||||
{
|
||||
NewPosition = newPosition;
|
||||
}
|
||||
}
|
|
@ -19,9 +19,9 @@ public partial class ScalingManager : Node
|
|||
private Vector2I _gameResolution;
|
||||
private GameArea _gameArea;
|
||||
|
||||
public event EventHandler<Vector2> NewPaddlePosition;
|
||||
public event EventHandler<Vector2> NewEnemyPosition;
|
||||
public event EventHandler<Vector2> NewBallPosition;
|
||||
public event Action<Vector2> NewPaddlePosition;
|
||||
public event Action<Vector2> NewEnemyPosition;
|
||||
public event Action<Vector2> NewBallPosition;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
|
@ -68,6 +68,7 @@ public partial class ScalingManager : Node
|
|||
SetWallPosition();
|
||||
SetScorePosition();
|
||||
SetPaddlePosition(normalizedPaddlePosition);
|
||||
SetEnemyPosition(normalizedEnemyPosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -105,18 +106,22 @@ public partial class ScalingManager : Node
|
|||
private void SetPaddlePosition(Vector2 normalizedPosition)
|
||||
{
|
||||
var newPaddlePos = _gameArea.GlobalizePosition(normalizedPosition with { X = 0 }) + new Vector2(48, 0);
|
||||
NewPaddlePosition?.Invoke(this, newPaddlePos);
|
||||
NewPaddlePosition?.Invoke(newPaddlePos);
|
||||
}
|
||||
|
||||
private void SetEnemyPosition(Vector2 normalizedPosition)
|
||||
{
|
||||
var newEnemyPos = _gameArea.GlobalizePosition(normalizedPosition with {X = 0}) + new Vector2(48,0);
|
||||
NewEnemyPosition?.Invoke(this, newEnemyPos);
|
||||
var newEnemyPos = _gameArea.GlobalizePosition(normalizedPosition with { X = 1 }) + new Vector2(-48, 0);
|
||||
NewEnemyPosition?.Invoke(newEnemyPos);
|
||||
}
|
||||
|
||||
private void SetBallPosition(Vector2 normalizedPosition)
|
||||
{
|
||||
var newBallPos = _gameArea.GlobalizePosition(normalizedPosition);
|
||||
NewBallPosition?.Invoke(this, newBallPos);
|
||||
NewBallPosition?.Invoke(newBallPos);
|
||||
}
|
||||
|
||||
public static void SetNewPosition(ref Vector2 newPositionField)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
using Pong.Scripts.Data;
|
||||
using Pong.Scripts.Managers;
|
||||
|
||||
namespace Pong.Scripts.Objects;
|
||||
|
||||
public partial class Enemy : RigidBody2D
|
||||
public partial class Enemy : BasePaddle
|
||||
{
|
||||
/// <summary>
|
||||
/// draw shapes to the screen (like <see cref="_scanArea"/>).
|
||||
/// </summary>
|
||||
[Export] private bool _drawDebugShapes;
|
||||
[Export] private double _moveSpeed;
|
||||
|
||||
private CollisionShape2D _collisionShape;
|
||||
private Rect2 _scanArea;
|
||||
|
||||
|
||||
private PhysicsDirectSpaceState2D _spaceState;
|
||||
private readonly Variant _collider = "collider";
|
||||
private PhysicsShapeQueryParameters2D _query;
|
||||
|
||||
public override void _Ready()
|
||||
public override void _EnterTree()
|
||||
{
|
||||
base._EnterTree();
|
||||
ScalingManager.NewEnemyPosition += SetNewPosition;
|
||||
_collisionShape = GetNode<CollisionShape2D>("CollisionShape2D");
|
||||
GenerateCastArea();
|
||||
|
||||
|
||||
_spaceState = GetWorld2D().DirectSpaceState;
|
||||
_query = new PhysicsShapeQueryParameters2D
|
||||
{
|
||||
|
@ -34,7 +37,17 @@ public partial class Enemy : RigidBody2D
|
|||
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
Scan(delta);
|
||||
}
|
||||
|
||||
public override void _IntegrateForces(PhysicsDirectBodyState2D state)
|
||||
{
|
||||
if (NewPosition.HasValue)
|
||||
{
|
||||
state.Transform = new Transform2D(0, NewPosition.Value);
|
||||
NewPosition = null;
|
||||
}
|
||||
|
||||
Scan(GetPhysicsProcessDeltaTime(), state);
|
||||
}
|
||||
|
||||
public override void _Draw()
|
||||
|
@ -43,7 +56,7 @@ public partial class Enemy : RigidBody2D
|
|||
DrawRect(_scanArea, Colors.Aqua);
|
||||
}
|
||||
|
||||
private void Scan(double delta)
|
||||
private void Scan(double delta, PhysicsDirectBodyState2D state)
|
||||
{
|
||||
var result = _spaceState.IntersectShape(_query);
|
||||
|
||||
|
@ -53,27 +66,28 @@ public partial class Enemy : RigidBody2D
|
|||
return;
|
||||
}
|
||||
|
||||
TrackBall(delta, result);
|
||||
TrackBall(delta, result, state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// track the distance between the ball and the enemy paddle on the y axis and move velocity accordingly.
|
||||
/// </summary>
|
||||
/// <param name="delta">how long it took to complete the last frame in seconds. this should be constant as
|
||||
/// should be executed in the physics process method which should be separate from the main frame rate.</param>
|
||||
/// should be executed in the physics process method which should be separate from the main frame rate.</param>
|
||||
/// <param name="result">a dictionary of objects that collided with the cast. this method only works if
|
||||
/// theres an object that has the Ball class.</param>
|
||||
private void TrackBall(double delta, IReadOnlyList<Dictionary> result)
|
||||
/// theres an object that has the Ball class.</param>
|
||||
/// <param name="state"></param>
|
||||
private void TrackBall(double delta, IReadOnlyList<Dictionary> result, PhysicsDirectBodyState2D state)
|
||||
{
|
||||
// checks if the collider is a ball, if not, return.
|
||||
if (result[0][_collider].As<Ball>() is not { } ball) return;
|
||||
|
||||
// gets the sign of the distance between the ball and the paddle on the y axis
|
||||
var normalisedDistance = new Vector2 { Y = Mathf.Sign(ball.Position.Y - Position.Y) };
|
||||
var linearVelocity = normalisedDistance * _moveSpeed * Constants.Meter;
|
||||
var linearVelocity = normalisedDistance * MoveSpeed.ByMeter();
|
||||
|
||||
// lerp the velocity to smooth out jerky movement.
|
||||
LinearVelocity = LinearVelocity.Lerp(linearVelocity, delta);
|
||||
state.LinearVelocity = LinearVelocity.Lerp(linearVelocity, delta);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,30 +1,21 @@
|
|||
using Pong.Scripts.Data;
|
||||
using Pong.Scripts.Managers;
|
||||
|
||||
namespace Pong.Scripts.Objects;
|
||||
|
||||
public partial class Paddle : RigidBody2D
|
||||
public partial class Paddle : BasePaddle
|
||||
{
|
||||
[Export] private double _moveSpeed;
|
||||
|
||||
private double _verticalInput;
|
||||
private readonly StringName _paddleUp = "paddle_up";
|
||||
private readonly StringName _paddleDown = "paddle_down";
|
||||
private ScalingManager _scalingManager;
|
||||
|
||||
private bool _canMove = true;
|
||||
private Vector2 _originalPosition;
|
||||
|
||||
private Vector2? _newPosition;
|
||||
|
||||
/// <summary>
|
||||
/// property that multiples the moveSpeed by the <see cref="Constants.Meter">Meter</see> constant.
|
||||
/// </summary>
|
||||
private double MoveSpeed => _moveSpeed * Constants.Meter;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
_scalingManager = GetNode<ScalingManager>("../ScalingManager");
|
||||
_scalingManager.NewPaddlePosition += (_, vector2) => _newPosition = vector2;
|
||||
base._EnterTree();
|
||||
ScalingManager.NewPaddlePosition += SetNewPosition;
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
|
@ -34,13 +25,13 @@ public partial class Paddle : RigidBody2D
|
|||
|
||||
public override void _IntegrateForces(PhysicsDirectBodyState2D state)
|
||||
{
|
||||
if (_newPosition.HasValue)
|
||||
if (NewPosition.HasValue)
|
||||
{
|
||||
state.Transform = new Transform2D(0, _newPosition.Value);
|
||||
_newPosition = null;
|
||||
state.Transform = new Transform2D(0, NewPosition.Value);
|
||||
NewPosition = null;
|
||||
}
|
||||
|
||||
state.LinearVelocity = Vector2.Up * MoveSpeed * _verticalInput;
|
||||
state.LinearVelocity = Vector2.Up * MoveSpeed.ByMeter() * _verticalInput;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
#if TOOLS
|
||||
using Godot;
|
||||
|
||||
namespace Pong.addons.BaseMenu;
|
||||
|
||||
[Tool]
|
||||
public partial class BaseMenu : EditorPlugin
|
||||
{
|
||||
public override void _EnterTree()
|
||||
{
|
||||
var baseMenuScript = GD.Load<Script>("res://Scripts/Managers/UI/BaseMenu.cs");
|
||||
AddCustomType("BaseMenu", "VBoxContainer", baseMenuScript, GetEditorIcon("VBoxContainer"));
|
||||
}
|
||||
|
||||
private Texture2D GetEditorIcon(string iconName)
|
||||
{
|
||||
return GetEditorInterface().GetBaseControl().GetThemeIcon(iconName, "EditorIcons");
|
||||
}
|
||||
}
|
||||
#endif
|
28
addons/CustomTypes/Plugin.cs
Normal file
28
addons/CustomTypes/Plugin.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
#if TOOLS
|
||||
namespace Pong.addons.CustomTypes
|
||||
{
|
||||
[Tool]
|
||||
public partial class Plugin : EditorPlugin
|
||||
{
|
||||
public override void _EnterTree()
|
||||
{
|
||||
var baseMenuScript = GD.Load<Script>("res://Scripts/Managers/UI/BaseMenu.cs");
|
||||
var basePaddleScript = GD.Load<Script>("res://Scripts/Managers/BasePaddle.cs");
|
||||
|
||||
AddCustomType("BaseMenu", "VBoxContainer", baseMenuScript, GetEditorIcon("VBoxContainer"));
|
||||
AddCustomType("BasePaddle", "RigidBody2D", basePaddleScript, GetEditorIcon("RigidBody2D"));
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
RemoveCustomType("BaseMenu");
|
||||
RemoveCustomType("BasePaddle");
|
||||
}
|
||||
|
||||
private Texture2D GetEditorIcon(string iconName)
|
||||
{
|
||||
return GetEditorInterface().GetBaseControl().GetThemeIcon(iconName, "EditorIcons");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
[plugin]
|
||||
|
||||
name="BaseMenu"
|
||||
name="CustomTypes"
|
||||
description=""
|
||||
author="Fries"
|
||||
version=""
|
||||
script="BaseMenu.cs"
|
||||
script="Plugin.cs"
|
|
@ -35,7 +35,7 @@ version_control/autoload_on_startup=true
|
|||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/BaseMenu/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/CustomTypes/plugin.cfg")
|
||||
|
||||
[input]
|
||||
|
||||
|
|
Loading…
Reference in a new issue