Phaser P2 Player kick ball and add Impulse on hit - javascript

I need help for a school project and want to code a game like Headsoccer in Phaser with P2 Physics, I already have two players, two goals and a ball that can collide with each other. Now I want to add a kick animation and a hitbox for the kick which when kicking the ball applies an impulse or some sort of force from the kick. How could I do that?
Thanks.
Here is some Code
Would be nice if you can give me some advice on how to structre my code better or if i can change something
function create() {
game.world.setBounds(0, 0, 800, 500);
game.physics.startSystem(Phaser.Physics.P2JS);
//game.physics.p2.enable([ player, player2, fussball, goal, latte ], true);
//game.physics.arcade.gravity.y = 200;
game.add.tileSprite(0, 0, 800, 600, 'Spielfeld');
game.physics.p2.gravity.y = 600;
goal = game.add.sprite(35, 428, 'goal');
game.physics.p2.enable(goal,true);
goal.body.static = true;
goal.physicsBodyType = Phaser.Physics.P2JS;
goal.body.data.shapes[0].sensor = true;
player = game.add.sprite(100, 500, 'player');
game.physics.p2.enable(player,true);
player.anchor.setTo(0.5, 0.5);
player.body.collideWorldBounds = true;
player.body.fixedRotation = true;
player.body.clearShapes();
player.body.loadPolygon('playerPhysics','player');
player2 = game.add.sprite(500, 500, 'player');
game.physics.p2.enable(player2);
player2.anchor.setTo(0.5, 0.5);
player2.body.collideWorldBounds = true;
player2.body.fixedRotation = true;
var shape = new p2.Circle();
ball = game.add.sprite( game.world.centerX, game.world.centerY, 'ball');
game.physics.p2.enable(ball);
ball.anchor.setTo(0.5, 0.5);
ball.body.collideWorldBounds = true;
ball.body.data.gravityScale = 1;
ball.body.clearShapes();
ball.body.addCircle(shape);
My game looks like this, and I showed the hitbox of Player 1 and Goal.

Since we don't have any code to work with, I'm assuming you have something like the official Impact Events example code in place.
In that case, you could play an animation when one of the players collides with the ball. In the example above, that would be changing this method to play the animation (instead of changing the sprite's alpha):
function hitPanda(body1, body2) {
body2.sprite.alpha -= 0.1; // Remove/replace this line.
// Add the playing of the kick animation.
body1.play('kick');
}
In this same area you could then apply a speed boost to the ball.

Related

Phaser 3: Change "Hitbox"/Interactive area of sprite without physics

The game I'm creating doesn't require any physics, however you are able to interact when hovering over/clicking on the sprite by using sprite.setInteractive({cursor: "pointer"});, sprite.on('pointermove', function(activePointer) {...}); and similar. However I noticed two issues with that:
The sprite has some area which are transparent. The interactive functions will still trigger when clicking on those transparent areas, which is unideal.
When playing a sprite animation, the interactive area doesn't seem to entirely (at all?) change, thus if the sprite ends on a frame bigger than the previous, there end up being small areas I can't interact with.
One option I thought of was to create a polygon over my sprite, which covers the area I want to be interactive. However before I do that, I simply wanted to ask if there are simpler ways to fix these issues.
Was trying to find an answer for this myself just now..
Think Make Pixel Perfect is what you're looking for.
this.add.sprite(x, y, key).setInteractive(this.input.makePixelPerfect());
https://newdocs.phaser.io/docs/3.54.0/focus/Phaser.Input.InputPlugin-makePixelPerfect
This might not be the best solution, but I would solve this problem like this. (If I don't want to use physics, and if it doesn't impact the performance too much)
I would check in the event-handler, if at the mouse-position the pixel is transparent or so, this is more exact and less work, than using bounding-boxes.
You would have to do some minor calculations, but it should work well.
btw.: if the origin is not 0, you would would have to compensate in the calculations for this. (in this example, the origin offset is implemented)
Here is a demo, for the click event:
let Scene = {
preload ()
{
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
},
create ()
{
// Animation set
this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('brawler', { frames: [ 0, 1, 2, 3 ] }),
frameRate: 8,
repeat: -1
});
// create sprite
const cody = this.add.sprite(200, 100).setOrigin(0);
cody.play('walk');
cody.setInteractive();
// just info text
this.mytext = this.add.text(10, 10, 'Click the Sprite, or close to it ...', { fontFamily: 'Arial' });
// event to watch
cody.on('pointerdown', function (pointer) {
// calculate x,y position of the sprite to check
let x = (pointer.x - cody.x) / (cody.displayWidth / cody.width)
let y = (pointer.y - cody.y) / (cody.displayHeight / cody.height);
// just checking if the properties are set
if(cody.anims && cody.anims.currentFrame){
let currentFrame = cody.anims.currentFrame;
let pixelColor = this.textures.getPixel(x, y, currentFrame.textureKey, currentFrame.textureFrame);
// alpha > 0 a visible pixel of the sprite, is clicked
if(pixelColor.a > 0) {
this.mytext.text = 'Hit';
} else {
this.mytext.text = 'No Hit';
}
// just reset the textmessage
setTimeout(_ => this.mytext.text = 'Click the Sprite, or close to it ...' , 1000);
}
}, this);
}
};
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: Scene
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>

Extreme Novice needing assistance with mousePressed() event

I am VERY new to P5.js/processing (taking programming for artists). I am trying to make a crude game where an image (Jar Jar) bounces across the screen and another image (lightsaber) that moves with the mouse and when the mouse attached image goes over the bouncing image then the lightsaber will be mirrored and activate a sound. If this at all makes sense...
I have the bouncing image part down so far, but I am unable to make the mousePressed() function work. like I mentioned, I need the "lightsaber.png" to flip when the mouse is pressed. Also, when the mouse is pressed and is directly over the JarJar image, how would I add a score count and sound event?
Thank you!
here is my code so far:
let jarJar;
let jarJarX=5;
let jarJarY=5;
let xspeed;
let yspeed;
let lightSaber;
function preload() {
jarJar = loadImage('jarjar.png');
lightSaber= loadImage ('lightSaber.png');
}
function setup() {
createCanvas(700,700);
xspeed=random (15,22);
yspeed=random (15,22);
}
function draw() {
background(0);
image (lightSaber,mouseX,mouseY,100,100);
image(jarJar,jarJarX,jarJarY, 140, 200);
jarJarX= jarJarX+xspeed;
if (jarJarX<=-300|| jarJarX>=width+200){
xspeed=xspeed*-1;
}
jarJarY= jarJarY+yspeed;
if (jarJarY<-200|| jarJarY>=height+200 ){
yspeed=yspeed*-1;
}
//picture mirrors when mouse pressed
if mouseClicked(){
scale(-1,1);
image(lightSaber);
}
//score counter coordinate with lightsaber hitting image
//
}
Let it be known that I'm not proficient at javaScript. This said, your question is quite simple so I can help anyway.
Some framework will have simple ways to mirror images. Processing likes to scale with a negative number. I re-coded some of your stuff to accommodate my changes. The main changes goes as follows:
I added a method to draw the lightsaber so we can "animate" it (read: flip it for a couple frames when the user clicks around).
I added a 'score' global variable to track the score, and a way for the user to see that score with the text method.
I added a method called "intersect" which isn't very well coded as it's something I did back when I was a student (please don't hurt me, it works just right so I still use it from time to time). For more details on how simple collisions works, take some time to read this answer I wrote some time ago, there are nice pictures too!
I added a mouseClicked method. This method will act like an event, which means that it will be triggered by a specific call (a left mouse button click in this case). This method contains the code to check for a collision between the squares which are the images. If there's an overlap, the score will increase and jarjar will run in another direction (this part is a bonus to demonstrate that this is the place where you can get creative about the collision).
I commented the code so you can get what I'm doing more easily:
let jarJar;
let jarJarX=5;
let jarJarY=5;
let xspeed;
let yspeed;
let lightSaber;
let flipLength;
let score = 0;
function preload() {
jarJar = loadImage('jarjar.png');
lightSaber= loadImage ('lightSaber.png');
}
function setup() {
createCanvas(700, 700);
runJarJarRun();
}
function draw() {
background(0);
drawLightSaber(); // this way I can deal with the lightsaber's appearance in a dedicated method
image(jarJar, jarJarX, jarJarY, 140, 200);
jarJarX= jarJarX+xspeed;
if (jarJarX<=-300|| jarJarX>=width+200) {
xspeed=xspeed*-1;
}
jarJarY= jarJarY+yspeed;
if (jarJarY<-200|| jarJarY>=height+200 ) {
yspeed=yspeed*-1;
}
//score counter coordinate with lightsaber hitting image
textSize(30);
fill(200, 200, 0);
text('Score: ' + score, 10, 40);
}
function drawLightSaber() {
if (flipLength) { // if the number is > 0 this will be true
flipLength--; // measure how ling the saber is flipped in frames # ~60 frames per second
push(); // isolating the translate ans scale manpulations to avoid ruining the rest of the sketch
translate(mouseX + 100, 0); // makes the coordinates so once flipped the lightsaber will still appear at the same location
scale(-1.0, 1.0); // flip x-axis backwards
image (lightSaber, 0, mouseY, 100, 100);
pop(); // ends the sequence started with 'push();'
} else {
image (lightSaber, mouseX, mouseY, 100, 100);
}
}
function runJarJarRun() {
xspeed=random (5, 10);
yspeed=random (5, 10);
}
function mouseClicked() { // this method will trigger once when the left mouse button is clicked
flipLength = 10;
if (intersect(jarJarX, jarJarY, 140, 200, mouseX, mouseY, 100, 100)) {
score++;
runJarJarRun(); // as a bonus, jarjar will run in another direction on hit
// you could totally put some more special effects, like a flash, a sound, some 'mesa ouchie bad!' text, whatever speaks to you
}
}
function intersect(x1, y1, w1, h1, x2, y2, w2, h2) {
let checkX = false;
let checkY = false;
if ( (x1<x2 && (x1+w1)>x2) || (x1<(x2+w2) && (x1+w1)>x2+w2) || (x1>x2 && (x1+w1)<(x2+w2)) ) {
checkX = true;
}
if ( (y1<y2 && (y1+h1)>y2) || (y1<(y2+h2) && (y1+h1)>y2+h2) || (y1>y2 && (y1+h1)<(y2+h2)) ) {
checkY = true;
}
return (checkX && checkY);
}
If there's something you don't understand, let me know in a comment and I'll be happy to elaborate. Good luck and have fun!
Hi and welcome to stack overflow. One thing to keep in mind when submitting here (or any forum where you're looking for help with code) is to post a minimal reproducible example. You'll be much more likely to get useful responses.
You'll also want to separate out your questions, as they each have multi-step responses.
Your first question is about how to get your sketch to display something when you press the mouse down. Your syntax isn't quite correct there. Here's a minimal example of how to check for a mouse held down.
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
if (mouseIsPressed == true) {
ellipse(100, 100, 100, 100);
}
}
Just a quick note that I tried to make this as 'novice-friendly' as possible. The == true is optional and not usually included.

Laser Animation with TweenJS and EaselJS

So, I'm trying to create a laser effect, similar to the one located at http://map.norsecorp.com/
For this example, I have a 500x500 canvas. The current javascript part of the solution is located below:
function shootLaser(x, y) {
var beam = new createjs.Shape();
beam.graphics.beginFill("red");
beam.graphics.moveTo(0,1.5).lineTo(70,0).lineTo(70,3).closePath();
beam.x = 80;
beam.y = 50;
stage.addChild(beam);
beam.setBounds(0,0,70,3);
createjs.Tween.get(beam,{ loop: true, onChange: beamUpdate })
.to({ x: 400 }, 1000, createjs.Ease.linear());
}
function beamUpdate(e) {
var beam = e.currentTarget.target;
var targetX = e.currentTarget._curQueueProps.x;
if( targetX - beam.x < beam.getBounds().width ) {
beam.scaleX = (targetX - beam.x) / targetX;
} else {
beam.scaleX = 1;
}
}
This draws the line the way that I want to. However the scaleX method doesn't quite work (not even close really, it just gets extremely small very fast).
The problem is that I can't find a way to shrink the "laser" once it hits it's target. If I shoot it from 0px to 250px. It should hit 250px and begin shrinking until the 250th pixel has "consumed" it for lack of a better term. Any help is greatly appreciated.
P.S. I'm also open to doing this with other libraries or tools. I just haven't found them yet.

Animate color change of shape for certain number of frames EaselJs

I am using EaselJS and want to create a flashing color rectangle that will flash a certain number of times when a button is pressed, displaying random colors from an array. It should stop after 10 color flashes and then I want to extract the final color.
So far the relevant code I have is:
var colorArray = ["#FE7B62","#CB2DD3","#F1FD66","#004CE8","#FFD068", "#02A97E"];
square = new createjs.Shape();
square.graphics.beginFill("#000").drawRoundRect(850, 50, 100, 100, 20);
function pushButton(event) {
square.graphics.inject(animateColor);
}
function animateColor(event) {
this.fillStyle = colorArray[parseInt(Math.random()*6)];
}
This code successfully triggers the flashing of colors from my color array, but I am not sure what the best method of running the animation for a limited number of frames is. I tried pausing the ticker and restarting it on the onclick of the button but that failed. I also tried using a for loop in the pushButton function but that caused a "too much recursion error" in the browser. Here is my full file link https://github.com/RMehta95/sherman-land/blob/master/main.js.
I would suggest creating an event to trigger your action (xamountOfFrames). Here is a link to some information that might help
http://www.w3schools.com/tags/ref_eventattributes.asp
I ended up not using the inject function and instead redrawing the shape each time, creating a couple counter and timer variables to ensure that it looped through the proper amount of times.
function pushButton() {
if (timer === false) {
animate = setInterval(animateColor, 200);
timer = true;
}
}
function animateColor() {
square.graphics.clear();
displayColor = colorArray[Math.floor(Math.random()*colorArray.length)];
square.graphics.beginFill(displayColor).drawRoundRect(850, 50, 100, 100, 20);
counter++;
if (counter===15) {
clearInterval(animate);
counter=0;
movePlayer(displayColor);
timer = false;
return;
}
}

gameQuery collision detection

it is the first time for me to explore jQuery and gameQuery for building games using JavaScript, so am asking about sth that might look very naive, but really i cant get it.
i am developing a game like Space Invader, the detection for collision between player missile and enemies not working.
This is my code:
the definition for my Enemy class
function Enemy(node){
this.node = $(node);
this.pts_value = 0;
return true;
}
this is the code i use to add ten enemy sprite next to each other. the enemies move together to the left and the right
$.each(new Array(10), function(index, value) {
$("#enemy_group").addSprite("enemy2_"+index,{animation: enemies[2],
posx: index * 55, posy: 0, width: 48, height: 48})
$("#enemy2_"+index).addClass("enemy");
$("#enemy2_"+index)[0].enemy = new Enemy($("#enemy2_"+index));
$("#enemy2_"+index)[0].pts_value = 150;
});
so when i need to move the enemies, i move the enemies together, i move the group that includes all the sprites "#enemy_group"
if(ENEMY_TO_RIGHT){
var enemiesNewPos = (parseInt($("#enemy_group").css("left"))) + ENEMY_SPEED;
if(enemiesNewPos < PLAYGROUND_WIDTH - 550){
$("#enemy_group").css("left", ""+enemiesNewPos+"px");
} else {
ENEMY_TO_RIGHT = false;
}
} else {
var enemiesNewPos = (parseInt($("#enemy_group").css("left"))) - ENEMY_SPEED;
if(enemiesNewPos > 0){
$("#enemy_group").css("left", ""+enemiesNewPos+"px");
} else {
ENEMY_TO_RIGHT = true;
}
}
finally for collision detection, i want to remove the enemy sprite that the players missile has hit, each missile sprite has an added class names ".playerMissiles"
$(".playerMissiles").each(function(){
var posy = parseInt($(this).css("top"));
if(posy < 0){
$(this).remove();
return;
}
$(this).css("top", ""+(posy - MISSILE_SPEED)+"px");
//Test for collisions
var collided = $(this).collision(".enemy, .group");
if(collided.length > 0){
//An enemy has been hit!
collided.each(function(){
$(this).setAnimation(enemies[0], function(node){$(node).remove();});
})
}
});
i was following the documentation tutorial on the gameQuery website.
any help appreciated, thanks,
I can't see any problem with your code. I can only give you a few pointers:
Did you create "enemy_group" with the addGroup function?
Is "enemy_group" nested in something special like a custom div ? for the collision detection to work you need a chain of parent composed only of sprites and groups (and tiles map)
Is "enemy_group" nested in a sprite, if so it's a bad idea because you will need to add the selector for this sprite in your methode call and this sprite will be included in the colliding element list.
The same goes for the ".playerMissiles"
Just to be sure what version of gameQuery and jQuery do you use? The last version from gitHub is unstable and I wouldn't recomend using it, user 0.5.1 instead.
You could use jquery collision plugin, so you avoid doid the logic by yourself.
Hope this helps. Cheers

Categories

Resources