Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Asteroids
#1
I gave Gemini this example to look at:

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
endfunc

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 Smile
Reply
#2
Thank you for sharing your insights on how to use AI effectively—training it first and then asking it to generate the code.

By the way, when you mentioned iterating backwards, were you referring to the backward iteration in the `UpdateAsteroids` and `UpdateExplosions` functions?
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)