(train whistle sound)
- Hello, welcome to a coding challenge, Angry Birds.
Although, my birds won't be angry,
they're going to be loving loving birds.
But maybe they won't even be birds,
they'll be like cute little Coding
Train characters, but that's not the point.
I am going to program a version,
a much simpler simplified version
of an Angry Bird style clone.
I'm going to use p5.js, I'm going to use a physics
library called matter.js, and I'm going to
get started in one moment.
But first (laughs) let me diagram out what I need.
So, I'm going to use an object-oriented programing approach.
I'm going to need something called like a box.
So, this will be a box class.
I'm going to need something like a bird,
we'll just call it a bird for right now.
And I also need,
the ground.
So, I'm going to start my simplified Angry Birds,
it's going to have a single box, a single bird.
The box is sitting on the ground.
I'm going to want to toss the bird at the box
and knock it over.
And from there, the glorious games
throughout the universe that you will make
maybe will follow.
This is the p5 web editor, I'm going to use p5
for all of the drawing stuff,
and I'm going to use the physics library matter.js
for handling all of the physics.
Now, matter.js does have rendering built into it
but I'm going to do things my sort of way
of combining both libraries
so that I can do all the rendering custom in p5,
and maybe by the end of this video,
have some of my Coding Train characters
inside of this little game that we make.
Alright, so, first I want to take
an object-oriented approach
and I'm going to do Add File, and I want to add,
I need a bird.js, and I'm going to make
something called a box.js.
And I think I'm going to be able to use
the box for both.
I'm going to use the box class for both
this thing that can actually get knocked over,
and the ground, which needs
to be something immobile, static.
So, what does a box need to have?
It needs to have an x, it needs to have a y,
it needs to have a width, and it needs to have a height.
And I'm going to require that all of those arguments
are passed in, via the constructor.
Then I'm going to, oh, and so I need
to put the arguments in here, x, y, w, h,
and I need to, what do I need to do?
I'm going to write a show function,
and in here, I'm just going to say,
I'm going to use fill to make it white
and I'm going to say rectangle this.x,
this.y, this.w, this.h.
Okay, so, this is the basic idea of a box class,
with no physics, this is just the data
about a box and this is me drawing it.
So, now, in the main sketch, I'm going to say,
let ground, I'm going to have a global variable called ground.
I'm going to say ground equals a new Box,
and it's going to be, the x is going to be at zero,
the y is going to be at like height minus 20,
and the width will be the full width of the window,
and the height will be 20.
And then I'm going to say ground.show.
Now, it's giving me all sorts of errors
like it has no idea what a box is,
and the reason why it has no idea what a box is,
is because even though I added a new JavaScript file,
I didn't add it to my index.html.
So, let me go and add it to index.html, box.js.
And there we go look.
(bell ringing)
Step one is done.
I have the ground.
The ground is there.
Now, the next thing I'm going to do,
is I'm going to have a box.
I'm going to just call it a box.
A box is another new Box,
and let's put it over to the side
in some arbitrary place.
And say box.show, there it is.
I want it to be tall.
I don't know what I'm doing exactly yet,
but something like this, there we go.
Okay, so that's the thing that I need to throw my bird at.
Now, I need another class.
I'm going to do Add File, and I'm going to call this bird,
oh, look when did I?
It like knows what I'm going to do in advance,
isn't that crazy?
I think I've written other things
in the p5 editor with a bird.js.
bird.js, class Bird, and I'm just, you know,
I probably could maybe use inheritance here,
where I made some videos about recently,
but I'm just going to do like a sort
of horrible copy paste job.
But I'm going to change this to an r,
to indicate radius, because my bird
is going to be a circle, and this dot r.
And now I can say let bird, bird equals new Bird,
and it'll be at like 50 pixels over, 300 pixels down,
and with a radius of 25, and oh, doesn't know
what bird is yet again because
I now also need to add bird.js to my index.html file.
So, I've got the bird, I've got the box,
these are all the elements.
So, I have all the elements that I want in my scene.
Ultimately, I'm going to want to have like a stack of boxes
and use images to make this have more personality.
But the next thing that I need to do,
is add physics.
Now, I could use, you know, I could start doing,
adding some functions to do all the physics myself,
but I would like to use a physics engine.
The matter.js library is released through NPM,
node package manager.
So, I can go, and everything NPM,
it's already like appearing in my,
'cause I looked for it before I started this.
But if I just go to unpkg, unpackage
which is the content delivery network
for NPM packages, and do matter.js,
and hit Enter, we can see this is the URL
for the matter.js library.
I want to get the minified version of it.
So, I'm going to also add .min.js.
So, now I have this particular URL.
I can go back to the p5 web editor, index and html
and I can, I'm just going to like paste it here
for a second.
I'm going to grab one of these.
These are the script tags for the p5 library, right.
And so, instead of, I've got p5, p5 dom, p5 sound
and now I want to add matter.js as a library.
So, these are now all of my libraries,
and all of my custom JavaScript code.
And if I go back to sketch.js.
Let's make sure the matter dot library has loaded.
If I just say console log Matter.
We can see yes, stuff is coming out here.
The library is loading.
That would obviously say if I hadn't loaded that library,
I don't know what you're talking about.
So, I have a whole bunch of tutorials
about the matter.js library.
So, I don't need to spend.
I can refer you to those if you want more background.
But basically, I need to establish
this idea of an engine object,
and a world object.
The world is talking about the environment,
and then, each one of these things
will be a body.
This will be a rectangular body,
this will be a rectangular body,
and this will be a circular body.
So, my classes, box and bird,
I'm going to make them wrappers
to have inside of them, a piece of data
which refers to the actual matter.js body.
So, the first thing that I need to do,
I think is let's have a world and an engine.
And then I think I say engine equals Matter.
Well, I think I better do this first.
engine equals Matter.Engine.create,
I don't know, I'm guessing.
I think that's right, having done this before.
And then I think the world is actually
created when I create the engine,
I can just grab it from the world.
So, now I have the matter engine,
and the matter world.
Then inside of my objects, what I want to do,
let's just do the box first.
So, here instead of having an x, a y
and a width, and a height.
Although, I think I might keep
the width and the height just to store it.
I now want to add this.body equals Matter.Bodies.rectangle.
This is a function that in the matter library,
will create a rectangular body object for me.
And I can give it,
I'm going to do this first.
Like, I don't, this box object no longer is going
to have its own x and y, it's just going
to give the matter body, the x and the y.
So, I'm going to say x, y,
I think this is actually what it gets.
And then I need to say
Matter.World.add to the world, this.body.
So, I need to actually put it in the world.
So, what happened to the box?
Oh, oh, oh, I took out this.x.y,
so now, the whole point of this
is in show, I want to ask,
I want to say hey, Matter. (laughs)
I want to say give me a position
which is this.body's position.
And now, I'm going to draw the rectangle at pos.x, and pos.y.
Now, there may be a way in fact,
that I could dig into the body
and get its width and height but I'm just going to store
those out of convenience for myself.
The size of these rectangles is never going to change,
so I can keep that.
There is a big issue here though.
Which is that, one, is that once I start adding the physics,
the box could wobble, meaning it could rotate,
so, I'm also wanting, I'm also going to want to get an angle.
And I am going to want to then draw it with rotation.
So, I'm going to say push, I'm going to say pop.
I'm going to say, translate pos.x, pos.y.
And then the rectangle's at zero, zero.
And I'm going to rotate by that angle.
There's another little weird nuance here.
So, I like for myself, I like to think about
placing the rectangle with the x, y in the corner,
and then the width and the height,
and that's the default behavior of p5.
But matter.js, when you make a rectangular
or circular object, the x, y position
for that object is always in the center.
So, this actually have told matter.js
where the object is and drawn it
in a different place.
So, I need to reconcile those two things.
So, to reconcile those two things.
There's a few different ways I could do it.
One, is first, I should say rectMode CENTER.
So, that I'm drawing.
But now you can see everything's off in a weird place,
which is maybe fine, maybe I just need to rethink
where I'm placing the stuff.
For example, the ground would be now at,
width divided by two, height minus 10.
So, that's the same thing.
So, that's fine.
(hands clapping)
(laughs) That's one way of doing it.
And my rectangle is in a weird place.
But I'm not going to worry about that right now,
I'm going to position stuff and I obviously
could use some math to get it to rest
perfectly on the ground.
But I'm not going to worry about that.
Still, there's no physics happening.
Why is there no physics happening?
I created the body, I added it to the world.
It's because I'm not running the engine.
So, what I need to do, draw is my loop.
So, basically I need to say every time
through draw step forward in time.
So, I think I can just say engine.run, no.
(bell ringing)
I looked it up.
I probably could have shown you me looking it up,
but it's not, how do you look this stuff up?
Let me show you, looking it up.
So, if I go here and I go under engine,
and I scroll through here.
I could be like, oh, where's that engine.run function.
Oh, it is there, how interesting.
But that's not, oh I forgot to say Matter.engine,
but that's actually not what I want. (laughs)
I want to use update.
I think there's two different ways of doing things.
Engine.run will just set the engine running.
But I want to lock step my p5 animation loop
with my matter physics engine,
so I'm going to use update.
So, and what I'm going to do then
is in here, I'm going to say Engine.update,
but I need to say Matter.Engine.update
and there we go, oh, did you see that.
The physics is happening. (sighing)
But the ground fell out below us, we're sinking. (laughs)
It's okay everybody, we can violate the laws of physics
and create an object with infinite mass that never moves.
The ground can be known as a static,
it can be a static object.
So, objects that you create in matter.js,
the physics engines can be static or dynamic,
by default they're dynamic.
So, the tricky thing here is I'm using
the same box class to describe both
the ground, and that rectangle.
So, I could separate them if they really
are different, or use inheritance,
but maybe, why not?
Let's use inheritance.
This will be fun.
I've been talking about inheritance, let's use it.
So, I'm going to add another file.
I don't know if this is the best technique.
I'm going to call it ground.
And I'm going to say class Ground,
oh there's a problem with this idea but it's fine,
extends Box (laughs) and then I'm going to say constructor.
It's going to get a x, y, width, and a height.
I'm going to say super x, y, width, and height.
So, now, the ground is a class
that inherits everything from box.
If you don't know about inheritance,
I'll refer you to my video about that.
And I can go into sketch,
and I can now say ground equals new Ground,
and it's not defined because
I have to add it to my index.html,
there it is, hello.
Alright, now, what still?
Still.
(bell ringing)
Wow, something really crazy happened.
I kind of forgot that the order,
it usually doesn't matter for me
because I don't have anything really happen
until the setup function in draw, and everything has loaded.
But I can't reference the Ground.js JavaScript file
before box.js 'cause it's extending box,
and as it's loading the DOM,
it's got to look at the box file first.
So, this actually is one of the rare instances
where I've got to put this script tag
before that one, no. (laughs)
Oh no, that's the bird.
Yes, this is going to work any second now.
Yes.
Okay, oh, it still goes away.
So, now I need to figure out how do I
just change one thing to make this static?
Can I do this?
this.body is static equals true.
Yay.
Okay, so, this is the idea of I have
a whole other kind of body that extends box,
it does everything the same way,
but I can set an additional variable isStatic to true.
And so, now, when this runs, we've got
our Angry Bird box thing over there,
and now we're ready to start working with our bird.
Oh, okay.
So, let's work with our bird now.
So, we need to get rid of the x and the y.
I'm going to say this.body equals
Matter.Bodies.circle, x, y, r.
I'm going to do the same thing.
I'll actually worry about rotation.
So, I'm going to sort of cheat a little bit,
by just copying this over,
'cause I don't feel like typing right now,
and then just change this to circle, and this dot r,
and there we go.
And then I also should say Matter.World.add
this.body to the world,
or this.body to the world.
There we go.
Ah, it's rolling away.
Alright, excellent.
So, I want to be able to toss
this bird over here to this rectangle,
how do I do that?
Well okay, maybe I do an if statement
to see if I click the mouse inside it, then I grab it.
Well, one of the nice things that matter.js provides
is this very general thing called a MouseConstraint.
So, I can add, I'm going to add, and this is a little tricky.
I'm definitely going to have to look this up.
I'm going to call this mConstraint for mouse constraint,
and then I'm going to say mConstraint equals matter dot,
alright we're going to have to look this up.
I want a MouseConstraint.
Create engine options, okay.
So, this is what I want, matter.MouseConstraint.create.
So, I'm going to say, Matter.MouseConstraint,
was capital, MouseConstraint.create,
and give it the engine.
Okay, so, look at this, options.mouse was undefined,
options.element was undefined.
May not function as expected.
So, matter.js is giving me a nice warning here,
explaining that well you made this mouse constraint,
but you need tell me where you're going to be
clicking the mouse, I need to know
where you're clicking the mouse.
And where I am clicking the mouse is in the canvas.
So, I could like if the canvas is a DOM element,
does it have an ID.
Well, one of the nice things about using p5
is I can just store in a variable,
the result of createCanvas which is this canvas object.
And I should be able to now say,
I should be able to give it some options.
And then so I can add a second argument here,
which is options,
and I think I need to just give it mouse null.
I'm just going to put things as null,
and then element null.
(bell ringing)
Alright I'm back, after looking up what I need to do.
So, what I forgot is that I need this mouse.
So, I need a separate mouse object
that I can use to create
and manipulate those mouse inputs.
One of the interesting things, there's a live chat
going on right now as I'm recording this.
And Alka wrote a nice suggestion for aliasing
all these matter dot things, you'll notice
how I'm driving to write matter dot,
matter dot, matter dot everywhere.
So, I'm going to actually just go over here and take.
I forget what this is called, but this
is kind of a new fangled JavaScript thing,
where I can basically just make a nice list
of all these objects I want.
I'm at Engine, World, MouseConstraint
and I'm maybe going to use Constraint,
and I can just set that all equal to Matter.
So, basically, this is me
aliasing everything that's matter.Engine,
matter.World, matter.Bodies.
So, in theory, I should be able to just say Engine now here,
this makes things a little bit easier,
just MouseConstraint here.
So, my code is a little bit more succinct
and I'll go back and fix that
in other places, as necessary.
But, what I need here is a Mouse,
and I need to say constant Matter mouse,
I'll just call it mouse equals Mouse.create canvas.elt.
So, I need to make a mouse object with the DOM element
associated with the canvas.
And then I believe, I can just put this here, under options.
And now, here we go, let me bring this all the way back.
Dare I say, oh no, oh, so close.
Oh, what did I forget?
I probably have to add it to the world.
World.add world, mConstraint.
Yay, look.
Now, I can pick this stuff up
and I can toss it, oh look come on.
I can do better.
Yay, oh, goodbye.
What's left to do?
I want to add a few more boxes.
I want to put images instead of these,
just these boxes and circles, and I think
I should try to add a slingshot, even though right now,
I could kind of just toss it.
Okay, the first thing would be just adding more boxes.
So, I'm going to change box to boxes,
and I am going to now have a little for loop,
i is zero, i is less than three, i plus plus.
And then I'm going to say instead of a single box,
I'm going to say boxes index i equals a new Box,
and then here I am going to then
say for let box of boxes, little for loop, draw them all.
So, now you can see, look at that,
What's so crazy, is when I start them all at the same point,
the two objects cannot appear,
cannot occupy the same space in a world of physics.
So, they like burst off from each other.
But let's do something like say, 300 minus i times 75,
which will stack them.
So, now I have little stack of boxes,
and then I can toss it, and there we go,
I didn't knock them over.
Oh, whoa, I threw it over.
So there's some nuance here to how physics engines work
and how I'm going to need to create some balance in the system.
And you know, one of the things there
is I probably need to increase the number of iterations
per update in order for it not to be able to move
so fast, just to jump over the stuff.
But let me just run this again.
I want to really see if I can knock those things over.
Yay, I knocked them over.
I could also play around with the properties
like restitution and friction, which are
physics attributes of each of these objects,
restitution being elasticity or bouncyness.
So, maybe towards the end of this video,
I'll try adding that.
But now we're in pretty good shape.
So, let me add the slingshot.
So, what I did right now, is I created
this idea of a MouseConstraint,
and a MouseConstraint is this very generic constraint
that just like, any time I click on something
it'll make a little spring like connection
between where I click the mouse, and the object,
so I can move it around.
But what I want, is actually to introduce,
a constraint maybe right here, that's fixed to this point,
and only attached to this particular bird.
And I think it's probably smart for me to wrap
this into a class.
Because I'm really going all in
on this object-orientated programming approach.
So, let me make another JavaScript file called slingshot.js,
and let me just right out the outset,
remember that I need to refer to slingshot.js,
then class SlingShot.
So, what does a slingshot need?
So, I think it needs an x and a y,
like where is the point from which
this object will be attached?
And then it needs. Oh, no no, that's not where these go.
It needs an x and a y, and then it needs a body.
So, now, I'm going to create, let's call this this.sling,
equals Constraint.create and then options.
I think this is how that works.
And this should be Constraint. (laughs)
Constraint.
So, I'm going to make up some options now.
So, I need to configure that Constraint.
The two things I want to be connected,
with this constraint are a point,
which I'll call pointA, this is in the matter.js
documentation specs, pointA, which is an object
with an x, which will be what I pass in,
and a y, which will be what I pass in,
and then also it needs to be connected
to something else, bodyB.
I think it could be bodyA and bodyB,
or pointA and bodyB.
There's different ways you can configure it,
but I want a point and a body.
I could make another body that's static body I guess,
but a point is the equivalent to that.
So, then the body is going to be,
oh, I don't think I need an object here,
just this particular body.
Then I want to say World.add, this to the world,
this.sling.
And the other things that are part of a constraint,
I believe, I forget the actual stiffness,
like, it's like a spring connection,
how stiff is it?
So, I think that's actually just called stiffness.
A value of one means the constraint
should be very stiff, a value of 0.2,
means the constraint acts like a soft spring.
So, let's just try, just to start with, let's try 0.5.
And then, a length is very important.
What is the rest length of that spring?
Let's make it like 20 pixels.
So, now, I've created this slingshot.
I also think it would make sense for me to draw it.
So, I'm going to do a show, I'm going to make show function,
and I'm going to say stroke 255, and I'm going to draw a line,
well, let's make posA equal this.sling.pointA.
And posB equals this.sling.body.position.
These are the two things that the sling,
the string, the spring, the connection,
the constraint is attached to.
So, draw a line from posA.x, posA.y, posB.x, posB.y.
Oh, so, I think, by the way I'm writing this class,
I didn't even make the slingshot.
So, now, I need to go into sketch.js
and I'm going to make a variable called slingshot.
I'm going to say slingshot equals a new SlingShot.
And I need to give it a x and a y,
which where did I make the bird 5300?
Let's just put it in the same place.
And then, I need to connect it to the bird's body.
You can see already, look,
this is kind of like stuck somewhere, right.
This is great.
But let me draw it, 'cause I think
that'll make it more obvious.
slingshot slash show,
and what did I call it?
slingshot show, ah PosB.
Oh, bodyB, it's pointA and bodyB.
So, if I do this.
Right, you can see there it is.
Now, okay, this was some goofiness here.
So, one thing that's really weird
is that if I drag the mouse off,
the mouse constraint gets confused,
and thinks it's stuck.
So, that's just an interaction design problem,
that I have to iron out at some point.
Let's change a few things like
let's make the bird much smaller.
Let's move everything over a little bit.
Just to give me little space here.
So, now, we can see and maybe I should make that rest length
a little bit longer, there we go.
And maybe the stiffness should
be a little bit less, there we go.
So, I'm pulling this back.
The idea is that I'm going to pull it back
and let go, and I want it to fly.
So, we're getting there.
I have this slingshot now.
Now, how do I release it?
I have to come up with a way of releasing this.
I need a way somehow, to launch this bird
off of the slingshot.
Like the slingshot should be broken,
and the constraint should be broken,
and it should go flying.
So, first let me least create a mechanism for that.
So, let me write a function here.
I'm going to call it fly.
And I think if I just say this.sling.bodyB equals null.
Like if I just detach the body
then the thing that's attached to it, will go flying.
So, let's just try in, let's just add, just as a test,
a keyPressed function.
If key equals space, then slingshot.fly.
So, again, I need to figure out when it should be flying.
But if I just hit the space bar,
cannot read property position of null, slingshot line 24.
So, okay, so only if there is a body attached,
then should I bother to draw the line.
Okay, so, I need to also not draw the line
if there's no body.
So, let me run it, there we go.
We can see (laughs) now could I possibly time it?
Like now my interaction is, I have to do this.
Yeah, but I shouldn't have to hit the space bar, right.
I shouldn't have to hit the space bar.
So, how can I determine a time
where I should have it fly?
What if I were to get the body's speed right.
So, a suggestion came in the chat
to just look at when the mouse is released.
I think this isn't going to work, timing wise.
But let's try it.
What if I just write function mouseReleased
which is a global p5 event for when I release the mouse.
And there I could just say, slingshot fly.
So now, I'm pulling this back and release the mouse.
See, it didn't have a chance to move,
before it could start pulling it.
So, I could use like setTimeout, this is kind of ridiculous.
I could and then, like do it in like 50 milliseconds later.
Is that right?
Maybe it should be more like a 100 milliseconds later.
Oh, that's actually kind of great.
That worked.
Weirdly, just giving it a little time later.
I was going to go through this whole
thing of testing its speed.
You know what?
This is good enough.
I think you could probably,
those of you watching, you might
want to come up with a different solution.
But I'm surprised that this actually worked,
just the little setTimeout, just give
it a 100 milliseconds later,
thank you to Betatester704, who maybe was
the one who suggested that.
So, this is great.
We have Angry Birds.
Now, one thing I should say, is like, at some point
I want to be able to like have a new bird,
and so, there's a variety of ways I could do that.
Let's use keyPressed.
We'll just use a key press right now.
And I could say,
remake the bird, and then I could say,
slingshot.attach this bird.body,
and then in bird, I mean sorry, in slingshot,
I could say, attach, get a body,
and I could say this.sling.bodyB equals that new body.
So here, now, what I should be able to do is
I should be able to let it fly, knock the stuff over,
and then, oh sure I want to probably detect
when it should do this.
I can hit space, oh no sorry, oops.
Space and then, oh there is, there's a big flaw
here in my system, I'm not going to worry about it,
this is good enough because I could like, first of all,
I can use the MouseConstraint (laughs)
the MouseConstraint will let me do anything.
And then I can also release,
when I release the box, also the bird gets released.
But you, the viewer, these things can be cleaned up.
These are interaction design problems.
There are better solutions.
This is kind of exciting.
I've got the basics of Angry Birds here.
Alma writes, you should utilize the concept of potential
and kinetic energy for it, it's just
a pure projectile thing.
So, I would love to see somebody make a variation on this,
and submit it to thecodingtrain.com.
There's a way that you can submit
your versions and doing that.
But I just got one more thing I want to do.
I want to add some images to this.
Before I add the images, there is kind of a big bug here
that I really should fix, which is that when
I put the new bird in, there's actually
another bird, that old bird is still here,
I'm just not drawing it anymore.
Maybe I want it there, or maybe I should remove it.
But probably right now, I should
just say World.remove bird.body world.
And its always the other way around.
So, I believe this.
Right, let me see if I can show you what I mean.
Right, I'm going to shoot this over there.
Now, notice this is here, I'm not going to see it anymore,
but I'm going to try to shoot it right over there again.
(laughs) See how it hit the invisible thing.
So, let me remove it.
And that should fix that.
So, if I do this.
And it's there, and then I do this again. (laughs)
I do this again.
Anyway, you can see it's gone, it's removing it.
So, there are different ways that I could approach this.
A Simon in the chat is pointing out
that instead of just making the bodyB
of the slingshot null, I could actually
remove the slingshot, I could reuse
the same bird by just resetting its position.
So, again, you might make,
have a different take on this, refactor
this in a different way.
But I've got the basic idea down.
Now, I want to start adding images.
Alright, so, I have all these Coding Train character images
designed by Jason Hegland, thank you for that.
I'm going to use the dot for the bird, a little smiley dot,
and the angry equals sign for the block.
Now, this block is square I think, not rectangular,
so I'll probably have to adjust the dimensions.
But the first thing I need to do,
is upload these images to the web editor.
So, the way that I will do that,
is by just going over here, doing Add File,
and then I can just drag these two images in.
You know, I could put them in a folder or something,
and we can see they're there.
So, now I have dot png and equals png.
And you know, there's probably a thoughtful way,
that I could think about what if
I want different blocks to show different images,
but I'm just going to in a very simple way,
use the preload function of p5.
I'm going to have a variable called dotImage,
and a variable called boxImage.
And I'm going to say dot image equals loadImage dot.png,
and boxImage equals loadImage,
what is it called?
equals.png.
And let's first just change the bird to show,
instead of a circle, instead of fill,
I'm just going to say image and then I'm, what was the name?
dotImg.
Oh, and then I want to say, imageMode CENTER,
and then I'm going to have to say this.r.
And this should be this.r times two really.
If I'm thinking about that as a radius.
So, there we go.
So, we can see now I've got the little dot, it's so tiny.
I should make it bigger.
And I think what I would prefer to do also,
is draw the slingshot behind the bird.
Okay.
So, now, I have my dot.
There it goes.
Now, I just need to replace those blocks.
So, the boxes.
When I make the box, I am in sketch.js.
When I make the box, I'm giving them an x and a y,
and a width, and a height.
Let's just make them square right now.
I could have an image that's not square.
So, they're much larger now, but that's fine.
And then, what I'm going to do is in box,
let's change I to image.
image, what did I call it?
boxImage, there we go.
Oh, we've got a problem. (laughs)
So, the ground is messed up now
'cause the ground is also the equals.
So, and we also have to say imageMode CENTER, (laughs)
the ground is this like smooshed equals, but guess what?
Not to worry, I used inheritance.
Oh, I'm so happy I used inheritance.
Then I could just override the show function,
and there's probably a more thoughtful way I could do this,
but I am just going to put this all in here,
and I'm just going to put this back TO rect,
and back to this.
And now, there we go.
So, I now, here we go.
(drum beating)
I have my Angry Birds clone with p5 and matter.js
and I'm going to pull this back, release and,
oh wait why did it make it so small? (laughs)
So, one thing I really need to
do a lot of (energetic rock music)
refactoring of this,
because I did something very silly here,
where I remake the bird, but I use a different size.
Which having a hard coded value here is pretty bad.
Right, let's try this one more time.
(drum beating)
Right.
Wait, wait, wait, wait.
I have an idea, I have an idea.
Let's add restitution.
So, I'm going to go to the bird, and when I make the body,
I could also add some options.
For example, one option might be restitution,
which is like elasticity.
Let's give that a value of one. (laughs)
Let's look it up in the documentation.
Always positive and in the range, zero to one.
A value of zero means the collision
would be perfectly inelastic and no bouncing
would may occur.
A value of 0.8 means the body may bounce back
with approximately 80 percent of its kinetic energy.
So, let's try giving it a value of 0.8.
Oh, guess what?
I can make up this variable called options
till the cows come home,
but if I don't actually put it in creating the body,
it's not going to make any difference.
So, now, let's see how that changes things.
There we go. (laughs)
It's kind of like Jenga, where it
just like slid out a little bit.
Oh, wait a sec, it's even bigger.
Whoa, okay, oh, things have gone really off the rails here.
This is supposed to be 25.
And let's be a little bit more kind,
let's give it 0.5 and let's also go to the box,
and let's give that also a restitution.
Okay, here we go.
(drum beating)
This is my angry birds game,
made with p5 and matter.js,
and Coding Train characters. (laughs)
Oh, fall, fall, fall.
Yes.
(triumphant classical music)
Thank you for watching this coding challenge.
Sorry to interrupt, I'm about to wrap this video up,
but I want to show you two quick improvements before I finish.
The first one is, when I loaded my Coding Train
equals character, it was a square image,
and there's actually a lot of additional extra space
on the width, and so there is some funny physics
happening that looked a little bit off.
So, I'm now actually cropped and re-uploaded that image.
So, that it's 84 pixels by 100.
The other thing that, thanks to a suggestion,
I increased the mass of the bird's body.
So, the matter.js will give elements
a sort of default mass, probably based on their size
and their geometry, and I just take the bodies
and set its mass to its own mass times four.
And so, now, if I were to play my game.
(drum beating)
One more time.
Let's zoom in on this.
And go.
Boom.
Yeah.
I am so angry dot Shiffman coding.
Oops sorry bonk.
So, this is my version, there are so many flaws
to what I've done here, in terms of how
I've organized the code, there's some like weirdness
in the physics, I haven't really been sort
of thoughtful about the design.
The whole slingshot mechanic is kind of off.
So, there's a couple things you could do for me here.
Number one, go to thecodingtrain.com, find the page
for this challenge, the source code will be there,
as well as any other supplementary links,
and you can submit your own version.
Maybe you just want to improve the way I wrote the code,
to make it better organized.
So, that people could see that.
Maybe you want to make your own delightful
design of a scene.
Maybe you have a totally other game mechanic
and idea for how the physics of this world should work.
Maybe you actually want to build this out to be,
you have more features, and levels, and score.
There's so many possibilities.
So, make your own version of this,
you don't need to use p5, you don't even need to use matter.
These kind of concepts will extend
to other drawing libraries and game engines.
Phaser might be one that you should take a look at.
Even perhaps, you can check out
the video from Catt Small,
about using Phaser and codependents on this channel.
And I will see you in a future coding challenge.
Thank you.
Mwah, goodbye.
(energetic electronic music)
(bell ringing)