Handmade Hero Day 047 - Vector Lengths

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
there we go so hello everyone welcome to handmade hero the show where we coat an entire game from scratch live on twitch no engine no libraries just straight-up every last little bit we code ourselves both our educational purposes and just because it's fun and because it's just kind of cool sometimes one of the things that's true and we kind of saw this happen with the with the looped live code editing that we did earlier and you know I will see couple more things like that when you actually write everything from scratch you also tend to find places where you can do things better than people have done them before and that's kind of compelling too if you never get down there and start writing the stuff that you kind of use in an engine or use in libraries you don't ever find the ways to do it better than what they do and I always like trying to find better ways to do things because I think that's kind of the most interesting thing about programming it's kind of coming up with new ways to do stuff that people haven't done before so since we're starting to late let's jump right into it if you have pre-ordered the game you can download the source code you should have got a link in your email and that link has a zip file that you can download and we are here if I'm not mistaken on day 47 I believe that's correct 47 let's double check that's true where are we I don't even know I don't even know anymore yes we're on day 47 so if you unzip this the zip file for day 46 then that is a source code that I am starting with here on day 47 and you will be exactly where I am right now now if you remember correctly yesterday we just took a little bit of time to fix well a bug but basically in fixing that bug we decided to kind of add a feature which is multiple people controlling multiple entities on the screen and so we basically had the ability for people to kind of drop in if I have a game I got a gamepad here I can add another guy right and and he's there hanging out now we started basically pulling out the code for for the sprite control for that hero character into its own function and he is kind of he's kind of doing his thing right but what we had interrupted to do that yesterday because I want to take care of that right what we interrupted is we interrupted fixing our walls sticking problem which we had discussed and we were in the process of writing code for now I want to talk about that a little bit but one thing I did want to do too is while we're at it at the beginning of the stream here I want to clean up one more thing because now that we actually have the the you know now that we actually have multiple little heroes on here we and we're supporting the analog stick now I want to go in there and deal with some stuff that we didn't deal with on the analog stick in terms of the motion of the actual player so just quickly if you recall we had not really learned vectors yet when we first visited see here when we first visited this code right here so what we were doing originally is we basically just did a little hack which said that if both of your if both of you were when when the user is controlling the hero we had just hacked into things so that when he tries to move diagonally he wouldn't move faster than he moved when he was moving in cardinal directions right and this is something that we did before we learned vectors so basically we had a situation where we had something that looks like this we have him moving in this direction and we would set this to be one Y and 0 X so this is the vector 0 1 right or we would be moving this way and this would be the vector 1 0 or or we would moving this way up sorry that's actually negative 1 and that's 0 1 because remember Y goes up that's positive x positive Y and and this is negative 1 right these are the vectors that the d-pad could be creating by pushing in the cardinal directions but when you push in two directions at once we were ending up the vector like 1 1 right which is longer if you remember by root 2 we went through all this so jump back to the is if you're not sure I'm talking about I'm not going to go over all again today but we would basically end up with this and that's moving faster than either of these its its root 2 long instead of one long right so what we decided to do is we decided to solve you know we actually solved Pythagorean theorem to figure out how long it should be so that would be the same length it would still be one long but just in that direction right but now we have a different problem if the analog stick is being used then really inside this unit circle right you could imagine the analog stick pushing in any direction and it can be pushing proportionally so it doesn't have to be just one of these Cardinal one of these carbon directions or the diagonal right so all we really want to do is we want to make sure that that vector that comes back to the analog stick we just want to use that as his acceleration directly unless for some reason the value we get back tries to exceed the length of one right tries to exceed the length of one so that it would be accelerating beyond the maximum acceleration that we wanted it to have right and well we don't necessarily know if that will ever happen because it could be that the analog stick always returns values that are perfectly inside that unit circle unit circle you could imagine if there was some game pad that had more of a square range of motion so that when you pushed it up into the corner here it was actually kind of more at negative I'm sorry negative one one you know or something like that or negative one negative one down here instead of sort of being more at that unit circle range then we would have this thing where people could sort of cheat by moving the player faster than they should be able to on those joysticks right so we want to make sure that no matter what we get back from the operating system as our joystick values we always want to make sure they are capped so that the that that motion that acceleration vector that we're taking from the joystick is not greater than one now we showed how to implement the length of a vector right we already showed how to say if we've got some acceleration vector here we showed how to say well we can take the length of that vector right and if you remember that was just the components of it right squared right so we had this the length squared was equal to this squared and getting that's just that Pythagorean theorem theorem a squared plus B squared equals C squared that's what we did right and if we wanted to actually find out the actual length we could just square root this right so we'd square root both sides and we've get this right x squared plus ay Y squared like that so we have this ability and we actually implemented that in our math library if you remember correctly we went and did length squared and we implemented that by just taking the inner product of the vector with itself which again basically computes exactly that thing ax times a X a Y times a Y because remember our passing a in both cases which is exactly that Pythagorean theorem that selects of the vector so now we do know at least how to directly ask the question whatever comes back is our acceleration vector how long is that vector right because I could go into this code and I can ask what the length square it is right I can say what is the length squared of this value so if I say DDP length I can compute it right and that'll get me a value that I know is gonna tell me how long the the requested acceleration for this player is and I can then go ahead and say well all right however long that acceleration vector is well I'm gonna get it squared value back now I could square root it if I wanted to but I don't really have to just do my check right because if you look at the value of square root right if we looked at what what square root was going to do and maybe I'll do this in a sort of kind of oh you know what I wonder if we can do this I wonder if we can do this this way Square or like Wolfram Alpha or something I don't know if it's I don't know if it's got this sort of stuff but let's see here square root I just want someone to give us a little graph and I figured it'd be easier than me drawing it out but I don't actually know if that would do it so there it is good so this is a graph right of the square root function and I guess the one we probably want more oops that's no good would actually be from zero to one I don't know if we can can we we're gonna have we got to have some kind of Pro thing God Wolfram Alpha what what is what don't know go away thank you alright good so I guess we'll use this one here what I really want is just the up to one but it's it's fine so if you look at this here you can see that the interesting thing about square root right is the square root of one is one it's right that's the one value where a square the square root of the number equals itself it's the identity for square root right so if I take the square root of one I actually get one back right and so I could just say well since I actually want to just check to see if this thing would be one if I took its actual length of square root of it well I could just say whatever that length is that I want you know max acceleration right I could just say whatever the square of that is I'll compare against that so if the if the length that we get back is greater than the square of the max duration then I'll do it but of course I know in this case the maxillary should here is just 1 and I know that the square of that is 1 so I can basically just check if it's greater than 1 and save everyone the trouble ok now you may ask why is the maxillary agen 1 it's because we're not actually producing the max acceleration here what we're doing is producing the direction and the amount of the max solutions that we will apply and you'll see that in one second so I need to do here is just check to see ok is the length of the thing that we were supposed to be using he is that going to be greater than 1 and if it is greater than 1 I need to cap it at length 1 okay so I need to figure out some way that now I need to do something to DDP here right I need to do something to DDP such that I can change its length to 1 without changing its direction right so I need to construct a kind of diagram that again should be familiar to you from your high school math right I have a vector oops I have a vector here right there's my vector and you can imagine in fact I should give myself a little more room to draw so let's say it's big there's my vector right and it has its components x and y here's the component of the original vector we'll call that vector a here are the components right and this is my vector now what I want to do is I want to construct another vector and I want to point in exactly the same direction as a but I want its length to be 1 so this length here should be 1 this length here is some other length it's the length of a right makes sense okay now if you remember again like I said from from your convenient your convenient sort of grade school or high school math you know that if you have right triangles like this that share all the angles are the same right you've got all the angles are the same on this diagram then you know that they are similar triangles and what similar triangles mean is that the sides are actually proportional in length to each other so the ratio of one of the sides of this triangle to one of the sides of this other triangle is the same ratio no matter which side I pick right so if I want to know how big this is relative to this or if I want to know how big this is relative to this all I have to know is the relative ratio of one of the sides now of course I have that because I know how long a is right and I know that I want it to be 1 right so I basically know that if I take the ratio of 1 which is this what I want here right to a which is the actual length that gives me the coefficient that gives me the ratio that I would want you know I can even I can write it out as an actual ratio expression the ratio of the you know the thing I want versus the thing that I have I can then pick any other part of it like the ax that I might want to get and if I want to get that new that new X right whatever that new a prime X is so a prime X would be down here right this length right so if I want to try and figure out what that is I can just use I can just use this exact this exact formula right and the thing that I want to solve for is this so multiplying out you get just doing the cross multiply again this is where I'm shocked I made a serious math error on the stream this may be the day but we'll find out yeah so anyway the thing I want software is this this right here this this a prime X the new the new you know this value because I know that value and I want to get this value so if I want to solve for that I just have to go ahead and isolate that term which just means dividing by this and of course that gives me a prime x equals ax over length a right and this turns into basically the the sort of the canonical version of changing the length of a vector so let's say I want to do it a little more sort of aggressively let's say I wanted to do a prime so I just have some new length here length of a prime whatever that length is right so I want to basically say no matter what the length is what would I do here well now cross multiplying right I get that length of a prime here right so ax times that right cross multiply here if that's this term cross multiply there that's this term they're equal to each other and so then when I actually do this right I get one additional term instead of just having ax over a on this side I actually have the length of a prime times ax over a right because I'm taking this and dividing by this and this right here is the canonical form for how you change the length of a vector without changing its direction it's this a prime over a right so length of a prime over a length of a so the lengths that I want my vector to be over the length that it is right is that term right there times the component that I want right ax is the existing value for my x coordinate of that vector so that gives me the new a prime the new the new a prime X and if I want to do it with Y again this would be the exact same equation there just be wise here so all the same math carries through so a prime Y is just the exact same thing coefficient times a Y right so what that get gets for us is just this really really simple way to take a vector and change its length all we have to do is multiply the components of the vector by that ratio a prime over a now we know that we want the length the the a prime there that length is just 1.0 and so now we just need to know what this value is here right what that is now unfortunately ratios do not work through squaring if that makes sense so basically if I have this a prime over a and this is the coefficient I want to compute I cannot compute a prime squared over a squared I can't do that right I wish that were true but I don't believe there's any real way you could you can yeah I'm trying to think if there's a good way to do that basically I can't think of any way to really do that simpler than just actually after you do the square root right so that means we do have to do a square root here but hey square roots aren't as expensive as they used to be I don't know if we actually ever put one into our math let's see here I into our math library oops where is intrinsics square root no we didn't so we want to put in a square root here again this is going to be something that should be generated directly by the compiler hopefully at least inverse square root usually is square root usually is as well anyway we'll see let's take a look so square root of some value that comes in that's going to be equal to the square root of the value that comes in return that as a result yeah and so all we really need to do here is just do the what that length we had take that square root and that will will essentially do that operation that we just said right multiply all the components of our of our vector of our acceleration vector by whatever would make its length equal to 1 right and we're not going to do that if it's less than 1 already because that's fine that just means the person is pushing just a little bit on the stick and now we can get rid of this right so hopefully that will what is the problem do we not have an F squirt first oh do we need there we go sorry for some reason it's F but squirt f don't ask me why that happened because I have no idea but that's just the way it goes alright so now in theory we should have more ability to control this guy a little smoother there's not really going to be a whole lot of difference there but that's just getting that's just getting rid of that kind of crufty code that only worked for the d-pad so now it'll work for the analog stick as well and we're all good right and you can see now you can move just a little bit right and we don't get any kind of weirdness in there or any kind of non proportional stuff so yeah so that's good so that's all I really wanted to take care of was just that yeah and hopefully that made some sense it's pretty straightforward now as I said before if you want to know why we are making it length one it's because basically anything that's length one is easy to then transform out into some other length right because if I know something is already length one and I want to make it some other length later I just multiply it by the length that I want right because you have to remember this this equation that I just said where it's the new length right over the the old length if I wanted to make something a new length and I already knew its old length was one well that means this square root here would just already be one and so it would just be a new length over one or new length so that would be the equation right for changing it to some new length if I knew its if its current length was already one and so the reason I'm constructing a length one vector here is because now I just have basically the generic vector that points in the direction that the person goes or a vector that's something less than one and if it's something less than one then all it will do is when I multiply it by something later it will be proportionally less which is exactly what I would want with the analog stick right I'd want a proportion less than whatever I'm going to do if it was pushed all the way out and so then we do exactly what I just said we take that vector and we multiply it by however fast we wanted the player to actually accelerate in meters per second squared and that basically gives us a new vector that's the correct length now for acceleration to use and then we proceed as normal so nothing nothing weird happens there so that's it I mean there's nothing there's nothing really fancy going on there just want to make sure everyone kind understood what was going on and so they'd hey there he goes and he's good so now we have to do is concentrate on this problem right where we're not grinding along the wall because we don't allow movement when we just when we when we detect a collision right and so what you want to do is allow movement when we detect collision now and clean that up ok so what we need to do for that I thought about this quite a bit and I talked about on a previous stream I was talking about whether we should do search and P or certainty and we like I kind of talked about how to implement both methods and I the more I thought think about it the less I want to do search and P I was kind of like really on the fence if you remember I wasn't sure and I thought about it over the weekend and that's like you know what I don't think it's a good idea and the reason I don't think it's a good idea is because I feel like it's gonna introduce a lot of complexity into the code for us for not a lot of benefit because really in this game we're not gonna be grinding against walls a lot it's not like a walking simulator kind of a game and I feel like the benefit that we'd get from having search and P which I like better for collision detection in the in some case sense it's just gonna cost too much in terms of the code complexity so I think since we really never actually bothered to implement it I'm just gonna say let's not bother and let's go with the more traditional version which I was going to show how to implement anyway let's just do that method because I think that method makes more sense because it's just it's cheaper is the thing and and I feel like the cheapness is gonna be important for us that's all and I don't think we're gonna get much benefit out of the other way so basically all we really needed to do was come up with a better way of actually detecting when we were hitting stuff so what all we were doing before is when we actually go in you know somewhere we say we're here and over a time step we want to go here but there's something in our way all we were doing before is checking checking that ending location we were checking that ending location to see whether we could stand there and if we could we just took accepted the move if we couldn't we denied the move that was it and so we need to do something better than that and in order to do something better than that the first thing we have to do is figure out what we actually hit and where we hit it so we need to do something where we're going to look at what you know what we could collide with and we have to go ahead and say all right when we collide with something let's figure out where we collided and when we figure out where we collided we will put the player there right we will update his velocity vector which is what we were doing before to basically not have any of the component that was going into the thing that he collided against and then we will try again to move him now we will try a few times we will basically do this in a loop that tries a few times to get him to where he should be and if it fails to get him to where he should be you know if it shouldn't say where he should be it'll try a few times to move him the total amount that it should have moved him right because when we go here you know we'll find the velocity vector still is has there still a delta T right because we moved to here and we know that he would have gotten there if this was the entire time step we know that we would have gotten to here in less than that so there's some smaller thing here delta T 2 or something right that's a smaller thing and we want to then use the remainder that delta T remainder we want to still try to move him by that much and so hopefully delta T that the amount that's remaining goes down to zero and we know that we've done a complete move but if we find that we just can't resolve it because there's all these crazy walls in there and he's bouncing around or whatever we'll just cut our losses and say you know after four iterations or something we're just gonna consider that good enough and we'll stop because we don't want to have something where we're gonna do an unbounded number of iterations that's just a very bad idea for something that's performance oriented and again this whole thing is very tiny we're talking about something that happens over a xxx or a sixtieth of a second so these are like microscopic movements that we're talking about here so how many bounces we support is not particularly relevant in terms of what the player can actually experience as long as it's like you know two or three I think we should be fine so what I need to do is figure out how to compute that right I need to figure out how to compute that and we'll start by computing it for the simplest case that we possibly could we'll start by compete computing it with point vs. line essentially right so what we want to do is say all right we need to we're going to have some kind of line right and we're going to have to have some representation for our guy and some concept of direction is going and we need to figure out when he hits that that sort of whatever that is that line that that blocker so we're gonna start with that as the simplest case and we'll kind of work up from there because I think I don't know how much time we got left got about a half hour left so that'll be it's quite that'll be quite a bit for us to actually go through in such a short amount of time actually so let's you know focus on doing that and then we will go ahead and see when we get when we get done with that we'll probably maybe tomorrow talk about how to do some more complicates complicated stuff okay so if we're just doing that simple case what we need to start thinking about is how to solve equations with these vectors right because typically when you have something like this you know if I've got if I have something like that where I've got some kind of a line segment right like so and I have some kind of a vector that's going in that direction I now need to figure out how to do solves because in order to figure out when if I was going along this line when I go here we're essentially talking about something that's going to be some function of time right as time progresses I'm moving and I want to know when this function of time that tells me like a location of the player when it equals some particular criteria right I've got you know some some some value that I want to satisfy here and I need to know when that becomes equal to something right and so if I want to do that we're starting to talk about actually solving some equations and so the first question is well what is the equations what is the first equation that were or what is the first part of the question that we're going to use how do we represent this part how do we represent there's a player and he's at a location and he's moving right well this the most simple thing to do here right is to say well I started a place we'll call that p0 right and then I move along some vector that's like a distance right I move in a direction so I know that I've got some you know p0 which is which is this point here and I know I've got some we'll call that D and I'm moving along it in you know some amount so if you remember we did that thing where we talked about the linear blend right and we said oh well if we want to if you want to have a linear blend between two points a and B right you can think of it as the Delta between them right B minus a you can think of that Delta between them you can think of starting at a and adding some port B a percentage of that difference between them right and this was the standard linear blend function and I said it comes up all the time right remember I said everything we do is gonna have this in it well guess what it's gonna happen here too I've got a place I'm going to I've got a place I'm coming from right and I want to move between them classic linear blend right so I'm going to talk about this as if I have this vector so we're gonna say that I have that that that Delta vector there right and I'm like I said I'm gonna call that D so I'm gonna call this this difference cream T and so I'm just talking about that p 0 which is this I'm tearing that p 0 plus T times D right that will tell me where my guy is at any time T right so if he starts from here I can plug in any time I want and he will move along that line and just keep going right now if I want to I can do different things here I can phrase this in a couple different ways I can say that D is the full distance that he moves so it's like B minus a if in this case here or like this is the p1 he's going to so in this case it would be p 1 minus p 0 i could say that and what that would mean is that t is normalized it means that t ranges from 0 to 1 right and when he gets to 1 he's done moving for this that's as far as he can go right i could on the other hand also take d and say that D has length 1 the length of D is 1 right that would be normalizing the D vector and then T would range from 0 to whatever the actual amount is that would get him along that vector to the location right it would be his his motion amount so we have different ways we could phrase this we could have tea range from 0 to some value or we can have it range from 0 to 1 and it depends on what we want our properties to be of these vectors do we want this to be normalized do we care stuff like that so just keeping in mind that this could actually be phrased a couple different ways the p0 is kind of unambiguous it's where we started at the beginning of time step where the player is standing right now the D is somewhat ambiguous in the somewhat unambiguous and that we know it's pointing in the direction of motion but in terms of the T and the length of D they are kind of interchangeable we can we can move between different schemes there depending on how we want it to work right ok so let's start with the simplest possible case we could we could imagine right the simplest possible case would be if we just know that we have like say a vertical wall right we just want to know when this guy hits a vertical wall that extends let's say infinitely for now so this is just an infinite vertical war he cannot go past it ever he'll never get past that wall whether he goes up down any other way well what do we know about a vertical wall we know a vertical wall has an x-coordinate of something and a y-coordinate of everything right any y coordinate that you want is on that wall but it only has one x-coordinate right so this can be anything but this would have to be a specific value and that would basically be like our wall X right or something so we'll call that wall X so if we want to we could now imagine how we would directly solve this equation to see when a guy walking in that direction right would hit this wall we would say we want to know when the X component of this so PT x which is p 0 x plus t DX remember because this is a vector equation and I can always look at its scalar parts by just looking at the X particular X component of it if I have this equation all I need to do is say whenever that equals the wall X right so this right here is the equation I would solve to tell when I would hit that in T so if I want to actually solve it right I can just solve for T I get T DX equals W X minus p0 X right I subtract this over to this side so that goes over here and then I divided by DX to get rid of the DX right so get rid of that and put it under here divided by DX okay so this is the time at which I would hit that wall simple enough right not particularly complicated but there's a catch here I now have a well you know what I should I should probably be sly err about that does anyone know what the catch is here maybe you guys already know there's a catch here and I haven't mentioned it yet we'll kind of see if anyone will give you a chance to think about it a little bit but I want to point it out I wish I had more tea but I'm regretfully out of tea all right so the catch is right here when you divide by DX you may remember from your high school math classes someone would always say you know the teacher would always say subject to DX not equal to zero right they would say I'm gonna write it in in our form not math forum right D s can't be zero I guess the math form is more typically that way right and they say that because D X can't be 0 because dividing by zero is undefined behavior in math you don't know what it is at least it's undefined behavior in some math the math we're doing it's undefined and since that's the case since you can't divide by zero you know that your solution to this equation depends on DX having been set to some value that isn't zero now you may have always wondered I don't care about that what is that for it's just lame stupid I don't care when you were in high school math that's it's just annoying right but it's not annoying when you actually get to start using math for real you realize it's very important and it's interesting what does that mean well what it means is think about this vector this is the vector D what are its components it is d is DX dy right that's the components we're talking about this the x-coordinate of the vector that's which how far it is like this so you know if I have my vector here you know here's my vector D we're talking about DX it's down here and here's dy well if DX was zero that means that the vector is pointing in either up or down straight up or down it's not pointing to left or right at all right or it's not pointing anywhere it's just zero but if that were true if this is pointing straight up or straight down well guess what it's parallel to this line so there is no solution to when he will hit this line when the person walking along that will hit it there's no solution because he'll never hit it you walk as long as he wants he can walk to the end of time and he'll never hit that wall right so what was stupid in math class rightfully so is actually quite nice in game programming it is information and that information has real meaning and that's one of the most satisfying things about math is when you actually start to use it you realize that all the stupid crap actually mean stuff and you use it right so when we're gonna implement this we have to look and say oh okay if that if that if the x-coordinate is very close to zero this is becoming an undefined equation we don't we just assume that you can't hit the wall at that point right and we don't have to check against this wall at all because they'll never hit it so what's the rest of this mean this T value that comes back assuming that he can hit the wall so it's got some X component well the T that was either gonna be positive which means he goes some direction and hits it or it's gonna be negative which means that like he was actually walking in the opposite direction of the wall and he would have hit it if he'd walked backwards some amount of time so this solution actually gives us how far it would take him to reach the wall go walking forwards or backwards and it tells us which one of them it would have been right so that's kind of cool but we can when this comes back we can go oh we're just gonna say we only care about stuff that's T greater than equal to zero because we actually don't care about Kim walking backwards into the wall we're only checking the forwards right so that would be a pretty simple thing for us to test and to see what happens when he walks into vertical or of course horizontal walls would be the same we just change this to W X the W X and the PX and DX would all change to right so we now have that that's sort of oh you know what I'm gonna try I'm gonna try it you guys ready for this I'm gonna try it scrolling over check it out man that's cool all right so this is the equation the T equals W X minus p0 x over DX right that's the equation that we would use to solve for an x wall and similarly if you wanna solve for y wall right we would say same thing but in Y right so that's how we solve for vertical or horizontal walls now with that we can actually go implement mostly our top map collision and maybe we should do that maybe that is what we'll do and then tomorrow we'll talk about how to do more arbitrary stuff so if you think about this well you think about this we go okay when we do these collision detection right excuse me we would be collide against infinite walls so we have stuff in our game where we've got these walls that have like holes in them and stuff that would work right because if we will start at kalitta colliding against this wall here where you know here's the walls right and the hero's trying to go through this door he'd never be able to get through there because the wall is infinitely high right it's just it goes up and down and covers everything because it's an infinitely long wall it's just testing against one thing but obviously if we wanted to we could fix that pretty easily right because when we find out where this would actually be like where do we find out what the actual collision time is right we could then say well use that T value because we have this function here right use plug that T value back into the walking equation find out where the guy is standing at that time right so do p 0 plus and let's call this like our solved for T or something plus T solve right times D this right here will give us this this solved for time P that will give us this when he walks that will give us this location when he it's the wall right when he hits the wall we can check the y-coordinate to see what its ranges and if that range is not in between the two locations that we know of the wall to be right we could just not do it so for every wall for every tile block that's solid we could basically check for different collisions right one for each side of the block and just check the range of the collision to make sure it's actually in between there if it's not we don't count it as a collision we just move on and so that's a pretty easy way right that we could do this so let's go ahead and implement that since this may be very new to a lot of people I figure like we shouldn't really jump ahead at all that makes sense so that makes sense hopefully that makes sense and again so so this is the yeah well there you go I need to I need to get my so there you go okay so moving along let's just go ahead and implement this code it's pretty trivial right so if we go ahead and implement this code this was our old code up above here that we were just that we were using pretty straightforwardly and so now we're gonna have to write some actual collision detection code here and so what we need to do here well I guess I can keep some of that actually this is this is actually really important what we need to do is loop over all of the tiles that are around us right all the tiles that are that we could be hitting taking a look at them and seeing if they are solid if we can't stand in them then we need to go ahead and see whether or not we would hit them by walking into them right if that makes sense yeah so first things first we need to map into some common location and so let's just assume that the player is like going to be at zero zero right that seems pretty straightforward so let's go ahead and say well actually it's we don't even have to do that we can just go ahead and say we have our tile map difference we're going to subtract the player position for the tile position that gets us the relative position of the of the player I guess in that tile that seems yeah I guess that seems fair enough yeah that's totally fine and then all we have to do in here is actually implement whatever the check is that we actually want to do okay so let's set up this loop I guess this we have not yet initialized so the first thing we need to figure out is which tiles do we actually want to check right like what are the tiles that actually need to be checked and so that's actually another discussion we kind of have to have there's a lot involved here I got explaining a lot of stuff we may not get through all this tonight all right so if you imagine what's happening here collision detection is complicated why can't I oh I'm just cuz I got some stuff selected so many things I have to do prerequisite wise all right so if you imagine that I have my tile map then we have to ask the question what are the things that I actually have to collide with if like my guy is say here and the time step would move him to here right well the answer is I need to check all of the tiles that he could have gone through so I need to check like the tile that I'm standing on I need to check the tile that that he would end up in and all the tiles in between right and so if you think about what that means it's basically just a min max such a situation right it's the minimum tile lie and the maximum tile lie and the minimum tile acts the maximum tile acts of the two locations where he is and where he's going because if he was going to go like that or something like this we'd want to check this whole rectangle right because we want to check all of these things for collision now really if we want it to be that's a that's not that's a conservative check right a conservative check means it checks perhaps more than enough things right a conservative check is basically one that that doesn't necessarily check the fewest number of things but it definitely checks all the things that has to right we could do better in the cases where we had something like this by actually saying well okay the the line the player moved doesn't actually pass through these guys here right it only passes through this one this one this one in this one so we don't have to do the full rectangle right and that's definitely something to think about when we're actually implementing the engine for reals because that could save time but again these aren't gonna be very there's really no way to pass through that of any tiles unless you're moving extremely quickly but yet just something to think about so all we really need to do is a conservative check at this point which will basically say ok as long as we get all the tiles we might check will be fine doesn't matter if we check some of the ones that we actually shouldn't have have checked because that's just like some waste of time and that's like stuff to worry about in the optimization phase of things so we don't actually care about that for now so we want to do is basically say ok the two places place we're coming from the place we're going to we want to take the min and Max tile values of those and to know which tiles to check so the min tile X is just going to be the minimum I don't know if we'd ever actually did did we actually ever do minimum and maximum macros I don't know if we did hand-made platform bed age did we do yeah we didn't so there is a C++ feature that someone was mentioning that actually well okay we don't actually need to use that for this but I was reminded of something just now that yeah that may be good to do in future but anyway so if we go in here we can define a min and Max basically if we want to do a minimum or a maximum of two things so I've got two values whatever they are it's pretty easy to do that check right we can just say if a is less than B then the thing you wanted was a right and if not the thing you wanted was be pretty simple right and the same is true for the maximum if a was greater than B rank then you'd want a otherwise you want B that's pretty much all I'm talking about here very very straightforward really nothing to it but what I would like to do now is say okay so I've got the old player P and I've got the new player P so let's take whatever his abs tile whichever one of those is a is a greater I'm sorry is a smaller for that one and greater absolute tile index oops there we go and then what I have to do is I have to add one because I want one past the maximum tile and again the reason I'm doing that is to make sure that wrapping works properly that makes sense so there we go next I'll let's get that Y in there and then this one will be there we go so basically I just got to get that minimum tile I got to get that back some tile and then I'm gonna loop and add one to it so I'm one passed it and then I loop over those tiles making sure that I I stop when I get to that that maximum one right and again I had to use not equals not less than because I want to support wrapping and you can't support wrapping with the less than because if I went if I under flow here and the min tile was less than then that would be no good all right so hmm what I need to do now say okay we we're only checking things in our tile Z so that the tile Z is not really relevant at this point we then are going to say we're gonna figure out where the best place is to leave the player and that's going to be again since I'm checking against all of these I need to check against multiple of these guys right I have an equation that'll tell me when I hit a wall like that but what I haven't done is figured out well okay if I have tons of walls what would I do right and the answer is just well okay if you've got tons of walls that you're checking against so you're checking against like this wall and this wall and so on right then that puts you in a situation where I've you know I've got here and I'm doing this sort of thing and I test like you know this wall first and I say oh okay you know he hit it here and so that would be some tea that's like some tea that I solved for is look all that tea far right but there was actually later on I find that I I test this wall and there's another tea right this the tea became he called the team near when I did this equation right and I need some way of figuring out well which one do they actually stop at right which one should I use when I loop through all these walls and find all these collision points how do I know which one's the actual collision point I should use well obviously we want the closest one so we just want whichever one let gave us the least value of T right so really what we can do here is say okay we've got a tea that we're solving for and there's some best tea which is really just the closest tea right the key that was the the you know the lowest right if that makes sense we could also call that tea lowest or something or team in right and then what we want to do is say okay the minimum value of T that we want to start with meaning we don't want to entertain anything further than that is just whatever the value would be if we what if we allowed the whole time step to go forwards right so basically if I was going to do the full difference between the new player P and the old player P that's what I would do right and so basically that's just that's just whatever the the player Delta is that this that's this right here right and so that player Delta is is basically the vector that would move us between them so if I take its length right if I take its squared length maybe I'll just I'll leave T min as a squared but I'm gonna actually solve for the actual T so we could also make T be equal to one if that you know what let's just say that T is equal to one let's do it this way so I I made this decision based on this thing I was talking about back here right remember how I said T and D are kind of fungible they have to multiply together when when get when they get to their maximum values they have to multiply out to be wherever the guy would end up at the end of the time step but what I realized just now because I saying like how much what am I going to do it's gonna be better if I just make the length of D be equal to the total movement right right so that's the total movement he should do and then T will be equal to one and that way I can just straight up set it at the beginning and I don't have to really do any other work so that'll be fine I can straight up set to one that's the maximum it should ever be so any collisions that you find had better be lower than that otherwise there were collision that would have happened after the time step would already be finished somewhere out here like you know after he would walk much further or something like that so okay so assuming that that is set up properly now now I just have to go through and if the tile is is not empty I have to test all of the walls and see if they need to update my my my team in right and I really don't need this best player P anymore because I just afterwards I can reconstruct where I should be by looking at the team in right so that's pretty easy so all I need to do here is say all right hmm I need to solve my team in so what I'm going to do is going to test each of the walls of of the of the guy so I need to do like a test wall if that makes sense and so I've got the relative position of the player I'll put that in a up with that in our rel vector here so real new player P I don't remember what we call this like we said we're going to change it to a 3d vector once we had them but we didn't quite yet DXY oh I actually can just use that directly there we go so I could even do yeah they're mine anyway so I've got my relative my relative movement here that is going to multiply by T obviously to give us the the motion that we want so T min times this relative vector would move me from the players current position to wherever oh sorry yeah that's not that's not correct at all what am I talking about that's that's the real that's his position relative to the tile my bad the it's it's the player Delta is the thing I was thinking of their player Delta is the function is the vector that's going to move us from our current location times you know times T to be wherever the the point is that we would end up right so what we need to do now is we need to actually compute this equation that I said we were going to compute for each wall and so we've got it here right we said that it was TS equals W X minus p 0 X the whole thing right over DX right and again DX is just that player Delta right so that's that player Delta X and then the p 0 X that was where we started from and so we know what that is that's real new player pee right that's that's where the player is relative to the tile that's his starting location and we're doing all this relative to where the tile is and then we've got that wall X which is the the the actual point that we want to test right so we've got the wall X there so what we want to do here is we want to make this into something that we can call and this is again going to be the the T result value we want to make this into something that we can call four times with four different values so we can do test wall with like the the rail player X and one of the wall X's right so you know like the min corner the minimum corner of the of the tiles X value for example we want to say that and then we can mm-hmm say what its bounds are in Y so it's its min corner Y and Max corner y so basically this is the location of the wall these are the bounds where the wall is and then we've got our R value that we're actually oh no that's sad the stream is over we're so close to well I guess test well we'll have to wait till tomorrow what are you gonna do all I was going to say is all right so the test well function right it it takes the wall information and then you know it takes the player the real new player whatever the yeah I'm so deflated right now can you see how deflated I am well some days go better than others you know you can't always have the Q&A start at just the right time and I have to admit we were on a streak I think we had two days we had one day yes yes yesterday and then one day I think maybe was Thursday where the Q&A started like exactly when I was done so you know what are you gonna do I guess we'll finish it tomorrow we're mostly there we just have to figure out a way to phrase this so that we can test each wall so we'll just say to do test all four walls and take the minimum see so that's really all we needed to do so what are you gonna do alright okay I will go to the QA deflated as I am of not being able to finish the code I always hate it when we get to a piece of code and I can't finish writing it that something doesn't really happen much in real life right because you just program a little longer but when you've got a schedule to skip to yeah you don't get that opportunity so we're still compiling cuz we're still using the other branch of the code so we don't have to worry about that the code that we post tonight will still compile just fine but we just won't have turned on our actual collision detection yet which we'd like to do and so tomorrow we'll go ahead and do that all right so please post questions now with Q : in front of them so I can see them and please keep the questions and stuff we've done on today's stream as deflating as it was and and if you want to ask things that are or anything for today's dream or previous dreams if you want to ask questions about stuff that's off topic you can do that on the pre stream so come 15 minutes early tomorrow to the stream and I'll be on answering questions that are off topic but please try to keep the ones in the official Q&A here to the actual stuff we coded today are on previous days so deflating stopping programming in the middle of stuff of something is so unsatisfying yeah that's all I can really say about that she's very very unsatisfying yeah I missed when you changed from F P 2 ft when why did you decide to switch so basically I can explain that in a little more detail here so basically the reason that I decided to go with F of T and you remember I was kind of hemming and hawing about it on Friday I couldn't decide which one I wanted to do and so on and so here's the reasoning behind it so f of P right all right I should say F of P is what I call it search in P versus certainty right so search and P has some nice properties right search and P has is is bounded in in iterations right where a certainty is unbounded in iterations to produce the correct answer right search in P allows sort of smoothly ignoring geometry bugs whereas this gets stuck right geometry bugs right so these are like pluses for search and P and minuses for this but search in P has a pretty big negative that search and T has is positive and there's there's really two positives one of which I don't think we care about much but one of which we really do so search in P one of the huge negatives is you have to be able to search MP right where a search and T doesn't have to do that so you never need to know you never need to know need to form the search space the space right the P space and what that means is like with search and P right if you imagine I'm I've got some crazy collision geometry here in order to search for the closest point to something like here which is what search and P is doing it's got to be able to actually know how to look through the space and figure out what that closest point is search and T never does that sir he just tries to drive in a straight line if it hit something it changes direction that's it so it never even knows really necessarily what the space looks like and that can be much more efficient right so this is definitely the more efficient algorithm in the normal case right the other problem is this is handles like bounciness better right and this doesn't and that's because with search and P you don't really know how many times you would have collided with a wall to get where you are and stuff like that so this is a little bit better if you want bouncy things this is better usually if you get basically this is a plus up until the point where you want things to bounce a lot and then this becomes a plus right and so really search and tea with fixing this unbounded in iterations problem so just full-on saying will produce the wrong result by bounding it arbitrarily just is going to be way more efficient than this is and so I just kind of decided this is you know just not gonna be a good algorithm for us to choose because we don't really care that much about this and we just give up too much because we have to do all this extra work to produce the space in the witness we have to produce the space anyway for other reasons and so that's why I chose to well I even choose to do this this actually just turned out to be the most efficient algorithm in the witness because of the way we were doing things but this is gonna be way more efficient for a Mahiro I think because we never build these spaces so hopefully that makes some sense how does the aim handle the state of the two separate players when they are on different floors well the collision detector just works right because it's it's using the the tile Z of wherever the entity that is that it's colliding so that's just that's doesn't matter it's really the rendering that we have to worry about because we don't know what we're going to do when people go off screen what we may do is just say that only the main character determines where the screen is and the secondary character can't go can't leave the screen we might just make that rule so that we don't have to have like split screen or something that's going to be weird why is the code complexity for piece art so much greater than T search so the reason is because of that of that process of searching so basically i've already told you you know 25 percent or 50 percent of the code necessary like this is not that far from the complete code that we're actually going to need to implement certainty it's just iterating doing this a bunch of times right and we're basically all we're gonna do when we move to a better collision detection than what we're doing with them then just point verses infinite wall when we move to like circle or ellipse versus sort of arbitrary shape or something right all we're gonna do is have a fancier set of equations here like a slightly fancier set right that's all that's gonna happen but the algorithm is the same it's still just like okay drive along the line see where you when you hit something change the direction you're driving drive Samora see if you hit something that's all that's it that's all that happens it's nothing else going on and so given that that's the case it's just really simple code complexity wise to implement this it's just the simplest darn thing and if you want to do search in P it's much harder search and P is basically a closest point problem it says take all the geometry that you've got whatever it is that the person's walking through take a point and I want to know the closest point on where you know to that point and so what you have to do is you then have to know how to be able to search firstly it's in two things you have to be able to search all along the edge of all the geometry to see what the closest point actually would be which is very complicated and you have to do that for another shape right because whatever the shape the player is it's not just really closest point it's closest extruded point so it's like it's the closest center of some collision shape right so in the case of a player who's represented by an ellipse or something it's the closest place and ellipse could be that's close to that point or something right and so you have to like minkowski your geometry or do other kind of stuff there it's complicated whereas we will just be able to bake that right into these when we do them you'll see so that's complicated but what's also complicated is the fact you have to know whether the player could have gotten there so you still have to end up doing a passing thing to see whether the player could get there because you don't want them to be able to tunnel through walls with this system right and so depending on what you actually have this is either very expensive or free in the case of the witness it was free to do this but in the case of this game it would be very expensive and this is going to be much cheaper why not treat the map as a matrix and validate objects and its collisions through coordinates what problems can appear with this mindset I'm not really sure what you mean by that if the map itself was a matrix that's really no different than what we have now which is just a tile map and the problem is that when you look to see you need to know between two points you need to know if you hit anything in between and so you still have to write this collision code for the matrix thing but really remember we're gonna be doing something better than a tile map so we're just using the tile map right now because that's all we actually have is a world representation but we're actually gonna be allowing all kinds of crazy stuff for closing section like we're gonna be allowing arbitrary geometries for close detection so we don't a matrix really wouldn't be able to store the world anyway so your towels are the 6:17 by ten blocks I'm fuzzy on collision detection as the player moves from tile to tile I get lost on the world coordinate tiles coordinate and screen coordinates still I guess well I mean we've kind of gone over this a bunch of times so I'm not sure how to elaborate on it on anyway other than how we already have basically our tiles you can just think of the tiles as a giant 4 billion by 4 billion array right so we've got ABS tile X and ABS tile Y for a person's location and ABS tiles II just think of these as a giant 4 billion by you know by 4 billion by 4 billion world ok so it's a giant cube made up of tiny cubes that's 4 billion by 4 billion by 4 billion right you know let's let's go over here okay so this is our world right this is four billion long this is 4 billion long this is for a billion long in tiles so each tile is this tiny little thing right and then at any given time we take out a little slice of that world right that's seventeen by ten or whatever we said it was seventeen by nine something like that seventeen by ten who knows I can't remember what we're drawing something like that we take out a little slice from somewhere in there and we draw it on the screen as the tile map right that's all we're doing now we have a sparse storage mechanism that breaks up this cube since we can't store for a billion by four billion by four billion that that basically just stores the places where there's actually part world data in them and so we have these tile chunks that are pieces that are just a storage thing but you don't have to think about those where you think about collision detection because Visnic doesn't care it doesn't care where that data is coming from it's just going to do the iteration of the absolute tile and disease right and so for the collision detection all that happens is we just pull out those tile use and go okay take where the player was and take where he's going and let's check all of the tiles that he could that are around there to see if any of them are solid and if they are figure out where he would hit them and and stop his motion there and that's what we were trying to write right now can this week's time to 3d collision yes the equations are the same in 2d and 3d could you check collisions by looking at the players position and seeing if it's in the inner side of the vectors along the walls like it's up from the bottom well vector it's to the right of the left ball vector yes as an optimization you can definitely do that so one optimization that you can do and we'll kind of we'll probably get to some of these well it's kind of hard to say which exactly ones we'll end up doing as depends how we do things but if you imagine that you've got a guy here's our p0 and here's our D so there's our direction and we're going along here and we want to know when we get this thing so we're gonna check against these walls right here are all the collision points we would find right here's when he hits this wall here's when he hits this wall here's where he hits this wall and here's where he hits this wall now these two collisions would get thrown out immediately because they're outside the bounds that we allowed for the wall so we would throw those out right but these two collisions are both valid and then we would take the closest one which is this one and what you were talking about is can we use the information about where the player is to maybe do less work here at least I think that's what you were saying and the answer is yes we could what we could do is since we know that these walls basically have a sightedness to them right we basically know that in here you cannot stand and so the walls kind of have a direction they kind of point outwards if you will right what we could do is see which direction the player is moving or which direction he is which direction we could see where the player is relative to the thing and only take those walls that are pointing towards him because we know he can't ever point he can't ever hit a wall facing away from him because he hit some other wall first so we could just flat-out reject these two because they are not pointing towards him only these are pointing towards him and how would you compute that well it's our old friend the inner product a transpose V we'll compute that how will it compute that well you remember it maps one vector onto another it is a B cosine theta and what does facing someone well if we took the sort of direction from the the tile to the guy right we know that it's this direction we want vectors that are not pointing backwards from that vector right we want these vectors not these vectors so what we can do is say all right the angle between those guys the theta between this and this and this and this right has to be less than 90 degrees right if the angle between them was greater than 90 degrees you'd be in trouble what do we know about cosine theta well cosine theta right if cosine if that angle if theta is less than 90 degrees right then cosine is positive but if it's greater than 90 degrees right then it's negative until it flips back around again right so we compute that dot product we could actually just use the sine of a transpose B to tell us which of these would actually be in play so you absolutely could do what you were saying it's just an optimization but it'd be a nice optimization right so again we'll look at stuff like that a little later on what's your point on zero length vector normalization and what behavior does your code have so we haven't really quite gotten to that yet but yeah if you notice here we don't have any normalization happening when things are zero because we're only looking at one point oh right we're only looking at things that are greater than 1.0 so we we would never divide by zero here because we'd be fine but if you were trying to do something normalization wise then yes you have to worry about that so hmm I guess I deleted that because I hadn't thought of my infinite swirl yet so basically if you think about what happens when we do that that canonical equation where I said we had the new length we want for a vector divided by the old length we want write times the vector itself gives us a new vector that's that's a different length with this length right when I said that obviously it's it's also again that thing of length of a equals it cannot be equal to zero right because it's the same as before where I saying it you can't divide by zero value now we didn't actually ever that cuz condition can't happen here so I was not bringing it up yet but when we get to that we'll talk about it a little bit more basically what happens is before you do anything with a vector to change the vectors length you have to be sure that its length currently isn't zero because if it's length were zero that would means that it has no direction it's just here it doesn't it doesn't point anywhere it's so you can't change its length there's no way to know what it's like would have been and so that's something that you have to handle on a case-by-case basis you need to know what was the purpose that you were doing you know what were you trying to accomplish when you did this and when you and when you know what the purpose is you know how to handle the zero case you know what you should do in that case right how can sometimes players enter glitching lis through the corners of walls or fall through them is that an art mistake or programming the answer is it can actually be either so basically you can have two you can have two conditions happen there one is that the collision geometry is just wrong right and so one case is I've got a thing and it looks like that right the collision geometry looks like this and the player is only that big and he fits between them and then he can glitch through it so even though maybe it's drawn like a solid thing the collision geometry is wrong and he can glitch through it another one's a programming bug the programming bug happens when the collision resolution the collision resolve is not robust in the face of twiki situations right so let's say like I'm jamming into a corner here you know in that corner basically has you know a couple of different things of budding in it like this you know something like that and maybe this is empty here and set to here and so these two things kind of abut and I've got this thing where I can glitch through there because I'd I'm not conservative about how I'm checking for the collision with my guys somehow right that could certainly occur it occurs in cases I mean I'd have to know the specific code to know why the glitch was occurring right but you can certainly have just things that are numerical precision problems and people not thinking through how to do the collision right or whatever so it may not be art can we look at our dropped frames it's been quite choppy so it looks a little dropping but not too much I don't know I don't know we're people on the stream in general having a problem let's see I don't know if anyone yeah can anyone tell me if we were having choppiness problems I don't know if we're having chopping his problems or not yeah so we're almost done here I think I'm day 47 we've got what have we got about ten minutes left okay so I think kuru I think that was just you who was dropping the frame sorry don't blame my isp yet it's not their fault this time alright so that it for questions so we can end early yeah I don't see any more questions so I think I'm a I don't know how to I I feel like we've now gotten too huge for for I want to kind of delete this so we're not taking up so much space there we go I'm afraid that that krita's gonna run out of room for us here all right so we'll put that back like that for next time there we go okay so I think that's it I don't see any more questions I'm surprised that the new timer code actually worked that's kind of surprising to me I was expecting it to roll over and die and really we only had one problem which is that it I didn't actually have the thing stop telling us when the stream was already started but that's okay so that's good the stream now supports fractional our boundaries just quite robust all right so yeah this was a bit disappointing today because I hope to get to that and I guess you know a large part of the problem was I decided to talk about vector lengths which you know takes up some time but what are you gonna do what are you gonna do storm buzzes do you need to do the math when doing solid walls and objects or is that just basic program arithmetics well you need to do the math regardless of what the thing is are I'm not sure you mean by solid walls aren't all walls solid yeah I'm sorry I don't quite understand the question if you want to rephrase it though I can answer it so yeah it doesn't look like any questions so I think we are done we can call it and everyone can you know go program get program on their own I actually wanted to go fix something in the witness just now I'm Mei she wrote me back about a thing that I was doing wrong that was that about iterating over collision geometry that I was like I'm not sure how to I don't actually know how to tell what this material is because I don't know the engine very well and so now that I know that I'd like to go do that so maybe I will go do that if that makes sense and of them I think he means graphically walls maybe hollow inside so doing the math of the whole object or just the outer collidable parts oh so well it if you think about it though it doesn't matter right because if a thing if an object is solid right so if I have a solid object and I have a hollow object but that stills got you know it's got walls right there's no difference between these two things as far as the collision detection is concerned if a guy is walking into this thing he still stops here regardless right so the equations are the same whether he's in a solid thing or a hollow thing it doesn't matter if just all that matters is the first wall he could run into and they're the same in both cases right you only for collision detection you only care about the boundary of the thing you don't care what's inside it because you can never get inside it that's the whole point the closed reduction is to prevent that right all right so I think that's it I will go ahead and call it for now we will close this down hello awesome I kind of like it when he pops up I can't wait to do his animation controller his animation controller is gonna be so much fun and that's what we'll do it right after we finish the collision detection but like getting him hopping along is gonna be the most fun thing to do and it will also be the thing that most motivates us to go do the renderer because once we do the hopping we'll really want to be able to bend his body like to emphasize the hop but of course we can't with our draw a bitmap code that we have right now and so that'll be like the perfect thing to make us want to go do like a nice renderer that can do like bending of stuff right so yeah anyway okay so I'm gonna go ahead and close this down and come to me there we go let's see okay so thank you very much for joining me this evening I'm sorry that we didn't quite get to finish the thing that I wanted to finish so we will try to do that tomorrow and then we can move on to doing some more animation sorts of stuff although we may actually want to do a little more collision detection because now that we've got two guys in there we probably want to throw like a monster in there and and collide against the monster and move it have different moving things colliding so well well well sort of probably we probably will have to do maybe the rest of this week on collision because we'll want to do all that stuff and get out to doing a nice rounded volume for the player and so on so we've realistically speaking we probably have a fair bit more collision detection to do but I didn't want to finish just the simple wall case the simple vertical horizontal wall case today so we could get on another stuff so sorry about that but we'll finish it up tomorrow and then we'll move on to sort of the more complex law cases to sort of see how to build a more interesting closure detector that doesn't work things that are better better for the field the game so thank you very much for joining me is been a pleasure coding with you as always if you would like to pre-order the game and get the source code you can do that at handmade hero org and you can download the source code every night I upload it every night you'll get a link in your email and you can use that link over and over and over again to download the source code every night you just save the link that comes and you can always go back there and download the latest source so if you want to do that you can do that a hammer here or if you want to just support the video series you can subscribe to our patreon as well which we have which is right here and then if you want to study the series more in depth we also have a news and forum site that's got a bunch of stuff on it that you might want to use it's got the schedule for the week in case you want to know when we're broadcasting each week it's got an episode guide so you can catch up on previous episodes that's really great it's got time coded videos and all this stuff it's pretty awesome we've got coding resources which is like ports to Mac OSX and Linux and stuff so if you're trying to run out in from platform you can check that out and we also have a code discussion board so if you want to ask questions or sort of talk more about a particular episode that is the place to do it and hey let the timer even still worked check that out alright so thank you very much for joining me I will be back tomorrow 8 p.m. Pacific Standard Time tomorrow our standard time slot since John is not doing to power Denver tomorrow and so I certainly hope see you there and have a wonderful Monday I'm sorry Wednesday either way take it easy everyone
Info
Channel: Molly Rocket
Views: 11,024
Rating: 5 out of 5
Keywords: Handmade Hero
Id: 5KzJ0TDeLxQ
Channel Id: undefined
Length: 83min 17sec (4997 seconds)
Published: Tue Jan 20 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.