I gave Gemini this example to look at:
, and then asked it to create an Asteroids game in the same language (n7):
It succeeded quite well.
Edit: And it did something that I never thought of. To be able to delete items from an array while iterating its elements, it does the iteration backwards. That way it can safely call "free key array, i" without messing up the loop. Maybe that's common practice and I've just been stupid
Code:
' Training program
' ----------------
' Make vStars a visible (global) variable.
visible vStars
' Create a window of the size 640x480 with the title "Example".
set window "Example", 640, 480
' Turn off automatic redraw, meaning that we will have to call 'redraw' to manually copy the game's
' back buffer to the window.
set redraw off
' Create a 1D array with coordinates for a "spaceship" turned left (0 degree rotation). The
' coordinates come as [X0, Y0, X1, Y1 .. Xn, Yn]
spaceship = [-16, -8, 16, 0, -16, 8, -8, 0]
' Make vStars an empty array and fill it with 100 stars.
vStars = []
for i = 1 to 100
' Add star last in array. 'rnd()' returns a random number in the range 0..1, 'rnd(n)' returns an
' integer in the range 0..n-1.
vStars[sizeof(vStars)] = [x: rnd(640), y: rnd(480), dx: -(0.25 + rnd()*3), i: 64 + rnd(128)]
next
' Create a player, position 320, 240, angle 0 degrees.
player = []
player.x = 320
player.y = 240
player.angle = 0
' Loop until the escape key is pressed.
while not keydown(KEY_ESCAPE)
' Call function UpdateBackground, that updates the stars in the global array vStars.
UpdateBackground()
' Update player.
if keydown(KEY_LEFT)
player.angle = (player.angle - 2.5)%360
endif
if keydown(KEY_RIGHT) player.angle = (player.angle + 2.5)%360
' Clear screen with the color black.
set color 0, 0, 0
cls
' Draw stars. Just for showing, pass vStars array as a parameter. Arrays (or tables) are always
' passed by reference.
DrawStars(vStars)
' Draw player as a filled polygon using 'draw poly xform points, x, y, scale_x, scale_y, angle,
' pivot_x, pivot_y[, filled]'
set color 255, 255, 255
draw poly xform spaceship, player.x, player.y, 1, 1, rad(player.angle), 0, 0, true
' Copy backbuffer to window and use 'fwait' to cap fps at 60.
redraw
fwait 60
wend
' UpdateBackground
' ----------------
function UpdateBackground()
' The % operator uses mathematical modulus and wraps negative numbers.
foreach s in vStars s.x = (s.x + s.dx)%640
endfunc
' DrawStars
' ---------
function DrawStars(stars)
foreach s in stars
set color s.i, s.i, s.i
draw pixel s.x, s.y
next
endfunc
' Some unused functions just to show how functions work.
' ------------------------------------------------------
' RectInsideWindow
' ----------------
' Return true if rect is inside window.
function RectInsideWindow(x, y, w, h)
return x + w > 0 and x < 640 and y + h > 0 and y < 480
endfunc
' NormalizedVector
' ----------------
' Return normalized vector as array.
function NormalizedVector(x, y)
d = x*x + y*y
if d
d = sqr(d)
return [x/d, y/d]
else
return [0, 0]
endif
endfunc, and then asked it to create an Asteroids game in the same language (n7):
Code:
' Asteroids Clone in Naalaa 7
' ---------------------------
visible vAsteroids, vLasers, vExplosions, vScore
' Initialize game engine canvas
set window "Asteroids 7", 800, 600
set redraw off
' Geometric shapes (Vectors/Polygons)
shapeShip = [0, -12, 10, 10, 4, 6, -4, 6, -10, 10]
shapeThrust = [3, 7, 0, 14, -3, 7]
' Globally shared lists
vAsteroids = []
vLasers = []
vExplosions = []
vScore = 0
' Player Entity Definition
player = [x: 400.0, y: 300.0, dx: 0.0, dy: 0.0, angle: 0.0, shootCooldown: 0, alive: true, spawnTimer: 0]
' Spawn initial wave of asteroids
SpawnAsteroidWave(4)
' Main Game Loop
while not keydown(KEY_ESCAPE)
' 1. Logic & Physics Updates
UpdatePlayer(player)
UpdateLasers()
UpdateAsteroids()
UpdateExplosions()
CheckCollisions(player)
' Respawn logic if player died
if not player.alive
player.spawnTimer = player.spawnTimer - 1
if player.spawnTimer <= 0
player.x = 400.0
player.y = 300.0
player.dx = 0.0
player.dy = 0.0
player.angle = 0.0
player.alive = true
endif
endif
' Advance waves if screen cleared
if sizeof(vAsteroids) = 0 and player.alive
SpawnAsteroidWave(5)
endif
' 2. Rendering Phase
set color 10, 10, 15 ' Deep space background
cls
' Render game components
DrawAsteroids()
DrawLasers()
DrawExplosions()
if player.alive
set color 255, 255, 255
draw poly xform shapeShip, player.x, player.y, 1.0, 1.0, rad(player.angle), 0, 0, false
' Draw thrust tail flame if accelerating
if keydown(KEY_UP)
set color 255, 128, 0
draw poly xform shapeThrust, player.x, player.y, 1.0, 1.0, rad(player.angle), 0, 0, false
endif
endif
' UI Overlay
set color 255, 255, 255
set caret 20, 20
write "SCORE: " + vScore
if not player.alive
set caret 340, 280
write "READYING SHIP..."
endif
redraw
fwait 60
wend
' ---- Physics & Controller Updates ----
function UpdatePlayer(p)
if not p.alive return
' Rotation (Angular mechanics)
if keydown(KEY_LEFT) p.angle = (p.angle - 4.0) % 360
if keydown(KEY_RIGHT) p.angle = (p.angle + 4.0) % 360
' Thrust acceleration using trigonometry
if keydown(KEY_UP)
' Subtracted 90 degrees because 0 rad points right, but ship shape points up
p.dx = p.dx + cos(rad(p.angle - 90.0)) * 0.12
p.dy = p.dy + sin(rad(p.angle - 90.0)) * 0.12
endif
' Apply space drag/friction
p.dx = p.dx * 0.99
p.dy = p.dy * 0.99
' Movement application
p.x = p.x + p.dx
p.y = p.y + p.dy
' Screen-edge toroidal wrapping
if p.x < -15 p.x = p.x + 830
if p.x > 815 p.x = p.x - 830
if p.y < -15 p.y = p.y + 630
if p.y > 615 p.y = p.y - 630
' Laser fire rate managing
if p.shootCooldown > 0 p.shootCooldown = p.shootCooldown - 1
if keydown(KEY_SPACE) and p.shootCooldown = 0
lx = p.x + cos(rad(p.angle - 90.0)) * 12.0
ly = p.y + sin(rad(p.angle - 90.0)) * 12.0
ldx = cos(rad(p.angle - 90.0)) * 7.0 + p.dx
ldy = sin(rad(p.angle - 90.0)) * 7.0 + p.dy
vLasers[sizeof(vLasers)] = [x: lx, y: ly, dx: ldx, dy: ldy, life: 60]
p.shootCooldown = 15 ' frames between shots
endif
endfunc
function UpdateLasers()
if sizeof(vLasers)
for i = sizeof(vLasers) - 1 to 0
vLasers[i].x = vLasers[i].x + vLasers[i].dx
vLasers[i].y = vLasers[i].y + vLasers[i].dy
vLasers[i].life = vLasers[i].life - 1
' Wrap lasers around screen borders
if vLasers[i].x < 0 vLasers[i].x = vLasers[i].x + 800
if vLasers[i].x > 800 vLasers[i].x = vLasers[i].x - 800
if vLasers[i].y < 0 vLasers[i].y = vLasers[i].y + 600
if vLasers[i].y > 600 vLasers[i].y = vLasers[i].y - 600
' Purge expired lasers
if vLasers[i].life <= 0
free key vLasers, i
endif
next
endif
endfunc
function UpdateAsteroids()
foreach ast in vAsteroids
ast.x = ast.x + ast.dx
ast.y = ast.y + ast.dy
ast.angle = (ast.angle + ast.rotSpeed) % 360
' Wrap rocks around screen boundaries
if ast.x < -40 ast.x = ast.x + 880
if ast.x > 840 ast.x = ast.x - 880
if ast.y < -40 ast.y = ast.y + 680
if ast.y > 640 ast.y = ast.y - 680
next
endfunc
function UpdateExplosions()
if sizeof(vExplosions)
for i = sizeof(vExplosions) - 1 to 0
foreach p in vExplosions[i].particles
p.x = p.x + p.dx
p.y = p.y + p.dy
next
vExplosions[i].life = vExplosions[i].life - 1
if vExplosions[i].life <= 0
free key vExplosions, i
endif
next
endif
endfunc
' ---- Collision Resolution & Scoring ----
function CheckCollisions(p)
if not p.alive return
' Laser hitting an Asteroid
if sizeof(vLasers)
for l = sizeof(vLasers) - 1 to 0
if sizeof(vAsteroids)
for a = sizeof(vAsteroids) - 1 to 0
distSq = (vLasers[l].x - vAsteroids[a].x)^2 + (vLasers[l].y - vAsteroids[a].y)^2
radiusSumSq = (vAsteroids[a].radius)^2
if distSq < radiusSumSq
' Trigger explosion and scoring updates
CreateExplosion(vAsteroids[a].x, vAsteroids[a].y, 12)
vScore = vScore + (4 - vAsteroids[a].size) * 10
' Fragmentation rules
if vAsteroids[a].size > 1
SplitAsteroid(vAsteroids[a])
endif
free key vAsteroids, a
free key vLasers, l
break
endif
next
endif
next
endif
' Asteroid smashing into player
if sizeof(vAsteroids)
for a = sizeof(vAsteroids) - 1 to 0
distSq = (p.x - vAsteroids[a].x)^2 + (p.y - vAsteroids[a].y)^2
radiusSumSq = (vAsteroids[a].radius + 8.0)^2
if distSq < radiusSumSq
CreateExplosion(p.x, p.y, 40)
p.alive = false
p.spawnTimer = 120 ' 2 seconds wait time
break
endif
next
endif
endfunc
' ---- Generation Mechanics ----
function SpawnAsteroidWave(count)
for i = 1 to count
ax = rnd(2) * 800 ' Spawn on edges safely away from center player
ay = rnd(2) * 600
if abs(ax - 400) < 100 ax = ax + 200
GenerateAsteroid(ax, ay, 3) ' 3 = Large size category
next
endfunc
function GenerateAsteroid(x, y, size)
radius = size * 12.0
p = []
' Build a randomly randomized procedural circular ring
numPoints = 10 + rnd(5)
for i = 0 to numPoints - 1
ang = (360.0 / numPoints) * i
r = radius - 4.0 + rnd() * 8.0
p[sizeof(p)] = cos(rad(ang)) * r
p[sizeof(p)] = sin(rad(ang)) * r
next
vAsteroids[sizeof(vAsteroids)] = [
x: x, y: y,
dx: -(1.5 - rnd()*3.0), dy: -(1.5 - rnd()*3.0),
size: size, radius: radius,
shape: p, angle: rnd(360), rotSpeed: -(1.0 + rnd()*2.0)
]
endfunc
function SplitAsteroid(parent)
' Create 2 smaller rocks with added divergent speeds
GenerateAsteroid(parent.x, parent.y, parent.size - 1)
GenerateAsteroid(parent.x, parent.y, parent.size - 1)
vAsteroids[sizeof(vAsteroids)-1].dx = parent.dx + (rnd() - 0.5) * 2.0
vAsteroids[sizeof(vAsteroids)-1].dy = parent.dy + (rnd() - 0.5) * 2.0
vAsteroids[sizeof(vAsteroids)-2].dx = parent.dx - (rnd() - 0.5) * 2.0
vAsteroids[sizeof(vAsteroids)-2].dy = parent.dy - (rnd() - 0.5) * 2.0
endfunc
function CreateExplosion(x, y, count)
parts = []
for i = 1 to count
parts[sizeof(parts)] = [
x: x, y: y,
dx: (rnd() - 0.5) * 4.0,
dy: (rnd() - 0.5) * 4.0
]
next
vExplosions[sizeof(vExplosions)] = [particles: parts, life: 30]
endfunc
' ---- Render Workers ----
function DrawAsteroids()
set color 180, 180, 190
foreach ast in vAsteroids
draw poly xform ast.shape, ast.x, ast.y, 1.0, 1.0, rad(ast.angle), 0, 0, false
next
endfunc
function DrawLasers()
set color 0, 255, 255
foreach l in vLasers
draw pixel l.x, l.y
draw pixel l.x - l.dx*0.5, l.y - l.dy*0.5 ' Tail element effect
next
endfunc
function DrawExplosions()
foreach exp in vExplosions
' Fade alpha based on remaining lifetime
c = exp.life * 8
set color c, c / 2, 0
foreach p in exp.particles
draw pixel p.x, p.y
next
next
endfuncIt succeeded quite well.
Edit: And it did something that I never thought of. To be able to delete items from an array while iterating its elements, it does the iteration backwards. That way it can safely call "free key array, i" without messing up the loop. Maybe that's common practice and I've just been stupid

