Introduction In modern web development, the boundaries between classic and web applications are blurring every day. Today, we can create not only interactive websites but also full-fledged games right in the browser. One of the tools that makes this possible is the library - a powerful tool for creating 3D graphics based on using technology. React Three Fiber Three.js React In today's article, we will implement: weapon aiming animation; flash animation when firing; add a sound effect when firing a gun. Repository on GitHub https://youtu.be/fSihvQn_qWQ?embedable=true https://codesandbox.io/p/github/JI0PATA/fps-game?embedable=true Minor edits Before we start, let's create a new images folder for images in the assets folder. And move the image of the floor surface to this folder. Also, change the path to the image in the file. Ground.jsx Section code Aiming mechanics As in most shooters, aiming is activated by right-clicking. But users can reassign this button to any other at any time in the game settings. Therefore, we will not set the condition of pressing this key directly in the code but will implement a separate config where we will set the control. In it is already possible to create such a config without additional libraries. To do this, you need to create a file in the root of the project. Then, it is in the format that we can set environment variables that we can use anywhere in our project. React(Vite), .env VITE_*** In the configuration file, let's add two variables that will contain the codes of mouse button presses. Namely, the code for the mouse button to activate firing and also for aiming. .env Now, we need to rework the mouse button logic so that different actions are activated when different buttons are pressed. But first, we need to fix some incorrect behavior when intercepting the mouse cursor on the canvas. At the moment, clicking the mouse on the screen immediately triggers a shot action, which looks a bit odd. So we'll add logic that until the cursor is intercepted by the application, then no click events will occur. Now, we'll use the library to store the global state of . In the file, we'll add the state and add event handlers for locking and unlocking the cursor. Zustand App.jsx In the file, we will add new logic that will differentiate between mouse keys pressed and also take into account the state of the intercepted cursor. Weapon.jsx Let's create a function . Inside, we will determine the current state of the intercepted cursor, and if the cursor has not been intercepted yet, we will not perform any actions. We also need to import from config the values for the mouse keys that activate the firing or aiming mode. mouseButtonHandler .env Let's also change the logic of the event handlers when pressing and releasing mouse keys. Now, let's directly implement the aiming animation. First, let's add a new state, to store the aiming state. useAimingStore, Let's add a variable to be able to change the aiming state. And in the function, where we previously left empty space for the button, we add a state change. mouseButtonHandler AIM_BUTTON Let's go to the file and do the implementation inside it. Player.jsx Firstly, we need to import the states from the file. Also, move the constant to the root of the file. useAimingStore Weapon.jsx easing Let's add the state for further use in the file. isAiming To save the state of the animation, let's add two states: aiming animation and returning to the original state. Now, let's create the function, which will describe both states of the aiming animation. initAimingAnimation In order for this animation to run, it is necessary to call the function when initializing the application. This is exactly when the object with the weapon model inside is ready for interaction. initAimingAnimation When changing the state, it is necessary to trigger either the aiming animation or the weapon return to the initial position. For this purpose, let's add , within which one or another logic will be triggered according to the condition. So, for example, when starting the aiming process, it will be necessary to stop the "wiggle" animation and then start the aiming animation. When the mouse button is released, the animation of returning the weapon to the initial position is triggered, and when the event is triggered, the "wiggle" animation is re-run. isAiming useEffect onComplete But now, when the application is initialized, the animation starts up, and it looks like the player was aiming and then exits the aiming mode. This happens because, by default, is set to , and the "or" branch in the condition is immediately triggered during initialization. You can solve this by fixing the default value to and then modifying the condition by adding a specific value to the condition. isAiming false null So now we have an aiming animation when the right mouse button is clicked and an exit from this mode when it is released. Section code Refactoring the recoil animation Before we get to the next part of our article, let's do some refactoring of the animation implementation. In the file, let's change the function name from to . And also replace this function name in other places. Player.jsx setAnimationParams setSwayingAnimationParams And from the function, we will remove the constant because earlier we moved it to the root of the file. initSwayingObjectAnimation easing Let's move on to fixing the Weapon.jsx file. Change the value for to 50. recoilDuration Let's remove for unnecessary. Instead, let's now add . recoilBackAnimation isRecoilAnimationFinished For the function, let's add a default value for the parameter. generateNewPositionOfRecoil currentPosition In the function, let's remove the constant for uselessness. initRecoilAnimation initialPosition For Tween-animation, we will rework the logic, making it automatically-return to the initial position from which the animation started. We will also remove the return animation . twRecoilBackAnimation Let's rework by splitting it into 2 different functions. The first will initialize the animation, and the second will run the weapon recoil animation. useEffect Section code Animation of the flash when shooting Now, let's implement the flash display when the weapon is fired. In the file import the function. And also, load the flash image into . Weapon.jsx useLoader assets/images In the component, import this image as . FlashShoot Next, let's use the function to load this image into the scene. We will also add a state to save the . useLoader flashAnimation Let's create a new state to smoothly change the transparency of the flash. We will also create a new function , in which we will describe the animation sequence. And after that, we'll to initialize the animation. flashOpacity initFlashAnimation useEffect Now, we need to display this image on the stage at the same level as the weapon model, setting the location so that the image is located directly on the end of the muzzle of the weapon. And finally, let's add a call to the startShooting function for animation at each shot. Section code Adding the sound of a gunshot Let's add the prepared sound file to the folder. assets/sounds Import it into a file. Using we can add a sound file for the current page (not for the scene). HTMLAudioElement, When the function is called, we launch the given audio file. For several shots, the audio files to be launched will start and overlap with each other. And at the end just stop playing. startShooting Section code Conclusion In this article, we have added an aiming animation, a flash animation when shooting, and a sound effect when shooting. In the next article, we will continue to refine our game by adding new functionality. Thanks for reading, and I will be glad to respond to your comments! Also published . here