This is a classic game - minesweeper. In it you have to open the whole field without hitting any mines. Opening the cells you will see numbers - the number of mines around the cell. You can put a flag on a closed cell so you don't accidentally open it
- Press
Primary fire
to open the cell - Press
Secondary fire
on the closed cell to put or take away the flag - Press
Secondary fire
on the opened cell to open neighboring cells if number of open cell <= count of neighboring cells marked with flag - The field is generated after the first shot. You can be sure that the first shot always hits a cell with no mines around it
- Fixed size of field: 10 x 10
- Custom mine count.
Jump
in theRed sphere
to increase the number of mines,Crouch
to decrease Crouch
in theYellow sphere
to restart the game- Press
F
to teleport into theYellow sphere
- Press
Melee attack
to toggle top view - Statistics
- You can play in co-op, but because of this can cause errors with the server or rendering elements
Game state not started
Game state in progress
Game state lost
Game state win
On server starting
:
- Setup all global variables
- Set Current status to
Game not started
Then Cast rule for projectile usage
On game not started
:
- Create HUD hints
- Set HUD with level
- Drop lose condition
- Stop timer
- Drop flag counter
- Generate mesh grid [1]
- Create action spheres, field borders, states
- Init projectile for each player
- Switch current status to
Game not started
- User can increase or decrease mines count
- Player open first cell
- If player hit the cell on the field => generate field. First hit always open cell with number
0
- Switch current status to
Game in progress
On Game in progress
:
- Start chase timer
- Player open cell [2]
- Player toggle flag on cell
- Win condition check (
count of closed cells == mines count
) => Switch current status toGame state win
- Lose condition check (player touched mine) => Switch current status to
Game state lost
On Game state lost
:
- Stop chase timer
- Show mines
- Kill player / Increase count of losses
On Game state win
:
- Stop timer and check personal best time
- Show message about win / Increase wins count
On Going
- Pressing F => teleport to Yellow sphere
- Pressing Crouch in Yellow sphere => destroy all effects/texts/flags, set current status to
Game state not started
. If game was in progress => Increase lose count - Pressing Melee - toggle camera
- Pressing Jump/Crouch in Red sphere => increase/decrease mines count, drop statistics
Then Destroy projctile
Subroutines:
- generateField: Get first cell -> find neighbors -> generate random mine patterns (mine position != position of first cell or neighbors)
- getNeighbors: Find neighbors around
getNeighborsArg
and place togetNeighborsOut
- findProjectileHitIndex: Find index of cell that projectile hit
- openCell: If projectile hit cell with number != 0 -> call
_openSingleCell
otherwise call_openStackCell
- _openSingleCell: Open single cell
- _openStackCell: Open stack cells
- flagCell: Toggle flag if cell is closed, Open neighbors if cell is opened and number of it <= count of flags around
- showAllMines: Show all mines. Show right placed flags, Show mistake, Show all not flagged mines
- dropStats: drop personal best time, wins count, loses count
[1] mesh grid - list of coordinates of the field
[2] player hit cell -> if cell is number -> open single cell (if cell is mine -> set touch mine status to True)
-> else -> create stack of cells -> for each -> open cell
In this project, I encountered that the text and icons start to float when the player moves. To solve this problem, I tried to recalculate the coordinates of the text and icons according to the player's position through some proportions. As a result, I got the following formula:
where:- Real coordinate of text (icon)
- Left to player in world coordinates World Vector(Left, Local Player, Rotation)
- Eye position of local player
- Y component of player eye position
- Forward to player in world coordinates World Vector(Forward, Local Player, Rotation)
In workshop:
Create In-World Text(
All Players(All Teams),
Event Player._fieldCellNumber,
Update Every Frame(
Evaluate Once(Global.fieldCoordinates[Event Player._cellToOpen]) + Cross Product(World Vector Of(Left, Local Player, Rotation), Normalize(
Evaluate Once(Global.fieldCoordinates[Event Player._cellToOpen]) - Eye Position(Local Player))) * (Y Component Of(Eye Position(
Local Player)) * (4 / 50) + Dot Product(World Vector Of(Forward, Local Player, Rotation), Evaluate Once(
Global.fieldCoordinates[Event Player._cellToOpen]) - Position Of(Local Player)) * (1 / 40))),
2,
Do Not Clip,
Visible To and Position,
Global.colorOfNumbers[Event Player._fieldCellNumber],
Default Visibility
);