A Hit, A Hit, A Very Palpable Hit
We've got lasers firing and astroids asteroiding, or whatever it is they do, so now we need to be able to actually hit objects with our lasers. And the reverse, to know when an object has been hit by a laser, or another object for that matter.
Since starting this foray into game development I've continually been impressed about how supportive and helpful the Pico-8 community is. The forums have loads of great posts with comments that are usually helpful and questions ask to help someones understanding. Very fun to be a part of it in whatever small way I can.
Updating bullets
As the guide in Pico-8 Zine #3 teaches the bullets (lasers in this case) need to have a hitobx to determine when they collide with something. With the hero laser there are two "beams" so we'll need to add a hitbox for each one. Update the bulletconstruct function with:
obj.hitbox = {x=0, y=0, w=8, h=8} |
This uses the entire sprite for a hitbox, but I think it makes sense because the "beams" are spread apart and if something is hitting it from the side it's still hitting it. Ya, I think that makes sense.
Next, add a hitbox (and an hp value which we'll get to later) to the astroid in the asteroidconstruct function:
obj.hitbox = {x=0, y=2, w=8, h=8} obj.hp = 5 obj.des = 0 |
The hero will also need a hitbox in the _init function add:
hitbox = {x=4, y=3, w=8, h=8}, |
Actually Doing The Hitting
Everything now has a hitbox so it's time to copy/integrate some more code from the DOM8VERSE article. In the foreach asteroids loop inside the _update function add a bullets loop:
foreach(asteroids, function(asteroid) asteroid.update(asteroid) foreach(bullets, function(bullet) if (asteroid.hp > 0) then if (collide(asteroid, bullet)) then del(bullets, bullet) asteroid.hp -= 1 -- knock it back a little asteroid.position.y -= 2 asteroid.position.x -= asteroid.dir + asteroid.dir if(asteroid.hp <= 0) then asteroid.explode(asteroid)end end end end) end) |
Inside the inner bullets foreach we're checking the asteroid.hp to make sure it's not 0 then checking to see if a bullet is colliding with the astroid. If a bullet has hit the astroid it is deleted from the bullets array, the astroid's hp is decremented by 1 and it is blasted back a little. Also, if the asteroid's hp is <= 0 (not sure if it can actually go below zero since it's being decremented by 1 each time, but better safe than sorry) the asteroid's explode function/method is called.
I used the same collide function as the guide:
function collide(obj, other) if other.position.x+other.hitbox.x+other.hitbox.w > obj.position.x+obj.hitbox.x and other.position.y+other.hitbox.y+other.hitbox.h > obj.position.y+obj.hitbox.y and other.position.x+other.hitbox.x < obj.position.x+obj.hitbox.x+obj.hitbox.w and other.position.y+other.hitbox.y < obj.position.y+obj.hitbox.y+obj.hitbox.h then return true end end |
It's a great way to see if two objects have connected their hitboxes and I'm not sure if I can improve it.
Exploding asteroids
After five hits by a laser it's bye bye asteroid, but it'd be cool to have it sort of come apart and degrade. In the asteroidconstruct function add:
obj.explode = function(this) this.sprite = 18 end |
This function/method (need to look up what the proper term is for lua functions on an object) simply set's the asteroid's sprite to a new one. Here's a screeny:
Changing the sprite once isn't all that great, but changing it again after a few cycles is a little cooler. Add these lines to the update function/method in astroidconstruct:
obj.update = function(this) this.position.y += 1 this.position.x += obj.dir -- remove it when it goes off screen if(this.position.y>127)then del(asteroids, this)end if(this.hp <= 0)then this.des += 1 end if(this.des >= 20)then this.sprite = 19 end if(this.des >= 40)then del(asteroids, this) end end |
Now the asteroid's update function will check if the des attribute is no longer 0 (des for destroyed, heh) and if so increment it. After des is greater than 20 the sprite changes again and after it reaches 40 the astroid is removed.
It's pretty much the effect I was going for.
Ship Bashing
Destroying asteroids is one thing, but what happens if they crash into our hero? The code to check for hero hits is pretty much the same as for an asteroid. I created an update function on the hero object setup in the _init function and moved some code from the _update function into it:
update = function(this) -- text = "updating hero..." b0=btn(0) b1=btn(1) b2=btn(2) b3=btn(3) b4=btnp(4, 0) b5=btn(5) if (b0 or b1 or b2 or b3) then move_hero() end if (b4) then hero_fire() end if(hero.des > 0)then hero.des += 1 end if(hero.des >= 20)then this.sprite = 21 end if(hero.des >= 40)then this.sprite = 22 end if(hero.des >= 60)then gameover() end end, |
The button check code is now scoped to the hero which makes it a little more readable I guess. Notice the hero.des check pretty much the same as the asteroid's. When the hero reaches 0 the gameover function is called though:
function gameover() text = "game over man" if(btn(4) or btn(5))then run() end end |
This simple function sets the text printed to the screen then calls the run function when button 4 or 5 is pressed. The run function essentially resets the cart.
Also, we'll add an explode function/method to the hero:
explode = function(this) this.sprite = 20 this.des = 1 end, |
Once again update the _update function to check if an asteroid has collided with the hero. Inside the foreach asteroids loop add:
-- asteroid collids with hero? if (collide(hero, asteroid) and asteroid.des == 0 and hero.des == 0) then sfx(01) asteroid.hp -= 1 hero.hp -= 1 -- knock it back a litte asteroid.position.y -= 2 asteroid.position.x -= asteroid.dir + asteroid.dir if(asteroid.hp <= 0) then asteroid.explode(asteroid) end if(hero.hp <= 0) then hero.explode(hero) end end |
Pow, now asteroids can take out our plucky hero.
Conclusion
It's fun to have a game over state and to blast some space rocks. I'm pretty satisfied with the way things explode too.
I'm kind of going for the effect of things exploding in space like the movie Gravity, but you know in 8 bit.
Feels good to make progress...
Party On!
Thanks man! The game I’m prototyping could really use this.
I want it to be hard and precise,but maybe 1 pixel is a bit top hard to hit ;)
[Please log in to post a comment]