@tool extends Node2D const SHEET = preload("res://games/space_invaders/art/sprites.png") const GLYPHS := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<>=*?-" var masks: Dictionary = {} var textures: Dictionary = {} var game: Node func _ready() -> void: game = get_parent().get_parent() var sheet := SHEET.get_image() for kind in range(3): for frame in range(2): register("alien%d_%d"%[kind,frame],sheet,Rect2i(1+kind*18,1+frame*10,16,8)) register("burst",sheet,Rect2i(55,1,16,8)) register("ufo",sheet,Rect2i(1,39,16,8)) register("ufo_burst",sheet,Rect2i(19,39,24,8)) register("shield",sheet,Rect2i(45,31,24,16)) register("player",sheet,Rect2i(1,49,16,8)) register("death0",sheet,Rect2i(19,49,16,8)) register("death1",sheet,Rect2i(37,49,16,8)) register("shot_burst",sheet,Rect2i(55,49,10,8)) for i in range(12): register("bomb%d"%i,sheet,Rect2i(1+i*5,21,3,8)) for i in range(GLYPHS.length()): register(GLYPHS[i],sheet,Rect2i(1+(i%8)*10,69+int(i/8)*10,8,8)) func register(key: String, sheet: Image, region: Rect2i) -> void: var pixels := sheet.get_region(region) pixels.convert(Image.FORMAT_RGBA8) for y in range(pixels.get_height()): for x in range(pixels.get_width()): var value := pixels.get_pixel(x,y) pixels.set_pixel(x,y,Color.WHITE if value.r>.8 and value.g>.8 and value.b>.8 else Color.TRANSPARENT) masks[key] = pixels textures[key] = ImageTexture.create_from_image(pixels) func sprite(key: String, point: Vector2) -> void: draw_texture(textures[key],point.round()) func text(value: String, point: Vector2, revealed: int = 999) -> void: for i in range(mini(value.length(),revealed)): if textures.has(value[i]): sprite(value[i],point+Vector2(i*8,0)) func centered(value: String, y: float, revealed: int = 999) -> void: text(value,Vector2((224-value.length()*8)/2.0,y),revealed) func title_repair(t: float) -> void: var letter_x := 120.0 var invader_x := 232.0 # Carry the letter beside the invader, fully beyond the right edge, # then bring it back upright before leaving it in its original position. if t < 12: invader_x = lerpf(232,128,clampf((t-9)/3,0,1)) elif t < 15: invader_x = lerpf(128,232,(t-12)/3) letter_x = invader_x-8 elif t < 15.5: letter_x = 224 elif t < 18.5: invader_x = lerpf(232,128,(t-15.5)/3) letter_x = invader_x-8 else: invader_x = lerpf(128,232,clampf((t-18.5)/3,0,1)) if t > .5: if t < 15.5: draw_set_transform(Vector2(roundf(letter_x),72),0,Vector2(1,-1)) sprite("Y",Vector2.ZERO) draw_set_transform(Vector2.ZERO) else: sprite("Y",Vector2(letter_x,64)) if t >= 9 and t < 21.5: sprite("alien0_%d"%(int(t*5)%2),Vector2(invader_x,64)) func attract() -> void: var t: float = game.phase_time if t<22: # The little invader repairs the upside-down Y in PLAY. text("PLA",Vector2(96,64),int(t*8)) title_repair(t) centered("SPACE INVADERS",88,int((t-1)*12)) if t>=2.5: centered("*SCORE ADVANCE TABLE*",120,int((t-2.5)*16)) for i in range(4): if t<4+i*.6: continue sprite(["ufo","alien0_0","alien1_0","alien2_0"][i],Vector2(56,136+i*16)) text(["=? MYSTERY","=30 POINTS","=20 POINTS","=10 POINTS"][i],Vector2(72,136+i*16),int((t-4-i*.6)*15)) else: centered("PUSH START",104) centered("<1 PLAYER>",136) centered("*FREE PLAY*",160) centered("BONUS AT %04d"%game.bonus_life_score,192) func _draw() -> void: if game == null: return draw_rect(Rect2(0,0,224,256),Color.BLACK) text("SCORE<1> HI-SCORE SCORE<2>",Vector2(8,8)) text("%04d"%(game.last_score if game.demo else game.score),Vector2(24,24)) text("%04d"%game.high_score,Vector2(88,24)) text("0000",Vector2(176,24)) text("CREDIT 00",Vector2(144,248)) if game.phase == "attract": attract() return for alien in game.aliens: if alien.alive: sprite("alien%d_%d"%[alien.kind,alien.frame],alien.position-Vector2(8,4)) for shield in game.shields: draw_texture(shield.texture,Vector2(shield.position)) if game.saucer_active: sprite("ufo",Vector2(game.saucer_x-8,40)) if game.phase == "dead": sprite("death%d"%(int(game.phase_time*10)%2),Vector2(game.player_x-8,216)) elif game.phase in ["play","clear"]: sprite("player",Vector2(game.player_x-8,216)) if game.shot_active: draw_rect(Rect2(game.player_shot.round()-Vector2(0,1),Vector2(1,4)),Color.WHITE) for bomb in game.bombs: sprite("bomb%d"%(bomb.kind*4+int(game.clock*12)%4),bomb.position-Vector2(1,4)) for effect in game.effects: if effect.text != "" and effect.time<.4: text(effect.text,effect.position-Vector2(12,4)) else: sprite(effect.name,effect.position-Vector2(8,4)) draw_line(Vector2(8,239),Vector2(216,239),Color.WHITE,1) text(str(game.lives),Vector2(8,248)) for i in range(mini(maxi(0,game.lives-1),6)): sprite("player",Vector2(24+i*16,248)) if game.phase == "ready": centered("PLAY PLAYER<1>",160) if game.phase == "won": centered("YOU WIN",160) if game.phase == "lost" or (game.demo and int(game.demo_time)%2==0): centered("GAME OVER",160)