Begin adding entities to editor
This commit is contained in:
@@ -7,11 +7,13 @@
|
|||||||
|
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
|
#include "rpg/entity/entity.h"
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t tileCount;
|
uint32_t tileCount;
|
||||||
uint8_t modelCount;
|
uint8_t modelCount;
|
||||||
|
uint8_t entityCount;
|
||||||
} assetchunkheader_t;
|
} assetchunkheader_t;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
@@ -27,6 +29,15 @@ typedef struct {
|
|||||||
} assetchunkmodelheader_t;
|
} assetchunkmodelheader_t;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
entitytype_t entityType;
|
||||||
|
uint8_t localX;
|
||||||
|
uint8_t localY;
|
||||||
|
uint8_t localZ;
|
||||||
|
} assetchunkentityheader_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
errorret_t assetChunkLoad(assetcustom_t custom) {
|
errorret_t assetChunkLoad(assetcustom_t custom) {
|
||||||
assertNotNull(custom.output, "Output pointer cannot be NULL");
|
assertNotNull(custom.output, "Output pointer cannot be NULL");
|
||||||
assertNotNull(custom.zipFile, "Zip file pointer cannot be NULL");
|
assertNotNull(custom.zipFile, "Zip file pointer cannot be NULL");
|
||||||
@@ -62,6 +73,15 @@ errorret_t assetChunkLoad(assetcustom_t custom) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(header.entityCount > CHUNK_ENTITY_COUNT_MAX) {
|
||||||
|
zip_fclose(custom.zipFile);
|
||||||
|
errorThrow(
|
||||||
|
"Chunk asset has too many entities: %d (max %d).",
|
||||||
|
header.entityCount,
|
||||||
|
CHUNK_ENTITY_COUNT_MAX
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
chunk->meshCount = header.modelCount;
|
chunk->meshCount = header.modelCount;
|
||||||
|
|
||||||
// Read tile data
|
// Read tile data
|
||||||
@@ -122,5 +142,37 @@ errorret_t assetChunkLoad(assetcustom_t custom) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read entity data
|
||||||
|
for(uint8_t i = 0; i < header.entityCount; i++) {
|
||||||
|
assetchunkentityheader_t entityHeader;
|
||||||
|
bytesRead = zip_fread(
|
||||||
|
custom.zipFile, &entityHeader, sizeof(assetchunkentityheader_t)
|
||||||
|
);
|
||||||
|
if(bytesRead != sizeof(assetchunkentityheader_t)) {
|
||||||
|
zip_fclose(custom.zipFile);
|
||||||
|
errorThrow("Failed to read chunk entity header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t entityIndex = entityGetAvailable();
|
||||||
|
if(entityIndex == 0xFF) {
|
||||||
|
zip_fclose(custom.zipFile);
|
||||||
|
errorThrow("No available entity slots.");
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_t *entity = &ENTITIES[entityIndex];
|
||||||
|
entityInit(entity, (entitytype_t)entityHeader.entityType);
|
||||||
|
entity->position.x = (
|
||||||
|
(chunk->position.x * CHUNK_WIDTH) + entityHeader.localX
|
||||||
|
);
|
||||||
|
entity->position.y = (
|
||||||
|
(chunk->position.y * CHUNK_HEIGHT) + entityHeader.localY
|
||||||
|
);
|
||||||
|
entity->position.z = (
|
||||||
|
(chunk->position.z * CHUNK_DEPTH) + entityHeader.localZ
|
||||||
|
);
|
||||||
|
|
||||||
|
chunk->entities[i] = entityIndex;
|
||||||
|
}
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
@@ -8,12 +8,20 @@ ENTITY_DIR_WEST = 1
|
|||||||
ENTITY_DIR_EAST = 2
|
ENTITY_DIR_EAST = 2
|
||||||
ENTITY_DIR_NORTH = 3
|
ENTITY_DIR_NORTH = 3
|
||||||
|
|
||||||
|
ENTITY_COUNT = 256
|
||||||
|
|
||||||
|
ENTITY_TYPE_NULL = 0
|
||||||
|
ENTITY_TYPE_PLAYER = 1
|
||||||
|
ENTITY_TYPE_NPC = 2
|
||||||
|
ENTITY_TYPE_COUNT = 3
|
||||||
|
|
||||||
CHUNK_WIDTH = 16
|
CHUNK_WIDTH = 16
|
||||||
CHUNK_HEIGHT = 16
|
CHUNK_HEIGHT = 16
|
||||||
CHUNK_DEPTH = 4
|
CHUNK_DEPTH = 4
|
||||||
# CHUNK_VERTEX_COUNT_MAX = QUAD_VERTEXES * CHUNK_WIDTH * CHUNK_HEIGHT * 4
|
# CHUNK_VERTEX_COUNT_MAX = QUAD_VERTEXES * CHUNK_WIDTH * CHUNK_HEIGHT * 4
|
||||||
CHUNK_VERTEX_COUNT_MAX=6144
|
CHUNK_VERTEX_COUNT_MAX=6144
|
||||||
CHUNK_MESH_COUNT_MAX = 14
|
CHUNK_MESH_COUNT_MAX = 14
|
||||||
|
CHUNK_ENTITY_COUNT_MAX = 8
|
||||||
|
|
||||||
TILE_WIDTH = 16.0
|
TILE_WIDTH = 16.0
|
||||||
TILE_HEIGHT = 16.0
|
TILE_HEIGHT = 16.0
|
||||||
|
|||||||
@@ -188,4 +188,13 @@ entity_t * entityGetAt(const worldpos_t position) {
|
|||||||
} while(++ent, ent < &ENTITIES[ENTITY_COUNT]);
|
} while(++ent, ent < &ENTITIES[ENTITY_COUNT]);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t entityGetAvailable() {
|
||||||
|
entity_t *ent = ENTITIES;
|
||||||
|
do {
|
||||||
|
if(ent->type == ENTITY_TYPE_NULL) return ent - ENTITIES;
|
||||||
|
} while(++ent, ent < &ENTITIES[ENTITY_COUNT]);
|
||||||
|
|
||||||
|
return 0xFF;
|
||||||
}
|
}
|
||||||
@@ -11,8 +11,6 @@
|
|||||||
#include "entitytype.h"
|
#include "entitytype.h"
|
||||||
#include "npc.h"
|
#include "npc.h"
|
||||||
|
|
||||||
#define ENTITY_COUNT 256
|
|
||||||
|
|
||||||
typedef struct map_s map_t;
|
typedef struct map_s map_t;
|
||||||
|
|
||||||
typedef struct entity_s {
|
typedef struct entity_s {
|
||||||
@@ -69,4 +67,11 @@ void entityWalk(entity_t *entity, const entitydir_t direction);
|
|||||||
* @param pos The world position to check.
|
* @param pos The world position to check.
|
||||||
* @return Pointer to the entity at the position, or NULL if none.
|
* @return Pointer to the entity at the position, or NULL if none.
|
||||||
*/
|
*/
|
||||||
entity_t *entityGetAt(const worldpos_t pos);
|
entity_t *entityGetAt(const worldpos_t pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an available entity index.
|
||||||
|
*
|
||||||
|
* @return The index of an available entity, or 0xFF if none are available.
|
||||||
|
*/
|
||||||
|
uint8_t entityGetAvailable();
|
||||||
@@ -6,17 +6,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "duskdefs.h"
|
||||||
#include "rpg/entity/player.h"
|
#include "rpg/entity/player.h"
|
||||||
#include "npc.h"
|
#include "npc.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef uint8_t entitytype_t;
|
||||||
ENTITY_TYPE_NULL = 0,
|
|
||||||
|
|
||||||
ENTITY_TYPE_PLAYER,
|
|
||||||
ENTITY_TYPE_NPC,
|
|
||||||
|
|
||||||
ENTITY_TYPE_COUNT
|
|
||||||
} entitytype_t;
|
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
player_t player;
|
player_t player;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "rpgcamera.h"
|
#include "rpgcamera.h"
|
||||||
#include "rpgtextbox.h"
|
#include "rpgtextbox.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
errorret_t rpgInit(void) {
|
errorret_t rpgInit(void) {
|
||||||
memoryZero(ENTITIES, sizeof(ENTITIES));
|
memoryZero(ENTITIES, sizeof(ENTITIES));
|
||||||
@@ -26,17 +27,14 @@ errorret_t rpgInit(void) {
|
|||||||
rpgTextboxInit();
|
rpgTextboxInit();
|
||||||
|
|
||||||
// TEST: Create some entities.
|
// TEST: Create some entities.
|
||||||
entity_t *ent;
|
uint8_t entIndex = entityGetAvailable();
|
||||||
ent = &ENTITIES[0];
|
assertTrue(entIndex != 0xFF, "No available entity slots!.");
|
||||||
|
entity_t *ent = &ENTITIES[entIndex];
|
||||||
entityInit(ent, ENTITY_TYPE_PLAYER);
|
entityInit(ent, ENTITY_TYPE_PLAYER);
|
||||||
RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY;
|
RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY;
|
||||||
RPG_CAMERA.followEntity.followEntityId = ent->id;
|
RPG_CAMERA.followEntity.followEntityId = ent->id;
|
||||||
ent->position.x = 2, ent->position.y = 2;
|
ent->position.x = 2, ent->position.y = 2;
|
||||||
|
|
||||||
ent = &ENTITIES[1];
|
|
||||||
entityInit(ent, ENTITY_TYPE_NPC);
|
|
||||||
ent->position.x = 4, ent->position.y = 0, ent->position.z = 1;
|
|
||||||
|
|
||||||
// All Good!
|
// All Good!
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ typedef struct chunk_s {
|
|||||||
uint8_t meshCount;
|
uint8_t meshCount;
|
||||||
meshvertex_t vertices[CHUNK_VERTEX_COUNT_MAX];
|
meshvertex_t vertices[CHUNK_VERTEX_COUNT_MAX];
|
||||||
mesh_t meshes[CHUNK_MESH_COUNT_MAX];
|
mesh_t meshes[CHUNK_MESH_COUNT_MAX];
|
||||||
|
uint8_t entities[CHUNK_ENTITY_COUNT_MAX];
|
||||||
} chunk_t;
|
} chunk_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
|
#include "rpg/entity/entity.h"
|
||||||
|
|
||||||
map_t MAP;
|
map_t MAP;
|
||||||
|
|
||||||
@@ -126,6 +127,11 @@ void mapDispose() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void mapChunkUnload(chunk_t* chunk) {
|
void mapChunkUnload(chunk_t* chunk) {
|
||||||
|
for(uint8_t i = 0; i < CHUNK_ENTITY_COUNT_MAX; i++) {
|
||||||
|
if(chunk->entities[i] == 0xFF) break;
|
||||||
|
entity_t *entity = &ENTITIES[chunk->entities[i]];
|
||||||
|
entity->type = ENTITY_TYPE_NULL;
|
||||||
|
}
|
||||||
for(uint8_t i = 0; i < chunk->meshCount; i++) {
|
for(uint8_t i = 0; i < chunk->meshCount; i++) {
|
||||||
if(chunk->meshes[i].vertexCount == 0) continue;
|
if(chunk->meshes[i].vertexCount == 0) continue;
|
||||||
meshDispose(&chunk->meshes[i]);
|
meshDispose(&chunk->meshes[i]);
|
||||||
@@ -137,6 +143,7 @@ errorret_t mapChunkLoad(chunk_t* chunk) {
|
|||||||
|
|
||||||
chunk->meshCount = 0;
|
chunk->meshCount = 0;
|
||||||
memoryZero(chunk->meshes, sizeof(chunk->meshes));
|
memoryZero(chunk->meshes, sizeof(chunk->meshes));
|
||||||
|
memorySet(chunk->entities, 0xFF, sizeof(chunk->entities));
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer), "map/map/%d_%d_%d.dcf",
|
snprintf(buffer, sizeof(buffer), "map/map/%d_%d_%d.dcf",
|
||||||
chunk->position.x,
|
chunk->position.x,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ def processChunk(chunk):
|
|||||||
buffer.extend(b'DCF')# Header
|
buffer.extend(b'DCF')# Header
|
||||||
buffer.extend(len(chunk.tiles).to_bytes(4, 'little')) # Number of tiles
|
buffer.extend(len(chunk.tiles).to_bytes(4, 'little')) # Number of tiles
|
||||||
buffer.extend(len(models).to_bytes(1, 'little')) # Number of models
|
buffer.extend(len(models).to_bytes(1, 'little')) # Number of models
|
||||||
|
buffer.extend(len(chunk.entities).to_bytes(1, 'little')) # Number of entities
|
||||||
|
|
||||||
# Buffer tile data as array of uint8_t
|
# Buffer tile data as array of uint8_t
|
||||||
for tileIndex, tile in chunk.tiles.items():
|
for tileIndex, tile in chunk.tiles.items():
|
||||||
@@ -79,6 +80,14 @@ def processChunk(chunk):
|
|||||||
buffer.extend(bytearray(struct.pack('<f', vertex[0])))
|
buffer.extend(bytearray(struct.pack('<f', vertex[0])))
|
||||||
buffer.extend(bytearray(struct.pack('<f', vertex[1])))
|
buffer.extend(bytearray(struct.pack('<f', vertex[1])))
|
||||||
buffer.extend(bytearray(struct.pack('<f', vertex[2])))
|
buffer.extend(bytearray(struct.pack('<f', vertex[2])))
|
||||||
|
|
||||||
|
# For each entity
|
||||||
|
for entity in chunk.entities.values():
|
||||||
|
buffer.extend(entity.type.to_bytes(1, 'little'))
|
||||||
|
buffer.extend(entity.localX.to_bytes(1, 'little'))
|
||||||
|
buffer.extend(entity.localY.to_bytes(1, 'little'))
|
||||||
|
buffer.extend(entity.localZ.to_bytes(1, 'little'))
|
||||||
|
pass
|
||||||
|
|
||||||
# Write out map file
|
# Write out map file
|
||||||
relative = getAssetRelativePath(chunk.getFilename())
|
relative = getAssetRelativePath(chunk.getFilename())
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import os
|
|||||||
from dusk.event import Event
|
from dusk.event import Event
|
||||||
from dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, CHUNK_VERTEX_COUNT_MAX, TILE_SHAPE_NULL
|
from dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, CHUNK_VERTEX_COUNT_MAX, TILE_SHAPE_NULL
|
||||||
from dusk.tile import Tile
|
from dusk.tile import Tile
|
||||||
|
from dusk.entity import Entity
|
||||||
from editortool.map.vertexbuffer import VertexBuffer
|
from editortool.map.vertexbuffer import VertexBuffer
|
||||||
from OpenGL.GL import *
|
from OpenGL.GL import *
|
||||||
|
|
||||||
@@ -14,12 +15,16 @@ class Chunk:
|
|||||||
self.z = z
|
self.z = z
|
||||||
self.current = {}
|
self.current = {}
|
||||||
self.original = {}
|
self.original = {}
|
||||||
|
self.entities = {}
|
||||||
self.onChunkData = Event()
|
self.onChunkData = Event()
|
||||||
self.dirty = False
|
self.dirty = False
|
||||||
|
|
||||||
self.tiles = {}
|
self.tiles = {}
|
||||||
self.vertexBuffer = VertexBuffer()
|
self.vertexBuffer = VertexBuffer()
|
||||||
|
|
||||||
|
# TEST
|
||||||
|
self.addEntity()
|
||||||
|
|
||||||
tileIndex = 0
|
tileIndex = 0
|
||||||
for tz in range(CHUNK_DEPTH):
|
for tz in range(CHUNK_DEPTH):
|
||||||
for ty in range(CHUNK_HEIGHT):
|
for ty in range(CHUNK_HEIGHT):
|
||||||
@@ -100,4 +105,18 @@ class Chunk:
|
|||||||
return f"{dir_path}/{self.x}_{self.y}_{self.z}.json"
|
return f"{dir_path}/{self.x}_{self.y}_{self.z}.json"
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
self.vertexBuffer.draw()
|
self.vertexBuffer.draw()
|
||||||
|
|
||||||
|
def addEntity(self):
|
||||||
|
ent = Entity()
|
||||||
|
self.entities[len(self.entities)] = ent
|
||||||
|
self.map.onEntityData.invoke()
|
||||||
|
return ent
|
||||||
|
|
||||||
|
def removeEntity(self, entity):
|
||||||
|
for key, val in list(self.entities.items()):
|
||||||
|
if val == entity:
|
||||||
|
del self.entities[key]
|
||||||
|
self.map.onEntityData.invoke()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@@ -37,4 +37,11 @@ TILE_SHAPES = {}
|
|||||||
for key in defs.keys():
|
for key in defs.keys():
|
||||||
if key.startswith('TILE_SHAPE_'):
|
if key.startswith('TILE_SHAPE_'):
|
||||||
globals()[key] = int(defs.get(key))
|
globals()[key] = int(defs.get(key))
|
||||||
TILE_SHAPES[key] = int(defs.get(key))
|
TILE_SHAPES[key] = int(defs.get(key))
|
||||||
|
|
||||||
|
ENTITY_TYPES = {}
|
||||||
|
for key in defs.keys():
|
||||||
|
if key.startswith('ENTITY_TYPE_'):
|
||||||
|
globals()[key] = int(defs.get(key))
|
||||||
|
if key != 'ENTITY_TYPE_COUNT':
|
||||||
|
ENTITY_TYPES[key] = int(defs.get(key))
|
||||||
9
tools/dusk/entity.py
Normal file
9
tools/dusk/entity.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from dusk.defs import ENTITY_TYPE_NULL, ENTITY_TYPE_NPC
|
||||||
|
|
||||||
|
class Entity:
|
||||||
|
def __init__(self):
|
||||||
|
self.type = ENTITY_TYPE_NPC
|
||||||
|
self.localX = 0
|
||||||
|
self.localY = 8
|
||||||
|
self.localZ = 1
|
||||||
|
pass
|
||||||
@@ -19,6 +19,7 @@ class Map:
|
|||||||
self.chunks = {}
|
self.chunks = {}
|
||||||
self.onMapData = Event()
|
self.onMapData = Event()
|
||||||
self.onPositionChange = Event()
|
self.onPositionChange = Event()
|
||||||
|
self.onEntityData = Event()
|
||||||
self.mapFileName = None
|
self.mapFileName = None
|
||||||
self.lastFile = None
|
self.lastFile = None
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QGridLayout, QTreeWidget, QTreeWidgetItem, QComboBox
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QGridLayout, QTreeWidget, QTreeWidgetItem, QComboBox
|
||||||
from dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, TILE_SHAPES
|
from dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, TILE_SHAPES
|
||||||
|
|
||||||
class ChunkPanel(QWidget):
|
class ChunkPanel(QWidget):
|
||||||
@@ -6,25 +6,6 @@ class ChunkPanel(QWidget):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
self.chunkInfoLabel = QLabel("Tile Information")
|
|
||||||
layout.addWidget(self.chunkInfoLabel)
|
|
||||||
|
|
||||||
# Nav buttons
|
|
||||||
grid = QGridLayout()
|
|
||||||
self.btnUp = QPushButton("U")
|
|
||||||
self.btnN = QPushButton("N")
|
|
||||||
self.btnDown = QPushButton("D")
|
|
||||||
self.btnW = QPushButton("W")
|
|
||||||
self.btnS = QPushButton("S")
|
|
||||||
self.btnE = QPushButton("E")
|
|
||||||
|
|
||||||
grid.addWidget(self.btnUp, 0, 0)
|
|
||||||
grid.addWidget(self.btnN, 0, 1)
|
|
||||||
grid.addWidget(self.btnDown, 0, 2)
|
|
||||||
grid.addWidget(self.btnW, 1, 0)
|
|
||||||
grid.addWidget(self.btnS, 1, 1)
|
|
||||||
grid.addWidget(self.btnE, 1, 2)
|
|
||||||
layout.addLayout(grid)
|
|
||||||
|
|
||||||
# Tile shape dropdown
|
# Tile shape dropdown
|
||||||
self.tileShapeDropdown = QComboBox()
|
self.tileShapeDropdown = QComboBox()
|
||||||
@@ -39,16 +20,9 @@ class ChunkPanel(QWidget):
|
|||||||
layout.addWidget(self.tree) # Removed invalid stretch factor
|
layout.addWidget(self.tree) # Removed invalid stretch factor
|
||||||
|
|
||||||
# Add stretch so tree expands
|
# Add stretch so tree expands
|
||||||
layout.setStretchFactor(grid, 0)
|
|
||||||
layout.setStretchFactor(self.tree, 1)
|
layout.setStretchFactor(self.tree, 1)
|
||||||
|
|
||||||
# Event subscriptions
|
# Event subscriptions
|
||||||
self.btnN.clicked.connect(lambda: self.parent.map.moveRelative(0, -1, 0))
|
|
||||||
self.btnS.clicked.connect(lambda: self.parent.map.moveRelative(0, 1, 0))
|
|
||||||
self.btnE.clicked.connect(lambda: self.parent.map.moveRelative(1, 0, 0))
|
|
||||||
self.btnW.clicked.connect(lambda: self.parent.map.moveRelative(-1, 0, 0))
|
|
||||||
self.btnUp.clicked.connect(lambda: self.parent.map.moveRelative(0, 0, 1))
|
|
||||||
self.btnDown.clicked.connect(lambda: self.parent.map.moveRelative(0, 0, -1))
|
|
||||||
self.parent.map.onMapData.sub(self.onMapData)
|
self.parent.map.onMapData.sub(self.onMapData)
|
||||||
self.parent.map.onPositionChange.sub(self.onPositionChange)
|
self.parent.map.onPositionChange.sub(self.onPositionChange)
|
||||||
self.tileShapeDropdown.currentTextChanged.connect(self.onTileShapeChanged)
|
self.tileShapeDropdown.currentTextChanged.connect(self.onTileShapeChanged)
|
||||||
|
|||||||
70
tools/editortool/map/entitypanel.py
Normal file
70
tools/editortool/map/entitypanel.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QListWidget, QHBoxLayout, QPushButton, QLineEdit
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from dusk.entity import Entity
|
||||||
|
|
||||||
|
class EntityPanel(QWidget):
|
||||||
|
def __init__(self, parent):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.parent = parent
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
# Top panel placeholder
|
||||||
|
topWidget = QLabel("Entity Editor (top)")
|
||||||
|
layout.addWidget(topWidget)
|
||||||
|
|
||||||
|
# Name input
|
||||||
|
nameLayout = QHBoxLayout()
|
||||||
|
nameLabel = QLabel("Name:")
|
||||||
|
self.nameInput = QLineEdit()
|
||||||
|
nameLayout.addWidget(nameLabel)
|
||||||
|
nameLayout.addWidget(self.nameInput)
|
||||||
|
layout.addLayout(nameLayout)
|
||||||
|
|
||||||
|
# Entity list and buttons
|
||||||
|
self.entityList = QListWidget()
|
||||||
|
self.entityList.addItems(["Entity 1", "Entity 2", "Entity 3"])
|
||||||
|
layout.addWidget(self.entityList, stretch=1)
|
||||||
|
|
||||||
|
btnLayout = QHBoxLayout()
|
||||||
|
self.btnAdd = QPushButton("Add")
|
||||||
|
self.btnRemove = QPushButton("Remove")
|
||||||
|
btnLayout.addWidget(self.btnAdd)
|
||||||
|
btnLayout.addWidget(self.btnRemove)
|
||||||
|
layout.addLayout(btnLayout)
|
||||||
|
|
||||||
|
# Events
|
||||||
|
self.btnAdd.clicked.connect(self.onAddEntity)
|
||||||
|
self.btnRemove.clicked.connect(self.onRemoveEntity)
|
||||||
|
self.parent.map.onEntityData.sub(self.onEntityData)
|
||||||
|
self.entityList.itemClicked.connect(self.onEntityClicked)
|
||||||
|
self.entityList.itemDoubleClicked.connect(self.onEntityDoubleClicked)
|
||||||
|
|
||||||
|
# Call once to populate
|
||||||
|
self.onEntityData()
|
||||||
|
self.onEntityUnselect()
|
||||||
|
|
||||||
|
def onEntityUnselect(self):
|
||||||
|
self.nameInput.setText("")
|
||||||
|
|
||||||
|
def onEntityDoubleClicked(self, item):
|
||||||
|
print(f"Double clicked: {item.text()}")
|
||||||
|
|
||||||
|
def onEntityClicked(self, item):
|
||||||
|
print(f"Clicked: {item.text()}")
|
||||||
|
|
||||||
|
def onAddEntity(self):
|
||||||
|
chunk = self.parent.map.getChunkAtWorldPos(*self.parent.map.position)
|
||||||
|
if chunk is None:
|
||||||
|
return
|
||||||
|
chunk.addEntity()
|
||||||
|
|
||||||
|
def onRemoveEntity(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def onEntityData(self):
|
||||||
|
self.onEntityUnselect()
|
||||||
|
self.entityList.clear()
|
||||||
|
for chunk in self.parent.map.chunks.values():
|
||||||
|
for entity_id, entity in chunk.entities.items():
|
||||||
|
self.entityList.addItem(f"Entity {entity_id}")
|
||||||
46
tools/editortool/map/mapleftpanel.py
Normal file
46
tools/editortool/map/mapleftpanel.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QGridLayout, QPushButton, QTabWidget, QLabel
|
||||||
|
from editortool.map.chunkpanel import ChunkPanel
|
||||||
|
from editortool.map.entitypanel import EntityPanel
|
||||||
|
|
||||||
|
class MapLeftPanel(QWidget):
|
||||||
|
def __init__(self, parent):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.parent = parent
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
# Nav buttons
|
||||||
|
self.chunkInfoLabel = QLabel("Tile Information")
|
||||||
|
layout.addWidget(self.chunkInfoLabel)
|
||||||
|
grid = QGridLayout()
|
||||||
|
self.btnUp = QPushButton("U")
|
||||||
|
self.btnN = QPushButton("N")
|
||||||
|
self.btnDown = QPushButton("D")
|
||||||
|
self.btnW = QPushButton("W")
|
||||||
|
self.btnS = QPushButton("S")
|
||||||
|
self.btnE = QPushButton("E")
|
||||||
|
|
||||||
|
grid.addWidget(self.btnUp, 0, 0)
|
||||||
|
grid.addWidget(self.btnN, 0, 1)
|
||||||
|
grid.addWidget(self.btnDown, 0, 2)
|
||||||
|
grid.addWidget(self.btnW, 1, 0)
|
||||||
|
grid.addWidget(self.btnS, 1, 1)
|
||||||
|
grid.addWidget(self.btnE, 1, 2)
|
||||||
|
layout.addLayout(grid)
|
||||||
|
|
||||||
|
# Tabs
|
||||||
|
self.tabs = QTabWidget()
|
||||||
|
self.chunkPanel = ChunkPanel(self.parent)
|
||||||
|
self.chunkPanel.setFixedWidth(250)
|
||||||
|
self.tabs.addTab(self.chunkPanel, "Tiles")
|
||||||
|
self.entityPanel = EntityPanel(self.parent)
|
||||||
|
self.tabs.addTab(self.entityPanel, "Entities")
|
||||||
|
layout.addWidget(self.tabs)
|
||||||
|
|
||||||
|
# Event subscriptions
|
||||||
|
self.btnN.clicked.connect(lambda: self.parent.map.moveRelative(0, -1, 0))
|
||||||
|
self.btnS.clicked.connect(lambda: self.parent.map.moveRelative(0, 1, 0))
|
||||||
|
self.btnE.clicked.connect(lambda: self.parent.map.moveRelative(1, 0, 0))
|
||||||
|
self.btnW.clicked.connect(lambda: self.parent.map.moveRelative(-1, 0, 0))
|
||||||
|
self.btnUp.clicked.connect(lambda: self.parent.map.moveRelative(0, 0, 1))
|
||||||
|
self.btnDown.clicked.connect(lambda: self.parent.map.moveRelative(0, 0, -1))
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
from PyQt5.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QMessageBox, QTabWidget
|
from PyQt5.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QMessageBox
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from editortool.map.glwidget import GLWidget
|
from editortool.map.glwidget import GLWidget
|
||||||
from editortool.map.chunkpanel import ChunkPanel
|
from editortool.map.mapleftpanel import MapLeftPanel
|
||||||
from editortool.map.mapinfopanel import MapInfoPanel
|
from editortool.map.mapinfopanel import MapInfoPanel
|
||||||
from editortool.map.menubar import MapMenubar
|
from editortool.map.menubar import MapMenubar
|
||||||
from editortool.map.statusbar import StatusBar
|
from editortool.map.statusbar import StatusBar
|
||||||
@@ -36,14 +36,10 @@ class MapWindow(QMainWindow):
|
|||||||
self.setCentralWidget(central)
|
self.setCentralWidget(central)
|
||||||
mainLayout = QHBoxLayout(central)
|
mainLayout = QHBoxLayout(central)
|
||||||
|
|
||||||
# Tabs (left)
|
# Left panel (tabs + nav buttons)
|
||||||
self.tabs = QTabWidget()
|
self.leftPanel = MapLeftPanel(self)
|
||||||
|
self.leftPanel.setFixedWidth(250)
|
||||||
self.chunkPanel = ChunkPanel(self)
|
mainLayout.addWidget(self.leftPanel)
|
||||||
self.chunkPanel.setFixedWidth(200)
|
|
||||||
self.tabs.addTab(self.chunkPanel, "Tile Editor")
|
|
||||||
|
|
||||||
mainLayout.addWidget(self.tabs)
|
|
||||||
|
|
||||||
# Center panel (GLWidget + controls)
|
# Center panel (GLWidget + controls)
|
||||||
self.glWidget = GLWidget(self)
|
self.glWidget = GLWidget(self)
|
||||||
|
|||||||
Reference in New Issue
Block a user