Make a Text Based FPS in Javascript [Solved] - javascript

Original Question
When I made the game in C++, the window and buffer size was 120 x 40 and the screen(array of wchar_t) was the same hence each character would take up equal space such that the whole array would make the screen and later redrawing it on the console
I am trying to make the basic console to work with the canvas but not every character has equal amount of space and not all would fit into it
//Display map
for (nx = 0; nx < MAP_WIDTH; nx++)
{
for (ny = 0; ny < MAP_HEIGHT; ny++)
{
Screen[(ny + 1) * SCREEN_WIDTH + nx] = MAP[ny * MAP_WIDTH + nx] //returns a character '#' or '.';
}
}
this is the sample of how I fill the array
`Screen = Array(SCREEN_WIDTH * SCREEEN_HEIGHT);`
this is the initialization of array
now how would I draw that screen buffer to the canvas
in C++ it would be like this
//finally printing the screen
screen[ScreenWidth * ScreenHeight - 1] = '\0';
WriteConsoleOutputCharacter(hConsole, screen, ScreenWidth * ScreenHeight, { 0, 0 }, &dwBytesWritten);

I just ditched the canvas and just printed my text inside a para tag with such
let line = "";
for (let y = 0; y < SCREEN_HEIGHT; y++)
{
for (let x = 0; x < SCREEN_WIDTH; x++)
{
line += screen[y * SCREEN_WIDTH + x];
}
line += "\n";
}
document.getElementById("consoletext").innerText = line;

Related

Pixelate animation

I'm trying to pixelate an animation.. I have a .png image where I cut in frames. I have a scrollbar who gives a number, which is the new size of every pixel. (rasterSize)
I already did it for an image and it's working.
http://bht-homework.com/RMA/PIX_PRES1/
But for animation it looks like doesn't calculate the first pixels.
http://bht-homework.com/RMA/PIX_PRES2/
var imgData=context.getImageData(0,0,img.width,img.height);// width is 190,height 240
for (var x = 0; x < spriteSizeWidth; x++) {
for (var y = 0; y < spriteSizeHeight; y++) {
var rasterX = ((x / rasterSize) | 0) * rasterSize;
var rasterY = ((y / rasterSize) | 0) * rasterSize;
var rasterValIndex = (rasterX + rasterY * imgData.width) * 4;
r=imgData.data[rasterValIndex];
g=imgData.data[rasterValIndex + 1];
b=imgData.data[rasterValIndex + 2];
a=imgData.data[rasterValIndex + 3];
context.fillStyle="rgba(" +r+","+g+","+b+","+a+")";
context.fillRect(x,y,rasterSize,rasterSize);
}
}
Does someone has an idea how to fix it?
Thanks!
Though it might look as it would skip the first few pixels of your image, it actually just draws the blocks at the wrong position. It's offset by rasterSize.
You need to shift back the pixels to the correct position.
So simply replace
context.fillRect(x, y, rasterSize, rasterSize);
by
context.fillRect(x - rasterSize, y - rasterSize, rasterSize, rasterSize);

Detect a mouse click on an overlapping grid of boxes - JavaScript Canvas

I am currently trying to detect a mouse click on two grids of boxes simultaneously. One grid is easy, and I've just been using:
var gridPosX = Math.floor(mouseClickX/BoxWidth);
var gridPosY = Math.floor(mouseClickY/BoxHeight);
Now I also want to detect a mouse click on a secondary grid of boxes, located at the corners of the first grid of boxes. This could be achieved in a similar way to the first grid. The problem comes in because I want to detect a click on either the first grid, or the second one, at the same time. What is the best way to differentiate a click on the first grid verses a click on the second grid? I've tried to remove the Math.floor and used the greater than and less than operators (> <) to see if the click was closer to one grid spot than the other, but I've had no luck with that so far.
This is an image example of the grid. The black being the main one, the red being the second one
var WIDTH = 1280, HEIGHT = 1280;
var canvas, context;
var grid = [];
var grid2 = [];
var gridWidth = 10, gridHeight = 10;
var boxWidth = WIDTH/gridWidth, boxHeight = HEIGHT/gridHeight;
function main(){
canvas = document.createElement("canvas");
canvas.width = WIDTH;
canvas.height = HEIGHT;
context = canvas.getContext("2d");
document.body.appendChild(canvas);
canvas.onmousedown = function(e){
if(e.which == 1){
var gridPosX = Math.floor(e.offsetX/boxWidth);
var gridPosY = Math.floor(e.offsetY/boxHeight);
grid[gridPosX][gridPosY] = 0;
}
}
init();
setInterval(draw, 30);
}
function init(){
for(var x = 0; x < gridWidth; x++){
grid[x] = [];
grid2[x] = [];
for(var y = 0; y < gridHeight; y++){
grid[x][y] = 1;
grid2[x][y] = 1;
}
}
}
function draw(){
for(var x = 0; x < gridWidth; x++){
for(var y = 0; y < gridHeight; y++){
if(grid[x][y] == 1){
context.fillStyle = 'gray';
context.fillRect(x*boxWidth, y*boxHeight, boxWidth, boxHeight);
context.strokeRect(x*boxWidth, y*boxHeight, boxWidth, boxHeight);
}
}
}
for(var x = 0; x < gridWidth; x++){
for(var y = 0; y < gridHeight; y++){
if(grid2[x][y] == 1){
context.fillStyle = 'red';
context.fillRect((x*boxWidth)+(boxWidth)-(boxWidth/4), (y*boxHeight)+(boxHeight)-(boxHeight/4), boxWidth/2, boxHeight/2);
context.strokeRect((x*boxWidth)+(boxWidth)-(boxWidth/4), (y*boxHeight)+(boxHeight)-(boxHeight/4), boxWidth/2, boxHeight/2);
}
}
}
}
main();
Since the red grids show on top of the gray ones, I think you can first decide whether a mouse event is on a red grid or not. If not, then it must be on gray grids.
Based on the calculations below to check if a red grid is clicked:
var xRedIndex = Math.floor((e.offsetX - 3 / 4 * boxWidth) / (boxWidth / 2));
var yRedIndex = Math.floor((e.offsetY - 3 / 4 * boxHeight) / (boxHeight / 2));
if (xRedIndex % 2 === 0 && yRedIndex % 2 === 0) {
console.log("red");
console.log("Red grid x: " + (xRedIndex / 2));
console.log("Red grid y: " + (yRedIndex / 2));
} else {
console.log("gray");
var gridPosX = Math.floor(e.offsetX / boxWidth);
var gridPosY = Math.floor(e.offsetY / boxHeight);
grid[gridPosX][gridPosY] = 0;
}
Basically, you first subtract the initial gray area in the first column/row from the offsetX/Y, then see if the rest of the offsetX/Y contains an odd or even number of boxSize/2 (side length of red grid). An even number means the click is on red grids, otherwise it falls on the uncovered gray area.
Working fiddle: https://jsfiddle.net/mwxzgth6/1/

Introductory JavaScript chessboard printing program giving me problems

I have access to the answer to this exercise, but I can't figure out why the code below doesn't work. The task is to print to the console a chessboard of alternating "#" and spaces, and include a size variable to increase or decrease the size of the board. Why doesn't this code do that?
size = 8;
for (height = 0; height < size; height++) {
width = 0;
board = ""
while (width < size) {
board += ((height + width) % 2 === 0 ? "#":" ");
width++;
} board += "/n"
};
console.log(board);
There were two issues in your implementation:
You were using "/n" while you should use "\n" for a newline.
You were resetting your board variable to blank string in every iteration. So, in the end you only had a single line of chess row in your variable. You needed to take that variable outside the for loop.
size = 8;
var board = ""
for (height = 0; height < size; height++) {
width = 0;
while (width < size) {
board += ((height + width) % 2 === 0 ? "#":" ");
width++;
} board += "\n"
};
console.log(board);
You run into a couple of issues here:
Newline = '/n'
Also, you are clearing your board in every iteration. Move the board = "" outside the loop.:
size = 8;
board = "";
for (height = 0; height < size/2; height++) {
width = 0;
while (width < size) {
board += ((height + width) % 2 === 0 ? "#":" ");
width++;
}
board += "\n";
};
https://jsfiddle.net/rgn9573g/2/

Reading MNIST dataset with javascript/node.js

I'm trying to decode the dataset from this source: http://yann.lecun.com/exdb/mnist/
There is a description of the "very simple" IDX file type in the bottom, but I cannot figure it out.
What I'm trying to achieve is something like:
var imagesFileBuffer = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues = {};
Do magic
pixelValues are now like:
// {
// "0": [0,0,200,190,79,0... for all 784 pixels ... ],
// "4": [0,0,200,190,79,0... for all 784 pixels ... ],
etc for all image entries in the dataset. I've tried to figure out the structure of the binary files, but failed.
I realized there would be duplicate keys in my structure of the pixelValues object, so I made an array of objects of it instaed. The following code will create the structure I'm after:
var dataFileBuffer = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues = [];
// It would be nice with a checker instead of a hard coded 60000 limit here
for (var image = 0; image <= 59999; image++) {
var pixels = [];
for (var x = 0; x <= 27; x++) {
for (var y = 0; y <= 27; y++) {
pixels.push(dataFileBuffer[(image * 28 * 28) + (x + (y * 28)) + 15]);
}
}
var imageData = {};
imageData[JSON.stringify(labelFileBuffer[image + 8])] = pixels;
pixelValues.push(imageData);
}
The structure of pixelValues is now something like this:
[
{5: [28,0,0,0,0,0,0,0,0,0...]},
{0: [0,0,0,0,0,0,0,0,0,0...]},
...
]
There are 28x28=784 pixel values, all varying from 0 to 255.
To render the pixels, use my for loops like I did above, rendering the first pixel in the upper left corner, then working towards the right.
Just a small improvement:
for (var image = 0; image <= 59999; image++) {
with 60000 there is an "entry" with null's at the very end of your pixelValues.
EDIT:
I got a little obsessed with details because I wanted to convert the MNIST dataset back to real and separate image files. So I have found more mistakes in your code.
it is definitely +16 because you have to skip the 16 Bytes of header data. This little mistake is reflected in your answer where the first pixel value of the first digit (with is a 5) is '28'. Which is actually the value that tells how many columns the image has - not the first pixel of the image.
Your nested for loops has to be turned inside-out to get you the right pixel order - asuming you will "rebuild" your image from the upper left corner down to the lower right corner. With your code the image will be flipped along the axis that goes from the upper left to the lower right corner.
So your code should be:
var dataFileBuffer = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues = [];
// It would be nice with a checker instead of a hard coded 60000 limit here
for (var image = 0; image <= 59999; image++) {
var pixels = [];
for (var y = 0; y <= 27; y++) {
for (var x = 0; x <= 27; x++) {
pixels.push(dataFileBuffer[(image * 28 * 28) + (x + (y * 28)) + 16]);
}
}
var imageData = {};
imageData[JSON.stringify(labelFileBuffer[image + 8])] = pixels;
pixelValues.push(imageData);
}
Those little details wouldn't be an issue if you stay consistent and use those extracted data to -for example- train neural networks, because you will do the same with the testing dataset. But if you want to take that MNIST trained neural network and try to verify it with real life hand written digits, you will get bad results because the real images are not flipped.
Hopefully this helps someone out, I have added the ability to save the images to a png. Please note you will need to have an images directory
var fs = require('fs');
const {createCanvas} = require('canvas');
function readMNIST(start, end)
{
var dataFileBuffer = fs.readFileSync(__dirname + '\\test_images_10k.idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '\\test_labels_10k.idx1-ubyte');
var pixelValues = [];
for (var image = start; image < end; image++)
{
var pixels = [];
for (var y = 0; y <= 27; y++)
{
for (var x = 0; x <= 27; x++)
{
pixels.push(dataFileBuffer[(image * 28 * 28) + (x + (y * 28)) + 16]);
}
}
var imageData = {};
imageData["index"] = image;
imageData["label"] = labelFileBuffer[image + 8];
imageData["pixels"] = pixels;
pixelValues.push(imageData);
}
return pixelValues;
}
function saveMNIST(start, end)
{
const canvas = createCanvas(28, 28);
const ctx = canvas.getContext('2d');
var pixelValues = readMNIST(start, end);
pixelValues.forEach(function(image)
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var y = 0; y <= 27; y++)
{
for (var x = 0; x <= 27; x++)
{
var pixel = image.pixels[x + (y * 28)];
var colour = 255 - pixel;
ctx.fillStyle = `rgb(${colour}, ${colour}, ${colour})`;
ctx.fillRect(x, y, 1, 1);
}
}
const buffer = canvas.toBuffer('image/png')
fs.writeFileSync(__dirname + `\\images\\image${image.index}-${image.label}.png`, buffer)
})
}
saveMNIST(0, 5);

convert list of relative widths to pixel widths

This is a code review question more then anything.
I have the following problem:
Given a list of relative widths (no unit whatsoever, just all relative to each other), generate a list of pixel widths so that these pixel widths have the same proportions as the original list.
input: list of proportions, total pixel width.
output: list of pixel widths, where each width is an int, and the sum of these equals the total width.
Code:
var sizes = "1,2,3,5,7,10".split(","); //initial proportions
var totalWidth = 1024; // total pixel width
var sizesTotal = 0;
for (var i = 0; i < sizes.length; i++) {
sizesTotal += parseInt(sizes[i], 10);
}
if(sizesTotal != 100){
var totalLeft = 100;;
for (var i = 0; i < sizes.length; i++) {
sizes[i] = Math.floor(parseInt(sizes[i], 10) / sizesTotal * 100);
totalLeft -= sizes[i];
}
sizes[sizes.lengh - 1] = totalLeft;
}
totalLeft = totalWidth;
for (var i = 0; i < sizes.length; i++) {
widths[i] = Math.floor(totalWidth / 100 * sizes[i])
totalLeft -= widths[i];
}
widths[sizes.lenght - 1] = totalLeft;
//return widths which contains a list of INT pixel sizes
Might be worth abstracting it to a function... I cleaned it up a bit. And I wasn't sure what the sizesTotal != 100... stuff was all about so I life it out.
function pixelWidths(proportions, totalPx) {
var pLen = proportions.length,
pTotal = 0,
ratio, i;
for ( i = -1; ++i < pLen; )
pTotal += proportions[i];
ratio = totalPx / pTotal;
pTotal = 0;
for ( i = -1; ++i < pLen; )
pTotal += proportions[i] = ~~(proportions[i] * ratio);
proportions[pLen-1] += totalPx - pTotal;
return proportions;
}
pixelWidths([1,2,3,5,7,10], 1024); // => [36, 73, 109, 182, 256, 368]
FYI, ~~ (double-bitwise-not) has the effect of getting the number representation of any type (using the internal toInt32 operation) and then flooring it. E.g:
~~'2'; // => 2
~~'2.333'; // => 2
~~null; // => 0
If sizes starts off declared as a list of numbers, why do you have to call parseInt()?
You misspelled "length" in the last line
Where is widths declared?
How does this account for rounding issues? Oh I see; it's that last line; well don't you need to add totalLeft and not just override whatever's there?

Categories