├── .gitignore ├── LICENSE ├── README.md ├── autoload ├── global.gd ├── hi_scores_manager.gd ├── notification_center.gd └── options_manager.gd ├── ball ├── ball.gd ├── ball.tscn └── ball_sprite.gd ├── board ├── arealost.gd ├── board.gd ├── board.tscn └── collision.gd ├── bonus ├── bonus.gd └── bonus.tscn ├── bonus_effect_manager ├── bonus_effect_manager.gd └── bonus_effect_manager.tscn ├── export_presets.cfg ├── fonts ├── Ricasso-Regular.ttf ├── font.tres ├── ricasso.fnt └── ricasso_font.tres ├── game_over ├── game_over.gd └── game_over.tscn ├── game_ui ├── ball_ui.gd ├── game_ui.gd └── game_ui.tscn ├── hi_scores ├── hi_scores.gd └── hi_scores.tscn ├── level ├── 1.gd ├── 2.gd ├── 3.gd ├── 4.gd ├── generic_level.gd ├── level.gd └── level.tscn ├── main.gd ├── main.tscn ├── materials ├── background_material.tres ├── background_shader.shd └── background_shader.tres ├── menu ├── menu.gd └── menu.tscn ├── new_hi_score_dialog ├── new_hi_score_dialog.gd └── new_hi_score_dialog.tscn ├── options ├── options.gd └── options.tscn ├── paddle ├── paddle.gd └── paddle.tscn ├── pause_dialog ├── pause_dialog.gd └── pause_dialog.tscn ├── project.godot ├── screenshots ├── screenshot.png └── screenshot.png.import ├── sounds ├── brick01.smp ├── brick01.wav ├── brick01.wav.import ├── pad.smp ├── pad.wav ├── pad.wav.import ├── wall.smp ├── wall.wav └── wall.wav.import ├── static_brick ├── brickshader.shd ├── brickshader1.shd ├── brickshader2.shd ├── static_brick.gd └── static_brick.tscn ├── textures ├── background.tres ├── black.png ├── black.png.import ├── bonus_big_paddle.png ├── bonus_big_paddle.png.import ├── bonus_extra_life.png ├── bonus_extra_life.png.import ├── bonus_score.png ├── bonus_score.png.import ├── bonus_small_paddle.png ├── bonus_small_paddle.png.import ├── bonus_sticky.png ├── bonus_sticky.png.import ├── bonus_three_balls.png ├── bonus_three_balls.png.import ├── brick01.ico ├── brick01.png ├── brick01.png.import ├── brick02.png ├── brick02.png.import ├── brick03.png ├── brick03.png.import ├── brick04.png ├── brick04.png.import ├── brick05.png ├── brick05.png.import ├── brick06.png ├── brick06.png.import ├── brick07.png ├── brick07.png.import ├── brick11.png ├── brick11.png.import ├── brick17.png ├── brick17.png.import ├── paddle.png └── paddle.png.import ├── themes └── main.tres ├── translations ├── translation.csv ├── translation.csv.import ├── translation.en.translation └── translation.fr.translation └── wall ├── wall.gd └── wall.tscn /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .fscache 3 | 4 | 5 | notes.txt 6 | export 7 | .import 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Didier Vandekerckhove 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Breakable 2 | A breakout-like game made with Godot Engine 3 | 4 | I made this game to learn Godot and test various features. 5 | ![Screenshot](screenshots/screenshot.png) 6 | 7 | ### Godot 3.4 8 | The master branch is now compatible with Godot 3.4.x. 9 | The Godot 2.x version is still available in the [Godot 2.1 branch](https://github.com/didier-v/breakable/tree/Godot-2.1). 10 | - new $ syntax for get_nodes 11 | - rewrote code incompatible with the new physics engine 12 | - small fixes and improvements 13 | 14 | ### Godot 2.1 15 | - tres format for theme 16 | 17 | ### Godot 2.0 18 | - tscn format readable scenes 19 | - autoload singletons 20 | - onready option 21 | 22 | ### Things I learned 23 | - Autoload magic 24 | - How to switch scenes 25 | - Loading and saving a file (user options) 26 | - Loading and saving an encrypted file (hi scores) 27 | - How to manage multiple languages 28 | - How to use fonts 29 | - How to use a theme 30 | - Window / Full screen 31 | - How to import and play sounds 32 | - Physics and collisions 2D 33 | - Collisions layers 34 | - How to add and remove instances with code 35 | - Connect an event on a UI element to a script 36 | - Use animations on UI elements 37 | - Animation with call function track 38 | - How to make a generic, reusable canvas item (see walls) 39 | - How to use a shader as a background 40 | 41 | 42 | This project also uses my [Godot Notification Center](https://github.com/didier-v/GodotNotificationCenter) in various ways. 43 | 44 | The sounds were made with [Cfxr](http://thirdcog.eu/apps/cfxr). 45 | 46 | # License 47 | MIT 48 | -------------------------------------------------------------------------------- /autoload/global.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | #Collision layers 5 | #ball 1 , no mask 6 | #bonus 2 , no mask 7 | #brick 3, mask 1 8 | #paddle 1,2, mask 1,2 9 | 10 | #more ideas... 11 | # bonus aleatoires 12 | # fog 13 | # "ghost":5, 14 | # "ninja":5 15 | # textures des bonus aleatoires 16 | # types de briques 17 | ## briques à 3 hits 18 | ## briques mobiles 19 | ## briques indestructibles 20 | # animation sur balle perdue 21 | # transition entre niveaux 22 | # hi score 23 | # bonus temps sur un niveau 24 | 25 | 26 | 27 | var score # score of the current game 28 | var brick_texture #array of brick textures 29 | var bonus_texture #dictionary of bonus textures 30 | var bonus_effect #dictionary of bonus effects 31 | var bonus_message #dictionary of bonus messages 32 | 33 | #constants 34 | const BRICK_WIDTH = 86 35 | const BRICK_HEIGHT = 37 36 | const INITIAL_PADDLE_WIDTH = 100 37 | const PADDLE_HEIGHT=15 38 | const MAX_LEVEL = 2 39 | 40 | func _ready(): 41 | 42 | score=0 43 | 44 | bonus_texture = { 45 | "score":preload("res://textures/bonus_score.png"), 46 | "sticky":preload("res://textures/bonus_sticky.png"), 47 | "three_balls":preload("res://textures/bonus_three_balls.png"), 48 | "extra_life":preload("res://textures/bonus_extra_life.png"), 49 | "small_paddle":preload("res://textures/bonus_small_paddle.png"), 50 | "big_paddle":preload("res://textures/bonus_big_paddle.png") 51 | } 52 | 53 | bonus_effect = { 54 | "score":15, 55 | "sticky":15, 56 | "three_balls":10, 57 | "extra_life":5, 58 | "small_paddle":15, 59 | "big_paddle":15, 60 | # "ninja_stars":10, ## More ideas 61 | # "ghost":5, 62 | # "fog":10 63 | } 64 | 65 | bonus_message = { 66 | "score":"BONUS_SCORE", 67 | "sticky":"BONUS_STICKY", 68 | "three_balls":"BONUS_THREE_BALLS", 69 | "extra_life":"BONUS_EXTRA_LIFE", 70 | "small_paddle":"BONUS_SMALL_PADDLE", 71 | "big_paddle":"BONUS_BIG_PADDLE", 72 | # "ninja_stars":10, 73 | # "ghost":5, 74 | # "fog":10 75 | } 76 | 77 | 78 | brick_texture=[null, 79 | preload("res://textures/brick01.png"), #1 hit 80 | preload("res://textures/brick11.png") #2 hits 81 | ] 82 | 83 | randomize() 84 | #mod_scener = get_node("/root/mod_scener") 85 | 86 | 87 | 88 | #SCENE MANAGEMENT 89 | 90 | func new_game(): 91 | get_tree().change_scene("res://board/board.tscn") 92 | 93 | func load_menu(): 94 | get_tree().change_scene("res://menu/menu.tscn") 95 | 96 | func load_hi_scores(): 97 | get_tree().change_scene("res://hi_scores/hi_scores.tscn") 98 | 99 | func load_options(): 100 | get_tree().change_scene("res://options/options.tscn") 101 | 102 | func load_game_over(_score): 103 | get_tree().change_scene("res://game_over/game_over.tscn") 104 | 105 | func quit(): 106 | get_tree().quit() 107 | -------------------------------------------------------------------------------- /autoload/hi_scores_manager.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | var score_names #array of the names of the best players 4 | var score_values #array of their scores 5 | var HI_SCORE_SIZE = 10 6 | 7 | func _ready(): 8 | score_names = [] 9 | score_values = [] 10 | read_scores() #load file of hi scores 11 | 12 | func get_lowest_hi_score(): 13 | #this function is useful to know if the last player deserves to be in the hi score list 14 | if score_values.size()score_values[i]): #insert the score, keep the array sorted by value 27 | score_values.insert(i,score) 28 | score_names.insert(i,playername) 29 | i=score_values.size() 30 | elif i==(score_values.size()-1): #some room left, put this low score at the end of the array 31 | score_values.append(score) 32 | score_names.append(playername) 33 | i=score_values.size() 34 | i+=1 35 | 36 | if score_values.size()>HI_SCORE_SIZE: #delete the lowest scores by resizing the arrays 37 | score_values.resize(HI_SCORE_SIZE) 38 | score_names.resize(HI_SCORE_SIZE) 39 | write_scores() #save to file 40 | 41 | 42 | 43 | func read_scores(): 44 | var f = File.new() 45 | if(f.file_exists("user://hiscores.data")): 46 | var _err = f.open_encrypted_with_pass("user://hiscores.data",File.READ,"foo") #encrypted file, so players don't cheat. 47 | score_names = f.get_var() 48 | score_values = f.get_var() 49 | f.close() 50 | 51 | 52 | func write_scores(): 53 | var f = File.new() 54 | var err = f.open_encrypted_with_pass("user://hiscores.data",File.WRITE,"foo") #will create or replace the file 55 | f.store_var(score_names) 56 | f.store_var(score_values) 57 | f.close() 58 | -------------------------------------------------------------------------------- /autoload/notification_center.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | # GodotNotificationCenter 4 | # https://github.com/didier-v/GodotNotificationCenter 5 | # Written by Didier Vandekerckhove 6 | # licence: MIT 7 | 8 | var notifications 9 | 10 | func _ready(): 11 | notifications = {}; 12 | pass 13 | 14 | func post_notification(notificationName,notificationData): 15 | if notifications.has(notificationName): 16 | var currentObservers=notifications[notificationName].observers 17 | for i in currentObservers: 18 | var anObserver = currentObservers[i] 19 | if anObserver.object.has_method(anObserver.action): 20 | anObserver.object.call(anObserver.action,anObserver.object,notificationName,notificationData) 21 | 22 | func add_observer(observer,notificationName,action): 23 | if not notifications.has(notificationName): 24 | notifications[notificationName]={ 25 | "observers":{} 26 | } 27 | var currentObservers=notifications[notificationName].observers 28 | currentObservers[observer.get_instance_id()]={ 29 | "object":observer, 30 | "action":action 31 | } 32 | 33 | func remove_observer(observer, notificationName): 34 | if notifications.has(notificationName): 35 | var currentObservers=notifications[notificationName].observers 36 | if currentObservers.has(observer.get_instance_id()): 37 | currentObservers.erase(observer.get_instance_id()) 38 | 39 | 40 | -------------------------------------------------------------------------------- /autoload/options_manager.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | func read_options(): 5 | var options = {} 6 | var f = File.new() 7 | if f.file_exists("user://options.data"): 8 | var err = f.open("user://options.data",File.READ) 9 | options = f.get_var() 10 | f.close() 11 | return options 12 | 13 | func write_options(options): 14 | var f = File.new() 15 | var err = f.open("user://options.data",File.WRITE) #will create or replace the file 16 | f.store_var(options) 17 | f.close() 18 | 19 | 20 | -------------------------------------------------------------------------------- /ball/ball.gd: -------------------------------------------------------------------------------- 1 | 2 | extends RigidBody2D 3 | 4 | #autoload singletons: 5 | # - nc: notification center 6 | 7 | 8 | var speed setget set_speed, get_speed # ball speed 9 | var active setget set_active #boolean true is ball is active (playing) 10 | var relative_pos_x =0 # ball position relative to the paddle, used to calculate the bounce angle 11 | var board # the board object, must be set by the object creating the ball 12 | var paddle_position = Vector2() #for the sticky bonus 13 | var is_starting = false # for the first call to integrate_forces 14 | 15 | func _ready(): 16 | set_active(false) 17 | nc.add_observer(self,"paddle_hit","paddle_hit") #What the ball should do when it hits the paddle 18 | nc.add_observer(self,"paddle_moved","follow_paddle") #when game starts (or sticky bonus), the ball follows the paddle 19 | 20 | func _integrate_forces(state): 21 | if is_starting: 22 | state.transform.origin = paddle_position 23 | is_starting = false 24 | elif board && board.sticky && !active: 25 | state.transform.origin = paddle_position 26 | 27 | 28 | func _on_ball_body_entered( body ): 29 | if(body.name=="brick_body"): 30 | var brick = body.get_parent() 31 | nc.post_notification( "brick_hit",{"brick":brick,"ball":self}) #let other objects know that the ball touched a brick 32 | elif(body.name.find("wall")>0): 33 | nc.post_notification( "wall_hit","") #let other objects know that the ball hit a wall 34 | 35 | 36 | func _exit_tree(): 37 | #always clean notifications 38 | nc.remove_observer(self,"paddle_moved") 39 | nc.remove_observer(self,"paddle_hit") 40 | 41 | 42 | func _on_ball_body_exited( body ): 43 | var lv=get_linear_velocity().normalized()*speed 44 | set_linear_velocity(lv) 45 | if(body.name=="brick_body"): 46 | adjust_angle() 47 | 48 | 49 | func adjust_angle(): 50 | #here we cheat with the angle to make the game more enjoyable 51 | var min_angle = 20 #below 20, it's too horizontal 52 | var lv=get_linear_velocity().normalized()*speed #current velocity 53 | var angle = rad2deg(lv.angle_to(Vector2(1,0))) #current angle 54 | 55 | #bounce 56 | if (angle>0 and angle-min_angle): 59 | angle=angle+min_angle #>0 60 | elif (angle>180-min_angle and angle<180): 61 | angle=angle-180+min_angle #>0 62 | elif (angle<-180+min_angle and angle>-180): 63 | angle=angle+180-min_angle #<0 64 | else: 65 | angle=0 66 | if angle!=0: 67 | lv= lv.rotated(deg2rad(angle)) # we change the angle, but keep the speed 68 | set_linear_velocity(lv) 69 | 70 | 71 | func start(from_paddle=true): #balls don't start from the paddle when they are created by the three balls bonus 72 | is_starting = from_paddle 73 | set_active(true) 74 | var lv=Vector2(rand_range(-200,200),-200).normalized()*speed #starting velocity, with random angle 75 | set_linear_velocity(lv) 76 | 77 | func paddle_hit(object,action,data): 78 | if board.sticky: 79 | active=false #sticky bonus, stop the ball 80 | if active: 81 | nc.remove_observer(self,"paddle_moved") #when the ball is active, it doesn't stick to the paddle anymore 82 | else: 83 | relative_pos_x = data #this happens when the sticky bonus has been caught 84 | nc.add_observer(self,"paddle_moved","follow_paddle") 85 | 86 | func follow_paddle(object,action,data): 87 | var pos = data 88 | pos.y=pos.y-15 89 | pos.x=pos.x+relative_pos_x #sticky bonus again. we want ball to stick to the hit point of the paddle 90 | pos.x=clamp(pos.x,15,get_viewport_rect().size.x-15) 91 | paddle_position = pos 92 | position = paddle_position 93 | 94 | func set_active(is_active): 95 | active=is_active 96 | 97 | func set_speed(new_speed): 98 | speed=new_speed 99 | 100 | func get_speed(): 101 | return speed 102 | 103 | -------------------------------------------------------------------------------- /ball/ball.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://ball/ball.gd" type="Script" id=1] 4 | [ext_resource path="res://ball/ball_sprite.gd" type="Script" id=2] 5 | 6 | [sub_resource type="CircleShape2D" id=1] 7 | 8 | custom_solver_bias = 0.0 9 | radius = 5.0 10 | 11 | [node name="ball" type="RigidBody2D"] 12 | 13 | input_pickable = false 14 | collision_layer = 1 15 | collision_mask = 0 16 | mode = 0 17 | mass = 1.0 18 | friction = 0.0 19 | bounce = 1.0 20 | gravity_scale = 1.0 21 | custom_integrator = false 22 | continuous_cd = 0 23 | contacts_reported = 1 24 | contact_monitor = true 25 | sleeping = false 26 | can_sleep = true 27 | linear_velocity = Vector2( 0, 0 ) 28 | linear_damp = -1.0 29 | angular_velocity = 0.0 30 | angular_damp = -1.0 31 | script = ExtResource( 1 ) 32 | _sections_unfolded = [ "Collision", "Transform" ] 33 | 34 | [node name="Sprite" type="Sprite" parent="." index="0"] 35 | 36 | script = ExtResource( 2 ) 37 | 38 | [node name="CollisionShape2D" type="CollisionShape2D" parent="." index="1"] 39 | 40 | shape = SubResource( 1 ) 41 | _sections_unfolded = [ "Transform" ] 42 | 43 | [connection signal="body_entered" from="." to="." method="_on_ball_body_entered"] 44 | 45 | [connection signal="body_exited" from="." to="." method="_on_ball_body_exited"] 46 | 47 | 48 | -------------------------------------------------------------------------------- /ball/ball_sprite.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Sprite 3 | 4 | 5 | var radius 6 | 7 | func _ready(): 8 | position=Vector2(0,0) 9 | radius = 5 10 | 11 | #TODO, use a real picture instead 12 | func _draw(): 13 | draw_circle(position,radius, Color(1,1,1)) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /board/arealost.gd: -------------------------------------------------------------------------------- 1 | extends Area2D 2 | 3 | 4 | #func _draw(): # for tests only 5 | # 6 | # var e= get_shape(0).get_extents() 7 | # var r =Rect2(-e.x,-e.y,e.x*2,e.y*2) 8 | # draw_rect(r,Color(1,1,1,1)) 9 | # 10 | # -------------------------------------------------------------------------------- /board/board.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node 3 | 4 | #autoload singletons: 5 | # - global 6 | # - nc 7 | 8 | #resources 9 | onready var pause_dialog_desource = preload("res://pause_dialog/pause_dialog.tscn") 10 | onready var ball_resource = preload("res://ball/ball.tscn") 11 | onready var bonus_resource = preload("res://bonus/bonus.tscn") 12 | 13 | var current_level 14 | var playing # true if playing, false if about to start 15 | var lifes setget set_lifes # number of balls left 16 | var score setget set_score 17 | var current_speed 18 | var multiplier # every brick hit has its value multiplied by this 19 | var bricks_left 20 | var bricks_since_last_bonus 21 | var balls_in_game # usually 1 but can be more with the "three balls" bonus 22 | var sticky = false # for the sticky bonus 23 | 24 | 25 | func _ready(): 26 | 27 | #notifications 28 | nc.add_observer(self,"brick_hit","brick_hit") 29 | nc.add_observer(self,"paddle_hit","paddle_hit") 30 | nc.add_observer(self,"wall_hit","wall_hit") 31 | nc.add_observer(self,"bonus_hit","bonus_hit") 32 | 33 | #initial state 34 | score=0 35 | balls_in_game=0 36 | set_lifes(3) 37 | current_speed=0 38 | bricks_since_last_bonus = 0 39 | current_level=1 40 | init_level() 41 | $paddle.board = self 42 | 43 | #input 44 | set_process_input(true) 45 | 46 | #mouse 47 | Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) 48 | 49 | 50 | ##################### 51 | ###### EVENTS ####### 52 | ##################### 53 | func _exit_tree(): 54 | #clean notification center 55 | nc.remove_observer(self,"brick_hit") 56 | nc.remove_observer(self,"paddle_hit") 57 | nc.remove_observer(self,"wall_hit") 58 | nc.remove_observer(self,"bonus_hit") 59 | 60 | func _input(event): 61 | if event.is_action("ui_cancel") and not event.is_pressed() : # pause on ESC 62 | get_tree().set_input_as_handled() 63 | set_process_input(false) 64 | show_pause_dialog() 65 | if playing: 66 | if event.is_action("ui_fire"): # during a game, some bonus can be activated with the mouse button 67 | $bonus_effect_manager.fire_effect() 68 | else: #not playing 69 | if event.is_action("ui_fire"): # start a game 70 | playing = true 71 | multiplier=0 72 | start_ball() 73 | 74 | 75 | ##################### 76 | ###### PAUSE DIALOG # 77 | ##################### 78 | func show_pause_dialog(): 79 | var pause_dialog_node = pause_dialog_desource.instance() 80 | self.add_child(pause_dialog_node) 81 | pause_dialog_node.delegate = self #delegate will be called with close_dialog function 82 | pause_dialog_node.popup_centered() 83 | get_tree().set_pause(true) 84 | Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 85 | 86 | #delegate functions 87 | func close_dialog(dialog,response): 88 | dialog.queue_free() # close the dialog 89 | Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) 90 | get_tree().set_pause(false) # run the game 91 | set_process_input(true) # can process input again 92 | if(response.message=="Continue"): 93 | pass #keep playing 94 | else: 95 | global.load_menu() # abandon 96 | 97 | 98 | ######################### 99 | ###### LEVEL MANAGEMENT # 100 | ######################### 101 | func init_level(): 102 | $level.load_level(current_level) 103 | playing = false 104 | multiplier=0 105 | current_speed=230 106 | create_ball(current_speed) 107 | bricks_left = $level.get_total_bricks() 108 | 109 | func create_ball(speed): 110 | var ball = ball_resource.instance() 111 | add_child(ball) 112 | balls_in_game+=1 113 | ball.board = self 114 | ball.set_meta("type","ball") 115 | ball.set_speed(speed) 116 | return ball 117 | 118 | func start_ball(): 119 | for child in get_children(): #find balls 120 | if child.has_meta("type") && child.get_meta("type")=="ball": 121 | child.start() 122 | return 123 | 124 | 125 | 126 | ###################### 127 | ###### NOTIFICATIONS # 128 | ###################### 129 | func brick_hit( observer, notificationName,data): 130 | #this notification sends the brick and the ball 131 | var brick=data.brick 132 | var ball=data.ball 133 | $brick_sound.play(0) 134 | multiplier=multiplier+1 #increase score and multiplier when you hit multiple bricks before hitting the paddle 135 | set_score(score+(10*multiplier)) 136 | current_speed+=4.54 #increase speed 137 | ball.set_speed(current_speed) 138 | brick.set_current_hp(brick.current_hp-1) #for bricks that require several hits 139 | if (brick.current_hp==0): 140 | generate_bonus(brick.position) #the brick may drop a bonus 141 | brick.queue_free() 142 | bricks_left = bricks_left-1 143 | if(bricks_left==0): #no more bricks, end level 144 | for child in get_children(): #remove all balls 145 | if child.has_meta("type") && child.get_meta("type")=="ball": 146 | child.queue_free() 147 | balls_in_game=0 148 | current_level+=1 149 | if(current_level>global.MAX_LEVEL): 150 | current_level=1 151 | $board_animation.play("level_transition") #animation between levels 152 | 153 | func paddle_hit(observer, notificationName,notificationData): 154 | if playing: 155 | $pad_sound.play(0) # paddle 156 | multiplier=0 157 | 158 | func wall_hit(observer, notificationName,notificationData): 159 | if playing: 160 | $wall_sound.play(0) # wall 161 | 162 | func bonus_hit(observer, notificationName,bonus): 163 | #this notification sends the bonus hit 164 | bonus.queue_free() 165 | if playing: 166 | $bonus_effect_manager.apply_effect(bonus.effect) 167 | 168 | 169 | ####################### 170 | ###### COLLISIONS ##### 171 | ####################### 172 | func _on_area_lost_body_entered( body ): #area below the paddle 173 | if body.has_meta("type"): 174 | if body.get_meta("type")=="ball": 175 | if(balls_in_game==1): 176 | set_lifes(lifes-1) # remove 1 life 177 | $bonus_effect_manager.current_effect="" # remove current effet 178 | for child in get_children(): #remove all bonuses 179 | if child.has_meta("type") && child.get_meta("type")=="bonus": 180 | child.queue_free() 181 | $paddle.set_paddle_width(global.INITIAL_PADDLE_WIDTH) # restore paddle 182 | if lifes==0: 183 | global.load_game_over(score) # game over 184 | else: 185 | playing = false 186 | create_ball(current_speed) #new ball 187 | 188 | body.queue_free() # remove the ball 189 | balls_in_game-=1 190 | elif body.get_meta("type")=="bonus": 191 | body.queue_free() # remove the bonus 192 | 193 | 194 | ###################### 195 | ###### UTILITIES ##### 196 | ###################### 197 | 198 | func generate_bonus(pos): 199 | if !sticky: ## no bonus while sticky is active 200 | #the probability increases with each brick hit 201 | var i=bricks_since_last_bonus*bricks_since_last_bonus/320.0 202 | var x=randf() 203 | bricks_since_last_bonus+=1 204 | if(xglobal.INITIAL_PADDLE_WIDTH): 59 | paddle.set_paddle_width(global.INITIAL_PADDLE_WIDTH) 60 | else: 61 | paddle.set_paddle_width(global.INITIAL_PADDLE_WIDTH-50) 62 | current_effect="" 63 | 64 | #################### 65 | #BIG PADDLE 66 | func apply_big_paddle(): 67 | var paddle = board.get_node("paddle") 68 | if(paddle.paddle_widthhsm.get_lowest_hi_score() or debug): 15 | $hi_score_dialog.delegate = self 16 | $hi_score_dialog.score = global.score 17 | $hi_score_dialog.show_modal(true) 18 | $hi_score_dialog.show() 19 | 20 | func _on_play_again_pressed(): 21 | global.new_game() 22 | 23 | func _on_main_menu_pressed(): 24 | global.load_menu() 25 | 26 | #HI SCORE DIALOG DELEGATE 27 | func close_hi_score_dialog(dialog,playername): 28 | dialog.hide() 29 | hsm.add_hi_score(playername,global.score) 30 | -------------------------------------------------------------------------------- /game_over/game_over.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=6 format=2] 2 | 3 | [ext_resource path="res://game_over/game_over.gd" type="Script" id=1] 4 | [ext_resource path="res://materials/background_material.tres" type="Material" id=2] 5 | [ext_resource path="res://textures/black.png" type="Texture" id=3] 6 | [ext_resource path="res://themes/main.tres" type="Theme" id=4] 7 | [ext_resource path="res://new_hi_score_dialog/new_hi_score_dialog.tscn" type="PackedScene" id=5] 8 | 9 | [node name="game_over" type="Node2D"] 10 | 11 | script = ExtResource( 1 ) 12 | _sections_unfolded = [ "Transform", "Z Index" ] 13 | 14 | [node name="background" type="Sprite" parent="." index="0"] 15 | 16 | material = ExtResource( 2 ) 17 | texture = ExtResource( 3 ) 18 | offset = Vector2( 512, 384 ) 19 | region_enabled = true 20 | region_rect = Rect2( 0, 0, 1024, 768 ) 21 | _sections_unfolded = [ "Material", "Transform" ] 22 | 23 | [node name="CenterContainer" type="CenterContainer" parent="." index="1"] 24 | 25 | anchor_left = 0.0 26 | anchor_top = 0.0 27 | anchor_right = 1.0 28 | anchor_bottom = 1.0 29 | margin_right = 960.0 30 | margin_bottom = 704.0 31 | rect_pivot_offset = Vector2( 0, 0 ) 32 | mouse_filter = 0 33 | mouse_default_cursor_shape = 0 34 | size_flags_horizontal = 1 35 | size_flags_vertical = 1 36 | theme = ExtResource( 4 ) 37 | use_top_left = false 38 | _sections_unfolded = [ "Theme" ] 39 | 40 | [node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer" index="0"] 41 | 42 | anchor_left = 0.0 43 | anchor_top = 0.0 44 | anchor_right = 0.0 45 | anchor_bottom = 0.0 46 | margin_left = 406.0 47 | margin_top = 323.0 48 | margin_right = 618.0 49 | margin_bottom = 444.0 50 | rect_pivot_offset = Vector2( 0, 0 ) 51 | mouse_filter = 1 52 | mouse_default_cursor_shape = 0 53 | size_flags_horizontal = 1 54 | size_flags_vertical = 1 55 | custom_constants/separation = 15 56 | alignment = 0 57 | _sections_unfolded = [ "Rect", "Size Flags", "custom_constants" ] 58 | 59 | [node name="title" type="Label" parent="CenterContainer/VBoxContainer" index="0"] 60 | 61 | anchor_left = 0.0 62 | anchor_top = 0.0 63 | anchor_right = 0.0 64 | anchor_bottom = 0.0 65 | margin_right = 212.0 66 | margin_bottom = 16.0 67 | rect_pivot_offset = Vector2( 0, 0 ) 68 | mouse_filter = 2 69 | mouse_default_cursor_shape = 0 70 | size_flags_horizontal = 1 71 | size_flags_vertical = 4 72 | text = "GAME_OVER" 73 | align = 1 74 | valign = 1 75 | percent_visible = 1.0 76 | lines_skipped = 0 77 | max_lines_visible = -1 78 | 79 | [node name="score" type="Label" parent="CenterContainer/VBoxContainer" index="1"] 80 | 81 | anchor_left = 0.0 82 | anchor_top = 0.0 83 | anchor_right = 0.0 84 | anchor_bottom = 0.0 85 | margin_top = 31.0 86 | margin_right = 212.0 87 | margin_bottom = 47.0 88 | rect_pivot_offset = Vector2( 0, 0 ) 89 | mouse_filter = 2 90 | mouse_default_cursor_shape = 0 91 | size_flags_horizontal = 1 92 | size_flags_vertical = 4 93 | custom_colors/font_color = Color( 0, 0.435294, 0, 1 ) 94 | text = "Score: 0" 95 | align = 1 96 | valign = 1 97 | percent_visible = 1.0 98 | lines_skipped = 0 99 | max_lines_visible = -1 100 | _sections_unfolded = [ "custom_colors" ] 101 | 102 | [node name="play_again" type="Button" parent="CenterContainer/VBoxContainer" index="2"] 103 | 104 | anchor_left = 0.0 105 | anchor_top = 0.0 106 | anchor_right = 0.0 107 | anchor_bottom = 0.0 108 | margin_top = 62.0 109 | margin_right = 212.0 110 | margin_bottom = 84.0 111 | rect_pivot_offset = Vector2( 0, 0 ) 112 | focus_mode = 2 113 | mouse_filter = 0 114 | mouse_default_cursor_shape = 0 115 | size_flags_horizontal = 1 116 | size_flags_vertical = 1 117 | toggle_mode = false 118 | enabled_focus_mode = 2 119 | shortcut = null 120 | group = null 121 | text = "BTN_PLAY_AGAIN" 122 | flat = false 123 | align = 1 124 | _sections_unfolded = [ "Margin", "Size Flags", "custom_constants" ] 125 | 126 | [node name="main_menu" type="Button" parent="CenterContainer/VBoxContainer" index="3"] 127 | 128 | anchor_left = 0.0 129 | anchor_top = 0.0 130 | anchor_right = 0.0 131 | anchor_bottom = 0.0 132 | margin_top = 99.0 133 | margin_right = 212.0 134 | margin_bottom = 121.0 135 | rect_pivot_offset = Vector2( 0, 0 ) 136 | focus_mode = 2 137 | mouse_filter = 0 138 | mouse_default_cursor_shape = 0 139 | size_flags_horizontal = 1 140 | size_flags_vertical = 1 141 | toggle_mode = false 142 | enabled_focus_mode = 2 143 | shortcut = null 144 | group = null 145 | text = "BTN_MAIN_MENU" 146 | flat = false 147 | align = 1 148 | _sections_unfolded = [ "custom_constants" ] 149 | 150 | [node name="hi_score_dialog" parent="." index="2" instance=ExtResource( 5 )] 151 | 152 | visible = false 153 | anchor_left = 0.5 154 | anchor_top = 0.5 155 | anchor_right = 0.5 156 | anchor_bottom = 0.5 157 | margin_left = 218.0 158 | margin_top = 218.0 159 | margin_right = 718.0 160 | margin_bottom = 458.0 161 | 162 | [connection signal="pressed" from="CenterContainer/VBoxContainer/play_again" to="." method="_on_play_again_pressed"] 163 | 164 | [connection signal="pressed" from="CenterContainer/VBoxContainer/main_menu" to="." method="_on_main_menu_pressed"] 165 | 166 | 167 | -------------------------------------------------------------------------------- /game_ui/ball_ui.gd: -------------------------------------------------------------------------------- 1 | 2 | tool 3 | extends Sprite 4 | 5 | export var radius=5 6 | 7 | 8 | func _draw(): 9 | draw_circle(position,radius, Color(1,1,1)) 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /game_ui/game_ui.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node2D 3 | 4 | #autoload singletons 5 | # global 6 | # nc 7 | 8 | func _ready(): 9 | nc.add_observer(self,"show_bonus_message","show_bonus_message") 10 | 11 | func _exit_tree(): 12 | nc.remove_observer(self,"show_bonus_message") 13 | 14 | func set_score(score): 15 | $score.text = str(score) 16 | 17 | func set_multiplier(multiplier): 18 | $multiplier.text = "x"+str(multiplier).pad_zeros(2) 19 | if(multiplier>1): 20 | $multiplier_animation.play("multiplier") 21 | 22 | func set_lifes(lifes): 23 | $lifes.text = str(lifes).pad_zeros(2) 24 | 25 | func show_bonus_message(observer, notificationName,effect): 26 | $message.text = global.bonus_message[effect] 27 | $message_animation.play("message") 28 | -------------------------------------------------------------------------------- /game_ui/game_ui.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=6 format=2] 2 | 3 | [ext_resource path="res://game_ui/game_ui.gd" type="Script" id=1] 4 | [ext_resource path="res://fonts/ricasso_font.tres" type="DynamicFont" id=2] 5 | [ext_resource path="res://game_ui/ball_ui.gd" type="Script" id=3] 6 | 7 | [sub_resource type="Animation" id=1] 8 | 9 | resource_name = "message" 10 | length = 3.0 11 | loop = false 12 | step = 0.1 13 | tracks/0/type = "value" 14 | tracks/0/path = NodePath("message:percent_visible") 15 | tracks/0/interp = 1 16 | tracks/0/loop_wrap = true 17 | tracks/0/imported = false 18 | tracks/0/enabled = true 19 | tracks/0/keys = { 20 | "times": PoolRealArray( 0, 0.2, 2.2, 3 ), 21 | "transitions": PoolRealArray( 1, 1, 1, 1 ), 22 | "update": 0, 23 | "values": [ 0.0, 1.0, 1.0, 0.0 ] 24 | } 25 | 26 | [sub_resource type="Animation" id=2] 27 | 28 | length = 1.0 29 | loop = false 30 | step = 0.1 31 | tracks/0/type = "value" 32 | tracks/0/path = NodePath("multiplier:custom_colors/font_color") 33 | tracks/0/interp = 1 34 | tracks/0/loop_wrap = true 35 | tracks/0/imported = false 36 | tracks/0/enabled = true 37 | tracks/0/keys = { 38 | "times": PoolRealArray( 0, 0.2, 1 ), 39 | "transitions": PoolRealArray( 1, 1, 1 ), 40 | "update": 0, 41 | "values": [ Color( 0.840985, 0, 0, 1 ), Color( 1, 1, 1, 1 ), Color( 0.840985, 0, 0, 1 ) ] 42 | } 43 | 44 | [node name="game_ui" type="Node2D" index="0"] 45 | 46 | position = Vector2( 6, -6 ) 47 | script = ExtResource( 1 ) 48 | __meta__ = { 49 | "__editor_plugin_screen__": "2D" 50 | } 51 | 52 | [node name="score" type="Label" parent="." index="0"] 53 | 54 | anchor_left = 0.0 55 | anchor_top = 0.0 56 | anchor_right = 0.0 57 | anchor_bottom = 0.0 58 | margin_left = 574.0 59 | margin_top = 1.0 60 | margin_right = 862.0 61 | margin_bottom = 41.0 62 | rect_pivot_offset = Vector2( 0, 0 ) 63 | mouse_filter = 2 64 | mouse_default_cursor_shape = 0 65 | size_flags_horizontal = 2 66 | size_flags_vertical = 4 67 | custom_fonts/font = ExtResource( 2 ) 68 | custom_colors/font_color = Color( 0, 0.386039, 1, 1 ) 69 | text = "000 000 000" 70 | align = 2 71 | percent_visible = 1.0 72 | lines_skipped = 0 73 | max_lines_visible = -1 74 | 75 | [node name="multiplier" type="Label" parent="." index="1"] 76 | 77 | anchor_left = 0.0 78 | anchor_top = 0.0 79 | anchor_right = 0.0 80 | anchor_bottom = 0.0 81 | margin_left = 890.0 82 | margin_top = 1.0 83 | margin_right = 998.0 84 | margin_bottom = 41.0 85 | rect_pivot_offset = Vector2( 0, 0 ) 86 | mouse_filter = 2 87 | mouse_default_cursor_shape = 0 88 | size_flags_horizontal = 2 89 | size_flags_vertical = 4 90 | custom_fonts/font = ExtResource( 2 ) 91 | custom_colors/font_color = Color( 0.840985, 0, 0, 1 ) 92 | text = "x01" 93 | percent_visible = 1.0 94 | lines_skipped = 0 95 | max_lines_visible = -1 96 | 97 | [node name="lifes" type="Label" parent="." index="2"] 98 | 99 | anchor_left = 0.0 100 | anchor_top = 0.0 101 | anchor_right = 0.0 102 | anchor_bottom = 0.0 103 | margin_left = 60.0 104 | margin_top = 1.0 105 | margin_right = 160.0 106 | margin_bottom = 41.0 107 | rect_pivot_offset = Vector2( 0, 0 ) 108 | mouse_filter = 2 109 | mouse_default_cursor_shape = 0 110 | size_flags_horizontal = 2 111 | size_flags_vertical = 4 112 | custom_fonts/font = ExtResource( 2 ) 113 | text = "02" 114 | percent_visible = 1.0 115 | lines_skipped = 0 116 | max_lines_visible = -1 117 | 118 | [node name="ball_ui" type="Sprite" parent="lifes" index="0"] 119 | 120 | position = Vector2( -4.50435, 3.52635 ) 121 | script = ExtResource( 3 ) 122 | _sections_unfolded = [ "Transform" ] 123 | radius = 5 124 | 125 | [node name="multiplier_animation" type="AnimationPlayer" parent="." index="3"] 126 | 127 | root_node = NodePath("..") 128 | autoplay = "" 129 | playback_process_mode = 1 130 | playback_default_blend_time = 0.0 131 | playback_speed = 1.0 132 | anims/message = SubResource( 1 ) 133 | anims/multiplier = SubResource( 2 ) 134 | blend_times = [ ] 135 | 136 | [node name="message" type="Label" parent="." index="4"] 137 | 138 | anchor_left = 0.0 139 | anchor_top = 0.0 140 | anchor_right = 0.0 141 | anchor_bottom = 0.0 142 | margin_left = 180.0 143 | margin_top = 1.0 144 | margin_right = 550.0 145 | margin_bottom = 41.0 146 | rect_pivot_offset = Vector2( 0, 0 ) 147 | mouse_filter = 2 148 | mouse_default_cursor_shape = 0 149 | size_flags_horizontal = 2 150 | size_flags_vertical = 4 151 | custom_fonts/font = ExtResource( 2 ) 152 | custom_colors/font_color = Color( 0.758645, 0.790448, 0.789488, 1 ) 153 | text = "Breakable" 154 | align = 1 155 | percent_visible = 1.0 156 | lines_skipped = 0 157 | max_lines_visible = -1 158 | 159 | [node name="message_animation" type="AnimationPlayer" parent="." index="5"] 160 | 161 | root_node = NodePath("..") 162 | autoplay = "" 163 | playback_process_mode = 1 164 | playback_default_blend_time = 0.0 165 | playback_speed = 1.0 166 | anims/message = SubResource( 1 ) 167 | blend_times = [ ] 168 | 169 | 170 | -------------------------------------------------------------------------------- /hi_scores/hi_scores.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node 3 | 4 | #autoload singletons 5 | # global 6 | # hsm 7 | 8 | func _ready(): 9 | var pos_text="" 10 | var name_text="" 11 | var score_text="" 12 | 13 | for i in range (hsm.score_names.size()): #read the current list 14 | var pos_label = Label.new() 15 | pos_label.text = str(i+1)+"." 16 | pos_label.align = Label.ALIGN_RIGHT 17 | 18 | pos_text = pos_text+str(i+1)+".\n" 19 | 20 | var name_label = Label.new() 21 | name_label.text = hsm.score_names[i] 22 | name_label.set_size(Vector2(800,30)) 23 | name_text = name_text+hsm.score_names[i]+"\n" 24 | 25 | var score_label = Label.new() 26 | score_label.text = str(hsm.score_values[i]) 27 | score_label.align = Label.ALIGN_RIGHT 28 | score_text = score_text+str(hsm.score_values[i])+"ı•\n" 29 | 30 | #list is made of 3 text nodes 31 | $VBoxContainer/GridContainer/Pos.text = pos_text 32 | $VBoxContainer/GridContainer/Name.text = name_text 33 | $VBoxContainer/GridContainer/Score.text = score_text 34 | 35 | func _on_MainMenu_pressed(): 36 | global.load_menu() 37 | -------------------------------------------------------------------------------- /hi_scores/hi_scores.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://hi_scores/hi_scores.gd" type="Script" id=1] 4 | [ext_resource path="res://textures/black.png" type="Texture" id=2] 5 | [ext_resource path="res://themes/main.tres" type="Theme" id=3] 6 | 7 | [node name="Hiscores" type="Node" index="0"] 8 | 9 | script = ExtResource( 1 ) 10 | 11 | [node name="Background" type="Sprite" parent="." index="0"] 12 | 13 | texture = ExtResource( 2 ) 14 | offset = Vector2( 512, 384 ) 15 | region_enabled = true 16 | region_rect = Rect2( 0, 0, 1024, 768 ) 17 | _sections_unfolded = [ "Material" ] 18 | 19 | [node name="MainMenu" type="Button" parent="." index="1"] 20 | 21 | anchor_left = 0.5 22 | anchor_top = 1.0 23 | anchor_right = 0.5 24 | anchor_bottom = 1.0 25 | margin_left = -103.0 26 | margin_top = -68.0 27 | margin_right = 103.0 28 | margin_bottom = -46.0 29 | rect_pivot_offset = Vector2( 0, 0 ) 30 | focus_mode = 2 31 | mouse_filter = 0 32 | mouse_default_cursor_shape = 0 33 | size_flags_horizontal = 1 34 | size_flags_vertical = 1 35 | theme = ExtResource( 3 ) 36 | toggle_mode = false 37 | enabled_focus_mode = 2 38 | shortcut = null 39 | group = null 40 | text = "BTN_MAIN_MENU" 41 | flat = false 42 | align = 1 43 | _sections_unfolded = [ "Theme" ] 44 | 45 | [node name="VBoxContainer" type="VBoxContainer" parent="." index="2"] 46 | 47 | anchor_left = 0.0 48 | anchor_top = 0.0 49 | anchor_right = 1.0 50 | anchor_bottom = 1.0 51 | margin_left = 200.0 52 | margin_top = 90.0 53 | margin_right = -200.0 54 | margin_bottom = -110.0 55 | rect_pivot_offset = Vector2( 0, 0 ) 56 | mouse_filter = 1 57 | mouse_default_cursor_shape = 0 58 | size_flags_horizontal = 1 59 | size_flags_vertical = 1 60 | theme = ExtResource( 3 ) 61 | alignment = 0 62 | _sections_unfolded = [ "Anchor", "Margin", "Theme" ] 63 | 64 | [node name="Title" type="Label" parent="VBoxContainer" index="0"] 65 | 66 | anchor_left = 0.0 67 | anchor_top = 0.0 68 | anchor_right = 0.0 69 | anchor_bottom = 0.0 70 | margin_right = 624.0 71 | margin_bottom = 16.0 72 | rect_pivot_offset = Vector2( 0, 0 ) 73 | mouse_filter = 2 74 | mouse_default_cursor_shape = 0 75 | size_flags_horizontal = 3 76 | size_flags_vertical = 1 77 | text = "HI_SCORES" 78 | align = 1 79 | percent_visible = 1.0 80 | lines_skipped = 0 81 | max_lines_visible = -1 82 | _sections_unfolded = [ "Size Flags", "Theme" ] 83 | 84 | [node name="GridContainer" type="GridContainer" parent="VBoxContainer" index="1"] 85 | 86 | anchor_left = 0.0 87 | anchor_top = 0.0 88 | anchor_right = 0.0 89 | anchor_bottom = 0.0 90 | margin_top = 20.0 91 | margin_right = 624.0 92 | margin_bottom = 50.0 93 | rect_pivot_offset = Vector2( 0, 0 ) 94 | mouse_filter = 1 95 | mouse_default_cursor_shape = 0 96 | size_flags_horizontal = 1 97 | size_flags_vertical = 1 98 | columns = 3 99 | _sections_unfolded = [ "Size Flags" ] 100 | 101 | [node name="Pos" type="Label" parent="VBoxContainer/GridContainer" index="0"] 102 | 103 | anchor_left = 0.0 104 | anchor_top = 0.0 105 | anchor_right = 0.0 106 | anchor_bottom = 0.0 107 | margin_right = 60.0 108 | margin_bottom = 30.0 109 | rect_min_size = Vector2( 60, 30 ) 110 | rect_pivot_offset = Vector2( 0, 0 ) 111 | mouse_filter = 2 112 | mouse_default_cursor_shape = 0 113 | size_flags_horizontal = 1 114 | size_flags_vertical = 4 115 | percent_visible = 1.0 116 | lines_skipped = 0 117 | max_lines_visible = -1 118 | _sections_unfolded = [ "Rect" ] 119 | 120 | [node name="Name" type="Label" parent="VBoxContainer/GridContainer" index="1"] 121 | 122 | anchor_left = 0.0 123 | anchor_top = 0.0 124 | anchor_right = 0.0 125 | anchor_bottom = 0.0 126 | margin_left = 64.0 127 | margin_right = 414.0 128 | margin_bottom = 30.0 129 | rect_min_size = Vector2( 350, 30 ) 130 | rect_pivot_offset = Vector2( 0, 0 ) 131 | mouse_filter = 2 132 | mouse_default_cursor_shape = 0 133 | size_flags_horizontal = 1 134 | size_flags_vertical = 4 135 | percent_visible = 1.0 136 | lines_skipped = 0 137 | max_lines_visible = -1 138 | _sections_unfolded = [ "Rect" ] 139 | 140 | [node name="Score" type="Label" parent="VBoxContainer/GridContainer" index="2"] 141 | 142 | anchor_left = 0.0 143 | anchor_top = 0.0 144 | anchor_right = 0.0 145 | anchor_bottom = 0.0 146 | margin_left = 418.0 147 | margin_right = 568.0 148 | margin_bottom = 30.0 149 | rect_min_size = Vector2( 150, 30 ) 150 | rect_pivot_offset = Vector2( 0, 0 ) 151 | mouse_filter = 2 152 | mouse_default_cursor_shape = 0 153 | size_flags_horizontal = 1 154 | size_flags_vertical = 4 155 | align = 2 156 | percent_visible = 1.0 157 | lines_skipped = 0 158 | max_lines_visible = -1 159 | _sections_unfolded = [ "Rect" ] 160 | 161 | [connection signal="pressed" from="MainMenu" to="." method="_on_MainMenu_pressed"] 162 | 163 | 164 | -------------------------------------------------------------------------------- /level/1.gd: -------------------------------------------------------------------------------- 1 | extends "res://level/generic_level.gd" 2 | 3 | #autoload singletons 4 | # global 5 | 6 | 7 | 8 | func init_level(level_node): 9 | var brick_array = { 10 | 0:[0,0,0,0,0,0,0,0,0,0,0], 11 | 1:[0,1,1,1,1,1,1,1,1,1,0], 12 | 2:[0,0,1,1,1,1,1,1,1,0,0], 13 | 3:[0,0,1,1,1,1,1,1,1,0,0], 14 | 4:[0,1,0,0,0,0,0,0,0,1,0], 15 | 5:[0,0,1,1,1,1,1,1,1,0,0], 16 | 6:[0,0,1,1,1,1,1,1,1,0,0], 17 | 7:[0,1,1,1,1,1,1,1,1,1,0] 18 | } 19 | 20 | # var brick_array = { #FOR TESTS 21 | # 0:[0,0,0,0,0,0,0,0,0,0,0], 22 | # 1:[0,0,0,0,0,0,0,0,0,0,0], 23 | # 2:[0,0,0,0,0,0,0,0,0,0,0], 24 | # 3:[0,0,0,0,0,0,0,0,0,0,0], 25 | # 4:[0,0,0,0,0,0,0,0,0,0,0], 26 | # 5:[0,0,0,0,0,0,0,0,0,0,0], 27 | # 6:[0,0,0,0,0,0,0,0,0,0,0], 28 | # 7:[1,1,1,1,1,1,1,1,1,1,1] 29 | # } 30 | 31 | var bricks_in_row = floor(1024/(global.BRICK_WIDTH+separation)) 32 | var margin = (1024-(global.BRICK_WIDTH+separation)*bricks_in_row)/2 33 | var top = 100 34 | var total_bricks=0 35 | for i in range(8): 36 | var brick_line = brick_array[i] 37 | for j in range(bricks_in_row): 38 | if(brick_line[j]>0): 39 | var b = brick.instance() 40 | b.name = "brick_"+str(i)+"_"+str(j) 41 | b.position = Vector2(j*(global.BRICK_WIDTH+separation)+margin+global.BRICK_WIDTH/2,top+i*(global.BRICK_HEIGHT+separation)) 42 | b.set_meta("type","brick") 43 | b.set_hp(brick_line[j]) 44 | level_node.add_child(b) 45 | total_bricks += 1 46 | 47 | return total_bricks 48 | -------------------------------------------------------------------------------- /level/2.gd: -------------------------------------------------------------------------------- 1 | extends "res://level/generic_level.gd" 2 | 3 | #autoload singletons 4 | # global 5 | 6 | func init_level(level_node): 7 | var brick_array = { 8 | 0:[0,1,2,1,2,1,2,1,2,1,0], 9 | 1:[1,1,1,1,1,1,1,1,1,1,1], 10 | 2:[2,1,1,1,1,1,1,1,1,1,2], 11 | 3:[1,1,1,2,1,1,1,2,1,1,1], 12 | 4:[1,1,1,2,1,1,1,2,1,1,1], 13 | 5:[2,1,1,1,1,1,1,1,1,1,2], 14 | 6:[1,1,1,1,1,1,1,1,1,1,1], 15 | 7:[0,1,2,1,2,1,2,1,2,1,0], 16 | } 17 | 18 | 19 | var bricks_in_row = floor(1024/(global.BRICK_WIDTH+separation)) 20 | var margin = (1024-(global.BRICK_WIDTH+separation)*bricks_in_row)/2 21 | var top = 100 22 | var total_bricks=0 23 | for i in range(8): 24 | var brick_line = brick_array[i] 25 | for j in range(bricks_in_row): 26 | if(brick_line[j]>0): 27 | var b = brick.instance() 28 | b.name = "brick_"+str(i)+"_"+str(j) 29 | b.position = Vector2(j*(global.BRICK_WIDTH+separation)+margin+global.BRICK_WIDTH/2,top+i*(global.BRICK_HEIGHT+separation)) 30 | b.set_meta("type","brick") 31 | b.set_hp(brick_line[j]) 32 | level_node.add_child(b) 33 | total_bricks += 1 34 | 35 | return total_bricks 36 | -------------------------------------------------------------------------------- /level/3.gd: -------------------------------------------------------------------------------- 1 | extends "res://level/generic_level.gd" 2 | 3 | #autoload singletons 4 | # global 5 | 6 | func init_level(level_node): 7 | var brick_array = { 8 | 0:[0,0,2,1,2,1,2,1,2,0,0], 9 | 1:[0,1,1,1,1,1,1,1,1,1,0], 10 | 2:[2,1,1,1,1,1,1,1,1,1,2], 11 | 3:[1,1,1,1,0,2,0,1,1,1,1], 12 | 4:[1,1,1,1,0,2,0,1,1,1,1], 13 | 5:[2,1,1,1,1,1,1,1,1,1,2], 14 | 6:[0,1,1,1,1,1,1,1,1,1,0], 15 | 7:[0,0,2,1,2,1,2,1,2,0,0], 16 | } 17 | 18 | 19 | var bricks_in_row = floor(1024/(global.BRICK_WIDTH+separation)) 20 | var margin = (1024-(global.BRICK_WIDTH+separation)*bricks_in_row)/2 21 | var top = 100 22 | var total_bricks=0 23 | for i in range(8): 24 | var brick_line = brick_array[i] 25 | for j in range(bricks_in_row): 26 | if(brick_line[j]>0): 27 | var b = brick.instance() 28 | b.name = "brick_"+str(i)+"_"+str(j) 29 | b.position = Vector2(j*(global.BRICK_WIDTH+separation)+margin+global.BRICK_WIDTH/2,top+i*(global.BRICK_HEIGHT+separation)) 30 | b.set_meta("type","brick") 31 | b.set_hp(brick_line[j]) 32 | level_node.add_child(b) 33 | total_bricks += 1 34 | 35 | return total_bricks 36 | -------------------------------------------------------------------------------- /level/4.gd: -------------------------------------------------------------------------------- 1 | extends "res://level/generic_level.gd" 2 | 3 | #autoload singletons 4 | # global 5 | 6 | func init_level(level_node): 7 | var brick_array = { 8 | 0:[0,0,1,1,0,0,0,1,1,0,0], 9 | 1:[0,1,0,0,0,0,1,0,0,1,0], 10 | 2:[0,1,0,1,1,0,1,0,0,1,0], 11 | 3:[0,0,1,1,0,0,0,1,1,0,0], 12 | 4:[1,1,0,0,0,1,1,0,1,1,1], 13 | 5:[1,0,1,0,1,0,0,1,0,1,0], 14 | 6:[1,0,1,0,1,0,0,1,0,1,0], 15 | 7:[1,1,0,0,0,1,1,0,0,1,0], 16 | } 17 | 18 | 19 | var bricks_in_row = floor(1024/(global.BRICK_WIDTH+separation)) 20 | var margin = (1024-(global.BRICK_WIDTH+separation)*bricks_in_row)/2 21 | var top = 100 22 | var total_bricks=0 23 | for i in range(8): 24 | var brick_line = brick_array[i] 25 | for j in range(bricks_in_row): 26 | if(brick_line[j]>0): 27 | var b = brick.instance() 28 | b.name = "brick_"+str(i)+"_"+str(j) 29 | b.position = Vector2(j*(global.BRICK_WIDTH+separation)+margin+global.BRICK_WIDTH/2,top+i*(global.BRICK_HEIGHT+separation)) 30 | b.set_meta("type","brick") 31 | b.set_hp(brick_line[j]) 32 | level_node.add_child(b) 33 | total_bricks += 1 34 | 35 | return total_bricks 36 | -------------------------------------------------------------------------------- /level/generic_level.gd: -------------------------------------------------------------------------------- 1 | extends Reference 2 | 3 | var separation 4 | var brick 5 | 6 | 7 | func _init(): 8 | brick = load("res://static_brick/static_brick.tscn") 9 | separation=1 10 | 11 | 12 | func init_level(level_node): 13 | #each level file must define this function 14 | pass -------------------------------------------------------------------------------- /level/level.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node2D 3 | 4 | var total_bricks setget set_total_bricks, get_total_bricks 5 | var lb 6 | 7 | func load_level(level): 8 | var level_builder=load("res://level/"+str(level)+".gd") 9 | lb = level_builder.new() 10 | for i in range (get_child_count()): 11 | get_child(i).queue_free() 12 | total_bricks=lb.init_level(self) 13 | 14 | 15 | func set_total_bricks(tb): 16 | total_bricks=tb 17 | 18 | func get_total_bricks(): 19 | return total_bricks 20 | -------------------------------------------------------------------------------- /level/level.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://level/level.gd" type="Script" id=1] 4 | 5 | [node name="level" type="Node2D"] 6 | 7 | script = ExtResource( 1 ) 8 | __meta__ = { 9 | "__editor_plugin_screen__": "Script" 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /main.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node 3 | 4 | 5 | func _ready(): 6 | 7 | #full screen 8 | var options = $"/root/options_manager".read_options() 9 | if(options.has("full_screen")): 10 | OS.set_window_fullscreen(options.full_screen) 11 | 12 | #language 13 | if(options.has("locale")): 14 | TranslationServer.set_locale(options.locale) 15 | else: 16 | if OS.get_locale().begins_with("fr") || OS.get_locale().begins_with("en"): 17 | TranslationServer.set_locale(OS.get_locale()) 18 | 19 | #load first scene 20 | $"/root/global".load_menu() 21 | 22 | 23 | -------------------------------------------------------------------------------- /main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://main.gd" type="Script" id=1] 4 | 5 | [node name="main" type="Node"] 6 | script = ExtResource( 1 ) 7 | __meta__ = { 8 | "__editor_plugin_screen__": "3D" 9 | } 10 | -------------------------------------------------------------------------------- /materials/background_material.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://materials/background_shader.tres" type="Shader" id=1] 4 | 5 | [resource] 6 | 7 | render_priority = 0 8 | shader = ExtResource( 1 ) 9 | _sections_unfolded = [ "shader_param" ] 10 | 11 | -------------------------------------------------------------------------------- /materials/background_shader.shd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/materials/background_shader.shd -------------------------------------------------------------------------------- /materials/background_shader.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Shader" format=2] 2 | 3 | [resource] 4 | 5 | code = "shader_type canvas_item; 6 | 7 | 8 | float r(vec2 n) 9 | { 10 | return fract(cos(dot(n,vec2(36.26,73.12)))*354.63); 11 | } 12 | 13 | float noise(vec2 n) 14 | { 15 | vec2 fn = floor(n); 16 | vec2 sn = smoothstep(vec2(0),vec2(1),fract(n)); 17 | 18 | float h1 = mix(r(fn),r(fn+vec2(1,0)),sn.x); 19 | float h2 = mix(r(fn+vec2(0,1)),r(fn+vec2(1)),sn.x); 20 | return mix(h1,h2,sn.y); 21 | } 22 | 23 | float perlin(vec2 n) 24 | { 25 | float total; 26 | total = noise(n/32.0)*0.5875+noise(n/16.0)*0.2+noise(n/8.0)*0.1+noise(n/4.0)*0.05+noise(n/2.0)*0.025+noise(n)*0.0125; 27 | return total; 28 | } 29 | 30 | void fragment() { 31 | vec2 uv=UV; 32 | uv.y=uv.y - (TIME * 4.0 ); 33 | float v = perlin(uv/TEXTURE_PIXEL_SIZE*1.8); 34 | v = smoothstep(.85,v,1); 35 | 36 | COLOR.rgb = vec3(v,v,v); 37 | }" 38 | 39 | -------------------------------------------------------------------------------- /menu/menu.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node 3 | 4 | #autoload singletons 5 | # global 6 | 7 | func _ready(): 8 | Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) #always show the mouse in this scene 9 | 10 | func _on_btn_new_game_pressed(): 11 | global.new_game() 12 | 13 | func _on_btn_hi_scores_pressed(): 14 | global.load_hi_scores() 15 | 16 | func _on_btn_options_pressed(): 17 | global.load_options() 18 | 19 | func _on_btn_quit_pressed(): 20 | global.quit() 21 | -------------------------------------------------------------------------------- /menu/menu.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://menu/menu.gd" type="Script" id=1] 4 | [ext_resource path="res://textures/background.tres" type="Texture" id=2] 5 | [ext_resource path="res://fonts/font.tres" type="Theme" id=3] 6 | 7 | [node name="menu" type="Node"] 8 | 9 | script = ExtResource( 1 ) 10 | 11 | [node name="background" type="Sprite" parent="." index="0"] 12 | 13 | texture = ExtResource( 2 ) 14 | offset = Vector2( 512, 384 ) 15 | 16 | [node name="CenterContainer" type="CenterContainer" parent="." index="1"] 17 | 18 | anchor_left = 0.0 19 | anchor_top = 0.0 20 | anchor_right = 0.0 21 | anchor_bottom = 0.0 22 | margin_right = 1024.0 23 | margin_bottom = 768.0 24 | rect_pivot_offset = Vector2( 0, 0 ) 25 | mouse_filter = 0 26 | mouse_default_cursor_shape = 0 27 | size_flags_horizontal = 1 28 | size_flags_vertical = 1 29 | theme = ExtResource( 3 ) 30 | use_top_left = false 31 | 32 | [node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer" index="0"] 33 | 34 | anchor_left = 0.0 35 | anchor_top = 0.0 36 | anchor_right = 0.0 37 | anchor_bottom = 0.0 38 | margin_left = 322.0 39 | margin_top = 293.0 40 | margin_right = 702.0 41 | margin_bottom = 474.0 42 | rect_min_size = Vector2( 380, 181 ) 43 | rect_pivot_offset = Vector2( 0, 0 ) 44 | mouse_filter = 1 45 | mouse_default_cursor_shape = 0 46 | size_flags_horizontal = 1 47 | size_flags_vertical = 1 48 | custom_constants/separation = 15 49 | alignment = 0 50 | 51 | [node name="btn_new_game" type="Button" parent="CenterContainer/VBoxContainer" index="0"] 52 | 53 | anchor_left = 0.0 54 | anchor_top = 0.0 55 | anchor_right = 0.0 56 | anchor_bottom = 0.0 57 | margin_right = 380.0 58 | margin_bottom = 22.0 59 | rect_pivot_offset = Vector2( 0, 0 ) 60 | focus_mode = 2 61 | mouse_filter = 0 62 | mouse_default_cursor_shape = 0 63 | size_flags_horizontal = 1 64 | size_flags_vertical = 1 65 | toggle_mode = false 66 | enabled_focus_mode = 2 67 | shortcut = null 68 | group = null 69 | text = "BTN_NEW_GAME" 70 | flat = false 71 | align = 1 72 | 73 | [node name="btn_hi_scores" type="Button" parent="CenterContainer/VBoxContainer" index="1"] 74 | 75 | anchor_left = 0.0 76 | anchor_top = 0.0 77 | anchor_right = 0.0 78 | anchor_bottom = 0.0 79 | margin_top = 37.0 80 | margin_right = 380.0 81 | margin_bottom = 59.0 82 | rect_pivot_offset = Vector2( 0, 0 ) 83 | focus_mode = 2 84 | mouse_filter = 0 85 | mouse_default_cursor_shape = 0 86 | size_flags_horizontal = 1 87 | size_flags_vertical = 1 88 | toggle_mode = false 89 | enabled_focus_mode = 2 90 | shortcut = null 91 | group = null 92 | text = "BTN_HI_SCORES" 93 | flat = false 94 | align = 1 95 | 96 | [node name="btn_options" type="Button" parent="CenterContainer/VBoxContainer" index="2"] 97 | 98 | anchor_left = 0.0 99 | anchor_top = 0.0 100 | anchor_right = 0.0 101 | anchor_bottom = 0.0 102 | margin_top = 74.0 103 | margin_right = 380.0 104 | margin_bottom = 96.0 105 | rect_pivot_offset = Vector2( 0, 0 ) 106 | focus_mode = 2 107 | mouse_filter = 0 108 | mouse_default_cursor_shape = 0 109 | size_flags_horizontal = 1 110 | size_flags_vertical = 1 111 | toggle_mode = false 112 | enabled_focus_mode = 2 113 | shortcut = null 114 | group = null 115 | text = "BTN_OPTIONS" 116 | flat = false 117 | align = 1 118 | 119 | [node name="btn_quit" type="Button" parent="CenterContainer/VBoxContainer" index="3"] 120 | 121 | anchor_left = 0.0 122 | anchor_top = 0.0 123 | anchor_right = 0.0 124 | anchor_bottom = 0.0 125 | margin_top = 111.0 126 | margin_right = 380.0 127 | margin_bottom = 133.0 128 | rect_pivot_offset = Vector2( 0, 0 ) 129 | focus_mode = 2 130 | mouse_filter = 0 131 | mouse_default_cursor_shape = 0 132 | size_flags_horizontal = 1 133 | size_flags_vertical = 1 134 | toggle_mode = false 135 | enabled_focus_mode = 2 136 | shortcut = null 137 | group = null 138 | text = "BTN_QUIT" 139 | flat = false 140 | align = 1 141 | 142 | [connection signal="pressed" from="CenterContainer/VBoxContainer/btn_new_game" to="." method="_on_btn_new_game_pressed"] 143 | 144 | [connection signal="pressed" from="CenterContainer/VBoxContainer/btn_hi_scores" to="." method="_on_btn_hi_scores_pressed"] 145 | 146 | [connection signal="pressed" from="CenterContainer/VBoxContainer/btn_options" to="." method="_on_btn_options_pressed"] 147 | 148 | [connection signal="pressed" from="CenterContainer/VBoxContainer/btn_quit" to="." method="_on_btn_quit_pressed"] 149 | 150 | 151 | -------------------------------------------------------------------------------- /new_hi_score_dialog/new_hi_score_dialog.gd: -------------------------------------------------------------------------------- 1 | extends Panel 2 | 3 | 4 | var delegate #defined 5 | var score setget setScore 6 | 7 | func _ready(): 8 | var line_edit = $CenterContainer/VBoxContainer/LineEdit 9 | line_edit.select_all() 10 | line_edit.grab_focus() 11 | 12 | func _on_ButtonOK_pressed(): 13 | var playername = $CenterContainer/VBoxContainer/LineEdit.text 14 | if delegate.has_method("close_hi_score_dialog"): 15 | delegate.close_hi_score_dialog(self,playername) 16 | 17 | func setScore(newScore): 18 | $CenterContainer/VBoxContainer/score_label.text = str(newScore) 19 | 20 | -------------------------------------------------------------------------------- /new_hi_score_dialog/new_hi_score_dialog.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://themes/main.tres" type="Theme" id=1] 4 | [ext_resource path="res://new_hi_score_dialog/new_hi_score_dialog.gd" type="Script" id=2] 5 | 6 | [sub_resource type="ImageTexture" id=1] 7 | 8 | flags = 7 9 | storage = 0 10 | lossy_quality = 0.7 11 | flags = 7 12 | size = Vector2( 500, 240 ) 13 | 14 | [node name="Node" type="Panel"] 15 | 16 | anchor_left = 0.0 17 | anchor_top = 0.0 18 | anchor_right = 0.0 19 | anchor_bottom = 0.0 20 | margin_right = 500.0 21 | margin_bottom = 240.0 22 | rect_pivot_offset = Vector2( 0, 0 ) 23 | mouse_filter = 0 24 | mouse_default_cursor_shape = 0 25 | size_flags_horizontal = 1 26 | size_flags_vertical = 1 27 | theme = ExtResource( 1 ) 28 | script = ExtResource( 2 ) 29 | _sections_unfolded = [ "Rect", "Theme" ] 30 | 31 | [node name="CenterContainer" type="CenterContainer" parent="." index="0"] 32 | 33 | anchor_left = 0.0 34 | anchor_top = 0.0 35 | anchor_right = 1.0 36 | anchor_bottom = 1.0 37 | rect_pivot_offset = Vector2( 0, 0 ) 38 | mouse_filter = 0 39 | mouse_default_cursor_shape = 0 40 | size_flags_horizontal = 1 41 | size_flags_vertical = 1 42 | use_top_left = false 43 | _sections_unfolded = [ "Anchor" ] 44 | 45 | [node name="background" type="Sprite" parent="CenterContainer" index="0"] 46 | 47 | position = Vector2( 250, 123 ) 48 | texture = SubResource( 1 ) 49 | _sections_unfolded = [ "Transform" ] 50 | 51 | [node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer" index="1"] 52 | 53 | anchor_left = 0.0 54 | anchor_top = 0.0 55 | anchor_right = 0.0 56 | anchor_bottom = 0.0 57 | margin_left = 135.0 58 | margin_top = 62.0 59 | margin_right = 365.0 60 | margin_bottom = 178.0 61 | rect_pivot_offset = Vector2( 0, 0 ) 62 | mouse_filter = 1 63 | mouse_default_cursor_shape = 0 64 | size_flags_horizontal = 1 65 | size_flags_vertical = 1 66 | alignment = 0 67 | 68 | [node name="new_hi_score" type="Label" parent="CenterContainer/VBoxContainer" index="0"] 69 | 70 | anchor_left = 0.0 71 | anchor_top = 0.0 72 | anchor_right = 0.0 73 | anchor_bottom = 0.0 74 | margin_right = 230.0 75 | margin_bottom = 16.0 76 | rect_pivot_offset = Vector2( 0, 0 ) 77 | mouse_filter = 2 78 | mouse_default_cursor_shape = 0 79 | size_flags_horizontal = 1 80 | size_flags_vertical = 4 81 | custom_colors/font_color = Color( 0, 1, 0, 1 ) 82 | text = "NEW_HI_SCORE" 83 | align = 1 84 | percent_visible = 1.0 85 | lines_skipped = 0 86 | max_lines_visible = -1 87 | _sections_unfolded = [ "custom_colors" ] 88 | 89 | [node name="score_label" type="Label" parent="CenterContainer/VBoxContainer" index="1"] 90 | 91 | anchor_left = 0.0 92 | anchor_top = 0.0 93 | anchor_right = 0.0 94 | anchor_bottom = 0.0 95 | margin_top = 20.0 96 | margin_right = 230.0 97 | margin_bottom = 36.0 98 | rect_pivot_offset = Vector2( 0, 0 ) 99 | mouse_filter = 2 100 | mouse_default_cursor_shape = 0 101 | size_flags_horizontal = 1 102 | size_flags_vertical = 4 103 | custom_colors/font_color = Color( 0, 1, 0, 1 ) 104 | text = "0" 105 | align = 1 106 | percent_visible = 1.0 107 | lines_skipped = 0 108 | max_lines_visible = -1 109 | _sections_unfolded = [ "custom_colors", "custom_constants" ] 110 | 111 | [node name="enter_your_name" type="Label" parent="CenterContainer/VBoxContainer" index="2"] 112 | 113 | anchor_left = 0.0 114 | anchor_top = 0.0 115 | anchor_right = 0.0 116 | anchor_bottom = 0.0 117 | margin_top = 40.0 118 | margin_right = 230.0 119 | margin_bottom = 56.0 120 | rect_pivot_offset = Vector2( 0, 0 ) 121 | mouse_filter = 2 122 | mouse_default_cursor_shape = 0 123 | size_flags_horizontal = 1 124 | size_flags_vertical = 4 125 | text = "ENTER_YOUR_NAME" 126 | align = 1 127 | percent_visible = 1.0 128 | lines_skipped = 0 129 | max_lines_visible = -1 130 | 131 | [node name="LineEdit" type="LineEdit" parent="CenterContainer/VBoxContainer" index="3"] 132 | 133 | anchor_left = 0.0 134 | anchor_top = 0.0 135 | anchor_right = 0.0 136 | anchor_bottom = 0.0 137 | margin_top = 60.0 138 | margin_right = 230.0 139 | margin_bottom = 86.0 140 | rect_pivot_offset = Vector2( 0, 0 ) 141 | focus_mode = 2 142 | mouse_filter = 0 143 | mouse_default_cursor_shape = 1 144 | size_flags_horizontal = 1 145 | size_flags_vertical = 1 146 | focus_mode = 2 147 | context_menu_enabled = true 148 | placeholder_alpha = 0.6 149 | caret_blink = false 150 | caret_blink_speed = 0.65 151 | caret_position = 0 152 | 153 | [node name="MarginContainer" type="MarginContainer" parent="CenterContainer/VBoxContainer" index="4"] 154 | 155 | anchor_left = 0.0 156 | anchor_top = 0.0 157 | anchor_right = 0.0 158 | anchor_bottom = 0.0 159 | margin_top = 90.0 160 | margin_right = 230.0 161 | margin_bottom = 90.0 162 | rect_pivot_offset = Vector2( 0, 0 ) 163 | mouse_filter = 0 164 | mouse_default_cursor_shape = 0 165 | size_flags_horizontal = 1 166 | size_flags_vertical = 1 167 | 168 | [node name="ButtonOK" type="Button" parent="CenterContainer/VBoxContainer" index="5"] 169 | 170 | anchor_left = 0.0 171 | anchor_top = 0.0 172 | anchor_right = 0.0 173 | anchor_bottom = 0.0 174 | margin_top = 94.0 175 | margin_right = 230.0 176 | margin_bottom = 116.0 177 | rect_pivot_offset = Vector2( 0, 0 ) 178 | focus_mode = 2 179 | mouse_filter = 0 180 | mouse_default_cursor_shape = 0 181 | size_flags_horizontal = 1 182 | size_flags_vertical = 1 183 | toggle_mode = false 184 | enabled_focus_mode = 2 185 | shortcut = null 186 | group = null 187 | text = "BTN_OK" 188 | flat = false 189 | align = 1 190 | 191 | [connection signal="pressed" from="CenterContainer/VBoxContainer/ButtonOK" to="." method="_on_ButtonOK_pressed"] 192 | 193 | 194 | -------------------------------------------------------------------------------- /options/options.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node 3 | 4 | #autoload singletons 5 | # global 6 | 7 | onready var options = $"/root/options_manager".read_options() 8 | onready var languages = ["en","fr"] 9 | 10 | func _ready(): 11 | var currentLang = TranslationServer.get_locale() 12 | for i in range(languages.size()): 13 | $GridContainer/LanguageOption.add_item(languages[i],i) 14 | if(languages[i]==currentLang): 15 | $GridContainer/LanguageOption.select(i) 16 | 17 | if(OS.is_window_fullscreen()): 18 | $GridContainer/ScreenOption.pressed = true 19 | 20 | 21 | func _on_MainMenu_pressed(): 22 | global.load_menu() 23 | 24 | func _on_LanguageOption_item_selected( id ): 25 | TranslationServer.set_locale(languages[id]) 26 | options["locale"]=languages[id] 27 | $"/root/options_manager".write_options(options) 28 | global.load_options() #reload the scene when language changes 29 | 30 | 31 | func _on_ScreenOption_toggled( pressed ): 32 | OS.set_window_fullscreen( pressed ) 33 | options["full_screen"]=pressed 34 | $"/root/options_manager".write_options(options) 35 | 36 | -------------------------------------------------------------------------------- /options/options.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://options/options.gd" type="Script" id=1] 4 | [ext_resource path="res://textures/black.png" type="Texture" id=2] 5 | [ext_resource path="res://themes/main.tres" type="Theme" id=3] 6 | 7 | [node name="Options" type="Node" index="0"] 8 | 9 | script = ExtResource( 1 ) 10 | _sections_unfolded = [ "Pause" ] 11 | 12 | [node name="background" type="Sprite" parent="." index="0"] 13 | 14 | texture = ExtResource( 2 ) 15 | offset = Vector2( 512, 384 ) 16 | region_enabled = true 17 | region_rect = Rect2( 0, 0, 1024, 768 ) 18 | _sections_unfolded = [ "Material" ] 19 | 20 | [node name="MainMenu" type="Button" parent="." index="1"] 21 | 22 | anchor_left = 0.5 23 | anchor_top = 1.0 24 | anchor_right = 0.5 25 | anchor_bottom = 1.0 26 | margin_left = -103.0 27 | margin_top = -176.0 28 | margin_right = 103.0 29 | margin_bottom = -154.0 30 | rect_pivot_offset = Vector2( 0, 0 ) 31 | focus_mode = 2 32 | mouse_filter = 0 33 | mouse_default_cursor_shape = 0 34 | size_flags_horizontal = 1 35 | size_flags_vertical = 1 36 | theme = ExtResource( 3 ) 37 | toggle_mode = false 38 | enabled_focus_mode = 2 39 | shortcut = null 40 | group = null 41 | text = "BTN_MAIN_MENU" 42 | flat = false 43 | align = 1 44 | _sections_unfolded = [ "Anchor", "Margin", "Rect", "Theme" ] 45 | 46 | [node name="Label" type="Label" parent="." index="2"] 47 | 48 | anchor_left = 0.5 49 | anchor_top = 0.0 50 | anchor_right = 0.5 51 | anchor_bottom = 0.0 52 | margin_left = -80.0 53 | margin_top = 47.0 54 | margin_right = 79.0 55 | margin_bottom = 63.0 56 | rect_pivot_offset = Vector2( 0, 0 ) 57 | mouse_filter = 2 58 | mouse_default_cursor_shape = 0 59 | size_flags_horizontal = 1 60 | size_flags_vertical = 4 61 | theme = ExtResource( 3 ) 62 | text = "BTN_OPTIONS" 63 | align = 1 64 | valign = 1 65 | percent_visible = 1.0 66 | lines_skipped = 0 67 | max_lines_visible = -1 68 | _sections_unfolded = [ "Theme" ] 69 | 70 | [node name="GridContainer" type="GridContainer" parent="." index="3"] 71 | 72 | anchor_left = 0.5 73 | anchor_top = 0.0 74 | anchor_right = 0.5 75 | anchor_bottom = 0.0 76 | margin_left = -122.0 77 | margin_top = 119.0 78 | margin_right = 122.0 79 | margin_bottom = 219.0 80 | rect_pivot_offset = Vector2( 0, 0 ) 81 | mouse_filter = 1 82 | mouse_default_cursor_shape = 0 83 | size_flags_horizontal = 1 84 | size_flags_vertical = 1 85 | theme = ExtResource( 3 ) 86 | columns = 2 87 | _sections_unfolded = [ "Anchor", "Rect" ] 88 | 89 | [node name="LanguageLabel" type="Label" parent="GridContainer" index="0"] 90 | 91 | anchor_left = 0.0 92 | anchor_top = 0.0 93 | anchor_right = 0.0 94 | anchor_bottom = 0.0 95 | margin_top = 3.0 96 | margin_right = 164.0 97 | margin_bottom = 19.0 98 | rect_pivot_offset = Vector2( 0, 0 ) 99 | mouse_filter = 2 100 | mouse_default_cursor_shape = 0 101 | size_flags_horizontal = 1 102 | size_flags_vertical = 4 103 | text = "LANGUAGE" 104 | percent_visible = 1.0 105 | lines_skipped = 0 106 | max_lines_visible = -1 107 | 108 | [node name="LanguageOption" type="OptionButton" parent="GridContainer" index="1"] 109 | 110 | anchor_left = 0.0 111 | anchor_top = 0.0 112 | anchor_right = 0.0 113 | anchor_bottom = 0.0 114 | margin_left = 168.0 115 | margin_right = 244.0 116 | margin_bottom = 22.0 117 | rect_pivot_offset = Vector2( 0, 0 ) 118 | focus_mode = 2 119 | mouse_filter = 0 120 | mouse_default_cursor_shape = 0 121 | size_flags_horizontal = 1 122 | size_flags_vertical = 1 123 | toggle_mode = false 124 | action_mode = 0 125 | enabled_focus_mode = 2 126 | shortcut = null 127 | group = null 128 | flat = false 129 | align = 0 130 | selected = -1 131 | items = [ ] 132 | 133 | [node name="ScreenLabel" type="Label" parent="GridContainer" index="2"] 134 | 135 | anchor_left = 0.0 136 | anchor_top = 0.0 137 | anchor_right = 0.0 138 | anchor_bottom = 0.0 139 | margin_top = 38.0 140 | margin_right = 164.0 141 | margin_bottom = 54.0 142 | rect_pivot_offset = Vector2( 0, 0 ) 143 | mouse_filter = 2 144 | mouse_default_cursor_shape = 0 145 | size_flags_horizontal = 1 146 | size_flags_vertical = 4 147 | text = "FULL_SCREEN" 148 | percent_visible = 1.0 149 | lines_skipped = 0 150 | max_lines_visible = -1 151 | 152 | [node name="ScreenOption" type="CheckButton" parent="GridContainer" index="3"] 153 | 154 | anchor_left = 0.0 155 | anchor_top = 0.0 156 | anchor_right = 0.0 157 | anchor_bottom = 0.0 158 | margin_left = 168.0 159 | margin_top = 26.0 160 | margin_right = 244.0 161 | margin_bottom = 66.0 162 | rect_pivot_offset = Vector2( 0, 0 ) 163 | focus_mode = 2 164 | mouse_filter = 0 165 | mouse_default_cursor_shape = 0 166 | size_flags_horizontal = 1 167 | size_flags_vertical = 1 168 | toggle_mode = true 169 | enabled_focus_mode = 2 170 | shortcut = null 171 | group = null 172 | flat = false 173 | align = 0 174 | _sections_unfolded = [ "Anchor", "Grow Direction", "Margin" ] 175 | 176 | [connection signal="pressed" from="MainMenu" to="." method="_on_MainMenu_pressed"] 177 | 178 | [connection signal="item_selected" from="GridContainer/LanguageOption" to="." method="_on_LanguageOption_item_selected"] 179 | 180 | [connection signal="toggled" from="GridContainer/ScreenOption" to="." method="_on_ScreenOption_toggled"] 181 | 182 | 183 | -------------------------------------------------------------------------------- /paddle/paddle.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node2D 3 | 4 | #autoload singletons 5 | # nc 6 | # global 7 | 8 | var center #of the viewport 9 | var board 10 | export(float) var paddle_width=0 setget set_paddle_width 11 | 12 | func _ready(): 13 | 14 | paddle_width=global.INITIAL_PADDLE_WIDTH 15 | #paddle initial pos 16 | self.position.x = get_viewport_rect().size.x/2 17 | 18 | center = get_viewport_rect().size/2; 19 | get_viewport().warp_mouse(center) 20 | 21 | set_physics_process(true) 22 | 23 | 24 | # mouse movement 25 | func _physics_process(delta): 26 | 27 | var mouse_pos = get_viewport().get_mouse_position() 28 | var size = get_viewport_rect().size 29 | position.x = clamp(mouse_pos.x,0,size.x) 30 | 31 | if board.sticky || !board.playing: 32 | nc.post_notification("paddle_moved",position) 33 | 34 | # collision 35 | func _on_Area2D_body_enter( body ): 36 | if body.has_meta("type"): 37 | if body.get_meta("type")=="ball": 38 | var velocity = body.get_linear_velocity() 39 | velocity.y=-velocity.y # simple bounce 40 | 41 | var body_pos = body.position 42 | var paddle_pos = position 43 | var relative_pos_x = body_pos.x-paddle_pos.x 44 | nc.post_notification( "paddle_hit",relative_pos_x) 45 | var coeff = (body_pos.x-paddle_pos.x)/paddle_width # -0,5 .. 0,5 , depending on where the ball hits the paddle 46 | var angle = coeff*PI/2.4 47 | velocity = velocity.rotated(angle) # relative rotation, keeps speed 48 | body.set_linear_velocity(velocity) 49 | body.adjust_angle() #let the ball adjust the angle so the game keeps being playable 50 | 51 | elif body.get_meta("type")=="bonus": 52 | nc.post_notification("bonus_hit",body) 53 | 54 | 55 | func update_paddle(): 56 | if has_node("paddle_area"): 57 | var paddle_area = $paddle_area 58 | if(paddle_area.get_shape_owners().empty()): 59 | paddle_area.create_shape_owner(paddle_area) 60 | var so = paddle_area.get_shape_owners()[0] 61 | paddle_area.shape_owner_clear_shapes(so) 62 | 63 | var r = RectangleShape2D.new() 64 | r.set_extents(Vector2(paddle_width/2,global.PADDLE_HEIGHT/2)) 65 | paddle_area.shape_owner_add_shape(so,r) 66 | update() 67 | 68 | func set_paddle_width(pw): #size changes with SMALL_PADDLE and BIG_PADDLE bonus 69 | if paddle_width!=pw: 70 | paddle_width=pw 71 | if has_node("left"): 72 | $left.position.x = -paddle_width/2 73 | if(has_node("right")): 74 | # $right.set_pos(pos) 75 | $right.position.x = paddle_width/2-16 76 | if(has_node("middle")): 77 | $middle.set_scale(Vector2(paddle_width/20.0-1.5,1)) 78 | update_paddle() 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /paddle/paddle.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://paddle/paddle.gd" type="Script" id=1] 4 | [ext_resource path="res://textures/paddle.png" type="Texture" id=2] 5 | 6 | [sub_resource type="RectangleShape2D" id=1] 7 | 8 | custom_solver_bias = 0.0 9 | extents = Vector2( 49.7446, 8.15161 ) 10 | 11 | [node name="paddle" type="Node2D" index="0"] 12 | 13 | script = ExtResource( 1 ) 14 | __meta__ = { 15 | "__editor_plugin_screen__": "Script" 16 | } 17 | paddle_width = 0 18 | 19 | [node name="paddle_area" type="Area2D" parent="." index="0"] 20 | 21 | input_pickable = true 22 | gravity_vec = Vector2( 0, 1 ) 23 | gravity = 98.0 24 | linear_damp = 0.1 25 | angular_damp = 1.0 26 | collision_layer = 3 27 | collision_mask = 3 28 | audio_bus_override = false 29 | audio_bus_name = "Master" 30 | _sections_unfolded = [ "Audio Bus", "Collision", "Pickable", "Transform", "Z Index" ] 31 | 32 | [node name="CollisionShape2D" type="CollisionShape2D" parent="paddle_area" index="0"] 33 | 34 | shape = SubResource( 1 ) 35 | _sections_unfolded = [ "Transform", "Z Index" ] 36 | 37 | [node name="middle" type="Sprite" parent="." index="1"] 38 | 39 | position = Vector2( 0, -1 ) 40 | scale = Vector2( 3.5, 1 ) 41 | texture = ExtResource( 2 ) 42 | region_enabled = true 43 | region_rect = Rect2( 20, 0, 20, 15 ) 44 | 45 | [node name="left" type="Sprite" parent="." index="2"] 46 | 47 | position = Vector2( -50, -8 ) 48 | texture = ExtResource( 2 ) 49 | centered = false 50 | region_enabled = true 51 | region_rect = Rect2( 0, 0, 16, 15 ) 52 | 53 | [node name="right" type="Sprite" parent="." index="3"] 54 | 55 | position = Vector2( 34, -8 ) 56 | texture = ExtResource( 2 ) 57 | centered = false 58 | region_enabled = true 59 | region_rect = Rect2( 44, 0, 16, 15 ) 60 | 61 | [connection signal="body_entered" from="paddle_area" to="." method="_on_Area2D_body_enter"] 62 | 63 | 64 | -------------------------------------------------------------------------------- /pause_dialog/pause_dialog.gd: -------------------------------------------------------------------------------- 1 | extends Popup 2 | 3 | onready var delegate = self 4 | #the delegate object can define the callback functions 5 | #it should be set by the object creating the PauseDialog 6 | 7 | func _draw(): 8 | var r = Rect2($CenterContainer.rect_position,$CenterContainer.rect_size) 9 | draw_rect(r,Color(1,1,1,.5)) 10 | 11 | 12 | func _input(event): 13 | # continue if user hits ESC 14 | if event.is_action("ui_cancel") and not event.is_pressed() : 15 | get_tree().set_input_as_handled() 16 | _on_btn_continue_pressed() 17 | pass 18 | 19 | func _on_btn_abandon_pressed(): 20 | var response = {"message":"Cancel"} 21 | if delegate.has_method("close_dialog"): 22 | delegate.close_dialog(self,response) 23 | 24 | 25 | func _on_btn_continue_pressed(): 26 | var response = {"message":"Continue"} 27 | if delegate.has_method("close_dialog"): 28 | delegate.close_dialog(self,response) 29 | 30 | -------------------------------------------------------------------------------- /pause_dialog/pause_dialog.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://pause_dialog/pause_dialog.gd" type="Script" id=1] 4 | [ext_resource path="res://themes/main.tres" type="Theme" id=2] 5 | 6 | [node name="Popup" type="Popup" index="0"] 7 | 8 | pause_mode = 2 9 | anchor_left = 0.0 10 | anchor_top = 0.0 11 | anchor_right = 1.0 12 | anchor_bottom = 1.0 13 | rect_pivot_offset = Vector2( 0, 0 ) 14 | mouse_filter = 0 15 | mouse_default_cursor_shape = 0 16 | size_flags_horizontal = 1 17 | size_flags_vertical = 1 18 | popup_exclusive = false 19 | script = ExtResource( 1 ) 20 | _sections_unfolded = [ "Pause", "Popup" ] 21 | 22 | [node name="CenterContainer" type="CenterContainer" parent="." index="0"] 23 | 24 | anchor_left = 0.5 25 | anchor_top = 0.5 26 | anchor_right = 0.5 27 | anchor_bottom = 0.5 28 | margin_left = -120.0 29 | margin_top = -60.0 30 | margin_right = 120.0 31 | margin_bottom = 60.0 32 | rect_pivot_offset = Vector2( 0, 0 ) 33 | mouse_filter = 0 34 | mouse_default_cursor_shape = 0 35 | size_flags_horizontal = 1 36 | size_flags_vertical = 1 37 | theme = ExtResource( 2 ) 38 | use_top_left = false 39 | 40 | [node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer" index="0"] 41 | 42 | anchor_left = 0.0 43 | anchor_top = 0.0 44 | anchor_right = 0.0 45 | anchor_bottom = 0.0 46 | margin_left = 26.0 47 | margin_top = 28.0 48 | margin_right = 214.0 49 | margin_bottom = 92.0 50 | rect_pivot_offset = Vector2( 0, 0 ) 51 | mouse_filter = 1 52 | mouse_default_cursor_shape = 0 53 | size_flags_horizontal = 1 54 | size_flags_vertical = 1 55 | custom_constants/separation = 20 56 | alignment = 0 57 | 58 | [node name="btn_continue" type="Button" parent="CenterContainer/VBoxContainer" index="0"] 59 | 60 | anchor_left = 0.0 61 | anchor_top = 0.0 62 | anchor_right = 0.0 63 | anchor_bottom = 0.0 64 | margin_right = 188.0 65 | margin_bottom = 22.0 66 | rect_pivot_offset = Vector2( 0, 0 ) 67 | focus_mode = 2 68 | mouse_filter = 0 69 | mouse_default_cursor_shape = 0 70 | size_flags_horizontal = 1 71 | size_flags_vertical = 1 72 | theme = ExtResource( 2 ) 73 | toggle_mode = false 74 | enabled_focus_mode = 2 75 | shortcut = null 76 | group = null 77 | text = "BTN_CONTINUE" 78 | flat = false 79 | align = 1 80 | 81 | [node name="btn_abandon" type="Button" parent="CenterContainer/VBoxContainer" index="1"] 82 | 83 | anchor_left = 0.0 84 | anchor_top = 0.0 85 | anchor_right = 0.0 86 | anchor_bottom = 0.0 87 | margin_top = 42.0 88 | margin_right = 188.0 89 | margin_bottom = 64.0 90 | rect_pivot_offset = Vector2( 0, 0 ) 91 | focus_mode = 2 92 | mouse_filter = 0 93 | mouse_default_cursor_shape = 0 94 | size_flags_horizontal = 1 95 | size_flags_vertical = 1 96 | theme = ExtResource( 2 ) 97 | toggle_mode = false 98 | enabled_focus_mode = 2 99 | shortcut = null 100 | group = null 101 | text = "BTN_ABANDON" 102 | flat = false 103 | align = 1 104 | 105 | [connection signal="pressed" from="CenterContainer/VBoxContainer/btn_continue" to="." method="_on_btn_continue_pressed"] 106 | 107 | [connection signal="pressed" from="CenterContainer/VBoxContainer/btn_abandon" to="." method="_on_btn_abandon_pressed"] 108 | 109 | 110 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | _global_script_classes=[ ] 12 | _global_script_class_icons={ 13 | } 14 | 15 | [application] 16 | 17 | config/name="Breakable" 18 | run/main_scene="res://main.tscn" 19 | icon="icon.png" 20 | main_scene="res://main.tscn" 21 | name="Breakable" 22 | 23 | [autoload] 24 | 25 | global="*res://autoload/global.gd" 26 | hsm="*res://autoload/hi_scores_manager.gd" 27 | nc="*res://autoload/notification_center.gd" 28 | options_manager="*res://autoload/options_manager.gd" 29 | 30 | [display] 31 | 32 | window/size/height=768 33 | window/stretch/mode="viewport" 34 | window/stretch/aspect="keep_width" 35 | stretch/aspect="keep_width" 36 | stretch/mode="viewport" 37 | window/fullscreen=false 38 | window/height=768 39 | window/resizable=true 40 | window/width=1024 41 | 42 | [gdnative] 43 | 44 | singletons=[ ] 45 | 46 | [gui] 47 | 48 | common/swap_ok_cancel=true 49 | 50 | [input] 51 | 52 | ui_fire={ 53 | "deadzone": 0.5, 54 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) 55 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 56 | ] 57 | } 58 | 59 | [locale] 60 | 61 | translations=PoolStringArray( "res://translations/translation.en.translation", "res://translations/translation.fr.translation" ) 62 | locale_filter=[ 1, [ "en", "fr" ] ] 63 | 64 | [physics] 65 | 66 | 2d/default_gravity=0 67 | -------------------------------------------------------------------------------- /screenshots/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/screenshots/screenshot.png -------------------------------------------------------------------------------- /screenshots/screenshot.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/screenshot.png-366f1bfaaaad7eddb9e724c7ff485921.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://screenshots/screenshot.png" 13 | dest_files=[ "res://.import/screenshot.png-366f1bfaaaad7eddb9e724c7ff485921.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /sounds/brick01.smp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/sounds/brick01.smp -------------------------------------------------------------------------------- /sounds/brick01.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/sounds/brick01.wav -------------------------------------------------------------------------------- /sounds/brick01.wav.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="wav" 4 | type="AudioStreamSample" 5 | path="res://.import/brick01.wav-0b34a3c4a66cc6a5e97552845e40dcc8.sample" 6 | 7 | [deps] 8 | 9 | source_file="res://sounds/brick01.wav" 10 | dest_files=[ "res://.import/brick01.wav-0b34a3c4a66cc6a5e97552845e40dcc8.sample" ] 11 | 12 | [params] 13 | 14 | force/8_bit=false 15 | force/mono=false 16 | force/max_rate=false 17 | force/max_rate_hz=44100 18 | edit/trim=true 19 | edit/normalize=true 20 | edit/loop=false 21 | compress/mode=0 22 | -------------------------------------------------------------------------------- /sounds/pad.smp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/sounds/pad.smp -------------------------------------------------------------------------------- /sounds/pad.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/sounds/pad.wav -------------------------------------------------------------------------------- /sounds/pad.wav.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="wav" 4 | type="AudioStreamSample" 5 | path="res://.import/pad.wav-6665021d4092b95196d2b5d2e89fbe76.sample" 6 | 7 | [deps] 8 | 9 | source_file="res://sounds/pad.wav" 10 | dest_files=[ "res://.import/pad.wav-6665021d4092b95196d2b5d2e89fbe76.sample" ] 11 | 12 | [params] 13 | 14 | force/8_bit=false 15 | force/mono=false 16 | force/max_rate=false 17 | force/max_rate_hz=44100 18 | edit/trim=true 19 | edit/normalize=true 20 | edit/loop=false 21 | compress/mode=0 22 | -------------------------------------------------------------------------------- /sounds/wall.smp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/sounds/wall.smp -------------------------------------------------------------------------------- /sounds/wall.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/sounds/wall.wav -------------------------------------------------------------------------------- /sounds/wall.wav.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="wav" 4 | type="AudioStreamSample" 5 | path="res://.import/wall.wav-59373acfcb0c45a5106115f03fac3c6e.sample" 6 | 7 | [deps] 8 | 9 | source_file="res://sounds/wall.wav" 10 | dest_files=[ "res://.import/wall.wav-59373acfcb0c45a5106115f03fac3c6e.sample" ] 11 | 12 | [params] 13 | 14 | force/8_bit=false 15 | force/mono=false 16 | force/max_rate=false 17 | force/max_rate_hz=44100 18 | edit/trim=true 19 | edit/normalize=true 20 | edit/loop=false 21 | compress/mode=0 22 | -------------------------------------------------------------------------------- /static_brick/brickshader.shd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/static_brick/brickshader.shd -------------------------------------------------------------------------------- /static_brick/brickshader1.shd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/static_brick/brickshader1.shd -------------------------------------------------------------------------------- /static_brick/brickshader2.shd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/static_brick/brickshader2.shd -------------------------------------------------------------------------------- /static_brick/static_brick.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node2D 3 | 4 | #autoload singletons 5 | # global 6 | 7 | var bw 8 | var bh 9 | var hp setget set_hp #bricks have hit points 10 | var current_hp setget set_current_hp 11 | 12 | func _ready(): 13 | bw=global.BRICK_WIDTH 14 | bh=global.BRICK_HEIGHT 15 | var rh = RectangleShape2D.new() 16 | rh.set_extents(Vector2(bw/2.2,bh/2.2)) 17 | var shape_owner_id = $brick_body.create_shape_owner($brick_body) 18 | $brick_body.shape_owner_clear_shapes(shape_owner_id) 19 | $brick_body.shape_owner_add_shape(shape_owner_id,rh) 20 | 21 | 22 | func set_hp(new_hp): 23 | hp = new_hp 24 | set_current_hp(hp) 25 | 26 | func set_current_hp(new_hp): 27 | current_hp=new_hp 28 | if(current_hp>0): 29 | $Sprite.set_texture(global.brick_texture[current_hp]) #change texture according to current hp 30 | 31 | 32 | -------------------------------------------------------------------------------- /static_brick/static_brick.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://static_brick/static_brick.gd" type="Script" id=1] 4 | [ext_resource path="res://textures/brick01.png" type="Texture" id=2] 5 | 6 | [node name="static_brick" type="Node2D"] 7 | 8 | position = Vector2( 3, 0 ) 9 | script = ExtResource( 1 ) 10 | __meta__ = { 11 | "__editor_plugin_screen__": "Script" 12 | } 13 | 14 | [node name="brick_body" type="StaticBody2D" parent="." index="0"] 15 | 16 | input_pickable = false 17 | collision_layer = 4 18 | collision_mask = 1 19 | constant_linear_velocity = Vector2( 0, 0 ) 20 | constant_angular_velocity = 0.0 21 | friction = 0.0 22 | bounce = 1.0 23 | 24 | [node name="Sprite" type="Sprite" parent="." index="1"] 25 | 26 | texture = ExtResource( 2 ) 27 | 28 | 29 | -------------------------------------------------------------------------------- /textures/background.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ImageTexture" format=2] 2 | 3 | [resource] 4 | 5 | flags = 7 6 | size = Vector2( 1024, 768 ) 7 | storage = 0 8 | lossy_quality = 0.7 9 | 10 | -------------------------------------------------------------------------------- /textures/black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/black.png -------------------------------------------------------------------------------- /textures/black.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/black.png-0262b92e70cb3a77f5677abea62f4776.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/black.png" 13 | dest_files=[ "res://.import/black.png-0262b92e70cb3a77f5677abea62f4776.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=1 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=false 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=false 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/bonus_big_paddle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/bonus_big_paddle.png -------------------------------------------------------------------------------- /textures/bonus_big_paddle.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/bonus_big_paddle.png-107148223a5eaef7ca7c2f1eb28428a8.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/bonus_big_paddle.png" 13 | dest_files=[ "res://.import/bonus_big_paddle.png-107148223a5eaef7ca7c2f1eb28428a8.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/bonus_extra_life.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/bonus_extra_life.png -------------------------------------------------------------------------------- /textures/bonus_extra_life.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/bonus_extra_life.png-dc59d503611c508b49059b9fae9a72c5.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/bonus_extra_life.png" 13 | dest_files=[ "res://.import/bonus_extra_life.png-dc59d503611c508b49059b9fae9a72c5.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/bonus_score.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/bonus_score.png -------------------------------------------------------------------------------- /textures/bonus_score.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/bonus_score.png-e15b913c0fd01f209aad2cc16bfb0a15.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/bonus_score.png" 13 | dest_files=[ "res://.import/bonus_score.png-e15b913c0fd01f209aad2cc16bfb0a15.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/bonus_small_paddle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/bonus_small_paddle.png -------------------------------------------------------------------------------- /textures/bonus_small_paddle.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/bonus_small_paddle.png-f30c11e89397be8d1e22e95c9625be9b.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/bonus_small_paddle.png" 13 | dest_files=[ "res://.import/bonus_small_paddle.png-f30c11e89397be8d1e22e95c9625be9b.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/bonus_sticky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/bonus_sticky.png -------------------------------------------------------------------------------- /textures/bonus_sticky.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/bonus_sticky.png-d1775f47d4109ec0b3ee3810f6df8c65.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/bonus_sticky.png" 13 | dest_files=[ "res://.import/bonus_sticky.png-d1775f47d4109ec0b3ee3810f6df8c65.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/bonus_three_balls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/bonus_three_balls.png -------------------------------------------------------------------------------- /textures/bonus_three_balls.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/bonus_three_balls.png-b9ca124edcc1826ffa6ca869ec918b28.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/bonus_three_balls.png" 13 | dest_files=[ "res://.import/bonus_three_balls.png-b9ca124edcc1826ffa6ca869ec918b28.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick01.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick01.ico -------------------------------------------------------------------------------- /textures/brick01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick01.png -------------------------------------------------------------------------------- /textures/brick01.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick01.png-e9c7295a1d8a3738692320ebca066bd9.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick01.png" 13 | dest_files=[ "res://.import/brick01.png-e9c7295a1d8a3738692320ebca066bd9.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick02.png -------------------------------------------------------------------------------- /textures/brick02.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick02.png-1428ffeddcdc04ae1026576e92d23efb.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick02.png" 13 | dest_files=[ "res://.import/brick02.png-1428ffeddcdc04ae1026576e92d23efb.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick03.png -------------------------------------------------------------------------------- /textures/brick03.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick03.png-49ec85ff40a3e35ead1def55134fe7d5.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick03.png" 13 | dest_files=[ "res://.import/brick03.png-49ec85ff40a3e35ead1def55134fe7d5.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick04.png -------------------------------------------------------------------------------- /textures/brick04.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick04.png-9313016d1fb8eaef4e67d5db4b79a50a.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick04.png" 13 | dest_files=[ "res://.import/brick04.png-9313016d1fb8eaef4e67d5db4b79a50a.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick05.png -------------------------------------------------------------------------------- /textures/brick05.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick05.png-6c8eb790c0d5985ab9d8190f7201ba14.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick05.png" 13 | dest_files=[ "res://.import/brick05.png-6c8eb790c0d5985ab9d8190f7201ba14.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick06.png -------------------------------------------------------------------------------- /textures/brick06.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick06.png-d4ee8459bc46ebcf0b84bc9c518da43d.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick06.png" 13 | dest_files=[ "res://.import/brick06.png-d4ee8459bc46ebcf0b84bc9c518da43d.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick07.png -------------------------------------------------------------------------------- /textures/brick07.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick07.png-9f6134bbf2f7f8292ccd5bf9fa47ac6a.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick07.png" 13 | dest_files=[ "res://.import/brick07.png-9f6134bbf2f7f8292ccd5bf9fa47ac6a.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick11.png -------------------------------------------------------------------------------- /textures/brick11.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick11.png-3d28983c71d81a1f90ef30fd395bde17.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick11.png" 13 | dest_files=[ "res://.import/brick11.png-3d28983c71d81a1f90ef30fd395bde17.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/brick17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/brick17.png -------------------------------------------------------------------------------- /textures/brick17.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/brick17.png-66276caaeb2e1e7b1101d23d4c4d2fa2.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/brick17.png" 13 | dest_files=[ "res://.import/brick17.png-66276caaeb2e1e7b1101d23d4c4d2fa2.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /textures/paddle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/textures/paddle.png -------------------------------------------------------------------------------- /textures/paddle.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/paddle.png-1d2a28e983477361da92398ef0d5efd1.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://textures/paddle.png" 13 | dest_files=[ "res://.import/paddle.png-1d2a28e983477361da92398ef0d5efd1.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /themes/main.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Theme" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://fonts/ricasso_font.tres" type="DynamicFont" id=1] 4 | 5 | [resource] 6 | 7 | default_font = ExtResource( 1 ) 8 | Button/colors/font_color = Color( 0.303863, 0.839844, 0.299643, 1 ) 9 | Button/colors/font_color_disabled = Color( 0.753906, 0.753906, 0.753906, 0.2 ) 10 | Button/colors/font_color_hover = Color( 0.303711, 0.839844, 0.299561, 1 ) 11 | Button/colors/font_color_pressed = Color( 1, 1, 1, 1 ) 12 | Button/constants/hseparation = 2 13 | Button/fonts/font = null 14 | Button/styles/disabled = null 15 | Button/styles/focus = null 16 | Button/styles/hover = null 17 | Button/styles/normal = null 18 | Button/styles/pressed = null 19 | GridContainer/constants/hseparation = 4 20 | GridContainer/constants/vseparation = 4 21 | _sections_unfolded = [ "GridContainer", "GridContainer/constants" ] 22 | 23 | -------------------------------------------------------------------------------- /translations/translation.csv: -------------------------------------------------------------------------------- 1 | ,fr,en 2 | BONUS_SCORE,1000 points de plus,1000 more points 3 | BONUS_STICKY,GLU,Sticky 4 | BONUS_THREE_BALLS,3 BALLES,3 BALLS 5 | BONUS_EXTRA_LIFE,1 vie supplémentaire,1 Extra Life 6 | BONUS_SMALL_PADDLE,Petite raquette,Small paddle 7 | BONUS_BIG_PADDLE,Grande raquette,Big paddle 8 | SCORE,Score,Score 9 | BTN_CONTINUE,Continuer,Continue 10 | BTN_ABANDON,Abandonner,Abandon 11 | GAME_OVER,Game over,Game over 12 | BTN_PLAY_AGAIN,Rejouer,Play again 13 | BTN_MAIN_MENU,Menu principal,Main menu 14 | HI_SCORES,HI SCORES,HI SCORES 15 | BTN_NEW_GAME,Nouvelle partie,New game 16 | BTN_HI_SCORES,Hi scores,Hi scores 17 | BTN_OPTIONS,Options,Options 18 | BTN_QUIT,Quitter,Quit 19 | NEW_HI_SCORE,Nouveau record,New Hi Score 20 | ENTER_YOUR_NAME,Entrez votre nom,Enter your name 21 | BTN_OK,OK,OK 22 | LANGUAGE,Langue,Language 23 | FULL_SCREEN,Plein écran,Full screen -------------------------------------------------------------------------------- /translations/translation.csv.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="csv_translation" 4 | type="Translation" 5 | 6 | [deps] 7 | 8 | files=[ "res://translations/translation.fr.translation", "res://translations/translation.en.translation" ] 9 | 10 | source_file="res://translations/translation.csv" 11 | dest_files=[ "res://translations/translation.fr.translation", "res://translations/translation.en.translation" ] 12 | 13 | [params] 14 | 15 | compress=true 16 | delimiter=0 17 | -------------------------------------------------------------------------------- /translations/translation.en.translation: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/translations/translation.en.translation -------------------------------------------------------------------------------- /translations/translation.fr.translation: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didier-v/breakable/b4530ee031fb40f962a13c8bf3b329299482b482/translations/translation.fr.translation -------------------------------------------------------------------------------- /wall/wall.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends StaticBody2D 3 | 4 | # a generic wall that can be made horizontal or vertical in the editor 5 | # it adjusts its collision shape accordingly 6 | 7 | export (String, "horizontal","vertical") var orientation setget set_orientation 8 | export (Color, RGBA) var color setget set_color 9 | export (float) var width=10 setget set_width 10 | export (float) var length=512 setget set_length 11 | var shape_owner 12 | 13 | func _ready(): 14 | if orientation==null: 15 | orientation="horizontal" 16 | update_wall() 17 | 18 | 19 | 20 | func update_wall(): 21 | if !get_shape_owners().empty(): # the function can be called before the shape owner is created 22 | var so = get_shape_owners()[0] 23 | self.shape_owner_clear_shapes(so) 24 | var r = RectangleShape2D.new() 25 | if(orientation=="horizontal"): 26 | r.set_extents(Vector2(length/2,width/2)) 27 | else: 28 | r.set_extents(Vector2(width/2,length/2)) 29 | self.shape_owner_add_shape(so,r) 30 | update() 31 | 32 | 33 | func _draw(): 34 | var r 35 | if(orientation=="horizontal"): 36 | r = Rect2(-length/2,-width/2,length,width) 37 | else: 38 | r = Rect2(-width/2,-length/2,width,length) 39 | draw_rect(r,color) 40 | 41 | 42 | func set_orientation(o): 43 | orientation=o 44 | update_wall() 45 | 46 | func set_color(c): 47 | color=c 48 | update() 49 | 50 | func set_width(w): 51 | width=w 52 | update_wall() 53 | 54 | func set_length(l): 55 | length=l 56 | update_wall() 57 | -------------------------------------------------------------------------------- /wall/wall.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://wall/wall.gd" type="Script" id=1] 4 | 5 | [sub_resource type="RectangleShape2D" id=1] 6 | 7 | custom_solver_bias = 0.0 8 | extents = Vector2( 2.03986, 2.63013 ) 9 | 10 | [node name="wall" type="StaticBody2D" index="0"] 11 | 12 | input_pickable = false 13 | collision_layer = 1 14 | collision_mask = 1 15 | constant_linear_velocity = Vector2( 0, 0 ) 16 | constant_angular_velocity = 0.0 17 | friction = 0.0 18 | bounce = 1.0 19 | script = ExtResource( 1 ) 20 | __meta__ = { 21 | "__editor_plugin_screen__": "2D" 22 | } 23 | orientation = null 24 | color = Color( 1, 1, 1, 1 ) 25 | width = 10 26 | length = 512 27 | 28 | [node name="CollisionShape2D" type="CollisionShape2D" parent="." index="0"] 29 | 30 | shape = SubResource( 1 ) 31 | _sections_unfolded = [ "Transform", "Z Index" ] 32 | 33 | 34 | --------------------------------------------------------------------------------