# Physics with an image!

I had an idea of creating an old tanks game using destructable terrain, one using an image, the other a polygon of vertices. Here is the concept of using an image and getting pixels to recreate a physics ball, on of the more simpler body shapes.

``````
-- destructable img

-- Use this function to perform your initial setup
function setup()
img = image(WIDTH,HEIGHT)
setContext(img)
background(40,40,50)
pushStyle()
fill(150,150,150,255)
rect(0,0,WIDTH,HEIGHT/2)
popStyle()
setContext()
ply = vec2(WIDTH/2,HEIGHT-350)
vel = vec2()
r,g,b,a = 40,40,50,255
holding = false
parameter.action("Restart",Clear)
end

function touched(t)
if t.state == BEGAN and vec2(t.x,t.y):dist(ply)>30 then
r,g,b,a = img:get(t.x,t.y)
elseif t.state == BEGAN and vec2(t.x,t.y):dist(ply)<30 then
holding = true
end
if holding == false then
setContext(img)
pushStyle()
stroke(r,g,b,a)
strokeWidth(50)
line(t.x,t.y,t.prevX,t.prevY)
fill(r,g,b,a)
strokeWidth(0)
ellipse(t.x,t.y,50)
popStyle()
setContext()
else
ply = vec2(t.x,t.y)
vel = vec2()
end
if t.state == ENDED then
if holding then holding = false end
end
end
function Drag(mlt)
if mlt > 1 then
vel = vel-vec2(vel.x,vel.y)/(50*mlt)
end
end
function Clear()
setContext(img)
background(40,40,50)
pushStyle()
fill(150,150,150,255)
rect(0,0,WIDTH,HEIGHT/2)
popStyle()
setContext()
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50,255)

-- This sets the line thickness
strokeWidth(5)

sprite(img,WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
sprite("Documents:circle",ply.x,ply.y,20,20)
local nply = ply
local amnt = 200
local normal = vec2()
local n = 0
local impulse = 0
local d = false
for x=1,20 do
for y=1,20 do
local r,g,b,a = img:get(ply.x-10+x,ply.y-10+y)
if color(r,g,b,255) == color(150,150,150,255) then
local ov = vel
--Drag(vec2(-10+x,-10+y):dist(vec2())*5)
vel = vel + (vec2()-vec2(-10+x,-10+y))/amnt
normal = normal + (vec2()-vec2(-10+x,-10+y))
impulse = 10-vec2(-10+x,-10+y):dist(vec2())
nply = nply + -((vec2(-10+x,-10+y))/450)*impulse
n = n + 1
d = true
end
end
end
end
normal = normal/n
if n>0 then
vel = vel -vec2(vel.x*n,vel.y*n)*0.0001
ply = nply
end
vel = vel + vec2(0,-0.1)

ply = ply + vec2(vel.x,vel.y)
end
``````

I’ve also been thinking about doing a Scorched Earth style tank game; doing sand and destroyable terrain really requires having the ability to peek at the frame buffer.

In the past, I wrote a Similar game for QuickBasic.

The trick was to basically scan each column, from the bottom up, looking at any pixel filled with the “dirt” color. Then look at the pixel underneath. If the pixel underneath was empty, move the pixel down. Then you scan downward from each tank’s base and figure out how far each tank falls.

Let me see if I can work out a little “collapsing terrain” demo. It looks like image.get is the method I need…

Hey welcome to the forum, I know about the collapsing terrain but that would be very performance heavy I think, maybe possible with a shader for better results… The scorched earth is the style I was basing my ideas round but I didn’t think the collapsing part would help as I’m already looping through 305 pixels in the ball.

@tomxp411 - I think you’ll find image.get too slow, if you’re scanning hundreds of pixels per redraw.

What might work better is to use the Minecraft approach and maybe use chunks of pixels, eg 2x2.

Also, Lua is optimised for tables, so if you keep a map of your terrain in memory, it would be fastest to figure out the collapsing by looping through a table, then you could use the results to draw the columns as vertical lines, which is faster than setting individual pixels.

Here is an earlier post when I was trying to do the same for a lemmings type game. I quickly found that a single large image was still too small for my requirements of a big scrollable image so I broke the image into tiles. The code in this discussion deals with this and though adds a sprite instead of removing parts, the principle should be similar

http://twolivesleft.com/Codea/Talk/discussion/1661/creating-a-large-scrollable-image#Item_25

This was where I was thinking towards when I started this one:

http://twolivesleft.com/Codea/Talk/discussion/2077/drop-2000-squares-into-a-pile-at-30-fps#Item_1

I freeze the physics objects when they stop moving to get performance, but my thought was if you destroy an area you could unfreeze the physics objects near it and let them recollapse. Even though the objects are squares which give pleasing bounce/roll effect, you could then draw them as a sprite to make it more “realistic”

very impresive!!

Thanks, Ignatz.

I actually worked up a prototype last night on my Mini,and it’s not that bad. I used a radius of 25 pixels for my “exploded” area, and I am only scanning the area impacted by the explosion. The lag between the end of the explosion and the drop is imperceptible.

Anyway… I’m going to play with this some more. Scorched Earth was a fun game back in the day, and Codea kind of makes me want to write a clone.

I’ll paste some sample code in a follow-up post from the iPad. By golly, I hate that Apple won’t let you export code from the program. Sometimes, the app store rules just leave me truly baffled.

I’ll keep you guys posted on the WIP of “Tanks.” This should be fun.

So here is my prototype. Note that this is just a tech demo, so I didn’t break stuff out in to classes or do things like check/lock the screen orientation… Or even check bounds on my drawing routine. This does demonstrate collapsible terrain, so here goes…

``````-- Test1

-- Use this function to perform your initial setup
function setup()
terrainColor=color(174, 174, 174, 255)
skyColor=color(130,170,255)
testColor=color(255,255,255)
fillTerrain()

explosionX=-1
explosionY=-1

parameter.action("fillTerrain",fillTerrain)
end

function touched(touch)
if CurrentTouch.state==ENDED then
print("touched " .. CurrentTouch.x .. "," .. CurrentTouch.y)
setExplosion(CurrentTouch.x,CurrentTouch.y,25)
end
end

function draw()
strokeWidth(2)
stroke(255)
fill(0)
background(skyColor)

drawTerrain()
stroke(255,255,0)
noFill()
setContext()

dropTerrain(explosionX,explosionY,25)
end
end
end

explosionX=x
explosionY=y
end

function drawTerrain()
spriteMode(CORNER)
sprite(terrain,0,0)
end

function fillTerrain()
print("Filling Terrain")
terrain=image(WIDTH,HEIGHT)
setContext(terrain)
rectMode(CORNER)
noStroke()
fill(skyColor)
rect(0,0,terrain.width,terrain.height)
fill(terrainColor)
rect(0,0,terrain.width,terrain.height-300)
setContext()
end

setContext(terrain)
noSmooth()
noStroke()
fill(skyColor)
setContext()
end

setContext(terrain)
-- get bottom of opening
bottom=centerY
bottom = bottom - 1
if getColor(terrain,x,bottom) == terrainColor then
break
end
end
--terrain:set(x,bottom,testColor)

top=centerY
top = top + 1
if getColor(terrain,x,top) == terrainColor then
break
end
end
if top > bottom then
slice=terrain:copy(x,top,2,terrain.height-top)
spriteMode(CORNER)
sprite(slice,x,bottom)
end
end
setContext()
end

function getColor(img,x,y)
r,g,b,a=img:get(x,y)
return color(r,g,b,a)
end
``````

Nice one@tomxp411

thanks. =)

I’ll post a new thread when I have a playable demo. I don’t want to hijack Luatee’s thread too far off course.