// the game itself var game; // global game options var gameOptions = { // target rotation speed, in degrees per frame rotationSpeed: 3, // knife throwing duration, in milliseconds throwSpeed: 150, // minimum angle between two knives minAngle: 15 } // once the window loads... window.onload = function() { // game configuration object var gameConfig = { // render type type: Phaser.CANVAS, // game width, in pixels width: 750, // game height, in pixels height: 1334, // game background color backgroundColor: 0x444444, // scenes used by the game scene: [playGame] }; // game constructor game = new Phaser.Game(gameConfig); // pure javascript to give focus to the page/frame and scale the game window.focus() resize(); window.addEventListener("resize", resize, false); } // PlayGame scene class playGame extends Phaser.Scene{ // constructor constructor(){ super("PlayGame"); } // method to be executed when the scene preloads preload(){ // loading assets this.load.image("target", "target.png"); this.load.image("knife", "knife.png"); } // method to be executed once the scene has been created create(){ // can the player throw a knife? Yes, at the beginning of the game this.canThrow = true; // group to store all rotating knives this.knifeGroup = this.add.group(); // adding the knife this.knife = this.add.sprite(game.config.width / 2, game.config.height / 5 * 4, "knife"); // adding the target this.target = this.add.sprite(game.config.width / 2, 400, "target"); // moving the target on front this.target.depth = 1; // waiting for player input to throw a knife this.input.on("pointerdown", this.throwKnife, this); } // method to throw a knife throwKnife(){ // can the player throw? if(this.canThrow){ // player can't throw anymore this.canThrow = false; // tween to throw the knife this.tweens.add({ // adding the knife to tween targets targets: [this.knife], // y destination y: this.target.y + this.target.width / 2, // tween duration duration: gameOptions.throwSpeed, // callback scope callbackScope: this, // function to be executed once the tween has been completed onComplete: function(tween){ // at the moment, this is a legal hit var legalHit = true; // getting an array with all rotating knives var children = this.knifeGroup.getChildren(); // looping through rotating knives for (var i = 0; i < children.length; i++){ // is the knife too close to the i-th knife? if(Math.abs(Phaser.Math.Angle.ShortestBetween(this.target.angle, children[i].impactAngle)) < gameOptions.minAngle){ // this is not a legal hit legalHit = false; // no need to continue with the loop break; } } // is this a legal hit? if(legalHit){ // player can now throw again this.canThrow = true; // adding the rotating knife in the same place of the knife just landed on target var knife = this.add.sprite(this.knife.x, this.knife.y, "knife"); // impactAngle property saves the target angle when the knife hits the target knife.impactAngle = this.target.angle; // adding the rotating knife to knifeGroup group this.knifeGroup.add(knife); // bringing back the knife to its starting position this.knife.y = game.config.height / 5 * 4; } // in case this is not a legal hit else{ // tween to throw the knife this.tweens.add({ // adding the knife to tween targets targets: [this.knife], // y destination y: game.config.height + this.knife.height, // rotation destination, in radians rotation: 5, // tween duration duration: gameOptions.throwSpeed * 4, // callback scope callbackScope: this, // function to be executed once the tween has been completed onComplete: function(tween){ // restart the game this.scene.start("PlayGame") } }); } } }); } } // method to be executed at each frame update(){ // rotating the target this.target.angle += gameOptions.rotationSpeed; // getting an array with all rotating knives var children = this.knifeGroup.getChildren(); // looping through rotating knives for (var i = 0; i < children.length; i++){ // rotating the knife children[i].angle += gameOptions.rotationSpeed; // turning knife angle in radians var radians = Phaser.Math.DegToRad(children[i].angle + 90); // trigonometry to make the knife rotate around target center children[i].x = this.target.x + (this.target.width / 2) * Math.cos(radians); children[i].y = this.target.y + (this.target.width / 2) * Math.sin(radians); } } } // pure javascript to scale the game function resize() { var canvas = document.querySelector("canvas"); var windowWidth = window.innerWidth; var windowHeight = window.innerHeight; var windowRatio = windowWidth / windowHeight; var gameRatio = game.config.width / game.config.height; if(windowRatio < gameRatio){ canvas.style.width = windowWidth + "px"; canvas.style.height = (windowWidth / gameRatio) + "px"; } else{ canvas.style.width = (windowHeight * gameRatio) + "px"; canvas.style.height = windowHeight + "px"; } }And we built a physics game without using physics thanks to trigonometry, Phaser 3 and its tweens. Download the source code.
Build a HTML5 game like “Knife Hit” with Phaser 3 using only tweens and trigonometry – hitting knives
Read all posts about "Knife Hit" game
I know you enjoyed the first part of my Knife Hit HTML5 prototype built using only tween and trigonometry, and here is the second step of the game: this time we’ll check if the knife we throw hits one of the knives that already landed on the target.
But most of all, we are doing it without trigonometry.
First, let’s have a look at the game:
Click or tap to throw a knife. Keep throwing knives until you hit a knife already on the target. If you have a mobile device, play directly on this link.
How can we do this without physics? It’s easy! When a knife lands on the target, it hits the target while it’s rotated by a known angle. We save the angle as a custom knife property.
When we throw next knife, we check if the difference between the angle of the target at the moment of the impact and the angle of the target of landed knives. If this angle is smaller than a given amount specified in the game options, then we can say the knife hit another knife.
Let’s have a look at the source code, commented line by line: