I have a problem with a script of mine. What I have is a tiled map made using a 2 dimensional array that specifies different tile types with different numbers and is drawn in a container div element. I also have a character div element that is movable. My problem is I can't figure out how to detect tiles and utilize the result of said detection in order to determine whether a character can move into nearby tiles or not.
The associated site that I have this hosted on is as follows;
http://brandynssite.webs.com/map_tile.html
As you can see with that example there is a container that draws the tiled map, a character element that starts at 0,0, and there are two buttons that check for character position and tile type. What I want to have happen is for the code to detect the tile the character is traveling to after a keypress event has happened and move their if possible. What functions would I need for this and is their a specific set of algorithms I would need for something as simple as what I have on that site?
I have provided one of the functions that allows the character to move as it seems to be the most related function in regards to possible collision detection that I can think of.
function anim(e) {
if(e.keyCode==39){
character_left += 10;
x += 1;
playerPos=mapArray[y][x];
character.style.left = character_left + "px";
if(character_left >= 190){
character_left -= 10;
x -= 1;
playerPos=mapArray[y][x];
}
}
if(e.keyCode==37){
character_left -= 10;
x -= 1;
playerPos=mapArray[y][x];
character.style.left = character_left + "px";
if(character_left <= 0){
character_left += 10;
x += 1;
playerPos=mapArray[y][x];
}
}
if(e.keyCode==40){
character_top += 10;
y += 1;
playerPos=mapArray[y][x];
character.style.top = character_top + "px";
if(character_top >= 190){
character_top -= 10;
y -= 1;
playerPos=mapArray[y][x];
}
}
if(e.keyCode==38){
character_top -= 10;
y -= 1;
playerPos=mapArray[y][x];
character.style.top = character_top + "px";
if(character_top <= 0){
character_top += 10;
y += 1;
playerPos=mapArray[y][x];
}
}
}
You need to create array where you specify on which tiles player can move. So:
var iCanMoveOn = [0, 2, 5];
And than you need to check if tile that is next to you is the one you can move on.
if(iCanMoveOn.indexOf(mapArray[y][x+1]) > -1){
//move player
}
x and y are coordinates where in array is a tile you are stading on. To check if you can step into the tile, you need to add or suntract "1" from one of coordinates. So:
[x+1] is tile on the right. Similarly: tile on the left is [x-1], tile on top: [y-1], bottom tile: [y+1]
To check if number is in array I used this
Related
I am using the Zdog library to create 3d objects in javascript. In the function that controls my animations I am trying to have a particle move around randomly and then after an interval return back to its original point. Here is my code:
if (radioOn == true){
radio.zoom = size;
path = [Math.floor((Math.random() * 3 - 1)),Math.floor((Math.random() * 2)),Math.floor((Math.random() * 2 - 1))];
origin[0] += path[0];
origin[1] += path[1];
origin[2] += path[2];
lightning.translate.x += path[0];
lightning.translate.y -= path[1];
lightning.translate.z += path[2];
timer++;
}
if (timer == 20){
timer = 0;
lightning.translate.x -= origin[0];
lightning.translate.y += origin[1];
lightning.translate.z -= origin[2];
origin = [0,0,0];
}
I have put alerts in the second if statement and timer is getting reset but origin is not. Also the particle initially does what I need but after it gets reset it will no longer move.
I would like to determine the proportion of a grid cell occupied by one (or more) circles. So, for example, the top left grid cell below would have a small value (~0.1) and the center grid cell (7,7) would have a value of 1, as it is entirely occupied by the circle.
At present I am doing this with canvas.context2d.getImageData, by sampling the cell's content to determine what is present. This works but is way too slow. This is this method:
var boxRadius = 6;
var boxSize = boxRadius * 2 + 1;
var cellWidth = gridWidth / boxSize;
var cellHeight = gridHeight / boxSize;
var scanInterval = 10;
var scanCount = 10;
for (var x = viewcenterpoint.x - (gridWidth / 2); x <= viewcenterpoint.x + (gridWidth / 2) -1; x += cellWidth) {
for (var y = viewcenterpoint.y - (gridHeight / 2) ; y <= viewcenterpoint.y + (gridHeight / 2) -1; y += cellHeight) {
var cellthreatlevel = 0.0;
for (var cellx = x; cellx < x + cellWidth; cellx += scanInterval){
for (var celly = y; celly < y + cellHeight; celly += scanInterval){
var pixeldata = context.getImageData(cellx, celly, 1, 1).data;
cellthreatlevel += ((pixeldata[0] + pixeldata[1] + pixeldata[2])/765 * -1) + 1;//255; //grey tone
scancount += 1;
}
}
cellthreatlevel = cellthreatlevel / scanCount; //mean
}
}
The getImageData call is the source of the problem - it is way too slow.
Given that I have an array of circles, each with their x, y and radius how can I calculate this? If possible I would like each value to be a decimal fraction (between 0 and 1).
The grid is static, but the circles may move within it. I would be happy to get a rough estimate for the value, it doesnt need to be 100% accurate.
You can use the Monte Carlo Method to get an approximate solution. It is a probability based method, in which you generate random samples in order to estimate some value. In this case, given the coordinates of the circle center, the circle radius and the boundaries of the grid cell, you can estimate the proportion of the grid cell occupied by the circle by generating K random samples (all contained inside the grid cell), and verify the proportion of the samples that are also inside the circle. The more samples you generate, the more accurate your result will be.
Remember: to verify if a given sample P is inside a circle with center C and radius R, all you have to do is check if the equation sqrt((Px-Cx)^2 + (Py-Cy)^2) <= R is true
You only need to call getImageData once, to obtain the entire canvas.
Once you have the image data you can access the bytes at offset 4 * (celly * width + cellx) to get the RGB(A) data.
This should be massively faster since it only makes one call to the graphics hardware instead of 10s of thousands.
I don't know a lot about JS, but i have to do assignments with it. right now i have a ball that bounces from one side of the screen to the other. with every bounce the colour of the screen and the ball change. but i'd like a slight increase of speed with every bounce as well(or a random speed every time it bounces if that's easier). this is the code I have for moving, the bouncing and the colour changing now:
fill(r,g,b);
ellipse(circleX, circleY, circleSize, circleSize);
circleX += moveX;
if (circleX > width - circleSize / 2 || circleX < circleSize / 2) {
moveX = -moveX;
r = random(255);
g = random(255);
b = random(255);
}
moveX is always 5 now and changes to -5 when turning back. but i'd like it if it turned into -6 and then +7 when going forward again. or something like that at least.
I thank you guys in advance for helping me and please explain it like you're explaining it to a child.
First, lets make a function which takes a number and returns +1 for non-negative numbers (positive or 0) and -1 for negative numbers, i.e. it's sign
function sign(x) {
if (x < 0) return -1;
return 1;
}
A full implementation of sign would have a special case for 0, and is available natively in ES6
Next, when it becomes time to change moveX separate it's magnitude (absolute value) and sign, increment it's magnitude and put the two pieces back together again before flipping the sign over
moveX = -sign(moveX) * (Math.abs(moveX) + 1);
You'll want to add another test inside your collision detection code to increase the speed. If the velocity is positive, then you want to add 1. If the velocity is negative, you want to subtract 1. Your code would look something like this...
...
moveX = -moveX
if (moveX < 0) {
--moveX;
} else {
++moveX;
}
...
Keep track of how many times the circle has "bounced" and add it to the speed.
var base_speed = 5;
var bounces = 0;
var direction = 1; //positive for moving right, negative for moving left
var moveX = base_speed + bounces * direction;
circleX += moveX;
if (circleX > width - circleSize / 2 || circleX < circleSize / 2) {
direction = -direction;
bounces++;
r = random(255);
g = random(255);
b = random(255);
}
This is my JSFiddle: http://jsfiddle.net/Au6br/13/
The problem is when I keep pressing keydown.up the player jump multiple times. What I want is to define a variable called JumpCount so when the player jump if the jump variable is greater than this value the jumping stop.
Character.prototype.Jump = function () { // Jumping
character.MaxJump += gravity;
character.y += character.MaxJump;
if (keydown.up) {
if (!character.jumping) {
character.jumping = true;
character.Pos = 4;
character.Row = 2;
character.h = 23;
character.MaxJump = -character.sp * 2.5;
}
}
if (character.y >= ch - character.h) { // if the character is under the bottom
character.y = ch - character.h;
character.jumping = false;
}
};
The first problem is that you can jump when you're not on the ground. It's because of the Onground function.
Replace this :
return this.y <= ch - this.h;
With this :
return this.y >= ch - this.h;
You should also use this function in Jump to avoid duplicate code :
if (character.Onground()) { // if the character is under the bottom
character.y = ch - character.h;
character.jumping = false;
}
Counting the jumps (I assume you want to make double jumps) can't work as long as you test if(keydown.up). When you press the UP key, this value will be true for more than one frame (depending on the duration the player presses it), so you'll never be able to correctly count the number of jumps. You must bind the jump on the onkeydown event, which is called once. After that, it will be simple to replace character.jumping with an integer.
I'd do it like this:
Character.prototype.Jump = function () {
character.MaxJump += gravity;
character.y += character.MaxJump;
if (keydown.up) {
if (character.CurrentJumps < character.JumpCount) {
character.CurrentJumps++
character.Pos = 4;
character.Row = 2;
character.h = 23;
character.MaxJump = -character.sp * 2.5;
}
}
if (character.y >= ch - character.h) {
character.y = ch - character.h;
character.CurrentJumps = 0
}
};
Were JumpCount is the max jumps, and CurrentJumps is the currently done jumps
And an example to set to double jump:
character.JumpCount = 2 // 2 Jumps
How about you add a variable called jumpCount or something that you increase every time the character jumps. Only allow the character to jump if jumpCount is smaller or equal to the number of jumps you like the character to be able to do. Then just set jumpCount to zero when the player touches the floor. This also gets rid of your jumping variable since this would mean the same thing as jumpCount === 0.
I'm working on a top down shooter, and basically the character starts in the middle of the screen, inside a rect (Safe Zone). The character isn't static, the scene is. He can walk around, inside the safe zone. As soon as the character walks out of this zone, the statics switch over ... the character is static, and the scene is moving around him.
The only problem with this is that I can't walk back into the safe zone, allowing my statics to switch over again.
So I'm forever stuck outside the zone. All I'm doing is checking to see whether my character position is 'within' a certain value (which is the rect), if he's out - then my KeyControls then affect the Map, not the character.
So this is my boundary (Safe Zone) checker:
//Walking Window Boundaries
var boundarySizeX = 400;
var boundarySizeY = 200;
ctxWalkBoundary.fillStyle = "grey";
ctxWalkBoundary.fillRect(gameWidth/2 - boundarySizeX/2, gameHeight/2 - boundarySizeY/2, boundarySizeX, boundarySizeY);
ctxWalkBoundary.clearRect((gameWidth/2 - boundarySizeX/2) + 2, (gameHeight/2 - boundarySizeY/2) + 2, (boundarySizeX) - 4, (boundarySizeY) -4 );
var paddingLeft = (gameWidth - boundarySizeX) / 2;
var paddingRight = gameWidth - ((gameWidth - boundarySizeX) / 2) - this.charWidth;
var paddingTop = (gameHeight - boundarySizeY) / 2;
var paddingBottom = gameHeight - ((gameHeight - boundarySizeY) / 2) - this.charHeight;
var paddingY = (gameHeight - boundarySizeY) / 2;
if(this.drawX > paddingLeft && this.drawX < paddingRight && this.drawY > paddingTop && this.drawY < paddingBottom){
inBoundary = true;
}
else{
inBoundary = false;
console.debug("Out Of Boundary!");
}
And this is my KeyChecker:
//UP
if(this.isUpKey){
//Character movement
if(inBoundary){
this.drawX = this.drawX + this.speed * Math.cos((this.characterRotation));
this.drawY = this.drawY + this.speed * Math.sin((this.characterRotation));
}
else{
mapPositionX = mapPositionX - this.speed * Math.cos((this.characterRotation));
mapPositionY = mapPositionY - this.speed * Math.sin((this.characterRotation));
}
My character always faces my mouse (rotates). So every time the user pressed W, or Up - the character will always walk towards the mouse position.
Any ideas how I can get back into the zone?
----- Update -----
I guess I need to somehow check if I'm still facing outside the safe zone - if not, then reverse he statics.
Just separate two things: map and view.
Map is your level, you keep there objects with coordinates.
View is part of map you see on screen.
View has 4 properties: x, y, widht and height, where widht and height most likely is your canvas size.
If your game start with view on map point (0,0) in the middle of screen, then your view (x,y) coordinates should be (-view.width/2, -view.height/2).
How to draw your character and objects in a view?
In first place, draw only thing that are in the view rectangle.
So loop over all objects and check if
object.x >= view.x && object.x <= view.x + view.width && object.y >= view.y && object.y <= view.y + view.height
(you probably should take into account objects boundaries too).
If object is in view area then draw it at position (object.x - view.x, object.y - view.y).
And that's all about drawing things.
Moving character and view area with him.
Now when your character collides with boundary, in example (colliding with right border)
character.x >= view.x + view.width
then move view to the right by incrementing view.x with some value (that might be character.width/2).
-- UPDATE --
I see that you are not using OOP in your game (actually you are because everything in JS is an object, but you are not using it on purpose).
OOP in JS is a lot of explaining, so I'll try to make it short.
You can make objects like your Character, Map and View using JSON format.
character = {
x: 0,
y: 0,
xspeed: 0,
yspeed: 0,
speed: 0,
radius: 20,
}
map = {
objects: [
{sprite: 'tree.jpg', x: 100, y: 50},
{sprite: 'stone.jpg', x: 20, y: 30},
],
}
view = {
width: canvas.width,
height: canvas.height,
x: -this.width/2,
y: -this.height/2,
}
These are objects that you can use like in your functions like that:
for (var i=0; i++, i<map.objects.length) {
if (map_obj.x >= view.x && map_obj.x <= view.x + view.width && map_obj.y >= view.y && map_obj.y <= view.y + view.height) {
var map_obj = map.objects[i];
draw_sprite(map_obj.sprite, map_obj.x - view.x, map_obj.y - view.y);
}
}
It's not the best way, but it's still much better than yours right now. When you understand what OOP is about you will make it better for your own.
The problem here is that you're waiting for the character to go out of bounds, then moving the map instead. But the flag has already been tripped, and now the character movement is static no matter what direction you go in, because you're already out of bounds.
You could instead detect when a character is going to cross the boundary and prevent it by moving the map instead:
//UP
if(this.isUpKey){
// save the x and y offset to prevent needless recalculation
var xOffset = this.speed * Math.cos(this.characterRotation),
yOffset = this.speed * Math.sin(this.characterRotation);
//Character movement
if( boundaryCheck(xOffset, yOffset) ){
this.drawX = this.drawX + xOffset;
this.drawY = this.drawY + yOffset;
}
else{
mapPositionX = mapPositionX - xOffset
mapPositionY = mapPositionY - yOffset;
}
then boundaryCheck takes the x and y delta's and figures out if they're still in bounds. If the character will still be in bounds, return true and the character will move, otherwise the map will move.
function boundaryCheck(xOffset, yOffset){
// variables set and other stuff done...
if(this.drawX + xOffset > paddingLeft && this.drawX + xOffset < paddingRight && this.drawY + yOffset > paddingTop && this.drawY + yOffset < paddingBottom){
return true;
}
else{
console.debug("Out Of Boundary!");
return false;
}
};
This way you don't have to figure out whether an out of bounds character is moving toward the boundary or not. Instead, you pre-determine where the character is going, and adjust accordingly, always keeping him in boundaries.
Without full code this isn't testable, of course, but I think it should work with what you've given.