-- Lesson 25: Particles. The finished script, exactly as the lesson ends. dofile("Singe/Framework.singe") local SHIP_WIDTH = 32 local SHIP_HEIGHT = 24 local SHIP_SPEED = 120 local RESPAWN_MS = 1400 local shipSprite = spriteLoad(DIR .. "art/ship.png") local sparkSprite = spriteLoad(DIR .. "art/star.png") local boomSound = soundLoad(DIR .. "art/boom.wav") local ground = overlayGetHeight() - 20 local shipX = (overlayGetWidth() - SHIP_WIDTH) / 2 local shipY = overlayGetHeight() - 56 local flying = true local movingLeft = false local movingRight = false local lastTicks = singeGetTicks() local exhaust = emitterNew() emitterSetBlend(exhaust, PARTICLE_ADD) emitterSetRate(exhaust, 90) emitterSetLife(exhaust, 0.15, 0.40) emitterSetDirection(exhaust, 0, 1) emitterSetSpread(exhaust, 12) emitterSetSpeed(exhaust, 40, 90) emitterSetSize(exhaust, 7, 1) emitterSetColor(exhaust, 255, 240, 180, 255, 255, 60, 0, 0) emitterSetMax(exhaust, 120) emitterStart(exhaust) local boom = emitterNew() emitterSetTexture(boom, sparkSprite) emitterSetBlend(boom, PARTICLE_ADD) emitterSetLife(boom, 0.4, 1.1) emitterSetSpeed(boom, 40, 220) emitterSetSpread(boom, 180) emitterSetGravity(boom, 0, 160) emitterSetDrag(boom, 0.9) emitterSetSize(boom, 10, 2, 0.4) emitterSetSpin(boom, -240, 240) emitterSetColor(boom, 255, 255, 220, 255, 255, 70, 20, 0) emitterSetCollide(boom, COLLIDE_FLOOR, 0.35, 0.3, ground) emitterSetTrail(boom, 4, 2) emitterSetMax(boom, 400) function explode() if not flying then return end flying = false emitterStop(exhaust) emitterSetPosition(boom, shipX + SHIP_WIDTH / 2, shipY + SHIP_HEIGHT / 2) emitterBurst(boom, 140) soundPlay(boomSound) timerAfter(RESPAWN_MS, function() flying = true emitterStart(exhaust) end) end function onInputPressed(what) if what == SWITCH_LEFT then movingLeft = true elseif what == SWITCH_RIGHT then movingRight = true elseif what == SWITCH_BUTTON1 then explode() end end function onInputReleased(what) if what == SWITCH_LEFT then movingLeft = false elseif what == SWITCH_RIGHT then movingRight = false end end function onOverlayUpdate() local now = singeGetTicks() local seconds = (now - lastTicks) / 1000 lastTicks = now if flying then if movingLeft then shipX = shipX - SHIP_SPEED * seconds end if movingRight then shipX = shipX + SHIP_SPEED * seconds end if shipX < 0 then shipX = 0 end if shipX > overlayGetWidth() - SHIP_WIDTH then shipX = overlayGetWidth() - SHIP_WIDTH end emitterSetPosition(exhaust, shipX + SHIP_WIDTH / 2, shipY + SHIP_HEIGHT - 2) end overlayClear() if flying then spriteDraw(shipSprite, shipX, shipY) end emitterDraw(exhaust) emitterDraw(boom) overlayPrint(2, 2, "Left and right to fly. Button 1 to blow up.") overlayPrint(2, 4, "Particles alive: " .. (emitterGetCount(exhaust) + emitterGetCount(boom))) return OVERLAY_UPDATED end