A First with Gameplay
This step admittedly added more features,
than i was aiming for with this project series,
that is why i will likely spend some follow up projects cleaning up some features to handle them properly.
We now have:
- Mouse controlled physics objects (Paddle)
- Static Physic Objects (Bricks)
- Gameplay logic
- Loose and Win conditions
- Fullscreen mode
Features
Hit "Ctrl + Enter" to go into fullscreen mode.
Control the paddle at the bottom with your mouse.
Press "Space" to release the ball, that is attached to you ball.
If a ball hits a brick, the brick gets damaged and after 3 hits it is destroyed.
Destroyed bricks have a chance to grant you a new ball or to increase you paddle size.
If a ball hits a brick, the brick gets damaged and after 3 hits it is destroyed.
Destroyed bricks have a chance to grant you a new ball or to increase you paddle size.
Upcomming
As described in the beginning, i will have to properly manifest some features.
I can make a fixed concept for gamestate transition between "Won" "Playing" and "Lost" and make them more interesting.
The mouse input and fullscreen mode should get more abstracted, adding more interactivity.
I also realized that, we may need a more defined way to add or remove entities to and from the game.
Details
Every element in the game has their own entity.
- Paddle
- Brick
- Ball
And they all handle collision events a little different.
Here the Ball defines how the paddle changes it velocity in a certain direction depending on where it hit the Paddle.
Also if the Ball collides with the bottom border of the screen, it will be destroyed.
export class Ball extends Entity { // ... public onCollision(other: PhysicsProxy, collision: Collision): void { this.no_collision_for_s = 0; this.speed_up_tick = 0; // steer the ball if it hits the paddle if (other.reference === game.model.paddle) { const paddle = other.reference as Entity; const paddle_center = paddle.hit_box.center; const ball_center = this.hit_box.center; const distance = ball_center.cpy().sub(paddle_center); const angle = distance.angle(); const source_angle = this.velocity.angle(); const speed = this.velocity.length(); const new_velocity = Vector2D.fromAngle(angle * 0.5 + source_angle * 0.5, speed); this.velocity.set(new_velocity); } } public onWorldCollision(distance: Vector2D): void { this.no_collision_for_s = 0; this.speed_up_tick = 0; if (distance.y > 0 && !game.model.isGameWon()) { // hit the bottom game.model.removeEntity(this); } } }
The Brick simply looses hp on collision and if it dropped to 0 it is destroyed and gives a buff based on random chance.
export class Brick extends Entity { public hp: number = 3; public max_hp: number = 3; // ... /** * * @param other */ public onCollision(other: PhysicsProxy, collision: Collision): void { assert(other.reference instanceof Entity) // on collision if (other.reference instanceof Ball) { this.hp--; if (this.hp === 0) { window.game.model.removeEntity(this); const bonis = Math.round(Math.random() * 100); if (bonis < 30) { const position = this.hit_box.center.cpy(); const entity = new Ball(position); entity.randomizeVelocity(); window.game.model.addEntity(entity); } else if (bonis < 60) { game.model.paddle?.increaseSize(); } } } } }
The paddle on the other hand does actually not react on collision and is counted as "static" to the physics engine, only moving through direct mouse control.
export class Paddle extends Entity { public has_ball: boolean = true; constructor( position: Vector2D ) { const image = window.game.assets.getImage("brick-metal"); super(position, image); this.physics.static = true; this.hit_box.size.set({x:100,y:20}); this.render_box.size.set({x:100,y:20}); } }
Comments