Placeholder Image

字幕列表 影片播放

  • (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)

(train whistle sound)

字幕與單字

單字即點即查 點擊單字可以查詢單字解釋

A2 初級

Coding Challenge #138: Angry Birds with Matter.js

  • 4 0
    林宜悉 發佈於 2020 年 04 月 06 日
影片單字