Collisions: Making Objects Interact
Most games involve objects that interact at some point. For this tutorial, we’re going to assume that your objects interact at one fixed point.
I’m going to go ahead and add code so that each rain drop will check if it has hit the bucket when it lands.
That’s going to involve the following steps:
- Let the rain “see” the bucket (import bucket into rain).
- Add a method to bucket to check if an object is directly over its opening (check for a collision).
- Insert a new step into our
rain.move
method so that when the rain moves it checks for a collision with the bucket. - When the rain hits the bucket, make something happen!
For a more generic introduction to collisions, see my collisions overview.
1. Letting the rain “see” the bucket
My first step will be importing my bucket into my rain file, since now my rain drops need access to the bucket.
rain.ts
import {bucket} from './bucket';
At this point, I can now write new code in rain.ts
that references my bucket
.
2. Adding a Collision-Detection method to Bucket
Now I want the rain to know when it hits the top of the bucket, so I’m going to add a new method to my bucket object called “isInBucket” which checks if a rain drop is in the position to fall into my bucket.
Note: there’s no “right” way to decide where this collision logic goes since it’s a feature of both a bucket and a raindrop, but I think it’s a little tidier to write the if statements for hitting the bucket inside of the bucket. If we changed our drawing code to be fancier, for example, we would probably end up updating both bucket.draw
and bucket.isInBucket
, so it’s nicer having both of those bits of code in the same module.
Regardless, I recommend writing comments alongside your “if” statements in this collision code because it gets tricky to keep track of. Any time you’re checking for collision with a rectangle, you’re likely going to be using a pattern like this:
const someObjectThatYouCanCollideWith = {
isColliding (x, y) {
if (
x >= this.right // is it to the right of my right
&&
x <= this.left // and to the left of my left
&&
y >= this.top // and under my top
&&
y <= this.bottom // and under my bottom
) {
return true
} else {
return false
}
}
}
Here is the code for my “bucket” example:
bucket.ts
export const bucket = {
...
/* Check if point x,y is entering our bucket
-- i.e. passing through the "lid" of the
bucket */
isInBucket (x : number, y: number) {
if ( // If...
y > this.top // it's past our "lid"
&& // and
y < this.top + 30 // + but not too far under
&& // and
x > this.x// + right of our start
&& // and
x < this.x + this.width // left of our edge
) {
return true
} else {
return false
}
}
}
3 & 4. Check each rain drop when we move it and fill the bucket if it hits!
I already have code that runs once per rain drop when we update the position of our rain drops. I’m going to go ahead and use that code to detect my collisions.
rain.ts
export const rain = {
...
move () {
...
this.raindrops.forEach(
(drop)=>{
...
if (bucket.isInBucket(drop.x,drop.y)) {
// Add to water in bucket
bucket.waterAmount += 1;
// Move rain drop back up to top
// so it can be a "new" raindrop
drop.y = -10;
}
...
}
)
}
}
Next step: make a score board.