I don't have any JSON files in this program only js and html my theory is that the program is running the html like a JSON file I'm using replit and kaboom to run the game
HTML code:
<!DOCTYPE html>
<html>
<head>
<title>kaboom</title>
<meta charset="utf-8">
<style>
* {
margin: 0;
}
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
display: block;
}
</style>
</head>
<body>
{{kaboom}}
</body>
</html>
js code:
import kaboom from "kaboom";
// initialize context
kaboom();
scene();
const SPEED = 320
var METEORX = 2
const NiceX = 20
//onsole.log(str(METEORX))
// load assets
loadSprite("grass", "sprites/grass.png");
loadSprite("Player", "sprites/Player.png");
loadPedit("meteor", "sprites/meteor.pedit");
loadPedit("air Meteor", "sprites/air Meteor.pedit");
// add a character to screen
const meteor = add ([
sprite("air Meteor"),
pos(rand(0, width()), 40),
area(),
move(DOWN, 300),
"meteor",
"enemy",
cleanup(20)
])
var player = add([
// list of components
"player",
sprite("Player"),
pos(center()),
area(),
body(),
health(3)
]);
add([
rect(width(), 48),
"ground",
pos(0, height() - 48),
outline(4),
area(),
solid(),
color(127, 200, 255),
])
onCollide("player", "enemy", () => {
player.hurt(1.5)
})
loadPedit("ground meteor", "sprites/ground meteor.pedit");
var difficulty = 5;
onCollide("enemy", (niceMeteor) => {
addExplosion()
destroy(niceMeteor)
})
onKeyPress("space", () => {
if (player.grounded()) {
player.jump()
}
})
onKeyDown("d", () => {
player.move(SPEED, 0)
})
onKeyDown("a", () => {
player.move(-SPEED, 0)
})
The most likely scenario is that one of the sprites you have specified does not exist. In this case you should also see an error: ERROR: sprite not found: "<your sprite name here>". (I think it's a bug that kaboom tries to parse the response as JSON at all in this case, because it's getting a 404 response with content-type text/html).
Another possibility, however improbable, is that one of your sprite files is corrupt. Kaboom's .pedit file format is actually a JSON file with image data embedded as base64:
{
"version": "1",
"width": 32,
"height": 32,
"palette": [[0,0,0,255],[255,255,255,255],[255,255,128,255],[255,128,255,255],[0,128,128,255],[128,0,255,255],[255,0,128,255],[0,255,255,255]],
"anims": {
"Test": {"from":0,"to":1,"loop":true}
},
"frames":[
"data:image/png;base64,...",
"data:image/png;base64,..."
]
}
So if one of those files got corrupted during editing that could also cause this error. Normally in order to figure this out I would suggest you look at the stack trace for the error that is being thrown, which is visible in your web browser's developer console. However, Kaboom does not produce good stack traces for calls to loadPedit. So your best bet is probably to put some console.log('loading sprite XXX') statements before each load call. Once you know which pedit file is invalid you can rename that file from whatever.pedit to whatever.json and inspect the contents in your repl.
Related
I am trying to make a playable on Unity Ads using Phaser 3 but it seems that there are multiple specifications to use it, one of the Unity Ads specifications and as in their documentation "Advertisements should be designed not to need any network requests (XHR), but for example, analytics calls to track user interaction are allowed"
So I don't know how to add the Phaser CDN to my file.
Note: the Playable should be in one file and images must be in base 64.
So I need to know if there is an example of how to make playable on unity ads using phaser 3.
The following code shows a black screen when I test it
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
padding: 200px;
}
</style>
</head>
<body>
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
<script>
class Test extends Phaser.Scene{
constructor(){
super('test')
this.imageData = 'data:image/png;base64,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';
this.brain = null;
}
create () {
this.textures.addBase64('brain', this.imageData);
this.textures.once('addtexture', function () {
this.brain = this.add.sprite(this.wid, 300, 'brain');
this.brain.setInteractive()
this.brain.on('pointerdown',()=>{
mraid.open('https://play.google.com/store/apps/details?id=[name of a game]')
})
}, this);
// this.btn = this.add.image(400, 300, 'btn')
// .setScale(0.3)
}
}
// Wait for the SDK to become ready
if (mraid.getState() === 'loading') {
mraid.addEventListener('ready', onSdkReady);
} else {
onSdkReady();
}
function viewableChangeHandler(viewable) {
// start/pause/resume gameplay, stop/play sounds
if(viewable) {
showMyAd();
} else {
// pause
}
}
function onSdkReady() {
mraid.addEventListener('viewableChange', viewableChangeHandler);
// Wait for the ad to become viewable for the first time
if (mraid.isViewable()) {
showMyAd();
}
}
function showMyAd() {
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 200 }
}
},
scene:[Test]
};
new Phaser.Game(config);
}
</script>
</body>
</html>
I don't really know how unity ads works, but you could simply inline the minified phaser-code-file into a script-tag above the gamecode, and so there are no calls to external source / cdn's.
...
<script> !function(t,e){"object"==typeof exports&& ... </script>
...
(This will obviously increase your html-file significantly (~ 1 MB), but works)
Tip: if you are using a bundler like webpack or so, this could be done automatically, maybe even images an such.
I am trying to create a Debug app for Body Positioning Data. This data is received as JSON via MQTT in my receiveAndConversion.js. I was able to receive the data properly and print to console. So far so good. But now I want in my main window the values that I receive to show up (make the screen green for example when hand closed).
I have tried a lot of things including ipc and adding
nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, as preferences in main.js
Researching this is kind of a pain, as I always get to questions where the person tries to change the DOM from main.js instead of the renderer.
I am new to electron and have been spending hours on the documentation but all their examples are either triggerd on launch of the app or by a button (user interaction). I need to change the DOM when a new message is received, independent on user interaction or other things.
My structure at the moment is like this:
main.js
receiveAndConversion.js
index.html
renderer.js
Except for receiveAndConversion.js, renderer.js and the mentioned Preferences in main.js, the code is more or less the same as The quick start guide.
The main issue that seems to block me is, that I cant seem to be able to call my renderer.js from my receiveAndConversion.js mqttClient.on() which runs when I have received a new message. My thinking was I could just call from there a render function in render.js but as it is called from receiveAndConversion.js I get a "document is not defined" error (at least I believe that's the reason).
I would really appreciate if you had an idea for me on how to implement this without having to put everything in main.js.
You can find the complete code below.
// main.js
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain } = require('electron')
//const Renderer = require('electron/renderer')
const path = require('path')
const mqttClient = require('./receiveAndConversion.js')
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
//nativeWindowOpen: true,
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
//
//ipcMain.handle('left-hand-closed', (event, arg) => {
// console.log('left hand is closed');
//}
//)
createWindow()
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<!--index.html-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
<!-- Create different field which will be used to visualise if hands are open or not. So one field for left hand one field for right hand. -->
<div id="left-hand"></div>
<div id="right-hand"></div>
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
//renderer.js
// get info of open or closed hands from receiveAndConversion.js
// then make the left-hand div or right-hand div green or red depending on open or closed
//const {ipcRenderer} = require('electron')
// //write something in the divs
// leftHandDiv.innerHTML = 'Left Hand: ' + leftHandClosed
// rightHandDiv.innerHTML = 'Right Hand: ' + rightHandClosed
// ipcRenderer.handle('left-hand-closed', (event, arg) => {
// leftHandDiv.innerHTML = 'Left Hand: ' + arg
// }
// )
// ipcRenderer.handle('right-hand-closed', (event, arg) => {
// rightHandDiv.innerHTML = 'Right Hand: ' + arg
// }
// )
function handChange(leftHandClosed, rightHandClosed) {
//get the divs from the html file
const leftHandDiv = document.getElementById('left-hand')
const rightHandDiv = document.getElementById('right-hand')
//check if the hand is open or closed
if (leftHandClosed) {
leftHandDiv.style.backgroundColor = 'green'
console.log('left hand is closed');
} else {
leftHandDiv.style.backgroundColor = 'red'
console.log('left hand is open');
}
if (rightHandClosed) {
rightHandDiv.style.backgroundColor = 'green'
console.log('right hand is closed');
} else {
rightHandDiv.style.backgroundColor = 'red'
console.log('right hand is open');
}
}
//make handChange() usable outside of the renderer.js
module.exports = {
handChange
}
// preload.js
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
To keep your receiveAndConversion.js file separate from your main.js file and send signals via IPC to index.html, you need access to Electrons window instance of index.html. This can be achieved by using a "getter" method. Separating the creation (and getting) of mainWindow into its own file will therefore be needed.
Good use of a preload.js script dictates setting nodeIntegration: false and contextIsolation: true. Additionally, there should be no need to use any form of remote modules. I have re-worked your preload.js script to be used only as a form of communication between the main process and render process. Various forms of preload.js scripts can be used, but in this instance I have used the most simplified (but not very flexible) approach.
Lastly, not having access to your receiveAndConversion.js file, I have mocked a random hand / position data stream.
As you can see, separating domains into their own files can keep the overall application logical, easy to maintain and bug free when adding additional features.
main.js (main process)
// Require the necessary Electron modules
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
// Require the necessary Node modules
const nodePath = require('path');
// Require the necessary Application modules
const appMainWindow = require(nodePath.join(__dirname, './main-window'));
const appReceiveAndConversion = require(nodePath.join(__dirname, './receiveAndConversion'));
// Prevent garbage collection
let mainWindow;
electronApp.on('ready', () => {
mainWindow = appMainWindow.create();
appReceiveAndConversion.run();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
appMainWindow.create();
}
});
Having the create() and get methods of the mainWindow in its own file allows for inclusion within any other file that need reference to the mainWindow.
main-window.js (main process)
// Require the necessary Electron modules
const electronBrowserWindow = require('electron').BrowserWindow;
// Require the necessary Node modules
const nodePath = require('path');
let mainWindow;
function create() {
mainWindow = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, './preload.js')
}
});
mainWindow.loadFile('index.html')
.then(() => { mainWindow.show(); })
return mainWindow;
}
function get() {
return mainWindow;
}
module.exports = {create, get}
receiveAndConversion.js (main process)
Mocked...
// Require the necessary Node modules
const nodePath = require('path');
// Require the necessary Application modules
const appMainWindow = require(nodePath.join(__dirname, './main-window'));
let mainWindow;
// Generate a random number
function randomNumber(lower, upper) {
return Math.floor(Math.random() * (upper - lower + 1) + lower)
}
// An infinitely polled function
function listener() {
let hand = (randomNumber(0, 1)) ? 'leftHand' : 'rightHand';
let position = (randomNumber(0, 1)) ? 'opened' : 'closed';
console.log(hand + ' ' + position); // Testing
mainWindow.webContents.send(hand, position);
}
// Called from main.js
function run() {
mainWindow = appMainWindow.get();
setInterval(() => { listener(); }, 350);
}
module.exports = {run}
preload.js (main process)
A simple (but rigid) example.
// Import the necessary Electron components
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// Exposed protected methods in the render process
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods
'electronAPI', {
// From main to render
leftHand: (position) => {
ipcRenderer.on('leftHand', position);
},
rightHand: (position) => {
ipcRenderer.on('rightHand', position);
}
});
Instead of changing background colors via JavaScript, it is better to change class names or even better again, data attribute values in this instance.
For simplicity, I have incorporated a revised renderer.js between the <script> tags.
index.html.js (render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
<style>
body {
margin: 0;
padding: 0;
height: 100vh;
display: flex;
flex-flow: row nowrap;
}
#left-hand,
#right-hand {
flex: 1 0 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 3em;
}
#left-hand[data-position="closed"],
#right-hand[data-position="closed"] {
background-color: darkred;
}
#left-hand[data-position="opened"],
#right-hand[data-position="opened"] {
background-color: darkgreen;
}
</style>
</head>
<body>
<div id="left-hand" data-position="closed">Left Hand</div>
<div id="right-hand" data-position="closed">Right Hand</div>
</body>
<script>
let leftHand = document.getElementById('left-hand');
let rightHand = document.getElementById('right-hand');
window.electronAPI.leftHand((event, position) => {
console.log('leftHand ' + position); // Testing
leftHand.dataset.position = position;
});
window.electronAPI.rightHand((event, position) => {
console.log('rightHand ' + position); // Testing
rightHand.dataset.position = position;
});
</script>
</html>
Ok this will be long please bear with me (Im new to Javascript programming btw)
So our task in school is to get an open source game and modify it
The one I found is good it's a tank shooter, however the thing is the game instantly start upon opening the index.html I wanted to add start menu/button and have option for 2,3,or 4 players
Here is the code in index.html, I'll put my observations next to it
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Neon Tankz</title>
<link rel="stylesheet" href="style.css">
<script src="p5.min.js"></script>
<script src="p5.play.js"></script>
<script src="Extensions/array-extensions.js"></script>
<script src="Extensions/vector-extensions.js"></script>
<script src="Entities/sprite-entity.js"></script>
<script src="Entities/Map/tile.js"></script>
<script src="Entities/Map/grid.js"></script>
<script src="Entities/Map/game-map.js"></script>
<script src="Entities/Scoreboard/score.js"></script>
<script src="Entities/Scoreboard/scoreboard.js"></script>
<script src="Entities/bullet.js"></script>
<script src="Entities/cannon.js"></script>
<script src="Entities/player.js"></script>
<script src="main.js"></script>
</head>
<body style="background-color: black;display: flex; justify-content: center;">
<div>
<input type="button" style="position: absolute; top: 0; left: 0;" onclick="location.reload(true);"
value="Reload">
<button onclick="stopMusic()"> Staph Moosic</button>
<button id="mylink" onclick="myclick()">
Load
</button>
</div>
</body>
</html>
You might be confused about the load, reload and Staph Moosic
Load = is a testing button for start or loading game,
Reload = reloads the game, or refresh the browser,
Staph Moosic = stops the music (I added a music in main.js)
Here are the observations I noticed and what I did:
main.js has preload() and load() function and it is the file where I can modify no. of players, removing it will leave the index blank
So I assumed that with bunch of loaded scripts, main.js is needed to run?
So I tried to make another copy of main.js (main2.js) but this file is modified to only two players
and changed the previous to
<script src= "main2.js">
and it works, the game started with two players only.
At this point, I don't know what solution I can do apart from creating multiple copies of index.html (rename each of them) and each has different main.js depending on how many players
and have index.html to just an html that links to those multiple htmls
I know it's kind of weird solution are there other solutions?
EDIT
This is the code in main.js
/*Im trying to add more maps value1 and value2 are for the maps,
Currently there are two maps (map1.txt and map2.txt)
It doesn't do anything much, don't mind this lool
*/
var value1 = "1";
var value2 = "2";
//This is for the background music
var myMusic;
//This code is to make the myMusic loop
myMusic = new Audio("Images/bgMusic.wav");
myMusic.addEventListener('ended', function () {
this.currentTime = 0;
this.play();
}, false);
//This code is to play music
myMusic.play();
function start() {
decision = true;
}
const config = {
screen: {
width: 1000,
height: 500,
},
players: [],
groups: {},
bullets: {
deathTimer: 4000
},
mapTile: {
dimension: 20
//this changes the size of the map previously 22
}
};
function preload() {
loadStrings("Entities/Map/map" + value2 + ".txt", mapText => config.map = new GameMap(mapText));
for (const group of ["players", "bullets", "tiles"]) {
config.groups[group] = new Group();
}
function load() {
function removePlayer() {
config.players.remove(this);
if (config.players.length === 1) {
let resetBoard = false;
for (const score in config.scoreboard.scores) {
if (config.scoreboard.scores[score].value > 8) {
config.scoreboard.reset();
resetBoard = true;
break;
}
}
if (!resetBoard) {
config.scoreboard.scores[config.players[0].name].increment();
}
//in my observation, the player score which is below will only increment if that player stays
//removing this, will not change the score no matter who survives
for (const player of config.players) {
player.destroy();
}
config.players.length = 0; //idk what this do but setting it to other value makes the screen hang after one wins
load();
}
}
//the no. of players can be determined
//When you remove this config.players.push...
//A player will be removed with no errors
config.players.push(new Player("Player1", "Happy", {
forward: 87, // W
backward: 83, // S
rotateLeft: 65, // A
rotateRight: 68, // D
shoot: 81 // Q this is the fire button for the player 1
}, removePlayer));
config.players.push(new Player("Player2", "Neutral", {
forward: 73, // I
backward: 75, // K
rotateLeft: 74, // J
rotateRight: 76, // L
shoot: 85 // U // this is the fire button for the player 2
}, removePlayer));
config.players.push(new Player("Player3", "Smiley", {
forward: 38, // Up arrow
backward: 40, // Down arrow
rotateLeft: 37, // Left arrow
rotateRight: 39, // Right arrow
shoot: 191 // Forward slash ('/') this is the fire button for the player 3
}, removePlayer));
config.players.push(new Player("Player4", "Neo", {
//the name "smiley" refers to the image that is provided
forward: 84, // T
backward: 71, // G
rotateLeft: 70, // F
rotateRight: 72, // H
shoot: 82 // R this is the fire button for the player 4
}, removePlayer));
//always take note when changing the controls, the program follows the ascii dec of UPPERCASE letters
}
load();
config.scoreboard = new Scoreboard(config.players);
}
function setup() {
createCanvas(config.screen.width, config.screen.height + 100);
//the 100 was added for the position of scoreboard?
}
function draw() {
clear();
config.map.update();
config.map.draw();
config.groups.bullets.draw();
//deleting this will make a bullet invisible
config.groups.players.overlap(config.groups.bullets, function (player, bullet) {
var mySound;
mySound = new Audio("Images/boxHit.wav");
mySound.play();
player.spriteEntity.destroy();
bullet.spriteEntity.destroy();
});
for (const player of config.players) {
player.update(config.players);
player.draw();
}
config.scoreboard.draw();
}
function keyPressed(event) {
for (const player of config.players) {
player.keyPressed(event.keyCode);
}
}
//This function is to stop music
//it doesnt totally work, because when a player gets hit, then the play will go on
function stopMusic() {
myMusic.pause();
}
function playMusic() {
myMusic.play();
}
Should I add all the js files? It might make the question long, Im new to this stack overflow
About this index.html goes blank
I'm sorry for misunderstanding, the index file doesnt go white and all
What I meant is to be like this
This is the game with
<script src="main.js"></script>
This is the game without
<script src="main.js"></script>
I'm sorry for misunderstanding I have level 0 in communication skills xD
I am new to phaser and game development.
I followed the below tutorial.
https://medium.com/#michaelwesthadley/modular-game-worlds-in-phaser-3-tilemaps-1-958fc7e6bbd6
I downloaded and Tiled software and made a simple map with a tileset I got from OpenGameArt.org. Unfortunately, nothing gets loaded on the browser screen, I just see a black rectangle instead of the map. I find no errors in the console. I am running this using XAMPP in Windows 10.
I will paste all my code here, let me know if you find anything wrong.
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdn.jsdelivr.net/npm/phaser#3.15.1/dist/phaser-arcade-physics.min.js">
</script>
</head>
<body>
<script src="index.js" type="text/javascript"></script>
</body>
</html>
The is the index.js file
const config = {
type: Phaser.AUTO, // Which renderer to use
width: 100, // Canvas width in pixels
height: 100, // Canvas height in pixels
parent: "game-container", // ID of the DOM element to add the canvas to
scene: {
preload: preload,
create: create,
update: update
}
};
const game = new Phaser.Game(config);
function preload() {
// Runs once, loads up assets like images and audio
this.load.image("tiles", "assets/tilesets/GoldBricks.png");
this.load.tilemapTiledJSON("map", "assets/tilemaps/mario.json");
}
function create() {
// Runs once, after all assets in preload are loaded
const map = this.make.tilemap({ key: "map" });
const tileset = map.addTilesetImage("GoldBricks", "tiles");
// Parameters: layer name (or index) from Tiled, tileset, x, y
const belowLayer = map.createStaticLayer("Tile Layer 1", tileset, 0, 0);
}
function update(time, delta) {
// Runs once per frame for the duration of the scene
}
EDIT: Below is the json file
{ "compressionlevel":-1,
"height":100,
"infinite":false,
"layers":[
{
"compression":"",
"data":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAAAAWAAAAFwAAABgAAAAZAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAVAAAAFgAAABcAAAAYAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAkQAAAJIAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAANgAAADYAAAA2AAAAA==",
"encoding":"base64",
"height":100,
"id":1,
"name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":100,
"x":0,
"y":0
}],
"nextlayerid":2,
"nextobjectid":1,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.3.2",
"tileheight":32,
"tilesets":[
{
"columns":16,
"firstgid":1,
"image":"..\/..\/..\/..\/..\/Users\/Shashank A C\/Downloads\/Goldbricksandgrass\/GoldBricks.png",
"imageheight":512,
"imagewidth":512,
"margin":0,
"name":"GoldBricks",
"spacing":0,
"tilecount":256,
"tileheight":32,
"tilewidth":32
}],
"tilewidth":32,
"type":"map",
"version":1.2,
"width":100
}
I am also seeing and error in the console now.
Uncaught TypeError: Cannot read property '0' of undefined
at StaticTilemapLayer.upload (phaser.js:74806)
at StaticTilemapLayerWebGLRenderer [as renderWebGL] (phaser.js:122959)
at WebGLRenderer.render (phaser.js:65133)
at CameraManager.render (phaser.js:114533)
at Systems.render (phaser.js:27184)
at SceneManager.render (phaser.js:46818)
at Game.step (phaser.js:109346)
at TimeStep.step (phaser.js:106091)
at step (phaser.js:66488)
UPDATE: Check this file structure --
https://next.plnkr.co/edit/OqywHzLC80aZMGeF
======
Need to see the JSON file to completely understand the issue, but I will just try to speculate. Make sure your JSON file has below settings correctly:
"tilesets":[
{
"image":"path/to/GoldBricks.png",
"name":"GoldBricks"
...
}
]
In some cases Tiled includes wrong/different path to the image file, so make sure to check that part. If there is no image path, embed it in Tiled.
In addition, the name value should match the first parameter of map.addTilesetImage(). Hope it helps!
I had a similar problem myself, the solution was going back to Tiled software and check: 'Embed tileset' on each tileset of the map.
Alright, I asked in the phaser community forum itself and got some help.
The tilemap layer is taller than the game canvas so the visible tiles are out of sight. The solution is to add the below code in the create function.
this.cameras.main.centerOn(800, 1300);
So I am currently coding a game for a school project using Phaser. I am very new to Phaser and I know pretty much no JavaScript. I have looked up a lot of possible fixes online but none seem to do the trick for me. I attached my code in case I am missing something. When I change the directory of the image to an image link it works just fine but any images from my PC do not load.
var gameState = {}
function preload() {
this.load.image('monkey', 'https://vignette.wikia.nocookie.net/jungle-thick/images/0/0c/Monky.png/revision/latest?cb=20190826180942');
this.load.image('full', 'C:/Users/Public/Trash Monkey/Trash Monkey Website/Assets/Images')
;
}
function create() {
var style = {
fill: '#FFF',
font: 'Bold 32px Arial'
}
gameState.cursors = this.input.keyboard.createCursorKeys();
gameState.menuBox = this.add.rectangle(200, 250, 150, 80, 0xB5CF16);
gameState.menu = this.add.text(147.5, 231, 'START', style);
gameState.menuBox.setInteractive();
gameState.menuBox.on('pointerup', function() {
gameState.menuBox.x = 600
gameState.menu.x = 600
if(gameState.randomizer == 0) {
gameState.monkey.x = 200;
gameState.monkey.y = 0;
}
});
gameState.randomizer = Math.floor(Math.random());
if(gameState.randomizer == 0) {
gameState.monkey = this.add.sprite(2000, 0, 'monkey');
}
gameState.fullHealth = this.add.sprite(300, 37.5, 'full');
}
function update() {
if(gameState.randomizer == 0) {
gameState.monkey.y += 3;
if (gameState.cursors.right.isDown) {
gameState.monkey.x = 300;
}
if (gameState.cursors.left.isDown) {
gameState.monkey.x = 100;
}
if (gameState.cursors.up.isDown) {
gameState.monkey.x = 200;
}
if (gameState.cursors.down.isDown) {
gameState.monkey.y += 15;
}
if (gameState.monkey.y >= 500) {
gameState.monkey.y = 0;
}
}
}
var config = {
type: Phaser.AUTO,
width: 400,
height: 500,
backgroundColor: "#2191E8",
parent: 'my-game',
scene: {
preload,
create,
update
}
}
var game = new Phaser.Game(config);
You need to adjust how you are developing. The crux of the matter is that you are trying to load a file on your local computer through the browser's JavaScript context and that is plainly not allowed due to the security implications.
See:
Access to local files only work with local HTML file
The solution is to serve your project using a static server like Apache, NGINX, node.js, whatever. It doesn't matter which one. You don't need a complex solution. You just need something that will serve your work on your local machine so that you can play nice with the Browser's security concerns.
The most straightforward way to deal with the need to use a static server is to use an integrated development environment (IDE) as many will do this for you. Again it doesn't matter which one as long as it will serve your content. Eclipse and Netbeans both have project templates for static projects and are fairly easy to set up. VSCode has a Live Server extension that lets you serve a folder with just a right click.