Level Editor Paint.Net

  • GM 8

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Level Editor Paint.Net

    Hallo,

    Ich hätte eine frag hat jemand von euch eine Idee wie man ne Map Laden könnte aus einer BMP oder PNG datei.
    Dabei wäre dan ein Level 32x32 Pixel und 1 Pixel entspricht dabei einem Tile von 32x32.

    Inspiriert hat mich dabei das Spiel Metagun , von Notch der sein level als BMP gespeichert bzw. erstellt hat.Leider ist alles
    in Java geschrieben und ich wollte halt ein Spiel in GML machen mit der Technik :P


    Mfg. xXTechmanXx
  • Es gibt ne Möglichkeit wie man Farb-Komponenten auf binärer Weise aus der BMP herauslesen oder einspeisen kann.
    Somit kann man 3 Zahlen zwischen 0 und 255 speichern (pro Pixel).
    Um das zu tun muss man wissen wie die daten in einer BMP gespeichert werden, was ich leider nicht weis, vieleicht kann uns jemand hier aufklären.
    Eine andere aber deutlich langsamere Möglichkeit ist es die Farbe zu berechnen und dann per draw_getpixel auszulesen und mit draw_pixel zu zeichnen.

    Für ein 2d-Spiel find ich dieses Verfahren aber unnötig. Eine einfache txt-File tut's auch.
    Verbreiteter ist diese Technik bei Hight-maps in 3d wobei der Grauton die Höhe an der bestimmten Stelle angibt.

    Willst du auf diese Drachen und -eier klicken?
    Sie werden sich freuen ;)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von DragonGamer ()

  • naj du machst einfach das der Map-editor jeden gesetzten Tile in die Datei speichert.
    Kommt drauf an wie der Editor funktionieren soll.
    Am einfachsten (bei nicht zu vielen Tiles) wäre es die Koordinaten und die tile-ID zu speichern.
    Also mit den file_text_-Funktionen in die erste Zeile die x-coordinate, zweite y und dritte die id des Tiles schreiben, und dann immer so weiter.
    Schau einfach in die Hilfe dort ist sehr gut erklärt wie man die Funktionen bedient.

    Willst du auf diese Drachen und -eier klicken?
    Sie werden sich freuen ;)
  • Also ich will die oberr THeorie noch mal unterstreichen. Daten aus einem Bild zu ziehen ist performancelastog. Bei einem Höhenmap bzw Voxel landschaft Test von mir, kamm der PC ganzschön ins stottert. Und um so größer dann das bild, um so heftiger.
    Das mit der Textdatei kann ich dir auch nicht genau weiter helfen.
    Aber wir haben im Forum dafür auch unsere Spezialisten.
    Ich würde zum anfang, wenn du es weist, den umgekehrten weg gehen.
    Am besten du Programiierst nicht nur das extrahieren aus einer Textdatei, sondern auch gleich den ganzen Mapeditor.
    Somit weist du wie alles in die Textdatei kommt, und kannstes umgekehrt wieder herausholen.

    Ps:Ich habe es mal auf die Billigste variante gemacht. Hab für die map ein savegame genommen. Das funst so auf halben weg und ist auch nur eine Notlösung und nicht sehr originell.
    Meine Signatur hat kein Visum für das GM Forum erhalten.
  • Mh ich bin ja nicht wirklich gut miten GM und ich kenne viele Funktionen garnicht deswegen habe ich gehoft , dass mir jemand helfen kann bei meinem Projekt.

    Es sollte ein Strategie Spiel werden wobei erstmal das Konzept und ein paar Grafiken stehen.
    Ich werde mich so langsam mal an die Engine wagen.

    Es wird ja kein 3D Spiel sondern ein 2D Spiel :D
    Die Map wird dan geladen es dauert ne weile und es kommt auch ein Ladebalken und dan kommt man ins Gefecht.



    Edit: Hier gibts den code für Metagun wodrin es benutzt wird

    Spoiler anzeigen
    [package com.mojang.metagun.level;

    import java.awt.*;
    import java.util.*;
    import java.util.List;

    import com.mojang.metagun.*;
    import com.mojang.metagun.entity.*;
    import com.mojang.metagun.screen.GameScreen;

    public class Level {
    public static final double FRICTION = 0.99;
    public static final double GRAVITY = 0.10;
    public List<Entity> entities = new ArrayList<Entity>();
    public byte[] walls;
    public List<Entity>[] entityMap;
    private int width, height;
    public Player player;
    public int xSpawn, ySpawn;
    private Random random = new Random(1000);
    private GameScreen screen;
    private int respawnTime = 0;
    // private int xo, yo;
    private int tick;

    @SuppressWarnings("unchecked")
    public Level(GameScreen screen, int w, int h, int xo, int yo, int xSpawn, int ySpawn) {
    this.screen = screen;
    int[] pixels = new int[32 * 24];
    this.xSpawn = xSpawn;
    this.ySpawn = ySpawn;

    Art.level.getRGB(xo * 31, yo * 23, 32, 24, pixels, 0, 32);

    walls = new byte[w * h];
    entityMap = new ArrayList[w * h];
    this.width = w;
    this.height = h;

    for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
    entityMap[x + y * w] = new ArrayList<Entity>();

    int col = pixels[x + y * w] & 0xffffff;
    byte wall = 0;

    if (col == 0xffffff) wall = 1;
    else if (col == 0xFF00FF) wall = 2;
    else if (col == 0xffff00) wall = 3;
    else if (col == 0xff0000) wall = 4;
    else if (col == 0xB7B7B7) wall = 5;
    else if (col == 0xFF5050) wall = 6;
    else if (col == 0xFF5051) wall = 7;
    else if (col == 0x383838) wall = 8;
    else if (col == 0xA3FFFF) wall = 9;
    else if (col == 0x83FFFF) {
    BossPart prev = new Boss(x * 10 - 2, y * 10 - 2);
    int timeOffs = random.nextInt(60);
    ((Boss)prev).time = timeOffs;
    add(prev);
    for (int i = 0; i < 10; i++) {
    BossNeck b = new BossNeck(x * 10 - 1, y * 10 - 1, prev);
    b.time = i * 10 + timeOffs;
    prev = b;
    add(prev);
    }
    } else if (col == 0x80FFFF) {
    Gremlin g = new Gremlin(0, x * 10 - 10, y * 10 - 20);
    g.jumpDelay = random.nextInt(50);
    add(g);
    } else if (col == 0x81FFFF) {
    Gremlin g = new Gremlin(1, x * 10 - 10, y * 10 - 20);
    g.jumpDelay = random.nextInt(50);
    add(g);
    } else if (col == 0x82FFFF) {
    Jabberwocky g = new Jabberwocky(x * 10 - 10, y * 10 - 10);
    g.slamTime = random.nextInt(30);
    add(g);
    } else if (col == 0xFFADF8) {
    add(new Hat(x * 10 + 1, y * 10 + 5, xo * 31 + x, yo * 23 + y));
    } else if ((col & 0x00ffff) == 0x00ff00 && (col & 0xff0000) > 0) {
    add(new Sign(x * 10, y * 10, (col >> 16) & 0xff));
    } else if (col == 0x0000ff) {
    // if (xSpawn == 0 && ySpawn == 0) {
    this.xSpawn = x * 10 + 1;
    this.ySpawn = y * 10 - 8;
    // }
    } else if (col == 0x00FFFF) {
    Gunner e = new Gunner(x * 10 + 2, y * 10 + 10 - 6, 0, 0);
    e.chargeTime = random.nextInt(Gunner.CHARGE_DURATION / 2);
    e.xa = e.ya = 0;

    add(e);
    }
    walls[x + y * w] = wall;
    }
    }

    player = new Player(this.xSpawn, this.ySpawn);
    add(player);
    }

    public void add(Entity e) {
    entities.add(e);
    e.init(this);

    e.xSlot = (int) ((e.x + e.w / 2.0) / 10);
    e.ySlot = (int) ((e.y + e.h / 2.0) / 10);
    if (e.xSlot >= 0 && e.ySlot >= 0 && e.xSlot < width && e.ySlot < height) {
    entityMap[e.xSlot + e.ySlot * width].add(e);
    }
    }

    public void tick() {
    tick++;
    if (player.removed) {
    respawnTime++;
    if (respawnTime == 20) {
    screen.mayRespawn = true;
    }
    }
    for (int i = 0; i < entities.size(); i++) {
    Entity e = entities.get(i);
    int xSlotOld = e.xSlot;
    int ySlotOld = e.ySlot;
    if (!e.removed) e.tick();
    e.xSlot = (int) ((e.x + e.w / 2.0) / 10);
    e.ySlot = (int) ((e.y + e.h / 2.0) / 10);
    if (e.removed) {
    if (xSlotOld >= 0 && ySlotOld >= 0 && xSlotOld < width && ySlotOld < height) {
    entityMap[xSlotOld + ySlotOld * width].remove(e);
    }
    entities.remove(i--);
    } else {
    if (e.xSlot != xSlotOld || e.ySlot != ySlotOld) {
    if (xSlotOld >= 0 && ySlotOld >= 0 && xSlotOld < width && ySlotOld < height) {
    entityMap[xSlotOld + ySlotOld * width].remove(e);
    }
    if (e.xSlot >= 0 && e.ySlot >= 0 && e.xSlot < width && e.ySlot < height) {
    entityMap[e.xSlot + e.ySlot * width].add(e);
    } else {
    e.outOfBounds();
    }

    }
    }
    }
    }

    private List<Entity> hits = new ArrayList<Entity>();

    public List<Entity> getEntities(double xc, double yc, double w, double h) {
    hits.clear();
    int r = 20;
    int x0 = (int) ((xc - r) / 10);
    int y0 = (int) ((yc - r) / 10);
    int x1 = (int) ((xc + w + r) / 10);
    int y1 = (int) ((yc + h + r) / 10);
    for (int x = x0; x <= x1; x++)
    for (int y = y0; y <= y1; y++) {
    if (x >= 0 && y >= 0 && x < width && y < height) {
    List<Entity> es = entityMap[x + y * width];
    for (int i = 0; i < es.size(); i++) {
    Entity e = es.get(i);
    double xx0 = e.x;
    double yy0 = e.y;
    double xx1 = e.x + e.w;
    double yy1 = e.y + e.h;
    if (xx0 > xc + w || yy0 > yc + h || xx1 < xc || yy1 < yc) continue;

    hits.add(e);
    }
    }
    }
    return hits;
    }

    public void render(Graphics g, Camera camera) {
    g.translate(-camera.x, -camera.y);

    int xo = camera.x / 10;
    int yo = camera.y / 10;
    for (int x = xo; x <= xo + camera.width / 10; x++) {
    for (int y = yo; y <= yo + camera.height / 10; y++) {
    if (x >= 0 && y >= 0 && x < width && y < height) {
    int ximg = 0;
    int yimg = 0;
    byte w = walls[x + y * width];
    if (w == 0) yimg = 1;
    if (w == 1) ximg = 0;
    if (w == 2) ximg = 2;
    if (w == 3) ximg = 1;
    if (w == 9) ximg = 7;
    if (w == 8) {
    ximg = 4;
    yimg = 1;
    }
    if (w == 5) {
    ximg = 1;
    yimg = 1;
    }
    if (w == 6) {
    ximg = (tick / 4 + x * 2) & 3;
    yimg = 2;
    }
    if (w == 7) {
    ximg = (-tick / 4 + x * 2) & 3;
    yimg = 3;
    }
    if (w == 4) {
    if (walls[x + (y - 1) * width] == 1) {
    yimg++;
    }
    ximg = 3;
    }

    g.drawImage(Art.walls[ximg][yimg], x * 10, y * 10, null);
    }
    }
    }
    for (int i = entities.size() - 1; i >= 0; i--) {
    Entity e = entities.get(i);
    e.render(g, camera);
    }
    }

    public boolean isFree(Entity ee, double xc, double yc, int w, int h, double xa, double ya) {
    if (ee.interactsWithWorld) {
    return isBulletFree(ee, xc, yc, w, h);
    }
    double e = 0.1;
    int x0 = (int) (xc / 10);
    int y0 = (int) (yc / 10);
    int x1 = (int) ((xc + w - e) / 10);
    int y1 = (int) ((yc + h - e) / 10);
    boolean ok = true;
    for (int x = x0; x <= x1; x++)
    for (int y = y0; y <= y1; y++) {
    if (x >= 0 && y >= 0 && x < width && y < height) {
    byte ww = walls[x + y * width];
    if (ww != 0) ok = false;
    if (ww == 8) ok = true;
    if (ww == 4 && ya != 0) ee.hitSpikes();
    if (ww == 6) {
    ee.xa += 0.12;
    }
    if (ww == 7) {
    ee.xa -= 0.12;
    }
    }
    }

    return ok;
    }

    public boolean isBulletFree(Entity bullet, double xc, double yc, int w, int h) {
    double e = 0.1;
    int x0 = (int) (xc / 10);
    int y0 = (int) (yc / 10);
    int x1 = (int) ((xc + w - e) / 10);
    int y1 = (int) ((yc + h - e) / 10);
    boolean ok = true;
    for (int x = x0; x <= x1; x++)
    for (int y = y0; y <= y1; y++) {
    if (x >= 0 && y >= 0 && x < width && y < height) {
    byte ww = walls[x + y * width];
    if (ww != 0) ok = false;
    if (ww == 5) ok = true;
    if (ww == 2) {
    int xPush = 0;
    int yPush = 0;

    if (Math.abs(bullet.xa) > Math.abs(bullet.ya)) {
    if (bullet.xa < 0) xPush = -1;
    if (bullet.xa > 0) xPush = 1;
    } else {
    if (bullet.ya < 0) yPush = -1;
    if (bullet.ya > 0) yPush = 1;
    }
    double r = 0.5;
    if (walls[(x + xPush) + (y + yPush) * width] == 0 && getEntities((x + xPush) * 10 + r, (y + yPush) * 10 + r, 10 - r * 2, 10 - r * 2).size() == 0) {
    walls[x + y * width] = 0;
    walls[(x + xPush) + (y + yPush) * width] = 2;
    }
    bullet.remove();
    }
    if (ww == 3) {
    Sound.boom.play();
    for (int i = 0; i < 16; i++) {
    double dir = i * Math.PI * 2 / 8.0;
    double xa = Math.sin(dir);
    double ya = Math.cos(dir);
    double dist = (i / 8) + 1;
    add(new Explosion(1, i * 3, x * 10 + 5 + xa * dist, y * 10 + 5 + ya * dist, xa, ya));
    }
    bullet.remove();
    walls[x + y * width] = 0;
    }
    if (ww == 9) {
    if ((bullet instanceof Explosion) && ((Explosion)bullet).power > 0) {
    Sound.boom.play();
    for (int i = 0; i < 16; i++) {
    double dir = i * Math.PI * 2 / 8.0;
    double xa = Math.sin(dir);
    double ya = Math.cos(dir);
    double dist = (i / 8) + 1;
    add(new Explosion(1, i * 3, x * 10 + 5 + xa * dist, y * 10 + 5 + ya * dist, xa, ya));
    }
    bullet.remove();
    walls[x + y * width] = 0;
    }
    }
    }
    }

    return ok;
    }

    public void readSign(Sign sign) {
    screen.readSign(sign.id - 1);
    }

    public void transition(int x, int y) {
    screen.transition(x, y);
    }

    public void getGun(int level) {
    screen.getGun(level);
    }
    }/hide]

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von xXTechmanXx ()

  • naja ginge schon, und wenn die Maps nich zu gross sind, wär draw_get_pixel auch kein Problem. Theoretisch könntest du für Paint.Net sogar ein Plugin schreiben, welches das Bild in ein vom GM leichter auslesbares Textformat konvertiert.
    Wäre auch ne Möglichkeit, nen eigenen kleinen Editor zu schreiben, wo man wirklich sieht, welches Tile wie aussieht.
    Zusätzlich musst du ja wohl nicht nur die Boden-Tiles, sondern auch noch die Objekte darauf speichern, nicht?
    Mal schaun ob ich heut Abend etwas Lust und Laune hab...

    Für grössere bzw komplexere Maps empfehle ich entweder ein binäres oder ein Xml-Format, evtl sogar gezipt, so dass sich zusätzlich Files mit reinpacken können(So lassen sich verschiedene Bereiche in verschiedene Files aufteilen und etwa Daten wie zB Bilder gleich mitreinpacken).
    Wobei die Maps wohl nicht so komplex sein werden ;P

    Daten aus einem Bild zu ziehen ist performancelastog. Bei einem Höhenmap bzw Voxel landschaft Test von mir, kamm der PC ganzschön ins stottert.

    Geht ja auch nich um Voxel. Und Voxel und GM kannste eig. gleich vergessen.
    "das war meine letzte flamewar PM an dich ."
  • Denke das wird funkten ^^

    GML-Quellcode

    1. spr="DeinGeladenesSprite"
    2. sprite_index=spr
    3. i=0
    4. j=0
    5. spr_w=0
    6. spr_h=0
    7. numb=0
    8. pix=0
    9. spr_w=sprite_get_width(spr)
    10. spr_h=sprite_get_height(spr)
    11. numb=spr_w*spr_h/32
    12. repeat numb
    13. {
    14. pix=draw_getpixel(i,j)
    15. switch pix
    16. {
    17. case c_red:
    18. instance_create(i,j,"WennRotAnDerStelleDannDasHierCreaten")
    19. break;
    20. case c_blue:
    21. instance_create(i,j,"WennBlauAnDerStelleDannDasHierCreaten")
    22. break;
    23. case c_green:
    24. instance_create(i,j,"WennGrünAnDerStelleDannDasHierCreaten")
    25. break;
    26. i+=32
    27. if i>=spr_w {j+=32 i=0}
    28. }
    29. }
    30. instance_destroy()
    Alles anzeigen
    :saint:

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Tice ()

  • setzt aber voraus, dass das sprite gezeichnet wird und dazu noch an der richtigen Position. Ausserdem darf nix drübergezeichnet werden.
    Wenn mit draw_getpixel, dann würd ich vorschlagen, man zeichnets in ne surface und macht von dort aus draw_getpixel...
    "das war meine letzte flamewar PM an dich ."