Added win/lose conditions, lose animation. Clicking on revealed tile with correct number of flags reveals the surrounding unflagged tiles. Added completion timer. Probably other things I'm forgetting

This commit is contained in:
Nolan Casey 2025-05-14 11:32:36 -04:00
parent 34a254b12c
commit 32150473c6
7 changed files with 112 additions and 14 deletions

View File

@ -0,0 +1,9 @@
[gd_scene load_steps=2 format=3 uid="uid://b8ewc3373b0t2"]
[ext_resource type="Script" uid="uid://du63nf81skbpt" path="res://scripts/Minefield.gd" id="1_rm6t6"]
[node name="Minefield" type="Node2D"]
script = ExtResource("1_rm6t6")
[node name="Camera2D" type="Camera2D" parent="."]
zoom = Vector2(4, 4)

View File

@ -0,0 +1,9 @@
[gd_scene load_steps=2 format=3 uid="uid://b8ewc3373b0t2"]
[ext_resource type="Script" uid="uid://du63nf81skbpt" path="res://scripts/Minefield.gd" id="1_rm6t6"]
[node name="Minefield" type="Node2D"]
script = ExtResource("1_rm6t6")
[node name="Camera2D" type="Camera2D" parent="."]
zoom = Vector2(4, 4)

View File

@ -11,8 +11,14 @@ static var instance: Minefield
@export var startingSafeZone: int = 2
var tiles: Array[Tile]
var mines: Array[Tile]
var falseFlags: Array[Tile]
var spriteWidth: int = 16
var fieldInitialized: bool = false
var gameRunning: bool = true
var revealed: int = 0
var winCondition: int
var timer: int
func _enter_tree() -> void:
if (instance == null || is_instance_valid(instance)): instance = self
@ -20,6 +26,7 @@ func _enter_tree() -> void:
func _ready() -> void:
var scale: float = 1
winCondition = (width * height) - mineCount
for x: int in range(width):
for y: int in range(height):
var tile: Tile = tilePrefab.instantiate()
@ -38,10 +45,29 @@ func initField(coord: Vector2i) -> void:
pickPool.erase(pick)
if (abs(coord - pick.coord) >= Vector2i(startingSafeZone, startingSafeZone)):
pick.type = Tile.TileTypes.MINE
mines.append(pick)
break
pick = pickPool.pick_random()
for tile: Tile in tiles:
tile.evaluateType()
timer = Time.get_ticks_msec()
func lose() -> void:
gameRunning = false
for mine: Tile in mines:
await get_tree().create_timer(randf_range(0.01, 0.25)).timeout
mine.reveal()
for flag: Tile in falseFlags:
await get_tree().create_timer(randf_range(0.01, 0.1)).timeout
flag.breakFlag()
func tilesRevealed(count: int) -> void:
revealed += count
if (revealed == winCondition):
gameRunning = false
var completionTime: int = Time.get_ticks_msec() - timer
var humanTime: float = float(completionTime) / 1000
print("You win.\nCompleted in " + str(humanTime) + " seconds")
func getTile(coord: Vector2i) -> Tile:
if (coord.x < 0 || coord.y < 0 || coord.x >= width || coord.y >= width): return null

View File

@ -4,6 +4,7 @@ class_name Tile extends Node2D
@onready var cover: CompressedTexture2D = preload("res://sprites/cover.png")
@onready var mine: CompressedTexture2D = preload("res://sprites/mine.png")
@onready var flag: CompressedTexture2D = preload("res://sprites/flag.png")
@onready var brokenFlag: CompressedTexture2D = preload("res://sprites/brokenFlag.png")
@onready var nums: Array[CompressedTexture2D] = [
preload("res://sprites/1.png"),
preload("res://sprites/2.png"),
@ -36,44 +37,63 @@ var coord: Vector2i
var revealed: bool = false
var flagged: bool = false
func evaluateType() -> void:
if (type == TileTypes.MINE): return
var count: int = 0
func getNeighbors() -> Array[Tile]:
var results: Array[Tile]
for x: int in range(-1, 2):
for y: int in range(-1, 2):
if (x == 0 && y == 0): continue
var tile: Tile = Minefield.instance.getTile(coord + Vector2i(x, y))
if (tile == null): continue
if (tile.type == TileTypes.MINE): count += 1
results.append(tile)
return results
func evaluateType() -> void:
if (type == TileTypes.MINE): return
var count: int = 0
for tile: Tile in getNeighbors():
if (tile.type == TileTypes.MINE): count += 1
type = count as TileTypes
func reveal() -> void:
if (revealed): return
func reveal() -> int:
if (revealed || Minefield.instance.gameRunning && flagged): return 0
revealed = true
var count: int = 1
layer1.texture = backplate
match type:
TileTypes.EMPTY:
layer2.texture = null
for x: int in range(-1, 2):
for y: int in range(-1, 2):
if (x == 0 && y == 0): continue
var tile: Tile = Minefield.instance.getTile(coord + Vector2i(x, y))
if (tile == null): continue
tile.reveal()
for tile: Tile in getNeighbors(): count += tile.reveal()
TileTypes.MINE:
layer2.texture = mine
if (Minefield.instance.gameRunning): Minefield.instance.lose()
_:
layer2.texture = nums[type as int - 1]
return count
func breakFlag() -> void:
layer2.texture = brokenFlag
func _on_area_2d_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
if (!Minefield.instance.gameRunning): return
if (event.is_released()):
if (event.is_action_released("reveal") && !flagged):
if (event.is_action_released("reveal") && revealed):
var count: int = 0
var neighbors: Array[Tile] = getNeighbors()
for tile: Tile in neighbors:
if (tile.flagged): count += 1
if (count == type as int):
count = 0
for tile: Tile in neighbors: count += tile.reveal()
Minefield.instance.tilesRevealed(count)
elif (event.is_action_released("reveal") && !flagged):
if (!Minefield.instance.fieldInitialized):
Minefield.instance.initField(coord)
reveal()
Minefield.instance.tilesRevealed(reveal())
elif (event.is_action_released("flag") && !revealed):
flagged = !flagged
if (flagged):
layer2.texture = flag
if (type != TileTypes.MINE): Minefield.instance.falseFlags.append(self)
else:
layer2.texture = null
if (type != TileTypes.MINE): Minefield.instance.falseFlags.erase(self)

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d353xpjsitdct"
path="res://.godot/imported/brokenFlag.png-785bad89b513c2a3f4b8d504b0f83440.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://sprites/brokenFlag.png"
dest_files=["res://.godot/imported/brokenFlag.png-785bad89b513c2a3f4b8d504b0f83440.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