Added Glitch Room Source code to Gitty
This commit is contained in:
commit
1ac9eb5644
505 files changed
+28504
No files matched your search
@@ -0,0 +1,211 @@
|
||||
@tool
|
||||
extends Node2D
|
||||
const SIZE := Vector2(256,231)
|
||||
const FONT := {
|
||||
"A":[14,17,17,31,17,17,17],"B":[30,17,17,30,17,17,30],"C":[14,17,16,16,16,17,14],"D":[30,17,17,17,17,17,30],"E":[31,16,16,30,16,16,31],"F":[31,16,16,30,16,16,16],"G":[14,17,16,23,17,17,15],"H":[17,17,17,31,17,17,17],"I":[31,4,4,4,4,4,31],"J":[7,2,2,2,18,18,12],"K":[17,18,20,24,20,18,17],"L":[16,16,16,16,16,16,31],"M":[17,27,21,21,17,17,17],"N":[17,25,21,19,17,17,17],"O":[14,17,17,17,17,17,14],"P":[30,17,17,30,16,16,16],"Q":[14,17,17,17,21,18,13],"R":[30,17,17,30,20,18,17],"S":[15,16,16,14,1,1,30],"T":[31,4,4,4,4,4,4],"U":[17,17,17,17,17,17,14],"V":[17,17,17,17,17,10,4],"W":[17,17,17,21,21,21,10],"X":[17,17,10,4,10,17,17],"Y":[17,17,10,4,4,4,4],"Z":[31,1,2,4,8,16,31],
|
||||
"0":[14,17,19,21,25,17,14],"1":[4,12,4,4,4,4,14],"2":[14,17,1,2,4,8,31],"3":[30,1,1,14,1,1,30],"4":[2,6,10,18,31,2,2],"5":[31,16,16,30,1,1,30],"6":[14,16,16,30,17,17,14],"7":[31,1,2,4,8,8,8],"8":[14,17,17,14,17,17,14],"9":[14,17,17,15,1,1,14],"!":[4,4,4,4,4,0,4],"-":[0,0,0,31,0,0,0],".":[0,0,0,0,0,12,12],":":[0,12,12,0,12,12,0]
|
||||
}
|
||||
var game: Node
|
||||
var mesh := ArrayMesh.new()
|
||||
var vertices := PackedVector3Array()
|
||||
var colors := PackedColorArray()
|
||||
var indices := PackedInt32Array()
|
||||
var logo_pixels: Array[Vector2i] = []
|
||||
var title_craters: Array[Dictionary] = []
|
||||
var title_rows: Dictionary = {}
|
||||
|
||||
func _ready() -> void:
|
||||
game = get_parent().get_parent()
|
||||
_build_logo()
|
||||
|
||||
func _build_logo() -> void:
|
||||
for row in range(2):
|
||||
var word := "MISSILE" if row == 0 else "COMMAND"
|
||||
for letter in range(word.length()):
|
||||
for y in range(7):
|
||||
for x in range(5):
|
||||
if FONT[word[letter]][y] & (1 << (4-x)):
|
||||
for sy in range(4):
|
||||
for sx in range(4):
|
||||
logo_pixels.append(Vector2i(46+letter*24+x*4+sx,65+row*43+y*4+sy))
|
||||
# Each crater has a deterministic impact time and persists as missing pixels.
|
||||
for i in range(42):
|
||||
title_craters.append({"pos":Vector2(42+fposmod(i*59.7,174),62+fposmod(i*37.3,79)),"time":1.0+i*.145,"radius":9.0+float(i%5)})
|
||||
|
||||
for row in range(2):
|
||||
for letter in range(7):
|
||||
title_craters.append({"pos":Vector2(56+letter*24,79+row*43),"time":6.2+letter*.1,"radius":20.0})
|
||||
# Precompute erosion times once, not a pixel/crater search every frame.
|
||||
for point in logo_pixels:
|
||||
var erased_at := 7.7
|
||||
for crater in title_craters:
|
||||
var distance := Vector2(point).distance_to(crater.pos)
|
||||
if distance < crater.radius:
|
||||
erased_at = minf(erased_at,crater.time+distance/30.0)
|
||||
if not title_rows.has(point.y): title_rows[point.y] = []
|
||||
title_rows[point.y].append(Vector2(point.x,erased_at))
|
||||
for y in title_rows:
|
||||
title_rows[y].sort_custom(func(a: Vector2,b: Vector2) -> bool: return a.x < b.x)
|
||||
|
||||
func rect(position: Vector2, size: Vector2, color: Color) -> void:
|
||||
var start := vertices.size()
|
||||
for point in [position,position+Vector2(size.x,0),position+size,position+Vector2(0,size.y)]:
|
||||
vertices.append(Vector3(floorf(point.x),floorf(point.y),0))
|
||||
colors.append(color)
|
||||
indices.append_array(PackedInt32Array([start,start+1,start+2,start,start+2,start+3]))
|
||||
|
||||
func segment(a: Vector2,b: Vector2,color: Color) -> void:
|
||||
var count := maxi(1,int(maxf(absf(b.x-a.x),absf(b.y-a.y))))
|
||||
for i in range(count+1): rect(a.lerp(b,float(i)/count).round(),Vector2.ONE,color)
|
||||
|
||||
func disk(center: Vector2,radius: float,color: Color) -> void:
|
||||
var r := int(radius)
|
||||
for y in range(-r,r+1):
|
||||
var extent := int(sqrt(maxf(0,r*r-y*y)))
|
||||
rect(center+Vector2(-extent,y),Vector2(extent*2+1,1),color)
|
||||
|
||||
func text_at(value: String,at: Vector2,color: Color,size: int = 1) -> void:
|
||||
for i in range(value.length()):
|
||||
if not FONT.has(value[i]): continue
|
||||
for y in range(7):
|
||||
var run := -1
|
||||
for x in range(6):
|
||||
var filled: bool = x < 5 and (FONT[value[i]][y] & (1 << (4-x))) != 0
|
||||
if filled and run < 0: run = x
|
||||
if not filled and run >= 0:
|
||||
rect(at+Vector2((i*6+run)*size,y*size),Vector2((x-run)*size,size),color)
|
||||
run = -1
|
||||
|
||||
func label(value: String,y: float,color: Color,size: int = 1) -> void:
|
||||
text_at(value,Vector2((256-(value.length()*6-1)*size)/2.0,y),color,size)
|
||||
|
||||
func palette() -> Array:
|
||||
return [[Color("ffff00"),Color("203cff"),Color("ff2525")],[Color("20e5ff"),Color("ff3030"),Color("ffffff")],[Color("ff3030"),Color("24ff35"),Color("ffff00")]][int((game.wave-1)/2)%3]
|
||||
|
||||
func landscape() -> void:
|
||||
var p := palette()
|
||||
rect(Vector2(0,214),Vector2(256,17),p[0])
|
||||
for i in range(3):
|
||||
var x: float = game.BASE_X[i]
|
||||
for y in range(12): rect(Vector2(x-8-y,202+y),Vector2(16+y*2,1),p[0])
|
||||
if game.bases[i]:
|
||||
var slots := [Vector2(0,-9),Vector2(-2,-6),Vector2(2,-6),Vector2(-4,-3),Vector2(0,-3),Vector2(4,-3),Vector2(-6,0),Vector2(-2,0),Vector2(2,0),Vector2(6,0)]
|
||||
for missile in range(game.ammo[i]):
|
||||
var at: Vector2 = Vector2(x,213)+slots[missile]
|
||||
rect(at-Vector2(0,2),Vector2(1,3),p[1])
|
||||
rect(at-Vector2(1,0),Vector2(3,1),p[1])
|
||||
else: rect(Vector2(x-7,207),Vector2(14,7),Color.BLACK)
|
||||
for i in range(6):
|
||||
var x: float = game.CITY_X[i]
|
||||
if game.cities[i]:
|
||||
for building in range(7):
|
||||
var h := 2+(building*3+i)%7
|
||||
rect(Vector2(x-9+building*3,214-h),Vector2(2,h),p[1])
|
||||
rect(Vector2(x-9,212),Vector2(20,2),p[1])
|
||||
else:
|
||||
rect(Vector2(x-9,213),Vector2(19,2),Color.BLACK)
|
||||
|
||||
func hud() -> void:
|
||||
var p := palette()
|
||||
text_at(str(game.score),Vector2(14,7),p[2])
|
||||
text_at(str(game.high_score),Vector2(106,7),p[2])
|
||||
text_at("1UP",Vector2(17,18),p[1])
|
||||
text_at("HIGH",Vector2(112,18),p[1])
|
||||
text_at("WAVE %d" % game.wave,Vector2(204,7),p[2])
|
||||
|
||||
func title() -> void:
|
||||
var t: float = game.attract_time
|
||||
var color := Color.from_hsv(fposmod(floor(t*5)/7,1),1,1)
|
||||
for y in title_rows:
|
||||
var run_start := -1
|
||||
var run_end := -1
|
||||
for pixel in title_rows[y]:
|
||||
var x := int(pixel.x)
|
||||
var visible: bool = t < pixel.y
|
||||
if run_start >= 0 and (not visible or x > run_end+1):
|
||||
rect(Vector2(run_start,y),Vector2(run_end-run_start+1,1),color)
|
||||
run_start = -1
|
||||
if visible:
|
||||
if run_start < 0: run_start = x
|
||||
run_end = x
|
||||
if run_start >= 0: rect(Vector2(run_start,y),Vector2(run_end-run_start+1,1),color)
|
||||
for crater in title_craters:
|
||||
var age: float = t-crater.time
|
||||
if age > 0 and age < .65:
|
||||
disk(crater.pos,minf(9,age*25)*(1-age/.65),Color.from_hsv(fposmod(t*.7+.33,1),1,1))
|
||||
label("PUSH START",174,Color("24ff35"))
|
||||
label("MISSILE COMMAND",193,Color("2040ff"))
|
||||
label("FREE PLAY",222,Color("ffff00"))
|
||||
|
||||
func _draw() -> void:
|
||||
if game == null: return
|
||||
vertices.clear()
|
||||
colors.clear()
|
||||
indices.clear()
|
||||
draw_rect(Rect2(Vector2.ZERO,SIZE),Color.BLACK)
|
||||
if game.phase == "title":
|
||||
title()
|
||||
elif game.phase == "leaderboard":
|
||||
landscape()
|
||||
hud()
|
||||
label("HIGH SCORES",37,Color("2040ff"))
|
||||
for i in range(8):
|
||||
var value := "%06d" % game.leaderboard[i] if i < game.leaderboard.size() else "------"
|
||||
text_at("P1" if i < game.leaderboard.size() else "--",Vector2(70,56+i*12),Color.YELLOW)
|
||||
text_at(value,Vector2(126,56+i*12),Color.YELLOW)
|
||||
label("BONUS CITY EVERY",163,Color("2040ff"))
|
||||
label("%d POINTS" % game.bonus_city_interval,176,Color.YELLOW)
|
||||
label("PUSH START",195,Color("2040ff"))
|
||||
else:
|
||||
landscape()
|
||||
hud()
|
||||
var p := palette()
|
||||
for missile in game.incoming:
|
||||
segment(missile.origin,missile.pos,p[2])
|
||||
if missile.kind == "smart":
|
||||
var at: Vector2 = missile.pos
|
||||
segment(at+Vector2(0,-3),at+Vector2(2,0),Color.WHITE)
|
||||
segment(at+Vector2(2,0),at+Vector2(0,3),Color.WHITE)
|
||||
segment(at+Vector2(0,3),at+Vector2(-2,0),Color.WHITE)
|
||||
segment(at+Vector2(-2,0),at+Vector2(0,-3),Color.WHITE)
|
||||
else: rect(missile.pos,Vector2(2,2),Color.WHITE)
|
||||
for shot in game.interceptors:
|
||||
segment(shot.origin,shot.pos,p[1])
|
||||
rect(shot.pos,Vector2(2,2),Color.WHITE)
|
||||
for plane in game.aircraft:
|
||||
var at: Vector2 = plane.pos
|
||||
segment(at-Vector2(6,0),at+Vector2(6,0),p[2])
|
||||
segment(at-Vector2(2,4),at+Vector2(2,4),p[2])
|
||||
segment(at-Vector2(5,2),at-Vector2(5,-2),p[2])
|
||||
for blast in game.blasts:
|
||||
var color: Color = p[2] if int(game.clock*12)%3 != 0 else Color.WHITE
|
||||
disk(blast.pos,blast.radius,color)
|
||||
if blast.age > 1.0: disk(blast.pos,blast.radius*.5,Color.BLACK)
|
||||
if game.phase in ["play","ready"]:
|
||||
var at: Vector2 = game.aim.round()
|
||||
segment(at-Vector2(3,0),at+Vector2(3,0),p[1])
|
||||
segment(at-Vector2(0,3),at+Vector2(0,3),p[1])
|
||||
if game.phase == "ready": label("DEFEND CITIES",181,p[1])
|
||||
if game.phase == "bonus":
|
||||
label("BONUS POINTS",85,p[1])
|
||||
label(str(game.wave_bonus),102,p[0],2)
|
||||
label("%d CITIES SAVED" % game.cities.count(true),131,p[1])
|
||||
if game.phase == "lost":
|
||||
disk(Vector2(128,114),minf(75,(5-game.phase_time)*24),p[2])
|
||||
label("THE END",110,Color.BLACK,2)
|
||||
if game.phase == "won":
|
||||
label("YOU WIN!",100,p[0],2)
|
||||
label("CITIES DEFENDED",123,p[1])
|
||||
label("PUSH START",178,p[1])
|
||||
mesh.clear_surfaces()
|
||||
if not vertices.is_empty():
|
||||
var arrays := []
|
||||
arrays.resize(Mesh.ARRAY_MAX)
|
||||
arrays[Mesh.ARRAY_VERTEX] = vertices
|
||||
arrays[Mesh.ARRAY_COLOR] = colors
|
||||
arrays[Mesh.ARRAY_INDEX] = indices
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES,arrays)
|
||||
draw_mesh(mesh,null)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user