public void shoot(float delta, bool isPuppet) { if (reloadWeapon) { return; } if (!isPuppet) { return; } // Get bullet ray. RayCast bulletRay = (RayCast)camera.GetNode("bullet_ray"); if (bullets > 0) { bullets -= 1; // Notify bullet update GameState.instance.EmitSignal(nameof(GameState.updateWeapon), weaponName, bullets, ammo); if (camera != null) { // Recoil camera.Rotation = new Vector3( Mathf.Lerp(camera.Rotation.x, (float)GD.RandRange(1, 2), delta), Mathf.Lerp(camera.Rotation.y, (float)GD.RandRange(-1, 1), delta), camera.Rotation.z ); // Shake camera.Set("shakeForce", 0.002); camera.Set("shakeTime", 0.2); } // Audio AudioStreamPlayer3D shoot = ((AudioStreamPlayer3D)audioNode.GetNode("shoot")); shoot.PitchScale = (float)GD.RandRange(0.9, 1.1); shoot.Play(); // Update crosshair crosshair.RectScale = crosshair.RectScale.LinearInterpolate(new Vector2(4, 4), 10 * delta); if (bulletRay.IsColliding()) { // Object collision CollisionObject collisionObject = (CollisionObject)bulletRay.GetCollider(); // Add spark to props. if (collisionObject.IsInGroup("props")) { // Add Spark Particles spark = (Particles)sparkScene.Instance(); ((Node)bulletRay.GetCollider()).AddChild(spark); spark.GlobalTransform = new Transform(spark.GlobalTransform.basis, bulletRay.GetCollisionPoint()); spark.Emitting = true; } // Add Muzzle Particles muzzle = (Particles)muzzleScene.Instance(); barrelNode.AddChild(muzzle); muzzle.Emitting = true; if (collisionObject is KinematicBody) { // Add Blood splatter Particles splatter = (Particles)splatterScene.Instance(); ((Node)bulletRay.GetCollider()).AddChild(splatter); splatter.GlobalTransform = new Transform(splatter.GlobalTransform.basis, bulletRay.GetCollisionPoint()); splatter.Emitting = true; int localDamage = 0; if (collisionObject.IsInGroup("head")) { localDamage = (int)GD.RandRange(damage / 2, damage); } else { localDamage = (int)GD.RandRange(damage / 3, damage / 2); } int colliderId = Convert.ToInt32(collisionObject.Name); // Send damage report. GameState.instance.EmitSignal(nameof(GameState.takeDamage), colliderId, localDamage); return; } else if (collisionObject.IsInGroup("props") || collisionObject.IsInGroup("walls")) { // Apply force to rigid body other than hitbox if (bulletRay.GetCollider() is RigidBody) { int localDamage = (int)GD.RandRange(damage / 1.5f, damage); ((RigidBody)bulletRay.GetCollider()).ApplyCentralImpulse(-bulletRay.GetCollisionNormal() * (localDamage * 0.3f)); } // Apply decal Spatial decal = (Spatial)decalScene.Instance(); ((Node)bulletRay.GetCollider()).AddChild(decal); decal.GlobalTransform = new Transform( decal.GlobalTransform.basis, bulletRay.GetCollisionPoint() ); decal.LookAt(bulletRay.GetCollisionPoint() + bulletRay.GetCollisionNormal(), new Vector3(1, 1, 0)); return; } } } else { AudioStreamPlayer3D empty = ((AudioStreamPlayer3D)audioNode.GetNode("empty")); if (!empty.Playing) { empty.PitchScale = (float)GD.RandRange(0.9, 1.1); empty.Play(); } } }
public override void _PhysicsProcess(float delta) { base._PhysicsProcess(delta); // check if the wave nearest the player has passed the global z-axis zero point // At that point it is not longer cutable, and must be removed var nearestWave = WaveInstances.FirstOrDefault(); if (nearestWave != null && nearestWave.GlobalTransform.origin.z >= 1) { // wave should have faded-out by now, so remove it from the scene. WaveInstances.Remove(nearestWave); nearestWave.Remove(); nearestWave.QueueFree(); } else if (nearestWave != null && nearestWave.GlobalTransform.origin.z >= 0) { nearestWave.SetForRemoval(); } // check for a collision with the ribbon // Check all waves within 1m of global origin for cuts foreach (var waveInstance in WaveInstances) { if (waveInstance.GlobalTransform.origin.z > -1) // only check for cuts when wave is near player origin { waveInstance.SetActive(); if (waveInstance.WaveCut(RibbonPoints)) { // todo - if all the segments are cut, play a special sound effect? } } } // check if it's time to emit another wave // Previously attempted to do this with a Timer, and also with OS.ticks() method, but both fell out of sync with audio over duration of track. // Using GetPlaybackPosition() to time wave emission seems to be effective // todo - investigate method here: https://docs.godotengine.org/en/stable/tutorials/audio/sync_with_audio.html#using-the-sound-hardware-clock-to-sync if (Active && AudioStreamPlayer.GetPlaybackPosition() >= NextEmissionTime - WARP_TIME) { // Initialise a new wave var waveInstance = WaveScene.Instance() as Wave; WaveSpawnPoint.AddChild(waveInstance); waveInstance.Initialise(WaveSequence.GetNextWave()); WaveInstances.Add(waveInstance); // "warp" the wave in quickly... WaveMovementTween.InterpolateProperty(waveInstance, "translation:z", -30, 0, WARP_TIME); // ...then move the wave towards the player at a reasonable speed (n.b. this tween starts after a delay) var animationDuration = 3f; WaveMovementTween.InterpolateProperty(waveInstance, "translation:z", 0, 3, animationDuration, delay: WARP_TIME); if (waveInstance.RotationRateRad != 0) { // some waves will also rotate as they move toward the player (n.b. this tween starts after a delay) var rotationStart = waveInstance.Rotation.z; var rotationEnd = waveInstance.Rotation.z + (waveInstance.RotationRateRad * animationDuration); WaveMovementTween.InterpolateProperty(waveInstance, "rotation:z", rotationStart, rotationEnd, animationDuration, delay: WARP_TIME); } WaveMovementTween.Start(); var nextWaveDelay = WaveSequence.GetNextWaveDelay(); if (nextWaveDelay.HasValue) { NextEmissionTime += nextWaveDelay.Value; } else { // no waves left in sequence Active = false; } } }