120 lines
4.8 KiB
GDScript
120 lines
4.8 KiB
GDScript
@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)
|