Moving a player in tilemaps - javascript

I am using vanilla tilemaps, I am not sure if there is software out there related to tilemaps, but if there is be assured I am just using plain javascript, I have an issue though, I want to move the x of a player when a button is pressed, but it doesn't move, the player is green, and is identified by the number 4 on the tilemap.
it registers that I press the button(in console), but doesn't move the player at all, can anyone point out the issue? look at lines 62-89, thats where the error mostly occurs except for some global variables.
here's a link to the jsfiddle, I used this because I needed to show that the blocks don't move.
http://jsfiddle.net/8jr2ha3h/
var playerY = 0;
var playerX = 0;
var moveLeft = 65;
var moveRight = -65;
//THE PLAYER
player.onload = function(){
for(var i = 0; i < mapArray.length; i++){
for(var j = 0; j < mapArray[i].length; j++){
if(mapArray[i][j]==4){
context.drawImage(player, playerX, playerY, 45,37);
}
playerX+=45;
}
playerX = 0;
playerY +=37;
}
};
//KEY FUNCTIONS
document.onkeydown = function(e) {
//identifying that it's a window event.
e = e || window.event;
switch(e.which || e.keyCode) {
//37 is key for left arrow.
case 37:
{
playerX = playerX - moveLeft;
console.log(playerX);
console.log('left');
}
break;
}
}

Seems as though you're only drawing the player in player.onload(). You'll likely want to have all the rendering code in a single render() function, and possibly call that in player.onload() and then also call that function whenever the screen changes (the player moves, enemies move/die, the map changes for whatever reason... there are any number of reasons you'd need to redraw).
You may want to consider a main game loop here, which would (very simply) be something to the effect of:
while (true) {
checkForInputFromThePlayer(); // this can update player coordinates, etc
doSomeAI(); // Move some enemies around, have them attack the player
render();
}
EDIT: A great example of a Game Loop can be seen in yckart's answer to requestAnimationFrame at a limited framerate

Related

How can I mimic the VC trigger behavior of modular synthesis with the WebAudio API?

I have this picture: http://bourt.com/color/slide.html. Left-clicking the circle will generate an audible click. I want the clicks to be constant until I release the mouse button, and to make the interval between the clicks smaller as I move the circle up, to the point where the clicks form a tone.
I can get the gist of what I need with a simple tone (http://bourt.com/color/slide1.html), but I would like the LFO to trigger the envelope which I use for creating the click.
It's easy to do in VCV, which is where I prototyped this:
But I can't quite figure out how to mimic the behavior of triggering the envelope with an LFO. As I understand it, one option is to use AnalyserNode.getFloatTimeDomainData(), find the peaks and schedule the clicks accordingly. Another would be to forego the LFO concept altogether and use a ScriptProcessor as a makeshift mixer by adding the clicks to the buffer manually. But that's a lot of damn work for something that is conceptually very simple.
So I'm still hoping that it's possible to somehow use an oscillator to trigger the clicks, and vary the frequency of that oscillator with the position of the circle. Is it?
(I am aware of The Tale Of Two Clocks, but I don't think this kind of scheduling will work for the upper part of the slider where the clicks are so close that they create a tone.)
Using logic circuitry (eg: LFO-based) would be painful indeed. I suggest you use a setTimeout based method to register future clicks while still using the sound clock as a reference for triggering the play. I once built an audiotracker in JS and this was the most straightforward solution. My own code is quite messy but I found a great example over here
After trying the setTimeout() scheduling method, it became clear that the only way to achieve this is by using ScriptProcessorNode and adding the clicks to the audio buffer myself. It's similar to the scheduling method, but all the samples have to be handled manually, which is a pain, but it's what I ended up doing.
For those curious, here's what the code looks like (the important parts):
var clickProc = null;
var clickBuffer = null;
var clickSample = 0;
var remSamples = 0;
var remBuffer = null;
var remBufferLength = 0;
remBuffer = new Float32Array(2048);
clickProc = ac.createScriptProcessor(2048, 1, 1);
clickProc.onaudioprocess = function (e)
{
var output = e.outputBuffer.getChannelData(0);
var click = clickBuffer.getChannelData(0);
for (var i = 0; i < output.length; i++)
output[i] = 0;
if (remBufferLength > 0)
{
for (i = 0; i < remBufferLength; i++)
output[i] = remBuffer[i];
remBufferLength = 0;
}
for (i = 0; i < remBuffer.length; i++)
remBuffer[i] = 0;
if (clickSample >= output.length)
clickSample -= output.length;
while (clickSample < output.length)
{
var c;
for (c = 0; c < click.length && clickSample < output.length; c++, clickSample++)
output[clickSample] = Math.min(Math.max(0, output[clickSample] + click[c]), 1);
remSamples = click.length - c;
clickSample -= c;
clickSample += Math.max(1, Math.floor(clickInterval * ac.sampleRate));
if (c < click.length)
{
var remLength = click.length - c;
for (i = 0; i < remLength; i++, c++)
remBuffer[i] = Math.min(Math.max(0, remBuffer[i] + click[c]), 1);
remBufferLength = Math.max(remBufferLength, remLength);
}
}
};
clickProc.connect(ac.destination);

Collision detection function prevents program from drawing more than one ball in array

I have a piece of code that adds 10 ball objects, each with individual values (x, xvel, radius etc) to an array.
Inside the ball object I have created 4 functions: a draw function, movement function, mouse box collision function and a ball collision function.
All these functions work successfully except for the ball collision function. This is because when it is added to the execution loop only one ball is drawn and the rest of the balls are invisible.
for(i = 0; i < balls.length;i++)
{
balls[i].move()
balls[i].draw()
balls[i].mouse_collision()
//This function is the reason for my quarrels, if I allow it to execute then no balls are drawn except for one however collisions are detected.
//balls[i].checkbox()
}
Despite this however, collision are still detected, so my problem is in figuring out how to get both the collision and drawing working at the same time.
Code used in checkbox function
this.checkbox = function() {
//Attempt at collision function, loops through all other balls and
//if collision == true then the function executes,
//causing the balls to bounce of each other.
for(i = 0; i < balls.length; i++)
{
if(collision(x,y,radius,balls[i].x,balls[i].y,balls[i].radius) && balls[i].id != id)
{
console.log("COLLISION")
o_xvel = balls[i].xvel
o_yvel = balls[i].yvel
balls[i].xvel = xvel
balls[i].yvel = yvel
xvel = o_xvel
yvel = o_yvel
}
}
}
Link to code at JSFiddle: https://jsfiddle.net/HatBreakingDad/fnzr51yq/
P.S Sorry if my English was bad as it is not my first language.
You're overwriting some other i variable.
Restrain their scopes, declaring them with let, var, or const.
Replacing
for(i = 0; i < balls.length; i++)
with
for(let i = 0; i < balls.length; i++)
will do, for example.
Or you can just rename them.

Can't detect collision in 3D JavaScript

I am using three.js to make a simulation of the Brownian Motion and I'm stuck on a part where I need to get the little molecules to collide against each other. This is what I have so far:
function intersects(sphere, other){ //check if the distance between one sphere and the other is less than radius of both (4)
var distance = Math.sqrt((sphere.position.x - other.position.x) * (sphere.position.x - other.position.x) +
(sphere.position.y - other.position.y) * (sphere.position.y - other.position.y) +
(sphere.position.z - other.position.z) * (sphere.position.z - other.position.z));
if(distance < (4)){
return true;
} else {
return false;
}
}
function checkCollision(current){
for(var i = 0; i < balls.length; i++) {
if(intersects(balls[current], balls[i]) == true){
// balls[current].velocity.negate();
alert('hey');
}
}
}
When I run the code, I know for certain that the balls don't collide/intersect with each other, however I continuously get an alert box. I've tried to check if it's less than (sphere.radius + other.radius) but I don't think that's correct since it didn't seem to work. Also when I do keep it '< 4', it messes up the performance and it starts to run slowly at around 5 fps or less. checkCollision gets used here during the animation, so basically it checks it every time.
function animate(){
for(var i = 0; i < balls.length; i++){
balls[i].position.add(balls[i].velocity);
checkWallBoundaries(i);
checkCollision(i);
}
THREEx.WindowResize(renderer, camera);
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
stats.update();
}
I don't know why I can't get this to work. If someone could help me, that'd be greatly appreciated.
edit: Here's a picture of what happens when I uncomment the balls[current].velocity.negate() line https://puu.sh/uG1eS.png. The balls keep going back and forth but they're not even remotely close to each other, so I don't know why collision is being detected
Every ball collides with itself. You need to exclude i === current
for(var i = 0; i < balls.length; i++) {
if(current === i) continue;
if(intersects(balls[current], balls[i]) == true){
alert('hey');
}
}

KineticJS - Swapping shape positions upon contact/mousemove trigger

I'm using KineticJS and trying to get something done that seems simple enough: trying to get a shape to change position with the shape that's currently being dragged.
The idea is that:
• You pick up a shape on the canvas. This triggers a mousedown event listener, which saves the current position of the shape you've picked up.
• While holding the shape, if you trigger the mouseover on another shape, that shape's event gets triggered and swaps its position, based on the current shape's saved position.
Here is the relevant code I've written to try to get that working:
Board setup:
Simply just setting up the board and calling the needed functions here. I'm not doing anything with the stage, gameBoard, or ctx yet (part of it was for when I tried to get drawImage to work on multiple canvases, but have abandoned that for now).
class BoardView {
constructor(stage, gameBoard, ctx) {
this.stage = stage;
this.gameBoard = gameBoard;
this.ctx = ctx;
this.orbs = [[], [], [], [], []];
this.setupBoard();
}
Board setup functions:
This is where I go about setting up the board and giving each Kinetic Circle the attributes it needs to render on the Layer. Maybe I'm missing something obvious here?
setupBoard () {
for (let colIdx = 0; colIdx < 5; colIdx++) {
this.addRow(colIdx);
}
this.renderBoard();
}
addRow (colIdx) {
for (let rowIdx = 0; rowIdx < 6; rowIdx++) {
let orbType = Math.round(Math.random() * 5);
let orbColor;
if (orbType === 0) {
orbColor = "#990000";
} else if (orbType === 1) {
orbColor = "#112288";
} else if (orbType === 2) {
orbColor = "#005544";
} else if (orbType === 3) {
orbColor = "#776611";
} else if (orbType === 4) {
orbColor = "#772299";
} else {
orbColor = "#dd2277";
}
let orbject = new Kinetic.Circle({
x: (rowIdx + 0.5) * 100,
y: (colIdx + 0.5) * 100,
width: 100,
height: 100,
fill: orbColor,
draggable: true
});
this.orbs[colIdx].push(orbject);
}
}
Board render function:
This is where I add all the Kinetic Circle objects into new layers, and give those layers all its own attributes to work with when I call the event handlers. I also set up the event handlers here after adding the layers to the stage. Am I perhaps messing this up by adding too many layers?
renderBoard () {
for (let row = 0; row < this.orbs.length; row++) {
for (let orb = 0; orb < this.orbs[row].length; orb++) {
let layer = new Kinetic.Layer();
layer.add(this.orbs[row][orb]);
layer.moving = false;
layer.orbId = `orb${row}${orb}`;
layer.pos = [this.orbs[row][orb].attrs.x, this.orbs[row][orb].attrs.y];
this.stage.add(layer);
layer.on("mousedown", this.handleMouseDown);
layer.on("mouseup", this.handleMouseUp);
layer.on("mouseout", this.handleMouseOut);
layer.on("mousemove", this.handleMouseMove);
}
}
}
Mouse event handlers:
This is where I think I'm having my main problem. How I handle the event of moving the mouse to change orbs, perhaps I'm doing something terribly wrong?
handleMouseDown (e) {
window.currentOrb = this;
console.log(window.currentOrb.orbId);
this.moving = true;
}
//handleMouseUp (e) {
// window.currentOrb = undefined;
// this.moving = false;
//}
//handleMouseOut (e) {
//}
handleMouseMove (e) {
if (window.currentOrb !== undefined && window.currentOrb.orbId != this.orbId) {
this.children[0].attrs.x = window.currentOrb.pos[0];
this.children[0].attrs.y = window.currentOrb.pos[1];
this.children[0].draw();
} else {
}
}
}
module.exports = BoardView;
I've tried looking at the KineticJS docs and many StackOverflow answers as I could in hopes of finding a solution that would work for me, but nothing I've seen and tried so far (including the suggestions that came up as I wrote this question) seemed to be of help, and I'm aware the way I've gone about this so far is probably far from the best way to accomplish what I want, so I'm open to any suggestions, pointers, answered questions, or whatever can point me in the right direction to what I'm missing in order to get this to work.
In case this is helpful, here is also a visualization of how things look when the board is rendered.
The circles are all Kinetic Circles (orbs for the purpose of what I'm going for), and clicking and dragging one to another, the one that isn't being dragged but hovered over should move to the original position of the dragged circles.
Thanks!
EDIT:
I made a few changes to the code since then. First off, I changed adding many layers to the stage, to just one:
renderBoard () {
let layer = new Kinetic.Layer();
for (let row = 0; row < this.orbs.length; row++) {
for (let orb = 0; orb < this.orbs[row].length; orb++) {
layer.add(this.orbs[row][orb]);
this.orbCanvases.push(orbCanvas.id);
}
}
this.stage.add(layer);
}
I instead added listeners to the orb objects instead:
addRow (colIdx) {
for (let rowIdx = 0; rowIdx < 6; rowIdx++) {
//same code as before
let orbject = new Kinetic.Circle({
x: (rowIdx + 0.5) * 100, y: (colIdx + 0.5) * 100,
width: 100, height: 100,
fill: orbColor, draggable: true, pos: [rowIdx, colIdx]
});
orbject.on("mousedown", this.handleMouseDown);
orbject.on("mouseup", this.handleMouseUp);
orbject.on("mouseout", this.handleMouseOut);
orbject.on("mousemove", this.handleMouseMove);
this.orbs[colIdx].push(orbject);
}
}
This has had the benefit of making drag and drop much much faster where before, it was going very slow, but I still can't get my objects to swap position.
To be clear, my main issue is knowing which x, y values I should be changing. At the moment in handleMouseMove, I've been trying to change:
e.target.attrs.x = newX;
e.target.attrs.y = newY;
// newX and newY can be any number
However, no matter what I change it to, it has no effect. So it would help me to know if I'm changing the wrong thing/place, for example, maybe I'm supposed to be changing the Kinetic Circle from the array I've stored? Thanks again.
EDIT 2:
I think I got it! However, I had to take this.orbs and set it in the window at window.orbs, and to test it I did:
window.orbs[0][0].x(450);
window.orbs[0][0].draw();
And this caused the x position to change. But putting it in a window does not seem like good practice?
EDIT 3:
I got the orbs to now swap continuously, except for when it's the same orb being swapped again while mouseover is continuing to fire. At mouseup however, it can be swapped again. I also had to set up multiple layers again to get the mouseover events to work while holding another orb, but the performance seems to have improved a little.
I'm going to try and figure out how to get them to be able to swap continuously on the same mouse hold, but in the meantime, here is the code I wrote to achieve this:
addRow (colIdx) {
for (let rowIdx = 0; rowIdx < 6; rowIdx++) {
// same code as before, changed attr given to Kinetic.Circle
let orbject = new Kinetic.Circle({
x: (rowIdx + 0.5) * 100, y: (colIdx + 0.5) * 100,
width: 100, height: 100,
fill: orbColor, draggable: true, orbId: `orb${colIdx}${rowIdx}`
});
}
}
handleMouseDown (e) {
window.currentOrb = window.orbs[e.target.attrs.orbId];
window.newX = e.target.attrs.x;
window.newY = e.target.attrs.y;
}
Mouse down saving currentOrb by ID and its X and Y
handleMouseUp (e) {
window.currentOrb.x(window.newX);
window.currentOrb.y(window.newY);
window.currentOrb.parent.clear();
window.currentOrb.parent.draw();
window.currentOrb.draw();
window.currentOrb = undefined;
for (let i = 0; i < 5; i++) {
for (let j = 0; j < 6; j++) {
window.orbs[`orb${i}${j}`].draw();
}
}
}
When mouse is released, currently, all orbs are redrawn so they can all be used. I plan to refactor this so only orbs hovered over have this change.
handleMouseMove (e) {
if (window.currentOrb !== undefined && (window.currentOrb.attrs.orbId !== e.target.attrs.orbId)) {
window.orbMove.pause();
window.currentTime = 0;
window.orbMove.play();
let targOrbX = e.target.attrs.x;
let targOrbY = e.target.attrs.y;
// This is the target orb that's being changed's value
// We're storing this in targOrb
e.target.x(window.newX);
e.target.y(window.newY);
e.target.parent.clear();
e.target.parent.draw();
e.target.draw();
// Here we have the previously set current orb's position becoming
// the target orb's position
window.newX = targOrbX;
window.newY = targOrbY;
// Now that the move is made, we can set the newX and Y to be the
// target orb's position once mouseup
}
}
Orb swapping logic which works for passing over orbs once, but not if they are passed over again in the same turn.
When does the "hover" officially take place?
When the mouse event's position enters the second orb? If yes, hit test the mouse vs every non-dragging orb:
// pseudo-code -- make this test for every non-dragging orb
var dx=mouseX-orb[n].x;
var dy=mouseY-orb[n].y;
if(dx*dx+dy*dy<orb[n].radius){
// change orb[n]'s x,y to the dragging orb's x,y (and optionally re-render)
}
When the dragging orb intersects the second orb? If yes, collision test the dragging orb vs every non-dragging orb:
// pseudo-code -- make this test for every non-dragging orb
var dx=orb[draggingIndex].x-orb[n].x;
var dy=orb[draggingIndex].y-orb[n].y;
var rSum=orb[draggingIndex].radius+orb[n].radius;
if(dx*dx+dy*dy<=rSum*rSum){
// change orb[n]'s x,y to the dragging orb's x,y (and optionally re-render)
}
BTW, if you drag an orb over all other orbs, the other orbs will all stack on the dragging orbs original position -- is that what you want?

jump algorithm isn't working when reaching a block

This is my jsfiddle: http://jsfiddle.net/seekpunk/whZ44/17/
As you can see in my jsfiddle when the ball reach a block the jump function is not working.I know i am missing something in my algorithm that i am using to make the ball jump but i can't figure it out i would appreciate some help from you
if (InAir) {
if (InAir == 1) {
if (ball.y > jumpMaxHeight) {
ball.y -= gravity;
} else {
InAir = 2;
}
}
if (InAir == 2) {
if (ball.y < 390) {
ball.y += gravity;
} else {
ball.y = 390;
InAir = false;
ball.color = "black";
}
}
} else if (keydown.up && !InAir) {
InAir = 1;
ball.color = "#4285F4";
}
for (var j = 0; j < Blocks.collection.length; j++) {
if (Collision(ball, Blocks.collection[j])) {
//console.log("collision");
ball.y = (Blocks.collection[j].blockY - ball.radius) ;
}
}
Maybe here is something to start with: http://jsfiddle.net/d247V/3/
I updated the jump to have a default jump of 80 (high enough to get to next platform), and then on keydown.up i update that with the current ball.y position + the default
I think though the issue is how you are tracking the ball being in the air or not, when a collision is detected, the ball is technically no longer in the air, but you didn't have anything saying as such, see code snipped below basically how #mainguy said but with a slight modification to not keep reassigning ball.y, in the fiddle it works pretty well:
if( InAir )
{
for (var j = 0; j < Blocks.collection.length; j++) {
if (Collision(ball, Blocks.collection[j])) {
//console.log("collision");
var calc = (Blocks.collection[j].blockY - ball.radius);
if( ball.y != calc ) {
ball.y = calc;
ball.color = "black";
InAir = 0;
}
}
}
}
My fiddle though broke the gravity portion of the code, because you now need to also know if the x of the circle is passed the x barrier of the rectangle, and fall if not. So this is by no means a complete solution, but if you jump and go right or left from a barrier, the gravity process works as expected as long as no collisions exist, you will fall down to the bottom. There are slight other tweaks but I think you will be able to find them by the comment //Tweaked next to the parts I added.
It seems like your collision detection is working pretty well.
Its the gameloop that has some issues.
You should not do a collision detection on keypress up because this will only fire once. You need to check for collides all the time while the ball is in the air.
Like so:
... } else if (keydown.up && !InAir) {
InAir = 1;
ball.color = "#4285F4";
}
if (InAir){
for (var j = 0; j < Blocks.collection.length; j++) {
if (Collision(ball, Blocks.collection[j])) {
//console.log("collision");
ball.y = (Blocks.collection[j].blockY - ball.radius) ;
InAir=false;
}
}
}
With his code you can jump on the first plattform. (Note also that i changed ball.y positioning).
But some issues remain:
The Ball can not leave the plattform because as soon as he is airborne the collision with the plattform he is lying on kicks in.
If you move the Ball left or right over the plattform border it would be way more fun if he starts falling down again, instead of hovering in the air. (Trust me, i played some games).
Maybe you should delay collision detection until the ball has gained some height to escape the collision detection.
I update your fiddle and converted it to a plunker (with firebug you have way better debugging functionality here) Play with me!
Not a perfect answer but i hope this will help you.

Categories

Resources