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