This guide shows you how to replace the procedural graphics with image sprites for the spaceship, bullets, and other game objects.
- PNG (with transparency support)
- JPG (for backgrounds without transparency)
- Spaceship: 50x50 pixels to 100x100 pixels
- Bullets: 8x16 pixels to 16x32 pixels
- Enemies: 40x40 pixels to 80x80 pixels
- Background: 800x600 pixels (or larger for tiling)
Put all image files in the assets/ directory:
assets/
├── spaceship.png
├── bullet.png
├── enemy1.png
├── enemy2.png
├── background.png
└── explosion.png
Add this section near the top of main.lua, after the initial variables:
-- Images
local images = {
player = nil,
bullet = nil,
enemy = nil,
background = nil
}
-- Load images in love.load()
function love.load()
love.window.setTitle("Space Shooter - Lua/LOVE2D Example")
love.graphics.setBackgroundColor(0.02, 0.02, 0.08)
math.randomseed(os.time())
initStars()
-- Load image files (will fallback to procedural if not found)
loadImages()
end
function loadImages()
-- Try to load images, use pcall to handle missing files gracefully
local success, img
success, img = pcall(love.graphics.newImage, "assets/spaceship.png")
if success then
images.player = img
print("Loaded: spaceship.png")
end
success, img = pcall(love.graphics.newImage, "assets/bullet.png")
if success then
images.bullet = img
print("Loaded: bullet.png")
end
success, img = pcall(love.graphics.newImage, "assets/enemy.png")
if success then
images.enemy = img
print("Loaded: enemy.png")
end
success, img = pcall(love.graphics.newImage, "assets/background.png")
if success then
images.background = img
print("Loaded: background.png")
end
end-- Draw player ship (with image or procedural fallback)
local function drawPlayer()
local x, y = player.x, player.y
local w, h = player.width, player.height
if images.player then
-- Draw the spaceship image
love.graphics.setColor(1, 1, 1, 1)
local img_w = images.player:getWidth()
local img_h = images.player:getHeight()
local scale_x = w / img_w
local scale_y = h / img_h
love.graphics.draw(
images.player,
x, y,
0, -- rotation
scale_x, scale_y,
img_w/2, img_h/2 -- origin (center)
)
else
-- Fallback to procedural graphics (existing code)
-- Glow effect
for i = 15, 1, -3 do
local alpha = 0.1 * (1 - i / 15)
love.graphics.setColor(player.color[1], player.color[2], player.color[3], alpha)
love.graphics.polygon("fill",
x, y - h/2 - i,
x - w/2 - i, y + h/2 + i,
x + w/2 + i, y + h/2 + i)
end
-- Main ship body
love.graphics.setColor(player.color[1], player.color[2], player.color[3], 1)
love.graphics.polygon("fill",
x, y - h/2,
x - w/2, y + h/2,
x + w/2, y + h/2)
-- Cockpit
love.graphics.setColor(0.1, 0.2, 0.3, 1)
love.graphics.polygon("fill",
x, y - h/4,
x - w/4, y + h/4,
x + w/4, y + h/4)
-- Engine glow
love.graphics.setColor(1, 0.5, 0.2, 0.8)
love.graphics.polygon("fill",
x - w/4, y + h/2,
x, y + h/2 + 15 + math.random(0, 5),
x + w/4, y + h/2)
end
endFind the bullet drawing section and replace it:
-- Draw bullets
for _, bullet in ipairs(bullets) do
if images.bullet then
-- Draw bullet image
love.graphics.setColor(1, 1, 1, 1)
local img_w = images.bullet:getWidth()
local img_h = images.bullet:getHeight()
local scale_x = bullet.width / img_w
local scale_y = bullet.height / img_h
love.graphics.draw(
images.bullet,
bullet.x, bullet.y,
0,
scale_x, scale_y,
img_w/2, img_h/2
)
else
-- Fallback to procedural bullet (existing code)
for i = 8, 1, -2 do
local alpha = 0.2 * (1 - i / 8)
love.graphics.setColor(bullet.color[1], bullet.color[2], bullet.color[3], alpha)
love.graphics.rectangle("fill",
bullet.x - bullet.width/2 - i,
bullet.y - bullet.height/2 - i,
bullet.width + i*2,
bullet.height + i*2)
end
love.graphics.setColor(bullet.color[1], bullet.color[2], bullet.color[3], 1)
love.graphics.rectangle("fill", bullet.x - bullet.width/2, bullet.y - bullet.height/2, bullet.width, bullet.height)
end
endFind the enemy drawing section and replace it:
-- Draw enemies
for _, enemy in ipairs(enemies) do
if images.enemy then
-- Draw enemy image
love.graphics.setColor(1, 1, 1, 1)
local img_w = images.enemy:getWidth()
local img_h = images.enemy:getHeight()
local scale_x = enemy.width / img_w
local scale_y = enemy.height / img_h
love.graphics.draw(
images.enemy,
enemy.x, enemy.y,
0,
scale_x, scale_y,
img_w/2, img_h/2
)
else
-- Fallback to procedural (existing code)
drawGlowingRect(enemy.x, enemy.y, enemy.width, enemy.height, enemy.color)
end
endIn love.draw(), add at the very beginning:
function love.draw()
-- Draw background image if available
if images.background then
love.graphics.setColor(1, 1, 1, 0.5) -- Semi-transparent
love.graphics.draw(images.background, 0, 0)
end
-- Draw stars (existing code)
for _, star in ipairs(stars) do
love.graphics.setColor(1, 1, 1, star.brightness)
love.graphics.circle("fill", star.x, star.y, star.size)
end
-- ... rest of the draw code
endOnline Sprite Editor (No Installation Required):
- XcaliburMoon Sprite Paint Tool: https://xcm-sandbox.tech/sprite-paint-tool/
- Free browser-based sprite editor developed by XcaliburMoon
- Perfect for creating game sprites
- No software installation needed
- Export as PNG
Desktop Image Editors:
- GIMP (free, cross-platform)
- Photoshop
- Aseprite (pixel art)
- Krita (free)
- Paint.NET (Windows)
Download free game sprites from:
- OpenGameArt.org
- itch.io (free assets section)
- Kenney.nl (free game assets)
- Craftpix.net (some free assets)
Use AI tools to generate sprites:
- DALL-E
- Midjourney
- Stable Diffusion
Here's a complete modification you can add to main.lua:
-- Add after the initial variables section
local images = {}
-- Modify love.load()
function love.load()
love.window.setTitle("Space Shooter - Lua/LOVE2D Example")
love.graphics.setBackgroundColor(0.02, 0.02, 0.08)
math.randomseed(os.time())
initStars()
-- Load images
images.player = loadImage("assets/spaceship.png")
images.bullet = loadImage("assets/bullet.png")
images.enemy = loadImage("assets/enemy.png")
images.background = loadImage("assets/background.png")
end
-- Helper function to safely load images
function loadImage(path)
local success, img = pcall(love.graphics.newImage, path)
if success then
print("Loaded: " .. path)
return img
else
print("Could not load: " .. path .. " (using procedural graphics)")
return nil
end
endThe love.graphics.draw() function parameters:
love.graphics.draw(
image, -- The image object
x, y, -- Position (center if origin is set)
rotation, -- Rotation in radians (0 = no rotation)
scale_x, -- Horizontal scale (1 = original size)
scale_y, -- Vertical scale (1 = original size)
origin_x, -- X offset for rotation/scaling center
origin_y -- Y offset for rotation/scaling center
)- Use Transparent PNGs: Save images with transparent backgrounds for best results
- Consistent Art Style: Keep all sprites in the same art style (pixel art, vector, realistic, etc.)
- Power of 2 Sizes: Use image dimensions that are powers of 2 (32, 64, 128, 256) for better performance
- Sprite Sheets: For animations, use sprite sheets and extract frames
- Test Without Images: The code includes fallbacks so the game works with or without images
- Place an image in the
assets/folder - Run the game with
love .or./start.sh - Check console output to see which images loaded successfully
- If an image doesn't load, the game will use procedural graphics as fallback
- Add rotation to bullets: Change rotation parameter from
0tomath.pi/2for vertical bullets - Add engine fire animation behind the spaceship
- Create explosion sprite sheets for better explosion effects
- Add parallax background layers with multiple images