Add terrain object generation and day/night cycle functionality
- Added new tile properties for forestTree, palmTree, and boulder counts in game-map.json and game-map.tmx - Implemented ObjectManager class to handle dynamic object spawning based on tile properties - Added CycleManager class to manage day/night cycle transitions and visual effects - Enhanced player collision detection with both map layers and spawned objects - Updated Game scene to initialize and update new managers - Adjusted player body size for better collision handling
This commit is contained in:
parent
13abba7061
commit
67c207e54e
|
|
@ -307,6 +307,129 @@
|
|||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"forestTree",
|
||||
"type":"int",
|
||||
"value":40
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"properties":[
|
||||
{
|
||||
"name":"forestTree",
|
||||
"type":"int",
|
||||
"value":2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"properties":[
|
||||
{
|
||||
"name":"forestTree",
|
||||
"type":"int",
|
||||
"value":5
|
||||
},
|
||||
{
|
||||
"name":"palmTree",
|
||||
"type":"int",
|
||||
"value":2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":4,
|
||||
"properties":[
|
||||
{
|
||||
"name":"forestTree",
|
||||
"type":"int",
|
||||
"value":0
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":7,
|
||||
"properties":[
|
||||
{
|
||||
"name":"forestTree",
|
||||
"type":"int",
|
||||
"value":8
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":8,
|
||||
"properties":[
|
||||
{
|
||||
"name":"forestTree",
|
||||
"type":"int",
|
||||
"value":15
|
||||
},
|
||||
{
|
||||
"name":"palmTree",
|
||||
"type":"int",
|
||||
"value":2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":10,
|
||||
"properties":[
|
||||
{
|
||||
"name":"palmTree",
|
||||
"type":"int",
|
||||
"value":15
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"properties":[
|
||||
{
|
||||
"name":"palmTree",
|
||||
"type":"int",
|
||||
"value":10
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":12,
|
||||
"properties":[
|
||||
{
|
||||
"name":"boulder",
|
||||
"type":"int",
|
||||
"value":2
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":13,
|
||||
"properties":[
|
||||
{
|
||||
"name":"boulder",
|
||||
"type":"int",
|
||||
"value":8
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":14,
|
||||
"properties":[
|
||||
{
|
||||
"name":"boulder",
|
||||
"type":"int",
|
||||
"value":20
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":16,
|
||||
"properties":[
|
||||
{
|
||||
"name":"boulder",
|
||||
"type":"int",
|
||||
"value":15
|
||||
},
|
||||
{
|
||||
"name":"forestTree",
|
||||
"type":"int",
|
||||
"value":2
|
||||
}]
|
||||
}],
|
||||
"tilewidth":100
|
||||
}],
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
|
|
@ -10,6 +10,69 @@
|
|||
<property name="collides" type="bool" value="true"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="1">
|
||||
<properties>
|
||||
<property name="forestTree" type="int" value="40"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="2">
|
||||
<properties>
|
||||
<property name="forestTree" type="int" value="2"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="3">
|
||||
<properties>
|
||||
<property name="forestTree" type="int" value="5"/>
|
||||
<property name="palmTree" type="int" value="2"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="4">
|
||||
<properties>
|
||||
<property name="forestTree" type="int" value="0"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="7">
|
||||
<properties>
|
||||
<property name="forestTree" type="int" value="8"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="8">
|
||||
<properties>
|
||||
<property name="forestTree" type="int" value="15"/>
|
||||
<property name="palmTree" type="int" value="2"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="10">
|
||||
<properties>
|
||||
<property name="palmTree" type="int" value="15"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="11">
|
||||
<properties>
|
||||
<property name="palmTree" type="int" value="10"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="12">
|
||||
<properties>
|
||||
<property name="boulder" type="int" value="2"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="13">
|
||||
<properties>
|
||||
<property name="boulder" type="int" value="8"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="14">
|
||||
<properties>
|
||||
<property name="boulder" type="int" value="20"/>
|
||||
</properties>
|
||||
</tile>
|
||||
<tile id="16">
|
||||
<properties>
|
||||
<property name="boulder" type="int" value="15"/>
|
||||
<property name="forestTree" type="int" value="2"/>
|
||||
</properties>
|
||||
</tile>
|
||||
</tileset>
|
||||
<layer id="1" name="main" width="60" height="40">
|
||||
<data encoding="csv">
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,74 @@
|
|||
export class CycleManager {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.currentCycle = 'day';
|
||||
this.cycleTimer = 0;
|
||||
this.cycleDuration = 120; // 3 minutes
|
||||
this.cycles = ['day', 'evening', 'night', 'morning'];
|
||||
|
||||
// Cycle tint values
|
||||
this.tintValues = {
|
||||
'day': 0xffffff, // White (no tint)
|
||||
'evening': 0xffb085, // Orange tint
|
||||
'night': 0x222244, // Dark blue tint
|
||||
'morning': 0xffffaa // Light yellow tint
|
||||
};
|
||||
|
||||
// Cycle tint values
|
||||
this.playerTintValues = {
|
||||
'day': 0xffffff, // White (no tint)
|
||||
'evening': 0xffccaa, // Orange tint
|
||||
'night': 0x8888ff, // Dark blue tint
|
||||
'morning': 0xffffdd // Light yellow tint
|
||||
};
|
||||
|
||||
this.cycleText = null;
|
||||
}
|
||||
|
||||
init() {
|
||||
// Create cycle display text in upper right corner
|
||||
this.cycleText = this.scene.add.text(
|
||||
40,
|
||||
40,
|
||||
'Day',
|
||||
{ fontSize: '24px', fill: '#ffffff' }
|
||||
).setShadow(3,3, '#333', 5).setScrollFactor(0);
|
||||
}
|
||||
|
||||
update(delta) {
|
||||
// Handle cycle timing
|
||||
this.cycleTimer += delta / 1000; // Convert ms to seconds
|
||||
|
||||
if (this.cycleTimer >= this.cycleDuration) {
|
||||
this.nextCycle();
|
||||
this.cycleTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
nextCycle() {
|
||||
const currentIndex = this.cycles.indexOf(this.currentCycle);
|
||||
const nextIndex = (currentIndex + 1) % this.cycles.length;
|
||||
|
||||
this.currentCycle = this.cycles[nextIndex];
|
||||
|
||||
// Update display text
|
||||
if (this.cycleText) {
|
||||
this.cycleText.setText(this.currentCycle.charAt(0).toUpperCase() + this.currentCycle.slice(1));
|
||||
}
|
||||
|
||||
// Apply tint to the terrain layer
|
||||
this.applyTint(this.scene.mainLayer);
|
||||
}
|
||||
|
||||
applyTint(layer) {
|
||||
if (layer && this.tintValues[this.currentCycle]) {
|
||||
layer.setTint(this.tintValues[this.currentCycle]);
|
||||
this.scene.player.setTint(this.playerTintValues[this.currentCycle]);
|
||||
this.scene.objects.setTint(this.playerTintValues[this.currentCycle]);
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentCycle() {
|
||||
return this.currentCycle;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
export class ObjectManager {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.objects = [];
|
||||
}
|
||||
|
||||
init() {
|
||||
// Parse main layer for object properties and create objects
|
||||
this.parseLayerForObjects();
|
||||
}
|
||||
|
||||
parseLayerForObjects() {
|
||||
const map = this.scene.mainLayer.tilemap;
|
||||
const layerData = this.scene.mainLayer.layer;
|
||||
|
||||
// Iterate through all tiles in the layer
|
||||
for (let y = 0; y < layerData.height; y++) {
|
||||
for (let x = 0; x < layerData.width; x++) {
|
||||
const tile = this.scene.mainLayer.getTileAt(x, y);
|
||||
|
||||
if (tile && tile.properties) {
|
||||
// Check for object-related properties
|
||||
this.createObjectFromTile(tile, x*100+50, y*100+50);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createObjectFromTile(tile, x, y) {
|
||||
// Example: Look for a "type" property to determine what object to create
|
||||
const objectType = tile.properties;
|
||||
|
||||
Object.keys(objectType).forEach(key => {
|
||||
const rand = Phaser.Math.Between(1,300);
|
||||
|
||||
if (key === 'palmTree' && rand <= objectType[key]) {
|
||||
const palmTree = this.scene.physics.add.sprite(x, y, 'objects', 0);
|
||||
this.scene.objects.add(palmTree);
|
||||
palmTree.setImmovable(true).setSize(60,100);
|
||||
} else if (key === 'forestTree' && rand <= objectType[key]) {
|
||||
const forestRand = Phaser.Math.Between(1,4);
|
||||
const forestTree = this.scene.physics.add.sprite(x, y, 'objects', forestRand);
|
||||
this.scene.objects.add(forestTree);
|
||||
forestTree.setImmovable(true).setSize(50,100);
|
||||
} else if (key === 'boulder' && rand <= objectType[key]) {
|
||||
const boulder = this.scene.physics.add.sprite(x, y, 'objects', 20);
|
||||
this.scene.objects.add(boulder);
|
||||
boulder.setImmovable(true);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
createEnemy(x, y, properties) {
|
||||
// Placeholder for enemy creation logic
|
||||
console.log(`Creating enemy at (${x}, ${y}) with properties:`, properties);
|
||||
|
||||
// Example implementation:
|
||||
// const enemy = this.scene.physics.add.sprite(
|
||||
// x * tileWidth + tileWidth / 2,
|
||||
// y * tileHeight + tileHeight / 2,
|
||||
// 'enemy-sprite'
|
||||
// );
|
||||
// this.objects.push(enemy);
|
||||
}
|
||||
|
||||
createCollectible(x, y, properties) {
|
||||
// Placeholder for collectible creation logic
|
||||
console.log(`Creating collectible at (${x}, ${y}) with properties:`, properties);
|
||||
|
||||
// Example implementation:
|
||||
// const collectible = this.scene.physics.add.sprite(
|
||||
// x * tileWidth + tileWidth / 2,
|
||||
// y * tileHeight + tileHeight / 2,
|
||||
// 'collectible-sprite'
|
||||
// );
|
||||
// this.objects.push(collectible);
|
||||
}
|
||||
|
||||
createPlatform(x, y, properties) {
|
||||
// Placeholder for platform creation logic
|
||||
console.log(`Creating platform at (${x}, ${y}) with properties:`, properties);
|
||||
|
||||
// Example implementation:
|
||||
// const platform = this.scene.physics.add.sprite(
|
||||
// x * tileWidth + tileWidth / 2,
|
||||
// y * tileHeight + tileHeight / 2,
|
||||
// 'platform-sprite'
|
||||
// );
|
||||
// platform.setImmovable(true);
|
||||
// this.objects.push(platform);
|
||||
}
|
||||
|
||||
update(delta) {
|
||||
// Update all created objects
|
||||
this.objects.forEach(object => {
|
||||
if (object.update) {
|
||||
object.update(delta);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ export class Player extends Phaser.GameObjects.Sprite {
|
|||
scene.add.existing(this);
|
||||
scene.physics.world.enable(this);
|
||||
this.body.setCollideWorldBounds(true);
|
||||
this.body.setSize(50,100);
|
||||
|
||||
// Set player properties
|
||||
this.speed = 200;
|
||||
|
|
@ -15,7 +16,6 @@ export class Player extends Phaser.GameObjects.Sprite {
|
|||
|
||||
// Add input listener for mouse clicks
|
||||
scene.input.on('pointerdown', (pointer) => {
|
||||
console.log(pointer);
|
||||
this.moveToPoint(pointer.worldX, pointer.worldY);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
import { Player } from '../player.js';
|
||||
import { CycleManager } from '../cycle.js';
|
||||
import { ObjectManager } from '../objects.js';
|
||||
|
||||
export class Game extends Phaser.Scene {
|
||||
constructor() {
|
||||
super({ key: 'Game' });
|
||||
this.cycleManager = null;
|
||||
this.objectManager = null;
|
||||
this.mainLayer = null;
|
||||
}
|
||||
|
||||
preload() {
|
||||
|
|
@ -11,6 +16,12 @@ export class Game extends Phaser.Scene {
|
|||
frameWidth: 100,
|
||||
frameHeight: 100
|
||||
});
|
||||
|
||||
// Load objects sprite
|
||||
this.load.spritesheet('objects', 'assets/images/objects.png', {
|
||||
frameWidth: 100,
|
||||
frameHeight: 100
|
||||
});
|
||||
|
||||
// Load tilemap
|
||||
this.load.tilemapTiledJSON('game-map', 'assets/game-map.json');
|
||||
|
|
@ -26,7 +37,7 @@ export class Game extends Phaser.Scene {
|
|||
const terrainTileset = map.addTilesetImage('terrain', 'terrain-tileset');
|
||||
|
||||
// Create layer named "main"
|
||||
const mainLayer = map.createLayer('main', terrainTileset, 0, 0)
|
||||
this.mainLayer = map.createLayer('main', terrainTileset, 0, 0)
|
||||
.setCollisionByProperty({ collides: true });
|
||||
|
||||
// Set world bounds based on tilemap dimensions
|
||||
|
|
@ -34,21 +45,46 @@ export class Game extends Phaser.Scene {
|
|||
const worldHeight = map.heightInPixels;
|
||||
this.physics.world.setBounds(0, 0, worldWidth, worldHeight);
|
||||
|
||||
// Initialize object manager
|
||||
this.objects = this.physics.add.group();
|
||||
this.objectManager = new ObjectManager(this);
|
||||
this.objectManager.init();
|
||||
|
||||
// Create player at center of screen
|
||||
this.player = new Player(this, 1600, 3100);
|
||||
|
||||
// Physics Collisions
|
||||
this.physics.add.collider(this.player, mainLayer);
|
||||
this.physics.add.collider(this.player, this.mainLayer);
|
||||
this.physics.add.collider(this.player, this.objects);
|
||||
|
||||
// Make camera follow the player
|
||||
this.cameras.main.startFollow(this.player);
|
||||
this.cameras.main.setBounds(0, 0, worldWidth, worldHeight);
|
||||
|
||||
// Initialize cycle manager
|
||||
this.cycleManager = new CycleManager(this);
|
||||
this.cycleManager.init();
|
||||
}
|
||||
|
||||
update() {
|
||||
update(time, delta) {
|
||||
// Update player
|
||||
if (this.player) {
|
||||
this.player.update();
|
||||
}
|
||||
|
||||
// Update cycle manager
|
||||
if (this.cycleManager) {
|
||||
this.cycleManager.update(delta);
|
||||
|
||||
// Apply tint to main layer when needed
|
||||
if (this.mainLayer && this.cycleManager.getCurrentCycle() !== 'day') {
|
||||
this.cycleManager.applyTint(this.mainLayer);
|
||||
}
|
||||
}
|
||||
|
||||
// Update object manager
|
||||
if (this.objectManager) {
|
||||
this.objectManager.update(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue