Initial commit. Matching game
This commit is contained in:
commit
3ee40cae0c
|
@ -0,0 +1 @@
|
||||||
|
.import/
|
|
@ -0,0 +1,20 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready():
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
func _process(_delta):
|
||||||
|
if Input.is_action_just_pressed("ui_up"):
|
||||||
|
$GemGrid.up()
|
||||||
|
elif Input.is_action_just_pressed("ui_down"):
|
||||||
|
$GemGrid.down()
|
||||||
|
elif Input.is_action_just_pressed("ui_left"):
|
||||||
|
$GemGrid.left()
|
||||||
|
elif Input.is_action_just_pressed("ui_right"):
|
||||||
|
$GemGrid.right()
|
||||||
|
elif Input.is_action_just_pressed("ui_accept"):
|
||||||
|
$GemGrid.select()
|
||||||
|
elif Input.is_action_just_pressed("ui_cancel"):
|
||||||
|
$GemGrid.cancel()
|
|
@ -0,0 +1,126 @@
|
||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://entities/gem_grid.tscn" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://entities/mana_counter.tscn" type="PackedScene" id=2]
|
||||||
|
[ext_resource path="res://Main.gd" type="Script" id=3]
|
||||||
|
|
||||||
|
[node name="Main" type="Node"]
|
||||||
|
script = ExtResource( 3 )
|
||||||
|
|
||||||
|
[node name="GemGrid" parent="." instance=ExtResource( 1 )]
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
margin_left = -256.0
|
||||||
|
margin_top = -256.0
|
||||||
|
margin_right = 256.0
|
||||||
|
margin_bottom = 256.0
|
||||||
|
|
||||||
|
[node name="Counters" type="Control" parent="."]
|
||||||
|
margin_right = 256.0
|
||||||
|
margin_bottom = 600.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="ManaCounter" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
|
||||||
|
[node name="ManaCounter2" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 32.0
|
||||||
|
margin_bottom = 64.0
|
||||||
|
type = 1
|
||||||
|
|
||||||
|
[node name="ManaCounter3" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 64.0
|
||||||
|
margin_bottom = 96.0
|
||||||
|
type = 2
|
||||||
|
|
||||||
|
[node name="ManaCounter4" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 96.0
|
||||||
|
margin_bottom = 128.0
|
||||||
|
type = 3
|
||||||
|
|
||||||
|
[node name="ManaCounter5" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 128.0
|
||||||
|
margin_bottom = 160.0
|
||||||
|
type = 4
|
||||||
|
|
||||||
|
[node name="ManaCounter6" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 160.0
|
||||||
|
margin_bottom = 192.0
|
||||||
|
type = 5
|
||||||
|
|
||||||
|
[node name="ManaCounter7" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 192.0
|
||||||
|
margin_bottom = 224.0
|
||||||
|
type = 6
|
||||||
|
|
||||||
|
[node name="ManaCounter8" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 224.0
|
||||||
|
margin_bottom = 256.0
|
||||||
|
type = 7
|
||||||
|
|
||||||
|
[node name="ManaCounter9" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 256.0
|
||||||
|
margin_bottom = 288.0
|
||||||
|
effect = 1
|
||||||
|
|
||||||
|
[node name="ManaCounter10" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 288.0
|
||||||
|
margin_bottom = 320.0
|
||||||
|
type = 1
|
||||||
|
effect = 1
|
||||||
|
|
||||||
|
[node name="ManaCounter11" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 320.0
|
||||||
|
margin_bottom = 352.0
|
||||||
|
type = 2
|
||||||
|
effect = 1
|
||||||
|
|
||||||
|
[node name="ManaCounter12" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 352.0
|
||||||
|
margin_bottom = 384.0
|
||||||
|
type = 3
|
||||||
|
effect = 1
|
||||||
|
|
||||||
|
[node name="ManaCounter13" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 384.0
|
||||||
|
margin_bottom = 416.0
|
||||||
|
type = 4
|
||||||
|
effect = 1
|
||||||
|
|
||||||
|
[node name="ManaCounter14" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 416.0
|
||||||
|
margin_bottom = 448.0
|
||||||
|
type = 5
|
||||||
|
effect = 1
|
||||||
|
|
||||||
|
[node name="ManaCounter15" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 448.0
|
||||||
|
margin_bottom = 480.0
|
||||||
|
type = 6
|
||||||
|
effect = 1
|
||||||
|
|
||||||
|
[node name="ManaCounter16" parent="Counters" instance=ExtResource( 2 )]
|
||||||
|
margin_top = 480.0
|
||||||
|
margin_bottom = 512.0
|
||||||
|
type = 7
|
||||||
|
effect = 1
|
||||||
|
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter2" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter3" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter4" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter5" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter6" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter7" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter8" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter9" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter10" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter11" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter12" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter13" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter14" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter15" method="update_count"]
|
||||||
|
[connection signal="gem_matched" from="GemGrid" to="Counters/ManaCounter16" method="update_count"]
|
|
@ -0,0 +1,7 @@
|
||||||
|
[gd_resource type="Environment" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSky" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
background_mode = 2
|
||||||
|
background_sky = SubResource( 1 )
|
|
@ -0,0 +1,110 @@
|
||||||
|
extends Control
|
||||||
|
class_name Gem
|
||||||
|
|
||||||
|
signal position_reached()
|
||||||
|
|
||||||
|
# Gem type enum
|
||||||
|
enum Type { Thermic, Optic, Kinetic, Electromagnetic, Acoustic, Biologic, Chemic } #, Skull }
|
||||||
|
# Gem effect enum
|
||||||
|
enum Effect { ManaNegative, ManaPositive, EffectNegative, EffectPositive }
|
||||||
|
const effect_distribution = {
|
||||||
|
Effect.ManaNegative: 45,
|
||||||
|
Effect.ManaPositive: 45,
|
||||||
|
Effect.EffectNegative: 5,
|
||||||
|
Effect.EffectPositive: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
const unscaled_size = 128
|
||||||
|
export(Type) var type = Type.Thermic
|
||||||
|
export(Effect) var effect = Effect.ManaNegative
|
||||||
|
# Indicate if animation are played
|
||||||
|
var animate = false
|
||||||
|
# For removing
|
||||||
|
var matched: bool = false
|
||||||
|
var bonus: int = 0
|
||||||
|
# For moving
|
||||||
|
var next_i: int = 0
|
||||||
|
var next_j: int = 0
|
||||||
|
var current_i: int = 0
|
||||||
|
var current_j: int = 0
|
||||||
|
var move_dist: float = 0.0
|
||||||
|
var move_inc: float = 0.0
|
||||||
|
var moving: bool = false
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready():
|
||||||
|
update_sprite()
|
||||||
|
|
||||||
|
# Called periodically
|
||||||
|
func _process(delta):
|
||||||
|
if moving:
|
||||||
|
move_inc += 4*delta
|
||||||
|
if (move_inc >= move_dist) or ((current_i == next_i) and (current_j == next_j)):
|
||||||
|
reach_position()
|
||||||
|
else:
|
||||||
|
var pos = size() * lerp(Vector2(current_i, current_j), Vector2(next_i, next_j), move_inc / move_dist)
|
||||||
|
set_position(pos)
|
||||||
|
|
||||||
|
# Randomize a gem
|
||||||
|
func randomize(rnd: Random):
|
||||||
|
type = rnd.pick_from_array(Type.values())
|
||||||
|
effect = rnd.pick_from_distribution(effect_distribution)
|
||||||
|
update_sprite()
|
||||||
|
|
||||||
|
# Update the sprite from its type and effect
|
||||||
|
func update_sprite():
|
||||||
|
$Sprite.region_rect.position.x = unscaled_size * (type % Type.size())
|
||||||
|
$Sprite.region_rect.position.y = unscaled_size * (effect % Effect.size())
|
||||||
|
|
||||||
|
# Used for movement and position
|
||||||
|
func size():
|
||||||
|
return $Sprite.transform.get_scale().x * unscaled_size
|
||||||
|
|
||||||
|
# Match a gem
|
||||||
|
func set_matched():
|
||||||
|
if !matched:
|
||||||
|
matched = true
|
||||||
|
if animate:
|
||||||
|
$Sprite.hide()
|
||||||
|
$ParticlesMatch.emitting = true
|
||||||
|
$ParticlesTimer.start()
|
||||||
|
else:
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
# Bonus value
|
||||||
|
func set_bonus():
|
||||||
|
bonus += 1
|
||||||
|
|
||||||
|
# Enable animations and particles
|
||||||
|
func enable_animations():
|
||||||
|
animate = true
|
||||||
|
|
||||||
|
# Set the position on the grid
|
||||||
|
func set_grid_position(i, j):
|
||||||
|
next_i = i
|
||||||
|
next_j = j
|
||||||
|
current_i = i
|
||||||
|
current_j = j
|
||||||
|
set_position(size() * Vector2(i,j))
|
||||||
|
|
||||||
|
# Move to grid position
|
||||||
|
func move_to_position(i, j):
|
||||||
|
next_i = i
|
||||||
|
next_j = j
|
||||||
|
move_dist = Vector2(current_i, current_j).distance_to(Vector2(next_i, next_j))
|
||||||
|
|
||||||
|
func update_position():
|
||||||
|
if animate:
|
||||||
|
moving = true
|
||||||
|
else:
|
||||||
|
reach_position()
|
||||||
|
|
||||||
|
func reach_position():
|
||||||
|
move_inc = 0.0
|
||||||
|
moving = false
|
||||||
|
current_i = next_i
|
||||||
|
current_j = next_j
|
||||||
|
set_position(size() * Vector2(next_i, next_j))
|
||||||
|
if animate:
|
||||||
|
emit_signal("position_reached")
|
|
@ -0,0 +1,44 @@
|
||||||
|
[gd_scene load_steps=5 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://entities/gem.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://entities/gems.svg" type="Texture" id=2]
|
||||||
|
[ext_resource path="res://entities/matched-particle.svg" type="Texture" id=3]
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id=1]
|
||||||
|
flags = 4
|
||||||
|
atlas = ExtResource( 2 )
|
||||||
|
region = Rect2( 0, 0, 1024, 512 )
|
||||||
|
|
||||||
|
[node name="Gem" type="Control"]
|
||||||
|
margin_right = 64.0
|
||||||
|
margin_bottom = 64.0
|
||||||
|
rect_min_size = Vector2( 64, 64 )
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="Sprite" type="Sprite" parent="."]
|
||||||
|
scale = Vector2( 0.5, 0.5 )
|
||||||
|
texture = SubResource( 1 )
|
||||||
|
centered = false
|
||||||
|
region_enabled = true
|
||||||
|
region_rect = Rect2( 0, 0, 128, 128 )
|
||||||
|
|
||||||
|
[node name="ParticlesMatch" type="CPUParticles2D" parent="."]
|
||||||
|
position = Vector2( 32, 32 )
|
||||||
|
z_index = 1
|
||||||
|
emitting = false
|
||||||
|
amount = 25
|
||||||
|
one_shot = true
|
||||||
|
explosiveness = 0.5
|
||||||
|
texture = ExtResource( 3 )
|
||||||
|
emission_shape = 1
|
||||||
|
emission_sphere_radius = 32.0
|
||||||
|
angular_velocity = 90.0
|
||||||
|
angular_velocity_random = 0.5
|
||||||
|
scale_amount = 0.5
|
||||||
|
scale_amount_random = 0.5
|
||||||
|
|
||||||
|
[node name="ParticlesTimer" type="Timer" parent="."]
|
||||||
|
wait_time = 5.0
|
||||||
|
one_shot = true
|
||||||
|
|
||||||
|
[connection signal="timeout" from="ParticlesTimer" to="." method="queue_free"]
|
|
@ -0,0 +1,328 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
signal is_ready()
|
||||||
|
signal gem_matched(matched_results)
|
||||||
|
signal gems_swapped()
|
||||||
|
|
||||||
|
const GemScene = preload("res://entities/gem.tscn")
|
||||||
|
|
||||||
|
# Random generator
|
||||||
|
var rnd = Random.new()
|
||||||
|
|
||||||
|
# Grid dimensions
|
||||||
|
const grid_width = 8
|
||||||
|
const grid_height = 8
|
||||||
|
|
||||||
|
# The grid
|
||||||
|
var grid = LogicalGrid.new(grid_width, grid_height)
|
||||||
|
#var grid: Array = [Array(), Array(), Array(), Array(), Array(), Array(), Array(), Array()]
|
||||||
|
|
||||||
|
# Cursor position
|
||||||
|
var cursor_i: int = 0
|
||||||
|
var cursor_j: int = 0
|
||||||
|
# Status of the cursor
|
||||||
|
var gem_selected: bool = false
|
||||||
|
# Counter for events sent by gems
|
||||||
|
var event_count: int = 0
|
||||||
|
|
||||||
|
# State machine for animations and event handling
|
||||||
|
# NONE : Do not change state
|
||||||
|
# INIT : Initial state, only here before the end of the _ready function
|
||||||
|
# READY : Accept input
|
||||||
|
# SWAPPING : Reject input, change the position of gems
|
||||||
|
# MATCHING : Reject input, match gems
|
||||||
|
#
|
||||||
|
# --------- ------------ ------------
|
||||||
|
# | READY |--(gem swapped)-->| SWAPPING |--(swap ended, gems are matching)-->| MATCHING |
|
||||||
|
# --------- ------------ ------------
|
||||||
|
# ^ ^ | |
|
||||||
|
# | ------------(match occured)----------------- |
|
||||||
|
# | |
|
||||||
|
# -------------------------------(no match)-----------------------------------
|
||||||
|
#
|
||||||
|
enum State { NONE, INIT, READY, SWAPPING, MATCHING }
|
||||||
|
var current_state = State.INIT
|
||||||
|
var next_state = State.NONE
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready():
|
||||||
|
# Init the grid
|
||||||
|
for i in range(grid_width):
|
||||||
|
for j in range(grid_height):
|
||||||
|
add_gem(i, j, i, j)
|
||||||
|
# match gems (without emitting events)
|
||||||
|
match_gems()
|
||||||
|
# change the direction
|
||||||
|
grid.set_flow_direction(LogicalGrid.FlowDirection.Down)
|
||||||
|
# State is ready
|
||||||
|
current_state = State.READY
|
||||||
|
# Tell all gems the grid is ready
|
||||||
|
emit_signal("is_ready")
|
||||||
|
|
||||||
|
# State machine
|
||||||
|
func _process(delta):
|
||||||
|
if (next_state != State.NONE) and (current_state != next_state):
|
||||||
|
match next_state:
|
||||||
|
State.READY:
|
||||||
|
show_cursor()
|
||||||
|
current_state = next_state
|
||||||
|
next_state = State.NONE
|
||||||
|
State.SWAPPING:
|
||||||
|
hide_cursor()
|
||||||
|
event_count = 0
|
||||||
|
emit_signal("gems_swapped")
|
||||||
|
current_state = next_state
|
||||||
|
next_state = State.NONE
|
||||||
|
State.MATCHING:
|
||||||
|
current_state = next_state
|
||||||
|
match_gems() # Computes next state
|
||||||
|
else:
|
||||||
|
next_state = State.NONE
|
||||||
|
|
||||||
|
|
||||||
|
# Add a new gem on the board to replace a gem at i,j
|
||||||
|
# On screen initialy displayed at position screen_i,screen_j
|
||||||
|
func add_gem(i, j, screen_i, screen_j):
|
||||||
|
var g = GemScene.instance()
|
||||||
|
g.randomize(rnd)
|
||||||
|
g.set_grid_position(screen_i, screen_j)
|
||||||
|
if current_state != State.INIT:
|
||||||
|
g.enable_animations()
|
||||||
|
else:
|
||||||
|
connect("is_ready", g, "enable_animations")
|
||||||
|
connect("gems_swapped", g, "update_position")
|
||||||
|
g.connect("position_reached", self, "on_gem_moved")
|
||||||
|
$Gems.add_child(g)
|
||||||
|
grid.push_value(i, j, g)
|
||||||
|
|
||||||
|
# Swap gems between cursor position and given position
|
||||||
|
func gem_swap(i_to, j_to):
|
||||||
|
if (i_to >= 0) and (j_to >= 0) and (i_to < grid_width) and (j_to < grid_width):
|
||||||
|
# Swap gem
|
||||||
|
grid.swap_values(cursor_i, cursor_j, i_to, j_to)
|
||||||
|
grid.at(cursor_i, cursor_j).move_to_position(cursor_i, cursor_j)
|
||||||
|
grid.at(i_to, j_to).move_to_position(i_to, j_to)
|
||||||
|
# Move cursor
|
||||||
|
gem_selected = false
|
||||||
|
cursor_i = i_to
|
||||||
|
cursor_j = j_to
|
||||||
|
update_cursor()
|
||||||
|
# Change state
|
||||||
|
next_state = State.SWAPPING
|
||||||
|
|
||||||
|
# Called each time a gems have finished moving
|
||||||
|
func on_gem_moved():
|
||||||
|
event_count += 1
|
||||||
|
if event_count >= (grid_width * grid_height):
|
||||||
|
# All gems have responded : matching
|
||||||
|
next_state = State.MATCHING
|
||||||
|
|
||||||
|
func match_gems():
|
||||||
|
# Init signaled result
|
||||||
|
var results = Dictionary()
|
||||||
|
for t in Gem.Type.values():
|
||||||
|
for e in Gem.Effect.values():
|
||||||
|
results[[t, e]] = 0
|
||||||
|
# Check loop
|
||||||
|
var check_loop: bool = true
|
||||||
|
var no_match = true
|
||||||
|
while check_loop:
|
||||||
|
no_match = true
|
||||||
|
check_loop = false
|
||||||
|
# Mark the gems to match.
|
||||||
|
check_matched()
|
||||||
|
# Collect the gems to match in results
|
||||||
|
var to_remove = []
|
||||||
|
for i in range(grid_width):
|
||||||
|
for j in range(grid_height):
|
||||||
|
var g = grid.at(i, j)
|
||||||
|
if g.matched:
|
||||||
|
# Loop if we are in the init state
|
||||||
|
check_loop = (current_state == State.INIT)
|
||||||
|
no_match = false
|
||||||
|
results[[g.type, g.effect]] = results[[g.type, g.effect]] + 1 + g.bonus
|
||||||
|
# The indexes to remove are placed by pushing front,
|
||||||
|
# so that the last indexes are removed first
|
||||||
|
to_remove.push_front([i, j])
|
||||||
|
# Remove the gems
|
||||||
|
grid.remove_values(to_remove)
|
||||||
|
# Add new gems. The initial positions depends on the flow direction.
|
||||||
|
var counts = [0]
|
||||||
|
var dir = grid.get_flow_direction()
|
||||||
|
match dir:
|
||||||
|
LogicalGrid.FlowDirection.Up:
|
||||||
|
counts.resize(grid_width)
|
||||||
|
LogicalGrid.FlowDirection.Down:
|
||||||
|
counts.resize(grid_width)
|
||||||
|
LogicalGrid.FlowDirection.Left:
|
||||||
|
counts.resize(grid_height)
|
||||||
|
LogicalGrid.FlowDirection.Right:
|
||||||
|
counts.resize(grid_height)
|
||||||
|
for i in range(counts.size()):
|
||||||
|
counts[i] = 0
|
||||||
|
for idx in to_remove:
|
||||||
|
var screen_idx = []
|
||||||
|
var i = 0
|
||||||
|
match dir:
|
||||||
|
LogicalGrid.FlowDirection.Up:
|
||||||
|
i = idx[0]
|
||||||
|
screen_idx = [i, grid_height + counts[i]]
|
||||||
|
LogicalGrid.FlowDirection.Down:
|
||||||
|
i = idx[0]
|
||||||
|
screen_idx = [i, -1 - counts[i]]
|
||||||
|
LogicalGrid.FlowDirection.Left:
|
||||||
|
i = idx[1]
|
||||||
|
screen_idx = [grid_width + counts[i], i]
|
||||||
|
LogicalGrid.FlowDirection.Right:
|
||||||
|
i = idx[1]
|
||||||
|
screen_idx = [-1 - counts[i], i]
|
||||||
|
counts[i] = counts[i] + 1
|
||||||
|
add_gem(idx[0], idx[1], screen_idx[0], screen_idx[1])
|
||||||
|
## Add new gems to fill the empty spaces
|
||||||
|
#for i in range(grid_width):
|
||||||
|
# var count = 0
|
||||||
|
# for _j in range(grid[i].size(), grid_height):
|
||||||
|
# # gems are not added on the position they are on the grid,
|
||||||
|
# # but outside so that animation plays correctly
|
||||||
|
# add_gem(i, count + grid_height)
|
||||||
|
# count += 1
|
||||||
|
# Update gems next position
|
||||||
|
for i in range(grid_width):
|
||||||
|
for j in range(grid_height):
|
||||||
|
grid.at(i, j).move_to_position(i, j)
|
||||||
|
if current_state == State.INIT:
|
||||||
|
grid.at(i, j).update_position()
|
||||||
|
# Emit events and compute next state
|
||||||
|
if current_state != State.INIT:
|
||||||
|
emit_signal("gem_matched", results)
|
||||||
|
if no_match:
|
||||||
|
next_state = State.READY
|
||||||
|
else:
|
||||||
|
next_state = State.SWAPPING
|
||||||
|
|
||||||
|
# If a gem is surrounded by two gem of the same type vertically or horizontally,
|
||||||
|
# mark the gem and its surronding gems as matched
|
||||||
|
func check_matched():
|
||||||
|
for i in range(grid_width):
|
||||||
|
for j in range(grid_height):
|
||||||
|
check_matched_at(i, j)
|
||||||
|
|
||||||
|
func check_matched_at(i, j):
|
||||||
|
# check vertically
|
||||||
|
var up_i = i
|
||||||
|
var up_j = j - 1
|
||||||
|
var down_i = i
|
||||||
|
var down_j = j + 1
|
||||||
|
if (up_j >= 0) and (down_j < grid_height):
|
||||||
|
if same_type(i, j, up_i, up_j) and same_type(i, j, down_i, down_j):
|
||||||
|
# match
|
||||||
|
mark_matched(i, j)
|
||||||
|
mark_matched(up_i, up_j)
|
||||||
|
mark_matched(down_i, down_j)
|
||||||
|
# Add a bonus if the effect is the same
|
||||||
|
if same_effect(i, j, up_i, up_j) and same_effect(i, j, down_i, down_j):
|
||||||
|
mark_bonus(i, j)
|
||||||
|
# Check horizontally
|
||||||
|
var left_i = i - 1
|
||||||
|
var left_j = j
|
||||||
|
var right_i = i + 1
|
||||||
|
var right_j = j
|
||||||
|
if (left_i >= 0) and (right_i < grid_width):
|
||||||
|
if same_type(i, j, left_i, left_j) and same_type(i, j, right_i, right_j):
|
||||||
|
# match
|
||||||
|
mark_matched(i, j)
|
||||||
|
mark_matched(left_i, left_j)
|
||||||
|
mark_matched(right_i, right_j)
|
||||||
|
# Add a bonus if the effect is the same
|
||||||
|
if same_effect(i, j, left_i, left_j) and same_effect(i, j, right_i, right_j):
|
||||||
|
mark_bonus(i, j)
|
||||||
|
|
||||||
|
func mark_matched(i, j):
|
||||||
|
var g = grid.at(i, j)
|
||||||
|
g.set_matched()
|
||||||
|
# disconnect signals related to gem displacement
|
||||||
|
if is_connected("gems_swapped", g, "update_position"):
|
||||||
|
disconnect("gems_swapped", g, "update_position")
|
||||||
|
if g.is_connected("position_reached", self, "on_gem_moved"):
|
||||||
|
g.disconnect("position_reached", self, "on_gem_moved")
|
||||||
|
|
||||||
|
func mark_bonus(i, j):
|
||||||
|
var g = grid.at(i, j)
|
||||||
|
g.set_bonus()
|
||||||
|
|
||||||
|
# True if gems at (i,j) and (x,y) have the same type
|
||||||
|
func same_type(i, j, x, y):
|
||||||
|
return grid.at(i, j).type == grid.at(x, y).type
|
||||||
|
|
||||||
|
# True is gems at (i,j) and (x,y) have the same effect
|
||||||
|
func same_effect(i, j, x, y):
|
||||||
|
return grid.at(i, j).effect == grid.at(x, y).effect
|
||||||
|
|
||||||
|
# Cursor management
|
||||||
|
func update_cursor():
|
||||||
|
# Position
|
||||||
|
$Cursor.set_position(64 * Vector2(cursor_i,cursor_j))
|
||||||
|
# Selected ?
|
||||||
|
var offset = 0
|
||||||
|
if gem_selected:
|
||||||
|
offset = 128
|
||||||
|
$Cursor.texture.region.position.x = offset
|
||||||
|
|
||||||
|
func show_cursor():
|
||||||
|
$Cursor.show()
|
||||||
|
|
||||||
|
func hide_cursor():
|
||||||
|
$Cursor.hide()
|
||||||
|
|
||||||
|
# Input handling
|
||||||
|
# Only handle events if state is READY and not in transition
|
||||||
|
func accept_input():
|
||||||
|
return (current_state == State.READY) and (next_state == State.NONE)
|
||||||
|
|
||||||
|
func up():
|
||||||
|
if accept_input():
|
||||||
|
if gem_selected:
|
||||||
|
gem_swap(cursor_i, cursor_j - 1)
|
||||||
|
else:
|
||||||
|
cursor_j = cursor_j - 1
|
||||||
|
if cursor_j < 0:
|
||||||
|
cursor_j = grid_height - 1
|
||||||
|
update_cursor()
|
||||||
|
|
||||||
|
func down():
|
||||||
|
if accept_input():
|
||||||
|
if gem_selected:
|
||||||
|
gem_swap(cursor_i, cursor_j + 1)
|
||||||
|
else:
|
||||||
|
cursor_j = (cursor_j + 1) % grid_height
|
||||||
|
update_cursor()
|
||||||
|
|
||||||
|
func left():
|
||||||
|
if accept_input():
|
||||||
|
if gem_selected:
|
||||||
|
gem_swap(cursor_i - 1, cursor_j)
|
||||||
|
else:
|
||||||
|
cursor_i = cursor_i - 1
|
||||||
|
if cursor_i < 0:
|
||||||
|
cursor_i = grid_width - 1
|
||||||
|
update_cursor()
|
||||||
|
|
||||||
|
func right():
|
||||||
|
if accept_input():
|
||||||
|
if gem_selected:
|
||||||
|
gem_swap(cursor_i + 1, cursor_j)
|
||||||
|
else:
|
||||||
|
cursor_i = (cursor_i + 1) % grid_width
|
||||||
|
update_cursor()
|
||||||
|
|
||||||
|
func select():
|
||||||
|
if accept_input():
|
||||||
|
gem_selected = !gem_selected
|
||||||
|
update_cursor()
|
||||||
|
|
||||||
|
func cancel():
|
||||||
|
if accept_input():
|
||||||
|
gem_selected = false
|
||||||
|
update_cursor()
|
|
@ -0,0 +1,44 @@
|
||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://entities/gem_grid.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://entities/gem_selector.svg" type="Texture" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id=1]
|
||||||
|
flags = 4
|
||||||
|
atlas = ExtResource( 2 )
|
||||||
|
region = Rect2( 0, 0, 128, 128 )
|
||||||
|
|
||||||
|
[node name="GemGrid" type="Control"]
|
||||||
|
margin_right = 512.0
|
||||||
|
margin_bottom = 512.0
|
||||||
|
rect_clip_content = true
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="ColorRect" type="ColorRect" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
color = Color( 0.603922, 0.647059, 0.65098, 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Gems" type="Control" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Cursor" type="TextureRect" parent="."]
|
||||||
|
margin_right = 64.0
|
||||||
|
margin_bottom = 64.0
|
||||||
|
rect_min_size = Vector2( 64, 64 )
|
||||||
|
texture = SubResource( 1 )
|
||||||
|
expand = true
|
||||||
|
stretch_mode = 1
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="256"
|
||||||
|
height="128"
|
||||||
|
viewBox="0 0 67.733332 33.866668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg41030"
|
||||||
|
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
|
||||||
|
sodipodi:docname="gem_selector.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview41032"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:zoom="4.4328844"
|
||||||
|
inkscape:cx="93.392916"
|
||||||
|
inkscape:cy="63.502671"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1049"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs41027" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
id="rect41113"
|
||||||
|
style="fill:#e5bf00;fill-opacity:1;stroke:none;stroke-width:5.00031;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:markers fill stroke"
|
||||||
|
d="M 0,0 V 54 H 10 V 10 H 54 V 0 Z m 74,0 v 10 h 44 v 44 h 10 V 0 Z M 0,74 v 54 H 54 V 118 H 10 V 74 Z m 118,0 v 44 H 74 v 10 h 54 V 74 Z"
|
||||||
|
transform="scale(0.26458334)" />
|
||||||
|
<path
|
||||||
|
id="path41877"
|
||||||
|
style="fill:#00e5e5;fill-opacity:1;stroke:none;stroke-width:1.323;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:markers fill stroke"
|
||||||
|
d="m 33.866667,0 v 14.2875 h 2.645834 V 2.6458334 H 48.154168 V 0 Z M 53.445835,0 V 2.6458334 H 65.087502 V 14.2875 h 2.645833 V 0 Z M 33.866667,19.579167 V 33.866668 H 48.154168 V 31.220834 H 36.512501 V 19.579167 Z m 31.220835,0 V 31.220834 H 53.445835 v 2.645834 h 14.2875 V 19.579167 Z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,35 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/gem_selector.svg-7ce7dce652630ac09e42a628d1b9123f.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://entities/gem_selector.svg"
|
||||||
|
dest_files=[ "res://.import/gem_selector.svg-7ce7dce652630ac09e42a628d1b9123f.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 99 KiB |
|
@ -0,0 +1,35 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/gems.svg-4ba00769f724f70394c92013b0796a53.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://entities/gems.svg"
|
||||||
|
dest_files=[ "res://.import/gems.svg-4ba00769f724f70394c92013b0796a53.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
|
@ -0,0 +1,20 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
export(Gem.Type) var type = Gem.Type.Thermic
|
||||||
|
export(Gem.Effect) var effect = Gem.Effect.ManaNegative
|
||||||
|
|
||||||
|
var count: int = 0
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready():
|
||||||
|
$Gem.type = type
|
||||||
|
$Gem.effect = effect
|
||||||
|
$Gem.update_sprite()
|
||||||
|
$Label.text = str(count)
|
||||||
|
|
||||||
|
func update_count(matched: Dictionary):
|
||||||
|
for k in matched.keys():
|
||||||
|
if (k[0] == type) and (k[1] == effect):
|
||||||
|
count += matched[k]
|
||||||
|
break
|
||||||
|
$Label.text = str(count)
|
|
@ -0,0 +1,23 @@
|
||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://entities/gem.tscn" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://entities/mana_counter.gd" type="Script" id=2]
|
||||||
|
|
||||||
|
[node name="ManaCounter" type="Control"]
|
||||||
|
margin_right = 192.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Gem" parent="." instance=ExtResource( 1 )]
|
||||||
|
rect_scale = Vector2( 0.5, 0.5 )
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="."]
|
||||||
|
margin_left = 40.0
|
||||||
|
margin_top = 8.0
|
||||||
|
margin_right = 192.0
|
||||||
|
margin_bottom = 22.0
|
||||||
|
text = "0000"
|
||||||
|
clip_text = true
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg5"
|
||||||
|
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
|
||||||
|
sodipodi:docname="matched-particle.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview7"
|
||||||
|
pagecolor="#cccccc"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="true"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:zoom="35.463075"
|
||||||
|
inkscape:cx="5.3858838"
|
||||||
|
inkscape:cy="8.5299991"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1049"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
id="path1233"
|
||||||
|
style="fill:#ffffff;stroke-width:5.00032;stroke-linecap:round;stroke-linejoin:round;paint-order:markers fill stroke;fill-opacity:1"
|
||||||
|
d="M 15.640625 0.052734375 C 14.307469 0.11206338 8.7924422 3.5389988 8 3.5390625 C 7.1404017 3.5391316 0.72301334 -0.49264224 0.11523438 0.11523438 C -0.49254457 0.72311097 3.5389934 7.1404017 3.5390625 8 C 3.5391316 8.8595983 -0.49264224 15.276987 0.11523438 15.884766 C 0.72311097 16.492545 7.1404017 12.461007 8 12.460938 C 8.8595983 12.460868 15.276987 16.492642 15.884766 15.884766 C 16.492545 15.276889 12.461007 8.8595983 12.460938 8 C 12.460868 7.1404017 16.492642 0.72301334 15.884766 0.11523438 C 15.837275 0.067751645 15.753604 0.047706493 15.640625 0.052734375 z M 8 5 A 2.9999999 2.9999999 0 0 1 11 8 A 2.9999999 2.9999999 0 0 1 8 11 A 2.9999999 2.9999999 0 0 1 5 8 A 2.9999999 2.9999999 0 0 1 8 5 z "
|
||||||
|
transform="scale(0.26458333)" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,35 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/matched-particle.svg-416c5e1325ce98f7ffcae31d9908d4ad.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://entities/matched-particle.svg"
|
||||||
|
dest_files=[ "res://.import/matched-particle.svg-416c5e1325ce98f7ffcae31d9908d4ad.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
|
@ -0,0 +1,35 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.png"
|
||||||
|
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
|
@ -0,0 +1,53 @@
|
||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
_global_script_classes=[ {
|
||||||
|
"base": "Control",
|
||||||
|
"class": "Gem",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://entities/gem.gd"
|
||||||
|
}, {
|
||||||
|
"base": "Reference",
|
||||||
|
"class": "LogicalGrid",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://tools/logical_grid.gd"
|
||||||
|
}, {
|
||||||
|
"base": "Reference",
|
||||||
|
"class": "Random",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://tools/random.gd"
|
||||||
|
} ]
|
||||||
|
_global_script_class_icons={
|
||||||
|
"Gem": "",
|
||||||
|
"LogicalGrid": "",
|
||||||
|
"Random": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Match Battle"
|
||||||
|
run/main_scene="res://Main.tscn"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/stretch/mode="2d"
|
||||||
|
window/stretch/aspect="keep"
|
||||||
|
|
||||||
|
[physics]
|
||||||
|
|
||||||
|
common/enable_pause_aware_picking=true
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
quality/driver/driver_name="GLES2"
|
||||||
|
vram_compression/import_etc=true
|
||||||
|
vram_compression/import_etc2=false
|
||||||
|
environment/default_environment="res://default_env.tres"
|
|
@ -0,0 +1,102 @@
|
||||||
|
extends Reference
|
||||||
|
class_name LogicalGrid
|
||||||
|
|
||||||
|
# Grid with a flow direction for the item added / removed
|
||||||
|
# The position on grid must be translated as the position in the array is different
|
||||||
|
|
||||||
|
enum FlowDirection { Up, Down, Left, Right }
|
||||||
|
|
||||||
|
# Fields
|
||||||
|
var width: int # width
|
||||||
|
var height: int # height
|
||||||
|
var table: Array = [] # table = array of columns or rows depending on the direction
|
||||||
|
var flow_direction = FlowDirection.Up
|
||||||
|
|
||||||
|
# Constructor
|
||||||
|
func _init(width: int, height: int):
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
# By default, array is initialized with empty arrays
|
||||||
|
for x in range(0, width):
|
||||||
|
table.push_back(Array())
|
||||||
|
|
||||||
|
# Get flow direction
|
||||||
|
func get_flow_direction():
|
||||||
|
return self.flow_direction
|
||||||
|
|
||||||
|
# Set flow direction
|
||||||
|
func set_flow_direction(dir):
|
||||||
|
# Keep old values
|
||||||
|
var old_table = self.table
|
||||||
|
var old_dir = self.flow_direction
|
||||||
|
# Update the flow direction
|
||||||
|
self.flow_direction = dir
|
||||||
|
# Update the array to reflect the change in flow direction
|
||||||
|
self.table = []
|
||||||
|
if (dir == FlowDirection.Up) or (dir == FlowDirection.Down):
|
||||||
|
for nx in range(width):
|
||||||
|
self.table.push_back(Array())
|
||||||
|
for ny in range(height):
|
||||||
|
self.table[nx].push_back(false)
|
||||||
|
else:
|
||||||
|
for ny in range(height):
|
||||||
|
self.table.push_back(Array())
|
||||||
|
for nx in range(width):
|
||||||
|
self.table[ny].push_back(false)
|
||||||
|
# Set the real values
|
||||||
|
for i in range(width):
|
||||||
|
for j in range(height):
|
||||||
|
var old_idx = get_idx(i, j, old_dir)
|
||||||
|
var new_idx = get_idx(i, j, dir)
|
||||||
|
self.table[new_idx[0]][new_idx[1]] = old_table[old_idx[0]][old_idx[1]]
|
||||||
|
|
||||||
|
# Get the index in the table depending on the flow direction
|
||||||
|
func get_idx(x, y, dir = self.flow_direction):
|
||||||
|
match dir:
|
||||||
|
FlowDirection.Up:
|
||||||
|
return [x, y]
|
||||||
|
FlowDirection.Down:
|
||||||
|
return [x, height - 1 - y]
|
||||||
|
FlowDirection.Left:
|
||||||
|
return [y, x]
|
||||||
|
FlowDirection.Right:
|
||||||
|
return [y, width - 1 - x]
|
||||||
|
|
||||||
|
# Get value at position
|
||||||
|
func at(x: int, y: int):
|
||||||
|
var idx = get_idx(x, y)
|
||||||
|
return self.table[idx[0]][idx[1]]
|
||||||
|
|
||||||
|
# Set value at position
|
||||||
|
func set_at(x: int, y: int, val):
|
||||||
|
var idx = get_idx(x, y)
|
||||||
|
self.table[idx[0]][idx[1]] = val
|
||||||
|
|
||||||
|
# Remove a value from the table
|
||||||
|
#func remove_at(x: int, y:int):
|
||||||
|
# var idx = get_idx(x, y)
|
||||||
|
# self.table[idx[0]].remove(idx[1])
|
||||||
|
|
||||||
|
# Remove the values from a list of indexes
|
||||||
|
class IdxSorter:
|
||||||
|
static func higher_idx_first(a, b):
|
||||||
|
return (a[0] > b[0]) or ((a[0] == b[0]) and (a[1] > b[1]))
|
||||||
|
func remove_values(lst_idx: Array):
|
||||||
|
# Tranform the values
|
||||||
|
var new_idx = []
|
||||||
|
for idx in lst_idx:
|
||||||
|
new_idx.push_back(get_idx(idx[0], idx[1]))
|
||||||
|
new_idx.sort_custom(IdxSorter, "higher_idx_first")
|
||||||
|
for idx in new_idx:
|
||||||
|
self.table[idx[0]].remove(idx[1])
|
||||||
|
|
||||||
|
# Push a value to the grid, the position indicate the row or column to push to
|
||||||
|
func push_value(x: int, y: int, val):
|
||||||
|
var idx = get_idx(x, y)
|
||||||
|
self.table[idx[0]].push_back(val)
|
||||||
|
|
||||||
|
# Swap two values
|
||||||
|
func swap_values(x1: int, y1: int, x2: int, y2: int):
|
||||||
|
var v = self.at(x1, y1)
|
||||||
|
self.set_at(x1, y1, self.at(x2, y2))
|
||||||
|
self.set_at(x2, y2, v)
|
|
@ -0,0 +1,36 @@
|
||||||
|
extends Reference
|
||||||
|
class_name Random
|
||||||
|
|
||||||
|
# Generator
|
||||||
|
var generator: RandomNumberGenerator = RandomNumberGenerator.new()
|
||||||
|
|
||||||
|
# Init
|
||||||
|
func _init():
|
||||||
|
generator.randomize()
|
||||||
|
|
||||||
|
# Generate from a range (inclusive)
|
||||||
|
func pick_from_range(v1: int, v2: int):
|
||||||
|
return generator.randi_range(v1, v2)
|
||||||
|
|
||||||
|
# Generate from an Array
|
||||||
|
func pick_from_array(a: Array):
|
||||||
|
var idx = generator.randi_range(0, a.size() - 1)
|
||||||
|
return a[idx]
|
||||||
|
|
||||||
|
# Generate from a dictionary of (value, weight)
|
||||||
|
func pick_from_distribution(d: Dictionary):
|
||||||
|
var keys = d.keys()
|
||||||
|
var weight_sum = 0
|
||||||
|
for k in keys:
|
||||||
|
weight_sum += d[k]
|
||||||
|
# pick a number between 0 and the total minus 1
|
||||||
|
var val = generator.randi_range(0, weight_sum - 1)
|
||||||
|
# Compute the sums until val < current_sum
|
||||||
|
var current_sum = 0
|
||||||
|
var ret = keys.front()
|
||||||
|
for k in keys:
|
||||||
|
current_sum += d[k]
|
||||||
|
ret = k
|
||||||
|
if val < current_sum:
|
||||||
|
break
|
||||||
|
return ret
|
Loading…
Reference in New Issue