Trying to draw multiple level scene in html5 canvas - javascript

this is my jsfiddle : jsfiddle.net/V8eKp/5/show
// START -- MOVE CAMERA
var p = new b2Vec2();
p = (ball.body.GetWorldCenter().x) * physics.scale;
pos.push(p);
var length = pos.length;
var s = (pos[length - 1] - pos[length - 2]); //in pixels
if ((halfwidth < (dw - p)) && (p > halfwidth)) {
ctx.translate(-s, 0);
}
I followed the code in here : http://www.codingowl.com/readblog.php?blogid=128
the rendering of the ball is acting weirdly and slow
i saw this example : http://www.emanueleferonato.com/2010/05/04/following-a-body-with-the-camera-in-box2d-the-smart-way/ but i didn't figure out how he do it he used 3 variables stage,x,y wish are undefined in the code he wrote.
and check out this demo by Impactjs and look how the camera move with the player movement i need this functionality : http://impactjs.com/demos/physics/
please can anyone help me in this

As long as ball.body.GetPosition().x > 48, this.current will start incrementing on each update, right? But your draw() only handles 0, 1 and 2.

Got a (kind of) working fix here: http://jsfiddle.net/u4Mv5/
You already got most of it right, just need a bit of work on the scene change logic.
My logic is, whenever the scene change, remove everything, manually shift the ball back or forward, and completely redraw the new scene.
As we are manually shifting the ball, the canvas does not need to be translated.
Draw and loop code: (Simplified)
draw: function () {
this.clear();
new Body(physics, { name: "Ground" });
ball = new Body(physics, { shape: "circle", x: ballx, y: bally, radius: 0.5 });
switch ( this.current ) {
case 0: // First scene
new Body(physics, { name: "Scene0Wall" });
new Body(physics, { name: "Scene0bricks0" });
new Body(physics, { name: "Scene0bricks1" });
break;
case 1: // Second scene
new Body(physics, { name: "Scene1bricks0" });
break;
case 2: // Third scene
new Body(physics, { name: "Scene2bricks0" });
break;
}
},
update: function () {
ballx = ball.body.GetPosition().x;
bally = ball.body.GetPosition().y;
if ( ballx > scene_width ) {
++this.current;
ballx -= scene_width;
this.draw();
}
if ( ballx < 0 && this.current > 0) {
--this.current;
ballx += scene_width;
this.draw();
}
},
This is also easier on scene layout since each scene's origin is [0,0].
I'm only preserving the balls' position, not its state and velocity, which you should implement. The scene layout (and scene cut off point) should also be adjusted to make sure the ball can continue its journey instead of getting stuck in a block.

Related

Limit dragged line to an arc / radius of a given length

I'm currently using Phaser 3, although my question isn't technically restricted to that framework, as it's more of a general JS/canvas/maths question, but:
I have a line drawn with graphics(). It’s anchored at one end, and the other end is draggable. I made a quick demo and so far, so good - you can see what I have already on CodePen.
Dragging the marker around and redrawing the line is no problem, but what I’d like is for that line to have a maximum length of 100, so even if you’re still dragging beyond that point, the line would still follow the mouse, but not get any longer than 100. Dragging inside that maximum radius, the line would shrink as normal.
I’ve put together a visual that hopefully explains it:
The issue is that I suspect this is VERY MATHS and I am very, very weak with maths. Could anyone explain like I’m five what I need to do to my code to achieve this?
Edit: Adding code in a snippet here, as requested:
var config = {
type: Phaser.AUTO,
width: 800,
height: 400,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: {
preload: preload,
create: create,
update: update
}
};
var path;
var curve;
var graphics;
var game = new Phaser.Game(config);
function preload() {
this.load.spritesheet('dragcircle', 'https://labs.phaser.io/assets/sprites/dragcircle.png', { frameWidth: 16 });
}
function create() {
graphics = this.add.graphics();
path = { t: 0, vec: new Phaser.Math.Vector2() };
curve = new Phaser.Curves.Line([ 400, 390, 300, 230 ]);
var point0 = this.add.image(curve.p0.x, curve.p0.y, 'dragcircle', 0);
var point1 = this.add.image(curve.p1.x, curve.p1.y, 'dragcircle', 0).setInteractive();
point1.setData('vector', curve.p1);
this.input.setDraggable(point1);
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
gameObject.data.get('vector').set(dragX, dragY);
});
this.input.on('dragend', function (pointer, gameObject) {
let distance = Phaser.Math.Distance.Between(curve.p0.x, curve.p0.y, curve.p1.x, curve.p1.y);
console.log(distance);
});
}
function update() {
graphics.clear();
graphics.lineStyle(2, 0xffffff, 1);
curve.draw(graphics);
curve.getPoint(path.t, path.vec);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser/3.55.2/phaser.min.js"></script>
You are right, you would need some math, but phaser has many helper functions, that will do the heavy lifting.
The main idea is, of this solution is
define a maxLength
get the the new point on drag, and create a real Phaser Vector2
here is some math is needed, to create the vector, just calculate destination point minus origin point
new Phaser.Math.Vector2(pointer.x - point0.x, pointer.y - point0.y) (origin point being the starting point of the desired vector, and destination point being the mouse pointer)
calculate the length of the created vector and compare it with the maxLength
if too long adjust the vector, with the handy function setLength (link to the documentation, this is where you would have needed math, but thankfully Phaser does it for us)
set the new coordinates for point1 and the curve endpoint
Here a quick demo (based on your code):
var config = {
type: Phaser.AUTO,
width: 500,
height: 170,
scene: {
preload: preload,
create: create,
update: update
}
};
var curve;
var graphics;
var game = new Phaser.Game(config);
function preload() {
this.load.spritesheet('dragcircle', 'https://labs.phaser.io/assets/sprites/dragcircle.png', { frameWidth: 16 });
}
function create() {
graphics = this.add.graphics();
curve = new Phaser.Curves.Line([ config.width/2, config.height - 20, config.width/2, 10 ]);
// define a length, could be a global constant
let maxLength = curve.p0.y - curve.p1.y;
var point0 = this.add.image(curve.p0.x, curve.p0.y, 'dragcircle', 0);
var point1 = this.add.image(curve.p1.x, curve.p1.y, 'dragcircle', 0).setInteractive();
this.input.setDraggable(point1);
// Just add for Debug Info
this.add.circle(curve.p0.x, curve.p0.y, maxLength)
.setStrokeStyle(1, 0xffffff, .5)
this.input.on('drag', function (pointer) {
let vector = new Phaser.Math.Vector2(pointer.x - point0.x, pointer.y - point0.y);
let distance = Phaser.Math.Distance.Between( point0.x, point0.y, pointer.x, pointer.y);
if(distance > maxLength){
vector.setLength(maxLength);
}
point1.x = point0.x + vector.x;
point1.y = point0.y + vector.y;
curve.p1.x = point1.x;
curve.p1.y = point1.y;
});
// NOT REALLY NEEDED
/*this.input.on('dragend', function (pointer, gameObject) {
let distance = Phaser.Math.Distance.Between(curve.p0.x, curve.p0.y, curve.p1.x, curve.p1.y);
console.log(distance);
});*/
}
function update() {
graphics.clear();
graphics.lineStyle(2, 0xffffff, 1);
curve.draw(graphics);
}
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
Optional - Code Version using Phaser.GameObjects.Line:
This uses less code, and thanks to the Line GameObject (link to Documentation), you can directly use the vector to update the line, and also don't need the update function, graphics and so.
const config = {
type: Phaser.CANVAS,
width: 500,
height: 160,
scene: {
create
}
};
const game = new Phaser.Game(config);
const MAX_LINE_LENGTH = 100;
function create() {
let points = [ {x: config.width/2, y: config.height - 20}, {x: config.width/2, y: config.height - 120} ];
let point0 = this.add.circle(points[0].x, points[0].y, 6)
.setStrokeStyle(4, 0xff0000);
let point1 = this.add.circle(points[1].x, points[1].y, 6)
.setStrokeStyle(4, 0xff0000)
.setInteractive();
this.input.setDraggable(point1);
// Just add for Debug Info
this.add.circle(point0.x, point0.y, MAX_LINE_LENGTH)
.setStrokeStyle(1, 0xffffff, .5);
let line = this.add.line(points[0].x, points[0].y, 0, 0, 0, -100, 0x00ff00)
.setOrigin(0);
this.input.on('drag', function (pointer) {
let vector = new Phaser.Math.Vector2(pointer.x - point0.x, pointer.y - point0.y);
let distance = Phaser.Math.Distance.Between( point0.x, point0.y, pointer.x, pointer.y);
if(distance > MAX_LINE_LENGTH){
vector.setLength(MAX_LINE_LENGTH);
}
point1.x = point0.x + vector.x;
point1.y = point0.y + vector.y;
line.setTo(0, 0, vector.x, vector.y);
});
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>

How to collide a player with walls?

I'm trying to create a top down shooter game and I am using Tiled to create my map. I've made my map and exported it as a .json file. I was finally able to make the map appear in my game, but I am having a hard time making the collision work.
I've been going through tutorials for hours and seem to have tried everything under the sun with no luck. I have an object layer in Tiled with the walls marked with the insert rectangle tool. I have every wall tile also marked with insert rectangle in the edit tileset menu. But I still cant get it to work. Walls are Tile Layer 1, ground is Tile Layer 2, object layer is called collision and the tile set name is tiles 48x48. Here's all my relevant code:
var game = new Phaser.Game(1440, 960, Phaser.man, 'phaser-example', { preload: preload, create: create, update: update, render: render });
var sprite
//sounds
var music
//movement
var controls
var cursors
//shooting
var fireRate = 200;
var nextFire = 0;
var Bullets
//map
var map
var walls
var ground
//var collision
function preload() {
game.load.audio('groove', ['sewer groove.mp3']);
game.load.audio('gunshot', 'pistol.mp3');
game.load.image('player', 'player lite.png');
game.load.image('bullet', 'bullet.png');
game.load.tilemap('map', 'sewermap.json', null, Phaser.Tilemap.TILED_JSON);
game.load.image('tiles 48x48','tiles 48x48.png')
}
function create() {
map = game.add.tilemap('map');
map.addTilesetImage('tiles 48x48');
//var tileset = map.addTilesetImage('map','tiles 48x48');
//map.physics.arcade.enable(sprite, Phaser.Physics.ARCADE);
ground = map.createLayer('Tile Layer 2');
walls = map.createLayer('Tile Layer 1');
//collision = map.createLayer('Object Layer 1')
map.setCollisionBetween(0, 65, true, 'Tile Layer 1');
//sprite.body.collideWorldbounds = true;
//layer.resizeWorld();
music = game.add.audio('groove',1,true);
music.play();
game.physics.startSystem(Phaser.Physics.ARCADE);
//game.physics.startSystem(Phaser.Physics.P2JS)
game.stage.backgroundColor = '#313131';
bullets = game.add.group();
bullets.enableBody = true;
bullets.physicsBodyType = Phaser.Physics.ARCADE;
bullets.createMultiple(50, 'bullet');
bullets.setAll('checkWorldBounds', true);
bullets.setAll('outOfBoundsKill', true);
sprite = game.add.sprite(620, 920, 'player');
sprite.anchor.set(0.5, 0.5);
//game.physics.p2.enable(sprite)
game.physics.arcade.enable(sprite, Phaser.Physics.ARCADE);
sprite.body.allowRotation = true;
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
game.physics.arcade.collider(sprite, walls);
//console.log(sprite.rotation);
sprite.rotation = game.physics.arcade.angleToPointer(sprite);
if (game.input.activePointer.isDown)
{
fire();
}
//sprite.body.setZeroVelocity();
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
{
sprite.x -= 4;
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
{
sprite.x += 4;
}
if (game.input.keyboard.isDown(Phaser.Keyboard.UP))
{
sprite.y -= 4;
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN))
{
sprite.y += 4;
}
}
function fire() {
if (game.time.now > nextFire && bullets.countDead() > 0)
{
nextFire = game.time.now + fireRate;
var bullet = bullets.getFirstDead();
bullet.reset(sprite.x - 8, sprite.y - 8);
game.physics.arcade.moveToPointer(bullet, 300);
}
}
function render() {
game.debug.text('Active Bullets: ' + bullets.countLiving() + ' / ' + bullets.total, 32, 32);
game.debug.spriteInfo(sprite, 32, 450);
//game.debug.spriteBounds(sprite);
//game.debug.spriteBounds(bullets);
//game.debug.body(sprite);
}
Alright, I've had the chance to take a look at this, the issue should solely lie in how you're moving the main player:
sprite.x -= 4;
Collisions only fire if the body has a velocity, the following table by samme should sum it up
You can apply acceleration, for the sake of example, to move the character towards the direction you're pointing at:
if (game.input.keyboard.isDown(Phaser.Keyboard.UP) || game.input.keyboard.isDown(Phaser.Keyboard.W)) {
game.physics.arcade.accelerationFromRotation(sprite.rotation, 200, sprite.body.acceleration);
}
In the image I'm also applying a certain drag and reducing acceleration when nothing is pressed but that's your call:
sprite.body.drag.x = 200;
sprite.body.drag.y = 200;
If you wanted to strafe an idea could be at dealing with multiple presses and applying a different accelerationFromRotation accordingly (with a variety of degrees converted with Phaser.Math.degToRad)
For debug's sake, if needed, you might want to use some of the following:
[...]
walls = map.createLayer("Tile Layer 1");
walls.debug = true;
[...]
function collisionHandler(obj1, obj2) {
console.log("Colliding!", obj1, obj2)
}
game.physics.arcade.collide(sprite, walls, collisionHandler, null, this);
game.debug.body(sprite);

Three.js - rotating a camera around a point

I have my custom Navigation control similar to Trackball but with additional functionality.
One of the features I want to implement is the specifying center of rotation of the camera and when we pan a camera, the rotation maintained around the specified point.
Here is the code of my update() function:
update(): this {
const camera = this.camera
if (this._enabled && camera && this._isInvalid) {
const cameraObject = camera.object
// validate all navigation changes
{
const {
offset,
panOffset,
axis,
tempVector3,
tempSpherical,
deltaRotation,
deltaPan,
quaternion
} = this.computeHelpers
// offset vector from eye to target
offset.subVectors(this._eye, this._target)
// apply rotation
if (deltaRotation.isInvalid) {
const { x: theta, y: phi } = deltaRotation.get()
// rotate around screen-space y-axis
if (theta) {
axis.set(0, 1, 0).applyQuaternion(cameraObject.quaternion)
quaternion.setFromAxisAngle(axis, theta)
offset.applyQuaternion(quaternion)
this._up.applyQuaternion(quaternion)
}
// rotate around screen-space x-axis
if (phi) {
axis.set(1, 0, 0).applyQuaternion(cameraObject.quaternion)
quaternion.setFromAxisAngle(axis, phi)
offset.applyQuaternion(quaternion)
this._up.applyQuaternion(quaternion)
}
// mark compute objects as valid
deltaRotation.set({ x: 0, y: 0 })
deltaRotation.isInvalid = false
}
// apply panning
if (deltaPan.isInvalid) {
cameraObject.updateMatrix()
const matrix = cameraObject.matrix
const { x: deltaPanX, y: deltaPanY } = deltaPan.get()
// pan screen space x-direction
{
tempVector3
// get x-column of local transform matrix
.setFromMatrixColumn(matrix, 0)
.multiplyScalar(deltaPanX)
panOffset.add(tempVector3)
}
// pan screen space y-direction
{
tempVector3
// get y-column of local transform matrix
.setFromMatrixColumn(matrix, 1)
.multiplyScalar(-deltaPanY)
panOffset.add(tempVector3)
}
this._target.add(panOffset)
// mark compute objects as valid
panOffset.set(0, 0, 0)
deltaPan.set({ x: 0, y: 0 })
deltaPan.isInvalid = false
}
// assemble new eye (camera) position
this._eye.addVectors(offset, this._target)
this._eyeSpherical.setFromVector3(this._eye)
this._direction.copy(this._eye).normalize()
}
// update camera position
cameraObject.position.copy(this._eye)
cameraObject.up.copy(this._up)
cameraObject.lookAt(this._target)
// mark the controller as valid
this._isInvalid = false
}
return this
}
How can I apply the translation?
Expected result:
Thanks a lot in advance

Trouble animating spritesheet in EaselJS

I'm trying to animate a spritesheet using EaselJS, but I keep getting an uncaught type error: undefined is not a function on this line - bmpAnimation = new createjs.BitmapAnimation(spriteSheet);
Here is my code so far:
// JavaScript Document
window.onload = function(){
//Creating a new Stage instance, passing in our canvas element's ID.
var stage = new createjs.Stage("canvas"),
imgMonsterARun = new Image();
imgMonsterARun.src = "img/MonsterARun.png";
var spriteSheet = new createjs.SpriteSheet({
// image to use
images: [imgMonsterARun],
// width, height & registration point of each sprite
frames: {width: 64, height: 64, regX: 32, regY: 32},
animations: {
walk: [0, 9, "walk"]
}
});
// create a BitmapAnimation instance to display and play back the sprite sheet:
bmpAnimation = new createjs.BitmapAnimation(spriteSheet);
// start playing the first sequence:
bmpAnimation.gotoAndPlay("walk"); //animate
// set up a shadow. Note that shadows are ridiculously expensive. You could display hundreds
// of animated rats if you disabled the shadow.
bmpAnimation.shadow = new createjs.Shadow("#454", 0, 5, 4);
bmpAnimation.name = "monster1";
bmpAnimation.direction = 90;
bmpAnimation.vX = 4;
bmpAnimation.x = 16;
bmpAnimation.y = 32;
// have each monster start at a specific frame
bmpAnimation.currentFrame = 0;
stage.addChild(bmpAnimation);
createjs.Ticker.setFPS(60);
createjs.Ticker.useRAF = true;
createjs.Ticker.addListener(window);
function tick()
{
// Hit testing the screen width, otherwise our sprite would disappear
if (bmpAnimation.x >= screen_width - 16) {
// We've reached the right side of our screen
// We need to walk left now to go back to our initial position
bmpAnimation.direction = -90;
}
if (bmpAnimation.x < 16) {
// We've reached the left side of our screen
// We need to walk right now
bmpAnimation.direction = 90;
}
// Moving the sprite based on the direction & the speed
if (bmpAnimation.direction == 90) {
bmpAnimation.x += bmpAnimation.vX;
}
else {
bmpAnimation.x -= bmpAnimation.vX;
}
// update the stage:
stage.update();
}
tick();
};
Any help would be appreciated.
In 0.8.0 you can use the normal SpriteSheet to create an animated SpriteSheet. Checkout the Demo on http://createjs.com/Demos/EaselJS/SpriteSheet (make sure to check the code under "live-edit" ;-))
Try using "Sprite" instead of "BitmapAnimation".
That is
bmpAnimation = new createjs.BitmapAnimation(spriteSheet);
becomes
bmpAnimation = new createjs.Sprite(spriteSheet);
Worked for me.

HTML5 Canvas Basic Line Animation

So, I'm trying to get into HTML5 Canvas with a small project animating an existing header consisting of red laser-like lines bursting from a single point. I'm able to draw these lines as I want them, and animate them as a group at a nice speed, but the next hurdle is above my head, I think: I'd like each line to move independently!
I've got an object defining the starting point for my lines such as:
var myLines = {
a: 1500,
b: 700,
c: 400,
d: 310,
e: 140,
f: 60
}
And I then draw with a loop kinda like:
for (var i in myLines)
{
var cur = myLines[i];
context.beginPath();
context.moveTo(0, canvas.height);
context.lineTo(canvas.width, myLine.y-cur);
context.stroke();
}
Using an awkward method of incrementation:
var step = 1;
if (myLine.y+step > canvas.height) {set = false;}
if (myLine.y-step < 0) {set = true;}
if (set) {
myLine.y = myLine.y+step;
} else {
myLine.y = myLine.y-step;
}
I'm aware the above code is poorly written, I'm out of my league here, I work during the day as a chef in a small kitchen, but I'd like some advice, please!
Here's a fiddle to see it all in action.
Thanks in advance!
If I were you I would change the script so that each line was a separate object, rather than just an offset. Something like:
var line = { x: 0, y: 0, speed: 1 };
That way each line can have its own speed, and inside your loop, you can do something like the following to add on the speed and flip it when you reach the edge of the screen:
line.x += line.speed;
if(/* edge of screen */) {
line.speed = -line.speed;
}

Categories