I’m trying to do the basic set up for game, where you are in a room and you can look left or right endlessly and you will still be rotating in a room (2d, just moving pictures).
I’ve got the main logic for this movement, but there is one bug, which I can’t figure out.
The bug is appearing when the canvas is smaller then the image itself (i have the scaling that the room always keep the same aspect ratio, can’t be bigger then the original image, so it won’t be blurry, but can be smaller). So when the canvas is smaller then original image (1000px), the break when you scroll the room atleast one cycle (when one side of the room will be moved to another side, so the loop would be infinite). I’m stuck with this for whole day and can’t figure out why it is happening when I tried some debugging. Could someone help please?
Link to the video where the bug is reproduced
In the video you can see, that you can scroll though the sides of the room (4 - left, front, right, back), but when you go outside these sides, so one of the sides have to be moved for it to be infinite, the logic breaks.
My resize setting is scale: { mode: Phaser.Scale.RESIZE, width: '100%', height: '100%' }
And most of the code which is relevant is here:
allGameObjects: any = {}
directions = ['left', 'front', 'right', 'back']
room_direction: 'left' | 'front' | 'right' | 'back' = 'back'
direction_shift: number = 0
getScale(objectWidth: number, objectHeight: number) {
const { width, height } = this.game.canvas;
const widthRatio = width / objectWidth
const heightRatio = height / objectHeight
if (widthRatio < heightRatio) {
const newWidth = Math.min(objectWidth, width)
const newHeight = (newWidth / objectWidth) * objectHeight
return { scaleX: newWidth / objectWidth, scaleY: newHeight / objectHeight }
} else {
const newHeight = Math.min(objectHeight, height)
const newWidth = (newHeight / objectHeight) * objectWidth
return { scaleX: newWidth / objectWidth, scaleY: newHeight / objectHeight }
}
}
getXFromMap(direction: 'front' | 'left' | 'right' | 'back') {
if (direction === 'left') return -this.mapSize.width
else if (direction === 'front') return 0
else if (direction === 'right') return this.mapSize.width
return this.mapSize.width * 2
}
createSide(direction: 'front' | 'left' | 'right' | 'back') {
const map = this.add.image(0, 0, `room_${direction}`)
const mapScale = this.getScale(map.width, map.height)
const mapSize = { width: map.width * mapScale.scaleX, height: map.height * mapScale.scaleY }
this.mapSize = mapSize
const mapSideX = this.getXFromMap(direction)
const directionIndex = this.directions.indexOf(this.room_direction)
const directionX = this.mapSize.width * directionIndex - this.mapSize.width
map.setX(mapSideX - directionX)
map.setScale(mapScale.scaleX, mapScale.scaleY)
const mapContainer = this.add.container(0, 0, map)
if (!this.allGameObjects.map) this.allGameObjects.map = { [direction]: mapContainer }
else this.allGameObjects.map[direction] = mapContainer
}
createMap() {
const { width, height } = this.game.canvas
this.createSide('front')
this.createSide('left')
this.createSide('right')
this.createSide('back')
this.allGameObjects.maps = this.add.container(width / 2, height / 2, Object.values(this.allGameObjects.map))
}
createRoomControls() {
const { width, height } = this.game.canvas
const leftArrow = this.add.rectangle(20, height / 2 - 25, 40, 50, 0xff0000)
.setInteractive({
hitArea: new Phaser.Geom.Rectangle(0, 0, 40, 50),
hitAreaCallback: Phaser.Geom.Rectangle.Contains,
useHandCursor: true,
})
const rightArrow = this.add.rectangle(width - 20, height / 2 - 25, 40, 50, 0xff0000)
.setInteractive({
hitArea: new Phaser.Geom.Rectangle(0, 0, 40, 50),
hitAreaCallback: Phaser.Geom.Rectangle.Contains,
useHandCursor: true,
})
const controlsContainer = this.add.container()
controlsContainer.add([leftArrow, rightArrow])
this.allGameObjects.controls = controlsContainer
this.input.enableDebug(leftArrow)
this.input.enableDebug(rightArrow)
leftArrow.on('pointerdown', () => {
if (!this.room_changin_direction) this.animationMovingMap('right')
})
rightArrow.on('pointerdown', () => {
if (!this.room_changin_direction) this.animationMovingMap('left')
})
}
create() {
this.createMap()
this.createRoomControls()
this.scale.on('resize', this.resize, this);
}
getDirection(direction: 'left' | 'right') {
const directions: any = ['left', 'front', 'right', 'back']
const directionIndex = directions.indexOf(this.room_direction)
var newDirectionIndex = direction === 'left' ? directionIndex + 1 : directionIndex - 1
if (newDirectionIndex < 0) newDirectionIndex = directions.length - 1
if (newDirectionIndex > directions.length - 1) newDirectionIndex = 0
return directions[newDirectionIndex]
}
animationMovingMap(direction: 'left' | 'right') {
const mapContainer = this.allGameObjects.maps
const newDirection = this.getDirection(direction)
const map = this.allGameObjects.map
// move map
if (direction === 'right' && this.directions[0] === this.room_direction) {
map[newDirection].setX(map[newDirection].x - this.mapSize.width * 4)
this.directions.unshift(this.directions[this.directions.length - 1])
this.directions.pop()
this.direction_shift -= 1
} else if (direction === 'left' && this.directions[this.directions.length - 1] === this.room_direction) {
map[newDirection].setX(map[newDirection].x + this.mapSize.width * 4)
this.directions.push(this.directions[0])
this.directions.shift()
this.direction_shift += 1
}
// move animation
this.tweens.add({
targets: mapContainer,
x: direction === 'left' ? mapContainer.x - this.mapSize.width : mapContainer.x + this.mapSize.width,
ease: 'Power1',
duration: 1000
}).on('complete', () => {
this.room_direction = newDirection
})
}
resize(gameSize: any) {
const { width, height } = gameSize
// maps resize
const mapContainer = this.allGameObjects.maps
const maps = Object.values(this.allGameObjects.map).map((container: any) => container.list[0])
const mapGameObjects = Object.values(this.allGameObjects.map).map((container: any) => container.list)
const keys = Object.entries(this.allGameObjects.map)
const map = maps[0]
const mapScale = this.getScale(map.width, map.height)
const mapSize = { width: map.width * mapScale.scaleX, height: map.height * mapScale.scaleY }
this.mapSize = mapSize
mapContainer.setX(width / 2)
mapContainer.setY(height / 2)
maps.forEach((map: any, index: number) => {
const gameObjects = mapGameObjects[index]
const direction: any = keys[index][0]
const mapSideX = this.getXFromMap(direction)
const directionIndex = this.directions.indexOf(this.room_direction) + this.direction_shift
var directionX = this.mapSize.width * directionIndex - this.mapSize.width
map.setX(mapSideX - directionX)
map.setScale(mapScale.scaleX, mapScale.scaleY)
// controls resize
const controlsContainer = this.allGameObjects.controls
const rightArrow = controlsContainer.list[1]
const controlsLastWidth = rightArrow.x + rightArrow.width - 20
const controlsLastHeight = rightArrow.y + rightArrow.height - 25
controlsContainer.setScale(width / controlsLastWidth, height / 2 / controlsLastHeight)
}
getCoordsInCanvasFromRoom() {
const { width, height } = this.game.canvas;
return {
x: width / 2 - this.mapSize.width / 2,
y: height / 2 - this.mapSize.height / 2,
}
}