FINAL PROJECT ************* The game ======== You will try to reproduce a game from the Steam store called `Coin Pusher Casino `_ : .. image:: coin.png Gameplay ======== Coin Pusher Casino is a virtual arcade game where you drop coins onto a moving platform, aiming to push others over the edge and into the tray at the bottom. Coins that fall in the tray are automatically collected and added to your total. * Player drop coins, one at a time, by clicking on the back wall * The click location determines where the coin is dropped from * Platforms are already filled with coins * Some platforms slowly slides back and forth * When your coin lands, it might: * Push other coins closer * Trigger a chain reaction * Knock coins or special prizes into the tray below * Coins that drop into the tray count as your winnings In the game interface, the bottom tray isn’t really visible. So consider that any coin that falls all the way down is automatically collected. .. raw:: html
Basic assets ============ Project setup ------------- * Create a new folder called *Project* * Insite this folder, create a new scene called *POC* and open it * Create a subfolder named *Tokens* in the *Project* folder At the beginning, we will only use two elements: * The **coins**, which represents the falling coins and the small coins already on the platform * The casino **chips**, which are larger, colored and often stacked in columns Chips look like classic casino chips, with values like $5 or $10 written on them. When they fall into the tray, their value is added to the player's total. Coins, on the other hand, are just for pushing — they don’t award any money. * Download the following asset: * :download:`coin ` * :download:`chip ` * :download:`textchip ` * Drag and drop these files into the *Tokens* folder Coins ----- * Create a new material for the coin * Select a warm copper color * Increase its metallic property to give a metallic aspect * Create the *Coin* object * Drag and drop the obj file into the scene * Drag and drop the material into the object * Add a rigibody component * Set mass (10g) * Activate gravity * Add a mesh collider .. warning:: Sometimes the mesh collider fails to detect the inner mesh and remains "empty" .. image:: empty.png :scale: 50% * In the *Tokens* folder, click on the *coin* asset to view its internal elements: .. image:: mesh.png :scale: 50% * Drag and drop the *default* mesh into the missing mesh of the mesh collider * Enable the Convex option * Create the prefab * Drag and drop the object into the *Tokens* folder Chips ----- Same procedure, except for the material where you have to assign the downloaded texture. * Set mass to 20g .. image:: folder.png :scale: 50% .. image:: tokens.png :scale: 50% Pusher ====== The pusher has a specific behavior: * It follows a predefined path * It can push coins * Its movement is not affected by objects it collides with By default, a Rigidbody reacts to forces and other objects in the scene. Fortunately, Unity provides an option called **Kinematic** which allows an object to behave like a pusher: * Ignores physics forces – The object won’t be affected by gravity or collisions * Doesn’t move automatically – It won’t react to physics; you must move it via a script * Still detects collisions – It can trigger collision events, but won’t be pushed or bounce Here are the dimensions of the pusher: .. image:: pusher.png :scale: 70% Scene setup ----------- * Create a floor using a cube scaled to 5×1×20 * Apply a solid color to this floor * Create the pusher using a cube scaled 5x0.6x20 * Apply a solid color to this floor * Move the pusher so that it rests on the floor (compute the Y value precisely) * Move the pusher back * Add a Rigidbody * Enable its Kinematic flag .. image:: floorpusher.png :scale: 50% * Build two walls on the left and right to prevent tokens from falling off the sides: Animate ------- * Create a script and attach it to the pusher * Look at the movement of the pusher, its speed is not constant * The pusher's speed decreases at the extremities of its movement * Thus, we propose to animate the pusher using this formula: .. math:: z(t) = z_0 + K.sin(\omega.t) ~~~~ // ~~x(t) ~~also ~~possible Thus: * As the pusher moves back and forth over a distance of 1, we know that :math:`K = 1` * The period lasts 5 seconds, so you can deduce the value of :math:`\omega` * The last step is to determine :math:`z_0` from the environment you’ve built .. image:: sin.gif :scale: 60% .. warning:: If we simply change the position of the pusher, objects placed on it won't move! To avoid this strange behavior, we need to move its Rigidbody instead of manipulating its Transform directly. .. code-block:: csharp Vector3 pos = transform.position; pos.z = ... rb.MovePosition(pos); // command the rigidbody Proof of concept ================ Before spending hours on production, we'll quickly set up a POC. If it's too complex for Unity's physics engine, there's no point in going further. Everything is ready — create multiple coins and chips flying through the air. This way, they'll fall like a waterfall, and we’ll be able to see if that works correctly! .. image:: test.png :scale: 30% Here is our result: .. image:: firsttry.gif :scale: 50% For a first attempt, it's really not bad at all! * The coins and chips fall as expected * They bounce realistically off the floor * The pusher moves the tokens forward But there are still a few annoying issues: * Some tokens keep shaking and sliding around * Some tokens partially sink into the floor Let’s be honest: you can tweak Rigidbody settings all you want, but it won’t fix the real issue. We’re overloading the physics engine with too many coins, all in constant contact. This is pretty much a nightmare scenario for physics, way more complex than simulating a car driving on a road. But the 3D engine almost manages to handle it — it just seems to lack precision. As a reminder, physics is simulated by discretizing time into fixed steps, which are set to 0.02 second by default. That timestep is still too large for our fast-falling, bouncing coins. Let’s reduce it by a factor of 10 and see how the engine reacts: * Navigate to: Menu > Edit > Project Settings > Time .. image:: time.png :scale: 50% * Set Timestep to 0.002 * Enter Play mode .. image:: gogo.gif :scale: 70% Wow, great, it works like a charm!