Bullet, shooting & camera shake

This commit is contained in:
LittleSheep 2024-08-08 12:13:53 +08:00
parent 6fa2c8411f
commit 0f9192a5f8
10 changed files with 216 additions and 20 deletions

View File

@ -5,25 +5,15 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="c7bd02c7-bbb4-431f-81ca-d2f8b7b09b37" name="Changes" comment=""> <list default="true" id="c7bd02c7-bbb4-431f-81ca-d2f8b7b09b37" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.idea/.idea.AceField/.idea/.gitignore" afterDir="false" /> <change afterPath="$PROJECT_DIR$/Scenes/Bullet.tscn" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/.idea.AceField/.idea/encodings.xml" afterDir="false" /> <change afterPath="$PROJECT_DIR$/Scripts/Bullet.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/.idea.AceField/.idea/indexLayout.xml" afterDir="false" /> <change afterPath="$PROJECT_DIR$/Scripts/Effects/CameraShake.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/.idea.AceField/.idea/vcs.xml" afterDir="false" /> <change afterPath="$PROJECT_DIR$/Sprites/Projectiles.png" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/.idea.CodingLand/.idea/workspace.xml" afterDir="false" /> <change afterPath="$PROJECT_DIR$/Sprites/Projectiles.png.import" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.CodingLand/.idea/.gitignore" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/.idea.CodingLand/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.CodingLand/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.CodingLand/.idea/encodings.xml" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/Scenes/Player.tscn" beforeDir="false" afterPath="$PROJECT_DIR$/Scenes/Player.tscn" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.CodingLand/.idea/indexLayout.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.CodingLand/.idea/vcs.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/CodingLand.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/AceField.csproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/CodingLand.sln" beforeDir="false" afterPath="$PROJECT_DIR$/AceField.sln" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Scenes/Root.tscn" beforeDir="false" afterPath="$PROJECT_DIR$/Scenes/Root.tscn" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Scenes/Tiles/Brick.tscn" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Scripts/Launcher.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Scripts/Launcher.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Scripts/Logic/PlayerInput.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Scripts/Logic/PlayerInput.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Scripts/Logic/PlayerInput.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Scripts/Logic/PlayerInput.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Scripts/Logic/World.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Scripts/Logic/World.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Scripts/Player.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Scripts/Player.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Scripts/Player.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Scripts/Player.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Scripts/TilesManager.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Scripts/UI/StartScreen.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Scripts/UI/StartScreen.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/project.godot" beforeDir="false" afterPath="$PROJECT_DIR$/project.godot" afterDir="false" /> <change beforePath="$PROJECT_DIR$/project.godot" beforeDir="false" afterPath="$PROJECT_DIR$/project.godot" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
@ -126,7 +116,7 @@
<workItem from="1722846222698" duration="9239000" /> <workItem from="1722846222698" duration="9239000" />
<workItem from="1722855558149" duration="11578000" /> <workItem from="1722855558149" duration="11578000" />
<workItem from="1723040712804" duration="74000" /> <workItem from="1723040712804" duration="74000" />
<workItem from="1723040934916" duration="1749000" /> <workItem from="1723040934916" duration="6034000" />
</task> </task>
<task id="LOCAL-00001" summary=":sparkles: Usable multiplayer"> <task id="LOCAL-00001" summary=":sparkles: Usable multiplayer">
<option name="closed" value="true" /> <option name="closed" value="true" />

21
Scenes/Bullet.tscn Normal file
View File

@ -0,0 +1,21 @@
[gd_scene load_steps=4 format=3 uid="uid://ds40mib6ur8yf"]
[ext_resource type="Texture2D" uid="uid://c6xf6w3jg0hfh" path="res://Sprites/Projectiles.png" id="1_cufey"]
[ext_resource type="Script" path="res://Scripts/Bullet.cs" id="1_ttgqp"]
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_tcwfy"]
radius = 5.0
height = 58.0
[node name="Bullet" type="Area2D" node_paths=PackedStringArray("FreeTimer")]
script = ExtResource("1_ttgqp")
FreeTimer = NodePath("FreeTimer")
[node name="Sprite2D" type="Sprite2D" parent="."]
texture = ExtResource("1_cufey")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("CapsuleShape2D_tcwfy")
[node name="FreeTimer" type="Timer" parent="."]
autostart = true

View File

@ -1,12 +1,16 @@
[gd_scene load_steps=7 format=3 uid="uid://b3gx0bl43lku3"] [gd_scene load_steps=10 format=3 uid="uid://b3gx0bl43lku3"]
[ext_resource type="Script" path="res://Scripts/Player.cs" id="1_0btyt"] [ext_resource type="Script" path="res://Scripts/Player.cs" id="1_0btyt"]
[ext_resource type="Texture2D" uid="uid://c4als6t3k4myc" path="res://Sprites/Player.png" id="1_cqpqa"] [ext_resource type="Texture2D" uid="uid://c4als6t3k4myc" path="res://Sprites/Player.png" id="1_cqpqa"]
[ext_resource type="PackedScene" uid="uid://ds40mib6ur8yf" path="res://Scenes/Bullet.tscn" id="2_nmop0"]
[ext_resource type="Script" path="res://Scripts/Logic/PlayerInput.cs" id="3_tvoua"] [ext_resource type="Script" path="res://Scripts/Logic/PlayerInput.cs" id="3_tvoua"]
[ext_resource type="Script" path="res://Scripts/Effects/CameraShake.cs" id="4_fwngj"]
[sub_resource type="CircleShape2D" id="CircleShape2D_68yf8"] [sub_resource type="CircleShape2D" id="CircleShape2D_68yf8"]
radius = 20.48 radius = 20.48
[sub_resource type="FastNoiseLite" id="FastNoiseLite_cfnx7"]
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_bekoo"] [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_bekoo"]
properties/0/path = NodePath(".:position") properties/0/path = NodePath(".:position")
properties/0/spawn = true properties/0/spawn = true
@ -27,6 +31,7 @@ properties/1/replication_mode = 1
script = ExtResource("1_0btyt") script = ExtResource("1_0btyt")
PlayerCamera = NodePath("Camera2D") PlayerCamera = NodePath("Camera2D")
PlayerInput = NodePath("InputSynchronizer") PlayerInput = NodePath("InputSynchronizer")
BulletScene = ExtResource("2_nmop0")
[node name="Sprite2D" type="Sprite2D" parent="."] [node name="Sprite2D" type="Sprite2D" parent="."]
position = Vector2(2.08165e-12, 2.08165e-12) position = Vector2(2.08165e-12, 2.08165e-12)
@ -41,6 +46,11 @@ enabled = false
process_callback = 0 process_callback = 0
position_smoothing_enabled = true position_smoothing_enabled = true
rotation_smoothing_enabled = true rotation_smoothing_enabled = true
script = ExtResource("4_fwngj")
Noise = SubResource("FastNoiseLite_cfnx7")
[node name="Muzzle" type="Marker2D" parent="."]
position = Vector2(2.08165e-12, -20)
[node name="DashCountdown" type="Timer" parent="."] [node name="DashCountdown" type="Timer" parent="."]
one_shot = true one_shot = true

31
Scripts/Bullet.cs Normal file
View File

@ -0,0 +1,31 @@
using Godot;
namespace AceField.Scripts;
public partial class Bullet : Area2D
{
[Export] public int PlayerId = 1;
[Export] public float Speed = 1500;
[Export] public double Damage = 8;
[Export] public Timer FreeTimer;
public override void _Ready()
{
FreeTimer.Timeout += QueueFree;
BodyEntered += body =>
{
if (body is Player player && player.PlayerId != PlayerId)
{
player.TakeDamage(Damage);
}
};
}
public override void _PhysicsProcess(double delta)
{
Position += -Transform.Y * Speed * (float)delta;
}
}

View File

@ -0,0 +1,58 @@
using System;
using Godot;
namespace AceField.Scripts.Effects;
public partial class CameraShake : Camera2D
{
[Export] public float Decay = 0.8f;
[Export] public Vector2 MaxOffset = new(100, 75);
[Export] public float MaxRoll = 0.0f;
[Export] public FastNoiseLite Noise;
private float _noiseY = 0.0f;
private float _trauma = 0.0f;
private int _traumaExponent = 3;
public override void _Ready()
{
GD.Randomize();
Noise.Seed = (int)GD.Randi();
}
public override void _Process(double delta)
{
if (_trauma > 0)
{
_trauma = Mathf.Max(_trauma - Decay * (float)delta, 0);
Shake();
}
else if (Offset.X != 0 || Offset.Y != 0 || Rotation != 0)
{
Mathf.Lerp(Offset.X, 0.0f, 1);
Mathf.Lerp(Offset.Y, 0.0f, 1);
Mathf.Lerp(Rotation, 0.0f, 1);
}
}
private void Shake()
{
var amount = Mathf.Pow(_trauma, _traumaExponent);
_noiseY++;
Rotation = MaxRoll * amount * Noise.GetNoise2D(0, _noiseY);
Offset = new Vector2(
MaxOffset.X * amount * Noise.GetNoise2D(2000, _noiseY),
MaxOffset.Y * amount * Noise.GetNoise2D(3000, _noiseY)
);
}
public void AddTrauma(float amount)
{
_trauma = Mathf.Min(_trauma + amount, 1.0f);
}
public void SetTrauma(float amount)
{
_trauma = Mathf.Min(amount, 1.0f);
}
}

View File

@ -5,6 +5,7 @@ namespace AceField.Scripts.Logic;
public partial class PlayerInput : MultiplayerSynchronizer public partial class PlayerInput : MultiplayerSynchronizer
{ {
[Export] public bool IsDashing; [Export] public bool IsDashing;
[Export] public bool IsShooting;
[Export] public Vector2 MovementDirection; [Export] public Vector2 MovementDirection;
@ -21,12 +22,18 @@ public partial class PlayerInput : MultiplayerSynchronizer
private void Dash() private void Dash()
=> IsDashing = true; => IsDashing = true;
[Rpc(CallLocal = true)]
private void Shoot()
=> IsShooting = true;
public override void _Process(double delta) public override void _Process(double delta)
{ {
MovementDirection = Input.GetVector("move_left", "move_right", "move_up", "move_down"); MovementDirection = Input.GetVector("move_left", "move_right", "move_up", "move_down");
if (Input.IsActionJustPressed("move_dash")) if (Input.IsActionJustPressed("move_dash"))
Rpc(nameof(Dash)); Rpc(nameof(Dash));
if (Input.IsActionJustPressed("shoot"))
Rpc(nameof(Shoot));
} }
public override void _Input(InputEvent evt) public override void _Input(InputEvent evt)

View File

@ -1,3 +1,4 @@
using AceField.Scripts.Effects;
using AceField.Scripts.Logic; using AceField.Scripts.Logic;
using Godot; using Godot;
@ -14,12 +15,18 @@ public partial class Player : CharacterBody2D
[Export] public int Reach = 5; [Export] public int Reach = 5;
[Export] public Camera2D PlayerCamera; [Export] public double Health = 100;
[Export] public double MaxHealth = 100;
[Export] public double ActionPoints = 20;
[Export] public double MaxActionPoints = 20;
[Export] public Camera2D PlayerCamera;
[Export] public PlayerInput PlayerInput; [Export] public PlayerInput PlayerInput;
[Export] public float PlayerDashAcceleration = 2f; [Export] public float PlayerDashAcceleration = 2f;
[Export] public PackedScene BulletScene;
[Export] [Export]
public int PlayerId public int PlayerId
{ {
@ -39,12 +46,20 @@ public partial class Player : CharacterBody2D
public override void _Ready() public override void _Ready()
{ {
Health = MaxHealth;
ActionPoints = MaxActionPoints;
if (PlayerId == Multiplayer.GetUniqueId()) if (PlayerId == Multiplayer.GetUniqueId())
PlayerCamera.Enabled = true; PlayerCamera.Enabled = true;
} }
public override void _Process(double delta) public override void _Process(double delta)
{ {
if (PlayerInput.IsShooting)
{
Rpc(nameof(Shoot));
PlayerInput.IsShooting = false;
}
} }
public override void _PhysicsProcess(double delta) public override void _PhysicsProcess(double delta)
@ -75,4 +90,29 @@ public partial class Player : CharacterBody2D
Position += Velocity * (float)delta; Position += Velocity * (float)delta;
MoveAndSlide(); MoveAndSlide();
} }
public void TakeDamage(double damage)
{
Rpc(nameof(GotDamage), damage);
}
[Rpc(MultiplayerApi.RpcMode.AnyPeer, CallLocal = true)]
private void GotDamage(double damage)
{
Health -= damage;
var shakableCamera = GetNode<CameraShake>("Camera2D");
shakableCamera.AddTrauma(0.5f);
}
[Rpc(MultiplayerApi.RpcMode.AnyPeer, CallLocal = true)]
private void Shoot()
{
var marker = GetNode<Marker2D>("Muzzle");
var projectile = BulletScene.Instantiate<Bullet>();
projectile.Transform = marker.GlobalTransform;
projectile.PlayerId = PlayerId;
GetParent().AddChild(projectile);
}
} }

BIN
Sprites/Projectiles.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c6xf6w3jg0hfh"
path="res://.godot/imported/Projectiles.png-a460b3308858e7ad21b3727966f952d3.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Sprites/Projectiles.png"
dest_files=["res://.godot/imported/Projectiles.png-a460b3308858e7ad21b3727966f952d3.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -46,6 +46,11 @@ move_dash={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":0,"echo":false,"script":null)
] ]
} }
shoot={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"echo":false,"script":null)
]
}
[rendering] [rendering]