实现八音盒小游戏所有玩法细节
This commit is contained in:
parent
994cd7d28b
commit
5413e8fe33
47
scene/little_game/gadget/wheel.gd
Normal file
47
scene/little_game/gadget/wheel.gd
Normal file
@ -0,0 +1,47 @@
|
||||
extends Control
|
||||
|
||||
# A wheel that can be rotated by the player.
|
||||
# Detects the angle of the wheel and emits a signal when the wheel is rotated.
|
||||
# The value might be positive or negative, and the negative value means the wheel is rotated in clockwise.
|
||||
signal rotated(radiant: float)
|
||||
|
||||
@export var enabled := true:
|
||||
set(val):
|
||||
enabled = val
|
||||
dragging = false
|
||||
@export var min_angle := 30.0
|
||||
@export var one_direction := true
|
||||
@export var clockwise := true
|
||||
|
||||
var start_pos := Vector2.ZERO
|
||||
var dragging := false
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if not enabled:
|
||||
return
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
if event.pressed:
|
||||
start_pos = event.position
|
||||
dragging = true
|
||||
else:
|
||||
dragging = false
|
||||
# print("mouse button")
|
||||
elif event is InputEventMouseMotion:
|
||||
if dragging:
|
||||
var current_pos = event.position
|
||||
# current node's viewport position
|
||||
var origin := get_viewport().global_canvas_transform * global_position
|
||||
# Calculate the angle between the start_pos and the current_pos around the origin.
|
||||
var radiant = (current_pos - origin).angle_to(start_pos - origin)
|
||||
var min_rad = min_angle * PI / 180
|
||||
if abs(radiant) > min_rad:
|
||||
# check if the wheel is rotated in the correct direction
|
||||
if one_direction:
|
||||
if (clockwise and radiant > 0) or (not clockwise and radiant < 0):
|
||||
start_pos = current_pos
|
||||
return
|
||||
rotated.emit(radiant)
|
||||
start_pos = current_pos
|
||||
# print(radiant, current_pos)
|
8
scene/little_game/gadget/wheel.tscn
Normal file
8
scene/little_game/gadget/wheel.tscn
Normal file
@ -0,0 +1,8 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dry6mhv6x0ppl"]
|
||||
|
||||
[ext_resource type="Script" path="res://scene/little_game/gadget/wheel.gd" id="1_halh6"]
|
||||
|
||||
[node name="Wheel" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
script = ExtResource("1_halh6")
|
@ -2,16 +2,18 @@ extends Control
|
||||
|
||||
# answer for the puzzle, by columns
|
||||
@export var current_answer := [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
# @export var answer := [1, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
@export var answer := [1, 4, 3, 1, 3, 6, 4, 3, 2]
|
||||
@export_enum("closed", "opened", "playing", "finished") var mode := "closed"
|
||||
|
||||
@export var answer := [1, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
# @export var answer := [1, 4, 3, 1, 3, 6, 4, 3, 2]
|
||||
@export var playing_step_degree := 45.0
|
||||
@export var playing_steps := 10
|
||||
|
||||
@onready var points_polygon = $ButtonPositionPoints as Polygon2D
|
||||
@onready var box = $Box as TextureRect
|
||||
@onready var side_handle = $SideHandle as AnimatedSprite2D
|
||||
@onready var inside_handle = $Handle as TextureButton
|
||||
@onready var side_handle = $Box/SideHandle as AnimatedSprite2D
|
||||
@onready var inside_handle = $InsideHandle as TextureButton
|
||||
@onready var audio_player = $MusicPlayer2D as AudioStreamPlayer2D
|
||||
@onready var handle_wheel = $Wheel
|
||||
|
||||
var button_texture = preload("res://asset/art/little_game/八音盒/小猫.png")
|
||||
var button_highlight_texture = preload("res://asset/art/little_game/八音盒/小猫高亮.png")
|
||||
@ -23,14 +25,13 @@ var box_finished_texture = preload("res://asset/art/little_game/八音盒/有按
|
||||
var sfx_interact = preload("res://asset/audio/sfx/game/八音盒/八音盒互动.mp3") as AudioStream
|
||||
var sfx_drag = preload("res://asset/audio/sfx/game/八音盒/拖动放置.mp3") as AudioStream
|
||||
var sfx_open = preload("res://asset/audio/sfx/game/八音盒/八音盒打开.mp3") as AudioStream
|
||||
var sfx_assemble = preload("res://asset/audio/sfx/game/八音盒/装上插销.mp3") as AudioStream
|
||||
var sfx_close = preload("res://asset/audio/sfx/game/八音盒/关盖子.mp3") as AudioStream
|
||||
var sfx_exit = preload("res://asset/audio/sfx/game/八音盒/退出界面.mp3") as AudioStream
|
||||
|
||||
var audio_manual = preload("res://asset/audio/sfx/game/八音盒/操纵八音盒.mp3") as AudioStream
|
||||
var audio_auto = preload("res://asset/audio/sfx/game/八音盒/自走八音盒.mp3") as AudioStream
|
||||
|
||||
var dragging = false
|
||||
|
||||
var current_selected_btn := 0:
|
||||
set(value):
|
||||
if has_node("button_root"):
|
||||
@ -41,20 +42,24 @@ var current_selected_btn := 0:
|
||||
root.get_node(str(value)).texture = button_highlight_texture
|
||||
current_selected_btn = value
|
||||
|
||||
var playing_step_sec := 0.5
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
playing_step_sec = audio_manual.get_length() / playing_steps
|
||||
_chechout_mode()
|
||||
inside_handle.pressed.connect(_on_handle_pressed)
|
||||
# SceneManager.focus_node(self)
|
||||
# CameraFocusMarker.lock_horizontal = false
|
||||
# CameraFocusMarker.limit_top = 0
|
||||
# CameraFocusMarker.limit_bottom = 316
|
||||
handle_wheel.rotated.connect(_on_wheel_rotated)
|
||||
|
||||
# # test close shaking effect
|
||||
# mode = "playing"
|
||||
# _chechout_mode(true)
|
||||
# get_tree().create_timer(1.0).timeout.connect(_on_auto_play_finished)
|
||||
|
||||
|
||||
func _chechout_mode(play_sfx := false) -> void:
|
||||
dragging = false
|
||||
$Handle.visible = mode == "opened"
|
||||
$SideHandle.visible = mode == "playing" or mode == "finished"
|
||||
inside_handle.visible = mode == "opened"
|
||||
side_handle.visible = mode == "playing" or mode == "finished"
|
||||
_reset_buttons()
|
||||
match mode:
|
||||
"closed":
|
||||
@ -69,7 +74,7 @@ func _chechout_mode(play_sfx := false) -> void:
|
||||
audio_player.play()
|
||||
box.texture = box_opened_texture
|
||||
"playing":
|
||||
audio_player.stream = sfx_drag
|
||||
audio_player.stream = audio_manual
|
||||
box.texture = box_opened_texture
|
||||
"finished":
|
||||
if play_sfx:
|
||||
@ -149,19 +154,90 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
elif event.is_action_pressed("right"):
|
||||
current_selected_btn = clampi(current_selected_btn + 1, 0, 8)
|
||||
if mode == "playing":
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
if event.pressed:
|
||||
dragging = true
|
||||
else:
|
||||
dragging = false
|
||||
if event is InputEventMouseMotion:
|
||||
if dragging:
|
||||
#TODO
|
||||
inside_handle.position += event.relative
|
||||
pass
|
||||
|
||||
|
||||
func _on_handle_pressed() -> void:
|
||||
if mode == "opened":
|
||||
mode = "playing"
|
||||
_chechout_mode(true)
|
||||
inside_handle.disabled = true
|
||||
$AnimationPlayer.play("handle_animation")
|
||||
|
||||
|
||||
func _checkout_playing():
|
||||
mode = "playing"
|
||||
box.z_index = 10
|
||||
var tween = create_tween()
|
||||
audio_player.stream = sfx_assemble
|
||||
audio_player.play()
|
||||
tween.tween_property(inside_handle, "modulate:a", 0, 0.2)
|
||||
tween.tween_callback(func(): _chechout_mode(true))
|
||||
|
||||
|
||||
var accumulated_radiant := 0.0
|
||||
# 8 steps in total, then auto play
|
||||
var accumulated_steps := 0
|
||||
var playing := false
|
||||
var continue_playing := false
|
||||
|
||||
|
||||
func _on_wheel_rotated(radiant: float) -> void:
|
||||
if mode != "playing" or accumulated_steps >= playing_steps:
|
||||
return
|
||||
accumulated_radiant += radiant
|
||||
if abs(accumulated_radiant) > deg_to_rad(playing_step_degree):
|
||||
accumulated_radiant = 0
|
||||
if playing:
|
||||
continue_playing = true
|
||||
else:
|
||||
playing = true
|
||||
side_handle.play("default")
|
||||
if accumulated_steps == 0:
|
||||
audio_player.play()
|
||||
else:
|
||||
audio_player.stream_paused = false
|
||||
get_tree().create_timer(playing_step_sec).timeout.connect(_on_playing_step_finished)
|
||||
|
||||
|
||||
func _on_playing_step_finished():
|
||||
accumulated_steps += 1
|
||||
if accumulated_steps == playing_steps:
|
||||
# auto play
|
||||
_checkout_auto_play()
|
||||
return
|
||||
if continue_playing:
|
||||
continue_playing = false
|
||||
get_tree().create_timer(playing_step_sec).timeout.connect(_on_playing_step_finished)
|
||||
else:
|
||||
playing = false
|
||||
audio_player.stream_paused = true
|
||||
side_handle.pause()
|
||||
|
||||
|
||||
func _checkout_auto_play():
|
||||
audio_player.stop()
|
||||
audio_player.stream = audio_auto
|
||||
audio_player.play()
|
||||
side_handle.play()
|
||||
# var audio_len = audio_auto.get_length()
|
||||
# 音效 9.5 秒时关闭盒子
|
||||
var audio_len = 9.5
|
||||
get_tree().create_timer(audio_len).timeout.connect(_on_auto_play_finished)
|
||||
|
||||
|
||||
func _on_auto_play_finished():
|
||||
side_handle.pause()
|
||||
mode = "finished"
|
||||
# 不播放关闭音效,因为自动播放时已经播放过了
|
||||
_chechout_mode(false)
|
||||
# 抖动效果,逐渐减弱
|
||||
var tween = create_tween()
|
||||
var fps := 6.0
|
||||
var duration := 0.5
|
||||
var delta := 4.0
|
||||
var origin_pos = box.position
|
||||
var count = int(duration * fps)
|
||||
var delta_t = 1.0 / fps
|
||||
for i in range(count):
|
||||
var offset = Vector2(randf_range(-delta, delta), randf_range(-delta, delta)) * exp(-i)
|
||||
tween.tween_property(box, "position", origin_pos + offset, delta_t).set_trans(
|
||||
Tween.TRANS_CUBIC
|
||||
)
|
||||
|
File diff suppressed because one or more lines are too long
11
util/canvas_util.gd
Normal file
11
util/canvas_util.gd
Normal file
@ -0,0 +1,11 @@
|
||||
class_name CanvasUtil extends Object
|
||||
|
||||
|
||||
# 晃动节点
|
||||
static func shake_node(node: CanvasItem, tween: Tween, duration: float, delta := 5.0, fps := 4.0) -> void:
|
||||
var origin_pos = node.position
|
||||
var count = int(duration * fps)
|
||||
var delta_t = 1.0 / fps
|
||||
for i in range(count):
|
||||
var offset = Vector2(randf_range(-delta, delta), randf_range(-delta, delta))
|
||||
tween.tween_property(node, "position", origin_pos + offset, delta_t).set_trans(Tween.TRANS_CUBIC)
|
Loading…
Reference in New Issue
Block a user