Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --# Main
- -- Bouncing Demos by Ignatz
- --These demos show how to bounce a ball round the screen, from very simple to using the physics engine
- --You can use them as templates for your own projects
- --Just run this, and press the buttons at upper left to see the various demos
- --Simple = Demo_1
- --Friction = Demo_2
- --Physics = Demo_3
- --Physics rotation = Demo_4
- --How to use the demos in your own projects
- --Each demo tab is completely self contained, but is set up as a class to make managing all of them easier.
- --To change any of them from a class to a main program, copy the code from the tab you want, into an
- --empty project and remove the first line saying Bounce_X =class()
- --remove the class prefixes in front of all the function names, so everywhere you (say) see
- --Bounce_2:somefunction(), change it to somefunction()
- --However, if you do want to use the demos in a class the way they are, you should probably prefix all
- --the variables with self. so they aren't global variables.
- --The code below manages all the demos and isn't part of them.
- function setup()
- choices={"Simple","Friction","Physics","Physics Rotation"}
- classes={Bounce_1(),Bounce_2(),Bounce_3(),Bounce_4()}
- callbacks={bounce1}
- for i=1,#choices do
- parameter.action(choices[i],function(n) Select(n) end)
- end
- currSel=""
- Select("Simple")
- end
- function draw()
- b:draw()
- end
- --this function changes between demos, setting up the new choice
- function Select(btn)
- if string.find(currSel,"Physics")~=nil then b:cleanup() end
- --setup new choice
- for i=1,#choices do
- if btn==choices[i] then
- b=classes[i]
- b:setup()
- currSel=btn
- return
- end
- end
- end
- --this function only applies to demos which use physics
- --it tells the demo which objects collided
- function collide(contact)
- b:collide(contact)
- end
- --# Bounce_1
- Bounce_1=class()
- --[[
- A simple bouncing object
- The code below makes a red ball and/or an image bounce around the walls endlessly.
- It isn't difficult to do, as long as you change direction when you get close to a wall
- You will see an image and a red ball bouncing together when you run this. They have
- been included to show you how to do both types. Just delete the one you don't want
- (the code is all marked to help you).
- --]]
- function Bounce_1:setup()
- x=200 --starting x
- y=250 --starting y
- dx=3 --the amount x changes
- dy=2 --the amount y changes
- --if you want to draw a ball, use this ---------
- d=60 --diameter of ball
- --if you prefer to use an image, use this instead--------
- --change the image by pressing on the name in brackets (try to pick a roughly circular one)
- img=readImage("Tyrian Remastered:Mine Spiked Huge")
- d=(img.width+img.height)/2 --use average of width and height as diameter
- output.clear()
- print("This is a simple bouncing demo")
- print("a ball and an image bounce forever")
- print("These are the two main things you will use for bouncing")
- print("They bounce together just to keep the code very simple for you to follow")
- end
- function Bounce_1:draw()
- --update x and y positions
- x=x+dx
- y=y+dy
- --set up screen and color
- background(200,200,200,255)
- --this chunk draws the ball --
- pushStyle() --see comment at very bottom
- fill(255,0,0,255)
- ellipse(x,y,d)
- popStyle()
- -------------------------------
- --this chunk draws an image ---
- sprite(img,x,y)
- -------------------------------
- --change direction if we hit a wall
- r=d/2 --how close the centre of the ball can get to a wall before bouncing
- if x>WIDTH-r or x<r then dx=-dx end --reverse x direction if we hit left or right wall
- if y>HEIGHT-r or y<r then dy=-dy end --reverse y direction if we hit top or bottom wall
- end
- -- pushStyle and popStyle --
- -- in some programming, we plonk an object on the screen, then start setting colour etc
- -- However, because Codea is refreshing the screen 60 times a second, nothing on the screen is permanent,
- -- and everything is just a drawing.
- -- Actually, it's more like real life. If you paint, you select a brush and mix a palette, and then you
- -- paint on the canvas. No matter what you paint, your brush size and your colours will stay the same
- -- until you change them.
- -- Codea works like this too. You set the colour, brush size, whatever, then you draw on the screen. Those
- -- settings will stay there for the next thing you draw.
- -- Which can make a mess! So Codea provides pushStyle, which stores current settings safely, and popStyle,
- -- whch brings them back when you're done messing around, so you don't mess things up for anything else
- -- you're drawing. So whenever changing colours, styles, etc, wrap your changes between pushStyle and
- -- popStyle.
- --# Bounce_2
- Bounce_2=class()
- --[[
- A simple bouncing object that slows down
- The code below makes a red ball and/or an image bounce around the walls, slowing down with friction and
- the effect of impacts.
- Bouncing isn't difficult to do, as long as you change direction when you get close to a wall. Friction
- and impacts require trial and error to get them looking realistic, and you can get your object stuck in
- a wall if you aren't careful. If objects collide it starts getting hard.
- You will see an image and a red ball bouncing together when you run this. Just delete the
- one you don't want (the code is all marked to help you).
- --]]
- function Bounce_2:setup()
- x=200 --starting x
- y=250 --starting y
- dx=3 --the amount x changes
- dy=2 --the amount y changes
- impact=0.9 --speed is multiplied by this on impact
- friction=0.999 --speed is multiplied by this on each draw
- stop=2 --stop if speed is below this level, so it doesn't go on forever getting tinier
- --if you want to draw a ball, use this ---------
- d=60 --diameter of ball
- --if you prefer to use an image, use this instead--------
- --change the image by pressing on the name in brackets (try to pick a roughly circular one)
- img=readImage("Tyrian Remastered:Mine Spiked Huge")
- d=(img.width+img.height)/2 --use average of width and height as diameter
- output.clear()
- print("The ball and image slow down and stop, due to impacts and friction. At this stage, we are managing all of this ourselves.")
- end
- function Bounce_2:draw()
- --update x and y positions and speed
- dx=dx*friction
- dy=dy*friction
- if math.abs(dx)+math.abs(dy)<stop then dx=0 dy=0 end
- x=x+dx
- y=y+dy
- --set up screen and color
- background(200,200,200,255)
- --this chunk draws the ball --
- pushStyle() --see comment at foot of Bounce_1
- fill(255,0,0,255)
- ellipse(x,y,d)
- popStyle()
- -------------------------------
- --this chunk draws an image ---
- sprite(img,x,y)
- -------------------------------
- --change direction if we hit a wall
- r=d/2 --how close the centre of the ball can get to a wall before bouncing
- --check for impact, if so, adjust speed for impact and reverse direction
- if x>WIDTH-r or x<r then dx=-dx*impact dy=dy*impact end --reverse x direction if we hit left or right wall
- if y>HEIGHT-r or y<r then dx=dx*impact dy=-dy*impact end --reverse y direction if we hit top or bottom wall
- end
- --# Bounce_3
- Bounce_3=class()
- --[[
- Bouncing with physics
- The code below makes a red ball and an image bounce around the walls, using the Codea physics engine.
- Some of the code is adapted from an example by Dalorbi.
- --]]
- function Bounce_3:setup()
- --create objects
- --we'll create a table of them simply to make it easy to destroy them later (see cleanup function at bottom)
- --They are unlike circles and images, which only exist if you draw them - instead, physics objects stay
- --alive until you actually destroy them, and they will interact with other physics objects
- --The added problem is they are invisible, so if you leave any lying around without something
- --visible attached, you're likely to collide with them
- bodies={}
- --first the ball
- ball_diam=60 --diameter of ball
- --now create the physics object that behaves like a real ball, it will tell us where to draw our ball
- --think of it as a GPS navigator that guides us
- p_ball = physics.body(CIRCLE,ball_diam/2) --physics bodies use radius not diameter
- p_ball.x = math.random(60,250) -- choose a random position between 30 and the screen width minus 30
- p_ball.y = math.random(60,250) -- same for the y position
- p_ball.gravityScale = 0 -- no gravity - if there was, the ball would fall to the bottom of screen
- p_ball.restitution = 1 -- this circle is bouncy
- p_ball.friction = 0.1 -- the amount of friction to be applied to the circle
- p_ball.linearVelocity = vec2(math.random(400),math.random(400)) --velocity (pixels per second = 60 redraws)
- p_ball.info="ball" --so when collisions occur, we can figure out which object was involved
- table.insert(bodies,p_ball) --keep track of body so we can destroy it later if we want
- --now much the same for the image
- img=readImage("Tyrian Remastered:Mine Spiked Huge")
- img_diam=(img.width+img.height)/2 --use average of width and height as diameter
- --create the physics object
- p_img = physics.body(CIRCLE,img_diam/2) --physics bodies use radius not diameter
- p_img.x = math.random(60,250) -- choose a random position
- p_img.y = math.random(60,250) -- same for the y position
- p_img.gravityScale = 0 -- no gravity
- p_img.restitution = 0.8 -- this image is not so bouncy
- p_img.friction = 0.4 -- the amount of friction to be applied to the image
- p_img.linearVelocity = vec2(math.random(400),math.random(400)) -- velocity
- p_img.info="mine" --so when collisions occur, we can figure out which object was involved
- table.insert(bodies,p_img) --keep track of body so we can destroy it later if we want
- --finally the walls
- Bounce_3:CreateWalls()
- output.clear()
- print("The physics engine handles friction, bouncing and collisions")
- end
- --create the walls - physics objects can only bounce off each other
- --the first four parameters are the starting x,y and ending x,y
- --the fifth parameter is restitution, or bounciness, from 0=no bounce to 1=very bouncy
- function Bounce_3:CreateWalls()
- leftWall = Bounce_3:CreateWall(1,1,1,HEIGHT-1,1.0)
- rightWall = Bounce_3:CreateWall(WIDTH-1,0,WIDTH-1,HEIGHT-1,0.9)
- bottomWall = Bounce_3:CreateWall(1,1,WIDTH-1,1,0.2)
- topWall = Bounce_3:CreateWall(1,HEIGHT-1,WIDTH-1,HEIGHT-1,0.7)
- end
- --this function creates one wall (actually just a line)
- function Bounce_3:CreateWall(x,y,x1,y1,r)
- local w = physics.body(EDGE,vec2(x,y),vec2(x1,y1)) -- vec2
- w.restitution=r --see comment above
- table.insert(bodies,w) --keep track of body so we can destroy it later if we want
- return w
- end
- function Bounce_3:draw()
- background(200,200,200,255)
- --draw the ball --
- pushStyle() --see comment at foot of Bounce_1
- fill(255,0,0,255)
- ellipse(p_ball.x,p_ball.y,ball_diam)
- popStyle()
- -------------------------------
- --draw image ---
- sprite(img,p_img.x,p_img.y)
- -------------------------------
- end
- --the function to be called when two physics bodies collide
- --we are told which bodies (including walls etc) have collided
- --contactA and contactB are the two bodies
- function Bounce_3:collide(contact)
- if contact.state == BEGAN then
- if contact.bodyA.info=="ball" or contact.bodyB.info=="ball" then sound(SOUND_JUMP, 50) end
- if contact.bodyA.info=="mine" or contact.bodyB.info=="mine" then sound(SOUND_EXPLODE, 50) end
- end
- end
- --destroy all bodies when we are done, we have to keep track of the, ourselves, hence the table
- function Bounce_3:cleanup()
- for i,bb in ipairs(bodies) do
- bb:destroy()
- end
- end
- --# Bounce_4
- Bounce_4=class()
- --[[
- Bouncing - and rotating - with physics
- The code below makes a red rectangle and an image bounce around the walls, using the Codea physics engine.
- Both of them rotate as they bounce.
- --]]
- function Bounce_4:setup()
- --create objects
- --we'll create a table of them simply to make it easy to destroy them later (see cleanup function at bottom)
- --They are unlike circles and images, which only exist if you draw them - instead, physics objects stay
- --alive until you actually destroy them, and they will interact with other physics objects
- --The added problem is they are invisible, so if you leave any lying around without something
- --visible attached, you're likely to collide with them
- bodies={}
- --first the rectangle
- rect_width=100 --size of rectangle
- rect_height=50
- --now create the physics object that behaves like a real block, it will tell us where to draw our rectangle
- --think of it as a GPS navigator that guides us
- p_rect = physics.body(POLYGON,
- vec2(-rect_width / 2, -rect_height / 2),
- vec2(-rect_width / 2, rect_height / 2),
- vec2(rect_width / 2, rect_height / 2),
- vec2(rect_width / 2, -rect_height / 2)
- )
- p_rect.x = math.random(60,250) -- choose a random position between 30 and the screen width minus 30
- p_rect.y = math.random(60,250) -- same for the y position
- p_rect.angle=math.random(0,360) -- and rotation
- p_rect.gravityScale = 0 -- no gravity - if there was, the ball would fall to the bottom of screen
- p_rect.restitution = 1 -- this circle is bouncy
- p_rect.friction = 0.1 -- the amount of friction to be applied to the circle
- p_rect.linearVelocity = vec2(100+math.random(400),100+math.random(400)) --velocity (pixels per second = 60 redraws)
- table.insert(bodies,p_rect)
- --p_rect.linearDamping = 0.2
- --p_rect.angularDamping = 0.2
- p_rect.info="rect" --so when collisions occur, we can figure out which object was involved
- --now much the same for the image
- img=readImage("Tyrian Remastered:Mine Spiked Huge")
- img_diam=(img.width+img.height)/2 --use average of width and height as diameter
- --create the physics object
- p_img = physics.body(CIRCLE,img_diam/2) --physics bodies use radius not diameter
- p_img.x = math.random(60,250) -- choose a random position
- p_img.y = math.random(60,250) -- same for the y position
- p_img.angle=math.random(0,360)
- p_img.gravityScale = 0 -- no gravity
- p_img.restitution = 0.8 -- this image is not so bouncy
- p_img.friction = 0.4 -- the amount of friction to be applied to the image
- p_img.linearVelocity = vec2(math.random(400),math.random(400)) -- velocity
- p_img.info="mine" --so when collisions occur, we can figure out which object was involved
- table.insert(bodies,p_img)
- --p_img.linearDamping = 0.9
- --p_img.angularDamping = 0.9
- --finally the walls
- Bounce_4:CreateWalls()
- output.clear()
- print("Watch how the rectangle and")
- print("image rotate as they bounce")
- end
- --create the walls - physics objects can only bounce off each other
- --the first four parameters are the starting x,y and ending x,y
- --the fifth parameter is restitution, or bounciness, from 0=no bounce to 1=very bouncy
- function Bounce_4:CreateWalls()
- leftWall = Bounce_3:CreateWall(1,1,1,HEIGHT-1,1.0)
- rightWall = Bounce_3:CreateWall(WIDTH-1,0,WIDTH-1,HEIGHT-1,0.9)
- bottomWall = Bounce_3:CreateWall(1,1,WIDTH-1,1,0.2)
- topWall = Bounce_3:CreateWall(1,HEIGHT-1,WIDTH-1,HEIGHT-1,0.7)
- end
- --this function creates one wall (actually just a line)
- function Bounce_4:CreateWall(x,y,x1,y1,r)
- local w = physics.body(EDGE,vec2(x,y),vec2(x1,y1)) -- vec2
- w.restitution=r --see comment above
- table.insert(bodies,w) --keep track of body so we can destroy it later if we want
- return w
- end
- function Bounce_4:draw()
- background(200,200,200,255)
- --draw the rectangle --
- pushStyle() --see comment at foot of Bounce_1
- fill(255,0,0,255)
- --see explanation of next few lines at bottom below
- pushMatrix()
- translate(p_rect.x, p_rect.y)
- rotate(p_rect.angle)
- rect(-rect_width / 2, -rect_height / 2, rect_width, rect_height)
- popMatrix()
- popStyle()
- -------------------------------
- --draw image ---
- --see explanation of next few lines at bottom below
- pushMatrix()
- translate(p_img.x, p_img.y)
- rotate(p_img.angle)
- sprite(img,0,0)
- popMatrix()
- -------------------------------
- end
- --the function to be called when two physics bodies collide
- --we are told which bodies (including walls etc) have collided
- --contactA and contactB are the two bodies
- function Bounce_4:collide(contact)
- if contact.state == BEGAN then
- if contact.bodyA.info=="rect" or contact.bodyB.info=="rect" then sound(SOUND_JUMP, 50) end
- if contact.bodyA.info=="mine" or contact.bodyB.info=="mine" then sound(SOUND_EXPLODE, 50) end
- end
- end
- function Bounce_4:cleanup()
- for i,bb in ipairs(bodies) do
- bb:destroy()
- end
- end
- --Drawing rotating physics objects
- --Suppose you had to draw a little shape all over a piece of paper, at different angles
- --The hard way is to keep the paper as is, and start having to lean all oer the place to draw sideways over
- --her, and upside down over there
- --The sensible approach is to swivel and move the paper so that you can draw each shape the right way up,
- --right in front of you. And Codea finds that the best way, too. Let's look at an example from above.
- --[[
- pushMatrix() --before we go swivelling the paper, let's remember how it was, so we can put it back later
- translate(x, y) -- move the place we want draw under our pen, so that the point x,y is now treated as 0,0
- -- this means if you now draw at 40,30, Codea will actually draw at x+40,y+30
- rotate(p_rect.angle) --rotate our whole screen by whatever angle our physics object is at
- -- this is like turning your paper round so you can draw the image the right way up
- rect(-rect_width / 2, -rect_height / 2, rect_width, rect_height) --draw our rectangle
- --note it is drawn the right way up, but Codea has the screen at an angle, so the final
- --result will be an angled rectangle
- --note also the centre of the rectangle is at 0,0, because we've moved to the exact
- --spot where we want to draw it. So the first two parameters x and y are set to a
- --point half of the width to the left, and half of the height below.
- popMatrix() --put everything back the way it was
- --]]
Add Comment
Please, Sign In to add comment